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

View File

@@ -1134,6 +1134,14 @@ public class ChangeZoneAi extends SpellAbilityAi {
if( fetchList.isEmpty() ) if( fetchList.isEmpty() )
return null; 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"); String type = sa.getParam("ChangeType");
if (type == null) { if (type == null) {
type = "Card"; type = "Card";

View File

@@ -13,19 +13,19 @@ import forge.game.player.RegisteredPlayer;
public enum GameType { public enum GameType {
// deck composition rules, isPoolRestricted, can sideboard between matches // deck composition rules, isPoolRestricted, can sideboard between matches
Sealed (DeckFormat.Limited, true, true, true, "Sealed", null), Sealed (DeckFormat.Limited, true, true, true, "Sealed", "", null),
Draft (DeckFormat.Limited, true, true, true, "Draft", null), Draft (DeckFormat.Limited, true, true, true, "Draft", "", null),
Winston (DeckFormat.Limited, true, true, true, "Winston", null), Winston (DeckFormat.Limited, true, true, true, "Winston", "", null),
Gauntlet (DeckFormat.Limited, true, true, true, "Gauntlet", null), Gauntlet (DeckFormat.Limited, true, true, true, "Gauntlet", "", null),
Quest (DeckFormat.QuestDeck, true, true, false, "Quest", null), Quest (DeckFormat.QuestDeck, true, true, false, "Quest", "", null),
QuestDraft (DeckFormat.Limited, true, true, true, "Quest Draft", null), QuestDraft (DeckFormat.Limited, true, true, true, "Quest Draft", "", null),
Constructed (DeckFormat.Constructed, false, true, true, "Constructed", null), Constructed (DeckFormat.Constructed, false, true, true, "Constructed", "", null),
Vanguard (DeckFormat.Vanguard, true, true, true, "Vanguard", 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", 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", 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", 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", 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", new Function<RegisteredPlayer, Deck>() { 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 @Override
public Deck apply(RegisteredPlayer player) { public Deck apply(RegisteredPlayer player) {
Deck deck = new Deck(); Deck deck = new Deck();
@@ -43,15 +43,16 @@ public enum GameType {
private final DeckFormat deckFormat; private final DeckFormat deckFormat;
private final boolean isCardPoolLimited, canSideboard, addWonCardsMidGame; private final boolean isCardPoolLimited, canSideboard, addWonCardsMidGame;
private final String name; private final String name, description;
private final Function<RegisteredPlayer, Deck> deckAutoGenerator; 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; deckFormat = deckFormat0;
isCardPoolLimited = isCardPoolLimited0; isCardPoolLimited = isCardPoolLimited0;
canSideboard = canSideboard0; canSideboard = canSideboard0;
addWonCardsMidGame = addWonCardsMidgame0; addWonCardsMidGame = addWonCardsMidgame0;
name = name0; name = name0;
description = description0;
deckAutoGenerator = deckAutoGenerator0; deckAutoGenerator = deckAutoGenerator0;
} }
@@ -104,4 +105,8 @@ public enum GameType {
public String toString() { public String toString() {
return name; 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, 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."); " 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")) { if (sb.toString().endsWith("\r\n\r\n")) {
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3); 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 addMultiKickerMagnitude(final int n) { this.multiKickerMagnitude += n; }
public final void setKickerMagnitude(final int n) { this.multiKickerMagnitude = n; } public final void setKickerMagnitude(final int n) { this.multiKickerMagnitude = n; }
public final int getKickerMagnitude() { public final int getKickerMagnitude() {
if (this.multiKickerMagnitude > 0) if (this.multiKickerMagnitude > 0) {
return multiKickerMagnitude; return multiKickerMagnitude;
}
boolean hasK1 = costsPaid.contains(OptionalCost.Kicker1); boolean hasK1 = costsPaid.contains(OptionalCost.Kicker1);
return hasK1 == costsPaid.contains(OptionalCost.Kicker2) ? (hasK1 ? 2 : 0) : 1; 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", "Enchant", "Protection", "Cumulative upkeep", "Equip", "Buyback",
"Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph", "Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph",
"Affinity", "Entwine", "Splice", "Ninjutsu", "Affinity", "Entwine", "Splice", "Ninjutsu",
"Transute", "Replicate", "Recover", "Suspend", "Aura swap", "Transmute", "Replicate", "Recover", "Suspend", "Aura swap",
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl", "Fortify", "Transfigure", "Champion", "Evoke", "Prowl",
"Reinforce", "Unearth", "Level up", "Miracle", "Overload", "Reinforce", "Unearth", "Level up", "Miracle", "Overload",
"Scavenge", "Bestow", "Outlast").build(); "Scavenge", "Bestow", "Outlast").build();

View File

@@ -31,6 +31,8 @@ import forge.util.maps.MapToAmount;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
/** /**
* <p> * <p>
* ManaCostBeingPaid class. * ManaCostBeingPaid class.
@@ -215,6 +217,20 @@ public class ManaCostBeingPaid {
return unpaidShards.isEmpty(); 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) { public final void increaseColorlessMana(final int manaToAdd) {
increaseShard(ManaCostShard.COLORLESS, manaToAdd); increaseShard(ManaCostShard.COLORLESS, manaToAdd);
} }

View File

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

View File

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

View File

@@ -332,27 +332,15 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
// TODO: make working triggered ability // TODO: make working triggered ability
sp.setTotalManaSpent(totManaSpent); sp.setTotalManaSpent(totManaSpent);
AbilityUtils.resolve(sp); AbilityUtils.resolve(sp);
} else { }
else {
for (OptionalCost s : sp.getOptionalCosts()) { for (OptionalCost s : sp.getOptionalCosts()) {
source.addOptionalCostPaid(s); source.addOptionalCostPaid(s);
} }
if (sp.isCopied()) { if (sp.isCopied()) {
si = this.push(sp); 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), if (sp.isSpell() && source.isCreature() && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
CardPredicates.hasKeyword("As an additional cost to cast creature spells," + CardPredicates.hasKeyword("As an additional cost to cast creature spells," +
" you may pay any amount of mana. If you do, that creature enters " + " 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") if (sp.isSpell() && (source.hasStartOfKeyword("Replicate")
|| ((source.isInstant() || source.isSorcery()) && Iterables.any(activator.getCardsIn(ZoneType.Battlefield), || ((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."))))) { CardPredicates.hasKeyword("Each instant and sorcery spell you cast has replicate. The replicate cost is equal to its mana cost."))))) {
int magnitude = 0; Integer magnitude = sp.getSVarInt("Replicate");
// TODO: convert multikicker/replicate support in abCost so this if (magnitude == null) {
// doesn't happen here magnitude = 0;
final Cost costReplicate = new Cost(source.getManaCost(), false); final Cost costReplicate = new Cost(source.getManaCost(), false);
boolean hasPaid = false; boolean hasPaid = false;
int replicateCMC = source.getManaCost().getCMC(); int replicateCMC = source.getManaCost().getCMC();
@@ -408,15 +395,17 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
magnitude++; magnitude++;
totManaSpent += replicateCMC; totManaSpent += replicateCMC;
} }
} while( hasPaid ); } while (hasPaid);
}
// Replicate Trigger // Replicate Trigger
String effect = String.format("AB$ CopySpellAbility | Cost$ 0 | Defined$ SourceFirstSpell | Amount$ %d", magnitude); String effect = String.format("AB$ CopySpellAbility | Cost$ 0 | Defined$ SourceFirstSpell | Amount$ %d", magnitude);
SpellAbility sa = AbilityFactory.getAbility(effect, source); SpellAbility sa = AbilityFactory.getAbility(effect, source);
sa.setDescription("Replicate - " + source); sa.setDescription("Replicate - " + source);
sa.setTrigger(true); sa.setTrigger(true);
sa.setCopied(true);
addSimultaneousStackEntry(sa); 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 FLabel.Builder().text("Maximum Packs").build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_MAX_PACKS, ErrType.SHOP), constraints1); 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 FLabel.Builder().text("Starting Packs").build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_STARTING_PACKS, ErrType.SHOP), constraints1); 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 FLabel.Builder().text("Maximum Packs").fontAlign(SwingConstants.RIGHT).build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_MAX_PACKS, QuestPreferencesErrType.SHOP), constraints1); 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 FLabel.Builder().text("Starting Packs").fontAlign(SwingConstants.RIGHT).build(), constraints2);
pnlShop.add(new PrefInput(QPref.SHOP_STARTING_PACKS, QuestPreferencesErrType.SHOP), constraints1); pnlShop.add(new PrefInput(QPref.SHOP_STARTING_PACKS, QuestPreferencesErrType.SHOP), constraints1);

View File

@@ -54,7 +54,6 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
*/ */
@Override @Override
public void update() { public void update() {
MenuUtil.setMenuProvider(this); MenuUtil.setMenuProvider(this);
SwingUtilities.invokeLater(new Runnable() { 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. } // 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); 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()) { for (final int i : view.getParticipants()) {
String name = view.getPlayerName(i); String name = view.getPlayerName(i);
String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(view.getDeckChooser(i).getPlayer().getDeck()); String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(view.getDeckChooser(i).getPlayer().getDeck());
@@ -220,9 +236,10 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
if (variantTypes.isEmpty()) { if (variantTypes.isEmpty()) {
rp.setTeamNumber(view.getTeam(i)); rp.setTeamNumber(view.getTeam(i));
players.add(rp.setPlayer(lobbyPlayer)); players.add(rp.setPlayer(lobbyPlayer));
} else { }
else {
Deck deck = null; Deck deck = null;
boolean isCommanderMatch = variantTypes.contains(GameType.Commander); PaperCard vanguardAvatar = null;
if (isCommanderMatch) { if (isCommanderMatch) {
Object selected = view.getCommanderDeckLists().get(i).getSelectedValue(); Object selected = view.getCommanderDeckLists().get(i).getSelectedValue();
if (selected instanceof String) { if (selected instanceof String) {
@@ -231,7 +248,8 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
if (sel.equals("Random") && comDecks.size() > 0) { if (sel.equals("Random") && comDecks.size() > 0) {
deck = Aggregates.random(comDecks); deck = Aggregates.random(comDecks);
} }
} else { }
else {
deck = (Deck) selected; deck = (Deck) selected;
} }
if (deck == null) { //Can be null if player deselects the list selection or chose Generate 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 // Initialise variables for other variants
deck = deck == null ? rp.getDeck() : deck; deck = deck == null ? rp.getDeck() : deck;
Iterable<PaperCard> schemes = null; Iterable<PaperCard> schemes = null;
boolean playerIsArchenemy = view.isPlayerArchenemy(i); boolean playerIsArchenemy = view.isPlayerArchenemy(i);
Iterable<PaperCard> planes = null; Iterable<PaperCard> planes = null;
PaperCard vanguardAvatar = null;
//Archenemy //Archenemy
if (variantTypes.contains(GameType.ArchenemyRumble) if (variantTypes.contains(GameType.ArchenemyRumble)

View File

@@ -110,13 +110,12 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
// Variants frame and variables // Variants frame and variables
private final Set<GameType> appliedVariants = new TreeSet<GameType>(); private final Set<GameType> appliedVariants = new TreeSet<GameType>();
private final FPanel variantsPanel = new FPanel(new MigLayout("insets 10, gapx 10")); private final FPanel variantsPanel = new FPanel(new MigLayout("insets 10, gapx 10"));
private final FCheckBox vntVanguard = new FCheckBox("Vanguard"); private final VariantCheckBox vntVanguard = new VariantCheckBox(GameType.Vanguard);
private final FCheckBox vntCommander = new FCheckBox("Commander"); private final VariantCheckBox vntMomirBasic = new VariantCheckBox(GameType.MomirBasic);
private final FCheckBox vntPlanechase = new FCheckBox("Planechase"); private final VariantCheckBox vntCommander = new VariantCheckBox(GameType.Commander);
private final FCheckBox vntArchenemy = new FCheckBox("Archenemy"); private final VariantCheckBox vntPlanechase = new VariantCheckBox(GameType.Planechase);
private String archenemyType = "Classic"; private final VariantCheckBox vntArchenemy = new VariantCheckBox(GameType.Archenemy);
private final FComboBoxWrapper<String> comboArchenemy = new FComboBoxWrapper<String>(new String[]{ private final VariantCheckBox vntArchenemyRumble = new VariantCheckBox(GameType.ArchenemyRumble);
"Archenemy (Classic - One player is the Archenemy)", "Supervillan Rumble (All players are Archenemies)"});
// Player frame elements // Player frame elements
private final JPanel playersFrame = new JPanel(new MigLayout("insets 0, gap 0 5, wrap, hidemode 3")); 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 //////////////////// //////////////////// 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.setOpaque(false);
variantsPanel.add(newLabel("Variants:")); variantsPanel.add(newLabel("Variants:"));
variantsPanel.add(vntVanguard); variantsPanel.add(vntVanguard);
variantsPanel.add(vntMomirBasic);
variantsPanel.add(vntCommander); variantsPanel.add(vntCommander);
variantsPanel.add(vntPlanechase); variantsPanel.add(vntPlanechase);
variantsPanel.add(vntArchenemy); variantsPanel.add(vntArchenemy);
comboArchenemy.addTo(variantsPanel); variantsPanel.add(vntArchenemyRumble);
constructedFrame.add(new FScrollPane(variantsPanel, false, true, constructedFrame.add(new FScrollPane(variantsPanel, false, true,
ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
@@ -459,6 +450,8 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
container.validate(); container.validate();
container.repaint(); container.repaint();
} }
changePlayerFocus(playerWithFocus, currentGameMode);
} }
/** @return {@link javax.swing.JButton} */ /** @return {@link javax.swing.JButton} */
@@ -682,29 +675,62 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
}; };
public void updateVariantControlsVisibility() { public void updateVariantControlsVisibility() {
// Commander deck replaces basic deck, so hide that boolean isCommanderApplied = false;
deckLabel.setVisible(!appliedVariants.contains(GameType.Commander)); boolean isPlanechaseApplied = false;
deckBtn.setVisible(!appliedVariants.contains(GameType.Commander)); boolean isVanguardApplied = false;
cmdDeckSelectorBtn.setVisible(appliedVariants.contains(GameType.Commander)); boolean isArchenemyApplied = false;
cmdDeckEditor.setVisible(appliedVariants.contains(GameType.Commander)); boolean archenemyVisiblity = false;
cmdLabel.setVisible(appliedVariants.contains(GameType.Commander)); 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); scmDeckSelectorBtn.setVisible(archenemyVisiblity);
scmDeckEditor.setVisible(archenemyVisiblity); scmDeckEditor.setVisible(archenemyVisiblity);
scmLabel.setVisible(archenemyVisiblity); scmLabel.setVisible(archenemyVisiblity);
teamComboBox.setVisible(!appliedVariants.contains(GameType.Archenemy)); teamComboBox.setVisible(!isArchenemyApplied);
aeTeamComboBox.setVisible(appliedVariants.contains(GameType.Archenemy)); aeTeamComboBox.setVisible(isArchenemyApplied);
aeTeamComboBox.setEnabled(!(appliedVariants.contains(GameType.Archenemy) && playerIsArchenemy)); aeTeamComboBox.setEnabled(!(isArchenemyApplied && playerIsArchenemy));
pchDeckSelectorBtn.setVisible(appliedVariants.contains(GameType.Planechase)); pchDeckSelectorBtn.setVisible(isPlanechaseApplied);
pchDeckEditor.setVisible(appliedVariants.contains(GameType.Planechase)); pchDeckEditor.setVisible(isPlanechaseApplied);
pchLabel.setVisible(appliedVariants.contains(GameType.Planechase)); pchLabel.setVisible(isPlanechaseApplied);
vgdSelectorBtn.setVisible(appliedVariants.contains(GameType.Vanguard)); vgdSelectorBtn.setVisible(isVanguardApplied);
vgdLabel.setVisible(appliedVariants.contains(GameType.Vanguard)); vgdLabel.setVisible(isVanguardApplied);
} }
@Override @Override
@@ -779,7 +805,8 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
public void toggleIsPlayerArchenemy() { public void toggleIsPlayerArchenemy() {
if (appliedVariants.contains(GameType.Archenemy)) { if (appliedVariants.contains(GameType.Archenemy)) {
playerIsArchenemy = lastArchenemy == index; playerIsArchenemy = lastArchenemy == index;
} else { }
else {
playerIsArchenemy = appliedVariants.contains(GameType.ArchenemyRumble); playerIsArchenemy = appliedVariants.contains(GameType.ArchenemyRumble);
} }
updateVariantControlsVisibility(); updateVariantControlsVisibility();
@@ -793,7 +820,7 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
scmDeckSelectorBtn.setCommand(new Runnable() { scmDeckSelectorBtn.setCommand(new Runnable() {
@Override @Override
public void run() { public void run() {
currentGameMode = archenemyType.contains("Classic") ? GameType.Archenemy : GameType.ArchenemyRumble; currentGameMode = vntArchenemy.isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble;
scmDeckSelectorBtn.requestFocusInWindow(); scmDeckSelectorBtn.requestFocusInWindow();
changePlayerFocus(index, currentGameMode); changePlayerFocus(index, currentGameMode);
} }
@@ -802,7 +829,7 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
scmDeckEditor.setCommand(new UiCommand() { scmDeckEditor.setCommand(new UiCommand() {
@Override @Override
public void run() { public void run() {
currentGameMode = archenemyType.contains("Classic") ? GameType.Archenemy : GameType.ArchenemyRumble; currentGameMode = vntArchenemy.isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble;
Predicate<PaperCard> predSchemes = new Predicate<PaperCard>() { Predicate<PaperCard> predSchemes = new Predicate<PaperCard>() {
@Override @Override
public boolean apply(PaperCard arg0) { public boolean apply(PaperCard arg0) {
@@ -1139,36 +1166,45 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
///////////////////////////////////////////// /////////////////////////////////////////////
//========== Various listeners in build order //========== Various listeners in build order
/** This listener unlocks the relevant buttons for players @SuppressWarnings("serial")
* and enables/disables archenemy combobox as appropriate. */ private class VariantCheckBox extends FCheckBox {
private ItemListener iListenerVariants = new ItemListener() { private final GameType variantType;
private VariantCheckBox(GameType variantType0) {
super(variantType0.toString());
variantType = variantType0;
setToolTipText(variantType.getDescription());
addItemListener(new ItemListener() {
@Override @Override
public void itemStateChanged(ItemEvent arg0) { public void itemStateChanged(ItemEvent e) {
FCheckBox cb = (FCheckBox) arg0.getSource(); if (e.getStateChange() == ItemEvent.SELECTED) {
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) {
appliedVariants.add(variantType); appliedVariants.add(variantType);
currentGameMode = 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 { else {
appliedVariants.remove(variantType); appliedVariants.remove(variantType);
@@ -1176,36 +1212,15 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
currentGameMode = GameType.Constructed; currentGameMode = GameType.Constructed;
} }
} }
}
for (PlayerPanel pp : playerPanels) { for (PlayerPanel pp : playerPanels) {
pp.toggleIsPlayerArchenemy(); pp.toggleIsPlayerArchenemy();
pp.updateVariantControlsVisibility();
} }
changePlayerFocus(playerWithFocus, currentGameMode); 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() { private ActionListener nameListener = new ActionListener() {
@Override @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. 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 - - 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 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ W U | SpellDescription$ Add {W}{U} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/azorius_chancery.jpg 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ R W | SpellDescription$ Add {R}{W} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/boros_garrison.jpg 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ U B | SpellDescription$ Add {U}{B} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/dimir_aqueduct.jpg 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ B G | SpellDescription$ Add {B}{G} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/golgari_rot_farm.jpg 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ R G | SpellDescription$ Add {R}{G} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/gruul_turf.jpg 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ U R | SpellDescription$ Add {U}{R} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/izzet_boilerworks.jpg 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. 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 Types:Land
K:CARDNAME enters the battlefield tapped. 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. 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. A:AB$ Mana | Cost$ T | Produced$ W B | SpellDescription$ Add {W}{B} to your mana pool.
SVar:NeedsToPlay:Land.Basic+YouCtrl SVar:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/orzhov_basilica.jpg 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ B R | SpellDescription$ Add {B}{R} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/rakdos_carnarium.jpg 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ G W | SpellDescription$ Add {G}{W} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/selesnya_sanctuary.jpg 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. 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. K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ G U | SpellDescription$ Add {G}{U} to your mana pool. 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. 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:NeedsToPlay:Land.Basic+YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/simic_growth_chamber.jpg 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. 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 final Object zoneToRestore;
private boolean bPaid = false; private boolean bPaid = false;
private Boolean canPayManaCost = null; protected Boolean canPayManaCost = null;
private boolean locked = false; private boolean locked = false;
@@ -343,7 +343,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
return true; return true;
} }
private void runAsAi(Runnable proc) { protected void runAsAi(Runnable proc) {
player.runWithController(proc, new PlayerControllerAi(game, player, player.getOriginalLobbyPlayer())); 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 com.google.common.collect.Iterables;
import forge.FThreads; import forge.FThreads;
import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil; import forge.game.GameActionUtil;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
@@ -27,7 +25,6 @@ import forge.game.zone.ZoneType;
import forge.match.input.InputPayMana; import forge.match.input.InputPayMana;
import forge.match.input.InputPayManaOfCostPayment; import forge.match.input.InputPayManaOfCostPayment;
import forge.match.input.InputPayManaSimple; import forge.match.input.InputPayManaSimple;
import forge.match.input.InputPayManaX;
import forge.match.input.InputSelectCardsFromList; import forge.match.input.InputSelectCardsFromList;
import forge.util.Lang; import forge.util.Lang;
import forge.util.gui.SGuiChoose; import forge.util.gui.SGuiChoose;
@@ -635,8 +632,9 @@ public class HumanPlay {
prompt = source + "\n" + promptCurrent; prompt = source + "\n" + promptCurrent;
} }
if( sourceAbility != null ) if (sourceAbility != null) {
sourceAbility.clearManaPaid(); sourceAbility.clearManaPaid();
}
boolean paid = p.getController().payManaCost(cost.getCostMana(), sourceAbility, prompt, false); boolean paid = p.getController().payManaCost(cost.getCostMana(), sourceAbility, prompt, false);
if (!paid) { if (!paid) {
p.getManaPool().refundManaPaid(sourceAbility); p.getManaPool().refundManaPaid(sourceAbility);
@@ -692,24 +690,32 @@ public class HumanPlay {
final Card source = ability.getHostCard(); final Card source = ability.getHostCard();
ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction()); ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction());
boolean xWasBilled = false;
String xInCard = source.getSVar("X"); String xInCard = source.getSVar("X");
if (mc.getAmountOfX() > 0 && !"Count$xPaid".equals(xInCard)) { // announce X will overwrite whatever was in card script 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 xPaid = AbilityUtils.calculateAmount(source, "X", ability);
int xCost = AbilityUtils.calculateAmount(source, "X", ability) * mc.getAmountOfX(); toPay.setXManaCostPaid(xPaid, ability.getParam("XColor"));
byte xColor = MagicColor.fromName(ability.hasParam("XColor") ? ability.getParam("XColor") : "1"); source.setXManaCostPaid(xPaid);
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);
} }
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); ManaCostAdjustment.adjust(toPay, ability, false);
}
InputPayMana inpPayment; InputPayMana inpPayment;
if (ability.isOffering() && ability.getSacrificedAsOffering() == null) { if (ability.isOffering() && ability.getSacrificedAsOffering() == null) {
@@ -727,19 +733,6 @@ public class HumanPlay {
source.setColorsPaid(toPay.getColorsPaid()); source.setColorsPaid(toPay.getColorsPaid());
source.setSunburstValue(toPay.getSunburst()); 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 // Handle convoke and offerings
if (ability.isOffering() && ability.getSacrificedAsOffering() != null) { if (ability.isOffering() && ability.getSacrificedAsOffering() != null) {

View File

@@ -196,40 +196,59 @@ public class HumanPlaySpellAbility {
} }
private boolean announceValuesLikeX() { 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 // Announcing Requirements like Choosing X or Multikicker
// SA Params as comma delimited list // SA Params as comma delimited list
String announce = ability.getParam("Announce"); String announce = ability.getParam("Announce");
if (announce != null) { if (announce != null) {
for(String aVar : announce.split(",")) { for (String aVar : announce.split(",")) {
String varName = aVar.trim(); String varName = aVar.trim();
boolean isX = "X".equalsIgnoreCase(varName); boolean isX = "X".equalsIgnoreCase(varName);
CostPartMana manaCost = ability.getPayCosts().getCostMana(); if (isX) { needX = false; }
boolean allowZero = !ability.hasParam("XCantBe0") && (!isX || manaCost == null || manaCost.canXbe0());
Integer value = ability.getActivatingPlayer().getController().announceRequirements(ability, varName, allowZero); Integer value = controller.announceRequirements(ability, varName, allowZero && (!isX || manaCost == null || manaCost.canXbe0()));
if (value == null) { if (value == null) {
return false; return false;
} }
ability.setSVar(varName, value.toString()); ability.setSVar(varName, value.toString());
if ("Multikicker".equals(varName)) { if ("Multikicker".equals(varName)) {
ability.getHostCard().setKickerMagnitude(value); card.setKickerMagnitude(value);
} }
else { 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; return true;
} }
private boolean announceType() {
// Announcing Requirements like choosing creature type or number // 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"); String announce = ability.getParam("AnnounceType");
PlayerController pc = ability.getActivatingPlayer().getController(); PlayerController pc = ability.getActivatingPlayer().getController();
if (announce != null) { if (announce != null) {
for(String aVar : announce.split(",")) { for (String aVar : announce.split(",")) {
String varName = aVar.trim(); String varName = aVar.trim();
if ("CreatureType".equals(varName)) { if ("CreatureType".equals(varName)) {
String choice = pc.chooseSomeType("Creature", ability, CardType.getCreatureTypes(), new ArrayList<String>()); 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 startPacks = this.qpref.getPrefInt(QPref.SHOP_STARTING_PACKS);
final int winsForPack = this.qpref.getPrefInt(QPref.SHOP_WINS_FOR_ADDITIONAL_PACK); final int winsForPack = this.qpref.getPrefInt(QPref.SHOP_WINS_FOR_ADDITIONAL_PACK);
final int maxPacks = this.qpref.getPrefInt(QPref.SHOP_MAX_PACKS); 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(); int level = this.qc.getAchievements().getLevel();
final int levelPacks = level > 0 ? startPacks / level : startPacks; final int levelPacks = level > 0 ? startPacks / level : startPacks;
final int winPacks = this.qc.getAchievements().getWin() / winsForPack; 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(); SealedProduct.Template tpl = getShopBoosterTemplate();

View File

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

View File

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