Merge branch 'Card-Forge:master' into master

This commit is contained in:
Suthro
2022-07-19 13:01:23 -05:00
committed by GitHub
250 changed files with 4220 additions and 2638 deletions

View File

@@ -131,10 +131,9 @@ public class ComputerUtil {
sa = GameActionUtil.addExtraKeywordCost(sa);
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
if (!CharmEffect.makeChoices(sa)) {
return false;
}
if (sa.getApi() == ApiType.Charm && !CharmEffect.makeChoices(sa)) {
// 603.3c If no mode is chosen, the ability is removed from the stack.
return false;
}
if (chooseTargets != null) {
chooseTargets.run();
@@ -250,6 +249,13 @@ public class ComputerUtil {
return false;
final Card source = sa.getHostCard();
Zone fromZone = game.getZoneOf(source);
int zonePosition = 0;
if (fromZone != null) {
zonePosition = fromZone.getCards().indexOf(source);
}
if (sa.isSpell() && !source.isCopiedSpell()) {
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -257,11 +263,18 @@ public class ComputerUtil {
sa = GameActionUtil.addExtraKeywordCost(sa);
final Cost cost = sa.getPayCosts();
final CostPayment pay = new CostPayment(cost, sa);
// do this after card got added to stack
if (!sa.checkRestrictions(ai)) {
GameActionUtil.rollbackAbility(sa, fromZone, zonePosition, pay, source);
return false;
}
if (cost == null) {
ComputerUtilMana.payManaCost(ai, sa, false);
game.getStack().add(sa);
} else {
final CostPayment pay = new CostPayment(cost, sa);
if (pay.payComputerCosts(new AiCostDecision(ai, sa, false))) {
game.getStack().add(sa);
}
@@ -292,17 +305,30 @@ public class ComputerUtil {
newSA = GameActionUtil.addExtraKeywordCost(newSA);
final Card source = newSA.getHostCard();
Zone fromZone = game.getZoneOf(source);
int zonePosition = 0;
if (fromZone != null) {
zonePosition = fromZone.getCards().indexOf(source);
}
if (newSA.isSpell() && !source.isCopiedSpell()) {
newSA.setHostCard(game.getAction().moveToStack(source, newSA));
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
if (!CharmEffect.makeChoices(newSA)) {
return false;
}
if (newSA.getApi() == ApiType.Charm && !CharmEffect.makeChoices(newSA)) {
// 603.3c If no mode is chosen, the ability is removed from the stack.
return false;
}
}
final CostPayment pay = new CostPayment(newSA.getPayCosts(), newSA);
// do this after card got added to stack
if (!sa.checkRestrictions(ai)) {
GameActionUtil.rollbackAbility(sa, fromZone, zonePosition, pay, source);
return false;
}
pay.payComputerCosts(new AiCostDecision(ai, newSA, false));
game.getStack().add(newSA);
@@ -2798,7 +2824,7 @@ public class ComputerUtil {
}
return type.is(CounterEnumType.AWAKENING) || type.is(CounterEnumType.MANIFESTATION) || type.is(CounterEnumType.PETRIFICATION)
|| type.is(CounterEnumType.TRAINING);
|| type.is(CounterEnumType.TRAINING) || type.is(CounterEnumType.GHOSTFORM);
}
public static Player evaluateBoardPosition(final List<Player> listToEvaluate) {

View File

@@ -7,6 +7,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.ai.AiCardMemory.MemorySet;
import forge.ai.ability.AnimateAi;
import forge.ai.ability.TokenAi;
import forge.card.ColorSet;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
@@ -14,6 +15,7 @@ import forge.game.ability.ApiType;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseType;
@@ -692,6 +694,72 @@ public class ComputerUtilCost {
return false;
} else if ("LowPriority".equals(aiLogic) && MyRandom.getRandom().nextInt(100) < 67) {
return false;
} else if (aiLogic != null && aiLogic.startsWith("Fabricate")) {
final int n = Integer.valueOf(aiLogic.substring("Fabricate".length()));
// if host would leave the play or if host is useless, create tokens
if (source.hasSVar("EndOfTurnLeavePlay") || ComputerUtilCard.isUselessCreature(payer, source)) {
return false;
}
// need a copy for one with extra +1/+1 counter boost,
// without causing triggers to run
final Card copy = CardUtil.getLKICopy(source);
copy.setCounters(CounterEnumType.P1P1, copy.getCounters(CounterEnumType.P1P1) + n);
copy.setZone(source.getZone());
// if host would put into the battlefield attacking
Combat combat = source.getGame().getCombat();
if (combat != null && combat.isAttacking(source)) {
final Player defender = combat.getDefenderPlayerByAttacker(source);
if (defender.canLoseLife() && !ComputerUtilCard.canBeBlockedProfitably(defender, copy, true)) {
return true;
}
return false;
}
// if the host has haste and can attack
if (CombatUtil.canAttack(copy)) {
for (final Player opp : payer.getOpponents()) {
if (CombatUtil.canAttack(copy, opp) &&
opp.canLoseLife() &&
!ComputerUtilCard.canBeBlockedProfitably(opp, copy, true))
return true;
}
}
// TODO check for trigger to turn token ETB into +1/+1 counter for host
// TODO check for trigger to turn token ETB into damage or life loss for opponent
// in this cases Token might be prefered even if they would not survive
final Card tokenCard = TokenAi.spawnToken(payer, sa);
// Token would not survive
if (!tokenCard.isCreature() || tokenCard.getNetToughness() < 1) {
return true;
}
// Special Card logic, this one try to median its power with the number of artifacts
if ("Marionette Master".equals(source.getName())) {
CardCollection list = CardLists.filter(payer.getCardsIn(ZoneType.Battlefield), Presets.ARTIFACTS);
return list.size() >= copy.getNetPower();
} else if ("Cultivator of Blades".equals(source.getName())) {
// Cultivator does try to median with number of Creatures
CardCollection list = payer.getCreaturesInPlay();
return list.size() >= copy.getNetPower();
}
// evaluate Creature with +1/+1
int evalCounter = ComputerUtilCard.evaluateCreature(copy);
final CardCollection tokenList = new CardCollection(source);
for (int i = 0; i < n; ++i) {
tokenList.add(TokenAi.spawnToken(payer, sa));
}
// evaluate Host with Tokens
int evalToken = ComputerUtilCard.evaluateCreatureList(tokenList);
return evalToken < evalCounter;
}
// Check for shocklands and similar ETB replacement effects

View File

@@ -45,7 +45,7 @@ public class CreatureEvaluator implements Function<Card, Integer> {
value += addValue(toughness * 10, "toughness: " + toughness);
// because backside is always stronger the potential makes it better than a single faced card
if (c.hasKeyword(Keyword.DAYBOUND)) {
if (c.hasKeyword(Keyword.DAYBOUND) && c.hasBackSide()) {
value += addValue(power * 10, "transforming");
}
}

View File

@@ -34,6 +34,7 @@ import forge.game.GameObject;
import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
@@ -1045,16 +1046,14 @@ public class PlayerControllerAi extends PlayerController {
}
}
/* FIXME: the new implementation (below) requires implementing setupNewTargets in the AI controller, among other possible changes, otherwise breaks AI
if (sa.isMayChooseNewTargets()) {
sa.setupNewTargets(player);
}
*/
if (sa.isMayChooseNewTargets() && !sa.setupTargets()) {
if (sa.isSpell()) {
getGame().getAction().ceaseToExist(sa.getHostCard(), false);
TargetChoices tc = sa.getTargets();
if (!sa.setupTargets()) {
// if AI can't choose targets need to keep old one even if illegal
sa.setTargets(tc);
}
continue;
// FIXME: the new implementation (below) requires implementing setupNewTargets in the AI controller, among other possible changes, otherwise breaks AI
// sa.setupNewTargets(player);
}
}
// need finally add the new spell to the stack
@@ -1064,6 +1063,9 @@ public class PlayerControllerAi extends PlayerController {
}
private boolean prepareSingleSa(final Card host, final SpellAbility sa, boolean isMandatory) {
if (sa.getApi() == ApiType.Charm) {
return CharmEffect.makeChoices(sa);
}
if (sa.hasParam("TargetingPlayer")) {
Player targetingPlayer = AbilityUtils.getDefinedPlayers(host, sa.getParam("TargetingPlayer"), sa).get(0);
sa.setTargetingPlayer(targetingPlayer);
@@ -1087,7 +1089,7 @@ public class PlayerControllerAi extends PlayerController {
if (tgtSA instanceof Spell) { // Isn't it ALWAYS a spell?
Spell spell = (Spell) tgtSA;
// TODO if mandatory AI is only forced to use mana when it's already in the pool
if (tgtSA.checkRestrictions(brains.getPlayer()) && (brains.canPlayFromEffectAI(spell, !optional, noManaCost) == AiPlayDecision.WillPlay || !optional)) {
if (brains.canPlayFromEffectAI(spell, !optional, noManaCost) == AiPlayDecision.WillPlay || !optional) {
if (noManaCost) {
return ComputerUtil.playSpellAbilityWithoutPayingManaCost(player, tgtSA, getGame());
}

View File

@@ -89,7 +89,6 @@ public class CharmAi extends SpellAbilityAi {
// First pass using standard canPlayAi() for good choices
for (AbilitySub sub : choices) {
sub.setActivatingPlayer(ai);
sub.getRestrictions().setZone(sub.getParent().getRestrictions().getZone());
if (AiPlayDecision.WillPlay == aic.canPlaySa(sub)) {
chosenList.add(sub);
if (chosenList.size() == num) {
@@ -101,8 +100,6 @@ public class CharmAi extends SpellAbilityAi {
// Second pass using doTrigger(false) to fulfill minimum choice
choices.removeAll(chosenList);
for (AbilitySub sub : choices) {
sub.setActivatingPlayer(ai);
sub.getRestrictions().setZone(sub.getParent().getRestrictions().getZone());
if (aic.doTrigger(sub, false)) {
chosenList.add(sub);
if (chosenList.size() == min) {
@@ -114,8 +111,6 @@ public class CharmAi extends SpellAbilityAi {
if (chosenList.size() < min) {
choices.removeAll(chosenList);
for (AbilitySub sub : choices) {
sub.setActivatingPlayer(ai);
sub.getRestrictions().setZone(sub.getParent().getRestrictions().getZone());
if (aic.doTrigger(sub, true)) {
chosenList.add(sub);
if (chosenList.size() == min) {
@@ -231,7 +226,6 @@ public class CharmAi extends SpellAbilityAi {
} else {
// Standard canPlayAi()
sub.setActivatingPlayer(ai);
sub.getRestrictions().setZone(sub.getParent().getRestrictions().getZone());
if (AiPlayDecision.WillPlay == aic.canPlaySa(sub)) {
chosenList.add(sub);
if (chosenList.size() == min) {
@@ -255,15 +249,6 @@ public class CharmAi extends SpellAbilityAi {
return Aggregates.random(opponents);
}
@Override
protected boolean doTriggerAINoCost(final Player aiPlayer, final SpellAbility sa, final boolean mandatory) {
// already done by chooseOrderOfSimultaneousStackEntry
if (sa.getChosenList() != null) {
return true;
}
return super.doTriggerAINoCost(aiPlayer, sa, mandatory);
}
@Override
public boolean chkDrawbackWithSubs(Player aiPlayer, AbilitySub ab) {
// choices were already targeted

View File

@@ -9,7 +9,6 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
@@ -19,12 +18,9 @@ import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;
@@ -43,7 +39,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {
if ("Khans".equals(aiLogic) || "Dragons".equals(aiLogic)) {
return true;
} else if (aiLogic.startsWith("Fabricate") || "Riot".equals(aiLogic)) {
} else if ("Riot".equals(aiLogic)) {
return true;
} else if ("Pump".equals(aiLogic) || "BestOption".equals(aiLogic)) {
for (AbilitySub sb : sa.getAdditionalAbilityList("Choices")) {
@@ -265,83 +261,6 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
}
// if unsure, random?
return Aggregates.random(spells);
} else if (logic.startsWith("Fabricate")) {
final int n = Integer.valueOf(logic.substring("Fabricate".length()));
if(spells.size() < 2) {
// If the creature is no longer on the battlefield, the option
// to add counters is already removed at this point. Return the
// only available option: create servo tokens.
return spells.get(0);
}
SpellAbility counterSA = spells.get(0), tokenSA = spells.get(1);
// check for something which might prevent the counters to be placed on host
if (!host.canReceiveCounters(CounterEnumType.P1P1)) {
return tokenSA;
}
// if host would leave the play or if host is useless, create tokens
if (host.hasSVar("EndOfTurnLeavePlay") || ComputerUtilCard.isUselessCreature(player, host)) {
return tokenSA;
}
// need a copy for one with extra +1/+1 counter boost,
// without causing triggers to run
final Card copy = CardUtil.getLKICopy(host);
copy.setCounters(CounterEnumType.P1P1, copy.getCounters(CounterEnumType.P1P1) + n);
copy.setZone(host.getZone());
// if host would put into the battlefield attacking
if (combat != null && combat.isAttacking(host)) {
final Player defender = combat.getDefenderPlayerByAttacker(host);
if (defender.canLoseLife() && !ComputerUtilCard.canBeBlockedProfitably(defender, copy, true)) {
return counterSA;
}
return tokenSA;
}
// if the host has haste and can attack
if (CombatUtil.canAttack(copy)) {
for (final Player opp : player.getOpponents()) {
if (CombatUtil.canAttack(copy, opp) &&
opp.canLoseLife() &&
!ComputerUtilCard.canBeBlockedProfitably(opp, copy, true))
return counterSA;
}
}
// TODO check for trigger to turn token ETB into +1/+1 counter for host
// TODO check for trigger to turn token ETB into damage or life loss for opponent
// in this cases Token might be prefered even if they would not survive
final Card tokenCard = TokenAi.spawnToken(player, tokenSA);
// Token would not survive
if (!tokenCard.isCreature() || tokenCard.getNetToughness() < 1) {
return counterSA;
}
// Special Card logic, this one try to median its power with the number of artifacts
if ("Marionette Master".equals(sourceName)) {
CardCollection list = CardLists.filter(player.getCardsIn(ZoneType.Battlefield), Presets.ARTIFACTS);
return list.size() >= copy.getNetPower() ? counterSA : tokenSA;
} else if ("Cultivator of Blades".equals(sourceName)) {
// Cultivator does try to median with number of Creatures
CardCollection list = player.getCreaturesInPlay();
return list.size() >= copy.getNetPower() ? counterSA : tokenSA;
}
// evaluate Creature with +1/+1
int evalCounter = ComputerUtilCard.evaluateCreature(copy);
final CardCollection tokenList = new CardCollection(host);
for (int i = 0; i < n; ++i) {
tokenList.add(TokenAi.spawnToken(player, tokenSA));
}
// evaluate Host with Tokens
int evalToken = ComputerUtilCard.evaluateCreatureList(tokenList);
return evalToken >= evalCounter ? tokenSA : counterSA;
} else if ("CombustibleGearhulk".equals(logic)) {
Player controller = sa.getActivatingPlayer();
List<ZoneType> zones = ZoneType.listValueOf("Graveyard, Battlefield, Exile");

View File

@@ -3,6 +3,7 @@ package forge;
import forge.item.PaperCard;
import forge.util.FileUtil;
import forge.util.TextUtil;
import forge.util.ThreadUtil;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
@@ -30,6 +31,7 @@ public final class ImageKeys {
private static Map<String, String> CACHE_CARD_PICS_SUBDIR;
private static Map<String, Boolean> editionImageLookup = new HashMap<>();
private static Set<String> toFind = new HashSet<>();
private static boolean isLibGDXPort = false;
@@ -109,7 +111,8 @@ public final class ImageKeys {
filename = key;
dir = CACHE_CARD_PICS_DIR;
}
if (toFind.contains(filename))
return null;
if (missingCards.contains(filename))
return null;
@@ -171,10 +174,20 @@ public final class ImageKeys {
return file;
}
//setlookup
file = setLookUpFile(filename, fullborderFile);
if (file != null) {
cachedCards.put(filename, file);
return file;
if (hasSetLookup(filename)) {
toFind.add(filename);
try {
ThreadUtil.getServicePool().submit(() -> {
File f = setLookUpFile(filename, fullborderFile);
if (f != null)
cachedCards.put(filename, f);
else //is null
missingCards.add(filename);
toFind.remove(filename);
});
} catch (Exception e) {
toFind.remove(filename);
}
}
}
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
@@ -250,7 +263,7 @@ public final class ImageKeys {
// System.out.println("File not found, no image created: " + key);
//add missing cards - disable for desktop version for compatibility reasons with autodownloader
if (isLibGDXPort)
if (isLibGDXPort && !hasSetLookup(filename)) //missing cards with setlookup is handled differently
missingCards.add(filename);
return null;
}
@@ -260,34 +273,44 @@ public final class ImageKeys {
? StaticData.instance().getEditions().getCode2ByCode(edition) // by default 2-letter codes from MWS are used
: CACHE_CARD_PICS_SUBDIR.get(edition); // may use custom paths though
}
private static File setLookUpFile(String filename, String fullborderFile) {
public static boolean hasSetLookup(String filename) {
if (!StaticData.instance().getSetLookup().isEmpty()) {
return StaticData.instance().getSetLookup().keySet().stream().anyMatch(setKey -> filename.startsWith(setKey));
}
return false;
}
public static File setLookUpFile(String filename, String fullborderFile) {
if (!StaticData.instance().getSetLookup().isEmpty()) {
for (String setKey : StaticData.instance().getSetLookup().keySet()) {
if (filename.startsWith(setKey)) {
for (String setLookup : StaticData.instance().getSetLookup().get(setKey)) {
String lookupDirectory = CACHE_CARD_PICS_DIR + setLookup;
File f = new File(lookupDirectory);
String[] cardNames = f.list();
if (cardNames != null) {
Set<String> cardList = new HashSet<>(Arrays.asList(cardNames));
if (f.exists() && f.isDirectory()) {
for (String ext : FILE_EXTENSIONS) {
if (ext.equals(""))
continue;
File placeholder;
String fb1 = fullborderFile.replace(setKey+"/","")+ext;
if (cardList.contains(fb1)) {
return new File(lookupDirectory+"/"+fb1);
placeholder = new File(lookupDirectory+"/"+fb1);
if (placeholder.exists()) {
return placeholder;
}
String fb2 = fullborderFile.replace(setKey+"/","").replaceAll("[0-9]*.fullborder", "1.fullborder")+ext;
if (cardList.contains(fb2)) {
return new File(lookupDirectory+"/"+fb2);
placeholder = new File(lookupDirectory+"/"+fb2);
if (placeholder.exists()) {
return placeholder;
}
String f1 = filename.replace(setKey+"/","")+ext;
if (cardList.contains(f1)) {
return new File(lookupDirectory+"/"+f1);
placeholder = new File(lookupDirectory+"/"+f1);
if (placeholder.exists()) {
return placeholder;
}
String f2 = filename.replace(setKey+"/","").replaceAll("[0-9]*.full", "1.full")+ext;
if (cardList.contains(f2)) {
return new File(lookupDirectory+"/"+f2);
placeholder = new File(lookupDirectory+"/"+f2);
if (placeholder.exists()) {
return placeholder;
}
}
}

View File

@@ -8,9 +8,11 @@ import forge.card.PrintSheet;
import forge.item.*;
import forge.token.TokenDb;
import forge.util.FileUtil;
import forge.util.ImageUtil;
import forge.util.TextUtil;
import forge.util.storage.IStorage;
import forge.util.storage.StorageBase;
import org.apache.commons.lang3.tuple.Pair;
import java.io.File;
import java.util.*;
@@ -45,6 +47,7 @@ public class StaticData {
private boolean allowCustomCardsInDecksConformance;
private boolean enableSmartCardArtSelection;
private boolean loadNonLegalCards;
// Loaded lazily:
private IStorage<SealedProduct.Template> boosters;
@@ -74,6 +77,7 @@ public class StaticData {
this.customCardReader = customCardReader;
this.allowCustomCardsInDecksConformance = allowCustomCardsInDecksConformance;
this.enableSmartCardArtSelection = enableSmartCardArtSelection;
this.loadNonLegalCards = loadNonLegalCards;
lastInstance = this;
List<String> funnyCards = new ArrayList<>();
List<String> filtered = new ArrayList<>();
@@ -752,6 +756,129 @@ public class StaticData {
preferences_avails[i] = prettifyCardArtPreferenceName(preferences[i]);
return preferences_avails;
}
public Pair<Integer, Integer> audit(StringBuffer noImageFound, StringBuffer cardNotImplemented) {
int missingCount = 0;
int notImplementedCount = 0;
for (CardEdition e : editions) {
if (CardEdition.Type.FUNNY.equals(e.getType()))
continue;
boolean nifHeader = false;
boolean cniHeader = false;
boolean tokenHeader = false;
String imagePath;
int artIndex = 1;
HashMap<String, Pair<Boolean, Integer>> cardCount = new HashMap<>();
for (CardEdition.CardInSet c : e.getAllCardsInSet()) {
if (cardCount.containsKey(c.name)) {
cardCount.put(c.name, Pair.of(c.collectorNumber.startsWith("F"), cardCount.get(c.name).getRight() + 1));
} else {
cardCount.put(c.name, Pair.of(c.collectorNumber.startsWith("F"), 1));
}
}
// loop through the cards in this edition, considering art variations...
for (Map.Entry<String, Pair<Boolean, Integer>> entry : cardCount.entrySet()) {
String c = entry.getKey();
artIndex = entry.getValue().getRight();
PaperCard cp = getCommonCards().getCard(c, e.getCode(), artIndex);
if (cp == null) {
cp = getVariantCards().getCard(c, e.getCode(), artIndex);
}
if (cp == null) {
if (entry.getValue().getLeft()) //skip funny cards
continue;
if (!loadNonLegalCards && CardEdition.Type.FUNNY.equals(e.getType()))
continue;
if (!cniHeader) {
cardNotImplemented.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
cniHeader = true;
}
cardNotImplemented.append(" ").append(c).append("\n");
notImplementedCount++;
continue;
}
// check the front image
imagePath = ImageUtil.getImageRelativePath(cp, false, true, false);
if (imagePath != null) {
File file = ImageKeys.getImageFile(imagePath);
if (file == null && ImageKeys.hasSetLookup(imagePath))
file = ImageKeys.setLookUpFile(imagePath, imagePath+"border");
if (file == null) {
if (!nifHeader) {
noImageFound.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
nifHeader = true;
}
noImageFound.append(" ").append(imagePath).append("\n");
missingCount++;
}
}
// check the back face
if (cp.hasBackFace()) {
imagePath = ImageUtil.getImageRelativePath(cp, true, true, false);
if (imagePath != null) {
File file = ImageKeys.getImageFile(imagePath);
if (file == null && ImageKeys.hasSetLookup(imagePath))
file = ImageKeys.setLookUpFile(imagePath, imagePath+"border");
if (file == null) {
if (!nifHeader) {
noImageFound.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
nifHeader = true;
}
noImageFound.append(" ").append(imagePath).append("\n");
missingCount++;
}
}
}
}
// TODO: Audit token images here...
for(Map.Entry<String, Integer> tokenEntry : e.getTokens().entrySet()) {
String name = tokenEntry.getKey();
artIndex = tokenEntry.getValue();
try {
PaperToken token = getAllTokens().getToken(name, e.getCode());
if (token == null) {
continue;
}
for(int i = 0; i < artIndex; i++) {
String imgKey = token.getImageKey(i);
File file = ImageKeys.getImageFile(imgKey);
if (file == null) {
if (!nifHeader) {
noImageFound.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
nifHeader = true;
}
if (!tokenHeader) {
noImageFound.append("\nTOKENS\n");
tokenHeader = true;
}
noImageFound.append(" ").append(token.getImageFilename(i + 1)).append("\n");
missingCount++;
}
}
} catch(Exception ex) {
System.out.println("No Token found: " + name + " in " + e.getName());
}
}
if (nifHeader)
noImageFound.append("\n");
}
String totalStats = "Missing images: " + missingCount + "\nUnimplemented cards: " + notImplementedCount + "\n";
cardNotImplemented.append("\n-----------\n");
cardNotImplemented.append(totalStats);
cardNotImplemented.append("-----------\n\n");
noImageFound.append(cardNotImplemented); // combine things together...
return Pair.of(missingCount, notImplementedCount);
}
private String prettifyCardArtPreferenceName(CardDb.CardArtPreference preference) {
StringBuilder label = new StringBuilder();

View File

@@ -53,6 +53,27 @@ public class ThreadUtil {
return Thread.currentThread().getName().startsWith("Game");
}
private static ExecutorService service = Executors.newWorkStealingPool();
public static ExecutorService getServicePool() {
return service;
}
public static void refreshServicePool() {
service = Executors.newWorkStealingPool();
}
public static <T> T limit(Callable<T> task, long millis){
Future<T> future = null;
T result;
try {
future = service.submit(task);
result = future.get(millis, TimeUnit.MILLISECONDS);
} catch (Exception e) {
result = null;
} finally {
if (future != null)
future.cancel(true);
}
return result;
}
public static <T> T executeWithTimeout(Callable<T> task, int milliseconds) {
ExecutorService executor = Executors.newCachedThreadPool();
Future<T> future = executor.submit(task);

View File

@@ -53,6 +53,7 @@ import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CardView;
import forge.game.card.CardZoneTable;
import forge.game.card.CounterType;
import forge.game.combat.Combat;
import forge.game.event.Event;
@@ -120,6 +121,8 @@ public class Game {
private CardCollection lastStateBattlefield = new CardCollection();
private CardCollection lastStateGraveyard = new CardCollection();
private CardZoneTable untilHostLeavesPlayTriggerList = new CardZoneTable();
private Table<CounterType, Player, List<Pair<Card, Integer>>> countersAddedThisTurn = HashBasedTable.create();
private FCollection<CardDamageHistory> globalDamageHistory = new FCollection<>();
@@ -187,6 +190,10 @@ public class Game {
initiative = p;
}
public CardZoneTable getUntilHostLeavesPlayTriggerList() {
return untilHostLeavesPlayTriggerList;
}
public CardCollectionView getLastStateBattlefield() {
return lastStateBattlefield;
}

View File

@@ -162,14 +162,32 @@ public class GameAction {
// need to check before it enters
if (c.isAura() && !c.isAttachedToEntity() && toBattlefield && (zoneFrom == null || !zoneFrom.is(ZoneType.Stack))) {
boolean found = false;
if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c, null))) {
found = true;
try {
if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c, null))) {
found = true;
}
} catch (Exception e1) {
found = false;
}
else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(c, null))) {
found = true;
if (!found) {
try {
if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(c, null))) {
found = true;
}
} catch (Exception e2) {
found = false;
}
}
else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(c, null))) {
found = true;
if (!found) {
try {
if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(c, null))) {
found = true;
}
} catch (Exception e3) {
found = false;
}
}
if (!found) {
c.clearControllers();
@@ -341,8 +359,10 @@ public class GameAction {
if (commanderEffect != null) break;
}
// Disable the commander replacement effect
for (final ReplacementEffect re : commanderEffect.getReplacementEffects()) {
re.setSuppressed(true);
if (commanderEffect != null) {
for (final ReplacementEffect re : commanderEffect.getReplacementEffects()) {
re.setSuppressed(true);
}
}
}
@@ -2315,14 +2335,16 @@ public class GameAction {
final Player p = e.getKey();
final CardCollection toTop = e.getValue().getLeft();
final CardCollection toBottom = e.getValue().getRight();
final int numLookedAt = toTop.size() + toBottom.size();
int numLookedAt = 0;
if (toTop != null) {
numLookedAt += toTop.size();
Collections.reverse(toTop); // reverse to get the correct order
for (Card c : toTop) {
moveToLibrary(c, cause, null);
}
}
if (toBottom != null) {
numLookedAt += toBottom.size();
for (Card c : toBottom) {
moveToBottomOfLibrary(c, cause, null);
}
@@ -2390,6 +2412,9 @@ public class GameAction {
}
}
// for Zangief do this before runWaitingTriggers DamageDone
damageMap.triggerExcessDamage(isCombat, lethalDamage, game);
// lose life simultaneously
if (isCombat) {
for (Player p : game.getPlayers()) {
@@ -2418,7 +2443,6 @@ public class GameAction {
preventMap.clear();
damageMap.triggerDamageDoneOnce(isCombat, game);
damageMap.triggerExcessDamage(isCombat, lethalDamage, game);
damageMap.clear();
counterTable.replaceCounterEffect(game, cause, !isCombat);

View File

@@ -34,6 +34,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.CardPlayOption.PayManaCost;
import forge.game.cost.Cost;
import forge.game.cost.CostPayment;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
import forge.game.player.Player;
@@ -842,4 +843,46 @@ public final class GameActionUtil {
c.getGame().getTriggerHandler().resetActiveTriggers();
}
public static void rollbackAbility(SpellAbility ability, final Zone fromZone, final int zonePosition, CostPayment payment, Card oldCard) {
// cancel ability during target choosing
final Game game = ability.getActivatingPlayer().getGame();
if (fromZone != null) { // and not a copy
oldCard.setCastSA(null);
oldCard.setCastFrom(null);
// add back to where it came from, hopefully old state
// skip GameAction
oldCard.getZone().remove(oldCard);
fromZone.add(oldCard, zonePosition >= 0 ? Integer.valueOf(zonePosition) : null);
ability.setHostCard(oldCard);
ability.setXManaCostPaid(null);
ability.setSpendPhyrexianMana(false);
if (ability.hasParam("Announce")) {
for (final String aVar : ability.getParam("Announce").split(",")) {
final String varName = aVar.trim();
if (!varName.equals("X")) {
ability.setSVar(varName, "0");
}
}
}
// better safe than sorry approach in case rolled back ability was copy (from addExtraKeywordCost)
for (SpellAbility sa : oldCard.getSpells()) {
sa.setHostCard(oldCard);
}
//for Chorus of the Conclave
ability.rollback();
oldCard.setBackSide(false);
oldCard.setState(oldCard.getFaceupCardStateName(), true);
oldCard.unanimateBestow();
}
ability.clearTargets();
ability.resetOnceResolved();
payment.refundPayment();
game.getStack().clearFrozen();
game.getTriggerHandler().clearWaitingTriggers();
}
}

View File

@@ -277,7 +277,7 @@ public final class AbilityFactory {
}
}
if (api == ApiType.Charm || api == ApiType.GenericChoice || api == ApiType.AssignGroup) {
if (api == ApiType.Charm || api == ApiType.GenericChoice || api == ApiType.AssignGroup) {
final String key = "Choices";
if (mapParams.containsKey(key)) {
List<String> names = Lists.newArrayList(mapParams.get(key).split(","));
@@ -426,7 +426,9 @@ public final class AbilityFactory {
private static final void makeRestrictions(final SpellAbility sa) {
// SpellAbilityRestrictions should be added in here
final SpellAbilityRestriction restrict = sa.getRestrictions();
restrict.setRestrictions(sa.getMapParams());
if (restrict != null) {
restrict.setRestrictions(sa.getMapParams());
}
}
/**
@@ -438,7 +440,7 @@ public final class AbilityFactory {
* a {@link forge.game.spellability.SpellAbility} object.
*/
private static final void makeConditions(final SpellAbility sa) {
// SpellAbilityRestrictions should be added in here
// SpellAbilityConditions should be added in here
final SpellAbilityCondition condition = sa.getConditions();
condition.setConditions(sa.getMapParams());
}

View File

@@ -29,7 +29,6 @@ public enum AbilityKey {
Blockers("Blockers"),
CanReveal("CanReveal"),
CastSA("CastSA"),
CastSACMC("CastSACMC"),
Card("Card"),
Cards("Cards"),
CardLKI("CardLKI"),

View File

@@ -163,17 +163,15 @@ public class AbilityUtils {
return cards;
}
}
else if (defined.equals("Targeted") && sa instanceof SpellAbility) {
else if ((defined.equals("Targeted") || defined.equals("TargetedCard")) && sa instanceof SpellAbility) {
for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) {
Iterables.addAll(cards, tc.getTargetCards());
}
}
else if (defined.equals("TargetedSource") && sa instanceof SpellAbility) {
for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) {
for (SpellAbility s : tc.getTargetSpells()) {
for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) for (SpellAbility s : tc.getTargetSpells()) {
cards.add(s.getHostCard());
}
}
}
else if (defined.equals("ThisTargetedCard") && sa instanceof SpellAbility) { // do not add parent targeted
if (((SpellAbility)sa).getTargets() != null) {
@@ -285,7 +283,7 @@ public class AbilityUtils {
System.err.println("Warning: couldn't find trigger SA in the chain of SpellAbility " + sa);
}
} else if (defined.equals("FirstRemembered")) {
Object o = Iterables.getFirst(hostCard.getRemembered(), null);
Object o = hostCard.getFirstRemembered();
if (o != null && o instanceof Card) {
cards.add(game.getCardState((Card) o));
}
@@ -544,6 +542,9 @@ public class AbilityUtils {
}
} else if (calcX[0].equals("OriginalHost")) {
val = xCount(ability.getOriginalHost(), calcX[1], ability);
} else if (calcX[0].equals("LastStateBattlefield") && ability instanceof SpellAbility) {
Card c = ((SpellAbility) ability).getLastStateBattlefield().get(card);
val = c == null ? 0 : xCount(c, calcX[1], ability);
} else if (calcX[0].startsWith("Remembered")) {
// Add whole Remembered list to handlePaid
final CardCollection list = new CardCollection();
@@ -687,10 +688,9 @@ public class AbilityUtils {
Object o = root.getTriggeringObject(AbilityKey.fromString(calcX[0].substring(9)));
val = o instanceof Player ? playerXProperty((Player) o, calcX[1], card, ability) : 0;
}
else if (calcX[0].equals("TriggeredSpellAbility")) {
final SpellAbility root = sa.getRootAbility();
SpellAbility sat = (SpellAbility) root.getTriggeringObject(AbilityKey.SpellAbility);
val = calculateAmount(sat.getHostCard(), calcX[1], sat);
else if (calcX[0].equals("TriggeredSpellAbility") || calcX[0].equals("TriggeredStackInstance") || calcX[0].equals("SpellTargeted")) {
final SpellAbility sat = getDefinedSpellAbilities(card, calcX[0], sa).get(0);
val = xCount(sat.getHostCard(), calcX[1], sat);
}
else if (calcX[0].startsWith("TriggerCount")) {
// TriggerCount is similar to a regular Count, but just
@@ -730,7 +730,7 @@ public class AbilityUtils {
else if (calcX[0].startsWith("Discarded")) {
final SpellAbility root = sa.getRootAbility();
list = root.getPaidList("Discarded");
if ((null == list) && root.isTrigger()) {
if (null == list && root.isTrigger()) {
list = root.getHostCard().getSpellPermanent().getPaidList("Discarded");
}
}
@@ -973,7 +973,7 @@ public class AbilityUtils {
final Player player = sa instanceof SpellAbility ? ((SpellAbility)sa).getActivatingPlayer() : card.getController();
if (defined.equals("Self") || defined.equals("ThisTargetedCard") || defined.startsWith("Valid") || getPaidCards(sa, defined) != null) {
if (defined.equals("Self") || defined.equals("TargetedCard") || defined.equals("ThisTargetedCard") || defined.startsWith("Valid") || getPaidCards(sa, defined) != null) {
// do nothing, Self is for Cards, not Players
} else if (defined.equals("TargetedOrController")) {
players.addAll(getDefinedPlayers(card, "Targeted", sa));
@@ -1849,7 +1849,7 @@ public class AbilityUtils {
return doXMath(0, expr, c, ctb);
}
}
list = CardLists.getValidCards(list, k[1], sa.getActivatingPlayer(), c, sa);
list = CardLists.getValidCards(list, k[1], player, c, sa);
return doXMath(list.size(), expr, c, ctb);
}
@@ -1873,7 +1873,7 @@ public class AbilityUtils {
return doXMath(0, expr, c, ctb);
}
}
list = CardLists.getValidCards(list, k[1], sa.getActivatingPlayer(), c, sa);
list = CardLists.getValidCards(list, k[1], player, c, sa);
return doXMath(list.size(), expr, c, ctb);
}
@@ -1901,14 +1901,14 @@ public class AbilityUtils {
// fallback if ctb isn't a spellability
if (sq[0].startsWith("LastStateBattlefield")) {
final String[] k = l[0].split(" ");
CardCollection list = new CardCollection(game.getLastStateBattlefield());
CardCollectionView list = game.getLastStateBattlefield();
list = CardLists.getValidCards(list, k[1], player, c, ctb);
return doXMath(list.size(), expr, c, ctb);
}
if (sq[0].startsWith("LastStateGraveyard")) {
final String[] k = l[0].split(" ");
CardCollection list = new CardCollection(game.getLastStateGraveyard());
CardCollectionView list = game.getLastStateGraveyard();
list = CardLists.getValidCards(list, k[1], player, c, ctb);
return doXMath(list.size(), expr, c, ctb);
}
@@ -2167,17 +2167,22 @@ public class AbilityUtils {
// Count$CardManaCost
if (sq[0].contains("CardManaCost")) {
Card ce;
if (sq[0].contains("Equipped") && c.isEquipping()) {
ce = c.getEquipping();
}
else if (sq[0].contains("Remembered")) {
if (sq[0].contains("Remembered")) {
ce = (Card) c.getFirstRemembered();
}
else {
ce = c;
}
return doXMath(ce == null ? 0 : ce.getCMC(), expr, c, ctb);
int cmc = ce == null ? 0 : ce.getCMC();
if (sq[0].contains("LKI") && ctb instanceof SpellAbility && ce != null && !ce.isInZone(ZoneType.Stack) && ce.getManaCost() != null) {
if (((SpellAbility) ctb).getXManaCostPaid() != null) {
cmc += ((SpellAbility) ctb).getXManaCostPaid() * ce.getManaCost().countX();
}
}
return doXMath(cmc, expr, c, ctb);
}
if (sq[0].startsWith("RememberedSize")) {
@@ -3481,7 +3486,8 @@ public class AbilityUtils {
}
if (value.equals("OpponentsAttackedThisCombat")) {
return doXMath(game.getCombat().getAttackedOpponents(player).size(), m, source, ctb);
int amount = game.getCombat() == null ? 0 : game.getCombat().getAttackedOpponents(player).size();
return doXMath(amount, m, source, ctb);
}
if (value.equals("DungeonsCompleted")) {

View File

@@ -657,7 +657,6 @@ public abstract class SpellAbilityEffect {
if (untilCards.isEmpty()) {
return;
}
CardZoneTable untilTable = new CardZoneTable();
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
moveParams.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield());
moveParams.put(AbilityKey.LastStateGraveyard, game.copyLastStateGraveyard());
@@ -697,10 +696,9 @@ public abstract class SpellAbilityEffect {
}
// no cause there?
Card movedCard = game.getAction().moveTo(cell.getRowKey(), newCard, 0, null, moveParams);
untilTable.put(cell.getColumnKey(), cell.getRowKey(), movedCard);
game.getUntilHostLeavesPlayTriggerList().put(cell.getColumnKey(), cell.getRowKey(), movedCard);
}
}
untilTable.triggerChangesZoneAll(game, null);
}
};

View File

@@ -154,8 +154,6 @@ public class AnimateEffect extends AnimateEffectBase {
}
}
List<Card> tgts = getCardsfromTargets(sa);
if (sa.hasParam("Optional")) {

View File

@@ -1,41 +1,18 @@
package forge.game.ability.effects;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import forge.game.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.GameCommand;
import forge.card.CardStateName;
import forge.card.CardType;
import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardState;
import forge.game.card.CardUtil;
import forge.game.card.CardView;
import forge.game.card.CardZoneTable;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.event.GameEventCombatChanged;
import forge.game.player.DelayedReveal;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerCollection;
import forge.game.player.PlayerView;
import forge.game.player.*;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility;
@@ -43,13 +20,13 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.trigger.TriggerType;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.CardTranslation;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.MessageUtil;
import forge.util.TextUtil;
import forge.util.*;
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
public class ChangeZoneEffect extends SpellAbilityEffect {
@@ -689,7 +666,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
// need to be facedown before it hits the battlefield in case of Replacement Effects or Trigger
if (sa.hasParam("FaceDown")) {
gameCard.turnFaceDown(true);
setFaceDownState(gameCard, sa);
CardFactoryUtil.setFaceDownState(gameCard, sa);
}
movedCard = game.getAction().moveTo(gameCard.getController().getZone(destination), gameCard, sa, moveParams);
@@ -1345,7 +1322,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
// need to be facedown before it hits the battlefield in case of Replacement Effects or Trigger
if (sa.hasParam("FaceDown")) {
c.turnFaceDown(true);
setFaceDownState(c, sa);
CardFactoryUtil.setFaceDownState(c, sa);
}
movedCard = game.getAction().moveToPlay(c, c.getController(), sa, moveParams);
@@ -1448,6 +1425,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
}
if (ZoneType.Exile.equals(destination) && sa.hasParam("WithCountersType")) {
CounterType cType = CounterType.getType(sa.getParam("WithCountersType"));
int cAmount = AbilityUtils.calculateAmount(sa.getOriginalHost(), sa.getParamOrDefault("WithCountersAmount", "1"), sa);
GameEntityCounterTable table = new GameEntityCounterTable();
movedCard.addCounter(cType, cAmount, player, table);
table.replaceCounterEffect(game, sa, true);
}
}
if (((!ZoneType.Battlefield.equals(destination) && changeType != null && !defined && !changeType.equals("Card"))
@@ -1496,39 +1480,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
&& sa.getParam("WithTotalCMC") == null;
}
private static void setFaceDownState(Card c, SpellAbility sa) {
final Card source = sa.getHostCard();
CardState faceDown = c.getFaceDownState();
// set New Pt doesn't work because this values need to be copyable for clone effects
if (sa.hasParam("FaceDownPower")) {
faceDown.setBasePower(AbilityUtils.calculateAmount(
source, sa.getParam("FaceDownPower"), sa));
}
if (sa.hasParam("FaceDownToughness")) {
faceDown.setBaseToughness(AbilityUtils.calculateAmount(
source, sa.getParam("FaceDownToughness"), sa));
}
if (sa.hasParam("FaceDownSetType")) {
faceDown.setType(new CardType(Arrays.asList(sa.getParam("FaceDownSetType").split(" & ")), false));
}
if (sa.hasParam("FaceDownPower") || sa.hasParam("FaceDownToughness")
|| sa.hasParam("FaceDownSetType")) {
final GameCommand unanimate = new GameCommand() {
private static final long serialVersionUID = 8853789549297846163L;
@Override
public void run() {
c.clearStates(CardStateName.FaceDown, true);
}
};
c.addFaceupCommand(unanimate);
}
}
/**
* <p>
* removeFromStack.

View File

@@ -156,6 +156,11 @@ public class CharmEffect extends SpellAbilityEffect {
}
public static boolean makeChoices(SpellAbility sa) {
// CR 700.2g
if (sa.isCopied()) {
return true;
}
//this resets all previous choices
sa.setSubAbility(null);

View File

@@ -1,9 +1,8 @@
package forge.game.ability.effects;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
import com.google.common.collect.Sets;
import forge.game.player.DelayedReveal;
import forge.game.player.PlayerView;
import forge.util.CardTranslation;
@@ -119,6 +118,23 @@ public class ChooseCardEffect extends SpellAbilityEffect {
}
}
}
} else if (sa.hasParam("ChooseParty")) {
Set<String> partyTypes = Sets.newHashSet("Cleric", "Rogue", "Warrior", "Wizard");
for (final String type : partyTypes) {
CardCollection valids = CardLists.filter(p.getCardsIn(ZoneType.Battlefield),
CardPredicates.isType(type));
for (Card alreadyChosen : chosen) {
valids.remove(alreadyChosen);
}
if (!valids.isEmpty()) {
final String prompt = Localizer.getInstance().getMessage("lblChoose") + " " +
Lang.nounWithNumeralExceptOne(1, type);
Card c = p.getController().chooseSingleEntityForEffect(valids, sa, prompt, true, null);
if (c != null) {
chosen.add(c);
}
}
}
} else if (sa.hasParam("WithTotalPower")) {
final int totP = AbilityUtils.calculateAmount(host, sa.getParam("WithTotalPower"), sa);
CardCollection negativeCreats = CardLists.filterLEPower(p.getCreaturesInPlay(), -1);
@@ -187,6 +203,18 @@ public class ChooseCardEffect extends SpellAbilityEffect {
chosenPool.add(choice);
}
chosen.addAll(chosenPool);
} else if (sa.hasParam("ControlAndNot")) {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseCreature");
// Targeted player (p) chooses N creatures that belongs to them
CardCollection tgtPlayerCtrl = CardLists.filterControlledBy(choices, p);
chosen.addAll(p.getController().chooseCardsForEffect(tgtPlayerCtrl, sa, title + " " + "you control", minAmount, validAmount,
!sa.hasParam("Mandatory"), null));
// Targeted player (p) chooses N creatures that don't belong to them
CardCollection notTgtPlayerCtrl = new CardCollection(choices);
notTgtPlayerCtrl.removeAll(tgtPlayerCtrl);
chosen.addAll(p.getController().chooseCardsForEffect(notTgtPlayerCtrl, sa, title + " " + "you don't control", minAmount, validAmount,
!sa.hasParam("Mandatory"), null));
} else if ((tgt == null) || p.canBeTargetedBy(sa)) {
if (sa.hasParam("AtRandom") && !choices.isEmpty()) {
Aggregates.random(choices, validAmount, chosen);
@@ -217,8 +245,13 @@ public class ChooseCardEffect extends SpellAbilityEffect {
}
}
}
if (sa.hasParam("Reveal")) {
game.getAction().reveal(chosen, p, true, Localizer.getInstance().getMessage("lblChosenCards") + " ");
if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) {
game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " ");
}
}
if(sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) {
for (final Player p : tgtPlayers) {
game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " ");
}
}
host.setChosenCards(chosen);

View File

@@ -50,7 +50,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
List<SpellAbility> saToRemove = Lists.newArrayList();
for (SpellAbility saChoice : abilities) {
if (!saChoice.getRestrictions().checkOtherRestrictions(host, saChoice, sa.getActivatingPlayer()) ) {
if (saChoice.getRestrictions() != null && !saChoice.getRestrictions().checkOtherRestrictions(host, saChoice, sa.getActivatingPlayer())) {
saToRemove.add(saChoice);
} else if (saChoice.hasParam("UnlessCost")) {
// generic check for if the cost can be paid

View File

@@ -124,11 +124,12 @@ public class ControlGainEffect extends SpellAbilityEffect {
sa.getParam("Chooser"), sa).get(0) : activator;
CardCollectionView choices = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield),
sa.getParam("Choices"), activator, source, sa);
if (!choices.isEmpty()) {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") :
Localizer.getInstance().getMessage("lblChooseaCard") +" ";
tgtCards = chooser.getController().chooseCardsForEffect(choices, sa, title, 1, 1, false, null);
if (choices.isEmpty()) {
return;
}
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") :
Localizer.getInstance().getMessage("lblChooseaCard") +" ";
tgtCards = chooser.getController().chooseCardsForEffect(choices, sa, title, 1, 1, false, null);
} else {
tgtCards = getDefinedCards(sa);
}

View File

@@ -122,8 +122,9 @@ public class CounterEffect extends SpellAbilityEffect {
CardZoneTable table = new CardZoneTable();
for (final SpellAbility tgtSA : sas) {
final Card tgtSACard = tgtSA.getHostCard();
// should remember even that spell cannot be countered, e.g. Dovescape
// TODO use LKI in case the spell gets countered before (else X amounts would be missing)
// should remember even that spell cannot be countered
// currently all effects using this are targeted in case the spell gets countered before
// so don't need to worry about LKI (else X amounts would be missing)
if (sa.hasParam("RememberCounteredCMC")) {
sa.getHostCard().addRemembered(Integer.valueOf(tgtSACard.getCMC()));
}

View File

@@ -67,8 +67,9 @@ public class CountersPutEffect extends SpellAbilityEffect {
stringBuilder.append(pronoun ? "they" : who).append(" ");
String desc = sa.getDescription();
boolean forEach = desc.contains("for each");
if (sa.hasParam("CounterTypes")) {
String desc = sa.getDescription();
if (desc.contains("Put ") && desc.contains(" on ")) {
desc = desc.substring(desc.indexOf("Put "), desc.indexOf(" on ") + 4)
.replaceFirst("Put ", "puts ");
@@ -84,8 +85,8 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
}
final int amount = AbilityUtils.calculateAmount(card,
sa.getParamOrDefault("CounterNum", "1"), sa);
final String key = forEach ? "ForEachNum" : "CounterNum";
final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault(key, "1"), sa);
if (sa.hasParam("Bolster")) {
stringBuilder.append("bolsters ").append(amount).append(".");
@@ -155,7 +156,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
}
}
stringBuilder.append(".");
stringBuilder.append(forEach ? desc.substring(desc.indexOf(" for each")) : ".");
return stringBuilder.toString();
}
@@ -495,7 +496,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
// need to unfreeze tracker
game.getTracker().unfreeze();
// check if it can recive the Tribute
// check if it can receive the Tribute
if (abort) {
continue;
}

View File

@@ -67,7 +67,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
if (revealed.equals(ZoneType.Exile)) {
sb.append("and exile all other cards revealed this way.");
}
} else {
} else if (revealed != null) {
if (revealed.equals(ZoneType.Hand)) {
sb.append("all cards revealed this way into their hand");
}
@@ -209,7 +209,9 @@ public class DigUntilEffect extends SpellAbilityEffect {
Collections.shuffle(revealed, MyRandom.getRandom());
}
if (sa.hasParam("NoneFoundDestination") && found.size() < untilAmount) {
if (sa.hasParam("NoMoveRevealed")) {
//don't do anything
} else if (sa.hasParam("NoneFoundDestination") && found.size() < untilAmount) {
// Allow ordering the revealed cards
if (noneFoundDest.isKnown() && revealed.size() >= 2) {
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa);

View File

@@ -1,6 +1,7 @@
package forge.game.ability.effects;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -144,6 +145,9 @@ public class RollDiceEffect extends SpellAbilityEffect {
sa.setSVar(sa.getParam("OtherSVar"), Integer.toString(other));
}
}
if (sa.hasParam("UseHighestRoll")) {
total = Collections.max(rolls);
}
Map<String, SpellAbility> diceAbilities = sa.getAdditionalAbilities();
SpellAbility resultAbility = null;

View File

@@ -162,6 +162,10 @@ public class SetStateEffect extends SpellAbilityEffect {
hasTransformed = gameCard.turnFaceUp(true, true, sa);
} else {
hasTransformed = gameCard.changeCardState(mode, sa.getParam("NewState"), sa);
if (gameCard.isFaceDown() && (sa.hasParam("FaceDownPower") || sa.hasParam("FaceDownToughness")
|| sa.hasParam("FaceDownSetType"))) {
CardFactoryUtil.setFaceDownState(gameCard, sa);
}
}
if (hasTransformed) {
if (sa.isMorphUp()) {

View File

@@ -256,6 +256,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private Map<Integer, Integer> damage = Maps.newHashMap();
private boolean hasBeenDealtDeathtouchDamage;
private boolean hasBeenDealtExcessDamageThisTurn;
// regeneration
private FCollection<Card> shields = new FCollection<>();
@@ -3016,7 +3017,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
public final FCollectionView<SpellAbility> getBasicSpells() {
return getBasicSpells(currentState);
}
public final FCollectionView<SpellAbility> getBasicSpells(CardState state) {
final FCollection<SpellAbility> res = new FCollection<>();
for (final SpellAbility sa : state.getNonManaAbilities()) {
@@ -5361,6 +5361,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
this.hasBeenDealtDeathtouchDamage = hasBeenDealtDeatchtouchDamage;
}
public final boolean hasBeenDealtExcessDamageThisTurn() {
return hasBeenDealtExcessDamageThisTurn;
}
public final void setHasBeenDealtExcessDamageThisTurn(final boolean bool) {
this.hasBeenDealtExcessDamageThisTurn = bool;
}
public final Map<Card, Integer> getAssignedDamageMap() {
return assignedDamageMap;
}
@@ -5515,7 +5522,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
// Defending player at the time the damage was dealt
runParams.put(AbilityKey.DefendingPlayer, game.getCombat() != null ? game.getCombat().getDefendingPlayerRelatedTo(source) : null);
getGame().getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false);
getGame().getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, true);
DamageType damageType = DamageType.Normal;
if (isPlaneswalker()) { // 120.3c
@@ -6158,6 +6165,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
setDamage(0);
}
setHasBeenDealtDeathtouchDamage(false);
setHasBeenDealtExcessDamageThisTurn(false);
setRegeneratedThisTurn(0);
resetShield();
setBecameTargetThisTurn(false);

View File

@@ -113,6 +113,7 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
int excess = sum - (damaged.getKey().hasBeenDealtDeathtouchDamage() ? 1 : damaged.getValue());
if (excess > 0) {
damaged.getKey().setHasBeenDealtExcessDamageThisTurn(true);
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.DamageTarget, damaged.getKey());

View File

@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import forge.GameCommand;
import forge.game.event.GameEventCardForetold;
import forge.game.trigger.TriggerType;
import org.apache.commons.lang3.StringUtils;
@@ -1147,29 +1148,21 @@ public class CardFactoryUtil {
+ " | ValidCard$ Card.Self | Secondary$ True"
+ " | TriggerDescription$ Fabricate " + n + " (" + inst.getReminderText() + ")";
final String choose = "DB$ GenericChoice | AILogic$ " + name;
final String counter = "DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ " + n +
" | IsPresent$ Card.StrictlySelf | SpellDescription$ Put "
+ Lang.nounWithNumeral(n, "+1/+1 counter") + " on it.";
final String token = "DB$ Token | TokenAmount$ " + n + " | TokenScript$ c_1_1_a_servo | TokenOwner$ You "
+ " | SpellDescription$ Create "
final String token = "DB$ Token | TokenAmount$ " + n + " | TokenScript$ c_1_1_a_servo"
+ " | UnlessCost$ AddCounter<" + n + "/P1P1> | UnlessPayer$ You | UnlessAI$ " + name
+ " | SpellDescription$ Fabricate - Create "
+ Lang.nounWithNumeral(n, "1/1 colorless Servo artifact creature token") + ".";
final Trigger trigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
SpellAbility saChoose = AbilityFactory.getAbility(choose, card);
List<AbilitySub> list = Lists.newArrayList();
list.add((AbilitySub)AbilityFactory.getAbility(counter, card));
list.add((AbilitySub)AbilityFactory.getAbility(token, card));
saChoose.setAdditionalAbilityList("Choices", list);
SpellAbility saChoose = AbilityFactory.getAbility(token, card);
saChoose.setIntrinsic(intrinsic);
trigger.setOverridingAbility(saChoose);
inst.addTrigger(trigger);
} else if (keyword.startsWith("Fading")) {
String upkeepTrig = "Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Secondary$ True " +
String upkeepTrig = "Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Secondary$ True" +
" | TriggerDescription$ At the beginning of your upkeep, remove a fade counter from CARDNAME. If you can't, sacrifice CARDNAME.";
final String removeCounterStr = "DB$ RemoveCounter | Defined$ Self | CounterType$ FADE | CounterNum$ 1 | RememberRemoved$ True";
@@ -3748,4 +3741,37 @@ public class CardFactoryUtil {
re.setOverridingAbility(saExile);
card.addReplacementEffect(re);
}
public static void setFaceDownState(Card c, SpellAbility sa) {
final Card source = sa.getHostCard();
CardState faceDown = c.getFaceDownState();
// set New Pt doesn't work because this values need to be copyable for clone effects
if (sa.hasParam("FaceDownPower")) {
faceDown.setBasePower(AbilityUtils.calculateAmount(
source, sa.getParam("FaceDownPower"), sa));
}
if (sa.hasParam("FaceDownToughness")) {
faceDown.setBaseToughness(AbilityUtils.calculateAmount(
source, sa.getParam("FaceDownToughness"), sa));
}
if (sa.hasParam("FaceDownSetType")) {
faceDown.setType(new CardType(Arrays.asList(sa.getParam("FaceDownSetType").split(" & ")), false));
}
if (sa.hasParam("FaceDownPower") || sa.hasParam("FaceDownToughness")
|| sa.hasParam("FaceDownSetType")) {
final GameCommand unanimate = new GameCommand() {
private static final long serialVersionUID = 8853789549297846163L;
@Override
public void run() {
c.clearStates(CardStateName.FaceDown, true);
}
};
c.addFaceupCommand(unanimate);
}
}
}

View File

@@ -607,7 +607,7 @@ public class CardProperty {
return false;
}
} else if (property.startsWith("Cloned")) {
if ((card.getCloneOrigin() == null) || !card.getCloneOrigin().equals(source)) {
if (card.getCloneOrigin() == null || !card.getCloneOrigin().equals(source)) {
return false;
}
} else if (property.startsWith("SharesCMCWith")) {
@@ -1180,6 +1180,10 @@ public class CardProperty {
if (card.getAssignedDamage(false, null) == 0) {
return false;
}
} else if (property.startsWith("wasDealtExcessDamageThisTurn")) {
if (!card.hasBeenDealtExcessDamageThisTurn()) {
return false;
}
} else if (property.startsWith("wasDealtDamageByThisGame")) {
int idx = source.getDamageHistory().getThisGameDamaged().indexOf(card);
if (idx == -1) {
@@ -1475,6 +1479,14 @@ public class CardProperty {
if (!card.getManaCost().getShortString().equals(property.substring(8))) {
return false;
}
} else if (property.equals("HasCounters")) {
if (!card.hasCounters()) {
return false;
}
} else if (property.equals("NoCounters")) {
if (card.hasCounters()) {
return false;
}
}
// syntax example: countersGE9 P1P1 or countersLT12TIME (greater number
@@ -1691,7 +1703,7 @@ public class CardProperty {
return false;
}
} else if (property.equals("hadToAttackThisCombat")) {
AttackRequirement e = game.getCombat().getAttackConstraints().getRequirements().get(card);
AttackRequirement e = combat.getAttackConstraints().getRequirements().get(card);
if (e == null || !e.hasCreatureRequirement() || !e.getAttacker().equalsWithTimestamp(card)) {
return false;
}
@@ -1807,14 +1819,6 @@ public class CardProperty {
if (!card.hasNoAbilities()) {
return false;
}
} else if (property.equals("HasCounters")) {
if (!card.hasCounters()) {
return false;
}
} else if (property.equals("NoCounters")) {
if (card.hasCounters()) {
return false;
}
} else if (property.equals("castKeyword")) {
SpellAbility castSA = card.getCastSA();
if (castSA == null) {
@@ -1937,8 +1941,16 @@ public class CardProperty {
} else if (property.startsWith("Triggered")) {
if (spellAbility instanceof SpellAbility) {
final String key = property.substring(9);
CardCollection cc = (CardCollection) ((SpellAbility)spellAbility).getTriggeringObject(AbilityKey.fromString(key));
if (cc == null || !cc.contains(card)) {
Object o = ((SpellAbility)spellAbility).getTriggeringObject(AbilityKey.fromString(key));
boolean found = false;
if (o != null) {
if (o instanceof CardCollection) {
found = ((CardCollection) o).contains(card);
} else {
found = card.equals(o);
}
}
if (!found) {
return false;
}
} else {

View File

@@ -56,7 +56,12 @@ public class CardZoneTable extends ForwardingTable<ZoneType, ZoneType, CardColle
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Cards, new CardZoneTable(this));
runParams.put(AbilityKey.Cause, cause);
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, AbilityKey.newMap(runParams), false);
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
}
final CardZoneTable untilTable = game.getUntilHostLeavesPlayTriggerList();
if (this != untilTable) {
untilTable.triggerChangesZoneAll(game, null);
untilTable.clear();
}
}

View File

@@ -141,16 +141,16 @@ public class CostPutCounter extends CostPartWithList {
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
final Card source = ability.getHostCard();
if (this.payCostFromSource()) {
return source.canReceiveCounters(this.counter);
} else {
// 3 Cards have Put a -1/-1 Counter on a Creature you control.
List<Card> typeList = CardLists.getValidCards(source.getGame().getCardsIn(ZoneType.Battlefield),
this.getType().split(";"), payer, source, ability);
typeList = CardLists.filter(typeList, CardPredicates.canReceiveCounters(this.counter));
return !typeList.isEmpty();
return source.isInPlay() && source.canReceiveCounters(this.counter);
}
// 3 Cards have Put a -1/-1 Counter on a Creature you control.
List<Card> typeList = CardLists.getValidCards(source.getGame().getCardsIn(ZoneType.Battlefield),
this.getType().split(";"), payer, source, ability);
typeList = CardLists.filter(typeList, CardPredicates.canReceiveCounters(this.counter));
return !typeList.isEmpty();
}
/*

View File

@@ -836,7 +836,6 @@ public class PhaseHandler implements java.io.Serializable {
game.getStack().onNextTurn();
game.getTriggerHandler().clearThisTurnDelayedTrigger();
game.getTriggerHandler().resetTurnTriggerState();
Player next = getNextActivePlayer();
while (next.hasLost()) {

View File

@@ -1603,6 +1603,12 @@ public class Player extends GameEntity implements Comparable<Player> {
}
}
// MilledAll trigger
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Cards, milled);
runParams.put(AbilityKey.Player, this);
game.getTriggerHandler().runTrigger(TriggerType.MilledAll, runParams, false);
return milled;
}

View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists;
@@ -44,6 +45,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardDamageMap;
import forge.game.card.CardState;
import forge.game.card.CardTraitChanges;
@@ -175,9 +177,17 @@ public class ReplacementHandler {
final Card c = preList.get(crd);
for (final ReplacementEffect replacementEffect : c.getReplacementEffects()) {
// Use "CheckLKIZone" parameter to test for effects that care abut where the card was last (e.g. Kalitas, Traitor of Ghet
Zone cardZone;
// Use "CheckLKIZone" parameter to test for effects that care about where the card was last (e.g. Kalitas, Traitor of Ghet
// getting hit by mass removal should still produce tokens).
Zone cardZone = "True".equals(replacementEffect.getParam("CheckSelfLKIZone")) ? game.getChangeZoneLKIInfo(c).getLastKnownZone() : game.getZoneOf(c);
if ("True".equals(replacementEffect.getParam("CheckSelfLKIZone"))) {
cardZone = game.getChangeZoneLKIInfo(c).getLastKnownZone();
if (cardZone.is(ZoneType.Battlefield) && runParams.containsKey(AbilityKey.LastStateBattlefield) && runParams.get(AbilityKey.LastStateBattlefield) != null && !((CardCollectionView) runParams.get(AbilityKey.LastStateBattlefield)).contains(crd)) {
continue;
}
} else {
cardZone = game.getZoneOf(c);
}
// Replacement effects that are tied to keywords (e.g. damage prevention effects - if the keyword is removed, the replacement
// effect should be inactive)
@@ -351,8 +361,8 @@ public class ReplacementHandler {
tailend = tailend.getSubAbility();
} while(tailend != null);
effectSA.setLastStateBattlefield(game.getLastStateBattlefield());
effectSA.setLastStateGraveyard(game.getLastStateGraveyard());
effectSA.setLastStateBattlefield((CardCollectionView) ObjectUtils.firstNonNull(runParams.get(AbilityKey.LastStateBattlefield), game.getLastStateBattlefield()));
effectSA.setLastStateGraveyard((CardCollectionView) ObjectUtils.firstNonNull(runParams.get(AbilityKey.LastStateGraveyard), game.getLastStateGraveyard()));
if (replacementEffect.isIntrinsic()) {
effectSA.setIntrinsic(true);
effectSA.changeText();

View File

@@ -179,7 +179,7 @@ public class AbilityManaPart implements java.io.Serializable {
if (source.isLand() && root.isManaAbility() && root.getPayCosts() != null && root.getPayCosts().hasTapCost()) {
player.setTappedLandForManaThisTurn(true);
}
} // end produceMana(String)
}
/**
* <p>
@@ -348,7 +348,7 @@ public class AbilityManaPart implements java.io.Serializable {
// "can't" zone restriction shouldn't be mixed with other restrictions
if (restriction.startsWith("CantCastSpellFrom")) {
if (!sa.isSpell()) { //
if (!sa.isSpell()) {
return true;
}
final ZoneType badZone = ZoneType.smartValueOf(restriction.substring(17));

View File

@@ -138,7 +138,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
/** The pay costs. */
private Cost payCosts;
private SpellAbilityRestriction restrictions = new SpellAbilityRestriction();
private SpellAbilityRestriction restrictions;
private SpellAbilityCondition conditions = new SpellAbilityCondition();
private AbilitySub subAbility;
@@ -179,8 +179,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private StaticAbility mayPlay;
private CardCollection lastStateBattlefield = null;
private CardCollection lastStateGraveyard = null;
private CardCollection lastStateBattlefield;
private CardCollection lastStateGraveyard;
private CardCollection rollbackEffects = new CardCollection();
@@ -214,6 +214,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
view0 = new SpellAbilityView(this);
}
view = view0;
if (!(this instanceof AbilitySub)) {
restrictions = new SpellAbilityRestriction();
}
}
@Override

View File

@@ -443,7 +443,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
if (getPresentDefined() != null) {
list = AbilityUtils.getDefinedObjects(sa.getHostCard(), getPresentDefined(), sa);
} else {
list = new FCollection<GameObject>(game.getCardsIn(getPresentZone()));
list = new FCollection<>(game.getCardsIn(getPresentZone()));
}
final int left = Iterables.size(Iterables.filter(list, GameObjectPredicates.restriction(getIsPresent().split(","), activator, c, sa)));

View File

@@ -214,7 +214,6 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
public final int getXManaPaid() {
return xManaPaid;
}
public final void setXManaPaid(int x) {
xManaPaid = x;
}
@@ -341,7 +340,6 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
public Player getActivatingPlayer() {
return activatingPlayer;
}
public void setActivatingPlayer(Player activatingPlayer0) {
if (activatingPlayer == activatingPlayer0) { return; }
activatingPlayer = activatingPlayer0;

View File

@@ -45,6 +45,7 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.CardTranslation;
import forge.util.Expressions;
import forge.util.FileSection;
import forge.util.Lang;
import forge.util.TextUtil;
@@ -89,41 +90,12 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
* @return a {@link java.util.HashMap} object.
*/
private static Map<String, String> parseParams(final String abString, final Card hostCard) {
final Map<String, String> mapParameters = Maps.newHashMap();
if (!(abString.length() > 0)) {
throw new RuntimeException("StaticEffectFactory : getAbility -- abString too short in "
+ hostCard.getName() + ": [" + abString + "]");
}
final String[] a = abString.split("\\|");
for (int aCnt = 0; aCnt < a.length; aCnt++) {
a[aCnt] = a[aCnt].trim();
}
if (!(a.length > 0)) {
throw new RuntimeException("StaticEffectFactory : getAbility -- a[] too short in " + hostCard.getName());
}
for (final String element : a) {
final String[] aa = element.split("\\$");
for (int aaCnt = 0; aaCnt < aa.length; aaCnt++) {
aa[aaCnt] = aa[aaCnt].trim();
}
if (aa.length != 2) {
final StringBuilder sb = new StringBuilder();
sb.append("StaticEffectFactory Parsing Error: Split length of ");
sb.append(element).append(" in ").append(hostCard.getName()).append(" is not 2.");
throw new RuntimeException(sb.toString());
}
mapParameters.put(aa[0], aa[1]);
}
return mapParameters;
return FileSection.parseToMap(abString, FileSection.DOLLAR_SIGN_KV_SEPARATOR);
}
/**

View File

@@ -111,12 +111,18 @@ public final class StaticAbilityContinuous {
final List<Player> affectedPlayers = StaticAbilityContinuous.getAffectedPlayers(stAb);
final Game game = hostCard.getGame();
final StaticEffect se = game.getStaticEffects().getStaticEffect(stAb);
final StaticEffects effects = game.getStaticEffects();
final StaticEffect se = effects.getStaticEffect(stAb);
se.setAffectedCards(affectedCards);
se.setAffectedPlayers(affectedPlayers);
se.setParams(params);
se.setTimestamp(hostCard.getTimestamp());
// nothing more to do
if (stAb.hasParam("Affected") && affectedPlayers.isEmpty() && affectedCards.isEmpty()) {
return affectedCards;
}
String addP = "";
int powerBonus = 0;
String addT = "";
@@ -161,7 +167,6 @@ public final class StaticAbilityContinuous {
//Global rules changes
if (layer == StaticAbilityLayer.RULES && params.containsKey("GlobalRule")) {
final StaticEffects effects = game.getStaticEffects();
effects.setGlobalRuleChange(GlobalRuleChange.fromString(params.get("GlobalRule")));
}
@@ -197,8 +202,6 @@ public final class StaticAbilityContinuous {
// update keywords with Chosen parts
final String hostCardUID = Integer.toString(hostCard.getId()); // Protection with "doesn't remove" effect
final ColorSet colorsYouCtrl = CardUtil.getColorsYouCtrl(controller);
Iterables.removeIf(addKeywords, new Predicate<String>() {
@Override
public boolean apply(String input) {
@@ -246,6 +249,8 @@ public final class StaticAbilityContinuous {
}
// two variants for Red vs. red in keyword
if (input.contains("ColorsYouCtrl") || input.contains("colorsYouCtrl")) {
final ColorSet colorsYouCtrl = CardUtil.getColorsYouCtrl(controller);
for (byte color : colorsYouCtrl) {
final String colorWord = MagicColor.toLongString(color);
String y = input.replaceAll("ColorsYouCtrl", StringUtils.capitalize(colorWord));
@@ -718,6 +723,7 @@ public final class StaticAbilityContinuous {
// add P/T bonus
if (layer == StaticAbilityLayer.MODIFYPT) {
if (addP.contains("Affected")) {
// TODO don't calculate these above if this gets used instead
powerBonus = AbilityUtils.calculateAmount(affectedCard, addP, stAb, true);
}
if (addT.contains("Affected")) {

View File

@@ -77,10 +77,6 @@ public abstract class Trigger extends TriggerReplacementBase {
private List<Object> triggerRemembered = Lists.newArrayList();
// number of times this trigger was activated this this turn
// used to handle once-per-turn triggers like Crawling Sensation
private int numberTurnActivations = 0;
private Set<PhaseType> validPhases;
private SpellAbility spawningAbility;
@@ -388,7 +384,8 @@ public abstract class Trigger extends TriggerReplacementBase {
for (Player opp : this.getHostCard().getController().getOpponents()) {
if (opp.equals(attackedP)) {
continue;
} else if (opp.getLife() > life) {
}
if (opp.getLife() > life) {
found = true;
break;
}
@@ -536,16 +533,13 @@ public abstract class Trigger extends TriggerReplacementBase {
}
public int getActivationsThisTurn() {
return this.numberTurnActivations;
return hostCard.getAbilityActivatedThisTurn(this.getOverridingAbility());
}
public void triggerRun() {
this.numberTurnActivations++;
}
// Resets the state stored each turn for per-turn and per-instance restriction
public void resetTurnState() {
this.numberTurnActivations = 0;
if (this.getOverridingAbility() != null) {
hostCard.addAbilityActivated(this.getOverridingAbility());
}
}
/** {@inheritDoc} */

View File

@@ -346,15 +346,6 @@ public class TriggerHandler {
waitingTriggers.clear();
}
public void resetTurnTriggerState() {
for (final Trigger t : activeTriggers) {
t.resetTurnState();
}
for (final Trigger t : delayedTriggers) {
t.resetTurnState();
}
}
private boolean runNonStaticTriggersForPlayer(final Player player, final TriggerWaiting wt, final List<Trigger> delayedTriggersWorkingCopy) {
final TriggerType mode = wt.getMode();
final Map<AbilityKey, Object> runParams = wt.getParams();
@@ -568,24 +559,11 @@ public class TriggerHandler {
sa.setActivatingPlayer(p);
}
if (regtrig.hasParam("RememberController")) {
host.addRemembered(sa.getActivatingPlayer());
}
if (regtrig.hasParam("RememberTriggeringCard")) {
Card triggeredCard = ((Card) sa.getTriggeringObject(AbilityKey.Card));
host.addRemembered(triggeredCard);
}
if (regtrig.hasParam("RememberKey")) {
host.addRemembered(runParams.get(AbilityKey.fromString(regtrig.getParam("RememberKey"))));
}
if (regtrig.hasParam("RememberAmount")) {
Integer amount = (Integer) sa.getTriggeringObject(AbilityKey.fromString(regtrig.getParam("RememberAmount")));
host.addRemembered(amount);
}
sa.setStackDescription(sa.toString());
Player decider = null;

View File

@@ -0,0 +1,71 @@
package forge.game.trigger;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
import java.util.Map;
/**
* <p>
* TriggerMilledAll class.
* </p>
*/
public class TriggerMilledAll extends Trigger {
/**
* <p>
* Constructor for TriggerMilledAll
* </p>
*
* @param params
* a {@link java.util.HashMap} object.
* @param host
* a {@link forge.game.card.Card} object.
* @param intrinsic
* the intrinsic
*/
public TriggerMilledAll (final Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
/** {@inheritDoc}
* @param runParams*/
@Override
public final boolean performTest(final Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) {
return false;
}
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Cards))) {
return false;
}
return true;
}
/** {@inheritDoc} */
@Override
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
CardCollection cards = (CardCollection) runParams.get(AbilityKey.Cards);
if (hasParam("ValidCard")) {
cards = CardLists.getValidCards(cards, getParam("ValidCard"), getHostCard().getController(),
getHostCard(), this);
}
sa.setTriggeringObject(AbilityKey.Cards, cards);
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player);
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ");
sb.append(sa.getTriggeringObject(AbilityKey.Player));
return sb.toString();
}
}

View File

@@ -64,8 +64,7 @@ public class TriggerScry extends Trigger {
/** {@inheritDoc} */
@Override
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player);
sa.setTriggeringObjectsFrom(runParams, AbilityKey.ScryNum);
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player, AbilityKey.ScryNum);
}
@Override

View File

@@ -313,8 +313,7 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
AbilityKey.Player,
AbilityKey.Activator,
AbilityKey.CurrentStormCount,
AbilityKey.CurrentCastSpells,
AbilityKey.CastSACMC
AbilityKey.CurrentCastSpells
);
}

View File

@@ -80,6 +80,7 @@ public enum TriggerType {
LifeGained(TriggerLifeGained.class),
LifeLost(TriggerLifeLost.class),
LosesGame(TriggerLosesGame.class),
MilledAll(TriggerMilledAll.class),
Mutates(TriggerMutates.class),
NewGame(TriggerNewGame.class),
PayCumulativeUpkeep(TriggerPayCumulativeUpkeep.class),

View File

@@ -175,21 +175,6 @@ public class WrappedAbility extends Ability {
return sa.copy();
}
@Override
public Player getActivatingPlayer() {
return sa.getActivatingPlayer();
}
@Override
public String getDescription() {
return sa.getDescription();
}
@Override
public ManaCost getMultiKickerManaCost() {
return sa.getMultiKickerManaCost();
}
@Override
public SpellAbilityRestriction getRestrictions() {
return sa.getRestrictions();
@@ -249,14 +234,18 @@ public class WrappedAbility extends Ability {
}
@Override
public AbilitySub getSubAbility() {
return sa.getSubAbility();
public void setStackDescription(final String s) {
sa.setStackDescription(s);
}
@Override
public TargetRestrictions getTargetRestrictions() {
return sa.getTargetRestrictions();
}
@Override
public void setTargetRestrictions(final TargetRestrictions tgt) {
sa.setTargetRestrictions(tgt);
}
@Override
public Card getTargetCard() {
@@ -267,6 +256,10 @@ public class WrappedAbility extends Ability {
public TargetChoices getTargets() {
return sa.getTargets();
}
@Override
public void setTargets(TargetChoices targets) {
sa.setTargets(targets);
}
@Override
public boolean isAbility() {
@@ -327,16 +320,28 @@ public class WrappedAbility extends Ability {
// sa.resetOnceResolved();
}
@Override
public Player getActivatingPlayer() {
return sa.getActivatingPlayer();
}
@Override
public void setActivatingPlayer(final Player player) {
sa.setActivatingPlayer(player);
}
@Override
public String getDescription() {
return sa.getDescription();
}
@Override
public void setDescription(final String s) {
sa.setDescription(s);
}
@Override
public ManaCost getMultiKickerManaCost() {
return sa.getMultiKickerManaCost();
}
@Override
public void setMultiKickerManaCost(final ManaCost cost) {
sa.setMultiKickerManaCost(cost);
@@ -358,25 +363,14 @@ public class WrappedAbility extends Ability {
}
@Override
public void setStackDescription(final String s) {
sa.setStackDescription(s);
public AbilitySub getSubAbility() {
return sa.getSubAbility();
}
@Override
public void setSubAbility(final AbilitySub subAbility) {
sa.setSubAbility(subAbility);
}
@Override
public void setTargetRestrictions(final TargetRestrictions tgt) {
sa.setTargetRestrictions(tgt);
}
@Override
public void setTargets(TargetChoices targets) {
sa.setTargets(targets);
}
@Override
public void setTargetCard(final Card card) {
sa.setTargetCard(card);

View File

@@ -41,7 +41,6 @@ import forge.game.GameObject;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardUtil;
@@ -72,6 +71,7 @@ import forge.util.TextUtil;
*/
public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbilityStackInstance> {
private final List<SpellAbility> simultaneousStackEntryList = Lists.newArrayList();
private final List<SpellAbility> activePlayerSAs = Lists.newArrayList();
// They don't provide a LIFO queue, so had to use a deque
private final Deque<SpellAbilityStackInstance> stack = new LinkedBlockingDeque<>();
@@ -308,7 +308,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
runParams.put(AbilityKey.Cost, sp.getPayCosts());
runParams.put(AbilityKey.Activator, sp.getActivatingPlayer());
runParams.put(AbilityKey.CastSA, si.getSpellAbility(true));
runParams.put(AbilityKey.CastSACMC, si.getSpellAbility(true).getHostCard().getCMC());
runParams.put(AbilityKey.CurrentStormCount, thisTurnCast.size());
runParams.put(AbilityKey.CurrentCastSpells, Lists.newArrayList(thisTurnCast));
@@ -825,38 +824,26 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
return false;
}
final List<SpellAbility> activePlayerSAs = Lists.newArrayList();
final List<SpellAbility> failedSAs = Lists.newArrayList();
activePlayerSAs.clear();
for (int i = 0; i < simultaneousStackEntryList.size(); i++) {
SpellAbility sa = simultaneousStackEntryList.get(i);
Player activator = sa.getActivatingPlayer();
if (sa.getApi() == ApiType.Charm) {
if (!CharmEffect.makeChoices(sa)) {
// 603.3c If no mode is chosen, the ability is removed from the stack.
failedSAs.add(sa);
continue;
}
}
if (activator == null) {
if (sa.getHostCard().getController().equals(activePlayer)) {
activePlayerSAs.add(sa);
}
} else {
if (activator.equals(activePlayer)) {
activePlayerSAs.add(sa);
}
activator = sa.getHostCard().getController();
}
if (activator.equals(activePlayer)) {
activePlayerSAs.add(sa);
}
}
simultaneousStackEntryList.removeAll(activePlayerSAs);
simultaneousStackEntryList.removeAll(failedSAs);
if (activePlayerSAs.isEmpty()) {
return false;
}
activePlayer.getController().orderAndPlaySimultaneousSa(activePlayerSAs);
activePlayerSAs.clear();
return true;
}
@@ -878,6 +865,12 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
return true;
}
}
for (final SpellAbility sa : activePlayerSAs) {
if (sa.getSourceTrigger() == triggerID) {
return true;
}
}
return false;
}

View File

@@ -212,8 +212,7 @@ public class GuiChoose {
if (selected != null) {
c.show(selected);
}
else {
} else {
c.show();
}

View File

@@ -7,9 +7,6 @@ import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
@@ -17,24 +14,17 @@ import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import forge.ImageKeys;
import forge.StaticData;
import forge.card.CardDb;
import forge.card.CardEdition;
import forge.card.CardEdition.CardInSet;
import forge.gui.SOverlayUtils;
import forge.gui.UiCommand;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
import forge.item.PaperCard;
import forge.item.PaperToken;
import forge.localinstance.properties.ForgeConstants;
import forge.localinstance.skin.FSkinProp;
import forge.screens.home.EMenuGroup;
import forge.screens.home.IVSubmenu;
import forge.screens.home.VHomeUI;
import forge.token.TokenDb;
import forge.toolbox.FButton;
import forge.toolbox.FLabel;
import forge.toolbox.FOverlay;
@@ -43,7 +33,6 @@ import forge.toolbox.FScrollPane;
import forge.toolbox.FSkin;
import forge.toolbox.FTextArea;
import forge.util.FileUtil;
import forge.util.ImageUtil;
import forge.util.Localizer;
import forge.util.RuntimeVersion;
import net.miginfocom.swing.MigLayout;
@@ -232,17 +221,8 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
* @param scr
*/
public void auditUpdate(FTextArea tar, FScrollPane scr) {
// Get top-level Forge objects
CardDb cardDb = StaticData.instance().getCommonCards();
CardDb variantDb = StaticData.instance().getVariantCards();
TokenDb tokenDb = StaticData.instance().getAllTokens();
CardEdition.Collection editions = StaticData.instance().getEditions();
int missingCount = 0;
int notImplementedCount = 0;
final StringBuffer nifSB = new StringBuffer(); // NO IMAGE FOUND BUFFER
final StringBuffer cniSB = new StringBuffer(); // CARD NOT IMPLEMENTED BUFFER
StringBuffer nifSB = new StringBuffer(); // NO IMAGE FOUND BUFFER
StringBuffer cniSB = new StringBuffer(); // CARD NOT IMPLEMENTED BUFFER
nifSB.append("\n\n-------------------\n");
nifSB.append("NO IMAGE FOUND LIST\n");
@@ -252,118 +232,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
cniSB.append("UNIMPLEMENTED CARD LIST\n");
cniSB.append("-------------------\n\n");
for (CardEdition e : editions) {
if (CardEdition.Type.FUNNY.equals(e.getType()))
continue;
boolean nifHeader = false;
boolean cniHeader = false;
boolean tokenHeader = false;
String imagePath;
int artIndex = 1;
HashMap<String, Pair<Boolean, Integer>> cardCount = new HashMap<>();
for (CardInSet c : e.getAllCardsInSet()) {
if (cardCount.containsKey(c.name)) {
cardCount.put(c.name, Pair.of(c.collectorNumber.startsWith("F"), cardCount.get(c.name).getRight() + 1));
} else {
cardCount.put(c.name, Pair.of(c.collectorNumber.startsWith("F"), 1));
}
}
// loop through the cards in this edition, considering art variations...
for (Entry<String, Pair<Boolean, Integer>> entry : cardCount.entrySet()) {
String c = entry.getKey();
artIndex = entry.getValue().getRight();
PaperCard cp = cardDb.getCard(c, e.getCode(), artIndex);
if (cp == null) {
cp = variantDb.getCard(c, e.getCode(), artIndex);
}
if (cp == null) {
if (entry.getValue().getLeft()) //skip funny cards
continue;
if (!cniHeader) {
cniSB.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
cniHeader = true;
}
cniSB.append(" ").append(c).append("\n");
notImplementedCount++;
continue;
}
// check the front image
imagePath = ImageUtil.getImageRelativePath(cp, false, true, false);
if (imagePath != null) {
File file = ImageKeys.getImageFile(imagePath);
if (file == null) {
if (!nifHeader) {
nifSB.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
nifHeader = true;
}
nifSB.append(" ").append(imagePath).append("\n");
missingCount++;
}
}
// check the back face
if (cp.hasBackFace()) {
imagePath = ImageUtil.getImageRelativePath(cp, true, true, false);
if (imagePath != null) {
File file = ImageKeys.getImageFile(imagePath);
if (file == null) {
if (!nifHeader) {
nifSB.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
nifHeader = true;
}
nifSB.append(" ").append(imagePath).append("\n");
missingCount++;
}
}
}
}
// TODO: Audit token images here...
for(Entry<String, Integer> tokenEntry : e.getTokens().entrySet()) {
String name = tokenEntry.getKey();
artIndex = tokenEntry.getValue();
try {
PaperToken token = tokenDb.getToken(name, e.getCode());
if (token == null) {
continue;
}
for(int i = 0; i < artIndex; i++) {
String imgKey = token.getImageKey(i);
File file = ImageKeys.getImageFile(imgKey);
if (file == null) {
if (!nifHeader) {
nifSB.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n");
nifHeader = true;
}
if (!tokenHeader) {
nifSB.append("\nTOKENS\n");
tokenHeader = true;
}
nifSB.append(" ").append(token.getImageFilename(i + 1)).append("\n");
missingCount++;
}
}
} catch(Exception ex) {
System.out.println("No Token found: " + name + " in " + e.getName());
}
}
if (nifHeader)
nifSB.append("\n");
}
String totalStats = "Missing images: " + missingCount + "\nUnimplemented cards: " + notImplementedCount + "\n";
cniSB.append("\n-----------\n");
cniSB.append(totalStats);
cniSB.append("-----------\n\n");
nifSB.append(cniSB); // combine things together...
Pair<Integer, Integer> totalAudit = StaticData.instance().audit(nifSB, cniSB);
tar.setText(nifSB.toString());
tar.setCaretPosition(0); // this will move scroll view to the top...
@@ -378,7 +247,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
});
scr.getParent().add(btnClipboardCopy, "w 200!, h pref+12!, center, gaptop 10");
String labelText = "<html>Missing images: " + missingCount + "<br>Unimplemented cards: " + notImplementedCount + "<br>";
String labelText = "<html>Missing images: " + totalAudit.getLeft() + "<br>Unimplemented cards: " + totalAudit.getRight() + "<br>";
final FLabel statsLabel = new FLabel.Builder().text(labelText).fontSize(15).build();
scr.getParent().add(statsLabel);

View File

@@ -55,9 +55,7 @@ import java.io.File;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Forge implements ApplicationListener {
public static final String CURRENT_VERSION = "1.6.53.001";
@@ -81,6 +79,7 @@ public class Forge implements ApplicationListener {
protected static TransitionScreen transitionScreen;
public static KeyInputAdapter keyInputAdapter;
private static boolean exited;
public boolean needsUpdate = false;
public static boolean safeToClose = true;
public static boolean magnify = false;
public static boolean magnifyToggle = true;
@@ -104,15 +103,14 @@ public class Forge implements ApplicationListener {
public static boolean enablePreloadExtendedArt = false;
public static boolean isTabletDevice = false;
public static String locale = "en-US";
public Assets cardAssets;
public Assets otherAssets;
public Assets assets;
public static boolean hdbuttons = false;
public static boolean hdstart = false;
public static boolean isPortraitMode = false;
public static boolean gameInProgress = false;
public static boolean disposeTextures = false;
public static boolean isMobileAdventureMode = false;
public static int cacheSize = 400;
public static int cacheSize = 300;
public static int totalDeviceRAM = 0;
public static int androidVersion = 0;
public static boolean autoCache = false;
@@ -126,7 +124,6 @@ public class Forge implements ApplicationListener {
public static boolean forcedEnglishonCJKMissing = false;
public static boolean adventureLoaded = false;
private static Localizer localizer;
static Map<Integer, Texture> misc = new HashMap<>();
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) {
app = new Forge();
@@ -166,8 +163,7 @@ public class Forge implements ApplicationListener {
// don't allow to read and process
ForgeConstants.SPRITE_CARDBG_FILE = "";
}
cardAssets = new Assets();
otherAssets = new Assets();
assets = new Assets();
graphics = new Graphics();
splashScreen = new SplashScreen();
frameRate = new FrameRate();
@@ -212,9 +208,9 @@ public class Forge implements ApplicationListener {
CJK_Font = prefs.getPref(FPref.UI_CJK_FONT);
if (autoCache) {
//increase cacheSize for devices with RAM more than 5GB, default is 400. Some phones have more than 10GB RAM (Mi 10, OnePlus 8, S20, etc..)
if (totalDeviceRAM > 5000) //devices with more than 10GB RAM will have 800 Cache size, 600 Cache size for morethan 5GB RAM
cacheSize = totalDeviceRAM > 10000 ? 800 : 600;
//increase cacheSize for devices with RAM more than 5GB, default is 300. Some phones have more than 10GB RAM (Mi 10, OnePlus 8, S20, etc..)
if (totalDeviceRAM > 5000) //devices with more than 10GB RAM will have 600 Cache size, 400 Cache size for morethan 5GB RAM
cacheSize = totalDeviceRAM > 10000 ? 600 : 400;
}
//init cache
ImageCache.initCache(cacheSize);
@@ -345,22 +341,6 @@ public class Forge implements ApplicationListener {
e.printStackTrace();
}
}
public static Texture getTitleBG() {
if (misc.get(0) == null) {
misc.put(0, new Texture(GuiBase.isAndroid()
? Gdx.files.internal("fallback_skin").child("title_bg_lq.png")
: Gdx.files.classpath("fallback_skin").child("title_bg_lq.png")));
}
return misc.get(0);
}
public static Texture getTransitionBG() {
if (misc.get(1) == null) {
misc.put(1, new Texture(GuiBase.isAndroid()
? Gdx.files.internal("fallback_skin").child("transition.png")
: Gdx.files.classpath("fallback_skin").child("transition.png")));
}
return misc.get(1);
}
protected void afterDbLoaded() {
destroyThis = false; //Allow back()
Gdx.input.setCatchKey(Keys.MENU, true);
@@ -801,7 +781,7 @@ public class Forge implements ApplicationListener {
@Override
public void render() {
if (showFPS)
frameRate.update();
frameRate.update(ImageCache.counter, Forge.getAssets().manager().getMemoryInMegabytes());
try {
ImageCache.allowSingleLoad();
@@ -837,8 +817,8 @@ public class Forge implements ApplicationListener {
animationBatch.setColor(1, 1, 1, 1);
animationBatch.draw(lastScreenTexture, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.setColor(1, 1, 1, 1 - (1 / transitionTime) * animationTimeout);
animationBatch.draw(getTransitionBG(), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.draw(getTransitionBG(), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.draw(getAssets().fallback_skins().get(1), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.draw(getAssets().fallback_skins().get(1), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.end();
if (animationTimeout < 0) {
currentScene.render();
@@ -857,8 +837,8 @@ public class Forge implements ApplicationListener {
animationBatch.setColor(1, 1, 1, 1);
animationBatch.draw(lastScreenTexture, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.setColor(1, 1, 1, (1 / transitionTime) * (animationTimeout + transitionTime));
animationBatch.draw(getTransitionBG(), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.draw(getTransitionBG(), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.draw(getAssets().fallback_skins().get(1), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.draw(getAssets().fallback_skins().get(1), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
animationBatch.end();
return;
}
@@ -896,6 +876,11 @@ public class Forge implements ApplicationListener {
}
}
}
//update here
if (needsUpdate) {
if (getAssets().manager().update())
needsUpdate = false;
}
graphics.end();
} catch (Exception ex) {
graphics.end();
@@ -942,6 +927,15 @@ public class Forge implements ApplicationListener {
@Override
public void resume() {
try {
Texture.setAssetManager(getAssets().manager());
needsUpdate = true;
} catch (Exception e) {
//the application context must have been recreated from its last state.
//it could be triggered by the low memory on heap on android.
needsUpdate = false;
e.printStackTrace();
}
if (MatchController.getHostedMatch() != null) {
MatchController.getHostedMatch().resume();
}
@@ -954,8 +948,7 @@ public class Forge implements ApplicationListener {
currentScreen.onClose(null);
currentScreen = null;
}
cardAssets.dispose();
otherAssets.dispose();
assets.dispose();
Dscreens.clear();
graphics.dispose();
SoundSystem.instance.dispose();
@@ -967,11 +960,8 @@ public class Forge implements ApplicationListener {
/** Retrieve assets.
* @param other if set to true returns otherAssets otherwise returns cardAssets
*/
public static Assets getAssets(boolean other) {
if (other)
return ((Forge)Gdx.app.getApplicationListener()).otherAssets;
else
return ((Forge)Gdx.app.getApplicationListener()).cardAssets;
public static Assets getAssets() {
return ((Forge)Gdx.app.getApplicationListener()).assets;
}
public static boolean switchScene(Scene newScene) {
if (currentScene != null) {

View File

@@ -16,6 +16,8 @@ import com.badlogic.gdx.utils.TimeUtils;
public class FrameRate implements Disposable{
long lastTimeCounted;
int cardsLoaded = 0;
int allocT = 0;
private float sinceChange;
private float frameRate;
private BitmapFont font;
@@ -38,7 +40,10 @@ public class FrameRate implements Disposable{
batch.setProjectionMatrix(cam.combined);
}
public void update() {
public void update(int loadedCardSize, float toAlloc) {
if (toAlloc > 300f)
allocT = (int) toAlloc;
cardsLoaded = loadedCardSize;
long delta = TimeUtils.timeSinceMillis(lastTimeCounted);
lastTimeCounted = TimeUtils.millis();
sinceChange += delta;
@@ -50,7 +55,7 @@ public class FrameRate implements Disposable{
public void render() {
batch.begin();
font.draw(batch, (int)frameRate + " fps", 3, Gdx.graphics.getHeight() - 3);
font.draw(batch, (int)frameRate + " FPS | " + cardsLoaded + " cards re/loaded - " + allocT + " vMem", 3, Gdx.graphics.getHeight() - 3);
batch.end();
}

View File

@@ -661,8 +661,10 @@ public class Graphics {
drawRoundRect(2f, borderLining(borderColor.toString()), x, y, w, h, (h-w)/12);
fillRoundRect(tintColor, x, y, w, h, (h-w)/12);
} else {
image.draw(this, x, y, w, h);
fillRoundRect(borderColor, x, y, w, h, (h-w)/10);//show corners edges
if (image != null) {
image.draw(this, x, y, w, h);
fillRoundRect(borderColor, x, y, w, h, (h - w) / 10);//show corners edges
}
}
setAlphaComposite(oldalpha);
}
@@ -672,10 +674,14 @@ public class Graphics {
setAlphaComposite(oldalpha);
}
public void drawImage(FImage image, Color borderColor, float x, float y, float w, float h) {
if (image == null)
return;
image.draw(this, x, y, w, h);
fillRoundRect(borderColor, x+1, y+1, w-1.5f, h-1.5f, (h-w)/10);//used by zoom let some edges show...
}
public void drawAvatarImage(FImage image, float x, float y, float w, float h, boolean drawGrayscale) {
if (image == null)
return;
if (!drawGrayscale) {
image.draw(this, x, y, w, h);
} else {
@@ -693,6 +699,8 @@ public class Graphics {
}
}
public void drawCardImage(FImage image, TextureRegion damage_overlay, float x, float y, float w, float h, boolean drawGrayscale, boolean damaged) {
if (image == null)
return;
if (!drawGrayscale) {
image.draw(this, x, y, w, h);
if (damage_overlay != null && damaged)
@@ -752,6 +760,8 @@ public class Graphics {
}
}
public void drawGrayTransitionImage(FImage image, float x, float y, float w, float h, boolean withDarkOverlay, float percentage) {
if (image == null)
return;
batch.end();
shaderGrayscale.bind();
shaderGrayscale.setUniformf("u_grayness", percentage);
@@ -839,6 +849,8 @@ public class Graphics {
batch.begin();
}
public void drawWarpImage(FImage image, float x, float y, float w, float h, float time) {
if (image == null)
return;
batch.end();
shaderWarp.bind();
shaderWarp.setUniformf("u_amount", 0.2f);
@@ -854,6 +866,8 @@ public class Graphics {
batch.begin();
}
public void drawUnderWaterImage(FImage image, float x, float y, float w, float h, float time, boolean withDarkOverlay) {
if (image == null)
return;
batch.end();
shaderUnderwater.bind();
shaderUnderwater.setUniformf("u_amount", 10f*time);
@@ -893,6 +907,8 @@ public class Graphics {
drawImage(image, x, y, w, h, false);
}
public void drawImage(FImage image, float x, float y, float w, float h, boolean withDarkOverlay) {
if (image == null)
return;
image.draw(this, x, y, w, h);
if(withDarkOverlay){
float oldalpha = alphaComposite;

View File

@@ -8,7 +8,6 @@ import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.utils.Array;
import com.google.common.base.Predicates;
import forge.Forge;
import forge.adventure.data.DialogData;
import forge.adventure.data.EffectData;
@@ -19,8 +18,6 @@ import forge.adventure.util.Current;
import forge.adventure.util.MapDialog;
import forge.adventure.util.Reward;
import forge.card.CardRarity;
import forge.card.CardRulesPredicates;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.item.PaperCard;
import forge.util.Aggregates;
@@ -106,10 +103,11 @@ public class EnemySprite extends CharacterSprite {
ret.add(new Reward(Reward.Type.Life, 1));
} else {
if(data.rewards != null) { //Collect standard rewards.
Deck enemyDeck = Current.latestDeck(); // By popular demand, remove basic lands from the reward pool.
CardPool deckNoBasicLands = enemyDeck.getMain().getFilteredPool(Predicates.compose(Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND), PaperCard.FN_GET_RULES));
Deck enemyDeck = Current.latestDeck();
/*// By popular demand, remove basic lands from the reward pool.
CardPool deckNoBasicLands = enemyDeck.getMain().getFilteredPool(Predicates.compose(Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND), PaperCard.FN_GET_RULES));*/
for (RewardData rdata : data.rewards) {
ret.addAll(rdata.generate(false, deckNoBasicLands.toFlatList() ));
ret.addAll(rdata.generate(false, enemyDeck == null ? null : enemyDeck.getMain().toFlatList() ));
}
}
if(rewards != null) { //Collect additional rewards.

View File

@@ -457,7 +457,8 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
onLifeTotalChangeList.emit();
}
public void defeated() {
gold=gold/2;
int percentLoss = 10;
gold=gold-(gold*percentLoss/100);
life=Math.max(1,(int)(life-(maxLife*0.2f)));
onLifeTotalChangeList.emit();
onGoldChangeList.emit();

View File

@@ -177,7 +177,17 @@ public class SaveLoadScene extends UIScene {
updateFiles();
//ensure the dialog is hidden before switching
dialog.getColor().a = 0f;
Forge.switchScene(SceneType.GameScene.instance);
Scene restoreScene = Forge.switchToLast();
if (restoreScene != null) {
restoreScene = Forge.switchToLast();
}
if (restoreScene == null) {
restoreScene = SceneType.GameScene.instance;
}
Forge.switchScene(restoreScene);
}
}

View File

@@ -133,7 +133,8 @@ public class SettingsScene extends UIScene {
Label label = Controls.newLabel(name);
label.setWrap(true);
settingGroup.row().space(5);
settingGroup.add(label).align(Align.left).pad(2, 2, 2, 5).width(100).expand();
int w = Forge.isLandscapeMode() ? 160 : 80;
settingGroup.add(label).align(Align.left).pad(2, 2, 2, 5).width(w).expand();
}
@Override

View File

@@ -83,8 +83,10 @@ public class StartScene extends UIScene {
@Override
public void enter() {
boolean hasSaveButton = WorldSave.getCurrentSave().getWorld().getData() != null;
if (hasSaveButton)
hasSaveButton = !((TileMapScene) SceneType.TileMapScene.instance).currentMap().isInMap();
if (hasSaveButton) {
TileMapScene scene = (TileMapScene) SceneType.TileMapScene.instance;
hasSaveButton = !scene.currentMap().isInMap() || scene.inTown();
}
saveButton.setVisible(hasSaveButton);
boolean hasResumeButton = WorldSave.getCurrentSave().getWorld().getData() != null;

View File

@@ -92,6 +92,10 @@ public class TileMapScene extends HudScene {
tiledMapRenderer.loadMap(map, "");
}
public boolean inTown() {
return "town".equalsIgnoreCase(rootPoint.getData().type);
}
PointOfInterest rootPoint;
String oldMap;

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
@@ -192,7 +193,8 @@ public class GameHUD extends Stage {
}
//auto follow touchpad
if (GuiBase.isAndroid() && !MapStage.getInstance().getDialogOnlyInput() && !console.isVisible()) {
if (!(Controls.actorContainsVector(miniMap,touch)) // not inside map bounds
if (!(Controls.actorContainsVector(avatar,touch)) // not inside avatar bounds
&& !(Controls.actorContainsVector(miniMap,touch)) // not inside map bounds
&& !(Controls.actorContainsVector(gamehud,touch)) //not inside gamehud bounds
&& !(Controls.actorContainsVector(menuActor,touch)) //not inside menu button
&& !(Controls.actorContainsVector(deckActor,touch)) //not inside deck button
@@ -251,23 +253,25 @@ public class GameHUD extends Stage {
mapborder.setVisible(visible);
miniMapPlayer.setVisible(visible);
gamehud.setVisible(visible);
avatarborder.setVisible(visible);
avatar.setVisible(visible);
lifePoints.setVisible(visible);
money.setVisible(visible);
blank.setVisible(visible);
if (visible) {
avatarborder.getColor().a = 1f;
avatar.getColor().a = 1f;
deckActor.getColor().a = 1f;
menuActor.getColor().a = 1f;
statsActor.getColor().a = 1f;
inventoryActor.getColor().a = 1f;
opacity = 1f;
} else {
deckActor.getColor().a = 0.5f;
menuActor.getColor().a = 0.5f;
statsActor.getColor().a = 0.5f;
inventoryActor.getColor().a = 0.5f;
opacity = 0.5f;
avatarborder.getColor().a = 0.4f;
avatar.getColor().a = 0.4f;
deckActor.getColor().a = 0.4f;
menuActor.getColor().a = 0.4f;
statsActor.getColor().a = 0.4f;
inventoryActor.getColor().a = 0.4f;
opacity = 0.4f;
}
}
@@ -317,7 +321,7 @@ public class GameHUD extends Stage {
}
class ConsoleToggleListener extends ActorGestureListener {
public ConsoleToggleListener() {
getGestureDetector().setLongPressSeconds(0.5f);
getGestureDetector().setLongPressSeconds(0.6f);
}
@Override
public boolean longPress(Actor actor, float x, float y) {
@@ -325,5 +329,12 @@ public class GameHUD extends Stage {
console.toggle();
return super.longPress(actor, x, y);
}
@Override
public void tap(InputEvent event, float x, float y, int count, int button) {
super.tap(event, x, y, count, button);
//show menu buttons if double tapping the avatar, for android devices without visible navigation buttons
if (count > 1)
showButtons();
}
}
}

View File

@@ -23,7 +23,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.Scaling;
import forge.Forge;
import forge.adventure.character.*;
@@ -43,6 +42,7 @@ import forge.sound.SoundEffectType;
import forge.sound.SoundSystem;
import java.util.HashMap;
import java.util.Map;
import static forge.adventure.util.Paths.MANA_ATLAS;
@@ -69,7 +69,7 @@ public class MapStage extends GameStage {
private final Vector2 oldPosition3 = new Vector2();
private final Vector2 oldPosition4 = new Vector2();
private boolean isLoadingMatch = false;
private ObjectMap<String, Byte> mapFlags = new ObjectMap<>(); //Stores local map flags. These aren't available outside this map.
private HashMap<String, Byte> mapFlags = new HashMap<>(); //Stores local map flags. These aren't available outside this map.
private Dialog dialog;
private Stage dialogStage;

View File

@@ -120,11 +120,11 @@ public class Config {
public TextureAtlas getAtlas(String spriteAtlas) {
String fileName = getFile(spriteAtlas).path();
if (!Forge.getAssets(true).manager.contains(fileName, TextureAtlas.class)) {
Forge.getAssets(true).manager.load(fileName, TextureAtlas.class);
Forge.getAssets(true).manager.finishLoadingAsset(fileName);
if (!Forge.getAssets().manager().contains(fileName, TextureAtlas.class)) {
Forge.getAssets().manager().load(fileName, TextureAtlas.class);
Forge.getAssets().manager().finishLoadingAsset(fileName);
}
return Forge.getAssets(true).manager.get(fileName);
return Forge.getAssets().manager().get(fileName);
}
public SettingData getSettingData()
{

View File

@@ -11,6 +11,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
import forge.Forge;
import java.util.function.Function;
@@ -18,15 +19,10 @@ import java.util.function.Function;
* Class to create ui elements in the correct style
*/
public class Controls {
private static Skin SelectedSkin = null;
private static BitmapFont defaultfont, bigfont;
static public TextButton newTextButton(String text) {
return new TextButton(text, GetSkin());
}
static public Rectangle getBoundingRect(Actor actor) {
return new Rectangle(actor.getX(),actor.getY(),actor.getWidth(),actor.getHeight());
}
static public boolean actorContainsVector (Actor actor, Vector2 point) {
@@ -56,8 +52,6 @@ public class Controls {
return ret;
}
static public TextField newTextField(String text) {
return new TextField(text, GetSkin());
}
@@ -108,32 +102,28 @@ public class Controls {
switch (fontName) {
case "blackbig":
case "big":
return bigfont;
return Forge.getAssets().advBigFont;
default:
return defaultfont;
return Forge.getAssets().advDefaultFont;
}
}
static public Skin GetSkin() {
if (SelectedSkin == null) {
SelectedSkin = new Skin();
if (Forge.getAssets().skin == null) {
Forge.getAssets().skin = new Skin();
FileHandle skinFile = Config.instance().getFile(Paths.SKIN);
FileHandle atlasFile = skinFile.sibling(skinFile.nameWithoutExtension() + ".atlas");
TextureAtlas atlas = new TextureAtlas(atlasFile);
//font
defaultfont = new BitmapFont(Config.instance().getFile(Paths.SKIN).sibling("LanaPixel.fnt"));
bigfont = new BitmapFont(Config.instance().getFile(Paths.SKIN).sibling("LanaPixel.fnt"));
bigfont.getData().setScale(2, 2);
SelectedSkin.add("default", defaultfont);
SelectedSkin.add("big", bigfont);
SelectedSkin.addRegions(atlas);
SelectedSkin.load(skinFile);
Forge.getAssets().advDefaultFont = new BitmapFont(Config.instance().getFile(Paths.SKIN).sibling("LanaPixel.fnt"));
Forge.getAssets().advBigFont = new BitmapFont(Config.instance().getFile(Paths.SKIN).sibling("LanaPixel.fnt"));
Forge.getAssets().advBigFont.getData().setScale(2, 2);
Forge.getAssets().skin.add("default", Forge.getAssets().advDefaultFont);
Forge.getAssets().skin.add("big", Forge.getAssets().advBigFont);
Forge.getAssets().skin.addRegions(atlas);
Forge.getAssets().skin.load(skinFile);
}
return SelectedSkin;
return Forge.getAssets().skin;
}
public static Label newLabel(String name) {

View File

@@ -15,6 +15,7 @@ import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.SerializationException;
import com.badlogic.gdx.utils.XmlReader;
import forge.Forge;
import java.io.File;
@@ -34,17 +35,15 @@ public class TemplateTmxMapLoader extends TmxMapLoader {
this.root = xml.parse(tmxFile);
ObjectMap<String, Texture> textures = new ObjectMap<String, Texture>();
final Array<FileHandle> textureFiles = getDependencyFileHandles(tmxFile);
for (FileHandle textureFile : textureFiles) {
Texture texture = new Texture(textureFile, parameter.generateMipMaps);
texture.setFilter(parameter.textureMinFilter, parameter.textureMagFilter);
textures.put(textureFile.path(), texture);
Forge.getAssets().tmxMap().put(textureFile.path(), texture);
}
TiledMap map = loadTiledMap(tmxFile, parameter, new ImageResolver.DirectImageResolver(textures));
map.setOwnedResources(textures.values().toArray());
TiledMap map = loadTiledMap(tmxFile, parameter, new ImageResolver.DirectImageResolver(Forge.getAssets().tmxMap()));
map.setOwnedResources(Forge.getAssets().tmxMap().values().toArray());
return map;
}

View File

@@ -1,13 +1,234 @@
package forge.assets;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetLoaderParameters;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.assets.loaders.TextureLoader;
import com.badlogic.gdx.assets.loaders.resolvers.AbsoluteFileHandleResolver;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.ObjectMap;
import forge.Forge;
import forge.gui.GuiBase;
import forge.localinstance.skin.FSkinProp;
import java.util.HashMap;
import java.util.Map;
public class Assets implements Disposable {
public AssetManager manager = new AssetManager(new AbsoluteFileHandleResolver());
private MemoryTrackingAssetManager manager = new MemoryTrackingAssetManager(new AbsoluteFileHandleResolver());
private HashMap<Integer, FSkinFont> fonts = new HashMap<>();
private HashMap<String, FImageComplex> cardArtCache = new HashMap<>(1024);
private HashMap<String, FImage> avatarImages = new HashMap<>();
private HashMap<String, FSkinImage> manaImages = new HashMap<>(128);
private HashMap<String, FSkinImage> symbolLookup = new HashMap<>(64);
private HashMap<FSkinProp, FSkinImage> images = new HashMap<>(512);
private HashMap<Integer, TextureRegion> avatars = new HashMap<>(150);
private HashMap<Integer, TextureRegion> sleeves = new HashMap<>(64);
private HashMap<Integer, TextureRegion> cracks = new HashMap<>(16);
private HashMap<Integer, TextureRegion> borders = new HashMap<>();
private HashMap<Integer, TextureRegion> deckbox = new HashMap<>();
private HashMap<Integer, TextureRegion> cursor = new HashMap<>();
private ObjectMap<Integer, BitmapFont> counterFonts = new ObjectMap<>();
private ObjectMap<String, Texture> generatedCards = new ObjectMap<>(512);
private ObjectMap<Integer, Texture> fallback_skins = new ObjectMap<>();
private ObjectMap<String, Texture> tmxMap = new ObjectMap<>();
public Skin skin;
public BitmapFont advDefaultFont, advBigFont;
public Assets() {
//init titlebg fallback
fallback_skins.put(0, new Texture(GuiBase.isAndroid()
? Gdx.files.internal("fallback_skin").child("title_bg_lq.png")
: Gdx.files.classpath("fallback_skin").child("title_bg_lq.png")));
//init transition fallback
fallback_skins.put(1, new Texture(GuiBase.isAndroid()
? Gdx.files.internal("fallback_skin").child("transition.png")
: Gdx.files.classpath("fallback_skin").child("transition.png")));
}
@Override
public void dispose() {
manager.dispose();
for (BitmapFont bitmapFont : counterFonts.values())
bitmapFont.dispose();
for (Texture texture : generatedCards.values())
texture.dispose();
for (FSkinFont fSkinFont : fonts.values())
fSkinFont.font.dispose();
for (Texture texture : fallback_skins.values())
texture.dispose();
for (Texture texture : tmxMap.values())
texture.dispose();
if (advDefaultFont != null)
advDefaultFont.dispose();
if (advBigFont != null)
advBigFont.dispose();
if (skin != null)
skin.dispose();
}
public MemoryTrackingAssetManager manager() {
if (manager == null)
manager = new MemoryTrackingAssetManager(new AbsoluteFileHandleResolver());
return manager;
}
public HashMap<Integer, FSkinFont> fonts() {
if (fonts == null)
fonts = new HashMap<>();
return fonts;
}
public HashMap<String, FImageComplex> cardArtCache() {
if (cardArtCache == null)
cardArtCache = new HashMap<>(1024);
return cardArtCache;
}
public HashMap<String, FImage> avatarImages() {
if (avatarImages == null)
avatarImages = new HashMap<>();
return avatarImages;
}
public HashMap<String, FSkinImage> manaImages() {
if (manaImages == null)
manaImages = new HashMap<>(128);
return manaImages;
}
public HashMap<String, FSkinImage> symbolLookup() {
if (symbolLookup == null)
symbolLookup = new HashMap<>(64);
return symbolLookup;
}
public HashMap<FSkinProp, FSkinImage> images() {
if (images == null)
images = new HashMap<>(512);
return images;
}
public HashMap<Integer, TextureRegion> avatars() {
if (avatars == null)
avatars = new HashMap<>(150);
return avatars;
}
public HashMap<Integer, TextureRegion> sleeves() {
if (sleeves == null)
sleeves = new HashMap<>(64);
return sleeves;
}
public HashMap<Integer, TextureRegion> cracks() {
if (cracks == null)
cracks = new HashMap<>(16);
return cracks;
}
public HashMap<Integer, TextureRegion> borders() {
if (borders == null)
borders = new HashMap<>();
return borders;
}
public HashMap<Integer, TextureRegion> deckbox() {
if (deckbox == null)
deckbox = new HashMap<>();
return deckbox;
}
public HashMap<Integer, TextureRegion> cursor() {
if (cursor == null)
cursor = new HashMap<>();
return cursor;
}
public ObjectMap<Integer, BitmapFont> counterFonts() {
if (counterFonts == null)
counterFonts = new ObjectMap<>();
return counterFonts;
}
public ObjectMap<String, Texture> generatedCards() {
if (generatedCards == null)
generatedCards = new ObjectMap<>(512);
return generatedCards;
}
public ObjectMap<Integer, Texture> fallback_skins() {
if (fallback_skins == null)
fallback_skins = new ObjectMap<>();
return fallback_skins;
}
public ObjectMap<String, Texture> tmxMap() {
if (tmxMap == null)
tmxMap = new ObjectMap<>();
return tmxMap;
}
public class MemoryTrackingAssetManager extends AssetManager {
private int currentMemory;
private Map<String, Integer> memoryPerFile;
public MemoryTrackingAssetManager(FileHandleResolver resolver) {
super(resolver);
currentMemory = 0;
memoryPerFile = new HashMap<String, Integer>();
}
@SuppressWarnings("unchecked")
private int calculateTextureSize(AssetManager assetManager, String fileName, Class type) {
if (memoryPerFile.containsKey(fileName)) {
return memoryPerFile.get(fileName);
}
Texture texture = (Texture) assetManager.get(fileName, type);
TextureData textureData = texture.getTextureData();
int textureSize = textureData.getWidth() * textureData.getHeight();
if (Forge.isTextureFilteringEnabled())
textureSize = textureSize + (textureSize/3);
switch (textureData.getFormat()) {
case RGB565:
textureSize *= 2;
break;
case RGB888:
textureSize *= 3;
break;
case RGBA4444:
textureSize *= 2;
break;
case RGBA8888:
textureSize *= 4;
break;
}
memoryPerFile.put(fileName, textureSize);
return textureSize;
}
@SuppressWarnings("unchecked")
@Override
public synchronized <T> void load(String fileName, Class<T> type, AssetLoaderParameters<T> parameter) {
if (type.equals(Texture.class)) {
if (parameter == null) {
parameter = (AssetLoaderParameters<T>) new TextureLoader.TextureParameter();
}
final AssetLoaderParameters.LoadedCallback prevCallback = parameter.loadedCallback;
parameter.loadedCallback = (assetManager, fileName1, type1) -> {
if (prevCallback != null) {
prevCallback.finishedLoading(assetManager, fileName1, type1);
}
currentMemory += calculateTextureSize(assetManager, fileName1, type1);
};
}
super.load(fileName, type, parameter);
}
@Override
public synchronized void unload(String fileName) {
super.unload(fileName);
if (memoryPerFile.containsKey(fileName)) {
currentMemory -= memoryPerFile.get(fileName);
}
}
public float getMemoryInMegabytes() {
return (float) currentMemory / 1024f / 1024f;
}
}
}

View File

@@ -25,18 +25,9 @@ import forge.screens.TransitionScreen;
import forge.toolbox.FProgressBar;
import forge.util.WordUtil;
import java.util.HashMap;
import java.util.Map;
public class FSkin {
private static final Map<FSkinProp, FSkinImage> images = new HashMap<>(512);
private static final Map<Integer, TextureRegion> avatars = new HashMap<>(150);
private static final Map<Integer, TextureRegion> sleeves = new HashMap<>(64);
private static final Map<Integer, TextureRegion> cracks = new HashMap<>(16);
private static final Map<Integer, TextureRegion> borders = new HashMap<>();
private static final Map<Integer, TextureRegion> deckbox = new HashMap<>();
private static final Map<Integer, TextureRegion> cursor = new HashMap<>();
private static Array<String> allSkins;
private static FileHandle preferredDir;
private static String preferredName;
@@ -53,27 +44,19 @@ public class FSkin {
prefs.setPref(FPref.UI_SKIN, skinName);
prefs.save();
Forge.setTransitionScreen(new TransitionScreen(new Runnable() {
@Override
public void run() {
FThreads.invokeInBackgroundThread(() -> FThreads.invokeInEdtLater(() -> {
final LoadingOverlay loader = new LoadingOverlay(Forge.getLocalizer().getMessageorUseDefault("lblRestartInFewSeconds", "Forge will restart after a few seconds..."), true);
loader.show();
FThreads.invokeInBackgroundThread(() -> {
FSkinFont.deleteCachedFiles(); //delete cached font files so font can be update for new skin
FThreads.delayInEDT(2000, new Runnable() {
@Override
public void run() {
Forge.clearTransitionScreen();
FThreads.invokeInEdtLater(() -> {
Forge.restart(true);
});
}
});
Forge.setTransitionScreen(new TransitionScreen(() -> FThreads.invokeInBackgroundThread(() -> FThreads.invokeInEdtLater(() -> {
final LoadingOverlay loader = new LoadingOverlay(Forge.getLocalizer().getMessageorUseDefault("lblRestartInFewSeconds", "Forge will restart after a few seconds..."), true);
loader.show();
FThreads.invokeInBackgroundThread(() -> {
FSkinFont.deleteCachedFiles(); //delete cached font files so font can be update for new skin
FThreads.delayInEDT(2000, () -> {
Forge.clearTransitionScreen();
FThreads.invokeInEdtLater(() -> {
Forge.restart(true);
});
}));
}
}, null, false, true));
});
});
})), null, false, true));
}
public static void loadLight(String skinName, final SplashScreen splashScreen,FileHandle prefDir) {
preferredDir = prefDir;
@@ -88,7 +71,7 @@ public class FSkin {
* the skin name
*/
public static void loadLight(String skinName, final SplashScreen splashScreen) {
AssetManager manager = Forge.getAssets(true).manager;
AssetManager manager = Forge.getAssets().manager();
preferredName = skinName.toLowerCase().replace(' ', '_');
//reset hd buttons/icons
@@ -165,17 +148,26 @@ public class FSkin {
}
try {
manager.load(f.path(), Texture.class);
manager.finishLoadingAsset(f.path());
final int w = manager.get(f.path(), Texture.class).getWidth();
final int h = manager.get(f.path(), Texture.class).getHeight();
if (f2.exists()) {
manager.load(f2.path(), Texture.class, new TextureLoader.TextureParameter(){{genMipMaps = true; minFilter = Texture.TextureFilter.MipMapLinearLinear; magFilter = Texture.TextureFilter.Linear;}});
manager.finishLoadingAsset(f2.path());
splashScreen.setBackground(new TextureRegion(manager.get(f2.path(), Texture.class)));
int w, h;
if (f.path().contains("fallback_skin")) {
//the file is not accesible by the assetmanager using absolute fileresolver since it resides on internal path or classpath
Texture txSplash = new Texture(f);
w = txSplash.getWidth();
h = txSplash.getHeight();
splashScreen.setBackground(new TextureRegion(txSplash, 0, 0, w, h - 100));
} else {
splashScreen.setBackground(new TextureRegion(manager.get(f.path(), Texture.class), 0, 0, w, h - 100));
manager.load(f.path(), Texture.class);
manager.finishLoadingAsset(f.path());
w = manager.get(f.path(), Texture.class).getWidth();
h = manager.get(f.path(), Texture.class).getHeight();
if (f2.exists()) {
manager.load(f2.path(), Texture.class, new TextureLoader.TextureParameter(){{genMipMaps = true; minFilter = Texture.TextureFilter.MipMapLinearLinear; magFilter = Texture.TextureFilter.Linear;}});
manager.finishLoadingAsset(f2.path());
splashScreen.setBackground(new TextureRegion(manager.get(f2.path(), Texture.class)));
} else {
splashScreen.setBackground(new TextureRegion(manager.get(f.path(), Texture.class), 0, 0, w, h - 100));
}
}
Pixmap pxSplash = new Pixmap(f);
@@ -217,8 +209,8 @@ public class FSkin {
if (FSkin.preferredName.isEmpty()) { FSkin.loadLight("default", splashScreen); }
}
avatars.clear();
sleeves.clear();
Forge.getAssets().avatars().clear();
Forge.getAssets().sleeves().clear();
TextureLoader.TextureParameter parameter = new TextureLoader.TextureParameter();
if (Forge.isTextureFilteringEnabled()) {
@@ -227,7 +219,7 @@ public class FSkin {
parameter.magFilter = Texture.TextureFilter.Linear;
}
AssetManager manager = Forge.getAssets(true).manager;
AssetManager manager = Forge.getAssets().manager();
// Grab and test various sprite files.
final FileHandle f1 = getDefaultSkinFile(SourceFile.ICONS.getFilename());
@@ -246,6 +238,8 @@ public class FSkin {
final FileHandle f17 = getDefaultSkinFile(ForgeConstants.SPRITE_CRACKS_FILE);
final FileHandle f18 = getDefaultSkinFile(ForgeConstants.SPRITE_PHYREXIAN_FILE);
final FileHandle f19 = getDefaultSkinFile(ForgeConstants.SPRITE_CURSOR_FILE);
final FileHandle f20 = getSkinFile(ForgeConstants.SPRITE_SLEEVES_FILE);
final FileHandle f21 = getSkinFile(ForgeConstants.SPRITE_SLEEVES2_FILE);
/*TODO Themeable
final FileHandle f14 = getDefaultSkinFile(ForgeConstants.SPRITE_SETLOGO_FILE);
@@ -321,7 +315,7 @@ public class FSkin {
int counter = 0;
int scount = 0;
Color pxTest;
Pixmap pxDefaultAvatars, pxPreferredAvatars, pxDefaultSleeves;
Pixmap pxDefaultAvatars, pxPreferredAvatars, pxDefaultSleeves, pxPreferredSleeves;
pxDefaultAvatars = new Pixmap(f4);
pxDefaultSleeves = new Pixmap(f8);
@@ -345,7 +339,7 @@ public class FSkin {
if (i == 0 && j == 0) { continue; }
pxTest = new Color(pxPreferredAvatars.getPixel(i + 50, j + 50));
if (pxTest.a == 0) { continue; }
FSkin.avatars.put(counter++, new TextureRegion(manager.get(f5.path(), Texture.class), i, j, 100, 100));
Forge.getAssets().avatars().put(counter++, new TextureRegion(manager.get(f5.path(), Texture.class), i, j, 100, 100));
}
}
pxPreferredAvatars.dispose();
@@ -360,37 +354,72 @@ public class FSkin {
if (i == 0 && j == 0) { continue; }
pxTest = new Color(pxDefaultAvatars.getPixel(i + 50, j + 50));
if (pxTest.a == 0) { continue; }
FSkin.avatars.put(counter++, new TextureRegion(manager.get(f4.path(), Texture.class), i, j, 100, 100));
Forge.getAssets().avatars().put(counter++, new TextureRegion(manager.get(f4.path(), Texture.class), i, j, 100, 100));
}
}
}
if (f20.exists()) {
pxPreferredSleeves = new Pixmap(f20);
manager.load(f20.path(), Texture.class, parameter);
manager.finishLoadingAsset(f20.path());
final int sw = pxPreferredSleeves.getWidth();
final int sh = pxPreferredSleeves.getHeight();
for (int j = 0; j < sh; j += 500) {
for (int i = 0; i < sw; i += 360) {
pxTest = new Color(pxPreferredSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
Forge.getAssets().sleeves().put(scount++, new TextureRegion(manager.get(f20.path(), Texture.class), i, j, 360, 500));
}
}
pxPreferredSleeves.dispose();
} else {
final int sw = pxDefaultSleeves.getWidth();
final int sh = pxDefaultSleeves.getHeight();
for (int j = 0; j < sh; j += 500) {
for (int i = 0; i < sw; i += 360) {
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
Forge.getAssets().sleeves().put(scount++, new TextureRegion(manager.get(f8.path(), Texture.class), i, j, 360, 500));
}
}
}
if (f21.exists()) {
pxPreferredSleeves = new Pixmap(f21);
manager.load(f21.path(), Texture.class, parameter);
manager.finishLoadingAsset(f21.path());
final int sw = pxPreferredSleeves.getWidth();
final int sh = pxPreferredSleeves.getHeight();
for (int j = 0; j < sh; j += 500) {
for (int i = 0; i < sw; i += 360) {
pxTest = new Color(pxPreferredSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
Forge.getAssets().sleeves().put(scount++, new TextureRegion(manager.get(f21.path(), Texture.class), i, j, 360, 500));
}
}
pxPreferredSleeves.dispose();
} else {
//re init second set of sleeves
pxDefaultSleeves = new Pixmap(f9);
manager.load(f9.path(), Texture.class, parameter);
manager.finishLoadingAsset(f9.path());
final int sw2 = pxDefaultSleeves.getWidth();
final int sh2 = pxDefaultSleeves.getHeight();
for (int j = 0; j < sh2; j += 500) {
for (int i = 0; i < sw2; i += 360) {
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
Forge.getAssets().sleeves().put(scount++, new TextureRegion(manager.get(f9.path(), Texture.class), i, j, 360, 500));
}
}
}
final int sw = pxDefaultSleeves.getWidth();
final int sh = pxDefaultSleeves.getHeight();
for (int j = 0; j < sh; j += 500) {
for (int i = 0; i < sw; i += 360) {
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
FSkin.sleeves.put(scount++, new TextureRegion(manager.get(f8.path(), Texture.class), i, j, 360, 500));
}
}
//re init second set of sleeves
pxDefaultSleeves = new Pixmap(f9);
manager.load(f9.path(), Texture.class, parameter);
manager.finishLoadingAsset(f9.path());
final int sw2 = pxDefaultSleeves.getWidth();
final int sh2 = pxDefaultSleeves.getHeight();
for (int j = 0; j < sh2; j += 500) {
for (int i = 0; i < sw2; i += 360) {
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
FSkin.sleeves.put(scount++, new TextureRegion(manager.get(f9.path(), Texture.class), i, j, 360, 500));
}
}
//cracks
manager.load(f17.path(), Texture.class, parameter);
manager.finishLoadingAsset(f17.path());
@@ -399,32 +428,32 @@ public class FSkin {
int x = j * 200;
for(int i = 0; i < 4; i++) {
int y = i * 279;
FSkin.cracks.put(crackCount++, new TextureRegion(manager.get(f17.path(), Texture.class), x, y, 200, 279));
Forge.getAssets().cracks().put(crackCount++, new TextureRegion(manager.get(f17.path(), Texture.class), x, y, 200, 279));
}
}
//borders
manager.load(f10.path(), Texture.class);
manager.finishLoadingAsset(f10.path());
FSkin.borders.put(0, new TextureRegion(manager.get(f10.path(), Texture.class), 2, 2, 672, 936));
FSkin.borders.put(1, new TextureRegion(manager.get(f10.path(), Texture.class), 676, 2, 672, 936));
Forge.getAssets().borders().put(0, new TextureRegion(manager.get(f10.path(), Texture.class), 2, 2, 672, 936));
Forge.getAssets().borders().put(1, new TextureRegion(manager.get(f10.path(), Texture.class), 676, 2, 672, 936));
//deckboxes
manager.load(f13.path(), Texture.class, parameter);
manager.finishLoadingAsset(f13.path());
//gold bg
FSkin.deckbox.put(0, new TextureRegion(manager.get(f13.path(), Texture.class), 2, 2, 488, 680));
Forge.getAssets().deckbox().put(0, new TextureRegion(manager.get(f13.path(), Texture.class), 2, 2, 488, 680));
//deck box for card art
FSkin.deckbox.put(1, new TextureRegion(manager.get(f13.path(), Texture.class), 492, 2, 488, 680));
Forge.getAssets().deckbox().put(1, new TextureRegion(manager.get(f13.path(), Texture.class), 492, 2, 488, 680));
//generic deck box
FSkin.deckbox.put(2, new TextureRegion(manager.get(f13.path(), Texture.class), 982, 2, 488, 680));
Forge.getAssets().deckbox().put(2, new TextureRegion(manager.get(f13.path(), Texture.class), 982, 2, 488, 680));
//cursor
manager.load(f19.path(), Texture.class);
manager.finishLoadingAsset(f19.path());
FSkin.cursor.put(0, new TextureRegion(manager.get(f19.path(), Texture.class), 0, 0, 32, 32)); //default
FSkin.cursor.put(1, new TextureRegion(manager.get(f19.path(), Texture.class), 32, 0, 32, 32)); //magnify on
FSkin.cursor.put(2, new TextureRegion(manager.get(f19.path(), Texture.class), 64, 0, 32, 32)); // magnify off
Forge.getAssets().cursor().put(0, new TextureRegion(manager.get(f19.path(), Texture.class), 0, 0, 32, 32)); //default
Forge.getAssets().cursor().put(1, new TextureRegion(manager.get(f19.path(), Texture.class), 32, 0, 32, 32)); //magnify on
Forge.getAssets().cursor().put(2, new TextureRegion(manager.get(f19.path(), Texture.class), 64, 0, 32, 32)); // magnify off
Forge.setCursor(cursor.get(0), "0");
Forge.setCursor(Forge.getAssets().cursor().get(0), "0");
preferredIcons.dispose();
pxDefaultAvatars.dispose();
@@ -514,31 +543,31 @@ public class FSkin {
}
public static Map<FSkinProp, FSkinImage> getImages() {
return images;
return Forge.getAssets().images();
}
public static Map<Integer, TextureRegion> getAvatars() {
return avatars;
return Forge.getAssets().avatars();
}
public static Map<Integer, TextureRegion> getSleeves() {
return sleeves;
return Forge.getAssets().sleeves();
}
public static Map<Integer, TextureRegion> getCracks() {
return cracks;
return Forge.getAssets().cracks();
}
public static Map<Integer, TextureRegion> getBorders() {
return borders;
return Forge.getAssets().borders();
}
public static Map<Integer, TextureRegion> getDeckbox() {
return deckbox;
return Forge.getAssets().deckbox();
}
public static Map<Integer, TextureRegion> getCursor() {
return cursor;
return Forge.getAssets().cursor();
}
public static boolean isLoaded() { return loaded; }

View File

@@ -22,7 +22,6 @@ import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntSet;
import com.badlogic.gdx.utils.ObjectMap;
import forge.Forge;
import forge.gui.FThreads;
import forge.localinstance.properties.ForgeConstants;
@@ -39,29 +38,19 @@ public class FSkinFont {
private static final int MAX_FONT_SIZE_MANY_GLYPHS = 36;
private static final String TTF_FILE = "font1.ttf";
private static final HashMap<Integer, FSkinFont> fonts = new HashMap<>();
private static final String commonCharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
+ "nopqrstuvwxyz1234567890\"!?'.,;:()[]{}<>|/@\\^$-%+=#_&*\u2014"
+ "\u2022ÁÉÍÓÚáéíóúÀÈÌÒÙàèìòùÑñÄËÏÖÜäëïöüẞß¿¡";
private static ObjectMap<String, String> langUniqueCharacterSet = new ObjectMap<>();
private static HashMap<String, String> langUniqueCharacterSet = new HashMap<>();
static {
FileUtil.ensureDirectoryExists(ForgeConstants.FONTS_DIR);
}
public static void clear() {
fonts.clear();
//reset maxFontSize and Preload
preloadAll("");
}
public static FSkinFont get(final int unscaledSize) {
return _get((int)Utils.scale(unscaledSize));
}
public static FSkinFont _get(final int scaledSize) {
FSkinFont skinFont = fonts.get(scaledSize);
FSkinFont skinFont = Forge.getAssets().fonts().get(scaledSize);
if (skinFont == null) {
skinFont = new FSkinFont(scaledSize);
fonts.put(scaledSize, skinFont);
Forge.getAssets().fonts().put(scaledSize, skinFont);
}
return skinFont;
}
@@ -69,7 +58,8 @@ public class FSkinFont {
public static FSkinFont forHeight(final float height) {
int size = MIN_FONT_SIZE + 1;
while (true) {
if (_get(size).getLineHeight() > height) {
FSkinFont f = _get(size);
if (f != null && f.getLineHeight() > height) {
return _get(size - 1);
}
size++;
@@ -97,14 +87,14 @@ public class FSkinFont {
}
public static void updateAll() {
for (FSkinFont skinFont : fonts.values()) {
for (FSkinFont skinFont : Forge.getAssets().fonts().values()) {
skinFont.updateFont();
}
}
private final int fontSize;
private final float scale;
private BitmapFont font;
BitmapFont font;
private FSkinFont(int fontSize0) {
if (fontSize0 > MAX_FONT_SIZE) {
@@ -127,6 +117,8 @@ public class FSkinFont {
}
public int computeVisibleGlyphs (CharSequence str, int start, int end, float availableWidth) {
if (font == null)
return 0;
BitmapFontData data = font.getData();
int index = start;
float width = 0;
@@ -180,6 +172,9 @@ public class FSkinFont {
return getBounds(str, 0, str.length());
}
public TextBounds getBounds(CharSequence str, int start, int end) {
if (font == null) {
return new TextBounds(0f, 0f);
}
BitmapFontData data = font.getData();
//int start = 0;
//int end = str.length();
@@ -228,6 +223,9 @@ public class FSkinFont {
}
public TextBounds getMultiLineBounds(CharSequence str) {
updateScale();
if (font == null) {
return new TextBounds(0f, 0f);
}
BitmapFontData data = font.getData();
int start = 0;
float maxWidth = 0;
@@ -247,6 +245,9 @@ public class FSkinFont {
}
public TextBounds getWrappedBounds(CharSequence str, float wrapWidth) {
updateScale();
if (font == null) {
return new TextBounds(0f, 0f);
}
BitmapFontData data = font.getData();
if (wrapWidth <= 0) wrapWidth = Integer.MAX_VALUE;
int start = 0;
@@ -303,14 +304,20 @@ public class FSkinFont {
return new TextBounds(maxWidth, data.capHeight + (numLines - 1) * data.lineHeight);
}
public float getAscent() {
if (font == null)
return 0f;
updateScale();
return font.getAscent();
}
public float getCapHeight() {
if (font == null)
return 0f;
updateScale();
return font.getCapHeight();
}
public float getLineHeight() {
if (font == null)
return 0f;
updateScale();
return font.getLineHeight();
}
@@ -323,8 +330,12 @@ public class FSkinFont {
//update scale of font if needed
private void updateScale() {
if (font.getScaleX() != scale) {
font.getData().setScale(scale);
try {
if (font.getScaleX() != scale) {
font.getData().setScale(scale);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@@ -348,10 +359,10 @@ public class FSkinFont {
if (langUniqueCharacterSet.containsKey(langCode)) {
return langUniqueCharacterSet.get(langCode);
}
StringBuilder characters = new StringBuilder(commonCharacterSet);
StringBuilder characters = new StringBuilder(FreeTypeFontGenerator.DEFAULT_CHARS);
IntSet characterSet = new IntSet();
for (int offset = 0; offset < commonCharacterSet.length();) {
final int codePoint = commonCharacterSet.codePointAt(offset);
for (int offset = 0; offset < FreeTypeFontGenerator.DEFAULT_CHARS.length();) {
final int codePoint = FreeTypeFontGenerator.DEFAULT_CHARS.codePointAt(offset);
characterSet.add(codePoint);
offset += Character.charCount(codePoint);
}
@@ -400,16 +411,13 @@ public class FSkinFont {
if (fontFile != null && fontFile.exists()) {
final BitmapFontData data = new BitmapFontData(fontFile, false);
String finalFontName = fontName;
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() { //font must be initialized on UI thread
try {
font = new BitmapFont(data, (TextureRegion) null, true);
found[0] = true;
} catch (Exception e) {
e.printStackTrace();
found[0] = false;
}
FThreads.invokeInEdtNowOrLater(() -> { //font must be initialized on UI thread
try {
font = new BitmapFont(data, (TextureRegion) null, true);
found[0] = true;
} catch (Exception e) {
e.printStackTrace();
found[0] = false;
}
});
}

View File

@@ -128,9 +128,13 @@ public enum FSkinTexture implements FImage {
FileHandle preferredFile = isPlane ? FSkin.getCachePlanechaseFile(filename) : FSkin.getSkinFile(filename);
if (preferredFile.exists()) {
try {
Forge.getAssets(true).manager.load(preferredFile.path(), Texture.class);
Forge.getAssets(true).manager.finishLoadingAsset(preferredFile.path());
texture = Forge.getAssets(true).manager.get(preferredFile.path(), Texture.class);
if (preferredFile.path().contains("fallback_skin")) {
texture = new Texture(preferredFile);
} else {
Forge.getAssets().manager().load(preferredFile.path(), Texture.class);
Forge.getAssets().manager().finishLoadingAsset(preferredFile.path());
texture = Forge.getAssets().manager().get(preferredFile.path(), Texture.class);
}
}
catch (final Exception e) {
System.err.println("Failed to load skin file: " + preferredFile);
@@ -148,9 +152,13 @@ public enum FSkinTexture implements FImage {
if (defaultFile.exists()) {
try {
Forge.getAssets(true).manager.load(defaultFile.path(), Texture.class);
Forge.getAssets(true).manager.finishLoadingAsset(defaultFile.path());
texture = Forge.getAssets(true).manager.get(defaultFile.path(), Texture.class);
if (defaultFile.path().contains("fallback_skin")) {
texture = new Texture(defaultFile);
} else {
Forge.getAssets().manager().load(defaultFile.path(), Texture.class);
Forge.getAssets().manager().finishLoadingAsset(defaultFile.path());
texture = Forge.getAssets().manager().get(defaultFile.path(), Texture.class);
}
}
catch (final Exception e) {
System.err.println("Failed to load skin file: " + defaultFile);

View File

@@ -18,22 +18,22 @@
package forge.assets;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.TextureLoader.TextureParameter;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectSet;
import com.google.common.collect.EvictingQueue;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
import forge.gui.FThreads;
import forge.gui.GuiBase;
import forge.util.FileUtil;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
@@ -74,10 +74,12 @@ import forge.util.ImageUtil;
* @version $Id: ImageCache.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class ImageCache {
private static final ObjectSet<String> missingIconKeys = new ObjectSet<>();
private static final HashSet<String> missingIconKeys = new HashSet<>();
private static List<String> borderlessCardlistKey = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
static int maxCardCapacity = 400; //default card capacity
public static int counter = 0;
static int maxCardCapacity = 300; //default card capacity
static EvictingQueue<String> q;
static Set<String> cardsLoaded;
static Queue<String> syncQ;
static TextureParameter defaultParameter = new TextureParameter();
static TextureParameter filtered = new TextureParameter();
@@ -92,12 +94,14 @@ public class ImageCache {
q = EvictingQueue.create(capacity);
//init syncQ for threadsafe use
syncQ = Queues.synchronizedQueue(q);
//cap
int cl = GuiBase.isAndroid() ? maxCardCapacity+(capacity/3) : 400;
cardsLoaded = new HashSet<>(cl);
}
public static final Texture defaultImage;
public static FImage BlackBorder = FSkinImage.IMG_BORDER_BLACK;
public static FImage WhiteBorder = FSkinImage.IMG_BORDER_WHITE;
private static final ObjectMap<String, Pair<String, Boolean>> imageBorder = new ObjectMap<>(1024);
private static final ObjectMap<String, Texture> generatedCards = new ObjectMap<>(512);
private static final HashMap<String, Pair<String, Boolean>> imageBorder = new HashMap<>(1024);
private static boolean imageLoaded, delayLoadRequested;
public static void allowSingleLoad() {
@@ -112,7 +116,7 @@ public class ImageCache {
} catch (Exception ex) {
System.err.println("could not load default card image");
} finally {
defaultImage = (null == defImage) ? new Texture(10, 10, Format.RGBA8888) : defImage;
defaultImage = (null == defImage) ? new Texture(10, 10, Format.RGBA4444) : defImage;
}
}
@@ -121,11 +125,18 @@ public class ImageCache {
ImageKeys.clearMissingCards();
}
public static void clearGeneratedCards() {
generatedCards.clear();
Forge.getAssets().generatedCards().clear();
}
public static void disposeTextures(){
CardRenderer.clearcardArtCache();
Forge.getAssets(false).manager.clear();
//unload all cardsLoaded
for (String fileName : cardsLoaded) {
if (Forge.getAssets().manager().contains(fileName)) {
Forge.getAssets().manager().unload(fileName);
}
}
cardsLoaded.clear();
((Forge)Gdx.app.getApplicationListener()).needsUpdate = true;
}
public static Texture getImage(InventoryItem ii) {
@@ -201,7 +212,7 @@ public class ImageCache {
public static Texture getImage(String imageKey, boolean useDefaultIfNotFound) {
return getImage(imageKey, useDefaultIfNotFound, false);
}
public static Texture getImage(String imageKey, boolean useDefaultIfNotFound, boolean useOtherCache) {
public static Texture getImage(String imageKey, boolean useDefaultIfNotFound, boolean others) {
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
return null;
@@ -226,7 +237,7 @@ public class ImageCache {
File imageFile = ImageKeys.getImageFile(imageKey);
if (useDefaultIfNotFound) {
// Load from file and add to cache if not found in cache initially.
image = getAsset(imageKey, imageFile, useOtherCache);
image = getAsset(imageKey, imageFile, others);
if (image != null) { return image; }
@@ -242,7 +253,7 @@ public class ImageCache {
}
try {
image = loadAsset(imageKey, imageFile, useOtherCache);
image = loadAsset(imageKey, imageFile, others);
} catch (final Exception ex) {
image = null;
}
@@ -261,55 +272,67 @@ public class ImageCache {
}
return image;
}
static Texture getAsset(String imageKey, File file, boolean otherCache) {
static Texture getAsset(String imageKey, File file, boolean others) {
if (file == null)
return null;
if (!otherCache && Forge.enableUIMask.equals("Full") && isBorderless(imageKey))
return generatedCards.get(imageKey);
return Forge.getAssets(otherCache).manager.get(file.getPath(), Texture.class, false);
if (!others && Forge.enableUIMask.equals("Full") && isBorderless(imageKey))
return Forge.getAssets().generatedCards().get(imageKey);
return Forge.getAssets().manager().get(file.getPath(), Texture.class, false);
}
static Texture loadAsset(String imageKey, File file, boolean otherCache) {
static Texture loadAsset(String imageKey, File file, boolean others) {
if (file == null)
return null;
syncQ.add(file.getPath());
if (!otherCache && Forge.getAssets(false).manager.getLoadedAssets() > maxCardCapacity) {
unloadCardTextures(Forge.getAssets(false).manager);
Texture check = getAsset(imageKey, file, others);
if (check != null)
return check;
if (!others) {
syncQ.add(file.getPath());
cardsLoaded.add(file.getPath());
}
if (!others && cardsLoaded.size() > maxCardCapacity) {
unloadCardTextures(Forge.getAssets().manager());
return null;
}
String fileName = file.getPath();
//load to assetmanager
Forge.getAssets(otherCache).manager.load(fileName, Texture.class, Forge.isTextureFilteringEnabled() ? filtered : defaultParameter);
Forge.getAssets(otherCache).manager.finishLoadingAsset(fileName);
if (!Forge.getAssets().manager().contains(fileName, Texture.class)) {
Forge.getAssets().manager().load(fileName, Texture.class, Forge.isTextureFilteringEnabled() ? filtered : defaultParameter);
Forge.getAssets().manager().finishLoadingAsset(fileName);
counter+=1;
}
//return loaded assets
if (otherCache) {
return Forge.getAssets(true).manager.get(fileName, Texture.class, false);
if (others) {
return Forge.getAssets().manager().get(fileName, Texture.class, false);
} else {
Texture t = Forge.getAssets(false).manager.get(fileName, Texture.class, false);
Texture cardTexture = Forge.getAssets().manager().get(fileName, Texture.class, false);
//if full bordermasking is enabled, update the border color
if (Forge.enableUIMask.equals("Full")) {
boolean borderless = isBorderless(imageKey);
updateBorders(t.toString(), borderless ? Pair.of(Color.valueOf("#171717").toString(), false): isCloserToWhite(getpixelColor(t)));
updateBorders(cardTexture.toString(), borderless ? Pair.of(Color.valueOf("#171717").toString(), false): isCloserToWhite(getpixelColor(cardTexture)));
//if borderless, generate new texture from the asset and store
if (borderless) {
generatedCards.put(imageKey, generateTexture(new FileHandle(file), t, Forge.isTextureFilteringEnabled()));
Forge.getAssets().generatedCards().put(imageKey, generateTexture(new FileHandle(file), cardTexture, Forge.isTextureFilteringEnabled()));
}
}
return t;
return cardTexture;
}
}
static void unloadCardTextures(AssetManager manager) {
static void unloadCardTextures(Assets.MemoryTrackingAssetManager manager) {
//get latest images from syncQ
Set<String> newQ = Sets.newHashSet(syncQ);
//get loaded images from assetmanager
Set<String> old = Sets.newHashSet(manager.getAssetNames());
//get all images not in newQ (old images to unload)
Set<String> toUnload = Sets.difference(old, newQ);
//get all images not in newQ (cardLists to unload)
Set<String> toUnload = Sets.difference(cardsLoaded, newQ);
//unload from assetmanager to save RAM
for (String asset : toUnload) {
manager.unload(asset);
if(manager.contains(asset)) {
manager.unload(asset);
}
cardsLoaded.remove(asset);
}
//clear cachedArt since this is dependant to the loaded texture
CardRenderer.clearcardArtCache();
((Forge)Gdx.app.getApplicationListener()).needsUpdate = true;
}
public static void preloadCache(Iterable<String> keys) {
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
@@ -409,10 +432,10 @@ public class ImageCache {
return borderColor(t);
}
public static Texture generateTexture(FileHandle fh, Texture t, boolean textureFilter) {
if (t == null || fh == null)
return t;
final Texture[] n = new Texture[1];
public static Texture generateTexture(FileHandle fh, Texture cardTexture, boolean textureFilter) {
if (cardTexture == null || fh == null)
return cardTexture;
final Texture[] placeholder = new Texture[1];
FThreads.invokeInEdtNowOrLater(() -> {
Pixmap pImage = new Pixmap(fh);
int w = pImage.getWidth();
@@ -422,20 +445,20 @@ public class ImageCache {
drawPixelstoMask(pImage, pMask);
TextureData textureData = new PixmapTextureData(
pMask, //pixmap to use
Format.RGBA8888,
Format.RGBA4444,
textureFilter, //use mipmaps
false, true);
n[0] = new Texture(textureData);
placeholder[0] = new Texture(textureData);
if (textureFilter)
n[0].setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
placeholder[0].setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
pImage.dispose();
pMask.dispose();
});
return n[0];
return placeholder[0];
}
public static Pixmap createRoundedRectangle(int width, int height, int cornerRadius, Color color) {
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
Pixmap ret = new Pixmap(width, height, Pixmap.Format.RGBA8888);
Pixmap pixmap = new Pixmap(width, height, Format.RGBA4444);
Pixmap ret = new Pixmap(width, height, Format.RGBA4444);
pixmap.setColor(color);
//round corners
pixmap.fillCircle(cornerRadius, cornerRadius, cornerRadius);
@@ -486,11 +509,7 @@ public class ImageCache {
//generated texture/pixmap?
if (t.toString().contains("com.badlogic.gdx.graphics.Texture@"))
return true;
for (String key : borderlessCardlistKey) {
if (t.toString().contains(key))
return true;
}
return false;
return borderlessCardlistKey.stream().anyMatch(key -> t.toString().contains(key));
}
public static String getpixelColor(Texture i) {

View File

@@ -2,10 +2,8 @@ package forge.assets;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Align;
@@ -20,64 +18,63 @@ import forge.util.TextBounds;
//Encodes text for drawing with symbols and reminder text
public class TextRenderer {
private static final Map<String, FSkinImage> symbolLookup = new HashMap<>(64);
static {
symbolLookup.put("C", FSkinImage.MANA_COLORLESS);
symbolLookup.put("W", FSkinImage.MANA_W);
symbolLookup.put("U", FSkinImage.MANA_U);
symbolLookup.put("B", FSkinImage.MANA_B);
symbolLookup.put("R", FSkinImage.MANA_R);
symbolLookup.put("G", FSkinImage.MANA_G);
symbolLookup.put("W/U", FSkinImage.MANA_HYBRID_WU);
symbolLookup.put("U/B", FSkinImage.MANA_HYBRID_UB);
symbolLookup.put("B/R", FSkinImage.MANA_HYBRID_BR);
symbolLookup.put("R/G", FSkinImage.MANA_HYBRID_RG);
symbolLookup.put("G/W", FSkinImage.MANA_HYBRID_GW);
symbolLookup.put("W/B", FSkinImage.MANA_HYBRID_WB);
symbolLookup.put("U/R", FSkinImage.MANA_HYBRID_UR);
symbolLookup.put("B/G", FSkinImage.MANA_HYBRID_BG);
symbolLookup.put("R/W", FSkinImage.MANA_HYBRID_RW);
symbolLookup.put("G/U", FSkinImage.MANA_HYBRID_GU);
symbolLookup.put("2/W", FSkinImage.MANA_2W);
symbolLookup.put("2/U", FSkinImage.MANA_2U);
symbolLookup.put("2/B", FSkinImage.MANA_2B);
symbolLookup.put("2/R", FSkinImage.MANA_2R);
symbolLookup.put("2/G", FSkinImage.MANA_2G);
symbolLookup.put("P", FSkinImage.MANA_PHRYX);
symbolLookup.put("P/W", FSkinImage.MANA_PHRYX_W);
symbolLookup.put("P/U", FSkinImage.MANA_PHRYX_U);
symbolLookup.put("P/B", FSkinImage.MANA_PHRYX_B);
symbolLookup.put("P/R", FSkinImage.MANA_PHRYX_R);
symbolLookup.put("P/G", FSkinImage.MANA_PHRYX_G);
symbolLookup.put("W/P", FSkinImage.MANA_PHRYX_W);
symbolLookup.put("U/P", FSkinImage.MANA_PHRYX_U);
symbolLookup.put("B/P", FSkinImage.MANA_PHRYX_B);
symbolLookup.put("R/P", FSkinImage.MANA_PHRYX_R);
symbolLookup.put("G/P", FSkinImage.MANA_PHRYX_G);
symbolLookup.put("P/B/G", FSkinImage.MANA_PHRYX_BG);
symbolLookup.put("P/B/R", FSkinImage.MANA_PHRYX_BR);
symbolLookup.put("P/G/U", FSkinImage.MANA_PHRYX_GU);
symbolLookup.put("P/G/W", FSkinImage.MANA_PHRYX_GW);
symbolLookup.put("P/R/G", FSkinImage.MANA_PHRYX_RG);
symbolLookup.put("P/R/W", FSkinImage.MANA_PHRYX_RW);
symbolLookup.put("P/U/B", FSkinImage.MANA_PHRYX_UB);
symbolLookup.put("P/U/R", FSkinImage.MANA_PHRYX_UR);
symbolLookup.put("P/W/B", FSkinImage.MANA_PHRYX_WB);
symbolLookup.put("P/W/U", FSkinImage.MANA_PHRYX_WU);
Forge.getAssets().symbolLookup().put("C", FSkinImage.MANA_COLORLESS);
Forge.getAssets().symbolLookup().put("W", FSkinImage.MANA_W);
Forge.getAssets().symbolLookup().put("U", FSkinImage.MANA_U);
Forge.getAssets().symbolLookup().put("B", FSkinImage.MANA_B);
Forge.getAssets().symbolLookup().put("R", FSkinImage.MANA_R);
Forge.getAssets().symbolLookup().put("G", FSkinImage.MANA_G);
Forge.getAssets().symbolLookup().put("W/U", FSkinImage.MANA_HYBRID_WU);
Forge.getAssets().symbolLookup().put("U/B", FSkinImage.MANA_HYBRID_UB);
Forge.getAssets().symbolLookup().put("B/R", FSkinImage.MANA_HYBRID_BR);
Forge.getAssets().symbolLookup().put("R/G", FSkinImage.MANA_HYBRID_RG);
Forge.getAssets().symbolLookup().put("G/W", FSkinImage.MANA_HYBRID_GW);
Forge.getAssets().symbolLookup().put("W/B", FSkinImage.MANA_HYBRID_WB);
Forge.getAssets().symbolLookup().put("U/R", FSkinImage.MANA_HYBRID_UR);
Forge.getAssets().symbolLookup().put("B/G", FSkinImage.MANA_HYBRID_BG);
Forge.getAssets().symbolLookup().put("R/W", FSkinImage.MANA_HYBRID_RW);
Forge.getAssets().symbolLookup().put("G/U", FSkinImage.MANA_HYBRID_GU);
Forge.getAssets().symbolLookup().put("2/W", FSkinImage.MANA_2W);
Forge.getAssets().symbolLookup().put("2/U", FSkinImage.MANA_2U);
Forge.getAssets().symbolLookup().put("2/B", FSkinImage.MANA_2B);
Forge.getAssets().symbolLookup().put("2/R", FSkinImage.MANA_2R);
Forge.getAssets().symbolLookup().put("2/G", FSkinImage.MANA_2G);
Forge.getAssets().symbolLookup().put("P", FSkinImage.MANA_PHRYX);
Forge.getAssets().symbolLookup().put("P/W", FSkinImage.MANA_PHRYX_W);
Forge.getAssets().symbolLookup().put("P/U", FSkinImage.MANA_PHRYX_U);
Forge.getAssets().symbolLookup().put("P/B", FSkinImage.MANA_PHRYX_B);
Forge.getAssets().symbolLookup().put("P/R", FSkinImage.MANA_PHRYX_R);
Forge.getAssets().symbolLookup().put("P/G", FSkinImage.MANA_PHRYX_G);
Forge.getAssets().symbolLookup().put("W/P", FSkinImage.MANA_PHRYX_W);
Forge.getAssets().symbolLookup().put("U/P", FSkinImage.MANA_PHRYX_U);
Forge.getAssets().symbolLookup().put("B/P", FSkinImage.MANA_PHRYX_B);
Forge.getAssets().symbolLookup().put("R/P", FSkinImage.MANA_PHRYX_R);
Forge.getAssets().symbolLookup().put("G/P", FSkinImage.MANA_PHRYX_G);
Forge.getAssets().symbolLookup().put("P/B/G", FSkinImage.MANA_PHRYX_BG);
Forge.getAssets().symbolLookup().put("P/B/R", FSkinImage.MANA_PHRYX_BR);
Forge.getAssets().symbolLookup().put("P/G/U", FSkinImage.MANA_PHRYX_GU);
Forge.getAssets().symbolLookup().put("P/G/W", FSkinImage.MANA_PHRYX_GW);
Forge.getAssets().symbolLookup().put("P/R/G", FSkinImage.MANA_PHRYX_RG);
Forge.getAssets().symbolLookup().put("P/R/W", FSkinImage.MANA_PHRYX_RW);
Forge.getAssets().symbolLookup().put("P/U/B", FSkinImage.MANA_PHRYX_UB);
Forge.getAssets().symbolLookup().put("P/U/R", FSkinImage.MANA_PHRYX_UR);
Forge.getAssets().symbolLookup().put("P/W/B", FSkinImage.MANA_PHRYX_WB);
Forge.getAssets().symbolLookup().put("P/W/U", FSkinImage.MANA_PHRYX_WU);
for (int i = 0; i <= 20; i++) {
symbolLookup.put(String.valueOf(i), FSkinImage.valueOf("MANA_" + i));
Forge.getAssets().symbolLookup().put(String.valueOf(i), FSkinImage.valueOf("MANA_" + i));
}
symbolLookup.put("X", FSkinImage.MANA_X);
symbolLookup.put("Y", FSkinImage.MANA_Y);
symbolLookup.put("Z", FSkinImage.MANA_Z);
symbolLookup.put("CHAOS", FSkinImage.CHAOS);
symbolLookup.put("Q", FSkinImage.UNTAP);
symbolLookup.put("S", FSkinImage.MANA_SNOW);
symbolLookup.put("T", FSkinImage.TAP);
symbolLookup.put("E", FSkinImage.ENERGY);
symbolLookup.put("AE", FSkinImage.AETHER_SHARD);
symbolLookup.put("PW", FSkinImage.PW_BADGE_COMMON);
symbolLookup.put("CR", FSkinImage.QUEST_COINSTACK);
Forge.getAssets().symbolLookup().put("X", FSkinImage.MANA_X);
Forge.getAssets().symbolLookup().put("Y", FSkinImage.MANA_Y);
Forge.getAssets().symbolLookup().put("Z", FSkinImage.MANA_Z);
Forge.getAssets().symbolLookup().put("CHAOS", FSkinImage.CHAOS);
Forge.getAssets().symbolLookup().put("Q", FSkinImage.UNTAP);
Forge.getAssets().symbolLookup().put("S", FSkinImage.MANA_SNOW);
Forge.getAssets().symbolLookup().put("T", FSkinImage.TAP);
Forge.getAssets().symbolLookup().put("E", FSkinImage.ENERGY);
Forge.getAssets().symbolLookup().put("AE", FSkinImage.AETHER_SHARD);
Forge.getAssets().symbolLookup().put("PW", FSkinImage.PW_BADGE_COMMON);
Forge.getAssets().symbolLookup().put("CR", FSkinImage.QUEST_COINSTACK);
}
public static String startColor(Color color) {
@@ -192,7 +189,7 @@ public class TextRenderer {
if (inSymbolCount > 0) {
inSymbolCount--;
if (text.length() > 0) {
FSkinImage symbol = symbolLookup.get(text.toString());
FSkinImage symbol = Forge.getAssets().symbolLookup().get(text.toString());
if (symbol != null) {
pieceWidth = lineHeight * CardFaceSymbols.FONT_SIZE_FACTOR;
if (x + pieceWidth > width) {

View File

@@ -17,10 +17,9 @@
*/
package forge.card;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import forge.Forge;
import forge.Graphics;
import forge.assets.FSkinImage;
import forge.card.mana.ManaCost;
@@ -30,141 +29,140 @@ import forge.gui.error.BugReporter;
public class CardFaceSymbols {
public static final float FONT_SIZE_FACTOR = 0.85f;
private static final Map<String, FSkinImage> MANA_IMAGES = new HashMap<>(128);
public static void loadImages() {
for (int i = 0; i <= 20; i++) {
MANA_IMAGES.put(String.valueOf(i), FSkinImage.valueOf("MANA_" + i));
Forge.getAssets().manaImages().put(String.valueOf(i), FSkinImage.valueOf("MANA_" + i));
}
MANA_IMAGES.put("X", FSkinImage.MANA_X);
MANA_IMAGES.put("Y", FSkinImage.MANA_Y);
MANA_IMAGES.put("Z", FSkinImage.MANA_Z);
Forge.getAssets().manaImages().put("X", FSkinImage.MANA_X);
Forge.getAssets().manaImages().put("Y", FSkinImage.MANA_Y);
Forge.getAssets().manaImages().put("Z", FSkinImage.MANA_Z);
MANA_IMAGES.put("C", FSkinImage.MANA_COLORLESS);
MANA_IMAGES.put("B", FSkinImage.MANA_B);
MANA_IMAGES.put("BG", FSkinImage.MANA_HYBRID_BG);
MANA_IMAGES.put("BR", FSkinImage.MANA_HYBRID_BR);
MANA_IMAGES.put("G", FSkinImage.MANA_G);
MANA_IMAGES.put("GU", FSkinImage.MANA_HYBRID_GU);
MANA_IMAGES.put("GW", FSkinImage.MANA_HYBRID_GW);
MANA_IMAGES.put("R", FSkinImage.MANA_R);
MANA_IMAGES.put("RG", FSkinImage.MANA_HYBRID_RG);
MANA_IMAGES.put("RW", FSkinImage.MANA_HYBRID_RW);
MANA_IMAGES.put("U", FSkinImage.MANA_U);
MANA_IMAGES.put("UB", FSkinImage.MANA_HYBRID_UB);
MANA_IMAGES.put("UR", FSkinImage.MANA_HYBRID_UR);
MANA_IMAGES.put("W", FSkinImage.MANA_W);
MANA_IMAGES.put("WB", FSkinImage.MANA_HYBRID_WB);
MANA_IMAGES.put("WU", FSkinImage.MANA_HYBRID_WU);
MANA_IMAGES.put("P", FSkinImage.MANA_PHRYX);
MANA_IMAGES.put("PW", FSkinImage.MANA_PHRYX_W);
MANA_IMAGES.put("PR", FSkinImage.MANA_PHRYX_R);
MANA_IMAGES.put("PU", FSkinImage.MANA_PHRYX_U);
MANA_IMAGES.put("PB", FSkinImage.MANA_PHRYX_B);
MANA_IMAGES.put("PG", FSkinImage.MANA_PHRYX_G);
MANA_IMAGES.put("PBG", FSkinImage.MANA_PHRYX_BG);
MANA_IMAGES.put("PBR", FSkinImage.MANA_PHRYX_BR);
MANA_IMAGES.put("PGU", FSkinImage.MANA_PHRYX_GU);
MANA_IMAGES.put("PGW", FSkinImage.MANA_PHRYX_GW);
MANA_IMAGES.put("PRG", FSkinImage.MANA_PHRYX_RG);
MANA_IMAGES.put("PRW", FSkinImage.MANA_PHRYX_RW);
MANA_IMAGES.put("PUB", FSkinImage.MANA_PHRYX_UB);
MANA_IMAGES.put("PUR", FSkinImage.MANA_PHRYX_UR);
MANA_IMAGES.put("PWB", FSkinImage.MANA_PHRYX_WB);
MANA_IMAGES.put("PWU", FSkinImage.MANA_PHRYX_WU);
MANA_IMAGES.put("2W", FSkinImage.MANA_2W);
MANA_IMAGES.put("2U", FSkinImage.MANA_2U);
MANA_IMAGES.put("2R", FSkinImage.MANA_2R);
MANA_IMAGES.put("2G", FSkinImage.MANA_2G);
MANA_IMAGES.put("2B", FSkinImage.MANA_2B);
Forge.getAssets().manaImages().put("C", FSkinImage.MANA_COLORLESS);
Forge.getAssets().manaImages().put("B", FSkinImage.MANA_B);
Forge.getAssets().manaImages().put("BG", FSkinImage.MANA_HYBRID_BG);
Forge.getAssets().manaImages().put("BR", FSkinImage.MANA_HYBRID_BR);
Forge.getAssets().manaImages().put("G", FSkinImage.MANA_G);
Forge.getAssets().manaImages().put("GU", FSkinImage.MANA_HYBRID_GU);
Forge.getAssets().manaImages().put("GW", FSkinImage.MANA_HYBRID_GW);
Forge.getAssets().manaImages().put("R", FSkinImage.MANA_R);
Forge.getAssets().manaImages().put("RG", FSkinImage.MANA_HYBRID_RG);
Forge.getAssets().manaImages().put("RW", FSkinImage.MANA_HYBRID_RW);
Forge.getAssets().manaImages().put("U", FSkinImage.MANA_U);
Forge.getAssets().manaImages().put("UB", FSkinImage.MANA_HYBRID_UB);
Forge.getAssets().manaImages().put("UR", FSkinImage.MANA_HYBRID_UR);
Forge.getAssets().manaImages().put("W", FSkinImage.MANA_W);
Forge.getAssets().manaImages().put("WB", FSkinImage.MANA_HYBRID_WB);
Forge.getAssets().manaImages().put("WU", FSkinImage.MANA_HYBRID_WU);
Forge.getAssets().manaImages().put("P", FSkinImage.MANA_PHRYX);
Forge.getAssets().manaImages().put("PW", FSkinImage.MANA_PHRYX_W);
Forge.getAssets().manaImages().put("PR", FSkinImage.MANA_PHRYX_R);
Forge.getAssets().manaImages().put("PU", FSkinImage.MANA_PHRYX_U);
Forge.getAssets().manaImages().put("PB", FSkinImage.MANA_PHRYX_B);
Forge.getAssets().manaImages().put("PG", FSkinImage.MANA_PHRYX_G);
Forge.getAssets().manaImages().put("PBG", FSkinImage.MANA_PHRYX_BG);
Forge.getAssets().manaImages().put("PBR", FSkinImage.MANA_PHRYX_BR);
Forge.getAssets().manaImages().put("PGU", FSkinImage.MANA_PHRYX_GU);
Forge.getAssets().manaImages().put("PGW", FSkinImage.MANA_PHRYX_GW);
Forge.getAssets().manaImages().put("PRG", FSkinImage.MANA_PHRYX_RG);
Forge.getAssets().manaImages().put("PRW", FSkinImage.MANA_PHRYX_RW);
Forge.getAssets().manaImages().put("PUB", FSkinImage.MANA_PHRYX_UB);
Forge.getAssets().manaImages().put("PUR", FSkinImage.MANA_PHRYX_UR);
Forge.getAssets().manaImages().put("PWB", FSkinImage.MANA_PHRYX_WB);
Forge.getAssets().manaImages().put("PWU", FSkinImage.MANA_PHRYX_WU);
Forge.getAssets().manaImages().put("2W", FSkinImage.MANA_2W);
Forge.getAssets().manaImages().put("2U", FSkinImage.MANA_2U);
Forge.getAssets().manaImages().put("2R", FSkinImage.MANA_2R);
Forge.getAssets().manaImages().put("2G", FSkinImage.MANA_2G);
Forge.getAssets().manaImages().put("2B", FSkinImage.MANA_2B);
MANA_IMAGES.put("S", FSkinImage.MANA_SNOW);
MANA_IMAGES.put("T", FSkinImage.TAP);
MANA_IMAGES.put("E", FSkinImage.ENERGY);
MANA_IMAGES.put("slash", FSkinImage.SLASH);
MANA_IMAGES.put("attack", FSkinImage.ATTACK);
MANA_IMAGES.put("defend", FSkinImage.DEFEND);
MANA_IMAGES.put("summonsick", FSkinImage.SUMMONSICK);
MANA_IMAGES.put("phasing", FSkinImage.PHASING);
MANA_IMAGES.put("sacrifice", FSkinImage.COSTRESERVED);
MANA_IMAGES.put("counters1", FSkinImage.COUNTERS1);
MANA_IMAGES.put("counters2", FSkinImage.COUNTERS2);
MANA_IMAGES.put("counters3", FSkinImage.COUNTERS3);
MANA_IMAGES.put("countersMulti", FSkinImage.COUNTERS_MULTI);
Forge.getAssets().manaImages().put("S", FSkinImage.MANA_SNOW);
Forge.getAssets().manaImages().put("T", FSkinImage.TAP);
Forge.getAssets().manaImages().put("E", FSkinImage.ENERGY);
Forge.getAssets().manaImages().put("slash", FSkinImage.SLASH);
Forge.getAssets().manaImages().put("attack", FSkinImage.ATTACK);
Forge.getAssets().manaImages().put("defend", FSkinImage.DEFEND);
Forge.getAssets().manaImages().put("summonsick", FSkinImage.SUMMONSICK);
Forge.getAssets().manaImages().put("phasing", FSkinImage.PHASING);
Forge.getAssets().manaImages().put("sacrifice", FSkinImage.COSTRESERVED);
Forge.getAssets().manaImages().put("counters1", FSkinImage.COUNTERS1);
Forge.getAssets().manaImages().put("counters2", FSkinImage.COUNTERS2);
Forge.getAssets().manaImages().put("counters3", FSkinImage.COUNTERS3);
Forge.getAssets().manaImages().put("countersMulti", FSkinImage.COUNTERS_MULTI);
MANA_IMAGES.put("foil01", FSkinImage.FOIL_01);
MANA_IMAGES.put("foil02", FSkinImage.FOIL_02);
MANA_IMAGES.put("foil03", FSkinImage.FOIL_03);
MANA_IMAGES.put("foil04", FSkinImage.FOIL_04);
MANA_IMAGES.put("foil05", FSkinImage.FOIL_05);
MANA_IMAGES.put("foil06", FSkinImage.FOIL_06);
MANA_IMAGES.put("foil07", FSkinImage.FOIL_07);
MANA_IMAGES.put("foil08", FSkinImage.FOIL_08);
MANA_IMAGES.put("foil09", FSkinImage.FOIL_09);
MANA_IMAGES.put("foil10", FSkinImage.FOIL_10);
Forge.getAssets().manaImages().put("foil01", FSkinImage.FOIL_01);
Forge.getAssets().manaImages().put("foil02", FSkinImage.FOIL_02);
Forge.getAssets().manaImages().put("foil03", FSkinImage.FOIL_03);
Forge.getAssets().manaImages().put("foil04", FSkinImage.FOIL_04);
Forge.getAssets().manaImages().put("foil05", FSkinImage.FOIL_05);
Forge.getAssets().manaImages().put("foil06", FSkinImage.FOIL_06);
Forge.getAssets().manaImages().put("foil07", FSkinImage.FOIL_07);
Forge.getAssets().manaImages().put("foil08", FSkinImage.FOIL_08);
Forge.getAssets().manaImages().put("foil09", FSkinImage.FOIL_09);
Forge.getAssets().manaImages().put("foil10", FSkinImage.FOIL_10);
MANA_IMAGES.put("foil11", FSkinImage.FOIL_11);
MANA_IMAGES.put("foil12", FSkinImage.FOIL_12);
MANA_IMAGES.put("foil13", FSkinImage.FOIL_13);
MANA_IMAGES.put("foil14", FSkinImage.FOIL_14);
MANA_IMAGES.put("foil15", FSkinImage.FOIL_15);
MANA_IMAGES.put("foil16", FSkinImage.FOIL_16);
MANA_IMAGES.put("foil17", FSkinImage.FOIL_17);
MANA_IMAGES.put("foil18", FSkinImage.FOIL_18);
MANA_IMAGES.put("foil19", FSkinImage.FOIL_19);
MANA_IMAGES.put("foil20", FSkinImage.FOIL_20);
Forge.getAssets().manaImages().put("foil11", FSkinImage.FOIL_11);
Forge.getAssets().manaImages().put("foil12", FSkinImage.FOIL_12);
Forge.getAssets().manaImages().put("foil13", FSkinImage.FOIL_13);
Forge.getAssets().manaImages().put("foil14", FSkinImage.FOIL_14);
Forge.getAssets().manaImages().put("foil15", FSkinImage.FOIL_15);
Forge.getAssets().manaImages().put("foil16", FSkinImage.FOIL_16);
Forge.getAssets().manaImages().put("foil17", FSkinImage.FOIL_17);
Forge.getAssets().manaImages().put("foil18", FSkinImage.FOIL_18);
Forge.getAssets().manaImages().put("foil19", FSkinImage.FOIL_19);
Forge.getAssets().manaImages().put("foil20", FSkinImage.FOIL_20);
MANA_IMAGES.put("commander", FSkinImage.IMG_ABILITY_COMMANDER);
Forge.getAssets().manaImages().put("commander", FSkinImage.IMG_ABILITY_COMMANDER);
MANA_IMAGES.put("deathtouch", FSkinImage.IMG_ABILITY_DEATHTOUCH);
MANA_IMAGES.put("defender", FSkinImage.IMG_ABILITY_DEFENDER);
MANA_IMAGES.put("doublestrike", FSkinImage.IMG_ABILITY_DOUBLE_STRIKE);
MANA_IMAGES.put("firststrike", FSkinImage.IMG_ABILITY_FIRST_STRIKE);
MANA_IMAGES.put("fear", FSkinImage.IMG_ABILITY_FEAR);
MANA_IMAGES.put("flash", FSkinImage.IMG_ABILITY_FLASH);
MANA_IMAGES.put("flying", FSkinImage.IMG_ABILITY_FLYING);
MANA_IMAGES.put("haste", FSkinImage.IMG_ABILITY_HASTE);
MANA_IMAGES.put("hexproof", FSkinImage.IMG_ABILITY_HEXPROOF);
MANA_IMAGES.put("horsemanship", FSkinImage.IMG_ABILITY_HORSEMANSHIP);
MANA_IMAGES.put("indestructible", FSkinImage.IMG_ABILITY_INDESTRUCTIBLE);
MANA_IMAGES.put("intimidate", FSkinImage.IMG_ABILITY_INTIMIDATE);
MANA_IMAGES.put("landwalk", FSkinImage.IMG_ABILITY_LANDWALK);
MANA_IMAGES.put("lifelink", FSkinImage.IMG_ABILITY_LIFELINK);
MANA_IMAGES.put("menace", FSkinImage.IMG_ABILITY_MENACE);
MANA_IMAGES.put("reach", FSkinImage.IMG_ABILITY_REACH);
MANA_IMAGES.put("shadow", FSkinImage.IMG_ABILITY_SHADOW);
MANA_IMAGES.put("shroud", FSkinImage.IMG_ABILITY_SHROUD);
MANA_IMAGES.put("trample", FSkinImage.IMG_ABILITY_TRAMPLE);
MANA_IMAGES.put("vigilance", FSkinImage.IMG_ABILITY_VIGILANCE);
Forge.getAssets().manaImages().put("deathtouch", FSkinImage.IMG_ABILITY_DEATHTOUCH);
Forge.getAssets().manaImages().put("defender", FSkinImage.IMG_ABILITY_DEFENDER);
Forge.getAssets().manaImages().put("doublestrike", FSkinImage.IMG_ABILITY_DOUBLE_STRIKE);
Forge.getAssets().manaImages().put("firststrike", FSkinImage.IMG_ABILITY_FIRST_STRIKE);
Forge.getAssets().manaImages().put("fear", FSkinImage.IMG_ABILITY_FEAR);
Forge.getAssets().manaImages().put("flash", FSkinImage.IMG_ABILITY_FLASH);
Forge.getAssets().manaImages().put("flying", FSkinImage.IMG_ABILITY_FLYING);
Forge.getAssets().manaImages().put("haste", FSkinImage.IMG_ABILITY_HASTE);
Forge.getAssets().manaImages().put("hexproof", FSkinImage.IMG_ABILITY_HEXPROOF);
Forge.getAssets().manaImages().put("horsemanship", FSkinImage.IMG_ABILITY_HORSEMANSHIP);
Forge.getAssets().manaImages().put("indestructible", FSkinImage.IMG_ABILITY_INDESTRUCTIBLE);
Forge.getAssets().manaImages().put("intimidate", FSkinImage.IMG_ABILITY_INTIMIDATE);
Forge.getAssets().manaImages().put("landwalk", FSkinImage.IMG_ABILITY_LANDWALK);
Forge.getAssets().manaImages().put("lifelink", FSkinImage.IMG_ABILITY_LIFELINK);
Forge.getAssets().manaImages().put("menace", FSkinImage.IMG_ABILITY_MENACE);
Forge.getAssets().manaImages().put("reach", FSkinImage.IMG_ABILITY_REACH);
Forge.getAssets().manaImages().put("shadow", FSkinImage.IMG_ABILITY_SHADOW);
Forge.getAssets().manaImages().put("shroud", FSkinImage.IMG_ABILITY_SHROUD);
Forge.getAssets().manaImages().put("trample", FSkinImage.IMG_ABILITY_TRAMPLE);
Forge.getAssets().manaImages().put("vigilance", FSkinImage.IMG_ABILITY_VIGILANCE);
//hexproof from
MANA_IMAGES.put("hexproofR", FSkinImage.IMG_ABILITY_HEXPROOF_R);
MANA_IMAGES.put("hexproofG", FSkinImage.IMG_ABILITY_HEXPROOF_G);
MANA_IMAGES.put("hexproofB", FSkinImage.IMG_ABILITY_HEXPROOF_B);
MANA_IMAGES.put("hexproofU", FSkinImage.IMG_ABILITY_HEXPROOF_U);
MANA_IMAGES.put("hexproofW", FSkinImage.IMG_ABILITY_HEXPROOF_W);
MANA_IMAGES.put("hexproofC", FSkinImage.IMG_ABILITY_HEXPROOF_C);
MANA_IMAGES.put("hexproofUB", FSkinImage.IMG_ABILITY_HEXPROOF_UB);
Forge.getAssets().manaImages().put("hexproofR", FSkinImage.IMG_ABILITY_HEXPROOF_R);
Forge.getAssets().manaImages().put("hexproofG", FSkinImage.IMG_ABILITY_HEXPROOF_G);
Forge.getAssets().manaImages().put("hexproofB", FSkinImage.IMG_ABILITY_HEXPROOF_B);
Forge.getAssets().manaImages().put("hexproofU", FSkinImage.IMG_ABILITY_HEXPROOF_U);
Forge.getAssets().manaImages().put("hexproofW", FSkinImage.IMG_ABILITY_HEXPROOF_W);
Forge.getAssets().manaImages().put("hexproofC", FSkinImage.IMG_ABILITY_HEXPROOF_C);
Forge.getAssets().manaImages().put("hexproofUB", FSkinImage.IMG_ABILITY_HEXPROOF_UB);
//token icon
MANA_IMAGES.put("token", FSkinImage.IMG_ABILITY_TOKEN);
Forge.getAssets().manaImages().put("token", FSkinImage.IMG_ABILITY_TOKEN);
//protection from
MANA_IMAGES.put("protectAll", FSkinImage.IMG_ABILITY_PROTECT_ALL);
MANA_IMAGES.put("protectB", FSkinImage.IMG_ABILITY_PROTECT_B);
MANA_IMAGES.put("protectBU", FSkinImage.IMG_ABILITY_PROTECT_BU);
MANA_IMAGES.put("protectBW", FSkinImage.IMG_ABILITY_PROTECT_BW);
MANA_IMAGES.put("protectColoredSpells", FSkinImage.IMG_ABILITY_PROTECT_COLOREDSPELLS);
MANA_IMAGES.put("protectG", FSkinImage.IMG_ABILITY_PROTECT_G);
MANA_IMAGES.put("protectGB", FSkinImage.IMG_ABILITY_PROTECT_GB);
MANA_IMAGES.put("protectGU", FSkinImage.IMG_ABILITY_PROTECT_GU);
MANA_IMAGES.put("protectGW", FSkinImage.IMG_ABILITY_PROTECT_GW);
MANA_IMAGES.put("protectGeneric", FSkinImage.IMG_ABILITY_PROTECT_GENERIC);
MANA_IMAGES.put("protectR", FSkinImage.IMG_ABILITY_PROTECT_R);
MANA_IMAGES.put("protectRB", FSkinImage.IMG_ABILITY_PROTECT_RB);
MANA_IMAGES.put("protectRG", FSkinImage.IMG_ABILITY_PROTECT_RG);
MANA_IMAGES.put("protectRU", FSkinImage.IMG_ABILITY_PROTECT_RU);
MANA_IMAGES.put("protectRW", FSkinImage.IMG_ABILITY_PROTECT_RW);
MANA_IMAGES.put("protectU", FSkinImage.IMG_ABILITY_PROTECT_U);
MANA_IMAGES.put("protectUW", FSkinImage.IMG_ABILITY_PROTECT_UW);
MANA_IMAGES.put("protectW", FSkinImage.IMG_ABILITY_PROTECT_W);
Forge.getAssets().manaImages().put("protectAll", FSkinImage.IMG_ABILITY_PROTECT_ALL);
Forge.getAssets().manaImages().put("protectB", FSkinImage.IMG_ABILITY_PROTECT_B);
Forge.getAssets().manaImages().put("protectBU", FSkinImage.IMG_ABILITY_PROTECT_BU);
Forge.getAssets().manaImages().put("protectBW", FSkinImage.IMG_ABILITY_PROTECT_BW);
Forge.getAssets().manaImages().put("protectColoredSpells", FSkinImage.IMG_ABILITY_PROTECT_COLOREDSPELLS);
Forge.getAssets().manaImages().put("protectG", FSkinImage.IMG_ABILITY_PROTECT_G);
Forge.getAssets().manaImages().put("protectGB", FSkinImage.IMG_ABILITY_PROTECT_GB);
Forge.getAssets().manaImages().put("protectGU", FSkinImage.IMG_ABILITY_PROTECT_GU);
Forge.getAssets().manaImages().put("protectGW", FSkinImage.IMG_ABILITY_PROTECT_GW);
Forge.getAssets().manaImages().put("protectGeneric", FSkinImage.IMG_ABILITY_PROTECT_GENERIC);
Forge.getAssets().manaImages().put("protectR", FSkinImage.IMG_ABILITY_PROTECT_R);
Forge.getAssets().manaImages().put("protectRB", FSkinImage.IMG_ABILITY_PROTECT_RB);
Forge.getAssets().manaImages().put("protectRG", FSkinImage.IMG_ABILITY_PROTECT_RG);
Forge.getAssets().manaImages().put("protectRU", FSkinImage.IMG_ABILITY_PROTECT_RU);
Forge.getAssets().manaImages().put("protectRW", FSkinImage.IMG_ABILITY_PROTECT_RW);
Forge.getAssets().manaImages().put("protectU", FSkinImage.IMG_ABILITY_PROTECT_U);
Forge.getAssets().manaImages().put("protectUW", FSkinImage.IMG_ABILITY_PROTECT_UW);
Forge.getAssets().manaImages().put("protectW", FSkinImage.IMG_ABILITY_PROTECT_W);
}
public static void drawManaCost(Graphics g, ManaCost manaCost, float x, float y, final float imageSize) {
@@ -228,7 +226,7 @@ public class CardFaceSymbols {
StringTokenizer tok = new StringTokenizer(s, " ");
while (tok.hasMoreTokens()) {
String symbol = tok.nextToken();
FSkinImage image = MANA_IMAGES.get(symbol);
FSkinImage image = Forge.getAssets().manaImages().get(symbol);
if (image == null) {
BugReporter.reportBug("Symbol not recognized \"" + symbol + "\" in string: " + s);
continue;
@@ -245,7 +243,7 @@ public class CardFaceSymbols {
}
public static void drawSymbol(final String imageName, final Graphics g, final float x, final float y, final float w, final float h) {
g.drawImage(MANA_IMAGES.get(imageName), x, y, w, h);
g.drawImage(Forge.getAssets().manaImages().get(imageName), x, y, w, h);
}
public static float getWidth(final ManaCost manaCost, float imageSize) {

View File

@@ -52,6 +52,7 @@ public class CardImageRenderer {
prevImageWidth = 0;
prevImageHeight = 0;
forgeArt.clear();
stretchedArt.clear();
}
private static void updateStaticFields(float w, float h) {
@@ -267,6 +268,7 @@ public class CardImageRenderer {
}
public static final FBufferedImage forgeArt;
private static final FBufferedImage stretchedArt;
static {
final float logoWidth = FSkinImage.LOGO.getWidth();
final float logoHeight = FSkinImage.LOGO.getHeight();
@@ -280,9 +282,25 @@ public class CardImageRenderer {
g.drawImage(FSkinImage.LOGO, (w - logoWidth) / 2, (h - logoHeight) / 2, logoWidth, logoHeight);
}
};
stretchedArt = new FBufferedImage(w, h) {
@Override
protected void draw(Graphics g, float w, float h) {
g.drawImage(FSkinTexture.BG_TEXTURE, 0, 0, w, h);
g.fillRect(FScreen.TEXTURE_OVERLAY_COLOR, 0, 0, w, h);
g.drawImage(FSkinImage.LOGO, (w - logoWidth) / 2, ((h - logoHeight) / 2)+h/3.5f, logoWidth, logoHeight/3);
}
};
}
private static void drawArt(CardView cv, Graphics g, float x, float y, float w, float h, boolean altState, boolean isFaceDown) {
boolean isSaga = cv.getCurrentState().getType().hasSubtype("Saga");
boolean isClass = cv.getCurrentState().getType().hasSubtype("Class");
boolean isDungeon = cv.getCurrentState().getType().isDungeon();
if (altState && cv.hasAlternateState()) {
isSaga = cv.getAlternateState().getType().hasSubtype("Saga");
isClass = cv.getAlternateState().getType().hasSubtype("Class");
isDungeon = cv.getAlternateState().getType().isDungeon();
}
if (cv == null) {
if (isFaceDown) {
Texture cardBack = ImageCache.getImage(ImageKeys.getTokenKey(ImageKeys.HIDDEN_CARD), false);
@@ -292,7 +310,11 @@ public class CardImageRenderer {
}
}
//fallback
g.drawImage(forgeArt, x, y, w, h);
if (isSaga || isClass || isDungeon) {
g.drawImage(stretchedArt, x, y, w, h);
} else {
g.drawImage(forgeArt, x, y, w, h);
}
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
return;
}
@@ -303,7 +325,11 @@ public class CardImageRenderer {
|| cv.getCurrentState().getImageKey().equals(ImageKeys.getTokenKey(ImageKeys.FORETELL_IMAGE)));
if (cardArt != null) {
if (isHidden && !altState) {
if (isSaga || isClass || isDungeon) {
g.drawImage(stretchedArt, x, y, w, h);
} else {
g.drawImage(forgeArt, x, y, w, h);
}
} else if (cv.getCurrentState().getImageKey().equals(ImageKeys.getTokenKey(ImageKeys.MANIFEST_IMAGE)) && !altState) {
altArt = CardRenderer.getAlternateCardArt(ImageKeys.getTokenKey(ImageKeys.MANIFEST_IMAGE), false);
g.drawImage(altArt, x, y, w, h);
@@ -330,10 +356,18 @@ public class CardImageRenderer {
}
}
} else {
g.drawImage(forgeArt, x, y, w, h);
if (isSaga || isClass || isDungeon) {
g.drawImage(stretchedArt, x, y, w, h);
} else {
g.drawImage(forgeArt, x, y, w, h);
}
}
} else {
g.drawImage(forgeArt, x, y, w, h);
if (isSaga || isClass || isDungeon) {
g.drawImage(stretchedArt, x, y, w, h);
} else {
g.drawImage(forgeArt, x, y, w, h);
}
}
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
}

View File

@@ -67,28 +67,28 @@ public class CardRenderer {
// class that simplifies the callback logic of CachedCardImage
static class RendererCachedCardImage extends CachedCardImage {
boolean clearCardArtCache = false;
boolean clearcardArtCache = false;
public RendererCachedCardImage(CardView card, boolean clearArtCache) {
super(card);
this.clearCardArtCache = clearArtCache;
this.clearcardArtCache = clearArtCache;
}
public RendererCachedCardImage(InventoryItem ii, boolean clearArtCache) {
super(ii);
this.clearCardArtCache = clearArtCache;
this.clearcardArtCache = clearArtCache;
}
public RendererCachedCardImage(String key, boolean clearArtCache) {
super(key);
this.clearCardArtCache = clearArtCache;
this.clearcardArtCache = clearArtCache;
}
@Override
public void onImageFetched() {
ImageCache.clear();
if (clearCardArtCache) {
cardArtCache.remove(key);
if (clearcardArtCache) {
Forge.getAssets().cardArtCache().remove(key);
}
}
}
@@ -104,8 +104,6 @@ public class CardRenderer {
private static final float BORDER_THICKNESS = Utils.scale(1);
public static final float PADDING_MULTIPLIER = 0.021f;
public static final float CROP_MULTIPLIER = 0.96f;
private static Map<Integer, BitmapFont> counterFonts = new HashMap<>();
private static final Color counterBackgroundColor = new Color(0f, 0f, 0f, 0.9f);
private static final Map<CounterType, Color> counterColorCache = new HashMap<>();
private static final GlyphLayout layout = new GlyphLayout();
@@ -191,13 +189,12 @@ public class CardRenderer {
return Math.round(MANA_SYMBOL_SIZE + FSkinFont.get(12).getLineHeight() + 3 * FList.PADDING + 1);
}
private static final Map<String, FImageComplex> cardArtCache = new HashMap<>(1024);
public static final float CARD_ART_RATIO = 1.302f;
public static final float CARD_ART_HEIGHT_PERCENTAGE = 0.43f;
private static List<String> classicModuleCardtoCrop = FileUtil.readFile(ForgeConstants.CLASSIC_MODULE_CARD_TO_CROP_FILE);
public static void clearcardArtCache(){
cardArtCache.clear();
Forge.getAssets().cardArtCache().clear();
}
//extract card art from the given card
@@ -221,7 +218,7 @@ public class CardRenderer {
}
public static FImageComplex getCardArt(String imageKey, boolean isSplitCard, boolean isHorizontalCard, boolean isAftermathCard, boolean isSaga, boolean isClass, boolean isDungeon, boolean isFlipCard, boolean isPlanesWalker, boolean isModernFrame) {
FImageComplex cardArt = cardArtCache.get(imageKey);
FImageComplex cardArt = Forge.getAssets().cardArtCache().get(imageKey);
boolean isClassicModule = imageKey != null && imageKey.length() > 2 && classicModuleCardtoCrop.contains(imageKey.substring(ImageKeys.CARD_PREFIX.length()).replace(".jpg", "").replace(".png", ""));
if (cardArt == null) {
Texture image = new RendererCachedCardImage(imageKey, true).getImage();
@@ -282,7 +279,7 @@ public class CardRenderer {
w *= artH / srcH;
h *= artW / srcW;
cardArt = new FRotatedImage(image, Math.round(x), Math.round(y), Math.round(w), Math.round(h), true);
cardArtCache.put(imageKey, cardArt);
Forge.getAssets().cardArtCache().put(imageKey, cardArt);
return cardArt;
}
} else {
@@ -305,7 +302,7 @@ public class CardRenderer {
cardArt = new FTextureRegionImage(new TextureRegion(image, Math.round(x), Math.round(y), Math.round(w), Math.round(h)));
}
if (!CardImageRenderer.forgeArt.equals(cardArt))
cardArtCache.put(imageKey, cardArt);
Forge.getAssets().cardArtCache().put(imageKey, cardArt);
}
}
//fix display for effect
@@ -315,13 +312,13 @@ public class CardRenderer {
}
public static FImageComplex getAftermathSecondCardArt(final String imageKey) {
FImageComplex cardArt = cardArtCache.get("Aftermath_second_"+imageKey);
FImageComplex cardArt = Forge.getAssets().cardArtCache().get("Aftermath_second_"+imageKey);
if (cardArt == null) {
Texture image = new CachedCardImage(imageKey) {
@Override
public void onImageFetched() {
ImageCache.clear();
cardArtCache.remove("Aftermath_second_" + imageKey);
Forge.getAssets().cardArtCache().remove("Aftermath_second_" + imageKey);
}
}.getImage();
if (image != null) {
@@ -341,20 +338,20 @@ public class CardRenderer {
}
if (!CardImageRenderer.forgeArt.equals(cardArt))
cardArtCache.put("Aftermath_second_"+imageKey, cardArt);
Forge.getAssets().cardArtCache().put("Aftermath_second_"+imageKey, cardArt);
}
}
return cardArt;
}
public static FImageComplex getAlternateCardArt(final String imageKey, boolean isPlanesWalker) {
FImageComplex cardArt = cardArtCache.get("Alternate_"+imageKey);
FImageComplex cardArt = Forge.getAssets().cardArtCache().get("Alternate_"+imageKey);
if (cardArt == null) {
Texture image = new CachedCardImage(imageKey) {
@Override
public void onImageFetched() {
ImageCache.clear();
cardArtCache.remove("Alternate_" + imageKey);
Forge.getAssets().cardArtCache().remove("Alternate_" + imageKey);
}
}.getImage();
if (image != null) {
@@ -388,7 +385,7 @@ public class CardRenderer {
cardArt = new FTextureRegionImage(new TextureRegion(image, Math.round(x), Math.round(y), Math.round(w), Math.round(h)));
}
if (!CardImageRenderer.forgeArt.equals(cardArt))
cardArtCache.put("Alternate_"+imageKey, cardArt);
Forge.getAssets().cardArtCache().put("Alternate_"+imageKey, cardArt);
}
}
return cardArt;
@@ -397,9 +394,9 @@ public class CardRenderer {
public static FImageComplex getMeldCardParts(final String imageKey, boolean bottom) {
FImageComplex cardArt;
if (!bottom) {
cardArt = cardArtCache.get("Meld_primary_"+imageKey);
cardArt = Forge.getAssets().cardArtCache().get("Meld_primary_"+imageKey);
} else {
cardArt = cardArtCache.get("Meld_secondary_"+imageKey);
cardArt = Forge.getAssets().cardArtCache().get("Meld_secondary_"+imageKey);
}
if (cardArt == null) {
@@ -407,8 +404,8 @@ public class CardRenderer {
@Override
public void onImageFetched() {
ImageCache.clear();
cardArtCache.remove("Meld_primary_" + imageKey);
cardArtCache.remove("Meld_secondary_" + imageKey);
Forge.getAssets().cardArtCache().remove("Meld_primary_" + imageKey);
Forge.getAssets().cardArtCache().remove("Meld_secondary_" + imageKey);
}
}.getImage();
if (image != null) {
@@ -423,9 +420,9 @@ public class CardRenderer {
}
if (!bottom && !CardImageRenderer.forgeArt.equals(cardArt))
cardArtCache.put("Meld_primary_"+imageKey, cardArt);
Forge.getAssets().cardArtCache().put("Meld_primary_"+imageKey, cardArt);
else if (!CardImageRenderer.forgeArt.equals(cardArt))
cardArtCache.put("Meld_secondary_"+imageKey, cardArt);
Forge.getAssets().cardArtCache().put("Meld_secondary_"+imageKey, cardArt);
}
}
return cardArt;
@@ -1101,7 +1098,7 @@ public class CardRenderer {
private static void drawCounterTabs(final CardView card, final Graphics g, final float x, final float y, final float w, final float h) {
int fontSize = Math.max(11, Math.min(22, (int) (h * 0.08)));
BitmapFont font = counterFonts.get(fontSize);
BitmapFont font = Forge.getAssets().counterFonts().get(fontSize);
final float additionalXOffset = 3f * ((fontSize - 11) / 11f);
final float variableWidth = ((fontSize - 11) / 11f) * 44f;
@@ -1218,7 +1215,7 @@ public class CardRenderer {
private static void drawMarkersTabs(final List<String> markers, final Graphics g, final float x, final float y, final float w, final float h, boolean larger) {
int fontSize = larger ? Math.max(9, Math.min(22, (int) (h * 0.08))) : Math.max(8, Math.min(22, (int) (h * 0.05)));
BitmapFont font = counterFonts.get(fontSize);
BitmapFont font = Forge.getAssets().counterFonts().get(fontSize);
final float additionalXOffset = 3f * ((fontSize - 8) / 8f);
@@ -1410,7 +1407,7 @@ public class CardRenderer {
textureRegions.add(new TextureRegion(texture));
}
counterFonts.put(fontSize, new BitmapFont(fontData, textureRegions, true));
Forge.getAssets().counterFonts().put(fontSize, new BitmapFont(fontData, textureRegions, true));
generator.dispose();
packer.dispose();

View File

@@ -131,75 +131,59 @@ public class FDeckChooser extends FScreen {
lstDecks = new DeckManager(gameType0);
isAi = isAi0;
lstDecks.setItemActivateHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (lstDecks.getGameType() == GameType.DeckManager) {
//for Deck Editor, edit deck instead of accepting
editSelectedDeck();
return;
}
accept();
}
});
btnNewDeck.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
createNewDeck();
}
});
btnEditDeck.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
lstDecks.setItemActivateHandler(event -> {
if (lstDecks.getGameType() == GameType.DeckManager) {
//for Deck Editor, edit deck instead of accepting
editSelectedDeck();
return;
}
accept();
});
btnNewDeck.setCommand(event -> createNewDeck());
btnEditDeck.setCommand(event -> editSelectedDeck());
btnViewDeck.setCommand(event -> {
if (selectedDeckType != DeckType.STANDARD_COLOR_DECK && selectedDeckType != DeckType.STANDARD_CARDGEN_DECK
&& selectedDeckType != DeckType.PIONEER_CARDGEN_DECK && selectedDeckType != DeckType.HISTORIC_CARDGEN_DECK
&& selectedDeckType != DeckType.MODERN_CARDGEN_DECK && selectedDeckType != DeckType.LEGACY_CARDGEN_DECK
&& selectedDeckType != DeckType.VINTAGE_CARDGEN_DECK && selectedDeckType != DeckType.MODERN_COLOR_DECK &&
selectedDeckType != DeckType.COLOR_DECK && selectedDeckType != DeckType.THEME_DECK
&& selectedDeckType != DeckType.RANDOM_COMMANDER_DECK && selectedDeckType != DeckType.RANDOM_CARDGEN_COMMANDER_DECK) {
FDeckViewer.show(getDeck(), false, DeckType.DRAFT_DECK.equals(selectedDeckType));
}
});
btnViewDeck.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (selectedDeckType != DeckType.STANDARD_COLOR_DECK && selectedDeckType != DeckType.STANDARD_CARDGEN_DECK
&& selectedDeckType != DeckType.PIONEER_CARDGEN_DECK && selectedDeckType != DeckType.HISTORIC_CARDGEN_DECK
&& selectedDeckType != DeckType.MODERN_CARDGEN_DECK && selectedDeckType != DeckType.LEGACY_CARDGEN_DECK
&& selectedDeckType != DeckType.VINTAGE_CARDGEN_DECK && selectedDeckType != DeckType.MODERN_COLOR_DECK &&
selectedDeckType != DeckType.COLOR_DECK && selectedDeckType != DeckType.THEME_DECK
&& selectedDeckType != DeckType.RANDOM_COMMANDER_DECK && selectedDeckType != DeckType.RANDOM_CARDGEN_COMMANDER_DECK) {
FDeckViewer.show(getDeck(), false, DeckType.DRAFT_DECK.equals(selectedDeckType));
}
btnRandom.setCommand(event -> {
if (lstDecks.getGameType() == GameType.DeckManager) {
//for Deck Editor, test deck instead of randomly selecting deck
testSelectedDeck();
return;
}
});
btnRandom.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (lstDecks.getGameType() == GameType.DeckManager) {
//for Deck Editor, test deck instead of randomly selecting deck
testSelectedDeck();
return;
}
if (selectedDeckType == DeckType.COLOR_DECK || selectedDeckType == DeckType.STANDARD_COLOR_DECK
|| selectedDeckType == DeckType.MODERN_COLOR_DECK) {
DeckgenUtil.randomSelectColors(lstDecks);
}
else if (selectedDeckType == DeckType.STANDARD_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.PIONEER_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.HISTORIC_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.MODERN_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.LEGACY_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.VINTAGE_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else {
int size = 0;
if (selectedDeckType == DeckType.COLOR_DECK || selectedDeckType == DeckType.STANDARD_COLOR_DECK
|| selectedDeckType == DeckType.MODERN_COLOR_DECK) {
DeckgenUtil.randomSelectColors(lstDecks);
}
else if (selectedDeckType == DeckType.STANDARD_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.PIONEER_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.HISTORIC_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.MODERN_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.LEGACY_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.VINTAGE_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else {
int size = 0;
try {
if (isAi && !isGeneratedDeck(selectedDeckType) && Forge.autoAIDeckSelection) {
btnRandom.setEnabled(false);
AIDecks = lstDecks.getPool().toFlatList().parallelStream().filter(deckProxy -> deckProxy.getAI().inMainDeck == 0).collect(Collectors.toList());
size = AIDecks.size();
}
@@ -207,9 +191,12 @@ public class FDeckChooser extends FScreen {
lstDecks.setSelectedItem(AIDecks.get(MyRandom.getRandom().nextInt(size)));
else
DeckgenUtil.randomSelect(lstDecks);
} catch (Exception ee) {
DeckgenUtil.randomSelect(lstDecks);
}
accept();
}
btnRandom.setEnabled(true);
accept();
});
switch (lstDecks.getGameType()) {
case Constructed:
@@ -371,32 +358,29 @@ public class FDeckChooser extends FScreen {
} else {
editor = new FDeckEditor(getEditorType(), "", false);
}
editor.setSaveHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
//ensure user returns to proper deck type and that list is refreshed if new deck is saved
if (!needRefreshOnActivate) {
needRefreshOnActivate = true;
if (lstDecks.getGameType() == GameType.DeckManager) {
switch (selectedDeckType) {
case COMMANDER_DECK:
case OATHBREAKER_DECK:
case TINY_LEADERS_DECK:
case BRAWL_DECK:
case SCHEME_DECK:
case PLANAR_DECK:
case DRAFT_DECK:
case SEALED_DECK:
break;
default:
setSelectedDeckType(DeckType.CONSTRUCTED_DECK);
break;
}
}
else {
setSelectedDeckType(DeckType.CUSTOM_DECK);
editor.setSaveHandler(event -> {
//ensure user returns to proper deck type and that list is refreshed if new deck is saved
if (!needRefreshOnActivate) {
needRefreshOnActivate = true;
if (lstDecks.getGameType() == GameType.DeckManager) {
switch (selectedDeckType) {
case COMMANDER_DECK:
case OATHBREAKER_DECK:
case TINY_LEADERS_DECK:
case BRAWL_DECK:
case SCHEME_DECK:
case PLANAR_DECK:
case DRAFT_DECK:
case SEALED_DECK:
break;
default:
setSelectedDeckType(DeckType.CONSTRUCTED_DECK);
break;
}
}
else {
setSelectedDeckType(DeckType.CUSTOM_DECK);
}
}
});
Forge.openScreen(editor);
@@ -624,249 +608,205 @@ public class FDeckChooser extends FScreen {
cmbDeckTypes.setAlignment(Align.center);
restoreSavedState();
cmbDeckTypes.setChangedHandler(new FEventHandler() {
@Override
cmbDeckTypes.setChangedHandler(event -> {
final DeckType deckType = cmbDeckTypes.getSelectedItem();
public void handleEvent(final FEvent e) {
final DeckType deckType = cmbDeckTypes.getSelectedItem();
if (!refreshingDeckType&&(deckType == DeckType.NET_DECK || deckType == DeckType.NET_COMMANDER_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = deckType == DeckType.NET_COMMANDER_DECK ? GameType.Commander : GameType.Constructed;
}
final NetDeckCategory category = NetDeckCategory.selectAndLoad(gameType);
if (!refreshingDeckType&&(deckType == DeckType.NET_DECK || deckType == DeckType.NET_COMMANDER_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = deckType == DeckType.NET_COMMANDER_DECK ? GameType.Commander : GameType.Constructed;
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && netDeckCategory != null) {
cmbDeckTypes.setText(netDeckCategory.getDeckType());
}
final NetDeckCategory category = NetDeckCategory.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && netDeckCategory != null) {
cmbDeckTypes.setText(netDeckCategory.getDeckType());
}
return;
}
netDeckCategory = category;
refreshDecksList(deckType, true, e);
}
});
return;
}
netDeckCategory = category;
refreshDecksList(deckType, true, event);
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_STANDARD_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveStandard category = NetDeckArchiveStandard.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveStandard != null) {
cmbDeckTypes.setText(NetDeckArchiveStandard.getDeckType());
}
return;
}
NetDeckArchiveStandard = category;
refreshDecksList(deckType, true, e);
}
});
}
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_PIONEER_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchivePioneer category = NetDeckArchivePioneer.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchivePioneer != null) {
cmbDeckTypes.setText(NetDeckArchivePioneer.getDeckType());
}
return;
}
NetDeckArchivePioneer = category;
refreshDecksList(deckType, true, e);
}
});
}
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_MODERN_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveModern category = NetDeckArchiveModern.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveModern != null) {
cmbDeckTypes.setText(NetDeckArchiveModern.getDeckType());
}
return;
}
NetDeckArchiveModern = category;
refreshDecksList(deckType, true, e);
}
});
}
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_PAUPER_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchivePauper category = NetDeckArchivePauper.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchivePauper != null) {
cmbDeckTypes.setText(NetDeckArchivePauper.getDeckType());
}
return;
}
NetDeckArchivePauper = category;
refreshDecksList(deckType, true, e);
}
});
}
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_LEGACY_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveLegacy category = NetDeckArchiveLegacy.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveLegacy != null) {
cmbDeckTypes.setText(NetDeckArchiveLegacy.getDeckType());
}
return;
}
NetDeckArchiveLegacy = category;
refreshDecksList(deckType, true, e);
}
});
}
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_VINTAGE_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveVintage category = NetDeckArchiveVintage.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveVintage != null) {
cmbDeckTypes.setText(NetDeckArchiveVintage.getDeckType());
}
return;
}
NetDeckArchiveVintage = category;
refreshDecksList(deckType, true, e);
}
});
}
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_BLOCK_DECK)) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveBlock category = NetDeckArchiveBlock.selectAndLoad(gameType);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveBlock != null) {
cmbDeckTypes.setText(NetDeckArchiveBlock.getDeckType());
}
return;
}
NetDeckArchiveBlock = category;
refreshDecksList(deckType, true, e);
}
});
}
});
return;
}
refreshDecksList(deckType, false, e);
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_STANDARD_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveStandard category = NetDeckArchiveStandard.selectAndLoad(gameType);
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveStandard != null) {
cmbDeckTypes.setText(NetDeckArchiveStandard.getDeckType());
}
return;
}
NetDeckArchiveStandard = category;
refreshDecksList(deckType, true, event);
});
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_PIONEER_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchivePioneer category = NetDeckArchivePioneer.selectAndLoad(gameType);
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchivePioneer != null) {
cmbDeckTypes.setText(NetDeckArchivePioneer.getDeckType());
}
return;
}
NetDeckArchivePioneer = category;
refreshDecksList(deckType, true, event);
});
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_MODERN_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveModern category = NetDeckArchiveModern.selectAndLoad(gameType);
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveModern != null) {
cmbDeckTypes.setText(NetDeckArchiveModern.getDeckType());
}
return;
}
NetDeckArchiveModern = category;
refreshDecksList(deckType, true, event);
});
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_PAUPER_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchivePauper category = NetDeckArchivePauper.selectAndLoad(gameType);
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchivePauper != null) {
cmbDeckTypes.setText(NetDeckArchivePauper.getDeckType());
}
return;
}
NetDeckArchivePauper = category;
refreshDecksList(deckType, true, event);
});
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_LEGACY_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveLegacy category = NetDeckArchiveLegacy.selectAndLoad(gameType);
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveLegacy != null) {
cmbDeckTypes.setText(NetDeckArchiveLegacy.getDeckType());
}
return;
}
NetDeckArchiveLegacy = category;
refreshDecksList(deckType, true, event);
});
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_VINTAGE_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveVintage category = NetDeckArchiveVintage.selectAndLoad(gameType);
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveVintage != null) {
cmbDeckTypes.setText(NetDeckArchiveVintage.getDeckType());
}
return;
}
NetDeckArchiveVintage = category;
refreshDecksList(deckType, true, event);
});
});
return;
}
if (!refreshingDeckType&&(deckType == DeckType.NET_ARCHIVE_BLOCK_DECK)) {
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
GameType gameType = lstDecks.getGameType();
if (gameType == GameType.DeckManager) {
gameType = GameType.Constructed;
}
final NetDeckArchiveBlock category = NetDeckArchiveBlock.selectAndLoad(gameType);
FThreads.invokeInEdtLater(() -> {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == deckType && NetDeckArchiveBlock != null) {
cmbDeckTypes.setText(NetDeckArchiveBlock.getDeckType());
}
return;
}
NetDeckArchiveBlock = category;
refreshDecksList(deckType, true, event);
});
});
return;
}
refreshDecksList(deckType, false, event);
});
add(cmbDeckTypes);
add(lstDecks);
@@ -888,11 +828,11 @@ public class FDeckChooser extends FScreen {
saveState();
}
private void refreshDecksList(DeckType deckType, boolean forceRefresh, FEvent e) {
private void refreshDecksList(DeckType deckType, boolean forceRefresh, FEvent event) {
if (selectedDeckType == deckType && !forceRefresh) { return; }
selectedDeckType = deckType;
if (e == null) {
if (event == null) {
refreshingDeckType = true;
cmbDeckTypes.setSelectedItem(deckType);
refreshingDeckType = false;
@@ -1186,7 +1126,7 @@ public class FDeckChooser extends FScreen {
btnRandom.setLeft(getWidth() - PADDING - btnRandom.getWidth());
if (e != null) { //set default list selection if from combo box change event
if (event != null) { //set default list selection if from combo box change event
if (deckType == DeckType.COLOR_DECK) {
// default selection = basic two color deck
lstDecks.setSelectedIndices(new Integer[]{0, 1});
@@ -1510,36 +1450,26 @@ public class FDeckChooser extends FScreen {
return;
}
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
final NetDeckCategory netCat;
if (allowedDeckTypes.contains(DeckType.NET_DECK)) {
netCat = NetDeckCategory.selectAndLoad(GameType.Constructed);
} else {
netCat = null;
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
GauntletData gauntlet = GauntletUtil.createQuickGauntlet(userDeck, numOpponents, allowedDeckTypes, netCat);
FModel.setGauntletData(gauntlet);
List<RegisteredPlayer> players = new ArrayList<>();
RegisteredPlayer humanPlayer = new RegisteredPlayer(userDeck).setPlayer(GamePlayerUtil.getGuiPlayer());
players.add(humanPlayer);
players.add(new RegisteredPlayer(gauntlet.getDecks().get(gauntlet.getCompleted())).setPlayer(GamePlayerUtil.createAiPlayer()));
gauntlet.startRound(players, humanPlayer);
}
});
}
});
//needed for loading net decks
FThreads.invokeInBackgroundThread(() -> {
final NetDeckCategory netCat;
if (allowedDeckTypes.contains(DeckType.NET_DECK)) {
netCat = NetDeckCategory.selectAndLoad(GameType.Constructed);
} else {
netCat = null;
}
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> {
GauntletData gauntlet = GauntletUtil.createQuickGauntlet(userDeck, numOpponents, allowedDeckTypes, netCat);
FModel.setGauntletData(gauntlet);
List<RegisteredPlayer> players = new ArrayList<>();
RegisteredPlayer humanPlayer = new RegisteredPlayer(userDeck).setPlayer(GamePlayerUtil.getGuiPlayer());
players.add(humanPlayer);
players.add(new RegisteredPlayer(gauntlet.getDecks().get(gauntlet.getCompleted())).setPlayer(GamePlayerUtil.createAiPlayer()));
gauntlet.startRound(players, humanPlayer);
}));
});
}
});
@@ -1554,26 +1484,23 @@ public class FDeckChooser extends FScreen {
public void run(final Deck aiDeck) {
if (aiDeck == null) { return; }
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
Set<GameType> appliedVariants = new HashSet<>();
appliedVariants.add(variant);
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> {
Set<GameType> appliedVariants = new HashSet<>();
appliedVariants.add(variant);
List<RegisteredPlayer> players = new ArrayList<>();
RegisteredPlayer humanPlayer = RegisteredPlayer.forVariants(2, appliedVariants, userDeck, null, false, null, null);
humanPlayer.setPlayer(GamePlayerUtil.getGuiPlayer());
RegisteredPlayer aiPlayer = RegisteredPlayer.forVariants(2, appliedVariants, aiDeck, null, false, null, null);
aiPlayer.setPlayer(GamePlayerUtil.createAiPlayer());
players.add(humanPlayer);
players.add(aiPlayer);
List<RegisteredPlayer> players = new ArrayList<>();
RegisteredPlayer humanPlayer = RegisteredPlayer.forVariants(2, appliedVariants, userDeck, null, false, null, null);
humanPlayer.setPlayer(GamePlayerUtil.getGuiPlayer());
RegisteredPlayer aiPlayer = RegisteredPlayer.forVariants(2, appliedVariants, aiDeck, null, false, null, null);
aiPlayer.setPlayer(GamePlayerUtil.createAiPlayer());
players.add(humanPlayer);
players.add(aiPlayer);
final Map<RegisteredPlayer, IGuiGame> guiMap = new HashMap<>();
guiMap.put(humanPlayer, MatchController.instance);
final Map<RegisteredPlayer, IGuiGame> guiMap = new HashMap<>();
guiMap.put(humanPlayer, MatchController.instance);
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Constructed, appliedVariants, players, guiMap);
}
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Constructed, appliedVariants, players, guiMap);
});
}
});

View File

@@ -22,39 +22,25 @@ public class LoadingOverlay extends FOverlay {
private static final FSkinFont FONT = FSkinFont.get(22);
private static final FSkinColor BACK_COLOR = FSkinColor.get(Colors.CLR_ACTIVE).alphaColor(0.75f);
private static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
public static void show(String caption0, final Runnable runnable) {
final LoadingOverlay loader = new LoadingOverlay(caption0);
show(caption0, false, runnable);
}
public static void show(String caption0, boolean textMode, final Runnable runnable) {
final LoadingOverlay loader = new LoadingOverlay(caption0, textMode);
loader.show(); //show loading overlay then delay running remaining logic so UI can respond
ThreadUtil.invokeInGameThread(new Runnable() {
@Override
public void run() {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
runnable.run();
loader.hide();
loader.finishedloading(); //setLoadingaMatch to false
}
});
}
});
ThreadUtil.invokeInGameThread(() -> FThreads.invokeInEdtLater(() -> {
runnable.run();
loader.hide();
loader.finishedloading(); //setLoadingaMatch to false
}));
}
public static void runBackgroundTask(String caption0, final Runnable task) {
final LoadingOverlay loader = new LoadingOverlay(caption0);
final LoadingOverlay loader = new LoadingOverlay(caption0, true);
loader.show();
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
task.run();
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
loader.hide();
}
});
}
FThreads.invokeInBackgroundThread(() -> {
task.run();
FThreads.invokeInEdtLater(() -> loader.hide());
});
}
@@ -63,6 +49,7 @@ public class LoadingOverlay extends FOverlay {
public LoadingOverlay(String caption0) {
caption = caption0;
textMode = false;
}
public LoadingOverlay(String caption0, boolean textOnly) {

View File

@@ -169,7 +169,7 @@ public class SplashScreen extends FContainer {
}
void drawTransition(Graphics g, boolean openAdventure, float percentage) {
TextureRegion tr = new TextureRegion(Forge.getTitleBG());
TextureRegion tr = new TextureRegion(Forge.getAssets().fallback_skins().get(0));
if (!Forge.isLandscapeMode() && tr != null) {
float ar = 1.78f;
int w = (int) (tr.getRegionHeight() / ar);
@@ -307,7 +307,7 @@ public class SplashScreen extends FContainer {
+ "Forge is open source software, released under the GNU General Public License.";
if (Forge.forcedEnglishonCJKMissing && !clear) {
clear = true;
FSkinFont.clear();
FSkinFont.preloadAll("");
disclaimerFont = FSkinFont.get(9);
}
g.drawText(disclaimer, disclaimerFont, FProgressBar.SEL_FORE_COLOR,

View File

@@ -44,8 +44,6 @@ import forge.screens.LoadingOverlay;
import forge.screens.settings.SettingsScreen;
import forge.toolbox.FCheckBox;
import forge.toolbox.FComboBox;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.toolbox.FList;
import forge.toolbox.FOptionPane;
@@ -111,23 +109,20 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
cbPlayerCount.addItem(i);
}
cbPlayerCount.setSelectedItem(2);
cbPlayerCount.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
int numPlayers = getNumPlayers();
while(lobby.getNumberOfSlots() < getNumPlayers()){
lobby.addSlot();
}
while(lobby.getNumberOfSlots() > getNumPlayers()){
lobby.removeSlot(lobby.getNumberOfSlots()-1);
}
for (int i = 0; i < MAX_PLAYERS; i++) {
if(i<playerPanels.size()) {
playerPanels.get(i).setVisible(i < numPlayers);
}
}
playersScroll.revalidate();
cbPlayerCount.setChangedHandler(event -> {
int numPlayers = getNumPlayers();
while(lobby.getNumberOfSlots() < getNumPlayers()){
lobby.addSlot();
}
while(lobby.getNumberOfSlots() > getNumPlayers()){
lobby.removeSlot(lobby.getNumberOfSlots()-1);
}
for (int i = 0; i < MAX_PLAYERS; i++) {
if(i<playerPanels.size()) {
playerPanels.get(i).setVisible(i < numPlayers);
}
}
playersScroll.revalidate();
});
initLobby(lobby0);
@@ -139,12 +134,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
cbGamesInMatch.addItem("3");
cbGamesInMatch.addItem("5");
cbGamesInMatch.setSelectedItem(FModel.getPreferences().getPref((FPref.UI_MATCHES_PER_GAME)));
cbGamesInMatch.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FModel.getPreferences().setPref(FPref.UI_MATCHES_PER_GAME, cbGamesInMatch.getSelectedItem());
}
});
cbGamesInMatch.setChangedHandler(event -> FModel.getPreferences().setPref(FPref.UI_MATCHES_PER_GAME, cbGamesInMatch.getSelectedItem()));
add(lblVariants);
add(cbVariants);
@@ -161,31 +151,28 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
cbVariants.addItem(GameType.Archenemy);
cbVariants.addItem(GameType.ArchenemyRumble);
cbVariants.addItem(Forge.getLocalizer().getMessage("lblMore"));
cbVariants.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (cbVariants.getSelectedIndex() <= 0) {
lobby.clearVariants();
updateLayoutForVariants();
Set<GameType> gameTypes = new HashSet<>();
FModel.getPreferences().setGameType(FPref.UI_APPLIED_VARIANTS, gameTypes);
FModel.getPreferences().save();
}
else if (cbVariants.getSelectedIndex() == cbVariants.getItemCount() - 1) {
Forge.openScreen(new MultiVariantSelect());
updateVariantSelection();
}
else {
lobby.clearVariants();
lobby.applyVariant((GameType)cbVariants.getSelectedItem());
updateLayoutForVariants();
Set<GameType> gameTypes = new HashSet<>();
for (GameType variant: lobby.getAppliedVariants()) {
gameTypes.add(variant);
}
FModel.getPreferences().setGameType(FPref.UI_APPLIED_VARIANTS, gameTypes);
FModel.getPreferences().save();
cbVariants.setChangedHandler(event -> {
if (cbVariants.getSelectedIndex() <= 0) {
lobby.clearVariants();
updateLayoutForVariants();
Set<GameType> gameTypes = new HashSet<>();
FModel.getPreferences().setGameType(FPref.UI_APPLIED_VARIANTS, gameTypes);
FModel.getPreferences().save();
}
else if (cbVariants.getSelectedIndex() == cbVariants.getItemCount() - 1) {
Forge.openScreen(new MultiVariantSelect());
updateVariantSelection();
}
else {
lobby.clearVariants();
lobby.applyVariant((GameType)cbVariants.getSelectedItem());
updateLayoutForVariants();
Set<GameType> gameTypes = new HashSet<>();
for (GameType variant: lobby.getAppliedVariants()) {
gameTypes.add(variant);
}
FModel.getPreferences().setGameType(FPref.UI_APPLIED_VARIANTS, gameTypes);
FModel.getPreferences().save();
}
});
@@ -195,40 +182,34 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
updatePlayersFromPrefs();
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
playerPanels.get(0).initialize(FPref.CONSTRUCTED_P1_DECK_STATE, FPref.COMMANDER_P1_DECK_STATE, FPref.OATHBREAKER_P1_DECK_STATE, FPref.TINY_LEADER_P1_DECK_STATE, FPref.BRAWL_P1_DECK_STATE, DeckType.PRECONSTRUCTED_DECK);
playerPanels.get(1).initialize(FPref.CONSTRUCTED_P2_DECK_STATE, FPref.COMMANDER_P2_DECK_STATE, FPref.OATHBREAKER_P2_DECK_STATE, FPref.TINY_LEADER_P2_DECK_STATE, FPref.BRAWL_P2_DECK_STATE, DeckType.COLOR_DECK);
try {
if (getNumPlayers() > 2) {
playerPanels.get(2).initialize(FPref.CONSTRUCTED_P3_DECK_STATE, FPref.COMMANDER_P3_DECK_STATE, FPref.OATHBREAKER_P3_DECK_STATE, FPref.TINY_LEADER_P3_DECK_STATE, FPref.BRAWL_P3_DECK_STATE, DeckType.COLOR_DECK);
}
if (getNumPlayers() > 3) {
playerPanels.get(3).initialize(FPref.CONSTRUCTED_P4_DECK_STATE, FPref.COMMANDER_P4_DECK_STATE, FPref.OATHBREAKER_P3_DECK_STATE, FPref.TINY_LEADER_P4_DECK_STATE, FPref.BRAWL_P4_DECK_STATE, DeckType.COLOR_DECK);
}
} catch (Exception e) {}
/*playerPanels.get(4).initialize(FPref.CONSTRUCTED_P5_DECK_STATE, DeckType.COLOR_DECK);
playerPanels.get(5).initialize(FPref.CONSTRUCTED_P6_DECK_STATE, DeckType.COLOR_DECK);
playerPanels.get(6).initialize(FPref.CONSTRUCTED_P7_DECK_STATE, DeckType.COLOR_DECK);
playerPanels.get(7).initialize(FPref.CONSTRUCTED_P8_DECK_STATE, DeckType.COLOR_DECK);*/ //TODO: Improve performance of loading this screen by using background thread
FThreads.invokeInBackgroundThread(() -> {
playerPanels.get(0).initialize(FPref.CONSTRUCTED_P1_DECK_STATE, FPref.COMMANDER_P1_DECK_STATE, FPref.OATHBREAKER_P1_DECK_STATE, FPref.TINY_LEADER_P1_DECK_STATE, FPref.BRAWL_P1_DECK_STATE, DeckType.PRECONSTRUCTED_DECK);
playerPanels.get(1).initialize(FPref.CONSTRUCTED_P2_DECK_STATE, FPref.COMMANDER_P2_DECK_STATE, FPref.OATHBREAKER_P2_DECK_STATE, FPref.TINY_LEADER_P2_DECK_STATE, FPref.BRAWL_P2_DECK_STATE, DeckType.COLOR_DECK);
try {
if (getNumPlayers() > 2) {
playerPanels.get(2).initialize(FPref.CONSTRUCTED_P3_DECK_STATE, FPref.COMMANDER_P3_DECK_STATE, FPref.OATHBREAKER_P3_DECK_STATE, FPref.TINY_LEADER_P3_DECK_STATE, FPref.BRAWL_P3_DECK_STATE, DeckType.COLOR_DECK);
}
if (getNumPlayers() > 3) {
playerPanels.get(3).initialize(FPref.CONSTRUCTED_P4_DECK_STATE, FPref.COMMANDER_P4_DECK_STATE, FPref.OATHBREAKER_P3_DECK_STATE, FPref.TINY_LEADER_P4_DECK_STATE, FPref.BRAWL_P4_DECK_STATE, DeckType.COLOR_DECK);
}
} catch (Exception e) {}
/*playerPanels.get(4).initialize(FPref.CONSTRUCTED_P5_DECK_STATE, DeckType.COLOR_DECK);
playerPanels.get(5).initialize(FPref.CONSTRUCTED_P6_DECK_STATE, DeckType.COLOR_DECK);
playerPanels.get(6).initialize(FPref.CONSTRUCTED_P7_DECK_STATE, DeckType.COLOR_DECK);
playerPanels.get(7).initialize(FPref.CONSTRUCTED_P8_DECK_STATE, DeckType.COLOR_DECK);*/ //TODO: Improve performance of loading this screen by using background thread
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
btnStart.setEnabled(lobby.hasControl());
FThreads.invokeInEdtLater(() -> {
btnStart.setEnabled(lobby.hasControl());
Set<GameType> gameTypes = FModel.getPreferences().getGameType(FPref.UI_APPLIED_VARIANTS);
if (!gameTypes.isEmpty()) {
for (GameType gameType : gameTypes) {
lobby.applyVariant(gameType);
}
updateVariantSelection();
updateLayoutForVariants();
}
Set<GameType> gameTypes = FModel.getPreferences().getGameType(FPref.UI_APPLIED_VARIANTS);
if (!gameTypes.isEmpty()) {
for (GameType gameType : gameTypes) {
lobby.applyVariant(gameType);
}
});
}
updateVariantSelection();
updateLayoutForVariants();
}
});
});
lblPlayers.setEnabled(true);
@@ -351,20 +332,13 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
updateName(0, GamePlayerUtil.getGuiPlayer().getName());
}
}
FThreads.invokeInBackgroundThread(new Runnable() { //must call startGame in background thread in case there are alerts
@Override
public void run() {
final Runnable startGame = lobby.startGame();
if (startGame != null) {
//set this so we cant get any multi/rapid tap on start button
Forge.setLoadingaMatch(true);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), startGame);
}
});
}
//must call startGame in background thread in case there are alerts
FThreads.invokeInBackgroundThread(() -> {
final Runnable startGame = lobby.startGame();
if (startGame != null) {
//set this so we cant get any multi/rapid tap on start button
Forge.setLoadingaMatch(true);
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, startGame));
}
});
}

View File

@@ -4,7 +4,6 @@ import java.io.File;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.badlogic.gdx.utils.Align;
@@ -31,8 +30,6 @@ import forge.screens.home.LoadGameMenu;
import forge.screens.home.NewGameMenu.NewGameScreen;
import forge.screens.settings.SettingsScreen;
import forge.toolbox.FButton;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FList;
import forge.toolbox.FOptionPane;
import forge.util.Callback;
@@ -53,26 +50,11 @@ public class LoadGauntletScreen extends LaunchScreen {
super(null, LoadGameMenu.getMenu());
btnNewGauntlet.setFont(FSkinFont.get(16));
btnNewGauntlet.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
NewGameScreen.Gauntlet.open();
}
});
btnNewGauntlet.setCommand(event -> NewGameScreen.Gauntlet.open());
btnRenameGauntlet.setFont(btnNewGauntlet.getFont());
btnRenameGauntlet.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
renameGauntlet(lstGauntlets.getSelectedGauntlet());
}
});
btnRenameGauntlet.setCommand(event -> renameGauntlet(lstGauntlets.getSelectedGauntlet()));
btnDeleteGauntlet.setFont(btnNewGauntlet.getFont());
btnDeleteGauntlet.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
deleteGauntlet(lstGauntlets.getSelectedGauntlet());
}
});
btnDeleteGauntlet.setCommand(event -> deleteGauntlet(lstGauntlets.getSelectedGauntlet()));
}
public void onActivate() {
@@ -136,81 +118,69 @@ public class LoadGauntletScreen extends LaunchScreen {
return;
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
final GauntletData gauntlet = FModel.getGauntletData();
List<RegisteredPlayer> players = new ArrayList<>();
RegisteredPlayer humanPlayer = new RegisteredPlayer(gauntlet.getUserDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
players.add(humanPlayer);
players.add(new RegisteredPlayer(gauntlet.getDecks().get(gauntlet.getCompleted())).setPlayer(GamePlayerUtil.createAiPlayer()));
gauntlet.startRound(players, humanPlayer);
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> {
final GauntletData gauntlet1 = FModel.getGauntletData();
List<RegisteredPlayer> players = new ArrayList<>();
RegisteredPlayer humanPlayer = new RegisteredPlayer(gauntlet1.getUserDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
players.add(humanPlayer);
players.add(new RegisteredPlayer(gauntlet1.getDecks().get(gauntlet1.getCompleted())).setPlayer(GamePlayerUtil.createAiPlayer()));
gauntlet1.startRound(players, humanPlayer);
});
}
private void renameGauntlet(final GauntletData gauntlet) {
if (gauntlet == null) { return; }
ThreadUtil.invokeInGameThread(new Runnable() {
@Override
public void run() {
String gauntletName;
String oldGauntletName = gauntlet.getName();
while (true) {
gauntletName = SOptionPane.showInputDialog(Forge.getLocalizer().getMessage("lblEnterNewGauntletGameName"), Forge.getLocalizer().getMessage("lblRenameGauntlet"), null, oldGauntletName);
if (gauntletName == null) { return; }
ThreadUtil.invokeInGameThread(() -> {
String gauntletName;
String oldGauntletName = gauntlet.getName();
while (true) {
gauntletName = SOptionPane.showInputDialog(Forge.getLocalizer().getMessage("lblEnterNewGauntletGameName"), Forge.getLocalizer().getMessage("lblRenameGauntlet"), null, oldGauntletName);
if (gauntletName == null) { return; }
gauntletName = QuestUtil.cleanString(gauntletName);
if (gauntletName.equals(oldGauntletName)) { return; } //quit if chose same name
gauntletName = QuestUtil.cleanString(gauntletName);
if (gauntletName.equals(oldGauntletName)) { return; } //quit if chose same name
if (gauntletName.isEmpty()) {
SOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblPleaseSpecifyGauntletName"));
continue;
}
boolean exists = false;
for (GauntletData gauntletData : lstGauntlets) {
if (gauntletData.getName().equalsIgnoreCase(gauntletName)) {
exists = true;
break;
}
}
if (exists) {
SOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblGauntletNameExistsPleasePickAnotherName"));
continue;
}
break;
if (gauntletName.isEmpty()) {
SOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblPleaseSpecifyGauntletName"));
continue;
}
final String newGauntletName = gauntletName;
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
gauntlet.rename(newGauntletName);
lstGauntlets.refresh();
lstGauntlets.setSelectedGauntlet(gauntlet);
boolean exists = false;
for (GauntletData gauntletData : lstGauntlets) {
if (gauntletData.getName().equalsIgnoreCase(gauntletName)) {
exists = true;
break;
}
});
}
if (exists) {
SOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblGauntletNameExistsPleasePickAnotherName"));
continue;
}
break;
}
final String newGauntletName = gauntletName;
FThreads.invokeInEdtLater(() -> {
gauntlet.rename(newGauntletName);
lstGauntlets.refresh();
lstGauntlets.setSelectedGauntlet(gauntlet);
});
});
}
private void deleteGauntlet(final GauntletData gauntlet) {
if (gauntlet == null) { return; }
ThreadUtil.invokeInGameThread(new Runnable() {
@Override
public void run() {
if (!SOptionPane.showConfirmDialog(
Forge.getLocalizer().getMessage("lblAreYouSuerDeleteGauntlet", gauntlet.getName()),
Forge.getLocalizer().getMessage("lblDeleteGauntlet"), Forge.getLocalizer().getMessage("lblDelete"), Forge.getLocalizer().getMessage("lblCancel"))) {
return;
}
GauntletIO.getGauntletFile(gauntlet).delete();
lstGauntlets.removeGauntlet(gauntlet);
ThreadUtil.invokeInGameThread(() -> {
if (!SOptionPane.showConfirmDialog(
Forge.getLocalizer().getMessage("lblAreYouSuerDeleteGauntlet", gauntlet.getName()),
Forge.getLocalizer().getMessage("lblDeleteGauntlet"), Forge.getLocalizer().getMessage("lblDelete"), Forge.getLocalizer().getMessage("lblCancel"))) {
return;
}
GauntletIO.getGauntletFile(gauntlet).delete();
lstGauntlets.removeGauntlet(gauntlet);
});
}
@@ -299,12 +269,7 @@ public class LoadGauntletScreen extends LaunchScreen {
public void refresh() {
List<GauntletData> sorted = new ArrayList<>();
sorted.addAll(gauntlets);
Collections.sort(sorted, new Comparator<GauntletData>() {
@Override
public int compare(final GauntletData x, final GauntletData y) {
return x.getName().toLowerCase().compareTo(y.getName().toLowerCase());
}
});
Collections.sort(sorted, (x, y) -> x.getName().toLowerCase().compareTo(y.getName().toLowerCase()));
setListData(sorted);
}

View File

@@ -60,39 +60,26 @@ public class PuzzleScreen extends LaunchScreen {
@Override
public void run(final Puzzle chosen) {
if (chosen != null) {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingThePuzzle"), new Runnable() {
@Override
public void run() {
// Load selected puzzle
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.setStartGameHook(new Runnable() {
@Override
public final void run() {
chosen.applyToGame(hostedMatch.getGame());
}
});
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingThePuzzle"), true, () -> {
// Load selected puzzle
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.setStartGameHook(() -> chosen.applyToGame(hostedMatch.getGame()));
hostedMatch.setEndGameHook((new Runnable() {
@Override
public void run() {
chosen.savePuzzleSolve(hostedMatch.getGame().getOutcome().isWinner(GamePlayerUtil.getGuiPlayer()));
}
}));
hostedMatch.setEndGameHook((() -> chosen.savePuzzleSolve(hostedMatch.getGame().getOutcome().isWinner(GamePlayerUtil.getGuiPlayer()))));
final List<RegisteredPlayer> players = new ArrayList<>();
final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer());
human.setStartingHand(0);
players.add(human);
final List<RegisteredPlayer> players = new ArrayList<>();
final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer());
human.setStartingHand(0);
players.add(human);
final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer());
ai.setStartingHand(0);
players.add(ai);
final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer());
ai.setStartingHand(0);
players.add(ai);
GameRules rules = new GameRules(GameType.Puzzle);
rules.setGamesPerMatch(1);
hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame());
FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName());
}
GameRules rules = new GameRules(GameType.Puzzle);
rules.setGamesPerMatch(1);
hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame());
FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName());
});
}
}

View File

@@ -30,8 +30,6 @@ import forge.screens.LaunchScreen;
import forge.screens.LoadingOverlay;
import forge.screens.home.LoadGameMenu;
import forge.toolbox.FComboBox;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.toolbox.FOptionPane;
@@ -54,12 +52,7 @@ public class LoadDraftScreen extends LaunchScreen {
cbMode.addItem(Forge.getLocalizer().getMessage("lblSingleMatch"));
lstDecks.setup(ItemManagerConfig.DRAFT_DECKS);
lstDecks.setItemActivateHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
editSelectedDeck();
}
});
lstDecks.setItemActivateHandler(event -> editSelectedDeck());
}
@Override
@@ -96,80 +89,63 @@ public class LoadDraftScreen extends LaunchScreen {
@Override
protected void startMatch() {
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
final DeckProxy humanDeck = lstDecks.getSelectedItem();
if (humanDeck == null) {
FOptionPane.showErrorDialog(Forge.getLocalizer().getMessage("lblYouMustSelectExistingDeck"), Forge.getLocalizer().getMessage("lblNoDeck"));
FThreads.invokeInBackgroundThread(() -> {
final DeckProxy humanDeck = lstDecks.getSelectedItem();
if (humanDeck == null) {
FOptionPane.showErrorDialog(Forge.getLocalizer().getMessage("lblYouMustSelectExistingDeck"), Forge.getLocalizer().getMessage("lblNoDeck"));
return;
}
// TODO: if booster draft tournaments are supported in the future, add the possibility to choose them here
final boolean gauntlet = cbMode.getSelectedItem().equals(Forge.getLocalizer().getMessage("lblGauntlet"));
if (gauntlet) {
final Integer rounds = SGuiChoose.getInteger(Forge.getLocalizer().getMessage("lblHowManyOpponents"),
1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size());
if (rounds == null) {
return;
}
// TODO: if booster draft tournaments are supported in the future, add the possibility to choose them here
final boolean gauntlet = cbMode.getSelectedItem().equals(Forge.getLocalizer().getMessage("lblGauntlet"));
if (gauntlet) {
final Integer rounds = SGuiChoose.getInteger(Forge.getLocalizer().getMessage("lblHowManyOpponents"),
1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size());
if (rounds == null) {
FThreads.invokeInEdtLater(() -> {
if (!checkDeckLegality(humanDeck)) {
return;
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (!checkDeckLegality(humanDeck)) {
return;
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
FModel.getGauntletMini().resetGauntletDraft();
FModel.getGauntletMini().launch(rounds, humanDeck.getDeck(), GameType.Draft);
}
});
}
});
} else {
final Integer aiIndex = SGuiChoose.getInteger(Forge.getLocalizer().getMessage("lblWhichOpponentWouldYouLikeToFace"),
1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size());
if (aiIndex == null) {
return; // Cancel was pressed
}
final DeckGroup opponentDecks = FModel.getDecks().getDraft().get(humanDeck.getName());
final Deck aiDeck = opponentDecks.getAiDecks().get(aiIndex - 1);
if (aiDeck == null) {
throw new IllegalStateException("Draft: Computer deck is null!");
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
if (!checkDeckLegality(humanDeck)) {
return;
}
final List<RegisteredPlayer> starter = new ArrayList<>();
final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
starter.add(human);
starter.add(new RegisteredPlayer(aiDeck).setPlayer(GamePlayerUtil.createAiPlayer()));
for (final RegisteredPlayer pl : starter) {
pl.assignConspiracies();
}
FModel.getGauntletMini().resetGauntletDraft();
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Draft, null, starter, human, GuiBase.getInterface().getNewGuiGame());
}
});
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> {
FModel.getGauntletMini().resetGauntletDraft();
FModel.getGauntletMini().launch(rounds, humanDeck.getDeck(), GameType.Draft);
});
});
} else {
final Integer aiIndex = SGuiChoose.getInteger(Forge.getLocalizer().getMessage("lblWhichOpponentWouldYouLikeToFace"),
1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size());
if (aiIndex == null) {
return; // Cancel was pressed
}
final DeckGroup opponentDecks = FModel.getDecks().getDraft().get(humanDeck.getName());
final Deck aiDeck = opponentDecks.getAiDecks().get(aiIndex - 1);
if (aiDeck == null) {
throw new IllegalStateException("Draft: Computer deck is null!");
}
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> {
if (!checkDeckLegality(humanDeck)) {
return;
}
final List<RegisteredPlayer> starter = new ArrayList<>();
final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
starter.add(human);
starter.add(new RegisteredPlayer(aiDeck).setPlayer(GamePlayerUtil.createAiPlayer()));
for (final RegisteredPlayer pl : starter) {
pl.assignConspiracies();
}
FModel.getGauntletMini().resetGauntletDraft();
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Draft, null, starter, human, GuiBase.getInterface().getNewGuiGame());
}));
}
});
}

View File

@@ -30,8 +30,6 @@ import forge.screens.LaunchScreen;
import forge.screens.LoadingOverlay;
import forge.screens.home.LoadGameMenu;
import forge.toolbox.FComboBox;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.toolbox.FOptionPane;
@@ -54,12 +52,7 @@ public class LoadSealedScreen extends LaunchScreen {
cbMode.addItem(Forge.getLocalizer().getMessage("lblSingleMatch"));
lstDecks.setup(ItemManagerConfig.SEALED_DECKS);
lstDecks.setItemActivateHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
editSelectedDeck();
}
});
lstDecks.setItemActivateHandler(event -> editSelectedDeck());
}
@Override
@@ -95,74 +88,59 @@ public class LoadSealedScreen extends LaunchScreen {
@Override
protected void startMatch() {
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
final DeckProxy humanDeck = lstDecks.getSelectedItem();
if (humanDeck == null) {
FOptionPane.showErrorDialog(Forge.getLocalizer().getMessage("lblYouMustSelectExistingSealedPool"), Forge.getLocalizer().getMessage("lblNoDeck"));
return;
}
FThreads.invokeInBackgroundThread(() -> {
final DeckProxy humanDeck = lstDecks.getSelectedItem();
if (humanDeck == null) {
FOptionPane.showErrorDialog(Forge.getLocalizer().getMessage("lblYouMustSelectExistingSealedPool"), Forge.getLocalizer().getMessage("lblNoDeck"));
return;
}
final boolean gauntlet = cbMode.getSelectedItem().equals(Forge.getLocalizer().getMessage("lblGauntlet"));
final boolean gauntlet = cbMode.getSelectedItem().equals(Forge.getLocalizer().getMessage("lblGauntlet"));
if (gauntlet) {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (!checkDeckLegality(humanDeck)) {
return;
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
final int matches = FModel.getDecks().getSealed().get(humanDeck.getName()).getAiDecks().size();
FModel.getGauntletMini().launch(matches, humanDeck.getDeck(), GameType.Sealed);
}
});
}
});
} else {
final Integer aiIndex = SGuiChoose.getInteger(Forge.getLocalizer().getMessage("lblWhichOpponentWouldYouLikeToFace"),
1, FModel.getDecks().getSealed().get(humanDeck.getName()).getAiDecks().size());
if (aiIndex == null) {
return; // Cancel was pressed
if (gauntlet) {
FThreads.invokeInEdtLater(() -> {
if (!checkDeckLegality(humanDeck)) {
return;
}
final DeckGroup opponentDecks = FModel.getDecks().getSealed().get(humanDeck.getName());
final Deck aiDeck = opponentDecks.getAiDecks().get(aiIndex - 1);
if (aiDeck == null) {
throw new IllegalStateException("Draft: Computer deck is null!");
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> {
final int matches = FModel.getDecks().getSealed().get(humanDeck.getName()).getAiDecks().size();
FModel.getGauntletMini().launch(matches, humanDeck.getDeck(), GameType.Sealed);
});
});
} else {
final Integer aiIndex = SGuiChoose.getInteger(Forge.getLocalizer().getMessage("lblWhichOpponentWouldYouLikeToFace"),
1, FModel.getDecks().getSealed().get(humanDeck.getName()).getAiDecks().size());
if (aiIndex == null) {
return; // Cancel was pressed
}
final DeckGroup opponentDecks = FModel.getDecks().getSealed().get(humanDeck.getName());
final Deck aiDeck = opponentDecks.getAiDecks().get(aiIndex - 1);
if (aiDeck == null) {
throw new IllegalStateException("Draft: Computer deck is null!");
}
FThreads.invokeInEdtLater(() -> {
if (!checkDeckLegality(humanDeck)) {
return;
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (!checkDeckLegality(humanDeck)) {
return;
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
final List<RegisteredPlayer> starter = new ArrayList<>();
final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
starter.add(human);
starter.add(new RegisteredPlayer(aiDeck).setPlayer(GamePlayerUtil.createAiPlayer()));
for (final RegisteredPlayer pl : starter) {
pl.assignConspiracies();
}
FModel.getGauntletMini().resetGauntletDraft();
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Sealed, null, starter, human, GuiBase.getInterface().getNewGuiGame());
}
});
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> {
final List<RegisteredPlayer> starter = new ArrayList<>();
final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
starter.add(human);
starter.add(new RegisteredPlayer(aiDeck).setPlayer(GamePlayerUtil.createAiPlayer()));
for (final RegisteredPlayer pl : starter) {
pl.assignConspiracies();
}
FModel.getGauntletMini().resetGauntletDraft();
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Sealed, null, starter, human, GuiBase.getInterface().getNewGuiGame());
});
}
});
}
});
}

