Merged changes from trunk to GuiRefactoring: 27239-27260

This commit is contained in:
elcnesh
2014-09-09 09:30:57 +00:00
parent 0222c64b62
commit ecdd2b2995
33 changed files with 1154 additions and 1019 deletions

View File

@@ -74,14 +74,12 @@ public class ComputerUtilMana {
manaSpent.clear();
}
private static boolean payManaCost(final SpellAbility sa, final Player ai, final boolean test, final int extraMana, boolean checkPlayable) {
ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, test, extraMana);
return payManaCost(cost, sa, ai, test, checkPlayable);
}
private static class ManaProducingCard {
private CoreType cardType;
private int manaCount;
@@ -1169,10 +1167,11 @@ public class ComputerUtilMana {
* @since 1.0.15
*/
public static int determineLeftoverMana(final SpellAbility sa, final Player player) {
for (int i = 1; i < 100; i++)
if (!canPayManaCost(sa, player, i))
for (int i = 1; i < 100; i++) {
if (!canPayManaCost(sa, player, i)) {
return i - 1;
}
}
return 99;
}

View File

@@ -1134,6 +1134,14 @@ public class ChangeZoneAi extends SpellAbilityAi {
if( fetchList.isEmpty() )
return null;
if (sa.hasParam("AILogic") && sa.getParam("AILogic").equals("NeverBounceItself")) {
Card source = sa.getHostCard();
if (fetchList.contains(source)) {
// For cards that should never be bounced back to hand with their own [e.g. triggered] abilities, such as guild lands.
fetchList.remove(source);
}
}
String type = sa.getParam("ChangeType");
if (type == null) {
type = "Card";

View File

@@ -13,19 +13,19 @@ import forge.game.player.RegisteredPlayer;
public enum GameType {
// deck composition rules, isPoolRestricted, can sideboard between matches
Sealed (DeckFormat.Limited, true, true, true, "Sealed", null),
Draft (DeckFormat.Limited, true, true, true, "Draft", null),
Winston (DeckFormat.Limited, true, true, true, "Winston", null),
Gauntlet (DeckFormat.Limited, true, true, true, "Gauntlet", null),
Quest (DeckFormat.QuestDeck, true, true, false, "Quest", null),
QuestDraft (DeckFormat.Limited, true, true, true, "Quest Draft", null),
Constructed (DeckFormat.Constructed, false, true, true, "Constructed", null),
Vanguard (DeckFormat.Vanguard, true, true, true, "Vanguard", null),
Commander (DeckFormat.Commander, false, false, false, "Commander", null),
Planechase (DeckFormat.Planechase, false, false, true, "Planechase", null),
Archenemy (DeckFormat.Archenemy, false, false, true, "Archenemy", null),
ArchenemyRumble (DeckFormat.Archenemy, false, false, true, "Archenemy Rumble", null),
MomirBasic (DeckFormat.Constructed, false, false, false, "Momir Basic", new Function<RegisteredPlayer, Deck>() {
Sealed (DeckFormat.Limited, true, true, true, "Sealed", "", null),
Draft (DeckFormat.Limited, true, true, true, "Draft", "", null),
Winston (DeckFormat.Limited, true, true, true, "Winston", "", null),
Gauntlet (DeckFormat.Limited, true, true, true, "Gauntlet", "", null),
Quest (DeckFormat.QuestDeck, true, true, false, "Quest", "", null),
QuestDraft (DeckFormat.Limited, true, true, true, "Quest Draft", "", null),
Constructed (DeckFormat.Constructed, false, true, true, "Constructed", "", null),
Vanguard (DeckFormat.Vanguard, true, true, true, "Vanguard", "Each player has a special \"Avatar\" card that affects the game.", null),
Commander (DeckFormat.Commander, false, false, false, "Commander", "Each player has a legendary \"General\" card which can be cast at any time and determines deck colors.", null),
Planechase (DeckFormat.Planechase, false, false, true, "Planechase", "Plane cards apply global effects. Plane card changed when a player rolls \"Chaos\" on the planar die.", null),
Archenemy (DeckFormat.Archenemy, false, false, true, "Archenemy", "One player is the Archenemy and can play scheme cards.", null),
ArchenemyRumble (DeckFormat.Archenemy, false, false, true, "Archenemy Rumble", "All players are Archenemies and can play scheme cards.", null),
MomirBasic (DeckFormat.Constructed, false, false, false, "Momir Basic", "Each player has a deck containing 60 basic lands and the Momir Vig avatar.", new Function<RegisteredPlayer, Deck>() {
@Override
public Deck apply(RegisteredPlayer player) {
Deck deck = new Deck();
@@ -43,15 +43,16 @@ public enum GameType {
private final DeckFormat deckFormat;
private final boolean isCardPoolLimited, canSideboard, addWonCardsMidGame;
private final String name;
private final String name, description;
private final Function<RegisteredPlayer, Deck> deckAutoGenerator;
GameType(DeckFormat deckFormat0, boolean isCardPoolLimited0, boolean canSideboard0, boolean addWonCardsMidgame0, String name0, Function<RegisteredPlayer, Deck> deckAutoGenerator0) {
GameType(DeckFormat deckFormat0, boolean isCardPoolLimited0, boolean canSideboard0, boolean addWonCardsMidgame0, String name0, String description0, Function<RegisteredPlayer, Deck> deckAutoGenerator0) {
deckFormat = deckFormat0;
isCardPoolLimited = isCardPoolLimited0;
canSideboard = canSideboard0;
addWonCardsMidGame = addWonCardsMidgame0;
name = name0;
description = description0;
deckAutoGenerator = deckAutoGenerator0;
}
@@ -104,4 +105,8 @@ public enum GameType {
public String toString() {
return name;
}
public String getDescription() {
return description;
}
}

View File

@@ -2535,7 +2535,7 @@ public class Card extends GameEntity implements Comparable<Card> {
sb.indexOf("Storm (When you cast this spell, copy it for each spell cast before it this turn.") + 81,
" You may choose new targets for the copies.");
}
} else if (keyword.contains("Replicate") && !sb.toString().contains("you paid its replicate cost.")) {
} else if (keyword.startsWith("Replicate") && !sb.toString().contains("you paid its replicate cost.")) {
if (sb.toString().endsWith("\r\n\r\n")) {
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3);
}
@@ -4181,8 +4181,9 @@ public class Card extends GameEntity implements Comparable<Card> {
public final void addMultiKickerMagnitude(final int n) { this.multiKickerMagnitude += n; }
public final void setKickerMagnitude(final int n) { this.multiKickerMagnitude = n; }
public final int getKickerMagnitude() {
if (this.multiKickerMagnitude > 0)
if (this.multiKickerMagnitude > 0) {
return multiKickerMagnitude;
}
boolean hasK1 = costsPaid.contains(OptionalCost.Kicker1);
return hasK1 == costsPaid.contains(OptionalCost.Kicker2) ? (hasK1 ? 2 : 0) : 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -51,7 +51,7 @@ public final class CardUtil {
"Enchant", "Protection", "Cumulative upkeep", "Equip", "Buyback",
"Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph",
"Affinity", "Entwine", "Splice", "Ninjutsu",
"Transute", "Replicate", "Recover", "Suspend", "Aura swap",
"Transmute", "Replicate", "Recover", "Suspend", "Aura swap",
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl",
"Reinforce", "Unearth", "Level up", "Miracle", "Overload",
"Scavenge", "Bestow", "Outlast").build();

View File

@@ -31,6 +31,8 @@ import forge.util.maps.MapToAmount;
import java.util.*;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
/**
* <p>
* ManaCostBeingPaid class.
@@ -215,6 +217,20 @@ public class ManaCostBeingPaid {
return unpaidShards.isEmpty();
}
public final void setXManaCostPaid(final int xPaid, final String xColor) {
int xCost = xPaid * cntX;
cntX = 0;
ManaCostShard increaseShard;
if (StringUtils.isEmpty(xColor)) {
increaseShard = ManaCostShard.COLORLESS;
}
else {
increaseShard = ManaCostShard.valueOf(MagicColor.fromName(xColor));
}
unpaidShards.add(increaseShard, xCost);
}
public final void increaseColorlessMana(final int manaToAdd) {
increaseShard(ManaCostShard.COLORLESS, manaToAdd);
}

View File

@@ -131,8 +131,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
public final AbilityManaPart getManaPartRecursive() {
SpellAbility tail = this;
while (tail != null) {
if(tail.manaPart != null)
if (tail.manaPart != null) {
return tail.manaPart;
}
tail = tail.getSubAbility();
}
return null;
@@ -140,14 +141,17 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
public final boolean isManaAbility() {
// Check whether spell or ability first
if (this.isSpell())
if (this.isSpell()) {
return false;
}
// without a target
if (this.usesTargeting()) return false;
if (getRestrictions() != null && getRestrictions().getPlaneswalker())
if (this.usesTargeting()) { return false; }
if (getRestrictions() != null && getRestrictions().getPlaneswalker()) {
return false; //Loyalty ability, not a mana ability.
if (this.isWrapper() && ((WrappedAbility) this).getTrigger().getMode() != TriggerType.TapsForMana)
}
if (this.isWrapper() && ((WrappedAbility) this).getTrigger().getMode() != TriggerType.TapsForMana) {
return false;
}
return getManaPartRecursive() != null;
}
@@ -157,7 +161,22 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
public final String getSVar(final String name) {
return sVars.get(name) != null ? sVars.get(name) : "";
String var = sVars.get(name);
if (var == null) {
var = "";
}
return var;
}
public final Integer getSVarInt(final String name) {
String var = sVars.get(name);
if (var != null) {
try {
return Integer.parseInt(var);
}
catch (Exception e) {}
}
return null;
}
public final void setSVar(final String name, final String value) {
@@ -298,18 +317,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
public boolean isSpell() { return false; }
public boolean isAbility() { return true; }
/**
* <p>
* isMultiKicker.
* </p>
*
* @return a boolean.
*/
public boolean isMultiKicker() {
return this.multiKickerManaCost != null && !this.isAnnouncing("Multikicker");
}
/**
* <p>
* setIsMorphUp.
@@ -380,14 +387,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
public String getParamOrDefault(String key, String defaultValue) {
return mapParams == null || !mapParams.containsKey(key) ? defaultValue : mapParams.get(key);
return mapParams.containsKey(key) ? mapParams.get(key) : defaultValue;
}
public String getParam(String key) {
return mapParams == null ? null : mapParams.get(key);
return mapParams.get(key);
}
public boolean hasParam(String key) {
return mapParams == null ? false : mapParams.containsKey(key);
return mapParams.containsKey(key);
}
/**
@@ -395,10 +402,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
* @param mapParams
*/
public void copyParamsToMap(Map<String, String> mapParams) {
if (null != this.mapParams) {
mapParams.putAll(this.mapParams);
}
}
// If this is not null, then ability was made in a factory
public ApiType getApi() {
@@ -1127,9 +1132,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
String[] validTgt = tr.getValidTgts();
if (entity instanceof GameEntity && !((GameEntity) entity).isValid(validTgt, this.getActivatingPlayer(), this.getHostCard()))
if (entity instanceof GameEntity && !((GameEntity) entity).isValid(validTgt, this.getActivatingPlayer(), this.getHostCard())) {
return false;
}
}
// Restrictions coming from target
return entity.canBeTargetedBy(this);
@@ -1298,7 +1304,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
while (null != parent.getParent()) {
parent = parent.getParent();
}
return parent;
}
@@ -1351,15 +1356,32 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
*/
public boolean isAnnouncing(String variable) {
String announce = getParam("Announce");
if (StringUtils.isBlank(announce)) return false;
if (StringUtils.isBlank(announce)) { return false; }
String[] announcedOnes = TextUtil.split(announce, ',');
for(String a : announcedOnes) {
if( a.trim().equalsIgnoreCase(variable))
for (String a : announcedOnes) {
if (a.trim().equalsIgnoreCase(variable)) {
return true;
}
}
return false;
}
public void addAnnounceVar(String variable) {
String announce = getParam("Announce");
if (StringUtils.isBlank(announce)) {
mapParams.put("Announce", variable);
return;
}
String[] announcedOnes = TextUtil.split(announce, ',');
for (String a : announcedOnes) {
if (a.trim().equalsIgnoreCase(variable)) {
return; //don't add announce variable that already exists
}
}
mapParams.put("Announce", announce + ";" + variable);
}
public boolean isXCost() {
CostPartMana cm = payCosts != null ? getPayCosts().getCostMana() : null;
return cm != null && cm.getAmountOfX() > 0;
@@ -1486,10 +1508,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
targetChosen.add(card);
final String desc;
if (!card.isFaceDown()) {
desc = this.getHostCard().getName() + " - targeting " + card;
} else {
}
else {
desc = this.getHostCard().getName() + " - targeting Morph(" + card.getUniqueNumber() + ")";
}
this.setStackDescription(desc);
@@ -1532,7 +1554,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return ImmutableList.<Card>of();
}
public SpellAbility getSATargetingCard() {
return targetChosen.isTargetingAnyCard() ? this : getParentTargetingCard();
}
@@ -1543,8 +1564,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
parent = ((WrappedAbility) parent).getWrappedAbility();
}
while (parent != null) {
if (parent.targetChosen.isTargetingAnyCard())
if (parent.targetChosen.isTargetingAnyCard()) {
return parent;
}
parent = parent.getParent();
}
return null;
@@ -1674,15 +1696,21 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
final String[] incR = restriction.split("\\.", 2);
if (incR[0].equals("Spell")) {
if (!this.isSpell())
if (!this.isSpell()) {
return false;
} else if (incR[0].equals("Triggered")) {
if (!this.isTrigger())
}
}
else if (incR[0].equals("Triggered")) {
if (!this.isTrigger()) {
return false;
} else if (incR[0].equals("Activated")) {
if (!(this instanceof AbilityActivated))
}
}
else if (incR[0].equals("Activated")) {
if (!(this instanceof AbilityActivated)) {
return false;
} else { //not a spell/ability type
}
}
else { //not a spell/ability type
return false;
}
@@ -1811,5 +1839,4 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
this.subAbility.setIntrinsic(i);
}
}
}

View File

@@ -243,11 +243,6 @@ public class WrappedAbility extends Ability implements ISpellAbility {
return sa.isFlashBackAbility();
}
@Override
public boolean isMultiKicker() {
return sa.isMultiKicker();
}
@Override
public boolean isSpell() {
return sa.isSpell();

View File

@@ -332,27 +332,15 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
// TODO: make working triggered ability
sp.setTotalManaSpent(totManaSpent);
AbilityUtils.resolve(sp);
} else {
}
else {
for (OptionalCost s : sp.getOptionalCosts()) {
source.addOptionalCostPaid(s);
}
if (sp.isCopied()) {
si = this.push(sp);
} else {
if (sp.isMultiKicker()) {
final Cost costMultikicker = new Cost(sp.getMultiKickerManaCost(), false);
boolean hasPaid = false;
do {
int mkMagnitude = source.getKickerMagnitude();
String prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", source, mkMagnitude );
hasPaid = activator.getController().payManaOptional(source, costMultikicker, sp, prompt, ManaPaymentPurpose.Multikicker);
if (hasPaid) {
source.addMultiKickerMagnitude(1);
totManaSpent += sp.getPayingMana().size();
// TODO: paying mana is replaced by multikicker cost, this should be fixed in the future
}
} while( hasPaid );
}
else {
if (sp.isSpell() && source.isCreature() && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
CardPredicates.hasKeyword("As an additional cost to cast creature spells," +
" you may pay any amount of mana. If you do, that creature enters " +
@@ -394,10 +382,9 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
if (sp.isSpell() && (source.hasStartOfKeyword("Replicate")
|| ((source.isInstant() || source.isSorcery()) && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
CardPredicates.hasKeyword("Each instant and sorcery spell you cast has replicate. The replicate cost is equal to its mana cost."))))) {
int magnitude = 0;
// TODO: convert multikicker/replicate support in abCost so this
// doesn't happen here
Integer magnitude = sp.getSVarInt("Replicate");
if (magnitude == null) {
magnitude = 0;
final Cost costReplicate = new Cost(source.getManaCost(), false);
boolean hasPaid = false;
int replicateCMC = source.getManaCost().getCMC();
@@ -408,15 +395,17 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
magnitude++;
totManaSpent += replicateCMC;
}
} while( hasPaid );
} while (hasPaid);
}
// Replicate Trigger
String effect = String.format("AB$ CopySpellAbility | Cost$ 0 | Defined$ SourceFirstSpell | Amount$ %d", magnitude);
SpellAbility sa = AbilityFactory.getAbility(effect, source);
sa.setDescription("Replicate - " + source);
sa.setTrigger(true);
sa.setCopied(true);
addSimultaneousStackEntry(sa);
}
}
}

View File

@@ -213,6 +213,9 @@ public class QuestPreferencesHandler extends SkinnedPanel {
pnlShop.add(new FLabel.Builder().text("Maximum Packs").build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_MAX_PACKS, ErrType.SHOP), constraints1);
pnlShop.add(new FLabel.Builder().text("Minimum Packs").build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_MIN_PACKS, ErrType.SHOP), constraints1);
pnlShop.add(new FLabel.Builder().text("Starting Packs").build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_STARTING_PACKS, ErrType.SHOP), constraints1);

View File

@@ -351,6 +351,9 @@ public enum VSubmenuQuestPrefs implements IVSubmenu<CSubmenuQuestPrefs> {
pnlShop.add(new FLabel.Builder().text("Maximum Packs").fontAlign(SwingConstants.RIGHT).build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_MAX_PACKS, QuestPreferencesErrType.SHOP), constraints1);
pnlShop.add(new FLabel.Builder().text("Minimum Packs").fontAlign(SwingConstants.RIGHT).build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_MIN_PACKS, QuestPreferencesErrType.SHOP), constraints1);
pnlShop.add(new FLabel.Builder().text("Starting Packs").fontAlign(SwingConstants.RIGHT).build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_STARTING_PACKS, QuestPreferencesErrType.SHOP), constraints1);

View File

@@ -54,7 +54,6 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
*/
@Override
public void update() {
MenuUtil.setMenuProvider(this);
SwingUtilities.invokeLater(new Runnable() {
@@ -196,8 +195,25 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
}
} // Is it even possible anymore? I think current implementation assigns decks automatically.
GameType autoGenerateVariant = null;
boolean isCommanderMatch = false;
if (!variantTypes.isEmpty()) {
isCommanderMatch = variantTypes.contains(GameType.Commander);
if (!isCommanderMatch) {
for (GameType variant : variantTypes) {
if (variant.isAutoGenerated()) {
autoGenerateVariant = variant;
break;
}
}
}
}
boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY);
if (checkLegality && !variantTypes.contains(GameType.Commander)) { //Commander deck replaces regular deck and is checked later
//Auto-generated decks don't need to be checked here
//Commander deck replaces regular deck and is checked later
if (checkLegality && autoGenerateVariant == null && !isCommanderMatch) {
for (final int i : view.getParticipants()) {
String name = view.getPlayerName(i);
String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(view.getDeckChooser(i).getPlayer().getDeck());
@@ -220,9 +236,10 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
if (variantTypes.isEmpty()) {
rp.setTeamNumber(view.getTeam(i));
players.add(rp.setPlayer(lobbyPlayer));
} else {
}
else {
Deck deck = null;
boolean isCommanderMatch = variantTypes.contains(GameType.Commander);
PaperCard vanguardAvatar = null;
if (isCommanderMatch) {
Object selected = view.getCommanderDeckLists().get(i).getSelectedValue();
if (selected instanceof String) {
@@ -231,7 +248,8 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
if (sel.equals("Random") && comDecks.size() > 0) {
deck = Aggregates.random(comDecks);
}
} else {
}
else {
deck = (Deck) selected;
}
if (deck == null) { //Can be null if player deselects the list selection or chose Generate
@@ -245,13 +263,19 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
}
}
}
else if (autoGenerateVariant != null) {
deck = autoGenerateVariant.autoGenerateDeck(rp);
CardPool avatarPool = deck.get(DeckSection.Avatar);
if (avatarPool != null) {
vanguardAvatar = avatarPool.get(0);
}
}
// Initialise variables for other variants
deck = deck == null ? rp.getDeck() : deck;
Iterable<PaperCard> schemes = null;
boolean playerIsArchenemy = view.isPlayerArchenemy(i);
Iterable<PaperCard> planes = null;
PaperCard vanguardAvatar = null;
//Archenemy
if (variantTypes.contains(GameType.ArchenemyRumble)

View File

@@ -110,13 +110,12 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
// Variants frame and variables
private final Set<GameType> appliedVariants = new TreeSet<GameType>();
private final FPanel variantsPanel = new FPanel(new MigLayout("insets 10, gapx 10"));
private final FCheckBox vntVanguard = new FCheckBox("Vanguard");
private final FCheckBox vntCommander = new FCheckBox("Commander");
private final FCheckBox vntPlanechase = new FCheckBox("Planechase");
private final FCheckBox vntArchenemy = new FCheckBox("Archenemy");
private String archenemyType = "Classic";
private final FComboBoxWrapper<String> comboArchenemy = new FComboBoxWrapper<String>(new String[]{
"Archenemy (Classic - One player is the Archenemy)", "Supervillan Rumble (All players are Archenemies)"});
private final VariantCheckBox vntVanguard = new VariantCheckBox(GameType.Vanguard);
private final VariantCheckBox vntMomirBasic = new VariantCheckBox(GameType.MomirBasic);
private final VariantCheckBox vntCommander = new VariantCheckBox(GameType.Commander);
private final VariantCheckBox vntPlanechase = new VariantCheckBox(GameType.Planechase);
private final VariantCheckBox vntArchenemy = new VariantCheckBox(GameType.Archenemy);
private final VariantCheckBox vntArchenemyRumble = new VariantCheckBox(GameType.ArchenemyRumble);
// Player frame elements
private final JPanel playersFrame = new JPanel(new MigLayout("insets 0, gap 0 5, wrap, hidemode 3"));
@@ -160,22 +159,14 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
////////////////////////////////////////////////////////
//////////////////// Variants Panel ////////////////////
// Populate and add variants panel
vntVanguard.addItemListener(iListenerVariants);
vntCommander.addItemListener(iListenerVariants);
vntPlanechase.addItemListener(iListenerVariants);
vntArchenemy.addItemListener(iListenerVariants);
comboArchenemy.setSelectedIndex(0);
comboArchenemy.setEnabled(vntArchenemy.isSelected());
comboArchenemy.addActionListener(aeComboListener);
variantsPanel.setOpaque(false);
variantsPanel.add(newLabel("Variants:"));
variantsPanel.add(vntVanguard);
variantsPanel.add(vntMomirBasic);
variantsPanel.add(vntCommander);
variantsPanel.add(vntPlanechase);
variantsPanel.add(vntArchenemy);
comboArchenemy.addTo(variantsPanel);
variantsPanel.add(vntArchenemyRumble);
constructedFrame.add(new FScrollPane(variantsPanel, false, true,
ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
@@ -459,6 +450,8 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
container.validate();
container.repaint();
}
changePlayerFocus(playerWithFocus, currentGameMode);
}
/** @return {@link javax.swing.JButton} */
@@ -682,29 +675,62 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
};
public void updateVariantControlsVisibility() {
// Commander deck replaces basic deck, so hide that
deckLabel.setVisible(!appliedVariants.contains(GameType.Commander));
deckBtn.setVisible(!appliedVariants.contains(GameType.Commander));
cmdDeckSelectorBtn.setVisible(appliedVariants.contains(GameType.Commander));
cmdDeckEditor.setVisible(appliedVariants.contains(GameType.Commander));
cmdLabel.setVisible(appliedVariants.contains(GameType.Commander));
boolean isCommanderApplied = false;
boolean isPlanechaseApplied = false;
boolean isVanguardApplied = false;
boolean isArchenemyApplied = false;
boolean archenemyVisiblity = false;
boolean isDeckBuildingAllowed = true;
for (GameType variant : appliedVariants) {
switch (variant) {
case Archenemy:
isArchenemyApplied = true;
if (playerIsArchenemy) {
archenemyVisiblity = true;
}
break;
case ArchenemyRumble:
archenemyVisiblity = true;
break;
case Commander:
isCommanderApplied = true;
isDeckBuildingAllowed = false; //Commander deck replaces basic deck, so hide that
break;
case Planechase:
isPlanechaseApplied = true;
break;
case Vanguard:
isVanguardApplied = true;
break;
default:
if (variant.isAutoGenerated()) {
isDeckBuildingAllowed = false;
}
break;
}
}
deckLabel.setVisible(isDeckBuildingAllowed);
deckBtn.setVisible(isDeckBuildingAllowed);
cmdDeckSelectorBtn.setVisible(isCommanderApplied);
cmdDeckEditor.setVisible(isCommanderApplied);
cmdLabel.setVisible(isCommanderApplied);
boolean archenemyVisiblity = appliedVariants.contains(GameType.ArchenemyRumble)
|| (appliedVariants.contains(GameType.Archenemy) && playerIsArchenemy);
scmDeckSelectorBtn.setVisible(archenemyVisiblity);
scmDeckEditor.setVisible(archenemyVisiblity);
scmLabel.setVisible(archenemyVisiblity);
teamComboBox.setVisible(!appliedVariants.contains(GameType.Archenemy));
aeTeamComboBox.setVisible(appliedVariants.contains(GameType.Archenemy));
aeTeamComboBox.setEnabled(!(appliedVariants.contains(GameType.Archenemy) && playerIsArchenemy));
teamComboBox.setVisible(!isArchenemyApplied);
aeTeamComboBox.setVisible(isArchenemyApplied);
aeTeamComboBox.setEnabled(!(isArchenemyApplied && playerIsArchenemy));
pchDeckSelectorBtn.setVisible(appliedVariants.contains(GameType.Planechase));
pchDeckEditor.setVisible(appliedVariants.contains(GameType.Planechase));
pchLabel.setVisible(appliedVariants.contains(GameType.Planechase));
pchDeckSelectorBtn.setVisible(isPlanechaseApplied);
pchDeckEditor.setVisible(isPlanechaseApplied);
pchLabel.setVisible(isPlanechaseApplied);
vgdSelectorBtn.setVisible(appliedVariants.contains(GameType.Vanguard));
vgdLabel.setVisible(appliedVariants.contains(GameType.Vanguard));
vgdSelectorBtn.setVisible(isVanguardApplied);
vgdLabel.setVisible(isVanguardApplied);
}
@Override
@@ -779,7 +805,8 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
public void toggleIsPlayerArchenemy() {
if (appliedVariants.contains(GameType.Archenemy)) {
playerIsArchenemy = lastArchenemy == index;
} else {
}
else {
playerIsArchenemy = appliedVariants.contains(GameType.ArchenemyRumble);
}
updateVariantControlsVisibility();
@@ -793,7 +820,7 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
scmDeckSelectorBtn.setCommand(new Runnable() {
@Override
public void run() {
currentGameMode = archenemyType.contains("Classic") ? GameType.Archenemy : GameType.ArchenemyRumble;
currentGameMode = vntArchenemy.isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble;
scmDeckSelectorBtn.requestFocusInWindow();
changePlayerFocus(index, currentGameMode);
}
@@ -802,7 +829,7 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
scmDeckEditor.setCommand(new UiCommand() {
@Override
public void run() {
currentGameMode = archenemyType.contains("Classic") ? GameType.Archenemy : GameType.ArchenemyRumble;
currentGameMode = vntArchenemy.isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble;
Predicate<PaperCard> predSchemes = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard arg0) {
@@ -1139,36 +1166,45 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
/////////////////////////////////////////////
//========== Various listeners in build order
/** This listener unlocks the relevant buttons for players
* and enables/disables archenemy combobox as appropriate. */
private ItemListener iListenerVariants = new ItemListener() {
@SuppressWarnings("serial")
private class VariantCheckBox extends FCheckBox {
private final GameType variantType;
private VariantCheckBox(GameType variantType0) {
super(variantType0.toString());
variantType = variantType0;
setToolTipText(variantType.getDescription());
addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent arg0) {
FCheckBox cb = (FCheckBox) arg0.getSource();
GameType variantType = null;
if (cb == vntVanguard) {
variantType = GameType.Vanguard;
}
else if (cb == vntCommander) {
variantType = GameType.Commander;
}
else if (cb == vntPlanechase) {
variantType = GameType.Planechase;
}
else if (cb == vntArchenemy) {
variantType = archenemyType.contains("Classic") ? GameType.Archenemy : GameType.ArchenemyRumble;
comboArchenemy.setEnabled(vntArchenemy.isSelected());
if (arg0.getStateChange() != ItemEvent.SELECTED) {
appliedVariants.remove(GameType.Archenemy);
appliedVariants.remove(GameType.ArchenemyRumble);
}
}
if (null != variantType) {
if (arg0.getStateChange() == ItemEvent.SELECTED) {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
appliedVariants.add(variantType);
currentGameMode = variantType;
//ensure other necessary variants are unchecked
switch (variantType) {
case Archenemy:
vntArchenemyRumble.setSelected(false);
break;
case ArchenemyRumble:
vntArchenemy.setSelected(false);
break;
case Commander:
vntMomirBasic.setSelected(false);
break;
case Vanguard:
vntMomirBasic.setSelected(false);
break;
case MomirBasic:
vntCommander.setSelected(false);
vntVanguard.setSelected(false);
break;
default:
break;
}
}
else {
appliedVariants.remove(variantType);
@@ -1176,36 +1212,15 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
currentGameMode = GameType.Constructed;
}
}
}
for (PlayerPanel pp : playerPanels) {
pp.toggleIsPlayerArchenemy();
pp.updateVariantControlsVisibility();
}
changePlayerFocus(playerWithFocus, currentGameMode);
}
};
// Listens to the archenemy combo box
private ActionListener aeComboListener = new ActionListener() {
@SuppressWarnings("unchecked")
@Override
public void actionPerformed(ActionEvent e) {
FComboBox<String> cb = (FComboBox<String>)e.getSource();
archenemyType = (String)cb.getSelectedItem();
GameType mode = archenemyType.contains("Classic") ? GameType.Archenemy : GameType.ArchenemyRumble;
appliedVariants.remove(GameType.Archenemy);
appliedVariants.remove(GameType.ArchenemyRumble);
appliedVariants.add(mode);
currentGameMode = mode;
for (PlayerPanel pp : playerPanels) {
pp.toggleIsPlayerArchenemy();
pp.updateVariantControlsVisibility();
});
}
changePlayerFocus(playerWithFocus, currentGameMode);
}
};
private ActionListener nameListener = new ActionListener() {
@Override

View File

@@ -14,6 +14,15 @@ The details previously available by hovering over that rectangle will now appear
The dialog for the commander replacement effect will now display the commander's name.
- Momir Basic variant type -
Momir Basic is now available as its own variant option on the Constructed screen
For this format. each player will automatically be given a deck with 12 of each basic land and the Momir Vig avatar
- Choose value for X mana costs -
Now, when playing spells/abilities with X in its mana cost, you will now be prompted for a value for X prior to mana payment, ensuring the final mana cost is calculated properly from cost adjustment effects and allowing using the "Auto" button to pay the entire cost.
This also applies to spells with Replicate and Multikicker to allow picking the Replicate or Multikicker amount prior to paying the final mana cost.
- Auto-targeting support -
When playing spells and abilities with the text "target opponent", if you only have one opponent, you will no longer be asked to choose the opponent to target.
When triggered abilities have only one valid target, that target will now be auto-selected.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ W U | SpellDescription$ Add {W}{U} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:DB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:DB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/azorius_chancery.jpg
Oracle:Azorius Chancery enters the battlefield tapped.\nWhen Azorius Chancery enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {W}{U} to your mana pool.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ R W | SpellDescription$ Add {R}{W} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:DB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:DB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/boros_garrison.jpg
Oracle:Boros Garrison enters the battlefield tapped.\nWhen Boros Garrison enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {R}{W} to your mana pool.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ U B | SpellDescription$ Add {U}{B} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/dimir_aqueduct.jpg
Oracle:Dimir Aqueduct enters the battlefield tapped.\nWhen Dimir Aqueduct enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {U}{B} to your mana pool.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ B G | SpellDescription$ Add {B}{G} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/golgari_rot_farm.jpg
Oracle:Golgari Rot Farm enters the battlefield tapped.\nWhen Golgari Rot Farm enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {B}{G} to your mana pool.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ R G | SpellDescription$ Add {R}{G} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/gruul_turf.jpg
Oracle:Gruul Turf enters the battlefield tapped.\nWhen Gruul Turf enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {R}{G} to your mana pool.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ U R | SpellDescription$ Add {U}{R} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/izzet_boilerworks.jpg
Oracle:Izzet Boilerworks enters the battlefield tapped.\nWhen Izzet Boilerworks enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {U}{R} to your mana pool.

View File

@@ -3,7 +3,7 @@ ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
A:AB$ Mana | Cost$ T | Produced$ W B | SpellDescription$ Add {W}{B} to your mana pool.
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/orzhov_basilica.jpg

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ B R | SpellDescription$ Add {B}{R} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/rakdos_carnarium.jpg
Oracle:Rakdos Carnarium enters the battlefield tapped.\nWhen Rakdos Carnarium enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {B}{R} to your mana pool.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ G W | SpellDescription$ Add {G}{W} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/selesnya_sanctuary.jpg
Oracle:Selesnya Sanctuary enters the battlefield tapped.\nWhen Selesnya Sanctuary enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {G}{W} to your mana pool.

View File

@@ -4,7 +4,7 @@ Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ G U | SpellDescription$ Add {G}{U} to your mana pool.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME enters the battlefield, return a land you control to its owner's hand.
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl
SVar:TrigReturn:AB$ChangeZone | Origin$ Battlefield | Destination$ Hand | Cost$ 0 | Hidden$ True | Mandatory$ True | ChangeType$ Land.YouCtrl | AILogic$ NeverBounceItself
SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/simic_growth_chamber.jpg
Oracle:Simic Growth Chamber enters the battlefield tapped.\nWhen Simic Growth Chamber enters the battlefield, return a land you control to its owner's hand.\n{T}: Add {G}{U} to your mana pool.

View File

@@ -41,7 +41,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
private final Object zoneToRestore;
private boolean bPaid = false;
private Boolean canPayManaCost = null;
protected Boolean canPayManaCost = null;
private boolean locked = false;
@@ -343,7 +343,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
return true;
}
private void runAsAi(Runnable proc) {
protected void runAsAi(Runnable proc) {
player.runWithController(proc, new PlayerControllerAi(game, player, player.getOriginalLobbyPlayer()));
}

View File

@@ -4,9 +4,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.FThreads;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameLogEntryType;
@@ -27,7 +25,6 @@ import forge.game.zone.ZoneType;
import forge.match.input.InputPayMana;
import forge.match.input.InputPayManaOfCostPayment;
import forge.match.input.InputPayManaSimple;
import forge.match.input.InputPayManaX;
import forge.match.input.InputSelectCardsFromList;
import forge.util.Lang;
import forge.util.gui.SGuiChoose;
@@ -635,8 +632,9 @@ public class HumanPlay {
prompt = source + "\n" + promptCurrent;
}
if( sourceAbility != null )
if (sourceAbility != null) {
sourceAbility.clearManaPaid();
}
boolean paid = p.getController().payManaCost(cost.getCostMana(), sourceAbility, prompt, false);
if (!paid) {
p.getManaPool().refundManaPaid(sourceAbility);
@@ -692,24 +690,32 @@ public class HumanPlay {
final Card source = ability.getHostCard();
ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction());
boolean xWasBilled = false;
String xInCard = source.getSVar("X");
if (mc.getAmountOfX() > 0 && !"Count$xPaid".equals(xInCard)) { // announce X will overwrite whatever was in card script
// this currently only works for things about Targeted object
int xCost = AbilityUtils.calculateAmount(source, "X", ability) * mc.getAmountOfX();
byte xColor = MagicColor.fromName(ability.hasParam("XColor") ? ability.getParam("XColor") : "1");
toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost);
xWasBilled = true;
}
int timesMultikicked = ability.getHostCard().getKickerMagnitude();
if ( timesMultikicked > 0 && ability.isAnnouncing("Multikicker")) {
ManaCost mkCost = ability.getMultiKickerManaCost();
for(int i = 0; i < timesMultikicked; i++)
toPay.addManaCost(mkCost);
int xPaid = AbilityUtils.calculateAmount(source, "X", ability);
toPay.setXManaCostPaid(xPaid, ability.getParam("XColor"));
source.setXManaCostPaid(xPaid);
}
if( isActivatedSa )
int timesMultikicked = source.getKickerMagnitude();
if (timesMultikicked > 0 && ability.isAnnouncing("Multikicker")) {
ManaCost mkCost = ability.getMultiKickerManaCost();
for (int i = 0; i < timesMultikicked; i++) {
toPay.addManaCost(mkCost);
}
}
Integer replicate = ability.getSVarInt("Replicate");
if (replicate != null) {
ManaCost rCost = source.getManaCost();
for (int i = 0; i < replicate; i++) {
toPay.addManaCost(rCost);
}
}
if (isActivatedSa) {
ManaCostAdjustment.adjust(toPay, ability, false);
}
InputPayMana inpPayment;
if (ability.isOffering() && ability.getSacrificedAsOffering() == null) {
@@ -727,19 +733,6 @@ public class HumanPlay {
source.setColorsPaid(toPay.getColorsPaid());
source.setSunburstValue(toPay.getSunburst());
}
if (mc.getAmountOfX() > 0) {
if (!ability.isAnnouncing("X") && !xWasBilled) {
source.setXManaCostPaid(0);
inpPayment = new InputPayManaX(controller, ability, mc.getAmountOfX(), mc.canXbe0());
inpPayment.showAndWait();
if (!inpPayment.isPaid()) {
return false;
}
} else {
int x = AbilityUtils.calculateAmount(source, "X", ability);
source.setXManaCostPaid(x);
}
}
// Handle convoke and offerings
if (ability.isOffering() && ability.getSacrificedAsOffering() != null) {

View File

@@ -196,40 +196,59 @@ public class HumanPlaySpellAbility {
}
private boolean announceValuesLikeX() {
if (ability.isCopied()) { return true; } //don't re-announce for spell copies
boolean needX = true;
boolean allowZero = !ability.hasParam("XCantBe0");
CostPartMana manaCost = ability.getPayCosts().getCostMana();
PlayerController controller = ability.getActivatingPlayer().getController();
Card card = ability.getHostCard();
// Announcing Requirements like Choosing X or Multikicker
// SA Params as comma delimited list
String announce = ability.getParam("Announce");
if (announce != null) {
for(String aVar : announce.split(",")) {
for (String aVar : announce.split(",")) {
String varName = aVar.trim();
boolean isX = "X".equalsIgnoreCase(varName);
CostPartMana manaCost = ability.getPayCosts().getCostMana();
boolean allowZero = !ability.hasParam("XCantBe0") && (!isX || manaCost == null || manaCost.canXbe0());
if (isX) { needX = false; }
Integer value = ability.getActivatingPlayer().getController().announceRequirements(ability, varName, allowZero);
Integer value = controller.announceRequirements(ability, varName, allowZero && (!isX || manaCost == null || manaCost.canXbe0()));
if (value == null) {
return false;
}
ability.setSVar(varName, value.toString());
if ("Multikicker".equals(varName)) {
ability.getHostCard().setKickerMagnitude(value);
card.setKickerMagnitude(value);
}
else {
ability.getHostCard().setSVar(varName, value.toString());
card.setSVar(varName, value.toString());
}
}
}
if (needX && manaCost != null && manaCost.getAmountOfX() > 0) {
Integer value = controller.announceRequirements(ability, "X", allowZero && manaCost.canXbe0());
if (value == null) {
return false;
}
ability.setSVar("X", value.toString());
card.setSVar("X", value.toString());
}
return true;
}
private boolean announceType() {
// Announcing Requirements like choosing creature type or number
private boolean announceType() {
if (ability.isCopied()) { return true; } //don't re-announce for spell copies
String announce = ability.getParam("AnnounceType");
PlayerController pc = ability.getActivatingPlayer().getController();
if (announce != null) {
for(String aVar : announce.split(",")) {
for (String aVar : announce.split(",")) {
String varName = aVar.trim();
if ("CreatureType".equals(varName)) {
String choice = pc.chooseSomeType("Creature", ability, CardType.getCreatureTypes(), new ArrayList<String>());

View File

@@ -665,11 +665,12 @@ public final class QuestUtilCards {
final int startPacks = this.qpref.getPrefInt(QPref.SHOP_STARTING_PACKS);
final int winsForPack = this.qpref.getPrefInt(QPref.SHOP_WINS_FOR_ADDITIONAL_PACK);
final int maxPacks = this.qpref.getPrefInt(QPref.SHOP_MAX_PACKS);
final int minPacks = this.qpref.getPrefInt(QPref.SHOP_MIN_PACKS);
int level = this.qc.getAchievements().getLevel();
final int levelPacks = level > 0 ? startPacks / level : startPacks;
final int winPacks = this.qc.getAchievements().getWin() / winsForPack;
final int totalPacks = Math.min(levelPacks + winPacks, maxPacks);
final int totalPacks = Math.min(Math.max(levelPacks + winPacks, minPacks), maxPacks);
SealedProduct.Template tpl = getShopBoosterTemplate();

View File

@@ -135,7 +135,8 @@ public class QuestPreferences extends PreferencesStore<QuestPreferences.QPref> i
WINS_UNLOCK_SET("20"),
// Maximum amount of "Packs" opened by the Shop and available as singles
SHOP_MAX_PACKS("6"),
SHOP_MAX_PACKS("7"),
SHOP_MIN_PACKS("3"),
// Rarity distribution of Singles in an Opened Shop Pack
SHOP_SINGLES_COMMON("7"),
@@ -145,7 +146,7 @@ public class QuestPreferences extends PreferencesStore<QuestPreferences.QPref> i
// How many wins it takes to open an additional pack in the shop
SHOP_WINS_FOR_ADDITIONAL_PACK("10"),
// How many packs the shop start with.
SHOP_STARTING_PACKS("4");
SHOP_STARTING_PACKS("5");
private final String strDefaultVal;
@@ -313,7 +314,7 @@ public class QuestPreferences extends PreferencesStore<QuestPreferences.QPref> i
return "Value too large (maximum 15).";
}
break;
case SHOP_WINS_FOR_ADDITIONAL_PACK: case SHOP_MAX_PACKS:
case SHOP_WINS_FOR_ADDITIONAL_PACK: case SHOP_MAX_PACKS: case SHOP_MIN_PACKS:
if (val < 1) {
return "Value too small (minimum 1).";
} else if (val > 25) {

View File

@@ -99,12 +99,15 @@ public class SGuiChoose {
// Get Integer in range
public static Integer getInteger(final IGuiBase gui, final String message) {
return getInteger(gui, message, 0, Integer.MAX_VALUE);
return getInteger(gui, message, 0, Integer.MAX_VALUE, false);
}
public static Integer getInteger(final IGuiBase gui, final String message, int min) {
return getInteger(gui, message, min, Integer.MAX_VALUE);
return getInteger(gui, message, min, Integer.MAX_VALUE, false);
}
public static Integer getInteger(final IGuiBase gui, final String message, int min, int max) {
return getInteger(gui, message, min, max, false);
}
public static Integer getInteger(final IGuiBase gui, final String message, int min, int max, boolean sortDesc) {
if (max <= min) { return min; } //just return min if max <= min
//force cutting off after 100 numbers at most
@@ -117,9 +120,16 @@ public class SGuiChoose {
}
final Integer[] choices = new Integer[count];
if (sortDesc) {
for (int i = 0; i < count; i++) {
choices[count - i - 1] = Integer.valueOf(i + min);
}
}
else {
for (int i = 0; i < count; i++) {
choices[i] = Integer.valueOf(i + min);
}
}
return SGuiChoose.oneOrNone(gui, message, choices);
}
public static Integer getInteger(final IGuiBase gui, final String message, int min, int max, int cutoff) {