mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Merge branch 'master' into questMode_wildOpponents
# Conflicts: # forge-gui/res/languages/en-US.properties
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||
@@ -14,6 +20,7 @@ import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.player.PlayerZoneUpdate;
|
||||
@@ -21,10 +28,6 @@ import forge.player.PlayerZoneUpdates;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IGuiGame {
|
||||
void setGameView(GameView gameView);
|
||||
GameView getGameView();
|
||||
@@ -51,6 +54,7 @@ public interface IGuiGame {
|
||||
void updateStack();
|
||||
void notifyStackAddition(final GameEventSpellAbilityCast event);
|
||||
void notifyStackRemoval(final GameEventSpellRemovedFromStack event);
|
||||
void handleLandPlayed(Card land, Zone zone);
|
||||
Iterable<PlayerZoneUpdate> tempShowZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
|
||||
void hideZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
|
||||
void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate);
|
||||
|
||||
@@ -9,8 +9,6 @@ import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import forge.GuiBase;
|
||||
import forge.util.Localizer;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -20,13 +18,16 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.IMayViewCards;
|
||||
@@ -34,6 +35,7 @@ import forge.model.FModel;
|
||||
import forge.properties.ForgeConstants;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.trackable.TrackableTypes;
|
||||
import forge.util.Localizer;
|
||||
|
||||
public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
private PlayerView currentPlayer = null;
|
||||
@@ -709,5 +711,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
public void notifyStackRemoval(GameEventSpellRemovedFromStack event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLandPlayed(Card land, Zone zone) {
|
||||
}
|
||||
|
||||
// End of Choice code
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
|
||||
private void updateMessage() {
|
||||
Localizer localizer = Localizer.getInstance();
|
||||
String message = localizer.getMessage("lblSelectAttackCreatures") + currentDefender + localizer.getMessage("lblSelectAttackTarget");
|
||||
String message = localizer.getMessage("lblSelectAttackCreatures") + " " + currentDefender + " " + localizer.getMessage("lblSelectAttackTarget");
|
||||
if (potentialBanding) {
|
||||
message += localizer.getMessage("lblSelectBandingTarget");
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
}
|
||||
else {
|
||||
String attackerName = currentAttacker.isFaceDown() ? localizer.getMessage("lblMorph") : currentAttacker.getName() + " (" + currentAttacker.getId() + ")";
|
||||
String message = localizer.getMessage("lblSelectBlocker") + attackerName + localizer.getMessage("lblOrSelectBlockTarget");
|
||||
String message = localizer.getMessage("lblSelectBlocker") + attackerName + " " + localizer.getMessage("lblOrSelectBlockTarget");
|
||||
showMessage(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,37 @@
|
||||
package forge.player;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.Range;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.*;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
@@ -11,7 +39,11 @@ import forge.StaticData;
|
||||
import forge.achievement.AchievementCollection;
|
||||
import forge.ai.GameState;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.card.*;
|
||||
import forge.card.CardDb;
|
||||
import forge.card.CardType;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.control.FControlGamePlayback;
|
||||
@@ -19,12 +51,27 @@ import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.events.UiEventNextGameDecision;
|
||||
import forge.game.*;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameEntityViewMap;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.GameType;
|
||||
import forge.game.PlanarDice;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.ability.effects.CharmEffect;
|
||||
import forge.game.card.*;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardFaceView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
import forge.game.cost.Cost;
|
||||
@@ -35,10 +82,20 @@ import forge.game.keyword.Keyword;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.mana.Mana;
|
||||
import forge.game.mana.ManaConversionMatrix;
|
||||
import forge.game.player.*;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementLayer;
|
||||
import forge.game.spellability.*;
|
||||
import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.OptionalCostValue;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.spellability.TargetChoices;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.WrappedAbility;
|
||||
import forge.game.zone.MagicStack;
|
||||
@@ -52,28 +109,32 @@ import forge.interfaces.IMacroSystem;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.match.input.*;
|
||||
import forge.match.input.Input;
|
||||
import forge.match.input.InputAttack;
|
||||
import forge.match.input.InputBlock;
|
||||
import forge.match.input.InputConfirm;
|
||||
import forge.match.input.InputConfirmMulligan;
|
||||
import forge.match.input.InputLondonMulligan;
|
||||
import forge.match.input.InputPassPriority;
|
||||
import forge.match.input.InputPayMana;
|
||||
import forge.match.input.InputProxy;
|
||||
import forge.match.input.InputQueue;
|
||||
import forge.match.input.InputSelectCardsForConvokeOrImprovise;
|
||||
import forge.match.input.InputSelectCardsFromList;
|
||||
import forge.match.input.InputSelectEntitiesFromList;
|
||||
import forge.model.FModel;
|
||||
import forge.properties.ForgeConstants;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.MessageUtil;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollection;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import forge.util.gui.SOptionPane;
|
||||
import io.sentry.Sentry;
|
||||
import org.apache.commons.lang3.Range;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* A prototype for player controller class
|
||||
@@ -3032,5 +3093,13 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLandPlayed(Card land, Zone zone) {
|
||||
IGuiGame guiGame = getGui();
|
||||
guiGame.handleLandPlayed(land,zone);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ public class TargetSelection {
|
||||
private boolean bTargetingDone = false;
|
||||
|
||||
private boolean isMandatory() {
|
||||
return ability.isMandatory() || getTgt().getMandatory();
|
||||
// even if its an optionalTrigger, the targeting is still mandatory
|
||||
return ability.isTrigger() || getTgt().getMandatory();
|
||||
}
|
||||
|
||||
public final boolean chooseTargets(Integer numTargets) {
|
||||
|
||||
@@ -321,6 +321,13 @@ public final class ForgeConstants {
|
||||
public static final String STACK_EFFECT_NOTIFICATION_NEVER = "Never";
|
||||
public static final String STACK_EFFECT_NOTIFICATION_ALWAYS = "Always";
|
||||
public static final String STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED = "AI cast/activated, or triggered by any player";
|
||||
|
||||
// Constants for LAnd played notification policy
|
||||
public static final String LAND_PLAYED_NOTIFICATION_NEVER = "Never";
|
||||
public static final String LAND_PLAYED_NOTIFICATION_ALWAYS = "Always";
|
||||
public static final String LAND_PLAYED_NOTIFICATION_ALWAYS_FOR_NONBASIC_LANDS = "Always, but only for nonbasic lands";
|
||||
public static final String LAND_PLAYED_NOTIFICATION_AI = "Lands entering a battlefield because of an action of a AI player";
|
||||
public static final String LAND_PLAYED_NOTIFICATION_AI_FOR_NONBASIC_LANDS = "Nonbasic lands entering a battlefield because of an action of a AI player";
|
||||
|
||||
// Set boolean constant for landscape mode for gdx port
|
||||
public static final boolean isGdxPortLandscape = FileUtil.doesFileExist(ASSETS_DIR + "switch_orientation.ini");
|
||||
|
||||
@@ -121,6 +121,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
||||
UI_CLOSE_ACTION ("NONE"),
|
||||
UI_MANA_LOST_PROMPT ("false"), // Prompt on losing mana when passing priority
|
||||
UI_STACK_EFFECT_NOTIFICATION_POLICY ("Never"),
|
||||
UI_LAND_PLAYED_NOTIFICATION_POLICY ("Never"),
|
||||
UI_PAUSE_WHILE_MINIMIZED("false"),
|
||||
UI_TOKENS_IN_SEPARATE_ROW("false"), // Display tokens in their own battlefield row.
|
||||
UI_DISPLAY_CURRENT_COLORS(ForgeConstants.DISP_CURRENT_COLORS_NEVER),
|
||||
|
||||
@@ -21,6 +21,22 @@ import forge.properties.ForgePreferences;
|
||||
|
||||
public abstract class ImageFetcher {
|
||||
private static final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
// see https://scryfall.com/docs/api/languages and
|
||||
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||||
private static final HashMap<String, String> langCodeMap = new HashMap<>();
|
||||
static {
|
||||
langCodeMap.put("en-US", "en");
|
||||
langCodeMap.put("es-ES", "es");
|
||||
langCodeMap.put("fr-FR", "fr");
|
||||
langCodeMap.put("de-DE", "de");
|
||||
langCodeMap.put("it-IT", "it");
|
||||
langCodeMap.put("pt-BR", "pt");
|
||||
langCodeMap.put("ja-JP", "ja");
|
||||
langCodeMap.put("ko-KR", "ko");
|
||||
langCodeMap.put("ru-RU", "ru");
|
||||
langCodeMap.put("zh-CN", "zhs");
|
||||
langCodeMap.put("zh-HK", "zht");
|
||||
};
|
||||
private HashMap<String, HashSet<Callback>> currentFetches = new HashMap<>();
|
||||
private HashMap<String, String> tokenImages;
|
||||
|
||||
@@ -47,40 +63,49 @@ public abstract class ImageFetcher {
|
||||
final String filename = ImageUtil.getImageKey(paperCard, backFace, true);
|
||||
destFile = new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + filename + ".jpg");
|
||||
|
||||
// First try to download the LQ Set URL, then fetch from scryfall
|
||||
StringBuilder setDownload = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD);
|
||||
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace));
|
||||
downloadUrls.add(setDownload.toString());
|
||||
|
||||
int artIndex = 1;
|
||||
final Pattern pattern = Pattern.compile(
|
||||
"^.:([^|]*\\|){2}(\\d+).*$"
|
||||
);
|
||||
final Pattern pattern = Pattern.compile("^.:([^|]*\\|){2}(\\d+).*$");
|
||||
Matcher matcher = pattern.matcher(imageKey);
|
||||
if (matcher.matches()) {
|
||||
artIndex = Integer.parseInt(matcher.group(2));
|
||||
}
|
||||
final StaticData data = StaticData.instance();
|
||||
final String cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition(), artIndex);
|
||||
if (cardNum != null) {
|
||||
final String cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(),
|
||||
paperCard.getEdition(), artIndex);
|
||||
if (cardNum != null) {
|
||||
String suffix = "";
|
||||
if (paperCard.getRules().getOtherPart() != null) {
|
||||
suffix = (backFace ? "b" : "a");
|
||||
}
|
||||
final String editionMciCode = data.getEditions().getMciCodeByCode(paperCard.getEdition());
|
||||
downloadUrls.add(String.format("https://img.scryfall.com/cards/normal/en/%s/%s%s.jpg", editionMciCode, cardNum, suffix));
|
||||
String langCode = "en";
|
||||
String UILang = FModel.getPreferences().getPref(ForgePreferences.FPref.UI_LANGUAGE);
|
||||
if (langCodeMap.containsKey(UILang)) {
|
||||
langCode = langCodeMap.get(UILang);
|
||||
}
|
||||
// see https://scryfall.com/blog 2020/8/6, and
|
||||
// https://scryfall.com/docs/api/cards/collector
|
||||
downloadUrls.add(String.format("https://api.scryfall.com/cards/%s/%s%s/%s?format=image&version=normal",
|
||||
editionMciCode, cardNum, suffix, langCode));
|
||||
}
|
||||
|
||||
StringBuilder setDownload = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD);
|
||||
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace));
|
||||
downloadUrls.add(setDownload.toString());
|
||||
|
||||
} else if (prefix.equals(ImageKeys.TOKEN_PREFIX)) {
|
||||
if (tokenImages == null) {
|
||||
tokenImages = new HashMap<>();
|
||||
for (Pair<String, String> nameUrlPair : FileUtil.readNameUrlFile(ForgeConstants.IMAGE_LIST_TOKENS_FILE)) {
|
||||
for (Pair<String, String> nameUrlPair : FileUtil
|
||||
.readNameUrlFile(ForgeConstants.IMAGE_LIST_TOKENS_FILE)) {
|
||||
tokenImages.put(nameUrlPair.getLeft(), nameUrlPair.getRight());
|
||||
}
|
||||
}
|
||||
final String filename = imageKey.substring(2) + ".jpg";
|
||||
String tokenUrl = tokenImages.get(filename);
|
||||
if (tokenUrl == null) {
|
||||
System.err.println("No specified file for '" + filename + "'.. Attempting to download from default Url");
|
||||
System.err
|
||||
.println("No specified file for '" + filename + "'.. Attempting to download from default Url");
|
||||
tokenUrl = String.format("%s%s", ForgeConstants.URL_TOKEN_DOWNLOAD, filename);
|
||||
}
|
||||
destFile = new File(ForgeConstants.CACHE_TOKEN_PICS_DIR, filename);
|
||||
|
||||
Reference in New Issue
Block a user