View File

@@ -41,27 +41,15 @@ public class NewDraftScreen extends LaunchScreen {
@Override
protected void startMatch() {
ThreadUtil.invokeInGameThread(new Runnable() { //must run in game thread to prevent blocking UI thread
@Override
public void run() {
final LimitedPoolType poolType = SGuiChoose.oneOrNone(Forge.getLocalizer().getMessage("lblChooseDraftFormat"), LimitedPoolType.values());
if (poolType == null) { return; }
//must run in game thread to prevent blocking UI thread
ThreadUtil.invokeInGameThread(() -> {
final LimitedPoolType poolType = SGuiChoose.oneOrNone(Forge.getLocalizer().getMessage("lblChooseDraftFormat"), LimitedPoolType.values());
if (poolType == null) { return; }
final BoosterDraft draft = BoosterDraft.createDraft(poolType);
if (draft == null) { return; }
final BoosterDraft draft = BoosterDraft.createDraft(poolType);
if (draft == null) { return; }
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewDraft"), new Runnable() {
@Override
public void run() {
Forge.openScreen(new DraftingProcessScreen(draft, EditorType.Draft, null));
}
});
}
});
}
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewDraft"), true, () -> Forge.openScreen(new DraftingProcessScreen(draft, EditorType.Draft, null))));
});
}
}

