mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Merged changes from trunk to GuiRefactoring: 27239-27260
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>());
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user