View File

@@ -2,7 +2,6 @@ package forge.screens.match;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -74,8 +73,6 @@ public class MatchController extends AbstractGuiGame {
private MatchController() { }
public static final MatchController instance = new MatchController();
private static final Map<String, FImage> avatarImages = new HashMap<>();
private static HostedMatch hostedMatch;
private static MatchScreen view;
private static GameState phaseGameState;
@@ -114,7 +111,7 @@ public class MatchController extends AbstractGuiGame {
public static FImage getPlayerAvatar(final PlayerView p) {
final String lp = p.getLobbyPlayerName();
FImage avatar = avatarImages.get(lp);
FImage avatar = Forge.getAssets().avatarImages().get(lp);
if (avatar == null) {
if (StringUtils.isEmpty(p.getAvatarCardImageKey())) {
avatar = new FTextureRegionImage(FSkin.getAvatars().get(p.getAvatarIndex()));
@@ -488,15 +485,13 @@ public class MatchController extends AbstractGuiGame {
public void setSelectables(final Iterable<CardView> cards) {
super.setSelectables(cards);
// update zones on tabletop and floating zones - non-selectable cards may be rendered differently
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public final void run() {
for (final PlayerView p : getGameView().getPlayers()) {
if ( p.getCards(ZoneType.Battlefield) != null ) {
updateCards(p.getCards(ZoneType.Battlefield));
}
if ( p.getCards(ZoneType.Hand) != null ) {
updateCards(p.getCards(ZoneType.Hand));
}
FThreads.invokeInEdtNowOrLater(() -> {
for (final PlayerView p : getGameView().getPlayers()) {
if ( p.getCards(ZoneType.Battlefield) != null ) {
updateCards(p.getCards(ZoneType.Battlefield));
}
if ( p.getCards(ZoneType.Hand) != null ) {
updateCards(p.getCards(ZoneType.Hand));
}
}
});
@@ -506,15 +501,13 @@ public class MatchController extends AbstractGuiGame {
public void clearSelectables() {
super.clearSelectables();
// update zones on tabletop and floating zones - non-selectable cards may be rendered differently
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public final void run() {
for (final PlayerView p : getGameView().getPlayers()) {
if ( p.getCards(ZoneType.Battlefield) != null ) {
updateCards(p.getCards(ZoneType.Battlefield));
}
if ( p.getCards(ZoneType.Hand) != null ) {
updateCards(p.getCards(ZoneType.Hand));
}
FThreads.invokeInEdtNowOrLater(() -> {
for (final PlayerView p : getGameView().getPlayers()) {
if ( p.getCards(ZoneType.Battlefield) != null ) {
updateCards(p.getCards(ZoneType.Battlefield));
}
if ( p.getCards(ZoneType.Hand) != null ) {
updateCards(p.getCards(ZoneType.Hand));
}
}
});
@@ -703,7 +696,7 @@ public class MatchController extends AbstractGuiGame {
@Override
public void setPlayerAvatar(final LobbyPlayer player, final IHasIcon ihi) {
avatarImages.put(player.getName(), ImageCache.getIcon(ihi));
Forge.getAssets().avatarImages().put(player.getName(), ImageCache.getIcon(ihi));
}
@Override

View File

@@ -56,18 +56,15 @@ public class OnlineLobbyScreen extends LobbyScreen implements IOnlineLobby {
clearGameLobby();
Forge.back();
if (msg.length() > 0) {
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
final boolean callBackAlwaysTrue = SOptionPane.showOptionDialog(msg, Forge.getLocalizer().getMessage("lblError"), FSkinProp.ICO_WARNING, ImmutableList.of(Forge.getLocalizer().getMessage("lblOk")), 1) == 0;
if (callBackAlwaysTrue) { //to activate online menu popup when player press play online
GuiBase.setInterrupted(false);
FThreads.invokeInBackgroundThread(() -> {
final boolean callBackAlwaysTrue = SOptionPane.showOptionDialog(msg, Forge.getLocalizer().getMessage("lblError"), FSkinProp.ICO_WARNING, ImmutableList.of(Forge.getLocalizer().getMessage("lblOk")), 1) == 0;
if (callBackAlwaysTrue) { //to activate online menu popup when player press play online
GuiBase.setInterrupted(false);
if(FServerManager.getInstance() != null)
FServerManager.getInstance().stopServer();
if(getfGameClient() != null)
closeClient();
}
if(FServerManager.getInstance() != null)
FServerManager.getInstance().stopServer();
if(getfGameClient() != null)
closeClient();
}
});
}
@@ -93,51 +90,37 @@ public class OnlineLobbyScreen extends LobbyScreen implements IOnlineLobby {
if (getGameLobby() == null) {
setGameLobby(getLobby());
//prompt to connect to server when offline lobby activated
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
final String url = NetConnectUtil.getServerUrl();
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (url == null) {
closeConn(""); //go back to previous screen if user cancels connection
FThreads.invokeInBackgroundThread(() -> {
final String url = NetConnectUtil.getServerUrl();
FThreads.invokeInEdtLater(() -> {
if (url == null) {
closeConn(""); //go back to previous screen if user cancels connection
return;
}
final boolean joinServer = url.length() > 0;
final String caption = joinServer ? Forge.getLocalizer().getMessage("lblConnectingToServer") : Forge.getLocalizer().getMessage("lblStartingServer");
LoadingOverlay.show(caption, true, () -> {
final ChatMessage result;
final IOnlineChatInterface chatInterface = (IOnlineChatInterface)OnlineScreen.Chat.getScreen();
if (joinServer) {
result = NetConnectUtil.join(url, OnlineLobbyScreen.this, chatInterface);
if (result.getMessage() == ForgeConstants.CLOSE_CONN_COMMAND) { //this message is returned via netconnectutil on exception
closeConn(Forge.getLocalizer().getMessage("lblDetectedInvalidHostAddress", url));
return;
}
final boolean joinServer = url.length() > 0;
final String caption = joinServer ? Forge.getLocalizer().getMessage("lblConnectingToServer") : Forge.getLocalizer().getMessage("lblStartingServer");
LoadingOverlay.show(caption, new Runnable() {
@Override
public void run() {
final ChatMessage result;
final IOnlineChatInterface chatInterface = (IOnlineChatInterface)OnlineScreen.Chat.getScreen();
if (joinServer) {
result = NetConnectUtil.join(url, OnlineLobbyScreen.this, chatInterface);
if (result.getMessage() == ForgeConstants.CLOSE_CONN_COMMAND) { //this message is returned via netconnectutil on exception
closeConn(Forge.getLocalizer().getMessage("lblDetectedInvalidHostAddress", url));
return;
}
}
else {
result = NetConnectUtil.host(OnlineLobbyScreen.this, chatInterface);
}
chatInterface.addMessage(result);
if (!joinServer) {
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
NetConnectUtil.copyHostedServerUrl();
}
});
}
//update menu buttons
OnlineScreen.Lobby.update();
}
});
}
else {
result = NetConnectUtil.host(OnlineLobbyScreen.this, chatInterface);
}
chatInterface.addMessage(result);
if (!joinServer) {
FThreads.invokeInBackgroundThread(() -> NetConnectUtil.copyHostedServerUrl());
}
//update menu buttons
OnlineScreen.Lobby.update();
});
}
});
});
}
}

View File

@@ -12,8 +12,6 @@ import forge.screens.FScreen;
import forge.screens.LoadingOverlay;
import forge.screens.home.HomeScreen;
import forge.screens.home.LoadGameMenu.LoadGameScreen;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
public class ConquestMenu extends FPopupMenu {
private static final ConquestMenu conquestMenu = new ConquestMenu();
@@ -26,54 +24,14 @@ public class ConquestMenu extends FPopupMenu {
private static final ConquestStatsScreen statsScreen = new ConquestStatsScreen();
private static final ConquestPrefsScreen prefsScreen = new ConquestPrefsScreen();
private static final FMenuItem multiverseItem = new FMenuItem(Forge.getLocalizer().getMessage("lblTheMultiverse"), FSkinImage.MULTIVERSE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(multiverseScreen);
}
});
private static final FMenuItem aetherItem = new FMenuItem(Forge.getLocalizer().getMessage("lblTheAether"), FSkinImage.AETHER_SHARD, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(aetherScreen);
}
});
private static final FMenuItem commandersItem = new FMenuItem(Forge.getLocalizer().getMessage("lblCommanders"), FSkinImage.COMMANDER, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(commandersScreen);
}
});
private static final FMenuItem planeswalkersItem = new FMenuItem(Forge.getLocalizer().getMessage("lblPlaneswalkers"), FSkinImage.PLANESWALKER, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(planeswalkersScreen);
}
});
private static final FMenuItem collectionItem = new FMenuItem(Forge.getLocalizer().getMessage("lblCollection"), FSkinImage.SPELLBOOK, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(collectionScreen);
}
});
private static final FMenuItem statsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(statsScreen);
}
});
private static final FMenuItem planeswalkItem = new FMenuItem(Forge.getLocalizer().getMessage("lblPlaneswalk"), FSkinImage.PW_BADGE_COMMON, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(planeswalkScreen);
}
});
private static final FMenuItem prefsItem = new FMenuItem(Forge.getLocalizer().getMessage("Preferences"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(prefsScreen);
}
});
private static final FMenuItem multiverseItem = new FMenuItem(Forge.getLocalizer().getMessage("lblTheMultiverse"), FSkinImage.MULTIVERSE, event -> setCurrentScreen(multiverseScreen));
private static final FMenuItem aetherItem = new FMenuItem(Forge.getLocalizer().getMessage("lblTheAether"), FSkinImage.AETHER_SHARD, event -> setCurrentScreen(aetherScreen));
private static final FMenuItem commandersItem = new FMenuItem(Forge.getLocalizer().getMessage("lblCommanders"), FSkinImage.COMMANDER, event -> setCurrentScreen(commandersScreen));
private static final FMenuItem planeswalkersItem = new FMenuItem(Forge.getLocalizer().getMessage("lblPlaneswalkers"), FSkinImage.PLANESWALKER, event -> setCurrentScreen(planeswalkersScreen));
private static final FMenuItem collectionItem = new FMenuItem(Forge.getLocalizer().getMessage("lblCollection"), FSkinImage.SPELLBOOK, event -> setCurrentScreen(collectionScreen));
private static final FMenuItem statsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblStatistics"), FSkinImage.MENU_STATS, event -> setCurrentScreen(statsScreen));
private static final FMenuItem planeswalkItem = new FMenuItem(Forge.getLocalizer().getMessage("lblPlaneswalk"), FSkinImage.PW_BADGE_COMMON, event -> setCurrentScreen(planeswalkScreen));
private static final FMenuItem prefsItem = new FMenuItem(Forge.getLocalizer().getMessage("Preferences"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, event -> setCurrentScreen(prefsScreen));
private static void setCurrentScreen(FScreen screen0) {
//make it so pressing Back from any screen besides Multiverse screen always goes to Multiverse screen
@@ -84,12 +42,7 @@ public class ConquestMenu extends FPopupMenu {
static {
//the first time planarconquest mode is launched, add button for it if in Landscape mode
if (Forge.isLandscapeMode()) {
HomeScreen.instance.addButtonForMode("-"+Forge.getLocalizer().getMessage("lblPlanarConquest"), new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
launchPlanarConquest(LaunchReason.StartPlanarConquest);
}
});
HomeScreen.instance.addButtonForMode("-"+Forge.getLocalizer().getMessage("lblPlanarConquest"), event -> launchPlanarConquest(LaunchReason.StartPlanarConquest));
}
}
@@ -108,20 +61,16 @@ public class ConquestMenu extends FPopupMenu {
public static void launchPlanarConquest(final LaunchReason reason) {
Forge.lastButtonIndex = 7;
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingCurrentConquest"), new Runnable() {
@Override
@SuppressWarnings("unchecked")
public void run() {
((DeckController<Deck>)EditorType.PlanarConquest.getController()).setRootFolder(FModel.getConquest().getDecks());
if (reason == LaunchReason.StartPlanarConquest) {
Forge.openScreen(multiverseScreen);
}
else {
multiverseScreen.update();
Forge.openScreen(multiverseScreen);
if (reason == LaunchReason.NewConquest) {
LoadGameScreen.PlanarConquest.setAsBackScreen(true);
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingCurrentConquest"), true, () -> {
((DeckController<Deck>)EditorType.PlanarConquest.getController()).setRootFolder(FModel.getConquest().getDecks());
if (reason == LaunchReason.StartPlanarConquest) {
Forge.openScreen(multiverseScreen);
}
else {
multiverseScreen.update();
Forge.openScreen(multiverseScreen);
if (reason == LaunchReason.NewConquest) {
LoadGameScreen.PlanarConquest.setAsBackScreen(true);
}
}
});

View File

@@ -47,8 +47,6 @@ import forge.screens.LoadingOverlay;
import forge.toolbox.FButton;
import forge.toolbox.FContainer;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FList;
import forge.toolbox.FOptionPane;
import forge.toolbox.FScrollPane;
@@ -260,29 +258,18 @@ public class ConquestMultiverseScreen extends FScreen {
}
private void launchEvent() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblStartingBattle"), new Runnable() {
@Override
public void run() {
ConquestLocation loc = model.getCurrentLocation();
activeBattle = loc.getEvent().createBattle(loc, 0);
FModel.getConquest().startBattle(activeBattle);
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblStartingBattle"), true, () -> {
ConquestLocation loc = model.getCurrentLocation();
activeBattle = loc.getEvent().createBattle(loc, 0);
FModel.getConquest().startBattle(activeBattle);
});
}
private void launchChaosBattle() {
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblChaosApproaching"), new Runnable() {
@Override
public void run() {
activeBattle = new ConquestChaosBattle();
FModel.getConquest().startBattle(activeBattle);
}
});
}
});
FThreads.invokeInEdtNowOrLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblChaosApproaching"), true, () -> {
activeBattle = new ConquestChaosBattle();
FModel.getConquest().startBattle(activeBattle);
}));
}
@Override
@@ -678,12 +665,7 @@ public class ConquestMultiverseScreen extends FScreen {
private BattleBar() {
playerAvatar = add(new AvatarDisplay(false));
opponentAvatar = add(new AvatarDisplay(true));
btnBattle = add(new FButton(Forge.getLocalizer().getMessage("lblBattle"), new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
launchEvent();
}
}));
btnBattle = add(new FButton(Forge.getLocalizer().getMessage("lblBattle"), event -> launchEvent()));
btnBattle.setFont(FSkinFont.get(20));
}

View File

@@ -37,12 +37,7 @@ public class NewConquestScreen extends MultiStepWizardScreen<NewConquestScreenMo
@Override
protected void finish() {
//create new quest in game thread so option panes can wait for input
ThreadUtil.invokeInGameThread(new Runnable() {
@Override
public void run() {
newConquest();
}
});
ThreadUtil.invokeInGameThread(() -> newConquest());
}
private void newConquest() {
@@ -52,26 +47,18 @@ public class NewConquestScreen extends MultiStepWizardScreen<NewConquestScreenMo
}
private void startNewConquest(final String conquestName) {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblStartingNewConquest"), new Runnable() {
@Override
public void run() {
ConquestController qc = FModel.getConquest();
qc.setModel(new ConquestData(conquestName, model.startingPlane, model.startingPlaneswalker, model.startingCommander));
qc.getDecks().add(Iterables.getFirst(qc.getModel().getCommanders(), null).getDeck()); //ensure starting deck is saved
qc.getModel().saveData();
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblStartingNewConquest"), true, () -> {
ConquestController qc = FModel.getConquest();
qc.setModel(new ConquestData(conquestName, model.startingPlane, model.startingPlaneswalker, model.startingCommander));
qc.getDecks().add(Iterables.getFirst(qc.getModel().getCommanders(), null).getDeck()); //ensure starting deck is saved
qc.getModel().saveData();
// Save in preferences.
FModel.getConquestPreferences().setPref(CQPref.CURRENT_CONQUEST, conquestName);
FModel.getConquestPreferences().save();
// Save in preferences.
FModel.getConquestPreferences().setPref(CQPref.CURRENT_CONQUEST, conquestName);
FModel.getConquestPreferences().save();
ConquestMenu.launchPlanarConquest(LaunchReason.NewConquest);
}
});
}
});
ConquestMenu.launchPlanarConquest(LaunchReason.NewConquest);
}));
}
private static class SelectStartingPlaneStep extends WizardStep<NewConquestScreenModel> {

View File

@@ -42,8 +42,6 @@ import forge.screens.quest.QuestMenu.LaunchReason;
import forge.toolbox.FCheckBox;
import forge.toolbox.FComboBox;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.toolbox.FNumericTextField;
import forge.toolbox.FOptionPane;
@@ -186,17 +184,9 @@ public class NewQuestScreen extends FScreen {
private final FCheckBox cbCommander = scroller.add(new FCheckBox(Forge.getLocalizer().getMessage("rbCommanderSubformat")));
private final FLabel btnEmbark = add(new FLabel.ButtonBuilder()
.font(FSkinFont.get(22)).text(Forge.getLocalizer().getMessage("lblEmbark")).icon(FSkinImage.QUEST_ZEP).command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
//create new quest in game thread so option panes can wait for input
ThreadUtil.invokeInGameThread(new Runnable() {
@Override
public void run() {
newQuest();
}
});
}
.font(FSkinFont.get(22)).text(Forge.getLocalizer().getMessage("lblEmbark")).icon(FSkinImage.QUEST_ZEP).command(event -> {
//create new quest in game thread so option panes can wait for input
ThreadUtil.invokeInGameThread(() -> newQuest());
}).build());
public NewQuestScreen() {
@@ -209,24 +199,18 @@ public class NewQuestScreen extends FScreen {
cbxStartingPool.addItem(StartingPoolType.DraftDeck);
cbxStartingPool.addItem(StartingPoolType.SealedDeck);
cbxStartingPool.addItem(StartingPoolType.Cube);
cbxStartingPool.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
updateStartingPoolOptions();
scroller.revalidate();
}
cbxStartingPool.setChangedHandler(event -> {
updateStartingPoolOptions();
scroller.revalidate();
});
cbxPrizedCards.addItem(Forge.getLocalizer().getMessage("lblSameAsStartingPool"));
cbxPrizedCards.addItem(StartingPoolType.Complete);
cbxPrizedCards.addItem(StartingPoolType.Sanctioned);
cbxPrizedCards.addItem(StartingPoolType.Casual);
cbxPrizedCards.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
updatePrizeOptions();
scroller.revalidate();
}
cbxPrizedCards.setChangedHandler(event -> {
updatePrizeOptions();
scroller.revalidate();
});
for (GameFormat gf : FModel.getFormats().getSanctionedList()) {
@@ -243,18 +227,15 @@ public class NewQuestScreen extends FScreen {
numberOfBoostersField.setEnabled(false);
@SuppressWarnings("serial")
UiCommand colorBoxEnabler = new UiCommand() {
@Override
public void run() {
cbBlack.setEnabled(radBalanced.isSelected());
cbBlue.setEnabled(radBalanced.isSelected());
cbGreen.setEnabled(radBalanced.isSelected());
cbRed.setEnabled(radBalanced.isSelected());
cbWhite.setEnabled(radBalanced.isSelected());
cbColorless.setEnabled(radBalanced.isSelected());
cbIncludeArtifacts.setEnabled(!radSurpriseMe.isSelected());
numberOfBoostersField.setEnabled(radBoosters.isSelected());
}
UiCommand colorBoxEnabler = () -> {
cbBlack.setEnabled(radBalanced.isSelected());
cbBlue.setEnabled(radBalanced.isSelected());
cbGreen.setEnabled(radBalanced.isSelected());
cbRed.setEnabled(radBalanced.isSelected());
cbWhite.setEnabled(radBalanced.isSelected());
cbColorless.setEnabled(radBalanced.isSelected());
cbIncludeArtifacts.setEnabled(!radSurpriseMe.isSelected());
numberOfBoostersField.setEnabled(radBoosters.isSelected());
};
radBalanced.setCommand(colorBoxEnabler);
@@ -268,12 +249,7 @@ public class NewQuestScreen extends FScreen {
// Default to 'Main world'
cbxStartingWorld.setSelectedItem(FModel.getWorlds().get("Main world"));
cbxStartingWorld.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
updateEnabledFormats();
}
});
cbxStartingWorld.setChangedHandler(event -> updateEnabledFormats());
updateStartingPoolOptions();
updatePrizeOptions();
@@ -298,59 +274,44 @@ public class NewQuestScreen extends FScreen {
unselectableSets.add("ARC");
unselectableSets.add("PC2");
btnSelectFormat.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
ArchivedFormatSelect archivedFormatSelect = new ArchivedFormatSelect();
archivedFormatSelect.setOnCloseCallBack(new Runnable() {
@Override
public void run() {
customFormatCodes.clear();
btnSelectFormat.setText(archivedFormatSelect.getSelectedFormat().getName());
List<String> setsToAdd = archivedFormatSelect.getSelectedFormat().getAllowedSetCodes();
for (String setName:setsToAdd){
if(!unselectableSets.contains(setName)){
customFormatCodes.add(setName);
}
}
btnSelectFormat.setCommand(event -> {
ArchivedFormatSelect archivedFormatSelect = new ArchivedFormatSelect();
archivedFormatSelect.setOnCloseCallBack(() -> {
customFormatCodes.clear();
btnSelectFormat.setText(archivedFormatSelect.getSelectedFormat().getName());
List<String> setsToAdd = archivedFormatSelect.getSelectedFormat().getAllowedSetCodes();
for (String setName:setsToAdd){
if(!unselectableSets.contains(setName)){
customFormatCodes.add(setName);
}
});
Forge.openScreen(archivedFormatSelect);
}
}
});
Forge.openScreen(archivedFormatSelect);
});
btnPrizeSelectFormat.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
ArchivedFormatSelect archivedFormatSelect = new ArchivedFormatSelect();
archivedFormatSelect.setOnCloseCallBack(new Runnable() {
@Override
public void run() {
customPrizeFormatCodes.clear();
btnPrizeSelectFormat.setText(archivedFormatSelect.getSelectedFormat().getName());
List<String> setsToAdd = archivedFormatSelect.getSelectedFormat().getAllowedSetCodes();
for (String setName:setsToAdd){
if(!unselectableSets.contains(setName)){
customPrizeFormatCodes.add(setName);
}
}
btnPrizeSelectFormat.setCommand(event -> {
ArchivedFormatSelect archivedFormatSelect = new ArchivedFormatSelect();
archivedFormatSelect.setOnCloseCallBack(() -> {
customPrizeFormatCodes.clear();
btnPrizeSelectFormat.setText(archivedFormatSelect.getSelectedFormat().getName());
List<String> setsToAdd = archivedFormatSelect.getSelectedFormat().getAllowedSetCodes();
for (String setName:setsToAdd){
if(!unselectableSets.contains(setName)){
customPrizeFormatCodes.add(setName);
}
});
Forge.openScreen(archivedFormatSelect);
}
}
});
Forge.openScreen(archivedFormatSelect);
});
// Fantasy box enabled by Default
cbFantasy.setSelected(true);
cbFantasy.setEnabled(true);
cbCommander.setSelected(false);
cbCommander.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (!isCommander())
return;
cbxStartingWorld.setSelectedItem(FModel.getWorlds().get("Random Commander"));
}
cbCommander.setCommand(event -> {
if (!isCommander())
return;
cbxStartingWorld.setSelectedItem(FModel.getWorlds().get("Random Commander"));
});
}
@@ -644,30 +605,22 @@ public class NewQuestScreen extends FScreen {
}
private void startNewQuest(final String questName, final GameFormat fmtPrizes, final Deck dckStartPool, final GameFormat fmtStartPool) {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblCreatingNewQuest"), new Runnable() {
@Override
public void run() {
final QuestMode mode = isFantasy() ? QuestMode.Fantasy : QuestMode.Classic;
final StartingPoolPreferences userPrefs =
new StartingPoolPreferences(getPoolType(), getPreferredColors(), cbIncludeArtifacts.isSelected(), startWithCompleteSet(), allowDuplicateCards(), numberOfBoostersField.getValue());
QuestController qc = FModel.getQuest();
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblCreatingNewQuest"), true, () -> {
final QuestMode mode = isFantasy() ? QuestMode.Fantasy : QuestMode.Classic;
final StartingPoolPreferences userPrefs =
new StartingPoolPreferences(getPoolType(), getPreferredColors(), cbIncludeArtifacts.isSelected(), startWithCompleteSet(), allowDuplicateCards(), numberOfBoostersField.getValue());
QuestController qc = FModel.getQuest();
DeckConstructionRules dcr = isCommander() ? DeckConstructionRules.Commander: DeckConstructionRules.Default;
DeckConstructionRules dcr = isCommander() ? DeckConstructionRules.Commander: DeckConstructionRules.Default;
qc.newGame(questName, getSelectedDifficulty(), mode, fmtPrizes, isUnlockSetsAllowed(), dckStartPool, fmtStartPool, getStartingWorldName(), userPrefs, dcr);
qc.save();
qc.newGame(questName, getSelectedDifficulty(), mode, fmtPrizes, isUnlockSetsAllowed(), dckStartPool, fmtStartPool, getStartingWorldName(), userPrefs, dcr);
qc.save();
// Save in preferences.
FModel.getQuestPreferences().setPref(QPref.CURRENT_QUEST, questName + ".dat");
FModel.getQuestPreferences().save();
// Save in preferences.
FModel.getQuestPreferences().setPref(QPref.CURRENT_QUEST, questName + ".dat");
FModel.getQuestPreferences().save();
QuestMenu.launchQuestMode(LaunchReason.NewQuest, isCommander()); //launch quest mode for new quest
}
});
}
});
QuestMenu.launchQuestMode(LaunchReason.NewQuest, isCommander()); //launch quest mode for new quest
}));
}
}

View File

@@ -12,8 +12,6 @@ import forge.gui.FThreads;
import forge.gui.interfaces.IButton;
import forge.model.FModel;
import forge.screens.LoadingOverlay;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
public class QuestDuelsScreen extends QuestLaunchScreen {
@@ -33,12 +31,7 @@ public class QuestDuelsScreen extends QuestLaunchScreen {
public QuestDuelsScreen() {
super();
pnlDuels.setActivateHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
startMatch();
}
});
pnlDuels.setActivateHandler(event -> startMatch());
}
@Override
@@ -74,23 +67,15 @@ public class QuestDuelsScreen extends QuestLaunchScreen {
}
private void generateDuels() {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingCurrentQuest"), new Runnable() {
@Override
public void run() {
pnlDuels.clear();
List<QuestEventDuel> duels = FModel.getQuest().getDuelsManager().generateDuels();
if (duels != null) {
for (QuestEventDuel duel : duels) {
pnlDuels.add(new QuestEventPanel(duel, pnlDuels));
}
}
pnlDuels.revalidate();
}
});
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingCurrentQuest"), true, () -> {
pnlDuels.clear();
List<QuestEventDuel> duels = FModel.getQuest().getDuelsManager().generateDuels();
if (duels != null) {
for (QuestEventDuel duel : duels) {
pnlDuels.add(new QuestEventPanel(duel, pnlDuels));
}
}
});
pnlDuels.revalidate();
}));
}
}

View File

@@ -22,23 +22,10 @@ public abstract class QuestLaunchScreen extends LaunchScreen {
@Override
protected void startMatch() {
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
if (QuestUtil.canStartGame()) {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
QuestUtil.finishStartingGame();
}
});
}
});
return;
}
FThreads.invokeInBackgroundThread(() -> {
if (QuestUtil.canStartGame()) {
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingNewGame"), true, () -> QuestUtil.finishStartingGame()));
return;
}
});
}

View File

@@ -26,8 +26,6 @@ import forge.screens.LoadingOverlay;
import forge.screens.home.HomeScreen;
import forge.screens.home.LoadGameMenu.LoadGameScreen;
import forge.screens.home.NewGameMenu.NewGameScreen;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.util.ThreadUtil;
public class QuestMenu extends FPopupMenu implements IVQuestStats {
@@ -42,88 +40,28 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
private static final QuestStatsScreen statsScreen = new QuestStatsScreen();
private static final QuestTournamentsScreen tournamentsScreen = new QuestTournamentsScreen();
private static final FMenuItem duelsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblDuels"), FSkinImage.QUEST_BIG_SWORD, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(duelsScreen);
}
private static final FMenuItem duelsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblDuels"), FSkinImage.QUEST_BIG_SWORD, event -> setCurrentScreen(duelsScreen));
private static final FMenuItem challengesItem = new FMenuItem(Forge.getLocalizer().getMessage("lblChallenges"), FSkinImage.QUEST_HEART, event -> setCurrentScreen(challengesScreen));
private static final FMenuItem tournamentsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblTournaments"), FSkinImage.QUEST_BIG_SHIELD, event -> setCurrentScreen(tournamentsScreen));
private static final FMenuItem decksItem = new FMenuItem(Forge.getLocalizer().getMessage("lblQuestDecks"), FSkinImage.QUEST_BIG_BAG, event -> setCurrentScreen(decksScreen));
private static final FMenuItem spellShopItem = new FMenuItem(Forge.getLocalizer().getMessage("lblSpellShop"), FSkinImage.QUEST_BOOK, event -> setCurrentScreen(spellShopScreen));
private static final FMenuItem bazaarItem = new FMenuItem(Forge.getLocalizer().getMessage("lblBazaar"), FSkinImage.QUEST_BOTTLES, event -> setCurrentScreen(bazaarScreen));
private static final FMenuItem statsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblStatistics"), FSkinImage.MENU_STATS, event -> setCurrentScreen(statsScreen));
private static final FMenuItem unlockSetsItem = new FMenuItem(Forge.getLocalizer().getMessage("btnUnlockSets"), FSkinImage.QUEST_MAP, event -> {
//invoke in background thread so prompts can work
ThreadUtil.invokeInGameThread(() -> {
QuestUtil.chooseAndUnlockEdition();
FThreads.invokeInEdtLater(() -> updateCurrentQuestScreen());
});
});
private static final FMenuItem challengesItem = new FMenuItem(Forge.getLocalizer().getMessage("lblChallenges"), FSkinImage.QUEST_HEART, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(challengesScreen);
}
});
private static final FMenuItem tournamentsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblTournaments"), FSkinImage.QUEST_BIG_SHIELD, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(tournamentsScreen);
}
});
private static final FMenuItem decksItem = new FMenuItem(Forge.getLocalizer().getMessage("lblQuestDecks"), FSkinImage.QUEST_BIG_BAG, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(decksScreen);
}
});
private static final FMenuItem spellShopItem = new FMenuItem(Forge.getLocalizer().getMessage("lblSpellShop"), FSkinImage.QUEST_BOOK, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(spellShopScreen);
}
});
private static final FMenuItem bazaarItem = new FMenuItem(Forge.getLocalizer().getMessage("lblBazaar"), FSkinImage.QUEST_BOTTLES, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(bazaarScreen);
}
});
private static final FMenuItem statsItem = new FMenuItem(Forge.getLocalizer().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(statsScreen);
}
});
private static final FMenuItem unlockSetsItem = new FMenuItem(Forge.getLocalizer().getMessage("btnUnlockSets"), FSkinImage.QUEST_MAP, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
ThreadUtil.invokeInGameThread(new Runnable() { //invoke in background thread so prompts can work
@Override
public void run() {
QuestUtil.chooseAndUnlockEdition();
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
updateCurrentQuestScreen();
}
});
}
});
}
});
private static final FMenuItem travelItem = new FMenuItem(Forge.getLocalizer().getMessage("btnTravel"), FSkinImage.QUEST_MAP, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
ThreadUtil.invokeInGameThread(new Runnable() { //invoke in background thread so prompts can work
@Override
public void run() {
QuestUtil.travelWorld();
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
updateCurrentQuestScreen();
}
});
}
});
}
});
private static final FMenuItem prefsItem = new FMenuItem(Forge.getLocalizer().getMessage("Preferences"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(prefsScreen);
}
private static final FMenuItem travelItem = new FMenuItem(Forge.getLocalizer().getMessage("btnTravel"), FSkinImage.QUEST_MAP, event -> {
//invoke in background thread so prompts can work
ThreadUtil.invokeInGameThread(() -> {
QuestUtil.travelWorld();
FThreads.invokeInEdtLater(() -> updateCurrentQuestScreen());
});
});
private static final FMenuItem prefsItem = new FMenuItem(Forge.getLocalizer().getMessage("Preferences"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, event -> setCurrentScreen(prefsScreen));
static {
statsScreen.addTournamentResultsLabels(tournamentsScreen);
@@ -159,12 +97,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
static {
//the first time quest mode is launched, add button for it if in Landscape mode
if (Forge.isLandscapeMode()) {
HomeScreen.instance.addButtonForMode("-"+Forge.getLocalizer().getMessage("lblQuestMode"), new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
launchQuestMode(LaunchReason.StartQuestMode, HomeScreen.instance.getQuestCommanderMode());
}
});
HomeScreen.instance.addButtonForMode("-"+Forge.getLocalizer().getMessage("lblQuestMode"), event -> launchQuestMode(LaunchReason.StartQuestMode, HomeScreen.instance.getQuestCommanderMode()));
}
}
@@ -190,40 +123,36 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
final String questname = FModel.getQuestPreferences().getPref(QPref.CURRENT_QUEST);
final File data = new File(dirQuests.getPath(), questname);
if (data.exists()) {
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingCurrentQuest"), new Runnable() {
@Override
@SuppressWarnings("unchecked")
public void run() {
try {
FModel.getQuest().load(QuestDataIO.loadData(data));
} catch (IOException e) {
System.err.println(String.format("Failed to load quest '%s'", questname));
// Failed to load last quest, don't continue with quest loading stuff
return;
}
LoadingOverlay.show(Forge.getLocalizer().getMessage("lblLoadingCurrentQuest"), true, () -> {
try {
FModel.getQuest().load(QuestDataIO.loadData(data));
} catch (IOException e) {
System.err.println(String.format("Failed to load quest '%s'", questname));
// Failed to load last quest, don't continue with quest loading stuff
return;
}
((DeckController<Deck>)EditorType.Quest.getController()).setRootFolder(FModel.getQuest().getMyDecks());
((DeckController<DeckGroup>)EditorType.QuestDraft.getController()).setRootFolder(FModel.getQuest().getDraftDecks());
if (reason == LaunchReason.StartQuestMode) {
if (QuestUtil.getCurrentDeck() == null) {
Forge.openScreen(decksScreen); //if quest doesn't have a deck specified, open decks screen by default
}
else {
Forge.openScreen(duelsScreen); //TODO: Consider opening most recent quest view
}
((DeckController<Deck>)EditorType.Quest.getController()).setRootFolder(FModel.getQuest().getMyDecks());
((DeckController<DeckGroup>)EditorType.QuestDraft.getController()).setRootFolder(FModel.getQuest().getDraftDecks());
if (reason == LaunchReason.StartQuestMode) {
if (QuestUtil.getCurrentDeck() == null) {
Forge.openScreen(decksScreen); //if quest doesn't have a deck specified, open decks screen by default
}
else {
duelsScreen.update();
challengesScreen.update();
tournamentsScreen.update();
decksScreen.refreshDecks();
Forge.openScreen(duelsScreen);
if (reason == LaunchReason.NewQuest) {
LoadGameScreen.QuestMode.setAsBackScreen(true);
}
Forge.openScreen(duelsScreen); //TODO: Consider opening most recent quest view
}
HomeScreen.instance.updateQuestWorld(FModel.getQuest().getWorld() == null ? "" : FModel.getQuest().getWorld().toString());
}
else {
duelsScreen.update();
challengesScreen.update();
tournamentsScreen.update();
decksScreen.refreshDecks();
Forge.openScreen(duelsScreen);
if (reason == LaunchReason.NewQuest) {
LoadGameScreen.QuestMode.setAsBackScreen(true);
}
}
HomeScreen.instance.updateQuestWorld(FModel.getQuest().getWorld() == null ? "" : FModel.getQuest().getWorld().toString());
});
return;
}

View File

@@ -29,8 +29,6 @@ import forge.model.FModel;
import forge.screens.LoadingOverlay;
import forge.screens.TabPageScreen;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.toolbox.FTextArea;
import forge.toolbox.GuiChoose;
@@ -49,36 +47,25 @@ public class QuestSpellShopScreen extends TabPageScreen<QuestSpellShopScreen> {
inventoryPage = ((InventoryPage)tabPages[1]);
btnBuySellMultiple.setVisible(false); //hide unless in multi-select mode
btnBuySellMultiple.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
final SpellShopManager itemManager = ((SpellShopBasePage)getSelectedPage()).itemManager;
final ItemPool<InventoryItem> items = itemManager.getSelectedItemPool();
btnBuySellMultiple.setCommand(event -> {
final SpellShopManager itemManager = ((SpellShopBasePage)getSelectedPage()).itemManager;
final ItemPool<InventoryItem> items = itemManager.getSelectedItemPool();
if (items.isEmpty()) {
//toggle off multi-select mode if no items selected
itemManager.toggleMultiSelectMode(-1);
return;
}
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
if (getSelectedPage() == spellShopPage) {
spellShopPage.activateItems(items);
}
else {
inventoryPage.activateItems(items);
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
updateCreditsLabel();
}
});
}
});
if (items.isEmpty()) {
//toggle off multi-select mode if no items selected
itemManager.toggleMultiSelectMode(-1);
return;
}
FThreads.invokeInBackgroundThread(() -> {
if (getSelectedPage() == spellShopPage) {
spellShopPage.activateItems(items);
}
else {
inventoryPage.activateItems(items);
}
FThreads.invokeInEdtLater(() -> updateCreditsLabel());
});
});
}
@@ -190,28 +177,17 @@ public class QuestSpellShopScreen extends TabPageScreen<QuestSpellShopScreen> {
parentScreen.tabHeader.setVisible(!multiSelectMode);
}
});
itemManager.setItemActivateHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
}
itemManager.setItemActivateHandler(event -> {
});
itemManager.setContextMenuBuilder(new ContextMenuBuilder<InventoryItem>() {
@Override
public void buildMenu(final FDropDownMenu menu, final InventoryItem item) {
menu.addItem(new FMenuItem(getVerb(), getVerbIcon(), new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
activateSelectedItem();
}
}));
menu.addItem(new FMenuItem(getVerb(), getVerbIcon(), event -> activateSelectedItem()));
}
});
itemManager.setSelectionChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (itemManager.getMultiSelectMode()) {
parentScreen.updateBuySellButtonCaption();
}
itemManager.setSelectionChangedHandler(event -> {
if (itemManager.getMultiSelectMode()) {
parentScreen.updateBuySellButtonCaption();
}
});
add(lblCredits);
@@ -235,19 +211,11 @@ public class QuestSpellShopScreen extends TabPageScreen<QuestSpellShopScreen> {
if (result == null || result <= 0) { return; }
//invoke in background thread so other dialogs can be shown properly
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
ItemPool<InventoryItem> items = new ItemPool<>(InventoryItem.class);
items.add(item, result);
activateItems(items);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
parentScreen.updateCreditsLabel();
}
});
}
FThreads.invokeInBackgroundThread(() -> {
ItemPool<InventoryItem> items = new ItemPool<>(InventoryItem.class);
items.add(item, result);
activateItems(items);
FThreads.invokeInEdtLater(() -> parentScreen.updateCreditsLabel());
});
}
};
@@ -290,22 +258,14 @@ public class QuestSpellShopScreen extends TabPageScreen<QuestSpellShopScreen> {
@Override
protected void refresh() {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show(Forge.getLocalizer().getInstance().getMessage("lblLoading"), new Runnable() {
@Override
public void run() {
Map<ColumnDef, ItemColumn> colOverrides = new HashMap<>();
ItemColumn.addColOverride(ItemManagerConfig.SPELL_SHOP, colOverrides, ColumnDef.PRICE, QuestSpellShop.fnPriceCompare, QuestSpellShop.fnPriceGet);
ItemColumn.addColOverride(ItemManagerConfig.SPELL_SHOP, colOverrides, ColumnDef.OWNED, FModel.getQuest().getCards().getFnOwnedCompare(), FModel.getQuest().getCards().getFnOwnedGet());
itemManager.setup(ItemManagerConfig.SPELL_SHOP, colOverrides);
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getInstance().getMessage("lblLoading"), true, () -> {
Map<ColumnDef, ItemColumn> colOverrides = new HashMap<>();
ItemColumn.addColOverride(ItemManagerConfig.SPELL_SHOP, colOverrides, ColumnDef.PRICE, QuestSpellShop.fnPriceCompare, QuestSpellShop.fnPriceGet);
ItemColumn.addColOverride(ItemManagerConfig.SPELL_SHOP, colOverrides, ColumnDef.OWNED, FModel.getQuest().getCards().getFnOwnedCompare(), FModel.getQuest().getCards().getFnOwnedGet());
itemManager.setup(ItemManagerConfig.SPELL_SHOP, colOverrides);
itemManager.setPool(FModel.getQuest().getCards().getShopList());
}
});
}
});
itemManager.setPool(FModel.getQuest().getCards().getShopList());
}));
}
@Override
@@ -337,47 +297,25 @@ public class QuestSpellShopScreen extends TabPageScreen<QuestSpellShopScreen> {
private static class InventoryPage extends SpellShopBasePage {
protected FLabel lblSellExtras = add(new FLabel.Builder().text(Forge.getLocalizer().getMessage("lblSellAllExtras"))
.icon(Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS).iconScaleFactor(1f).align(Align.right).font(FSkinFont.get(16))
.command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
//invoke in background thread so other dialogs can be shown properly
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
.command(event -> {
//invoke in background thread so other dialogs can be shown properly
FThreads.invokeInBackgroundThread(() -> {
QuestSpellShop.sellExtras(parentScreen.spellShopPage.itemManager, itemManager);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
parentScreen.updateCreditsLabel();
}
});
}
});
}
}).build());
FThreads.invokeInEdtLater(() -> parentScreen.updateCreditsLabel());
});
}).build());
protected FLabel lblSelectAll = add(new FLabel.Builder().text(Forge.getLocalizer().getMessage("lblSelectAllCards"))
.icon(Forge.hdbuttons ? FSkinImage.HDSTAR_FILLED : FSkinImage.STAR_FILLED).iconScaleFactor(1f).align(Align.right).font(FSkinFont.get(16))
.command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
//invoke in background thread so other dialogs can be shown properly
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
if (!itemManager.getMultiSelectMode()) {
itemManager.toggleMultiSelectMode(0);
}
itemManager.selectAll();
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
parentScreen.updateCreditsLabel();
}
});
}
});
}
.command(event -> {
//invoke in background thread so other dialogs can be shown properly
FThreads.invokeInBackgroundThread(() -> {
if (!itemManager.getMultiSelectMode()) {
itemManager.toggleMultiSelectMode(0);
}
itemManager.selectAll();
FThreads.invokeInEdtLater(() -> parentScreen.updateCreditsLabel());
});
}).build());
private InventoryPage() {

View File

@@ -34,8 +34,6 @@ import forge.screens.LoadingOverlay;
import forge.screens.limited.DraftingProcessScreen;
import forge.toolbox.FButton;
import forge.toolbox.FContainer;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.toolbox.FTextField;
import forge.util.Utils;
@@ -84,52 +82,21 @@ public class QuestTournamentsScreen extends QuestLaunchScreen implements IQuestT
public QuestTournamentsScreen() {
super();
controller = new QuestTournamentController(this);
btnSpendToken.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FThreads.invokeInBackgroundThread(new Runnable() { //must run in background thread to handle alerts
@Override
public void run() {
controller.spendToken();
}
});
}
btnSpendToken.setCommand(event -> {
//must run in background thread to handle alerts
FThreads.invokeInBackgroundThread(() -> controller.spendToken());
});
btnEditDeck.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
editDeck(true);
}
});
btnLeaveTournament.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FThreads.invokeInBackgroundThread(new Runnable() { //must run in background thread to handle alerts
@Override
public void run() {
controller.endTournamentAndAwardPrizes();
}
});
}
btnEditDeck.setCommand(event -> editDeck(true));
btnLeaveTournament.setCommand(event -> {
//must run in background thread to handle alerts
FThreads.invokeInBackgroundThread(() -> controller.endTournamentAndAwardPrizes());
});
// TODO: is it possible to somehow reuse the original btnEditDeck/btnLeaveTournament
btnEditDeckInTourn.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
editDeck(true);
}
});
btnLeaveTournamentInTourn.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FThreads.invokeInBackgroundThread(new Runnable() { //must run in background thread to handle alerts
@Override
public void run() {
controller.endTournamentAndAwardPrizes();
}
});
}
btnEditDeckInTourn.setCommand(event -> editDeck(true));
btnLeaveTournamentInTourn.setCommand(event -> {
//must run in background thread to handle alerts
FThreads.invokeInBackgroundThread(() -> controller.endTournamentAndAwardPrizes());
});
pnlPrepareDeck.add(btnEditDeck);
@@ -173,7 +140,8 @@ public class QuestTournamentsScreen extends QuestLaunchScreen implements IQuestT
@Override
protected void updateHeaderCaption() {
if (mode == Mode.PREPARE_DECK) {
setHeaderCaption(FModel.getQuest().getName() + " - " + getGameType() + "\n" + Forge.getLocalizer().getMessage("lblDraft") + " - " + FModel.getQuest().getAchievements().getCurrentDraft().getTitle());
String title = FModel.getQuest().getAchievements().getCurrentDraft() == null ? "" : FModel.getQuest().getAchievements().getCurrentDraft().getTitle();
setHeaderCaption(FModel.getQuest().getName() + " - " + getGameType() + "\n" + Forge.getLocalizer().getMessage("lblDraft") + " - " + title);
}
else {
super.updateHeaderCaption();
@@ -230,17 +198,7 @@ public class QuestTournamentsScreen extends QuestLaunchScreen implements IQuestT
@Override
public void startDraft(BoosterDraft draft) {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show("Loading Quest Tournament", new Runnable() {
@Override
public void run() {
Forge.openScreen(new DraftingProcessScreen(draft, EditorType.QuestDraft, controller));
}
});
}
});
FThreads.invokeInEdtLater(() -> LoadingOverlay.show("Loading Quest Tournament", true, () -> Forge.openScreen(new DraftingProcessScreen(draft, EditorType.QuestDraft, controller))));
}
private Deck getDeck() {
@@ -275,22 +233,20 @@ public class QuestTournamentsScreen extends QuestLaunchScreen implements IQuestT
return;
}
FThreads.invokeInBackgroundThread(new Runnable() { //must run in background thread to handle alerts
@Override
public void run() {
switch (mode) {
case SELECT_TOURNAMENT:
controller.startDraft();
break;
case PREPARE_DECK:
controller.startTournament();
break;
case TOURNAMENT_ACTIVE:
controller.startNextMatch();
break;
default:
break;
}
//must run in background thread to handle alerts
FThreads.invokeInBackgroundThread(() -> {
switch (mode) {
case SELECT_TOURNAMENT:
controller.startDraft();
break;
case PREPARE_DECK:
controller.startTournament();
break;
case TOURNAMENT_ACTIVE:
controller.startNextMatch();
break;
default:
break;
}
});
}

View File

@@ -5,7 +5,11 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.collect.ImmutableList;
import forge.StaticData;
import forge.gui.FThreads;
import forge.gui.GuiBase;
import forge.screens.LoadingOverlay;
import org.apache.commons.lang3.StringUtils;
import com.badlogic.gdx.utils.Align;
@@ -34,6 +38,7 @@ import forge.toolbox.FOptionPane;
import forge.toolbox.GuiChoose;
import forge.util.Callback;
import forge.util.FileUtil;
import org.apache.commons.lang3.tuple.Pair;
public class FilesPage extends TabPage<SettingsScreen> {
private final FGroupList<FilesItem> lstItems = add(new FGroupList<>());
@@ -43,10 +48,45 @@ public class FilesPage extends TabPage<SettingsScreen> {
lstItems.setListItemRenderer(new FilesItemRenderer());
lstItems.addGroup(Forge.getLocalizer().getMessage("lblCardAudit"));
lstItems.addGroup(Forge.getLocalizer().getMessage("ContentDownloaders"));
lstItems.addGroup(Forge.getLocalizer().getMessage("lblStorageLocations"));
//lstItems.addGroup("Data Import");
//Auditer
lstItems.addItem(new Extra(Forge.getLocalizer().getMessage("btnListImageData"), Forge.getLocalizer().getMessage("lblListImageData")) {
@Override
public void select() {
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Forge.getLocalizer().getMessage("lblProcessingCards"), true, () -> {
StringBuffer nifSB = new StringBuffer(); // NO IMAGE FOUND BUFFER
StringBuffer cniSB = new StringBuffer(); // CARD NOT IMPLEMENTED BUFFER
nifSB.append("\n\n-------------------\n");
nifSB.append("NO IMAGE FOUND LIST\n");
nifSB.append("-------------------\n\n");
cniSB.append("\n\n-------------------\n");
cniSB.append("UNIMPLEMENTED CARD LIST\n");
cniSB.append("-------------------\n\n");
Pair<Integer, Integer> totalAudit = StaticData.instance().audit(nifSB, cniSB);
String msg = nifSB.toString();
String title = "Missing images: " + totalAudit.getLeft() + "\nUnimplemented cards: " + totalAudit.getRight();
FOptionPane.showOptionDialog(msg, title, FOptionPane.INFORMATION_ICON, ImmutableList.of(Forge.getLocalizer().getMessage("lblCopy"), Forge.getLocalizer().getMessage("lblClose")), -1, new Callback<Integer>() {
@Override
public void run(Integer result) {
switch (result) {
case 0:
Forge.getClipboard().setContents(msg);
break;
default:
break;
}
}
});
}));
}
}, 0);
//content downloaders
lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadPics"),
Forge.getLocalizer().getMessage("lblDownloadPics")) {
@@ -54,35 +94,35 @@ public class FilesPage extends TabPage<SettingsScreen> {
protected GuiDownloadService createService() {
return new GuiDownloadPicturesLQ();
}
}, 0);
}, 1);
lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadSetPics"),
Forge.getLocalizer().getMessage("lblDownloadSetPics")) {
@Override
protected GuiDownloadService createService() {
return new GuiDownloadSetPicturesLQ();
}
}, 0);
}, 1);
lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadQuestImages"),
Forge.getLocalizer().getMessage("lblDownloadQuestImages")) {
@Override
protected GuiDownloadService createService() {
return new GuiDownloadQuestImages();
}
}, 0);
}, 1);
lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadAchievementImages"),
Forge.getLocalizer().getMessage("lblDownloadAchievementImages")) {
@Override
protected GuiDownloadService createService() {
return new GuiDownloadAchievementImages();
}
}, 0);
}, 1);
lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadPrices"),
Forge.getLocalizer().getMessage("lblDownloadPrices")) {
@Override
protected GuiDownloadService createService() {
return new GuiDownloadPrices();
}
}, 0);
}, 1);
lstItems.addItem(new ContentDownloader(Forge.getLocalizer().getMessage("btnDownloadSkins"),
Forge.getLocalizer().getMessage("lblDownloadSkins")) {
@Override
@@ -93,7 +133,7 @@ public class FilesPage extends TabPage<SettingsScreen> {
protected void finishCallback() {
SettingsScreen.getSettingsScreen().getSettingsPage().refreshSkinsList();
}
}, 0);
}, 1);
lstItems.addItem(new OptionContentDownloader(Forge.getLocalizer().getMessage("btnDownloadCJKFonts"),
Forge.getLocalizer().getMessage("lblDownloadCJKFonts"),
Forge.getLocalizer().getMessage("lblDownloadCJKFontPrompt")) {
@@ -118,7 +158,7 @@ public class FilesPage extends TabPage<SettingsScreen> {
protected void finishCallback() {
SettingsScreen.getSettingsScreen().getSettingsPage().refreshCJKFontsList();
}
}, 0);
}, 1);
//storage locations
final StorageOption cardPicsOption = new StorageOption(Forge.getLocalizer().getMessage("lblCardPicsLocation"), ForgeProfileProperties.getCardPicsDir()) {
@Override
@@ -141,7 +181,7 @@ public class FilesPage extends TabPage<SettingsScreen> {
//ensure decks option is updated if needed
decksOption.updateDir(ForgeProfileProperties.getDecksDir());
}
}, 1);
}, 2);
lstItems.addItem(new StorageOption(Forge.getLocalizer().getMessage("lblImageCacheLocation"), ForgeProfileProperties.getCacheDir()) {
@Override
protected void onDirectoryChanged(String newDir) {
@@ -150,9 +190,9 @@ public class FilesPage extends TabPage<SettingsScreen> {
//ensure card pics option is updated if needed
cardPicsOption.updateDir(ForgeProfileProperties.getCardPicsDir());
}
}, 1);
lstItems.addItem(cardPicsOption, 1);
lstItems.addItem(decksOption, 1);
}, 2);
lstItems.addItem(cardPicsOption, 2);
lstItems.addItem(decksOption, 2);
}
}
@@ -201,7 +241,19 @@ public class FilesPage extends TabPage<SettingsScreen> {
g.drawText(value.description, SettingsScreen.DESC_FONT, SettingsScreen.DESC_COLOR, x, y + h, w, totalHeight - h + SettingsScreen.getInsets(w), true, Align.left, false);
}
}
private abstract class Extra extends FilesItem {
Extra(String label0, String description0) {
super(label0, description0);
}
@Override
public void select() {
}
protected void finishCallback() {
}
}
private abstract class ContentDownloader extends FilesItem {
ContentDownloader(String label0, String description0) {
super(label0, description0);
@@ -239,7 +291,7 @@ public class FilesPage extends TabPage<SettingsScreen> {
@Override
public void run(String result) {
final String url = categories.get(result);
final String name = url.substring(url.lastIndexOf("/") + 1);
final String name = url.substring(url.lastIndexOf("/") + 2);
new GuiDownloader(new GuiDownloadZipService(name, name, url, ForgeConstants.FONTS_DIR, null, null), new Callback<Boolean>() {
@Override
public void run(Boolean finished) {

View File

@@ -61,5 +61,6 @@ twosat
Xyx
Zimtente
Zuchinni
XavierMD
(If you think your name should be on this list, add it with your next contribution)

View File

@@ -1,6 +1,7 @@
Name:Aerial Predation
ManaCost:2 G
Types:Instant
A:SP$ Destroy | Cost$ 2 G | ValidTgts$ Creature.withFlying | TgtPrompt$ Select target creature with flying | SubAbility$ NaturalLife | SpellDescription$ Destroy target creature with flying. You gain 2 life
SVar:NaturalLife:DB$ GainLife | Defined$ You | LifeAmount$ 2
A:SP$ Destroy | ValidTgts$ Creature.withFlying | TgtPrompt$ Select target creature with flying | SubAbility$ DBGainLife | SpellDescription$ Destroy target creature with flying. You gain 2 life.
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 2
DeckHas:Ability$LifeGain
Oracle:Destroy target creature with flying. You gain 2 life.

View File

@@ -5,7 +5,7 @@ K:Casualty:2
A:SP$ ChangeZone | ValidTgts$ Permanent.nonEnchantment | TgtPrompt$ Select target nonenchantment permanent | Origin$ Battlefield | Destination$ Library | Shuffle$ True | SubAbility$ DBExile | SpellDescription$ The owner of target nonenchantment permanent shuffles it into their library,
SVar:DBExile:DB$ Dig | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | Defined$ TargetedOwner | RememberChanged$ True | SubAbility$ DBPutLand | SpellDescription$ then exiles the top card of their library.
SVar:DBPutLand:DB$ ChangeZone | ConditionDefined$ Remembered | ConditionPresent$ Land | Defined$ Remembered | DefinedDesc$ it | Origin$ Exile | Destination$ Battlefield | ForgetChanged$ True | SubAbility$ DBCast | SpellDescription$ If it's a land card, they put it onto the battlefield.
SVar:DBCast:DB$ Play | Defined$ Remembered | DefinedDesc$ it | ValidSA$ Spell | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup | SpellDescription$ Otherwise, they may cast it without paying its mana cost.
SVar:DBCast:DB$ Play | Defined$ Remembered | DefinedDesc$ it | ValidSA$ Spell | Controller$ RememberedOwner | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup | SpellDescription$ Otherwise, they may cast it without paying its mana cost.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHas:Ability$Sacrifice
Oracle:Casualty 2 (As you cast this spell, you may sacrifice a creature with power 2 or greater. When you do, copy this spell and you may choose a new target for the copy.)\nThe owner of target nonenchantment permanent shuffles it into their library, then exiles the top card of their library. If it's a land card, they put it onto the battlefield. Otherwise, they may cast it without paying its mana cost.

View File

@@ -3,7 +3,7 @@ ManaCost:2 G
Types:Snow Creature Elf Warrior
PT:3/2
T:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | Execute$ TrigEffect | TriggerZones$ Battlefield | SnowSpentForCardsColor$ True | TriggerDescription$ Whenever you cast a creature spell, if {S} of any of that spell's colors was spent to cast it, that creature enters the battlefield with an additional +1/+1 counter on it. ({S} is mana from a snow source.)
SVar:TrigEffect:DB$ Effect | RememberObjects$ TriggeredCard | ReplacementEffects$ ETBCreat
SVar:TrigEffect:DB$ Effect | RememberObjects$ TriggeredCard | ReplacementEffects$ ETBCreat | ExileOnMoved$ Stack
SVar:ETBCreat:Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | ReplaceWith$ DBPutP1P1 | ReplacementResult$ Updated | Description$ That creature enters the battlefield with an additional +1/+1 counter on it.
SVar:DBPutP1P1:DB$ PutCounter | Defined$ ReplacedCard | CounterType$ P1P1 | ETB$ True | CounterNum$ 1 | SubAbility$ DBExile
SVar:DBExile:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile

Some files were not shown because too many files have changed in this diff Show More