mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 10:18:01 +00:00
Compare commits
169 Commits
paperCardI
...
Hanmac-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a21656521f | ||
|
|
bdec4095c0 | ||
|
|
8475456c0b | ||
|
|
651caccd71 | ||
|
|
8e9fb8570e | ||
|
|
5a183a6042 | ||
|
|
67e6a7aa1a | ||
|
|
b76c67f309 | ||
|
|
99c6b6d815 | ||
|
|
cadc39699d | ||
|
|
8c06aab7b3 | ||
|
|
25c59cd5dd | ||
|
|
9825239e43 | ||
|
|
fb69f245da | ||
|
|
7ef8dddc2a | ||
|
|
2abcae84b1 | ||
|
|
b4beb6c182 | ||
|
|
786d14663b | ||
|
|
f8269e69c4 | ||
|
|
29274d0acf | ||
|
|
d6b925f171 | ||
|
|
f1f18d1823 | ||
|
|
03ff2147db | ||
|
|
c66a72806d | ||
|
|
e89f2cbac0 | ||
|
|
d831530c50 | ||
|
|
9fe18c2af8 | ||
|
|
fe4ff7ac0f | ||
|
|
a8ca3d8188 | ||
|
|
3b9867c537 | ||
|
|
01d22c26f4 | ||
|
|
e8f7fe5a95 | ||
|
|
bd0b8fbc65 | ||
|
|
05e20b4e92 | ||
|
|
716d58ad4b | ||
|
|
ca12ad529a | ||
|
|
6eea82706d | ||
|
|
d69d005ce0 | ||
|
|
b98b322dfe | ||
|
|
e73e72d150 | ||
|
|
8cabc244f7 | ||
|
|
4f04e5cc13 | ||
|
|
bcf9d2585d | ||
|
|
e03b07f940 | ||
|
|
a45c6aa37e | ||
|
|
dd672945f2 | ||
|
|
e634be4273 | ||
|
|
9acf5bee41 | ||
|
|
1e3297ab64 | ||
|
|
58df290c8e | ||
|
|
e2075886b1 | ||
|
|
ad53abc75a | ||
|
|
a599c318dd | ||
|
|
14e2a0c5e2 | ||
|
|
2ae3efc12e | ||
|
|
fb18134c12 | ||
|
|
2215a101a3 | ||
|
|
4df2fe7ac5 | ||
|
|
c24369d1ec | ||
|
|
41eb86029a | ||
|
|
357026ce66 | ||
|
|
9b558cb069 | ||
|
|
303020ca75 | ||
|
|
b900abcc71 | ||
|
|
c4ba6df6e9 | ||
|
|
cc4a507799 | ||
|
|
d8de8ec696 | ||
|
|
e6563814e8 | ||
|
|
016d51669f | ||
|
|
f19828b2ec | ||
|
|
36fc87c2a1 | ||
|
|
4322bddabf | ||
|
|
c128a9d4ba | ||
|
|
2feeffc95c | ||
|
|
53de238a7e | ||
|
|
c207e74369 | ||
|
|
04ca02a77a | ||
|
|
6ff89c71b6 | ||
|
|
d7c6a8e53e | ||
|
|
150741a443 | ||
|
|
460f322c44 | ||
|
|
ef5d35fe38 | ||
|
|
16044556b5 | ||
|
|
81d5079468 | ||
|
|
edc4b22cbc | ||
|
|
c01dfd4740 | ||
|
|
53a4a46d1f | ||
|
|
d61e7e7102 | ||
|
|
17f4df9293 | ||
|
|
24071582bb | ||
|
|
5754466a0d | ||
|
|
a18eda92b7 | ||
|
|
11d0a8f2fe | ||
|
|
2b8b386882 | ||
|
|
45a5027451 | ||
|
|
2cb72f55f3 | ||
|
|
fa27fbab46 | ||
|
|
87821fe287 | ||
|
|
cee4bcd867 | ||
|
|
b9cc4c18a8 | ||
|
|
4577e61940 | ||
|
|
9ac6147a98 | ||
|
|
74d4ea8a78 | ||
|
|
e2f4c7f872 | ||
|
|
07db8e5a94 | ||
|
|
ed7fb03b9c | ||
|
|
f0ebc3e6a0 | ||
|
|
f2570b4cef | ||
|
|
97e1939021 | ||
|
|
bebb894f3e | ||
|
|
288c533c91 | ||
|
|
6891f9a5d5 | ||
|
|
37a62eed6b | ||
|
|
3ee6b0e58d | ||
|
|
7e6f772345 | ||
|
|
ef28173b65 | ||
|
|
a26614c6b6 | ||
|
|
ee00293e48 | ||
|
|
ce977387e6 | ||
|
|
8cc45dbbd8 | ||
|
|
851a4c104c | ||
| 45ddf3fded | |||
|
|
cb538f4026 | ||
|
|
6bd6db3c16 | ||
|
|
6af3940ffb | ||
|
|
66c864c8d7 | ||
|
|
15354dd8e8 | ||
|
|
215070fe3f | ||
|
|
ed73883e80 | ||
|
|
df85ebc0aa | ||
|
|
885a6af943 | ||
|
|
94820d4782 | ||
|
|
7f044e5ac3 | ||
|
|
1284f23620 | ||
|
|
bdcc8acdc4 | ||
|
|
73a9dfcf43 | ||
|
|
7a277ce283 | ||
|
|
f8b3f9dd30 | ||
|
|
840f3ea96c | ||
|
|
51929434be | ||
|
|
3ec480afa4 | ||
|
|
3d19e9e444 | ||
|
|
6d987791f7 | ||
|
|
7b7da00c22 | ||
|
|
34791bd892 | ||
|
|
e6bcd1be72 | ||
|
|
4cac354983 | ||
|
|
042f7f77a9 | ||
|
|
5fbb1dd0cd | ||
|
|
bb14dfc00e | ||
|
|
f83cc4ccfa | ||
|
|
d0d6835a5d | ||
|
|
104bc8fc55 | ||
|
|
057dd867a8 | ||
|
|
9eed8f5095 | ||
|
|
1f62be9773 | ||
|
|
7a46f92059 | ||
|
|
cfa79b9676 | ||
|
|
c0a63fa15b | ||
|
|
c61537ae16 | ||
|
|
3871095b92 | ||
|
|
dee846da49 | ||
|
|
2477553d13 | ||
|
|
c9df7d7f8e | ||
|
|
53cb093f9e | ||
|
|
28e86970dc | ||
|
|
f847fc1669 | ||
|
|
f3df55177a | ||
|
|
be6f345127 |
40
.github/workflows/maven-publish.yml
vendored
40
.github/workflows/maven-publish.yml
vendored
@@ -81,7 +81,7 @@ jobs:
|
|||||||
export _JAVA_OPTIONS="-Xmx2g"
|
export _JAVA_OPTIONS="-Xmx2g"
|
||||||
d=$(date +%m.%d)
|
d=$(date +%m.%d)
|
||||||
# build only desktop and only try to move desktop files
|
# build only desktop and only try to move desktop files
|
||||||
mvn -U -B clean -P windows-linux install -e -T 1C release:clean release:prepare release:perform -DskipTests
|
mvn -U -B clean -P windows-linux install -DskipTests -Dskip.flatten=true -e -T 1C release:clean release:prepare release:perform
|
||||||
mkdir izpack
|
mkdir izpack
|
||||||
# move bz2 and jar from work dir to izpack dir
|
# move bz2 and jar from work dir to izpack dir
|
||||||
mv /home/runner/work/forge/forge/forge-installer/*/*.{bz2,jar} izpack/
|
mv /home/runner/work/forge/forge/forge-installer/*/*.{bz2,jar} izpack/
|
||||||
@@ -128,6 +128,44 @@ jobs:
|
|||||||
removeArtifacts: true
|
removeArtifacts: true
|
||||||
makeLatest: true
|
makeLatest: true
|
||||||
|
|
||||||
|
- name: 🔧 Install XML tools
|
||||||
|
run: sudo apt-get install -y libxml2-utils
|
||||||
|
|
||||||
|
- name: 🔼 Bump versionCode in root POM
|
||||||
|
id: bump_version
|
||||||
|
run: |
|
||||||
|
cd /home/runner/work/forge/forge/
|
||||||
|
|
||||||
|
current_version=$(xmllint --xpath "//*[local-name()='versionCode']/text()" pom.xml)
|
||||||
|
echo "Current versionCode: $current_version"
|
||||||
|
|
||||||
|
IFS='.' read -r major minor patch <<< "${current_version}"
|
||||||
|
new_patch=$(printf "%02d" $((10#$patch + 1)))
|
||||||
|
new_version="${major}.${minor}.${new_patch}"
|
||||||
|
|
||||||
|
sed -i -E "s|<versionCode>.*</versionCode>|<versionCode>${new_version}</versionCode>|" pom.xml
|
||||||
|
|
||||||
|
echo "version_code=${new_version}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: ♻️ Restore {revision} in child POMs
|
||||||
|
run: |
|
||||||
|
find . -name pom.xml ! -path "./pom.xml" | while read -r pom; do
|
||||||
|
sed -i -E 's|<version>2\.0+\.[0-9]+(-SNAPSHOT)?</version>|<version>${revision}</version>|' "$pom"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: 💾 Commit restored {revision}
|
||||||
|
run: |
|
||||||
|
# Add only pom.xml files
|
||||||
|
find . -name pom.xml -exec git add {} \;
|
||||||
|
|
||||||
|
# Commit if there are changes
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "No pom.xml changes to commit."
|
||||||
|
else
|
||||||
|
git commit -m "Restore POM files for preparation of next release" || echo "No changes to commit"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Send failure notification to Discord
|
- name: Send failure notification to Discord
|
||||||
if: failure() # This step runs only if the job fails
|
if: failure() # This step runs only if the job fails
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Dev instructions here: [Getting Started](https://github.com/Card-Forge/forge/wik
|
|||||||
|
|
||||||
## Requirements / Tools
|
## Requirements / Tools
|
||||||
|
|
||||||
- you favourite Java IDE (IntelliJ, Eclipse, VSCodium, Emacs, Vi...)
|
- your favourite Java IDE (IntelliJ, Eclipse, VSCodium, Emacs, Vi...)
|
||||||
- Java JDK 17 or later
|
- Java JDK 17 or later
|
||||||
- Git
|
- Git
|
||||||
- Git client (optional)
|
- Git client (optional)
|
||||||
@@ -28,7 +28,6 @@ Dev instructions here: [Getting Started](https://github.com/Card-Forge/forge/wik
|
|||||||
|
|
||||||
IntelliJ is the recommended IDE for Forge development. Quick start guide for [setting up the Forge project within IntelliJ](https://github.com/Card-Forge/forge/wiki/IntelliJ-setup).
|
IntelliJ is the recommended IDE for Forge development. Quick start guide for [setting up the Forge project within IntelliJ](https://github.com/Card-Forge/forge/wiki/IntelliJ-setup).
|
||||||
|
|
||||||
|
|
||||||
## Eclipse
|
## Eclipse
|
||||||
|
|
||||||
Eclipse includes Maven integration so a separate install is not necessary. For other IDEs, your mileage may vary.
|
Eclipse includes Maven integration so a separate install is not necessary. For other IDEs, your mileage may vary.
|
||||||
@@ -124,10 +123,11 @@ TBD
|
|||||||
|
|
||||||
SNAPSHOT builds can be built via the Maven integration in Eclipse.
|
SNAPSHOT builds can be built via the Maven integration in Eclipse.
|
||||||
|
|
||||||
1) Create a Maven build for the forge top-level project. Right-click on the forge project. Run as.. > Maven build...
|
1. Create a Maven build for the forge top-level project. Right-click on the forge project. Run as.. > Maven build...
|
||||||
|
|
||||||
- On the Main tab, set Goals: clean install, set Profiles: windows-linux
|
- On the Main tab, set Goals: clean install, set Profiles: windows-linux
|
||||||
|
|
||||||
2) Run forge Maven build. If everything built, you should see "BUILD SUCCESS" in the Console View.
|
2. Run forge Maven build. If everything built, you should see "BUILD SUCCESS" in the Console View.
|
||||||
|
|
||||||
The resulting snapshot will be found at: forge-gui-desktop/target/forge-gui-desktop-[version]-SNAPSHOT
|
The resulting snapshot will be found at: forge-gui-desktop/target/forge-gui-desktop-[version]-SNAPSHOT
|
||||||
|
|
||||||
@@ -158,13 +158,19 @@ The platform-specific projects are:
|
|||||||
|
|
||||||
#### forge-ai
|
#### forge-ai
|
||||||
|
|
||||||
|
The forge-ai project contains the computer opponent logic for gameplay. It includes decision-making algorithms for specific abilities, cards and turn phases.
|
||||||
|
|
||||||
#### forge-core
|
#### forge-core
|
||||||
|
|
||||||
|
The forge-core project contains the core game engine, card mechanics, rules engine, and fundamental game logic. It includes the implementation of Magic: The Gathering rules, card interactions, and the game state management system.
|
||||||
|
|
||||||
#### forge-game
|
#### forge-game
|
||||||
|
|
||||||
|
The forge-game project handles the game session management, player interactions, and game flow control. It includes implementations for multiplayer support, game modes, matchmaking, and game state persistence. This module bridges the core game engine with the user interface and networking components.
|
||||||
|
|
||||||
#### forge-gui
|
#### forge-gui
|
||||||
|
|
||||||
The forge-gui project includes the scripting resource definitions in the res/ path.
|
The forge-gui project contains the user interface components and rendering logic for the game. It includes the main game window, card displays, player interactions, and the scripting resource definitions in the res/ path.
|
||||||
|
|
||||||
#### forge-gui-android
|
#### forge-gui-android
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ Join the **Forge community** on [Discord](https://discord.gg/HcPJNyD66a)!
|
|||||||
4. **Java Requirement:** Ensure you have **Java 17 or later** installed.
|
4. **Java Requirement:** Ensure you have **Java 17 or later** installed.
|
||||||
|
|
||||||
### 📱 Android Installation
|
### 📱 Android Installation
|
||||||
|
- _(Note: **Android 11** is the minimum requirements with at least **6GB RAM** to run smoothly. You need to enable **"Install unknown apps"** for Forge to initialize and update itself)_
|
||||||
- Download the **APK** from the [Snapshot Build](https://github.com/Card-Forge/forge/releases/tag/daily-snapshots). On the first launch, Forge will automatically download all necessary assets.
|
- Download the **APK** from the [Snapshot Build](https://github.com/Card-Forge/forge/releases/tag/daily-snapshots). On the first launch, Forge will automatically download all necessary assets.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -359,18 +359,28 @@ public class SpecialCardAi {
|
|||||||
private static final int demonSacThreshold = Integer.MAX_VALUE; // if we're in dire conditions, sac everything from worst to best hoping to find an answer
|
private static final int demonSacThreshold = Integer.MAX_VALUE; // if we're in dire conditions, sac everything from worst to best hoping to find an answer
|
||||||
|
|
||||||
public static boolean considerSacrificingCreature(final Player ai, final SpellAbility sa) {
|
public static boolean considerSacrificingCreature(final Player ai, final SpellAbility sa) {
|
||||||
|
Card c = sa.getHostCard();
|
||||||
|
|
||||||
|
// Only check for sacrifice if it's the owner's turn, and it can attack.
|
||||||
|
// TODO: Maybe check if sacrificing a creature allows AI to kill the opponent with the rest on their turn?
|
||||||
|
if (!CombatUtil.canAttack(c) ||
|
||||||
|
!ai.getGame().getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CardCollection flyingCreatures = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
|
CardCollection flyingCreatures = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
|
||||||
CardPredicates.UNTAPPED.and(
|
CardPredicates.UNTAPPED.and(
|
||||||
CardPredicates.hasKeyword(Keyword.FLYING).or(CardPredicates.hasKeyword(Keyword.REACH))));
|
CardPredicates.hasKeyword(Keyword.FLYING).or(CardPredicates.hasKeyword(Keyword.REACH))));
|
||||||
boolean hasUsefulBlocker = false;
|
boolean hasUsefulBlocker = false;
|
||||||
|
|
||||||
for (Card c : flyingCreatures) {
|
for (Card fc : flyingCreatures) {
|
||||||
if (!ComputerUtilCard.isUselessCreature(ai, c)) {
|
if (!ComputerUtilCard.isUselessCreature(ai, fc)) {
|
||||||
hasUsefulBlocker = true;
|
hasUsefulBlocker = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ai.getLife() <= sa.getHostCard().getNetPower() && !hasUsefulBlocker;
|
return ai.getLife() <= c.getNetPower() && !hasUsefulBlocker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getSacThreshold() {
|
public static int getSacThreshold() {
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ public final class ImageKeys {
|
|||||||
public static final String RADIATION_IMAGE = "radiation";
|
public static final String RADIATION_IMAGE = "radiation";
|
||||||
|
|
||||||
public static final String BACKFACE_POSTFIX = "$alt";
|
public static final String BACKFACE_POSTFIX = "$alt";
|
||||||
|
public static final String SPECFACE_W = "$wspec";
|
||||||
|
public static final String SPECFACE_U = "$uspec";
|
||||||
|
public static final String SPECFACE_B = "$bspec";
|
||||||
|
public static final String SPECFACE_R = "$rspec";
|
||||||
|
public static final String SPECFACE_G = "$gspec";
|
||||||
|
|
||||||
private static String CACHE_CARD_PICS_DIR, CACHE_TOKEN_PICS_DIR, CACHE_ICON_PICS_DIR, CACHE_BOOSTER_PICS_DIR,
|
private static String CACHE_CARD_PICS_DIR, CACHE_TOKEN_PICS_DIR, CACHE_ICON_PICS_DIR, CACHE_BOOSTER_PICS_DIR,
|
||||||
CACHE_FATPACK_PICS_DIR, CACHE_BOOSTERBOX_PICS_DIR, CACHE_PRECON_PICS_DIR, CACHE_TOURNAMENTPACK_PICS_DIR;
|
CACHE_FATPACK_PICS_DIR, CACHE_BOOSTERBOX_PICS_DIR, CACHE_PRECON_PICS_DIR, CACHE_TOURNAMENTPACK_PICS_DIR;
|
||||||
@@ -92,28 +97,13 @@ public final class ImageKeys {
|
|||||||
return cachedCards.get(key);
|
return cachedCards.get(key);
|
||||||
}
|
}
|
||||||
public static File getImageFile(String key) {
|
public static File getImageFile(String key) {
|
||||||
return getImageFile(key, false);
|
|
||||||
}
|
|
||||||
public static File getImageFile(String key, boolean artCrop) {
|
|
||||||
if (StringUtils.isEmpty(key))
|
if (StringUtils.isEmpty(key))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
final String dir;
|
final String dir;
|
||||||
final String filename;
|
final String filename;
|
||||||
String[] tempdata = null;
|
String[] tempdata = null;
|
||||||
if (key.startsWith(ImageKeys.CARD_PREFIX)) {
|
if (key.startsWith(ImageKeys.TOKEN_PREFIX)) {
|
||||||
tempdata = key.substring(ImageKeys.CARD_PREFIX.length()).split("\\|");
|
|
||||||
String tokenname = tempdata[0];
|
|
||||||
if (tempdata.length > 1) {
|
|
||||||
tokenname += "_" + tempdata[1];
|
|
||||||
}
|
|
||||||
if (tempdata.length > 2) {
|
|
||||||
tokenname += "_" + tempdata[2];
|
|
||||||
}
|
|
||||||
filename = tokenname ;
|
|
||||||
|
|
||||||
dir = CACHE_CARD_PICS_DIR;
|
|
||||||
} else if (key.startsWith(ImageKeys.TOKEN_PREFIX)) {
|
|
||||||
tempdata = key.substring(ImageKeys.TOKEN_PREFIX.length()).split("\\|");
|
tempdata = key.substring(ImageKeys.TOKEN_PREFIX.length()).split("\\|");
|
||||||
String tokenname = tempdata[0];
|
String tokenname = tempdata[0];
|
||||||
if (tempdata.length > 1) {
|
if (tempdata.length > 1) {
|
||||||
@@ -164,31 +154,7 @@ public final class ImageKeys {
|
|||||||
cachedCards.put(filename, file);
|
cachedCards.put(filename, file);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
if (tempdata != null && dir.equals(CACHE_CARD_PICS_DIR)) {
|
if (dir.equals(CACHE_TOKEN_PICS_DIR)) {
|
||||||
String setlessFilename = tempdata[0] + (artCrop ? ".artcrop" : ".fullborder");
|
|
||||||
String setCode = tempdata.length > 1 ? tempdata[1] : "";
|
|
||||||
String collectorNumber = tempdata.length > 2 ? tempdata[2] : "";
|
|
||||||
if (!setCode.isEmpty()) {
|
|
||||||
if (!collectorNumber.isEmpty()) {
|
|
||||||
file = findFile(dir, setCode + "/" + collectorNumber + "_" + setlessFilename);
|
|
||||||
if (file != null) {
|
|
||||||
cachedCards.put(filename, file);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file = findFile(dir, setCode + "/" + setlessFilename);
|
|
||||||
if (file != null) {
|
|
||||||
cachedCards.put(filename, file);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file = findFile(dir, setlessFilename);
|
|
||||||
if (file != null) {
|
|
||||||
cachedCards.put(filename, file);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tempdata != null && dir.equals(CACHE_TOKEN_PICS_DIR)) {
|
|
||||||
String setlessFilename = tempdata[0];
|
String setlessFilename = tempdata[0];
|
||||||
String setCode = tempdata.length > 1 ? tempdata[1] : "";
|
String setCode = tempdata.length > 1 ? tempdata[1] : "";
|
||||||
String collectorNumber = tempdata.length > 2 ? tempdata[2] : "";
|
String collectorNumber = tempdata.length > 2 ? tempdata[2] : "";
|
||||||
|
|||||||
@@ -433,17 +433,6 @@ public final class CardEdition implements Comparable<CardEdition> {
|
|||||||
|
|
||||||
public Multimap<String, EditionEntry> getTokens() { return tokenMap; }
|
public Multimap<String, EditionEntry> getTokens() { return tokenMap; }
|
||||||
|
|
||||||
public EditionEntry getTokenFromCollectorNumber(String collectorNumber) {
|
|
||||||
if(collectorNumber == null || collectorNumber.isEmpty())
|
|
||||||
return null;
|
|
||||||
for(EditionEntry c : this.tokenMap.values()) {
|
|
||||||
//Could build a map for this one too if it's used for more than one-offs.
|
|
||||||
if (c.collectorNumber.equalsIgnoreCase(collectorNumber))
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTokenSet(String token) {
|
public String getTokenSet(String token) {
|
||||||
if (tokenMap.containsKey(token)) {
|
if (tokenMap.containsKey(token)) {
|
||||||
return this.getCode();
|
return this.getCode();
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ package forge.card;
|
|||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import forge.StaticData;
|
|
||||||
import forge.card.mana.IParserManaCost;
|
import forge.card.mana.IParserManaCost;
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.card.mana.ManaCostShard;
|
import forge.card.mana.ManaCostShard;
|
||||||
@@ -151,10 +149,6 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
return splitType;
|
return splitType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBackSide() {
|
|
||||||
return CardSplitType.DUAL_FACED_CARDS.contains(splitType) || splitType == CardSplitType.Flip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICardFace getMainPart() {
|
public ICardFace getMainPart() {
|
||||||
return mainPart;
|
return mainPart;
|
||||||
}
|
}
|
||||||
@@ -171,32 +165,20 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
return Iterables.concat(Arrays.asList(mainPart, otherPart), specializedParts.values());
|
return Iterables.concat(Arrays.asList(mainPart, otherPart), specializedParts.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getImageName(CardStateName state) {
|
public ICardFace getWSpecialize() {
|
||||||
if (splitType == CardSplitType.Split) {
|
return specializedParts.get(CardStateName.SpecializeW);
|
||||||
return mainPart.getName() + otherPart.getName();
|
|
||||||
} else if (state.equals(splitType.getChangedStateName())) {
|
|
||||||
if (otherPart != null) {
|
|
||||||
return otherPart.getName();
|
|
||||||
} else if (this.hasBackSide()) {
|
|
||||||
if (!getMeldWith().isEmpty()) {
|
|
||||||
final CardDb db = StaticData.instance().getCommonCards();
|
|
||||||
return db.getRules(getMeldWith()).getOtherPart().getName();
|
|
||||||
}
|
}
|
||||||
return null;
|
public ICardFace getUSpecialize() {
|
||||||
|
return specializedParts.get(CardStateName.SpecializeU);
|
||||||
}
|
}
|
||||||
|
public ICardFace getBSpecialize() {
|
||||||
|
return specializedParts.get(CardStateName.SpecializeB);
|
||||||
}
|
}
|
||||||
|
public ICardFace getRSpecialize() {
|
||||||
switch (state) {
|
return specializedParts.get(CardStateName.SpecializeR);
|
||||||
case SpecializeW:
|
|
||||||
case SpecializeU:
|
|
||||||
case SpecializeB:
|
|
||||||
case SpecializeR:
|
|
||||||
case SpecializeG:
|
|
||||||
ICardFace face = specializedParts.get(state);
|
|
||||||
return face != null ? face.getName() : null;
|
|
||||||
default:
|
|
||||||
return getName();
|
|
||||||
}
|
}
|
||||||
|
public ICardFace getGSpecialize() {
|
||||||
|
return specializedParts.get(CardStateName.SpecializeG);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -303,7 +285,10 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
CardType type = mainPart.getType();
|
CardType type = mainPart.getType();
|
||||||
if (type.isLegendary() && canBeCreature()) {
|
if (!type.isLegendary()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (canBeCreature() || type.isVehicle() || type.isSpacecraft()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -529,6 +529,9 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
|||||||
return hasSubtype("Contraption");
|
return hasSubtype("Contraption");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isVehicle() { return hasSubtype("Vehicle"); }
|
||||||
|
public boolean isSpacecraft() { return hasSubtype("Spacecraft"); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSaga() {
|
public boolean isSaga() {
|
||||||
return hasSubtype("Saga");
|
return hasSubtype("Saga");
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import forge.util.CardTranslation;
|
|||||||
import forge.util.ImageUtil;
|
import forge.util.ImageUtil;
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -346,13 +347,34 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
if (pc == null) {
|
if (pc == null) {
|
||||||
pc = StaticData.instance().getVariantCards().getCard(name, edition, artIndex);
|
pc = StaticData.instance().getVariantCards().getCard(name, edition, artIndex);
|
||||||
if (pc == null) {
|
if (pc == null) {
|
||||||
throw new IOException(TextUtil.concatWithSpace("Card", name, "not found"));
|
System.out.println("PaperCard: " + name + " not found with set and index " + edition + ", " + artIndex);
|
||||||
|
pc = readObjectAlternate(name, edition);
|
||||||
|
if (pc == null) {
|
||||||
|
throw new IOException(TextUtil.concatWithSpace("Card", name, "not found with set and index", edition, Integer.toString(artIndex)));
|
||||||
|
}
|
||||||
|
System.out.println("Alternate object found: " + pc.getName() + ", " + pc.getEdition() + ", " + pc.getArtIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rules = pc.getRules();
|
rules = pc.getRules();
|
||||||
rarity = pc.getRarity();
|
rarity = pc.getRarity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IPaperCard readObjectAlternate(String name, String edition) throws ClassNotFoundException, IOException {
|
||||||
|
IPaperCard pc = StaticData.instance().getCommonCards().getCard(name, edition);
|
||||||
|
if (pc == null) {
|
||||||
|
pc = StaticData.instance().getVariantCards().getCard(name, edition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc == null) {
|
||||||
|
pc = StaticData.instance().getCommonCards().getCard(name);
|
||||||
|
if (pc == null) {
|
||||||
|
pc = StaticData.instance().getVariantCards().getCard(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private Object readResolve() throws ObjectStreamException {
|
private Object readResolve() throws ObjectStreamException {
|
||||||
//If we deserialize an old PaperCard with no flags, reinitialize as a fresh copy to set default flags.
|
//If we deserialize an old PaperCard with no flags, reinitialize as a fresh copy to set default flags.
|
||||||
@@ -363,14 +385,20 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getImageKey(boolean altState) {
|
public String getImageKey(boolean altState) {
|
||||||
return altState ? this.getCardAltImageKey() : this.getCardImageKey();
|
String normalizedName = StringUtils.stripAccents(name);
|
||||||
|
String imageKey = ImageKeys.CARD_PREFIX + normalizedName + CardDb.NameSetSeparator
|
||||||
|
+ edition + CardDb.NameSetSeparator + artIndex;
|
||||||
|
if (altState) {
|
||||||
|
imageKey += ImageKeys.BACKFACE_POSTFIX;
|
||||||
|
}
|
||||||
|
return imageKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String cardImageKey = null;
|
private String cardImageKey = null;
|
||||||
@Override
|
@Override
|
||||||
public String getCardImageKey() {
|
public String getCardImageKey() {
|
||||||
if (this.cardImageKey == null)
|
if (this.cardImageKey == null)
|
||||||
this.cardImageKey = ImageUtil.getImageKey(this, CardStateName.Original);
|
this.cardImageKey = ImageUtil.getImageKey(this, "", true);
|
||||||
return cardImageKey;
|
return cardImageKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,9 +407,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
public String getCardAltImageKey() {
|
public String getCardAltImageKey() {
|
||||||
if (this.cardAltImageKey == null){
|
if (this.cardAltImageKey == null){
|
||||||
if (this.hasBackFace())
|
if (this.hasBackFace())
|
||||||
this.cardAltImageKey = ImageUtil.getImageKey(this, this.getRules().getSplitType().getChangedStateName());
|
this.cardAltImageKey = ImageUtil.getImageKey(this, "back", true);
|
||||||
else // altImageKey will be the same as cardImageKey
|
else // altImageKey will be the same as cardImageKey
|
||||||
this.cardAltImageKey = getCardImageKey();
|
this.cardAltImageKey = ImageUtil.getImageKey(this, "", true);
|
||||||
}
|
}
|
||||||
return cardAltImageKey;
|
return cardAltImageKey;
|
||||||
}
|
}
|
||||||
@@ -391,9 +419,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
public String getCardWSpecImageKey() {
|
public String getCardWSpecImageKey() {
|
||||||
if (this.cardWSpecImageKey == null) {
|
if (this.cardWSpecImageKey == null) {
|
||||||
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
||||||
this.cardWSpecImageKey = ImageUtil.getImageKey(this, CardStateName.SpecializeW);
|
this.cardWSpecImageKey = ImageUtil.getImageKey(this, "white", true);
|
||||||
else // just use cardImageKey
|
else // just use cardImageKey
|
||||||
this.cardWSpecImageKey = getCardImageKey();
|
this.cardWSpecImageKey = ImageUtil.getImageKey(this, "", true);
|
||||||
}
|
}
|
||||||
return cardWSpecImageKey;
|
return cardWSpecImageKey;
|
||||||
}
|
}
|
||||||
@@ -403,9 +431,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
public String getCardUSpecImageKey() {
|
public String getCardUSpecImageKey() {
|
||||||
if (this.cardUSpecImageKey == null) {
|
if (this.cardUSpecImageKey == null) {
|
||||||
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
||||||
this.cardUSpecImageKey = ImageUtil.getImageKey(this, CardStateName.SpecializeU);
|
this.cardUSpecImageKey = ImageUtil.getImageKey(this, "blue", true);
|
||||||
else // just use cardImageKey
|
else // just use cardImageKey
|
||||||
this.cardUSpecImageKey = getCardImageKey();
|
this.cardUSpecImageKey = ImageUtil.getImageKey(this, "", true);
|
||||||
}
|
}
|
||||||
return cardUSpecImageKey;
|
return cardUSpecImageKey;
|
||||||
}
|
}
|
||||||
@@ -415,9 +443,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
public String getCardBSpecImageKey() {
|
public String getCardBSpecImageKey() {
|
||||||
if (this.cardBSpecImageKey == null) {
|
if (this.cardBSpecImageKey == null) {
|
||||||
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
||||||
this.cardBSpecImageKey = ImageUtil.getImageKey(this, CardStateName.SpecializeB);
|
this.cardBSpecImageKey = ImageUtil.getImageKey(this, "black", true);
|
||||||
else // just use cardImageKey
|
else // just use cardImageKey
|
||||||
this.cardBSpecImageKey = getCardImageKey();
|
this.cardBSpecImageKey = ImageUtil.getImageKey(this, "", true);
|
||||||
}
|
}
|
||||||
return cardBSpecImageKey;
|
return cardBSpecImageKey;
|
||||||
}
|
}
|
||||||
@@ -427,9 +455,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
public String getCardRSpecImageKey() {
|
public String getCardRSpecImageKey() {
|
||||||
if (this.cardRSpecImageKey == null) {
|
if (this.cardRSpecImageKey == null) {
|
||||||
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
||||||
this.cardRSpecImageKey = ImageUtil.getImageKey(this, CardStateName.SpecializeR);
|
this.cardRSpecImageKey = ImageUtil.getImageKey(this, "red", true);
|
||||||
else // just use cardImageKey
|
else // just use cardImageKey
|
||||||
this.cardRSpecImageKey = getCardImageKey();
|
this.cardRSpecImageKey = ImageUtil.getImageKey(this, "", true);
|
||||||
}
|
}
|
||||||
return cardRSpecImageKey;
|
return cardRSpecImageKey;
|
||||||
}
|
}
|
||||||
@@ -439,16 +467,18 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
|||||||
public String getCardGSpecImageKey() {
|
public String getCardGSpecImageKey() {
|
||||||
if (this.cardGSpecImageKey == null) {
|
if (this.cardGSpecImageKey == null) {
|
||||||
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
if (this.rules.getSplitType() == CardSplitType.Specialize)
|
||||||
this.cardGSpecImageKey = ImageUtil.getImageKey(this, CardStateName.SpecializeG);
|
this.cardGSpecImageKey = ImageUtil.getImageKey(this, "green", true);
|
||||||
else // just use cardImageKey
|
else // just use cardImageKey
|
||||||
this.cardGSpecImageKey = getCardImageKey();
|
this.cardGSpecImageKey = ImageUtil.getImageKey(this, "", true);
|
||||||
}
|
}
|
||||||
return cardGSpecImageKey;
|
return cardGSpecImageKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasBackFace(){
|
public boolean hasBackFace(){
|
||||||
return this.rules.hasBackSide();
|
CardSplitType cst = this.rules.getSplitType();
|
||||||
|
return cst == CardSplitType.Transform || cst == CardSplitType.Flip || cst == CardSplitType.Meld
|
||||||
|
|| cst == CardSplitType.Modal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -401,24 +401,31 @@ public class BoosterGenerator {
|
|||||||
System.out.println(numCards + " of type " + slotType);
|
System.out.println(numCards + " of type " + slotType);
|
||||||
|
|
||||||
// For cards that end in '+', attempt to convert this card to foil.
|
// For cards that end in '+', attempt to convert this card to foil.
|
||||||
boolean convertCardFoil = slotType.endsWith("+");
|
boolean convertAllToFoil = slotType.endsWith("+");
|
||||||
if (convertCardFoil) {
|
if (convertAllToFoil) {
|
||||||
slotType = slotType.substring(0, slotType.length() - 1);
|
slotType = slotType.substring(0, slotType.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack Base
|
|
||||||
BoosterSlot boosterSlot = boosterSlots.get(slotType);
|
BoosterSlot boosterSlot = boosterSlots.get(slotType);
|
||||||
String determineSheet = boosterSlot.replaceSlot();
|
Map<String, Integer> slotReplacementCount = bulkSlotReplacement(boosterSlot, numCards);
|
||||||
|
|
||||||
|
List<PaperCard> paperCards = Lists.newArrayList();
|
||||||
|
for(Map.Entry<String, Integer> entry : slotReplacementCount.entrySet()) {
|
||||||
|
String determineSheet = entry.getKey();
|
||||||
|
int numCardsToGenerate = entry.getValue();
|
||||||
|
|
||||||
|
if (determineSheet == null || determineSheet.isEmpty() || numCardsToGenerate == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the sheet ends with a '+', convert all cards in replacement section to foil
|
||||||
|
boolean convertThisToFoil = false;
|
||||||
if (determineSheet.endsWith("+")) {
|
if (determineSheet.endsWith("+")) {
|
||||||
determineSheet = determineSheet.substring(0, determineSheet.length() - 1);
|
determineSheet = determineSheet.substring(0, determineSheet.length() - 1);
|
||||||
convertCardFoil = true;
|
convertThisToFoil = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String setCode = template.getEdition();
|
String setCode = template.getEdition();
|
||||||
|
|
||||||
// Ok, so we have a sheet now. Most should be standard sheets, but some named edition sheets
|
|
||||||
List<PaperCard> paperCards;
|
|
||||||
PrintSheet ps;
|
PrintSheet ps;
|
||||||
try {
|
try {
|
||||||
// Apply the edition to the sheet name by default. We'll try again if thats not a real sheet
|
// Apply the edition to the sheet name by default. We'll try again if thats not a real sheet
|
||||||
@@ -426,21 +433,36 @@ public class BoosterGenerator {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ps = getPrintSheet(determineSheet);
|
ps = getPrintSheet(determineSheet);
|
||||||
}
|
}
|
||||||
if (convertCardFoil) {
|
if (convertAllToFoil || convertThisToFoil) {
|
||||||
paperCards = Lists.newArrayList();
|
for (PaperCard pc : ps.random(numCardsToGenerate, true)) {
|
||||||
for(PaperCard pc : ps.random(numCards, true)) {
|
|
||||||
paperCards.add(pc.getFoiled());
|
paperCards.add(pc.getFoiled());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
paperCards = ps.random(numCards, true);
|
paperCards.addAll(ps.random(numCardsToGenerate, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.addAll(paperCards);
|
result.addAll(paperCards);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<String, Integer> bulkSlotReplacement(BoosterSlot boosterSlot, int numCards) {
|
||||||
|
Map<String, Integer> slotReplacementCount = new HashMap<>();
|
||||||
|
|
||||||
|
for(int i = 0; i < numCards; i++) {
|
||||||
|
String determineSheet = boosterSlot.replaceSlot();
|
||||||
|
if (slotReplacementCount.containsKey(determineSheet)) {
|
||||||
|
slotReplacementCount.put(determineSheet, slotReplacementCount.get(determineSheet) + 1);
|
||||||
|
} else {
|
||||||
|
slotReplacementCount.put(determineSheet, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slotReplacementCount;
|
||||||
|
}
|
||||||
|
|
||||||
private static void ensureGuaranteedCardInBooster(List<PaperCard> result, SealedTemplate template, String boosterMustContain) {
|
private static void ensureGuaranteedCardInBooster(List<PaperCard> result, SealedTemplate template, String boosterMustContain) {
|
||||||
// First, see if there's already a card of the given type
|
// First, see if there's already a card of the given type
|
||||||
String[] types = TextUtil.split(boosterMustContain, ' ');
|
String[] types = TextUtil.split(boosterMustContain, ' ');
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ import forge.StaticData;
|
|||||||
import forge.card.CardDb;
|
import forge.card.CardDb;
|
||||||
import forge.card.CardRules;
|
import forge.card.CardRules;
|
||||||
import forge.card.CardSplitType;
|
import forge.card.CardSplitType;
|
||||||
import forge.card.CardStateName;
|
|
||||||
import forge.item.IPaperCard;
|
import forge.item.IPaperCard;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
public class ImageUtil {
|
public class ImageUtil {
|
||||||
public static float getNearestHQSize(float baseSize, float actualSize) {
|
public static float getNearestHQSize(float baseSize, float actualSize) {
|
||||||
//get nearest power of actualSize to baseSize so that the image renders good
|
//get nearest power of actualSize to baseSize so that the image renders good
|
||||||
@@ -25,17 +26,20 @@ public class ImageUtil {
|
|||||||
key = imageKey.substring(ImageKeys.CARD_PREFIX.length());
|
key = imageKey.substring(ImageKeys.CARD_PREFIX.length());
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (key.endsWith(ImageKeys.BACKFACE_POSTFIX)) {
|
|
||||||
key = key.substring(0, key.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key.isEmpty())
|
if (key.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
String[] tempdata = key.split("\\|");
|
CardDb db = StaticData.instance().getCommonCards();
|
||||||
PaperCard cp = StaticData.instance().fetchCard(tempdata[0], tempdata[1], tempdata[2]);
|
PaperCard cp = null;
|
||||||
|
//db shouldn't be null
|
||||||
|
if (db != null) {
|
||||||
|
cp = db.getCard(key);
|
||||||
|
if (cp == null) {
|
||||||
|
db = StaticData.instance().getVariantCards();
|
||||||
|
if (db != null)
|
||||||
|
cp = db.getCard(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (cp == null)
|
if (cp == null)
|
||||||
System.err.println("Can't find PaperCard from key: " + key);
|
System.err.println("Can't find PaperCard from key: " + key);
|
||||||
// return cp regardless if it's null
|
// return cp regardless if it's null
|
||||||
@@ -52,21 +56,6 @@ public class ImageUtil {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getImageRelativePath(String name, String set, String collectorNumber, boolean artChop) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.append(set).append("/");
|
|
||||||
if (!collectorNumber.isEmpty() && !collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)) {
|
|
||||||
sb.append(collectorNumber).append("_");
|
|
||||||
}
|
|
||||||
sb.append(StringUtils.stripAccents(name));
|
|
||||||
|
|
||||||
sb.append(artChop ? ".artcrop" : ".fullborder");
|
|
||||||
sb.append(".jpg");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String getImageRelativePath(PaperCard cp, String face, boolean includeSet, boolean isDownloadUrl) {
|
public static String getImageRelativePath(PaperCard cp, String face, boolean includeSet, boolean isDownloadUrl) {
|
||||||
final String nameToUse = cp == null ? null : getNameToUse(cp, face);
|
final String nameToUse = cp == null ? null : getNameToUse(cp, face);
|
||||||
if (nameToUse == null) {
|
if (nameToUse == null) {
|
||||||
@@ -113,7 +102,7 @@ public class ImageUtil {
|
|||||||
|
|
||||||
if (includeSet) {
|
if (includeSet) {
|
||||||
String editionAliased = isDownloadUrl ? StaticData.instance().getEditions().getCode2ByCode(edition) : ImageKeys.getSetFolder(edition);
|
String editionAliased = isDownloadUrl ? StaticData.instance().getEditions().getCode2ByCode(edition) : ImageKeys.getSetFolder(edition);
|
||||||
if (editionAliased == "") //FIXME: Custom Cards Workaround
|
if (editionAliased.isEmpty()) //FIXME: Custom Cards Workaround
|
||||||
editionAliased = edition;
|
editionAliased = edition;
|
||||||
return TextUtil.concatNoSpace(editionAliased, "/", fname);
|
return TextUtil.concatNoSpace(editionAliased, "/", fname);
|
||||||
} else {
|
} else {
|
||||||
@@ -136,15 +125,25 @@ public class ImageUtil {
|
|||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
} else if (face.equals("white")) {
|
} else if (face.equals("white")) {
|
||||||
return card.getImageName(CardStateName.SpecializeW);
|
if (card.getWSpecialize() != null) {
|
||||||
|
return card.getWSpecialize().getName();
|
||||||
|
}
|
||||||
} else if (face.equals("blue")) {
|
} else if (face.equals("blue")) {
|
||||||
return card.getImageName(CardStateName.SpecializeU);
|
if (card.getUSpecialize() != null) {
|
||||||
|
return card.getUSpecialize().getName();
|
||||||
|
}
|
||||||
} else if (face.equals("black")) {
|
} else if (face.equals("black")) {
|
||||||
return card.getImageName(CardStateName.SpecializeB);
|
if (card.getBSpecialize() != null) {
|
||||||
|
return card.getBSpecialize().getName();
|
||||||
|
}
|
||||||
} else if (face.equals("red")) {
|
} else if (face.equals("red")) {
|
||||||
return card.getImageName(CardStateName.SpecializeR);
|
if (card.getRSpecialize() != null) {
|
||||||
|
return card.getRSpecialize().getName();
|
||||||
|
}
|
||||||
} else if (face.equals("green")) {
|
} else if (face.equals("green")) {
|
||||||
return card.getImageName(CardStateName.SpecializeG);
|
if (card.getGSpecialize() != null) {
|
||||||
|
return card.getGSpecialize().getName();
|
||||||
|
}
|
||||||
} else if (CardSplitType.Split == cp.getRules().getSplitType()) {
|
} else if (CardSplitType.Split == cp.getRules().getSplitType()) {
|
||||||
return card.getMainPart().getName() + card.getOtherPart().getName();
|
return card.getMainPart().getName() + card.getOtherPart().getName();
|
||||||
} else if (!IPaperCard.NO_FUNCTIONAL_VARIANT.equals(cp.getFunctionalVariant())) {
|
} else if (!IPaperCard.NO_FUNCTIONAL_VARIANT.equals(cp.getFunctionalVariant())) {
|
||||||
@@ -153,86 +152,66 @@ public class ImageUtil {
|
|||||||
return cp.getName();
|
return cp.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getNameToUse(PaperCard cp, CardStateName face) {
|
|
||||||
if (!IPaperCard.NO_FUNCTIONAL_VARIANT.equals(cp.getFunctionalVariant())) {
|
|
||||||
return cp.getFunctionalVariant();
|
|
||||||
}
|
|
||||||
final CardRules card = cp.getRules();
|
|
||||||
return card.getImageName(face);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getImageKey(PaperCard cp, String face, boolean includeSet) {
|
public static String getImageKey(PaperCard cp, String face, boolean includeSet) {
|
||||||
return getImageRelativePath(cp, face, includeSet, false);
|
return getImageRelativePath(cp, face, includeSet, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getImageKey(PaperCard cp, CardStateName face) {
|
|
||||||
String name = getNameToUse(cp, face);
|
|
||||||
String number = cp.getCollectorNumber();
|
|
||||||
String suffix = "";
|
|
||||||
switch (face) {
|
|
||||||
case SpecializeB:
|
|
||||||
number += "b";
|
|
||||||
break;
|
|
||||||
case SpecializeG:
|
|
||||||
number += "g";
|
|
||||||
break;
|
|
||||||
case SpecializeR:
|
|
||||||
number += "r";
|
|
||||||
break;
|
|
||||||
case SpecializeU:
|
|
||||||
number += "u";
|
|
||||||
break;
|
|
||||||
case SpecializeW:
|
|
||||||
number += "w";
|
|
||||||
break;
|
|
||||||
case Meld:
|
|
||||||
case Modal:
|
|
||||||
case Secondary:
|
|
||||||
case Transformed:
|
|
||||||
suffix = ImageKeys.BACKFACE_POSTFIX;
|
|
||||||
break;
|
|
||||||
case Flipped:
|
|
||||||
break; // add info to rotate the image?
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
return ImageKeys.CARD_PREFIX + name + CardDb.NameSetSeparator + cp.getEdition()
|
|
||||||
+ CardDb.NameSetSeparator + number + CardDb.NameSetSeparator + cp.getArtIndex() + suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDownloadUrl(PaperCard cp, String face) {
|
public static String getDownloadUrl(PaperCard cp, String face) {
|
||||||
return getImageRelativePath(cp, face, true, true);
|
return getImageRelativePath(cp, face, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getScryfallDownloadUrl(String collectorNumber, String setCode, String langCode, String faceParam, boolean useArtCrop){
|
public static String getScryfallDownloadUrl(PaperCard cp, String face, String setCode, String langCode, boolean useArtCrop){
|
||||||
return getScryfallDownloadUrl(collectorNumber, setCode, langCode, faceParam, useArtCrop, false);
|
return getScryfallDownloadUrl(cp, face, setCode, langCode, useArtCrop, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getScryfallDownloadUrl(String collectorNumber, String setCode, String langCode, String faceParam, boolean useArtCrop, boolean hyphenateAlchemy){
|
public static String getScryfallDownloadUrl(PaperCard cp, String face, String setCode, String langCode, boolean useArtCrop, boolean hyphenateAlchemy){
|
||||||
|
String editionCode;
|
||||||
|
if (setCode != null && !setCode.isEmpty())
|
||||||
|
editionCode = setCode;
|
||||||
|
else
|
||||||
|
editionCode = cp.getEdition().toLowerCase();
|
||||||
|
String cardCollectorNumber = cp.getCollectorNumber();
|
||||||
// Hack to account for variations in Arabian Nights
|
// Hack to account for variations in Arabian Nights
|
||||||
collectorNumber = collectorNumber.replace("+", "†");
|
cardCollectorNumber = cardCollectorNumber.replace("+", "†");
|
||||||
// override old planechase sets from their modified id since scryfall move the planechase cards outside their original setcode
|
// override old planechase sets from their modified id since scryfall move the planechase cards outside their original setcode
|
||||||
if (collectorNumber.startsWith("OHOP")) {
|
if (cardCollectorNumber.startsWith("OHOP")) {
|
||||||
setCode = "ohop";
|
editionCode = "ohop";
|
||||||
collectorNumber = collectorNumber.substring("OHOP".length());
|
cardCollectorNumber = cardCollectorNumber.substring("OHOP".length());
|
||||||
} else if (collectorNumber.startsWith("OPCA")) {
|
} else if (cardCollectorNumber.startsWith("OPCA")) {
|
||||||
setCode = "opca";
|
editionCode = "opca";
|
||||||
collectorNumber = collectorNumber.substring("OPCA".length());
|
cardCollectorNumber = cardCollectorNumber.substring("OPCA".length());
|
||||||
} else if (collectorNumber.startsWith("OPC2")) {
|
} else if (cardCollectorNumber.startsWith("OPC2")) {
|
||||||
setCode = "opc2";
|
editionCode = "opc2";
|
||||||
collectorNumber = collectorNumber.substring("OPC2".length());
|
cardCollectorNumber = cardCollectorNumber.substring("OPC2".length());
|
||||||
} else if (hyphenateAlchemy) {
|
} else if (hyphenateAlchemy) {
|
||||||
if (!collectorNumber.startsWith("A")) {
|
if (!cardCollectorNumber.startsWith("A")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
collectorNumber = collectorNumber.replace("A", "A-");
|
cardCollectorNumber = cardCollectorNumber.replace("A", "A-");
|
||||||
}
|
}
|
||||||
String versionParam = useArtCrop ? "art_crop" : "normal";
|
String versionParam = useArtCrop ? "art_crop" : "normal";
|
||||||
if (!faceParam.isEmpty()) {
|
String faceParam = "";
|
||||||
faceParam = (faceParam.equals("back") ? "&face=back" : "&face=front");
|
if (cp.getRules().getOtherPart() != null) {
|
||||||
|
faceParam = (face.equals("back") ? "&face=back" : "&face=front");
|
||||||
|
} else if (cp.getRules().getSplitType() == CardSplitType.Meld
|
||||||
|
&& !cardCollectorNumber.endsWith("a")
|
||||||
|
&& !cardCollectorNumber.endsWith("b")) {
|
||||||
|
// Only the bottom half of a meld card shares a collector number.
|
||||||
|
// Hanweir Garrison EMN already has a appended.
|
||||||
|
cardCollectorNumber += face.equals("back") ? "b" : "a";
|
||||||
}
|
}
|
||||||
return String.format("%s/%s/%s?format=image&version=%s%s", setCode, collectorNumber,
|
|
||||||
|
String cardCollectorNumberEncoded;
|
||||||
|
try {
|
||||||
|
cardCollectorNumberEncoded = URLEncoder.encode(cardCollectorNumber, "UTF-8");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Unlikely, for the possibility that "UTF-8" is not supported.
|
||||||
|
System.err.println("UTF-8 encoding not supported on this device.");
|
||||||
|
cardCollectorNumberEncoded = cardCollectorNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.format("%s/%s/%s?format=image&version=%s%s", editionCode, cardCollectorNumberEncoded,
|
||||||
langCode, versionParam, faceParam);
|
langCode, versionParam, faceParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,8 @@ public class ForgeScript {
|
|||||||
return sa.isCrew();
|
return sa.isCrew();
|
||||||
} else if (property.equals("Saddle")) {
|
} else if (property.equals("Saddle")) {
|
||||||
return sa.isKeyword(Keyword.SADDLE);
|
return sa.isKeyword(Keyword.SADDLE);
|
||||||
|
} else if (property.equals("Station")) {
|
||||||
|
return sa.isKeyword(Keyword.STATION);
|
||||||
}else if (property.equals("Cycling")) {
|
}else if (property.equals("Cycling")) {
|
||||||
return sa.isCycling();
|
return sa.isCycling();
|
||||||
} else if (property.equals("Dash")) {
|
} else if (property.equals("Dash")) {
|
||||||
|
|||||||
@@ -519,6 +519,7 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
card.setZone(zoneTo);
|
card.setZone(zoneTo);
|
||||||
}
|
}
|
||||||
|
copied.clearMergedCards();
|
||||||
} else {
|
} else {
|
||||||
storeChangesZoneAll(copied, zoneFrom, zoneTo, params);
|
storeChangesZoneAll(copied, zoneFrom, zoneTo, params);
|
||||||
// "enter the battlefield as a copy" - apply code here
|
// "enter the battlefield as a copy" - apply code here
|
||||||
@@ -548,20 +549,20 @@ public class GameAction {
|
|||||||
|
|
||||||
copied.updateStateForView();
|
copied.updateStateForView();
|
||||||
|
|
||||||
|
// we don't want always trigger before counters are placed
|
||||||
|
game.getTriggerHandler().suppressMode(TriggerType.Always);
|
||||||
|
// Need to apply any static effects to produce correct triggers
|
||||||
|
checkStaticAbilities();
|
||||||
|
|
||||||
// needed for counters + ascend
|
// needed for counters + ascend
|
||||||
if (!suppress && toBattlefield) {
|
if (!suppress && toBattlefield) {
|
||||||
game.getTriggerHandler().registerActiveTrigger(copied, false);
|
game.getTriggerHandler().registerActiveTrigger(copied, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!table.isEmpty()) {
|
|
||||||
// we don't want always trigger before counters are placed
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.Always);
|
|
||||||
// Need to apply any static effects to produce correct triggers
|
|
||||||
checkStaticAbilities();
|
|
||||||
// do ETB counters after zone add
|
// do ETB counters after zone add
|
||||||
table.replaceCounterEffect(game, null, true, true, params);
|
table.replaceCounterEffect(game, null, true, true, params);
|
||||||
|
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.Always);
|
game.getTriggerHandler().clearSuppression(TriggerType.Always);
|
||||||
}
|
|
||||||
|
|
||||||
// update static abilities after etb counters have been placed
|
// update static abilities after etb counters have been placed
|
||||||
checkStaticAbilities();
|
checkStaticAbilities();
|
||||||
@@ -645,7 +646,8 @@ public class GameAction {
|
|||||||
// Ask controller if it wants to be on top or bottom of other meld.
|
// Ask controller if it wants to be on top or bottom of other meld.
|
||||||
unmeldPosition++;
|
unmeldPosition++;
|
||||||
}
|
}
|
||||||
changeZone(null, zoneTo, unmeld, position, cause, params);
|
unmeld = changeZone(null, zoneTo, unmeld, position, cause, params);
|
||||||
|
storeChangesZoneAll(unmeld, zoneFrom, zoneTo, params);
|
||||||
}
|
}
|
||||||
} else if (toBattlefield) {
|
} else if (toBattlefield) {
|
||||||
for (Player p : game.getPlayers()) {
|
for (Player p : game.getPlayers()) {
|
||||||
@@ -2794,6 +2796,7 @@ public class GameAction {
|
|||||||
if (aura == null) {
|
if (aura == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
aura.setActivatingPlayer(source.getController());
|
||||||
|
|
||||||
Set<ZoneType> zones = EnumSet.noneOf(ZoneType.class);
|
Set<ZoneType> zones = EnumSet.noneOf(ZoneType.class);
|
||||||
boolean canTargetPlayer = false;
|
boolean canTargetPlayer = false;
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ public enum AbilityKey {
|
|||||||
SourceSA("SourceSA"),
|
SourceSA("SourceSA"),
|
||||||
SpellAbility("SpellAbility"),
|
SpellAbility("SpellAbility"),
|
||||||
SpellAbilityTargets("SpellAbilityTargets"),
|
SpellAbilityTargets("SpellAbilityTargets"),
|
||||||
StackInstance("StackInstance"),
|
|
||||||
StackSa("StackSa"),
|
StackSa("StackSa"),
|
||||||
SurveilNum("SurveilNum"),
|
SurveilNum("SurveilNum"),
|
||||||
Target("Target"),
|
Target("Target"),
|
||||||
@@ -140,7 +139,7 @@ public enum AbilityKey {
|
|||||||
Valiant("Valiant"),
|
Valiant("Valiant"),
|
||||||
Won("Won"),
|
Won("Won"),
|
||||||
|
|
||||||
// below used across different Replacements, don't reuse
|
// below shared across different Replacements, don't reuse
|
||||||
InternalTriggerTable("InternalTriggerTable"),
|
InternalTriggerTable("InternalTriggerTable"),
|
||||||
SimultaneousETB("SimultaneousETB"); // for CR 614.13c
|
SimultaneousETB("SimultaneousETB"); // for CR 614.13c
|
||||||
|
|
||||||
|
|||||||
@@ -663,7 +663,7 @@ public class AbilityUtils {
|
|||||||
Object o = root.getTriggeringObject(AbilityKey.fromString(calcX[0].substring(9)));
|
Object o = root.getTriggeringObject(AbilityKey.fromString(calcX[0].substring(9)));
|
||||||
val = o instanceof Player ? playerXProperty((Player) o, calcX[1], card, ability) : 0;
|
val = o instanceof Player ? playerXProperty((Player) o, calcX[1], card, ability) : 0;
|
||||||
}
|
}
|
||||||
else if (calcX[0].equals("TriggeredSpellAbility") || calcX[0].equals("TriggeredStackInstance") || calcX[0].equals("SpellTargeted")) {
|
else if (calcX[0].equals("TriggeredSpellAbility") || calcX[0].equals("SpellTargeted")) {
|
||||||
final SpellAbility sat = Iterables.getFirst(getDefinedSpellAbilities(card, calcX[0], sa), null);
|
final SpellAbility sat = Iterables.getFirst(getDefinedSpellAbilities(card, calcX[0], sa), null);
|
||||||
val = sat == null ? 0 : xCount(sat.getHostCard(), calcX[1], sat);
|
val = sat == null ? 0 : xCount(sat.getHostCard(), calcX[1], sat);
|
||||||
}
|
}
|
||||||
@@ -1281,8 +1281,6 @@ public class AbilityUtils {
|
|||||||
final Object o = root.getTriggeringObject(AbilityKey.fromString(triggeringType));
|
final Object o = root.getTriggeringObject(AbilityKey.fromString(triggeringType));
|
||||||
if (o instanceof SpellAbility) {
|
if (o instanceof SpellAbility) {
|
||||||
s = (SpellAbility) o;
|
s = (SpellAbility) o;
|
||||||
} else if (o instanceof SpellAbilityStackInstance) {
|
|
||||||
s = ((SpellAbilityStackInstance) o).getSpellAbility();
|
|
||||||
}
|
}
|
||||||
} else if (defined.endsWith("Targeted") && sa instanceof SpellAbility) {
|
} else if (defined.endsWith("Targeted") && sa instanceof SpellAbility) {
|
||||||
final List<TargetChoices> targets = defined.startsWith("This") ? Arrays.asList(((SpellAbility)sa).getTargets()) : ((SpellAbility)sa).getAllTargetChoices();
|
final List<TargetChoices> targets = defined.startsWith("This") ? Arrays.asList(((SpellAbility)sa).getTargets()) : ((SpellAbility)sa).getAllTargetChoices();
|
||||||
@@ -1685,11 +1683,11 @@ public class AbilityUtils {
|
|||||||
return doXMath(x, expr, c, ctb);
|
return doXMath(x, expr, c, ctb);
|
||||||
} else if (TriggerType.SpellCast.equals(t.getMode())) {
|
} else if (TriggerType.SpellCast.equals(t.getMode())) {
|
||||||
// Cast Trigger like Hydroid Krasis
|
// Cast Trigger like Hydroid Krasis
|
||||||
SpellAbilityStackInstance castSI = (SpellAbilityStackInstance) root.getTriggeringObject(AbilityKey.StackInstance);
|
SpellAbility castSA = (SpellAbility) root.getTriggeringObject(AbilityKey.SpellAbility);
|
||||||
if (castSI == null || castSI.getSpellAbility().getXManaCostPaid() == null) {
|
if (castSA == null || castSA.getXManaCostPaid() == null) {
|
||||||
return doXMath(0, expr, c, ctb);
|
return doXMath(0, expr, c, ctb);
|
||||||
}
|
}
|
||||||
return doXMath(castSI.getSpellAbility().getXManaCostPaid(), expr, c, ctb);
|
return doXMath(castSA.getXManaCostPaid(), expr, c, ctb);
|
||||||
} else if (TriggerType.Cycled.equals(t.getMode())) {
|
} else if (TriggerType.Cycled.equals(t.getMode())) {
|
||||||
SpellAbility cycleSA = (SpellAbility) sa.getTriggeringObject(AbilityKey.Cause);
|
SpellAbility cycleSA = (SpellAbility) sa.getTriggeringObject(AbilityKey.Cause);
|
||||||
if (cycleSA == null || cycleSA.getXManaCostPaid() == null) {
|
if (cycleSA == null || cycleSA.getXManaCostPaid() == null) {
|
||||||
@@ -3751,6 +3749,10 @@ public class AbilityUtils {
|
|||||||
return Aggregates.max(paidList, Card::getNetToughness);
|
return Aggregates.max(paidList, Card::getNetToughness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.startsWith("TapPowerValue")) {
|
||||||
|
return CardLists.getTotalPower(paidList, ctb);
|
||||||
|
}
|
||||||
|
|
||||||
if (string.startsWith("SumToughness")) {
|
if (string.startsWith("SumToughness")) {
|
||||||
return Aggregates.sum(paidList, Card::getNetToughness);
|
return Aggregates.sum(paidList, Card::getNetToughness);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,8 +72,8 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
|||||||
// 2. prepare new target choices
|
// 2. prepare new target choices
|
||||||
SpellAbilityStackInstance replaceIn = chosenTarget.getKey();
|
SpellAbilityStackInstance replaceIn = chosenTarget.getKey();
|
||||||
GameObject oldTarget = chosenTarget.getValue();
|
GameObject oldTarget = chosenTarget.getValue();
|
||||||
TargetChoices oldTargetBlock = replaceIn.getTargetChoices();
|
TargetChoices newTargetBlock = replaceIn.getTargetChoices();
|
||||||
TargetChoices newTargetBlock = oldTargetBlock.clone();
|
TargetChoices oldTargetBlock = newTargetBlock.clone();
|
||||||
// gets the divided value from old target
|
// gets the divided value from old target
|
||||||
Integer div = oldTargetBlock.getDividedValue(oldTarget);
|
Integer div = oldTargetBlock.getDividedValue(oldTarget);
|
||||||
// 3. test if updated choices would be correct.
|
// 3. test if updated choices would be correct.
|
||||||
@@ -87,7 +87,7 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
|||||||
if (div != null) {
|
if (div != null) {
|
||||||
newTargetBlock.addDividedAllocation(newTarget, div);
|
newTargetBlock.addDividedAllocation(newTarget, div);
|
||||||
}
|
}
|
||||||
replaceIn.updateTarget(newTargetBlock, sa.getHostCard());
|
replaceIn.updateTarget(oldTargetBlock, sa.getHostCard());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (changingTgtSI != null) {
|
while (changingTgtSI != null) {
|
||||||
@@ -104,25 +104,26 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
|||||||
if (candidates.isEmpty()) {
|
if (candidates.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
changingTgtSA.resetTargets();
|
|
||||||
GameEntity choice = Aggregates.random(candidates);
|
GameEntity choice = Aggregates.random(candidates);
|
||||||
|
TargetChoices oldTarget = changingTgtSA.getTargets();
|
||||||
|
changingTgtSA.resetTargets();
|
||||||
changingTgtSA.getTargets().add(choice);
|
changingTgtSA.getTargets().add(choice);
|
||||||
if (changingTgtSA.isDividedAsYouChoose()) {
|
if (changingTgtSA.isDividedAsYouChoose()) {
|
||||||
changingTgtSA.addDividedAllocation(choice, div);
|
changingTgtSA.addDividedAllocation(choice, div);
|
||||||
}
|
}
|
||||||
|
changingTgtSI.updateTarget(oldTarget, sa.getHostCard());
|
||||||
changingTgtSI.updateTarget(changingTgtSA.getTargets(), sa.getHostCard());
|
|
||||||
}
|
}
|
||||||
else if (sa.hasParam("DefinedMagnet")) {
|
else if (sa.hasParam("DefinedMagnet")) {
|
||||||
GameObject newTarget = Iterables.getFirst(getDefinedCardsOrTargeted(sa, "DefinedMagnet"), null);
|
GameObject newTarget = Iterables.getFirst(getDefinedCardsOrTargeted(sa, "DefinedMagnet"), null);
|
||||||
if (newTarget != null && changingTgtSA.canTarget(newTarget)) {
|
if (newTarget != null && changingTgtSA.canTarget(newTarget)) {
|
||||||
int div = changingTgtSA.getTotalDividedValue();
|
int div = changingTgtSA.getTotalDividedValue();
|
||||||
|
TargetChoices oldTarget = changingTgtSA.getTargets();
|
||||||
changingTgtSA.resetTargets();
|
changingTgtSA.resetTargets();
|
||||||
changingTgtSA.getTargets().add(newTarget);
|
changingTgtSA.getTargets().add(newTarget);
|
||||||
changingTgtSI.updateTarget(changingTgtSA.getTargets(), sa.getHostCard());
|
|
||||||
if (changingTgtSA.isDividedAsYouChoose()) {
|
if (changingTgtSA.isDividedAsYouChoose()) {
|
||||||
changingTgtSA.addDividedAllocation(newTarget, div);
|
changingTgtSA.addDividedAllocation(newTarget, div);
|
||||||
}
|
}
|
||||||
|
changingTgtSI.updateTarget(oldTarget, sa.getHostCard());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Update targets, with a potential new target
|
// Update targets, with a potential new target
|
||||||
@@ -132,8 +133,9 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
|||||||
source = changingTgtSA.getTargetCard();
|
source = changingTgtSA.getTargetCard();
|
||||||
}
|
}
|
||||||
Predicate<GameObject> filter = sa.hasParam("TargetRestriction") ? GameObjectPredicates.restriction(sa.getParam("TargetRestriction").split(","), activator, source, sa) : null;
|
Predicate<GameObject> filter = sa.hasParam("TargetRestriction") ? GameObjectPredicates.restriction(sa.getParam("TargetRestriction").split(","), activator, source, sa) : null;
|
||||||
TargetChoices newTarget = chooser.getController().chooseNewTargetsFor(changingTgtSA, filter, false);
|
TargetChoices oldTarget = changingTgtSA.getTargets();
|
||||||
changingTgtSI.updateTarget(newTarget, sa.getHostCard());
|
chooser.getController().chooseNewTargetsFor(changingTgtSA, filter, false);
|
||||||
|
changingTgtSI.updateTarget(oldTarget, sa.getHostCard());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
changingTgtSI = changingTgtSI.getSubInstance();
|
changingTgtSI = changingTgtSI.getSubInstance();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package forge.game.ability.effects;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import forge.GameCommand;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -36,6 +37,10 @@ public class TextBoxExchangeEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolve(final SpellAbility sa) {
|
public void resolve(final SpellAbility sa) {
|
||||||
|
if (!checkValidDuration(sa.getParam("Duration"), sa)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final List<Card> tgtCards = getTargetCards(sa);
|
final List<Card> tgtCards = getTargetCards(sa);
|
||||||
if (tgtCards.size() < 2) {
|
if (tgtCards.size() < 2) {
|
||||||
return;
|
return;
|
||||||
@@ -55,6 +60,37 @@ public class TextBoxExchangeEffect extends SpellAbilityEffect {
|
|||||||
swapTextBox(c1, data2, ts);
|
swapTextBox(c1, data2, ts);
|
||||||
swapTextBox(c2, data1, ts);
|
swapTextBox(c2, data1, ts);
|
||||||
|
|
||||||
|
if (sa.hasParam("Duration")) {
|
||||||
|
final GameCommand revertTextExchange = new GameCommand() {
|
||||||
|
private static final long serialVersionUID = 5331255714437747836L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Check if the cards are still there
|
||||||
|
Card card1 = game.getCardState(c1, null);
|
||||||
|
Card card2 = game.getCardState(c2, null);
|
||||||
|
|
||||||
|
if (card1 != null && c1.equalsWithGameTimestamp(card1)) {
|
||||||
|
card1.removeChangedCardTraits(ts, 0);
|
||||||
|
card1.removeChangedCardKeywords(ts, 0, false);
|
||||||
|
card1.updateChangedText();
|
||||||
|
card1.updateStateForView();
|
||||||
|
game.fireEvent(new GameEventCardStatsChanged(card1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (card2 != null && c2.equalsWithGameTimestamp(card2)) {
|
||||||
|
card2.removeChangedCardTraits(ts, 0);
|
||||||
|
card2.removeChangedCardKeywords(ts, 0, false);
|
||||||
|
card2.updateChangedText();
|
||||||
|
card2.updateStateForView();
|
||||||
|
game.fireEvent(new GameEventCardStatsChanged(card2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addUntilCommand(sa, revertTextExchange);
|
||||||
|
}
|
||||||
|
|
||||||
game.fireEvent(new GameEventCardStatsChanged(c1));
|
game.fireEvent(new GameEventCardStatsChanged(c1));
|
||||||
game.fireEvent(new GameEventCardStatsChanged(c2));
|
game.fireEvent(new GameEventCardStatsChanged(c2));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1407,6 +1407,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
|||||||
public final CardCollectionView getMergedCards() {
|
public final CardCollectionView getMergedCards() {
|
||||||
return CardCollection.getView(mergedCards);
|
return CardCollection.getView(mergedCards);
|
||||||
}
|
}
|
||||||
|
public final void setMergedCards(Iterable<Card> mc) {
|
||||||
|
mergedCards = new CardCollection(mc);
|
||||||
|
}
|
||||||
|
|
||||||
public final Card getTopMergedCard() {
|
public final Card getTopMergedCard() {
|
||||||
return mergedCards.get(0);
|
return mergedCards.get(0);
|
||||||
}
|
}
|
||||||
@@ -2739,7 +2743,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
|||||||
|| keyword.startsWith("Class") || keyword.startsWith("Blitz")
|
|| keyword.startsWith("Class") || keyword.startsWith("Blitz")
|
||||||
|| keyword.startsWith("Specialize") || keyword.equals("Ravenous")
|
|| keyword.startsWith("Specialize") || keyword.equals("Ravenous")
|
||||||
|| keyword.equals("For Mirrodin") || keyword.equals("Job select") || keyword.startsWith("Craft")
|
|| keyword.equals("For Mirrodin") || keyword.equals("Job select") || keyword.startsWith("Craft")
|
||||||
|| keyword.startsWith("Landwalk") || keyword.startsWith("Visit") || keyword.startsWith("Mobilize")) {
|
|| keyword.startsWith("Landwalk") || keyword.startsWith("Visit") || keyword.startsWith("Mobilize")
|
||||||
|
|| keyword.startsWith("Station")) {
|
||||||
// keyword parsing takes care of adding a proper description
|
// keyword parsing takes care of adding a proper description
|
||||||
} else if (keyword.equals("Read ahead")) {
|
} else if (keyword.equals("Read ahead")) {
|
||||||
sb.append(Localizer.getInstance().getMessage("lblReadAhead")).append(" (").append(Localizer.getInstance().getMessage("lblReadAheadDesc"));
|
sb.append(Localizer.getInstance().getMessage("lblReadAhead")).append(" (").append(Localizer.getInstance().getMessage("lblReadAheadDesc"));
|
||||||
@@ -4229,12 +4234,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
|||||||
return ImmutableList.of();
|
return ImmutableList.of();
|
||||||
}
|
}
|
||||||
Iterable<CardChangedType> byText = changedTypeByText == null ? ImmutableList.of() : ImmutableList.of(this.changedTypeByText);
|
Iterable<CardChangedType> byText = changedTypeByText == null ? ImmutableList.of() : ImmutableList.of(this.changedTypeByText);
|
||||||
return ImmutableList.copyOf(Iterables.concat(
|
return ImmutableList.<CardChangedType>builder()
|
||||||
changedCardTypesByText.values(), // Layer 3
|
.addAll(changedCardTypesByText.values()) // Layer 3
|
||||||
byText, // Layer 3 by Word Changes,
|
.addAll(byText) // Layer 3 by Word Changes,
|
||||||
changedCardTypesCharacterDefining.values(), // Layer 4
|
.addAll(changedCardTypesCharacterDefining.values()) // Layer 4
|
||||||
changedCardTypes.values() // Layer 6
|
.addAll(changedCardTypes.values()) // Layer 6
|
||||||
));
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean clearChangedCardTypes() {
|
public boolean clearChangedCardTypes() {
|
||||||
@@ -6515,6 +6520,29 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
|||||||
if(uiCard != null)
|
if(uiCard != null)
|
||||||
uiCard.currentState.setImageKey(iFN);
|
uiCard.currentState.setImageKey(iFN);
|
||||||
}
|
}
|
||||||
|
public final void setImageKey(final IPaperCard ipc, final CardStateName stateName) {
|
||||||
|
if (ipc == null)
|
||||||
|
return;
|
||||||
|
switch (stateName) {
|
||||||
|
case SpecializeB:
|
||||||
|
setImageKey(ipc.getCardBSpecImageKey());
|
||||||
|
break;
|
||||||
|
case SpecializeR:
|
||||||
|
setImageKey(ipc.getCardRSpecImageKey());
|
||||||
|
break;
|
||||||
|
case SpecializeG:
|
||||||
|
setImageKey(ipc.getCardGSpecImageKey());
|
||||||
|
break;
|
||||||
|
case SpecializeU:
|
||||||
|
setImageKey(ipc.getCardUSpecImageKey());
|
||||||
|
break;
|
||||||
|
case SpecializeW:
|
||||||
|
setImageKey(ipc.getCardWSpecImageKey());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getImageKey(CardStateName state) {
|
public String getImageKey(CardStateName state) {
|
||||||
if (!getRenderForUI()) {
|
if (!getRenderForUI()) {
|
||||||
@@ -6814,6 +6842,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
|||||||
}
|
}
|
||||||
public final void setSpecialized(final boolean bool) {
|
public final void setSpecialized(final boolean bool) {
|
||||||
specialized = bool;
|
specialized = bool;
|
||||||
|
setImageKey(getPaperCard(), getCurrentStateName());
|
||||||
}
|
}
|
||||||
public final boolean canSpecialize() {
|
public final boolean canSpecialize() {
|
||||||
return getRules() != null && getRules().getSplitType() == CardSplitType.Specialize;
|
return getRules() != null && getRules().getSplitType() == CardSplitType.Specialize;
|
||||||
|
|||||||
@@ -66,8 +66,15 @@ public class CardCopyService {
|
|||||||
out.setCollectible(copyFrom.isCollectible());
|
out.setCollectible(copyFrom.isCollectible());
|
||||||
|
|
||||||
// this's necessary for forge.game.GameAction.unattachCardLeavingBattlefield(Card)
|
// this's necessary for forge.game.GameAction.unattachCardLeavingBattlefield(Card)
|
||||||
|
if (copyFrom.hasCardAttachments()) {
|
||||||
out.setAttachedCards(copyFrom.getAttachedCards());
|
out.setAttachedCards(copyFrom.getAttachedCards());
|
||||||
|
}
|
||||||
|
if (copyFrom.isAttachedToEntity()) {
|
||||||
out.setEntityAttachedTo(copyFrom.getEntityAttachedTo());
|
out.setEntityAttachedTo(copyFrom.getEntityAttachedTo());
|
||||||
|
}
|
||||||
|
if (copyFrom.hasMergedCard()) {
|
||||||
|
out.setMergedCards(copyFrom.getMergedCards());
|
||||||
|
}
|
||||||
|
|
||||||
out.setLeavesPlayCommands(copyFrom.getLeavesPlayCommands());
|
out.setLeavesPlayCommands(copyFrom.getLeavesPlayCommands());
|
||||||
|
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ public class CardFactory {
|
|||||||
c.setRarity(cp.getRarity());
|
c.setRarity(cp.getRarity());
|
||||||
|
|
||||||
// Would like to move this away from in-game entities
|
// Would like to move this away from in-game entities
|
||||||
String originalPicture = cp.getCardImageKey();
|
String originalPicture = cp.getImageKey(false);
|
||||||
c.setImageKey(originalPicture);
|
c.setImageKey(originalPicture);
|
||||||
|
|
||||||
if(cp.isToken())
|
if(cp.isToken())
|
||||||
@@ -198,11 +198,11 @@ public class CardFactory {
|
|||||||
if (c.hasAlternateState()) {
|
if (c.hasAlternateState()) {
|
||||||
if (c.isFlipCard()) {
|
if (c.isFlipCard()) {
|
||||||
c.setState(CardStateName.Flipped, false);
|
c.setState(CardStateName.Flipped, false);
|
||||||
c.setImageKey(cp.getCardAltImageKey());
|
c.setImageKey(cp.getImageKey(true));
|
||||||
}
|
}
|
||||||
else if (c.isDoubleFaced() && cardRules != null) {
|
else if (c.isDoubleFaced() && cardRules != null) {
|
||||||
c.setState(cardRules.getSplitType().getChangedStateName(), false);
|
c.setState(cardRules.getSplitType().getChangedStateName(), false);
|
||||||
c.setImageKey(cp.getCardAltImageKey());
|
c.setImageKey(cp.getImageKey(true));
|
||||||
}
|
}
|
||||||
else if (c.isSplitCard()) {
|
else if (c.isSplitCard()) {
|
||||||
c.setState(CardStateName.LeftSplit, false);
|
c.setState(CardStateName.LeftSplit, false);
|
||||||
@@ -216,23 +216,23 @@ public class CardFactory {
|
|||||||
c.setImageKey(originalPicture);
|
c.setImageKey(originalPicture);
|
||||||
} else if (c.canSpecialize()) {
|
} else if (c.canSpecialize()) {
|
||||||
c.setState(CardStateName.SpecializeW, false);
|
c.setState(CardStateName.SpecializeW, false);
|
||||||
c.setImageKey(cp.getCardWSpecImageKey());
|
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_W);
|
||||||
c.setSetCode(cp.getEdition());
|
c.setSetCode(cp.getEdition());
|
||||||
c.setRarity(cp.getRarity());
|
c.setRarity(cp.getRarity());
|
||||||
c.setState(CardStateName.SpecializeU, false);
|
c.setState(CardStateName.SpecializeU, false);
|
||||||
c.setImageKey(cp.getCardUSpecImageKey());
|
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_U);
|
||||||
c.setSetCode(cp.getEdition());
|
c.setSetCode(cp.getEdition());
|
||||||
c.setRarity(cp.getRarity());
|
c.setRarity(cp.getRarity());
|
||||||
c.setState(CardStateName.SpecializeB, false);
|
c.setState(CardStateName.SpecializeB, false);
|
||||||
c.setImageKey(cp.getCardBSpecImageKey());
|
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_B);
|
||||||
c.setSetCode(cp.getEdition());
|
c.setSetCode(cp.getEdition());
|
||||||
c.setRarity(cp.getRarity());
|
c.setRarity(cp.getRarity());
|
||||||
c.setState(CardStateName.SpecializeR, false);
|
c.setState(CardStateName.SpecializeR, false);
|
||||||
c.setImageKey(cp.getCardRSpecImageKey());
|
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_R);
|
||||||
c.setSetCode(cp.getEdition());
|
c.setSetCode(cp.getEdition());
|
||||||
c.setRarity(cp.getRarity());
|
c.setRarity(cp.getRarity());
|
||||||
c.setState(CardStateName.SpecializeG, false);
|
c.setState(CardStateName.SpecializeG, false);
|
||||||
c.setImageKey(cp.getCardGSpecImageKey());
|
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_G);
|
||||||
c.setSetCode(cp.getEdition());
|
c.setSetCode(cp.getEdition());
|
||||||
c.setRarity(cp.getRarity());
|
c.setRarity(cp.getRarity());
|
||||||
}
|
}
|
||||||
@@ -742,7 +742,7 @@ public class CardFactory {
|
|||||||
TextUtil.fastReplace(host.getName(), ",", ""),
|
TextUtil.fastReplace(host.getName(), ",", ""),
|
||||||
" ", "_").toLowerCase();
|
" ", "_").toLowerCase();
|
||||||
String set = host.getSetCode().toLowerCase();
|
String set = host.getSetCode().toLowerCase();
|
||||||
state.setImageKey(ImageKeys.getTokenKey("offspring_" + name + "_" + set));
|
state.setImageKey(ImageKeys.getTokenKey("offspring_" + name + "|" + set));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2122,23 +2122,13 @@ public class CardFactoryUtil {
|
|||||||
} else if (keyword.startsWith("Amplify")) {
|
} else if (keyword.startsWith("Amplify")) {
|
||||||
final String[] ampString = keyword.split(":");
|
final String[] ampString = keyword.split(":");
|
||||||
final String amplifyMagnitude = ampString[1];
|
final String amplifyMagnitude = ampString[1];
|
||||||
final String ampTypes = ampString[2];
|
|
||||||
String[] refinedTypes = ampTypes.split(",");
|
|
||||||
final StringBuilder types = new StringBuilder();
|
|
||||||
for (int i = 0; i < refinedTypes.length; i++) {
|
|
||||||
types.append("Card.").append(refinedTypes[i]).append("+YouCtrl");
|
|
||||||
if (i + 1 != refinedTypes.length) {
|
|
||||||
types.append(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup ETB replacement effects
|
// Setup ETB replacement effects
|
||||||
final String actualRep = "Event$ Moved | Destination$ Battlefield | ValidCard$ Card.Self |"
|
final String actualRep = "Event$ Moved | Destination$ Battlefield | ValidCard$ Card.Self |"
|
||||||
+ " | ReplacementResult$ Updated | Description$ Amplify " + amplifyMagnitude + " ("
|
+ " | ReplacementResult$ Updated | Description$ Amplify " + amplifyMagnitude + " ("
|
||||||
+ inst.getReminderText() + ")";
|
+ inst.getReminderText() + ")";
|
||||||
|
|
||||||
final String abString = "DB$ Reveal | AnyNumber$ True | RevealValid$ "
|
final String abString = "DB$ Reveal | AnyNumber$ True | RevealValid$ Card.YouOwn+sharesCreatureTypeWith+Other+NotDefinedReplacedSimultaneousETB | RememberRevealed$ True";
|
||||||
+ types.toString() + " | RememberRevealed$ True";
|
|
||||||
|
|
||||||
SpellAbility saReveal = AbilityFactory.getAbility(abString, card);
|
SpellAbility saReveal = AbilityFactory.getAbility(abString, card);
|
||||||
|
|
||||||
@@ -2792,7 +2782,7 @@ public class CardFactoryUtil {
|
|||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final Cost blitzCost = new Cost(k[1], false);
|
final Cost blitzCost = new Cost(k[1], false);
|
||||||
|
|
||||||
final SpellAbility newSA = card.getFirstSpellAbility().copyWithManaCostReplaced(host.getController(), blitzCost);
|
final SpellAbility newSA = card.getFirstSpellAbilityWithFallback().copyWithManaCostReplaced(host.getController(), blitzCost);
|
||||||
|
|
||||||
if (k.length > 2) {
|
if (k.length > 2) {
|
||||||
newSA.getMapParams().put("ValidAfterStack", k[2]);
|
newSA.getMapParams().put("ValidAfterStack", k[2]);
|
||||||
@@ -2905,7 +2895,7 @@ public class CardFactoryUtil {
|
|||||||
}
|
}
|
||||||
desc += ")";
|
desc += ")";
|
||||||
|
|
||||||
final SpellAbility sa = card.getFirstSpellAbility();
|
final SpellAbility sa = card.getFirstSpellAbilityWithFallback();
|
||||||
final SpellAbility newSA = sa.copyWithDefinedCost(new Cost(costStr, false));
|
final SpellAbility newSA = sa.copyWithDefinedCost(new Cost(costStr, false));
|
||||||
|
|
||||||
newSA.getRestrictions().setIsPresent(validStr + ".YouCtrl+CanBeSacrificedBy");
|
newSA.getRestrictions().setIsPresent(validStr + ".YouCtrl+CanBeSacrificedBy");
|
||||||
@@ -3591,6 +3581,15 @@ public class CardFactoryUtil {
|
|||||||
sa.setSVar("ScavengeX", "Exiled$CardPower");
|
sa.setSVar("ScavengeX", "Exiled$CardPower");
|
||||||
sa.setIntrinsic(intrinsic);
|
sa.setIntrinsic(intrinsic);
|
||||||
inst.addSpellAbility(sa);
|
inst.addSpellAbility(sa);
|
||||||
|
} else if (keyword.startsWith("Station")) {
|
||||||
|
String effect = "AB$ PutCounter | Cost$ tapXType<1/Creature.Other> | Defined$ Self " +
|
||||||
|
"| CounterType$ CHARGE | CounterNum$ StationX | SorcerySpeed$ True " +
|
||||||
|
"| CostDesc$ | SpellDescription$ Station (" + inst.getReminderText() + ")";
|
||||||
|
|
||||||
|
final SpellAbility sa = AbilityFactory.getAbility(effect, card);
|
||||||
|
sa.setSVar("StationX", "TappedCards$TapPowerValue");
|
||||||
|
sa.setIntrinsic(intrinsic);
|
||||||
|
inst.addSpellAbility(sa);
|
||||||
} else if (keyword.startsWith("Encore")) {
|
} else if (keyword.startsWith("Encore")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final String manacost = k[1];
|
final String manacost = k[1];
|
||||||
|
|||||||
@@ -421,13 +421,13 @@ public class CardLists {
|
|||||||
* @param cardList the list of creature cards for which to sum the power
|
* @param cardList the list of creature cards for which to sum the power
|
||||||
* @param crew for cards that crew with toughness rather than power
|
* @param crew for cards that crew with toughness rather than power
|
||||||
*/
|
*/
|
||||||
public static int getTotalPower(Iterable<Card> cardList, SpellAbility sa) {
|
public static int getTotalPower(Iterable<Card> cardList, CardTraitBase ctb) {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
for (final Card crd : cardList) {
|
for (final Card crd : cardList) {
|
||||||
if (StaticAbilityTapPowerValue.withToughness(crd, sa)) {
|
if (StaticAbilityTapPowerValue.withToughness(crd, ctb)) {
|
||||||
total += Math.max(0, crd.getNetToughness());
|
total += Math.max(0, crd.getNetToughness());
|
||||||
} else {
|
} else {
|
||||||
int m = StaticAbilityTapPowerValue.getMod(crd, sa);
|
int m = StaticAbilityTapPowerValue.getMod(crd, ctb);
|
||||||
total += Math.max(0, crd.getNetPower() + m);
|
total += Math.max(0, crd.getNetPower() + m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import java.util.Collection;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
||||||
private String name = "";
|
private String name = "";
|
||||||
@@ -366,14 +367,16 @@ public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
|||||||
public final FCollectionView<SpellAbility> getManaAbilities() {
|
public final FCollectionView<SpellAbility> getManaAbilities() {
|
||||||
FCollection<SpellAbility> newCol = new FCollection<>();
|
FCollection<SpellAbility> newCol = new FCollection<>();
|
||||||
updateSpellAbilities(newCol, true);
|
updateSpellAbilities(newCol, true);
|
||||||
newCol.addAll(abilities.stream().filter(SpellAbility::isManaAbility).toList());
|
// stream().toList() causes crash on Android, use Collectors.toList()
|
||||||
|
newCol.addAll(abilities.stream().filter(SpellAbility::isManaAbility).collect(Collectors.toList()));
|
||||||
card.updateSpellAbilities(newCol, this, true);
|
card.updateSpellAbilities(newCol, this, true);
|
||||||
return newCol;
|
return newCol;
|
||||||
}
|
}
|
||||||
public final FCollectionView<SpellAbility> getNonManaAbilities() {
|
public final FCollectionView<SpellAbility> getNonManaAbilities() {
|
||||||
FCollection<SpellAbility> newCol = new FCollection<>();
|
FCollection<SpellAbility> newCol = new FCollection<>();
|
||||||
updateSpellAbilities(newCol, false);
|
updateSpellAbilities(newCol, false);
|
||||||
newCol.addAll(abilities.stream().filter(Predicate.not(SpellAbility::isManaAbility)).toList());
|
// stream().toList() causes crash on Android, use Collectors.toList()
|
||||||
|
newCol.addAll(abilities.stream().filter(Predicate.not(SpellAbility::isManaAbility)).collect(Collectors.toList()));
|
||||||
card.updateSpellAbilities(newCol, this, false);
|
card.updateSpellAbilities(newCol, this, false);
|
||||||
return newCol;
|
return newCol;
|
||||||
}
|
}
|
||||||
@@ -385,7 +388,10 @@ public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
|||||||
CardState leftState = getCard().getState(CardStateName.LeftSplit);
|
CardState leftState = getCard().getState(CardStateName.LeftSplit);
|
||||||
Collection<SpellAbility> leftAbilities = leftState.abilities;
|
Collection<SpellAbility> leftAbilities = leftState.abilities;
|
||||||
if (null != mana) {
|
if (null != mana) {
|
||||||
leftAbilities = leftAbilities.stream().filter(mana ? SpellAbility::isManaAbility : Predicate.not(SpellAbility::isManaAbility)).toList();
|
leftAbilities = leftAbilities.stream()
|
||||||
|
.filter(mana ? SpellAbility::isManaAbility : Predicate.not(SpellAbility::isManaAbility))
|
||||||
|
// stream().toList() causes crash on Android, use Collectors.toList()
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
newCol.addAll(leftAbilities);
|
newCol.addAll(leftAbilities);
|
||||||
leftState.updateSpellAbilities(newCol, mana);
|
leftState.updateSpellAbilities(newCol, mana);
|
||||||
@@ -394,7 +400,10 @@ public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
|||||||
CardState rightState = getCard().getState(CardStateName.RightSplit);
|
CardState rightState = getCard().getState(CardStateName.RightSplit);
|
||||||
Collection<SpellAbility> rightAbilities = rightState.abilities;
|
Collection<SpellAbility> rightAbilities = rightState.abilities;
|
||||||
if (null != mana) {
|
if (null != mana) {
|
||||||
rightAbilities = rightAbilities.stream().filter(mana ? SpellAbility::isManaAbility : Predicate.not(SpellAbility::isManaAbility)).toList();
|
rightAbilities = rightAbilities.stream()
|
||||||
|
.filter(mana ? SpellAbility::isManaAbility : Predicate.not(SpellAbility::isManaAbility))
|
||||||
|
// stream().toList() causes crash on Android, use Collectors.toList()
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
newCol.addAll(rightAbilities);
|
newCol.addAll(rightAbilities);
|
||||||
rightState.updateSpellAbilities(newCol, mana);
|
rightState.updateSpellAbilities(newCol, mana);
|
||||||
@@ -428,8 +437,7 @@ public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
|||||||
CardTypeView type = getTypeWithChanges();
|
CardTypeView type = getTypeWithChanges();
|
||||||
if (type.isLand()) {
|
if (type.isLand()) {
|
||||||
if (landAbility == null) {
|
if (landAbility == null) {
|
||||||
landAbility = new LandAbility(card);
|
landAbility = new LandAbility(card, this);
|
||||||
landAbility.setCardState(this);
|
|
||||||
}
|
}
|
||||||
newCol.add(landAbility);
|
newCol.add(landAbility);
|
||||||
} else if (type.isAura()) {
|
} else if (type.isAura()) {
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ public class CardView extends GameEntityView {
|
|||||||
set(TrackableProperty.Controller, ownerAndController);
|
set(TrackableProperty.Controller, ownerAndController);
|
||||||
set(TrackableProperty.ImageKey, imageKey);
|
set(TrackableProperty.ImageKey, imageKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerView getOwner() {
|
public PlayerView getOwner() {
|
||||||
return get(TrackableProperty.Owner);
|
return get(TrackableProperty.Owner);
|
||||||
}
|
}
|
||||||
@@ -1061,6 +1060,8 @@ public class CardView extends GameEntityView {
|
|||||||
mergedCollection.add(card);
|
mergedCollection.add(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
set(TrackableProperty.MergedCards, null);
|
||||||
}
|
}
|
||||||
updateMergeCollections(mergedCollection);
|
updateMergeCollections(mergedCollection);
|
||||||
|
|
||||||
@@ -1335,29 +1336,9 @@ public class CardView extends GameEntityView {
|
|||||||
}
|
}
|
||||||
void updateImageKey(Card c) {
|
void updateImageKey(Card c) {
|
||||||
set(TrackableProperty.ImageKey, c.getImageKey());
|
set(TrackableProperty.ImageKey, c.getImageKey());
|
||||||
// currently only works for Cards
|
|
||||||
if (!c.getGamePieceType().equals(GamePieceType.CARD)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
IPaperCard pc = c.getPaperCard();
|
|
||||||
if (pc != null) {
|
|
||||||
set(TrackableProperty.Artist, pc.getArtist());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void updateImageKey(CardState c) {
|
void updateImageKey(CardState c) {
|
||||||
set(TrackableProperty.ImageKey, c.getImageKey());
|
set(TrackableProperty.ImageKey, c.getImageKey());
|
||||||
// currently only works for Cards
|
|
||||||
if (!c.getCard().getGamePieceType().equals(GamePieceType.CARD)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
IPaperCard pc = c.getCard().getPaperCard();
|
|
||||||
if (pc != null) { // currently Artist is per Card
|
|
||||||
set(TrackableProperty.Artist, pc.getArtist());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getArtist() {
|
|
||||||
return get(TrackableProperty.Artist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardTypeView getType() {
|
public CardTypeView getType() {
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ public class CostPayment extends ManaConversionMatrix {
|
|||||||
private static List<Pair<Mana, Integer>> selectManaToPayFor(final ManaPool manapool, final ManaCostShard shard,
|
private static List<Pair<Mana, Integer>> selectManaToPayFor(final ManaPool manapool, final ManaCostShard shard,
|
||||||
final SpellAbility saBeingPaidFor, final byte colorsPaid, Map<String, Integer> xManaCostPaidByColor) {
|
final SpellAbility saBeingPaidFor, final byte colorsPaid, Map<String, Integer> xManaCostPaidByColor) {
|
||||||
final List<Pair<Mana, Integer>> weightedOptions = new ArrayList<>();
|
final List<Pair<Mana, Integer>> weightedOptions = new ArrayList<>();
|
||||||
for (final Mana thisMana : manapool) {
|
for (final Mana thisMana : Lists.newArrayList(manapool)) {
|
||||||
if (shard == ManaCostShard.COLORED_X && !ManaCostBeingPaid.canColoredXShardBePaidByColor(MagicColor.toShortString(thisMana.getColor()), xManaCostPaidByColor)) {
|
if (shard == ManaCostShard.COLORED_X && !ManaCostBeingPaid.canColoredXShardBePaidByColor(MagicColor.toShortString(thisMana.getColor()), xManaCostPaidByColor)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ public enum Keyword {
|
|||||||
SQUAD("Squad", KeywordWithCost.class, false, "As an additional cost to cast this spell, you may pay %s any number of times. When this creature enters, create that many tokens that are copies of it."),
|
SQUAD("Squad", KeywordWithCost.class, false, "As an additional cost to cast this spell, you may pay %s any number of times. When this creature enters, create that many tokens that are copies of it."),
|
||||||
START_YOUR_ENGINES("Start your engines", SimpleKeyword.class, true, "If you have no speed, it starts at 1. It increases once on each of your turns when an opponent loses life. Max speed is 4."),
|
START_YOUR_ENGINES("Start your engines", SimpleKeyword.class, true, "If you have no speed, it starts at 1. It increases once on each of your turns when an opponent loses life. Max speed is 4."),
|
||||||
STARTING_INTENSITY("Starting intensity", KeywordWithAmount.class, true, null),
|
STARTING_INTENSITY("Starting intensity", KeywordWithAmount.class, true, null),
|
||||||
|
STATION("Station", KeywordWithAmount.class, false, "Tap another creature you control: Put charge counters equal to its power on this Spacecraft. Station only as a sorcery. It’s an artifact creature at %d+."),
|
||||||
STORM("Storm", SimpleKeyword.class, false, "When you cast this spell, copy it for each other spell that was cast before it this turn. You may choose new targets for the copies."),
|
STORM("Storm", SimpleKeyword.class, false, "When you cast this spell, copy it for each other spell that was cast before it this turn. You may choose new targets for the copies."),
|
||||||
STRIVE("Strive", KeywordWithCost.class, false, "CARDNAME costs %s more to cast for each target beyond the first."),
|
STRIVE("Strive", KeywordWithCost.class, false, "CARDNAME costs %s more to cast for each target beyond the first."),
|
||||||
SUNBURST("Sunburst", SimpleKeyword.class, false, "This enters with either a +1/+1 or charge counter on it for each color of mana spent to cast it based on whether it's a creature."),
|
SUNBURST("Sunburst", SimpleKeyword.class, false, "This enters with either a +1/+1 or charge counter on it for each color of mana spent to cast it based on whether it's a creature."),
|
||||||
|
|||||||
@@ -904,10 +904,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
|
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
|
||||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAdded, AbilityKey.newMap(runParams), false);
|
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAdded, AbilityKey.newMap(runParams), false);
|
||||||
}
|
}
|
||||||
if (addAmount > 0) {
|
|
||||||
runParams.put(AbilityKey.CounterAmount, addAmount);
|
runParams.put(AbilityKey.CounterAmount, addAmount);
|
||||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAddedOnce, AbilityKey.newMap(runParams), false);
|
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAddedOnce, AbilityKey.newMap(runParams), false);
|
||||||
}
|
|
||||||
if (table != null) {
|
if (table != null) {
|
||||||
table.put(source, this, counterType, addAmount);
|
table.put(source, this, counterType, addAmount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.esotericsoftware.minlog.Log;
|
|||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardState;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,6 +38,9 @@ public abstract class Ability extends SpellAbility {
|
|||||||
protected Ability(final Card sourceCard, final ManaCost manaCost) {
|
protected Ability(final Card sourceCard, final ManaCost manaCost) {
|
||||||
this(sourceCard, new Cost(manaCost, true), null);
|
this(sourceCard, new Cost(manaCost, true), null);
|
||||||
}
|
}
|
||||||
|
protected Ability(final Card sourceCard, final ManaCost manaCost, final CardState state) {
|
||||||
|
super(sourceCard, new Cost(manaCost, true), null, state);
|
||||||
|
}
|
||||||
protected Ability(final Card sourceCard, final ManaCost manaCost, SpellAbilityView view0) {
|
protected Ability(final Card sourceCard, final ManaCost manaCost, SpellAbilityView view0) {
|
||||||
this(sourceCard, new Cost(manaCost, true), view0);
|
this(sourceCard, new Cost(manaCost, true), view0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package forge.game.spellability;
|
|||||||
|
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardState;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,6 +44,9 @@ public abstract class AbilityStatic extends Ability implements Cloneable {
|
|||||||
public AbilityStatic(final Card sourceCard, final ManaCost manaCost) {
|
public AbilityStatic(final Card sourceCard, final ManaCost manaCost) {
|
||||||
super(sourceCard, manaCost);
|
super(sourceCard, manaCost);
|
||||||
}
|
}
|
||||||
|
public AbilityStatic(final Card sourceCard, final ManaCost manaCost, final CardState state) {
|
||||||
|
super(sourceCard, manaCost, state);
|
||||||
|
}
|
||||||
|
|
||||||
public AbilityStatic(final Card sourceCard, final Cost abCost, final TargetRestrictions tgt) {
|
public AbilityStatic(final Card sourceCard, final Cost abCost, final TargetRestrictions tgt) {
|
||||||
super(sourceCard, abCost);
|
super(sourceCard, abCost);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import forge.card.CardStateName;
|
|||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCopyService;
|
import forge.game.card.CardCopyService;
|
||||||
|
import forge.game.card.CardState;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
@@ -31,8 +32,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
|
|
||||||
public class LandAbility extends AbilityStatic {
|
public class LandAbility extends AbilityStatic {
|
||||||
|
|
||||||
public LandAbility(Card sourceCard) {
|
public LandAbility(Card sourceCard, CardState state) {
|
||||||
super(sourceCard, ManaCost.NO_COST);
|
super(sourceCard, ManaCost.NO_COST, state);
|
||||||
|
|
||||||
getRestrictions().setZone(ZoneType.Hand);
|
getRestrictions().setZone(ZoneType.Hand);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,12 +195,18 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected SpellAbility(final Card iSourceCard, final Cost toPay) {
|
protected SpellAbility(final Card iSourceCard, final Cost toPay) {
|
||||||
this(iSourceCard, toPay, null);
|
this(iSourceCard, toPay, null, null);
|
||||||
}
|
}
|
||||||
protected SpellAbility(final Card iSourceCard, final Cost toPay, SpellAbilityView view0) {
|
protected SpellAbility(final Card iSourceCard, final Cost toPay, SpellAbilityView view0) {
|
||||||
|
this(iSourceCard, toPay, view0, null);
|
||||||
|
}
|
||||||
|
protected SpellAbility(final Card iSourceCard, final Cost toPay, SpellAbilityView view0, CardState cs) {
|
||||||
id = nextId();
|
id = nextId();
|
||||||
hostCard = iSourceCard;
|
hostCard = iSourceCard;
|
||||||
payCosts = toPay;
|
payCosts = toPay;
|
||||||
|
if (cs != null) {
|
||||||
|
cardState = cs;
|
||||||
|
}
|
||||||
if (view0 == null) {
|
if (view0 == null) {
|
||||||
view0 = new SpellAbilityView(this);
|
view0 = new SpellAbilityView(this);
|
||||||
}
|
}
|
||||||
@@ -1222,12 +1228,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
try {
|
try {
|
||||||
clone = (SpellAbility) clone();
|
clone = (SpellAbility) clone();
|
||||||
clone.id = lki ? id : nextId();
|
clone.id = lki ? id : nextId();
|
||||||
clone.view = new SpellAbilityView(clone, lki || host.getGame() == null ? null : host.getGame().getTracker());
|
|
||||||
|
|
||||||
// don't use setHostCard to not trigger the not copied parts yet
|
// don't use setHostCard to not trigger the not copied parts yet
|
||||||
|
|
||||||
copyHelper(clone, host, lki || keepTextChanges);
|
copyHelper(clone, host, lki || keepTextChanges);
|
||||||
|
|
||||||
|
// need CardState before View
|
||||||
|
clone.view = new SpellAbilityView(clone, lki || host.getGame() == null ? null : host.getGame().getTracker());
|
||||||
|
|
||||||
// always set this to false, it is only set in CopyEffect
|
// always set this to false, it is only set in CopyEffect
|
||||||
clone.mayChooseNewTargets = false;
|
clone.mayChooseNewTargets = false;
|
||||||
|
|
||||||
|
|||||||
@@ -133,18 +133,16 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
|
|||||||
return ability.getTargets();
|
return ability.getTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateTarget(TargetChoices target, Card cause) {
|
public void updateTarget(TargetChoices oldTC, Card cause) {
|
||||||
if (target != null) {
|
if (oldTC != null) {
|
||||||
TargetChoices oldTarget = ability.getTargets();
|
|
||||||
ability.setTargets(target);
|
|
||||||
stackDescription = ability.getStackDescription();
|
stackDescription = ability.getStackDescription();
|
||||||
view.updateTargetCards(this);
|
view.updateTargetCards(this);
|
||||||
view.updateTargetPlayers(this);
|
view.updateTargetPlayers(this);
|
||||||
view.updateText(this);
|
view.updateText(this);
|
||||||
|
|
||||||
Set<GameObject> distinctObjects = Sets.newHashSet();
|
Set<GameObject> distinctObjects = Sets.newHashSet();
|
||||||
for (final GameObject tgt : target) {
|
for (final GameObject tgt : ability.getTargets()) {
|
||||||
if (oldTarget != null && oldTarget.contains(tgt)) {
|
if (oldTC.contains(tgt)) {
|
||||||
// it was an old target, so don't trigger becomes target
|
// it was an old target, so don't trigger becomes target
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import forge.util.TextUtil;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -273,7 +274,7 @@ public final class StaticAbilityContinuous {
|
|||||||
if (hostCard.hasChosenPlayer()) {
|
if (hostCard.hasChosenPlayer()) {
|
||||||
Player cp = hostCard.getChosenPlayer();
|
Player cp = hostCard.getChosenPlayer();
|
||||||
input = input.replaceAll("ChosenPlayerUID", String.valueOf(cp.getId()));
|
input = input.replaceAll("ChosenPlayerUID", String.valueOf(cp.getId()));
|
||||||
input = input.replaceAll("ChosenPlayerName", cp.getName());
|
input = input.replaceAll("ChosenPlayerName", Matcher.quoteReplacement(cp.getName()));
|
||||||
}
|
}
|
||||||
if (hostCard.hasNamedCard()) {
|
if (hostCard.hasNamedCard()) {
|
||||||
final String chosenName = hostCard.getNamedCard().replace(",", ";");
|
final String chosenName = hostCard.getNamedCard().replace(",", ";");
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
package forge.game.staticability;
|
package forge.game.staticability;
|
||||||
|
|
||||||
|
import forge.game.CardTraitBase;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.spellability.SpellAbility;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
public class StaticAbilityTapPowerValue {
|
public class StaticAbilityTapPowerValue {
|
||||||
|
|
||||||
public static boolean withToughness(final Card card, final SpellAbility sa) {
|
public static boolean withToughness(final Card card, final CardTraitBase ctb) {
|
||||||
final Game game = card.getGame();
|
final Game game = card.getGame();
|
||||||
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
|
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
|
||||||
for (final StaticAbility stAb : ca.getStaticAbilities()) {
|
for (final StaticAbility stAb : ca.getStaticAbilities()) {
|
||||||
if (!stAb.checkConditions(StaticAbilityMode.TapPowerValue)) {
|
if (!stAb.checkConditions(StaticAbilityMode.TapPowerValue)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (withToughness(stAb, card, sa)) {
|
if (withToughness(stAb, card, ctb)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,20 +22,20 @@ public class StaticAbilityTapPowerValue {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean withToughness(final StaticAbility stAb, final Card card, final SpellAbility sa) {
|
public static boolean withToughness(final StaticAbility stAb, final Card card, final CardTraitBase ctb) {
|
||||||
if (!stAb.getParam("Value").equals("Toughness")) {
|
if (!stAb.getParam("Value").equals("Toughness")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!stAb.matchesValidParam("ValidCard", card)) {
|
if (!stAb.matchesValidParam("ValidCard", card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!stAb.matchesValidParam("ValidSA", sa)) {
|
if (!stAb.matchesValidParam("ValidSA", ctb)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMod(final Card card, SpellAbility sa) {
|
public static int getMod(final Card card, final CardTraitBase ctb) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
final Game game = card.getGame();
|
final Game game = card.getGame();
|
||||||
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
|
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
|
||||||
@@ -46,11 +46,10 @@ public class StaticAbilityTapPowerValue {
|
|||||||
if (!stAb.matchesValidParam("ValidCard", card)) {
|
if (!stAb.matchesValidParam("ValidCard", card)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!stAb.matchesValidParam("ValidSA", sa)) {
|
if (!stAb.matchesValidParam("ValidSA", ctb)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int t = Integer.parseInt(stAb.getParam("Value"));
|
i += Integer.parseInt(stAb.getParam("Value"));
|
||||||
i = i + t;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ public class TriggerBecomesTarget extends Trigger {
|
|||||||
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
||||||
sa.setTriggeringObject(AbilityKey.Source, ((SpellAbility) runParams.get(AbilityKey.SourceSA)).getHostCard());
|
sa.setTriggeringObject(AbilityKey.Source, ((SpellAbility) runParams.get(AbilityKey.SourceSA)).getHostCard());
|
||||||
sa.setTriggeringObjectsFrom(runParams, AbilityKey.SourceSA, AbilityKey.Target);
|
sa.setTriggeringObjectsFrom(runParams, AbilityKey.SourceSA, AbilityKey.Target);
|
||||||
sa.setTriggeringObject(AbilityKey.StackInstance, sa.getHostCard().getGame().getStack().getInstanceMatchingSpellAbilityID((SpellAbility) runParams.get(AbilityKey.SourceSA)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import java.util.Set;
|
|||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.game.Game;
|
|
||||||
import forge.game.GameEntity;
|
import forge.game.GameEntity;
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
@@ -35,7 +34,6 @@ import forge.game.card.CardUtil;
|
|||||||
import forge.game.mana.Mana;
|
import forge.game.mana.Mana;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.SpellAbilityStackInstance;
|
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
import forge.util.Expressions;
|
import forge.util.Expressions;
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
@@ -78,22 +76,9 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Card cast = spellAbility.getHostCard();
|
final Card cast = spellAbility.getHostCard();
|
||||||
final Game game = cast.getGame();
|
|
||||||
final SpellAbilityStackInstance si = game.getStack().getInstanceMatchingSpellAbilityID(spellAbility);
|
|
||||||
|
|
||||||
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasParam("ValidActivatingPlayer")) {
|
if (hasParam("ValidActivatingPlayer")) {
|
||||||
Player activator;
|
Player activator = (Player) runParams.get(AbilityKey.Activator);
|
||||||
if (spellAbility.isManaAbility()) {
|
|
||||||
activator = (Player) runParams.get(AbilityKey.Activator);
|
|
||||||
} else if (si == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
activator = si.getSpellAbility().getActivatingPlayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!matchesValidParam("ValidActivatingPlayer", activator)) {
|
if (!matchesValidParam("ValidActivatingPlayer", activator)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -143,9 +128,6 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
|
|||||||
|
|
||||||
if (hasParam("TargetsValid")) {
|
if (hasParam("TargetsValid")) {
|
||||||
SpellAbility sa = spellAbility;
|
SpellAbility sa = spellAbility;
|
||||||
if (si != null) {
|
|
||||||
sa = si.getSpellAbility();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean validTgtFound = false;
|
boolean validTgtFound = false;
|
||||||
while (sa != null && !validTgtFound) {
|
while (sa != null && !validTgtFound) {
|
||||||
@@ -249,13 +231,10 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
|
|||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
||||||
final SpellAbility castSA = (SpellAbility) runParams.get(AbilityKey.SpellAbility);
|
final SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.SpellAbility);
|
||||||
final SpellAbilityStackInstance si = sa.getHostCard().getGame().getStack().getInstanceMatchingSpellAbilityID(castSA);
|
sa.setTriggeringObject(AbilityKey.Card, cause.getHostCard());
|
||||||
final SpellAbility saForTargets = si != null ? si.getSpellAbility() : castSA;
|
sa.setTriggeringObject(AbilityKey.SpellAbility, cause);
|
||||||
sa.setTriggeringObject(AbilityKey.Card, castSA.getHostCard());
|
final List<TargetChoices> allTgts = cause.getAllTargetChoices();
|
||||||
sa.setTriggeringObject(AbilityKey.SpellAbility, castSA);
|
|
||||||
sa.setTriggeringObject(AbilityKey.StackInstance, si);
|
|
||||||
final List<TargetChoices> allTgts = saForTargets.getAllTargetChoices();
|
|
||||||
if (!allTgts.isEmpty()) {
|
if (!allTgts.isEmpty()) {
|
||||||
final FCollection<GameEntity> saTargets = new FCollection<>();
|
final FCollection<GameEntity> saTargets = new FCollection<>();
|
||||||
for (TargetChoices tc : allTgts) {
|
for (TargetChoices tc : allTgts) {
|
||||||
@@ -263,11 +242,10 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
|
|||||||
}
|
}
|
||||||
sa.setTriggeringObject(AbilityKey.SpellAbilityTargets, saTargets);
|
sa.setTriggeringObject(AbilityKey.SpellAbilityTargets, saTargets);
|
||||||
}
|
}
|
||||||
sa.setTriggeringObject(AbilityKey.LifeAmount, castSA.getAmountLifePaid());
|
sa.setTriggeringObject(AbilityKey.LifeAmount, cause.getAmountLifePaid());
|
||||||
sa.setTriggeringObjectsFrom(
|
sa.setTriggeringObjectsFrom(
|
||||||
runParams,
|
runParams,
|
||||||
AbilityKey.CardLKI,
|
AbilityKey.CardLKI,
|
||||||
AbilityKey.Player,
|
|
||||||
AbilityKey.Activator,
|
AbilityKey.Activator,
|
||||||
AbilityKey.CurrentStormCount,
|
AbilityKey.CurrentStormCount,
|
||||||
AbilityKey.CurrentCastSpells
|
AbilityKey.CurrentCastSpells
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
addAbilityActivatedThisTurn(sp, source);
|
addAbilityActivatedThisTurn(sp, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(source.getController());
|
Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||||
runParams.put(AbilityKey.Activator, activator);
|
runParams.put(AbilityKey.Activator, activator);
|
||||||
runParams.put(AbilityKey.SpellAbility, sp);
|
runParams.put(AbilityKey.SpellAbility, sp);
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCast, runParams, true);
|
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCast, runParams, true);
|
||||||
@@ -355,7 +355,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
si = push(sp, si, id);
|
si = push(sp, si, id);
|
||||||
|
|
||||||
// Copied spells aren't cast per se so triggers shouldn't run for them.
|
// Copied spells aren't cast per se so triggers shouldn't run for them.
|
||||||
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(sp.getHostCard().getController());
|
Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||||
|
|
||||||
if (sp.isSpell() && !sp.isCopied()) {
|
if (sp.isSpell() && !sp.isCopied()) {
|
||||||
final Card lki = CardCopyService.getLKICopy(sp.getHostCard());
|
final Card lki = CardCopyService.getLKICopy(sp.getHostCard());
|
||||||
@@ -394,7 +394,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
runParams.put(AbilityKey.Activator, sp.getActivatingPlayer());
|
runParams.put(AbilityKey.Activator, sp.getActivatingPlayer());
|
||||||
runParams.put(AbilityKey.SpellAbility, si.getSpellAbility());
|
runParams.put(AbilityKey.SpellAbility, sp);
|
||||||
runParams.put(AbilityKey.CurrentStormCount, thisTurnCast.size());
|
runParams.put(AbilityKey.CurrentStormCount, thisTurnCast.size());
|
||||||
runParams.put(AbilityKey.CurrentCastSpells, Lists.newArrayList(thisTurnCast));
|
runParams.put(AbilityKey.CurrentCastSpells, Lists.newArrayList(thisTurnCast));
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ public enum TrackableProperty {
|
|||||||
|
|
||||||
//Card State
|
//Card State
|
||||||
Name(TrackableTypes.StringType),
|
Name(TrackableTypes.StringType),
|
||||||
Artist(TrackableTypes.StringType),
|
|
||||||
Colors(TrackableTypes.ColorSetType),
|
Colors(TrackableTypes.ColorSetType),
|
||||||
OriginalColors(TrackableTypes.ColorSetType),
|
OriginalColors(TrackableTypes.ColorSetType),
|
||||||
LeftSplitColors(TrackableTypes.ColorSetType),
|
LeftSplitColors(TrackableTypes.ColorSetType),
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
|||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.mortennobel.imagescaling.ResampleOp;
|
import com.mortennobel.imagescaling.ResampleOp;
|
||||||
|
|
||||||
import forge.card.CardEdition;
|
import forge.card.CardSplitType;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardView;
|
import forge.game.card.CardView;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
@@ -56,8 +56,8 @@ import forge.model.FModel;
|
|||||||
import forge.toolbox.FSkin;
|
import forge.toolbox.FSkin;
|
||||||
import forge.toolbox.FSkin.SkinIcon;
|
import forge.toolbox.FSkin.SkinIcon;
|
||||||
import forge.toolbox.imaging.FCardImageRenderer;
|
import forge.toolbox.imaging.FCardImageRenderer;
|
||||||
import forge.util.Aggregates;
|
|
||||||
import forge.util.ImageUtil;
|
import forge.util.ImageUtil;
|
||||||
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class stores ALL card images in a cache with soft values. this means
|
* This class stores ALL card images in a cache with soft values. this means
|
||||||
@@ -171,41 +171,65 @@ public class ImageCache {
|
|||||||
|
|
||||||
IPaperCard ipc = null;
|
IPaperCard ipc = null;
|
||||||
boolean altState = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
boolean altState = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
||||||
boolean useArtCrop = "Crop".equals(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_CARD_ART_FORMAT));
|
String specColor = "";
|
||||||
String fileName = imageKey;
|
if (imageKey.endsWith(ImageKeys.SPECFACE_W)) {
|
||||||
|
specColor = "white";
|
||||||
|
} else if (imageKey.endsWith(ImageKeys.SPECFACE_U)) {
|
||||||
|
specColor = "blue";
|
||||||
|
} else if (imageKey.endsWith(ImageKeys.SPECFACE_B)) {
|
||||||
|
specColor = "black";
|
||||||
|
} else if (imageKey.endsWith(ImageKeys.SPECFACE_R)) {
|
||||||
|
specColor = "red";
|
||||||
|
} else if (imageKey.endsWith(ImageKeys.SPECFACE_G)) {
|
||||||
|
specColor = "green";
|
||||||
|
}
|
||||||
if (altState)
|
if (altState)
|
||||||
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
||||||
|
if (!specColor.isEmpty())
|
||||||
|
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.SPECFACE_W.length());
|
||||||
if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) {
|
if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) {
|
||||||
String[] tempdata = imageKey.substring(2).split("\\|"); //We want to check the edition first.
|
ipc = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||||
|
if (ipc != null) {
|
||||||
String name = tempdata[0];
|
if (altState) {
|
||||||
String setCode = tempdata.length > 1 ? tempdata[1] : CardEdition.UNKNOWN_CODE;
|
imageKey = ipc.getCardAltImageKey();
|
||||||
String collectorNumber = tempdata.length > 3 ? tempdata[2] : IPaperCard.NO_COLLECTOR_NUMBER;
|
} else if (!specColor.isEmpty()) {
|
||||||
|
switch (specColor) {
|
||||||
CardEdition edition = StaticData.instance().getEditions().get(setCode);
|
case "white":
|
||||||
|
imageKey = ipc.getCardWSpecImageKey();
|
||||||
if (useArtCrop) {
|
break;
|
||||||
CardEdition.EditionEntry ee;
|
case "blue":
|
||||||
if (!collectorNumber.isEmpty() && !collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)) {
|
imageKey = ipc.getCardUSpecImageKey();
|
||||||
ee = edition.getCardFromCollectorNumber(collectorNumber);
|
break;
|
||||||
if (ee != null) { // TODO handle Specialize Collector number
|
case "black":
|
||||||
ee = edition.getCardFromCollectorNumber(collectorNumber.substring(0, collectorNumber.length() - 1));
|
imageKey = ipc.getCardBSpecImageKey();
|
||||||
|
break;
|
||||||
|
case "red":
|
||||||
|
imageKey = ipc.getCardRSpecImageKey();
|
||||||
|
break;
|
||||||
|
case "green":
|
||||||
|
imageKey = ipc.getCardGSpecImageKey();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ee = Aggregates.random(edition.getCardInSet(name));
|
imageKey = ipc.getCardImageKey();
|
||||||
}
|
}
|
||||||
|
if (StringUtils.isBlank(imageKey))
|
||||||
// Skip fetching if artist info is not available for art crop
|
return Pair.of(_defaultImage, true);
|
||||||
if (ee != null && ee.artistName().isEmpty()) {
|
|
||||||
useArtCrop = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ipc = StaticData.instance().fetchCard(name, setCode, collectorNumber);
|
|
||||||
|
|
||||||
fileName = ImageUtil.getImageRelativePath(name, setCode, collectorNumber, useArtCrop);
|
|
||||||
} // TODO add artCrop for Token
|
|
||||||
|
|
||||||
|
// Replace .full to .artcrop if art crop is preferred
|
||||||
|
// Only allow use art if the artist info is available
|
||||||
|
boolean useArtCrop = "Crop".equals(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_CARD_ART_FORMAT))
|
||||||
|
&& ipc != null && !ipc.getArtist().isEmpty();
|
||||||
String originalKey = imageKey;
|
String originalKey = imageKey;
|
||||||
|
if (useArtCrop) {
|
||||||
|
if (ipc != null && ipc.getRules().getSplitType() == CardSplitType.Flip) {
|
||||||
|
// Art crop will always use front face as image key for flip cards
|
||||||
|
imageKey = ipc.getCardImageKey();
|
||||||
|
}
|
||||||
|
imageKey = TextUtil.fastReplace(imageKey, ".full", ".artcrop");
|
||||||
|
}
|
||||||
|
|
||||||
// Load from file and add to cache if not found in cache initially.
|
// Load from file and add to cache if not found in cache initially.
|
||||||
BufferedImage original = getImage(imageKey);
|
BufferedImage original = getImage(imageKey);
|
||||||
@@ -215,11 +239,16 @@ public class ImageCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if art crop is exist, check also if the full card image is also cached.
|
// if art crop is exist, check also if the full card image is also cached.
|
||||||
|
if (useArtCrop && original != null) {
|
||||||
|
BufferedImage cached = _CACHE.getIfPresent(originalKey);
|
||||||
|
if (cached != null)
|
||||||
|
return Pair.of(cached, false);
|
||||||
|
}
|
||||||
|
|
||||||
boolean noBorder = !useArtCrop && !isPreferenceEnabled(ForgePreferences.FPref.UI_RENDER_BLACK_BORDERS);
|
boolean noBorder = !useArtCrop && !isPreferenceEnabled(ForgePreferences.FPref.UI_RENDER_BLACK_BORDERS);
|
||||||
boolean fetcherEnabled = isPreferenceEnabled(ForgePreferences.FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER);
|
boolean fetcherEnabled = isPreferenceEnabled(ForgePreferences.FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER);
|
||||||
boolean isPlaceholder = (original == null) && fetcherEnabled;
|
boolean isPlaceholder = (original == null) && fetcherEnabled;
|
||||||
String setCode = fileName.split("/")[0].trim().toUpperCase();
|
String setCode = imageKey.split("/")[0].trim().toUpperCase();
|
||||||
|
|
||||||
// If the user has indicated that they prefer Forge NOT render a black border, round the image corners
|
// If the user has indicated that they prefer Forge NOT render a black border, round the image corners
|
||||||
// to account for JPEG images that don't have a transparency.
|
// to account for JPEG images that don't have a transparency.
|
||||||
@@ -272,7 +301,7 @@ public class ImageCache {
|
|||||||
CardView card = ipc != null ? Card.getCardForUi(ipc).getView() : cardView;
|
CardView card = ipc != null ? Card.getCardForUi(ipc).getView() : cardView;
|
||||||
String legalString = null;
|
String legalString = null;
|
||||||
original = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
original = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
if (art != null && ipc != null) {
|
if (art != null) {
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
cal.setTime(StaticData.instance().getCardEdition(ipc.getEdition()).getDate());
|
cal.setTime(StaticData.instance().getCardEdition(ipc.getEdition()).getDate());
|
||||||
int year = cal.get(Calendar.YEAR);
|
int year = cal.get(Calendar.YEAR);
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ final class ImageLoader extends CacheLoader<String, BufferedImage> {
|
|||||||
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
|
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
boolean useArtCrop = "Crop".equals(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_CARD_ART_FORMAT));
|
File file = ImageKeys.getImageFile(key);
|
||||||
File file = ImageKeys.getImageFile(key, useArtCrop);
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -77,11 +77,41 @@ public final class FImageUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean altState = key.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
boolean altState = key.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
||||||
|
String specColor = "";
|
||||||
|
if (key.endsWith(ImageKeys.SPECFACE_W)) {
|
||||||
|
specColor = "white";
|
||||||
|
} else if (key.endsWith(ImageKeys.SPECFACE_U)) {
|
||||||
|
specColor = "blue";
|
||||||
|
} else if (key.endsWith(ImageKeys.SPECFACE_B)) {
|
||||||
|
specColor = "black";
|
||||||
|
} else if (key.endsWith(ImageKeys.SPECFACE_R)) {
|
||||||
|
specColor = "red";
|
||||||
|
} else if (key.endsWith(ImageKeys.SPECFACE_G)) {
|
||||||
|
specColor = "green";
|
||||||
|
}
|
||||||
String imageKey = key;
|
String imageKey = key;
|
||||||
if (prefix.equals(ImageKeys.CARD_PREFIX)) {
|
if (prefix.equals(ImageKeys.CARD_PREFIX)) {
|
||||||
PaperCard card = ImageUtil.getPaperCardFromImageKey(key);
|
PaperCard card = ImageUtil.getPaperCardFromImageKey(key);
|
||||||
if (altState) {
|
if (altState) {
|
||||||
imageKey = card.getCardAltImageKey();
|
imageKey = card.getCardAltImageKey();
|
||||||
|
} else if (!specColor.isEmpty()) {
|
||||||
|
switch (specColor) {
|
||||||
|
case "white":
|
||||||
|
imageKey = card.getCardWSpecImageKey();
|
||||||
|
break;
|
||||||
|
case "blue":
|
||||||
|
imageKey = card.getCardUSpecImageKey();
|
||||||
|
break;
|
||||||
|
case "black":
|
||||||
|
imageKey = card.getCardBSpecImageKey();
|
||||||
|
break;
|
||||||
|
case "red":
|
||||||
|
imageKey = card.getCardRSpecImageKey();
|
||||||
|
break;
|
||||||
|
case "green":
|
||||||
|
imageKey = card.getCardGSpecImageKey();
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
imageKey = card.getCardImageKey();
|
imageKey = card.getCardImageKey();
|
||||||
}
|
}
|
||||||
@@ -89,6 +119,9 @@ public final class FImageUtil {
|
|||||||
if(altState) {
|
if(altState) {
|
||||||
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
||||||
imageKey += "full.jpg";
|
imageKey += "full.jpg";
|
||||||
|
} else if (!specColor.isEmpty()) {
|
||||||
|
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.SPECFACE_W.length());
|
||||||
|
imageKey += "full.jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
File file = ImageKeys.getImageFile(imageKey);
|
File file = ImageKeys.getImageFile(imageKey);
|
||||||
|
|||||||
@@ -34,14 +34,10 @@ public class SwingImageFetcher extends ImageFetcher {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String newdespath = destPath;
|
String newdespath = urlToDownload.contains(".fullborder.jpg") || urlToDownload.startsWith(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD) ?
|
||||||
if (!destPath.contains(".artcrop")) {
|
|
||||||
newdespath = urlToDownload.contains(".fullborder.jpg") || urlToDownload.startsWith(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD) ?
|
|
||||||
TextUtil.fastReplace(destPath, ".full.jpg", ".fullborder.jpg") : destPath;
|
TextUtil.fastReplace(destPath, ".full.jpg", ".fullborder.jpg") : destPath;
|
||||||
if (!newdespath.contains(".full") && urlToDownload.startsWith(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD) && !destPath.startsWith(ForgeConstants.CACHE_TOKEN_PICS_DIR))
|
if (!newdespath.contains(".full") && urlToDownload.startsWith(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD) && !destPath.startsWith(ForgeConstants.CACHE_TOKEN_PICS_DIR))
|
||||||
newdespath = newdespath.replace(".jpg", ".fullborder.jpg"); //fix planes/phenomenon for round border options
|
newdespath = newdespath.replace(".jpg", ".fullborder.jpg"); //fix planes/phenomenon for round border options
|
||||||
}
|
|
||||||
|
|
||||||
URL url = new URL(urlToDownload);
|
URL url = new URL(urlToDownload);
|
||||||
System.out.println("Attempting to fetch: " + url);
|
System.out.println("Attempting to fetch: " + url);
|
||||||
BufferedImage image = ImageIO.read(url);
|
BufferedImage image = ImageIO.read(url);
|
||||||
|
|||||||
@@ -274,6 +274,14 @@ public class Forge implements ApplicationListener {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasExternalInput() {
|
||||||
|
return hasGamepad() || hasKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasKeyboard() {
|
||||||
|
return !GuiBase.isAndroid();
|
||||||
|
}
|
||||||
|
|
||||||
public static InputProcessor getInputProcessor() {
|
public static InputProcessor getInputProcessor() {
|
||||||
return inputProcessor;
|
return inputProcessor;
|
||||||
}
|
}
|
||||||
@@ -1235,8 +1243,16 @@ public class Forge implements ApplicationListener {
|
|||||||
if (keyInputAdapter != null) {
|
if (keyInputAdapter != null) {
|
||||||
return keyInputAdapter.keyUp(keyCode);
|
return keyInputAdapter.keyUp(keyCode);
|
||||||
}
|
}
|
||||||
|
// if no active key input adapter, give current screen or overlay a chance to handle key
|
||||||
|
FContainer container = FOverlay.getTopOverlay();
|
||||||
|
if (container == null) {
|
||||||
|
container = currentScreen;
|
||||||
|
if (container == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return container.keyUp(keyCode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyTyped(char ch) {
|
public boolean keyTyped(char ch) {
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ public class EnemySprite extends CharacterSprite implements Steerable<Vector2> {
|
|||||||
if (data.copyPlayerDeck && Current.latestDeck() != null) {
|
if (data.copyPlayerDeck && Current.latestDeck() != null) {
|
||||||
List<PaperCard> paperCardList = Current.latestDeck().getMain().toFlatList().stream()
|
List<PaperCard> paperCardList = Current.latestDeck().getMain().toFlatList().stream()
|
||||||
.filter(paperCard -> !paperCard.isVeryBasicLand())
|
.filter(paperCard -> !paperCard.isVeryBasicLand())
|
||||||
.toList();
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
if (paperCardList.size() < 6) {
|
if (paperCardList.size() < 6) {
|
||||||
// Player trying to cheese doppleganger and farm cards. Sorry, the fun police have arrived
|
// Player trying to cheese doppleganger and farm cards. Sorry, the fun police have arrived
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ import java.util.*;
|
|||||||
* Class that represents the player (not the player sprite)
|
* Class that represents the player (not the player sprite)
|
||||||
*/
|
*/
|
||||||
public class AdventurePlayer implements Serializable, SaveFileContent {
|
public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||||
public static final int NUMBER_OF_DECKS = 10;
|
public static final int MIN_DECK_COUNT = 10;
|
||||||
|
// this is a purely arbitrary limit, could be higher or lower; just meant as some sort of reasonable limit for the user
|
||||||
|
public static final int MAX_DECK_COUNT = 20;
|
||||||
// Player profile data.
|
// Player profile data.
|
||||||
private String name;
|
private String name;
|
||||||
private int heroRace;
|
private int heroRace;
|
||||||
@@ -45,7 +47,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
|
|
||||||
// Deck data
|
// Deck data
|
||||||
private Deck deck;
|
private Deck deck;
|
||||||
private final Deck[] decks = new Deck[NUMBER_OF_DECKS];
|
private final ArrayList<Deck> decks = new ArrayList<Deck>(MIN_DECK_COUNT);
|
||||||
private int selectedDeckIndex = 0;
|
private int selectedDeckIndex = 0;
|
||||||
private final DifficultyData difficultyData = new DifficultyData();
|
private final DifficultyData difficultyData = new DifficultyData();
|
||||||
|
|
||||||
@@ -91,9 +93,13 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
return statistic;
|
return statistic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDeckCount() { return decks.size(); }
|
||||||
|
|
||||||
private void clearDecks() {
|
private void clearDecks() {
|
||||||
for (int i = 0; i < NUMBER_OF_DECKS; i++) decks[i] = new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck"));
|
decks.clear();
|
||||||
deck = decks[0];
|
for (int i = 0; i < MIN_DECK_COUNT; i++)
|
||||||
|
decks.add(new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck")));
|
||||||
|
deck = decks.get(0);
|
||||||
selectedDeckIndex = 0;
|
selectedDeckIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +146,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
announceCustom = usingCustomDeck = isUsingCustomDeck;
|
announceCustom = usingCustomDeck = isUsingCustomDeck;
|
||||||
|
|
||||||
deck = startingDeck;
|
deck = startingDeck;
|
||||||
decks[0] = deck;
|
decks.set(0, deck);
|
||||||
|
|
||||||
cards.addAllFlat(deck.getAllCardsInASinglePool().toFlatList());
|
cards.addAllFlat(deck.getAllCardsInASinglePool().toFlatList());
|
||||||
|
|
||||||
@@ -173,9 +179,9 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSelectedDeckSlot(int slot) {
|
public void setSelectedDeckSlot(int slot) {
|
||||||
if (slot >= 0 && slot < NUMBER_OF_DECKS) {
|
if (slot >= 0 && slot < getDeckCount()) {
|
||||||
selectedDeckIndex = slot;
|
selectedDeckIndex = slot;
|
||||||
deck = decks[selectedDeckIndex];
|
deck = decks.get(selectedDeckIndex);
|
||||||
setColorIdentity(DeckProxy.getColorIdentity(deck));
|
setColorIdentity(DeckProxy.getColorIdentity(deck));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,7 +220,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Deck getDeck(int index) {
|
public Deck getDeck(int index) {
|
||||||
return decks[index];
|
return decks.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardPool getCards() {
|
public CardPool getCards() {
|
||||||
@@ -448,17 +454,44 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NUMBER_OF_DECKS; i++) {
|
// load decks
|
||||||
|
// check if this save has dynamic deck count, use set-count load if not
|
||||||
|
boolean hasDynamicDeckCount = data.containsKey("deckCount");
|
||||||
|
if (hasDynamicDeckCount) {
|
||||||
|
int dynamicDeckCount = data.readInt("deckCount");
|
||||||
|
// in case the save had previously saved more decks than the current version allows (in case of the max being lowered)
|
||||||
|
dynamicDeckCount = Math.min(MAX_DECK_COUNT, dynamicDeckCount);
|
||||||
|
for (int i = 0; i < dynamicDeckCount; i++){
|
||||||
|
// the first x elements are pre-created
|
||||||
|
if (i < MIN_DECK_COUNT) {
|
||||||
|
decks.set(i, new Deck(data.readString("deck_name_" + i)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
decks.add(new Deck(data.readString("deck_name_" + i)));
|
||||||
|
}
|
||||||
|
decks.get(i).getMain().addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("deck_" + i))));
|
||||||
|
if (data.containsKey("sideBoardCards_" + i))
|
||||||
|
decks.get(i).getOrCreate(DeckSection.Sideboard).addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("sideBoardCards_" + i))));
|
||||||
|
}
|
||||||
|
// in case we allow removing decks from the deck selection GUI, populate up to the minimum
|
||||||
|
for (int i = dynamicDeckCount++; i < MIN_DECK_COUNT; i++) {
|
||||||
|
decks.set(i, new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck")));
|
||||||
|
}
|
||||||
|
// legacy load
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < MIN_DECK_COUNT; i++) {
|
||||||
if (!data.containsKey("deck_name_" + i)) {
|
if (!data.containsKey("deck_name_" + i)) {
|
||||||
if (i == 0) decks[i] = deck;
|
if (i == 0) decks.set(i, deck);
|
||||||
else decks[i] = new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck"));
|
else decks.set(i, new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck")));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
decks[i] = new Deck(data.readString("deck_name_" + i));
|
decks.set(i, new Deck(data.readString("deck_name_" + i)));
|
||||||
decks[i].getMain().addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("deck_" + i))));
|
decks.get(i).getMain().addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("deck_" + i))));
|
||||||
if (data.containsKey("sideBoardCards_" + i))
|
if (data.containsKey("sideBoardCards_" + i))
|
||||||
decks[i].getOrCreate(DeckSection.Sideboard).addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("sideBoardCards_" + i))));
|
decks.get(i).getOrCreate(DeckSection.Sideboard).addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("sideBoardCards_" + i))));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setSelectedDeckSlot(data.readInt("selectedDeckIndex"));
|
setSelectedDeckSlot(data.readInt("selectedDeckIndex"));
|
||||||
cards.addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("cards"))));
|
cards.addAll(CardPool.fromCardList(Lists.newArrayList((String[]) data.readObject("cards"))));
|
||||||
|
|
||||||
@@ -602,11 +635,14 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
data.storeObject("deckCards", deck.getMain().toCardList("\n").split("\n"));
|
data.storeObject("deckCards", deck.getMain().toCardList("\n").split("\n"));
|
||||||
if (deck.get(DeckSection.Sideboard) != null)
|
if (deck.get(DeckSection.Sideboard) != null)
|
||||||
data.storeObject("sideBoardCards", deck.get(DeckSection.Sideboard).toCardList("\n").split("\n"));
|
data.storeObject("sideBoardCards", deck.get(DeckSection.Sideboard).toCardList("\n").split("\n"));
|
||||||
for (int i = 0; i < NUMBER_OF_DECKS; i++) {
|
|
||||||
data.store("deck_name_" + i, decks[i].getName());
|
// save decks dynamically
|
||||||
data.storeObject("deck_" + i, decks[i].getMain().toCardList("\n").split("\n"));
|
data.store("deckCount", getDeckCount());
|
||||||
if (decks[i].get(DeckSection.Sideboard) != null)
|
for (int i = 0; i < getDeckCount(); i++) {
|
||||||
data.storeObject("sideBoardCards_" + i, decks[i].get(DeckSection.Sideboard).toCardList("\n").split("\n"));
|
data.store("deck_name_" + i, decks.get(i).getName());
|
||||||
|
data.storeObject("deck_" + i, decks.get(i).getMain().toCardList("\n").split("\n"));
|
||||||
|
if (decks.get(i).get(DeckSection.Sideboard) != null)
|
||||||
|
data.storeObject("sideBoardCards_" + i, decks.get(i).get(DeckSection.Sideboard).toCardList("\n").split("\n"));
|
||||||
}
|
}
|
||||||
data.store("selectedDeckIndex", selectedDeckIndex);
|
data.store("selectedDeckIndex", selectedDeckIndex);
|
||||||
data.storeObject("cards", cards.toCardList("\n").split("\n"));
|
data.storeObject("cards", cards.toCardList("\n").split("\n"));
|
||||||
@@ -933,7 +969,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
|
|
||||||
public void renameDeck(String text) {
|
public void renameDeck(String text) {
|
||||||
deck = (Deck) deck.copyTo(text);
|
deck = (Deck) deck.copyTo(text);
|
||||||
decks[selectedDeckIndex] = deck;
|
decks.set(selectedDeckIndex, deck);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int cardSellPrice(PaperCard card) {
|
public int cardSellPrice(PaperCard card) {
|
||||||
@@ -1182,10 +1218,23 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a deck by replacing the current selected deck with a new deck
|
* Clears a deck by replacing the current selected deck with a new deck
|
||||||
|
*/
|
||||||
|
public void clearDeck() {
|
||||||
|
deck = decks.set(selectedDeckIndex, new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually removes the deck from the list of decks.
|
||||||
*/
|
*/
|
||||||
public void deleteDeck(){
|
public void deleteDeck(){
|
||||||
deck = decks[selectedDeckIndex] = new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck"));
|
int oldIndex = selectedDeckIndex;
|
||||||
|
this.setSelectedDeckSlot(0);
|
||||||
|
decks.remove(oldIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDeck(){
|
||||||
|
decks.add(new Deck(Forge.getLocalizer().getMessage("lblEmptyDeck")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1194,9 +1243,9 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
* @return int - index of new copy slot, or -1 if no slot was available
|
* @return int - index of new copy slot, or -1 if no slot was available
|
||||||
*/
|
*/
|
||||||
public int copyDeck() {
|
public int copyDeck() {
|
||||||
for (int i = 0; i < decks.length; i++) {
|
for (int i = 0; i < MAX_DECK_COUNT; i++) {
|
||||||
if (isEmptyDeck(i)) {
|
if (isEmptyDeck(i)) {
|
||||||
decks[i] = (Deck) deck.copyTo(deck.getName() + " (" + Forge.getLocalizer().getMessage("lblCopy") + ")");
|
decks.set(i, (Deck) deck.copyTo(deck.getName() + " (" + Forge.getLocalizer().getMessage("lblCopy") + ")"));
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1205,7 +1254,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmptyDeck(int deckIndex) {
|
public boolean isEmptyDeck(int deckIndex) {
|
||||||
return decks[deckIndex].isEmpty() && decks[deckIndex].getName().equals(Forge.getLocalizer().getMessage("lblEmptyDeck"));
|
return decks.get(deckIndex).isEmpty() && decks.get(deckIndex).getName().equals(Forge.getLocalizer().getMessage("lblEmptyDeck"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEvent(AdventureEventData completedEvent) {
|
public void removeEvent(AdventureEventData completedEvent) {
|
||||||
@@ -1227,8 +1276,8 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
|||||||
|
|
||||||
// 2. Count max cards across all decks in excess of unsellable
|
// 2. Count max cards across all decks in excess of unsellable
|
||||||
Map<PaperCard, Integer> maxCardCounts = new HashMap<>();
|
Map<PaperCard, Integer> maxCardCounts = new HashMap<>();
|
||||||
for (int i = 0; i < NUMBER_OF_DECKS; i++) {
|
for (int i = 0; i < getDeckCount(); i++) {
|
||||||
for (final Map.Entry<PaperCard, Integer> cp : decks[i].getAllCardsInASinglePool()) {
|
for (final Map.Entry<PaperCard, Integer> cp : decks.get(i).getAllCardsInASinglePool()) {
|
||||||
int count = cp.getValue();
|
int count = cp.getValue();
|
||||||
if (count > maxCardCounts.getOrDefault(cp.getKey(), 0)) {
|
if (count > maxCardCounts.getOrDefault(cp.getKey(), 0)) {
|
||||||
maxCardCounts.put(cp.getKey(), cp.getValue());
|
maxCardCounts.put(cp.getKey(), cp.getValue());
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public class PointOfInterestChanges implements SaveFileContent {
|
|||||||
//private final java.util.Map<Integer, Float> shopModifiers = new HashMap<>();
|
//private final java.util.Map<Integer, Float> shopModifiers = new HashMap<>();
|
||||||
private final java.util.Map<Integer, Integer> reputation = new HashMap<>();
|
private final java.util.Map<Integer, Integer> reputation = new HashMap<>();
|
||||||
private Boolean isBookmarked;
|
private Boolean isBookmarked;
|
||||||
|
private Boolean isVisited;
|
||||||
|
|
||||||
public static class Map extends HashMap<String,PointOfInterestChanges> implements SaveFileContent {
|
public static class Map extends HashMap<String,PointOfInterestChanges> implements SaveFileContent {
|
||||||
@Override
|
@Override
|
||||||
@@ -67,6 +68,7 @@ public class PointOfInterestChanges implements SaveFileContent {
|
|||||||
reputation.putAll((java.util.Map<Integer, Integer>) data.readObject("reputation"));
|
reputation.putAll((java.util.Map<Integer, Integer>) data.readObject("reputation"));
|
||||||
}
|
}
|
||||||
isBookmarked = (Boolean) data.readObject("isBookmarked");
|
isBookmarked = (Boolean) data.readObject("isBookmarked");
|
||||||
|
isVisited = (Boolean) data.readObject("isVisited");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,6 +80,7 @@ public class PointOfInterestChanges implements SaveFileContent {
|
|||||||
data.storeObject("shopSeeds", shopSeeds);
|
data.storeObject("shopSeeds", shopSeeds);
|
||||||
data.storeObject("reputation", reputation);
|
data.storeObject("reputation", reputation);
|
||||||
data.storeObject("isBookmarked", isBookmarked);
|
data.storeObject("isBookmarked", isBookmarked);
|
||||||
|
data.storeObject("isVisited", isVisited);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,4 +180,12 @@ public class PointOfInterestChanges implements SaveFileContent {
|
|||||||
// reset map when assigning as a quest target that needs enemies
|
// reset map when assigning as a quest target that needs enemies
|
||||||
deletedObjects.clear();
|
deletedObjects.clear();
|
||||||
}
|
}
|
||||||
|
public boolean isVisited() {
|
||||||
|
if (isVisited ==null)
|
||||||
|
return false;
|
||||||
|
return isVisited;
|
||||||
|
}
|
||||||
|
public void visit() {
|
||||||
|
isVisited = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
|||||||
@Override
|
@Override
|
||||||
public void onActivate() {
|
public void onActivate() {
|
||||||
decksUsingMyCards = new ItemPool<>(InventoryItem.class);
|
decksUsingMyCards = new ItemPool<>(InventoryItem.class);
|
||||||
for (int i = 0; i < AdventurePlayer.NUMBER_OF_DECKS; i++) {
|
for (int i = 0; i < AdventurePlayer.current().getDeckCount(); i++) {
|
||||||
final Deck deck = AdventurePlayer.current().getDeck(i);
|
final Deck deck = AdventurePlayer.current().getDeck(i);
|
||||||
CardPool main = deck.getMain();
|
CardPool main = deck.getMain();
|
||||||
for (final Map.Entry<PaperCard, Integer> e : main) {
|
for (final Map.Entry<PaperCard, Integer> e : main) {
|
||||||
@@ -577,6 +577,9 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
|||||||
@Override
|
@Override
|
||||||
protected void buildMenu() {
|
protected void buildMenu() {
|
||||||
addItem(new FMenuItem(Forge.getLocalizer().getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, e1 -> FDeckViewer.copyDeckToClipboard(getDeck())));
|
addItem(new FMenuItem(Forge.getLocalizer().getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, e1 -> FDeckViewer.copyDeckToClipboard(getDeck())));
|
||||||
|
addItem(new FMenuItem(Forge.getLocalizer().getMessage("btnCopyCollectionToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, e1 -> {
|
||||||
|
FDeckViewer.copyCollectionToClipboard(AdventurePlayer.current().getCards());
|
||||||
|
}));
|
||||||
if (allowsAddBasic()) {
|
if (allowsAddBasic()) {
|
||||||
FMenuItem addBasic = new FMenuItem(Forge.getLocalizer().getMessage("lblAddBasicLands"), FSkinImage.LANDLOGO, e1 -> launchBasicLandDialog());
|
FMenuItem addBasic = new FMenuItem(Forge.getLocalizer().getMessage("lblAddBasicLands"), FSkinImage.LANDLOGO, e1 -> launchBasicLandDialog());
|
||||||
addItem(addBasic);
|
addItem(addBasic);
|
||||||
@@ -649,6 +652,8 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
|||||||
Map<String, CardEdition> editionsByName = new HashMap<>();
|
Map<String, CardEdition> editionsByName = new HashMap<>();
|
||||||
for (CardEdition e : FModel.getMagicDb().getEditions()) {
|
for (CardEdition e : FModel.getMagicDb().getEditions()) {
|
||||||
editionsByName.put(e.getName().toLowerCase(), e);
|
editionsByName.put(e.getName().toLowerCase(), e);
|
||||||
|
editionsByName.put(e.getName().replace(":", "").toLowerCase(), e);
|
||||||
|
editionsByName.put(e.getName().replace("'", "").toLowerCase(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
String sketchbookPrefix = "landscape sketchbook - ";
|
String sketchbookPrefix = "landscape sketchbook - ";
|
||||||
@@ -1611,5 +1616,13 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyUp(int keyCode) {
|
||||||
|
if (keyCode == Input.Keys.ESCAPE) {
|
||||||
|
return this.tabHeader.btnBack.trigger();
|
||||||
|
}
|
||||||
|
return super.keyUp(keyCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ import forge.adventure.util.Current;
|
|||||||
|
|
||||||
public class DeckSelectScene extends UIScene {
|
public class DeckSelectScene extends UIScene {
|
||||||
private final IntMap<TextraButton> buttons = new IntMap<>();
|
private final IntMap<TextraButton> buttons = new IntMap<>();
|
||||||
|
private final IntMap<Label> labels = new IntMap<>();
|
||||||
Color defColor;
|
Color defColor;
|
||||||
TextField textInput;
|
TextField textInput;
|
||||||
Table layout;
|
Table layout;
|
||||||
TextraLabel header;
|
TextraLabel header;
|
||||||
TextraButton back, edit, rename;
|
TextraButton back, edit, rename, add;
|
||||||
int currentSlot = 0;
|
int currentSlot = 0;
|
||||||
ScrollPane scrollPane;
|
ScrollPane scrollPane;
|
||||||
Dialog renameDialog;
|
Dialog renameDialog;
|
||||||
@@ -45,13 +46,13 @@ public class DeckSelectScene extends UIScene {
|
|||||||
root.add(header).colspan(2);
|
root.add(header).colspan(2);
|
||||||
root.row();
|
root.row();
|
||||||
root.add(scrollPane).expand().width(window.getWidth() - 20);
|
root.add(scrollPane).expand().width(window.getWidth() - 20);
|
||||||
for (int i = 0; i < AdventurePlayer.NUMBER_OF_DECKS; i++)
|
this.layoutDeckButtons();
|
||||||
addDeckSlot(Forge.getLocalizer().getMessage("lblDeck") + ": " + (i + 1), i);
|
|
||||||
|
|
||||||
textInput = Controls.newTextField("");
|
textInput = Controls.newTextField("");
|
||||||
back = ui.findActor("return");
|
back = ui.findActor("return");
|
||||||
edit = ui.findActor("edit");
|
edit = ui.findActor("edit");
|
||||||
rename = ui.findActor("rename");
|
rename = ui.findActor("rename");
|
||||||
|
add = ui.findActor("add");
|
||||||
ui.onButtonPress("return", DeckSelectScene.this::back);
|
ui.onButtonPress("return", DeckSelectScene.this::back);
|
||||||
ui.onButtonPress("edit", DeckSelectScene.this::edit);
|
ui.onButtonPress("edit", DeckSelectScene.this::edit);
|
||||||
ui.onButtonPress("rename", () -> {
|
ui.onButtonPress("rename", () -> {
|
||||||
@@ -59,11 +60,44 @@ public class DeckSelectScene extends UIScene {
|
|||||||
showRenameDialog();
|
showRenameDialog();
|
||||||
});
|
});
|
||||||
ui.onButtonPress("copy", DeckSelectScene.this::copy);
|
ui.onButtonPress("copy", DeckSelectScene.this::copy);
|
||||||
ui.onButtonPress("delete", DeckSelectScene.this::maybeDelete);
|
ui.onButtonPress("delete", DeckSelectScene.this::promptDelete);
|
||||||
|
ui.onButtonPress("add", DeckSelectScene.this::addDeck);
|
||||||
defColor = ui.findActor("return").getColor();
|
defColor = ui.findActor("return").getColor();
|
||||||
window.add(root);
|
window.add(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void refreshDeckButtons(){
|
||||||
|
clearDeckButtons();
|
||||||
|
layoutDeckButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearDeckButtons(){
|
||||||
|
int count = AdventurePlayer.current().getDeckCount();
|
||||||
|
for (int i = count; i >= 0; i--){
|
||||||
|
clearDeckButton(i);
|
||||||
|
}
|
||||||
|
layout.clearChildren();
|
||||||
|
buttons.clear();
|
||||||
|
labels.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void layoutDeckButtons() {
|
||||||
|
for (int i = 0; i < AdventurePlayer.current().getDeckCount(); i++)
|
||||||
|
addDeckButton(Forge.getLocalizer().getMessage("lblDeck") + ": " + (i + 1), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDeck(){
|
||||||
|
if (Current.player().getDeckCount() >= AdventurePlayer.MAX_DECK_COUNT){
|
||||||
|
showDialog(createGenericDialog(Forge.getLocalizer().getMessage("lblAddDeck"), Forge.getLocalizer().getMessage("lblMaxDeckCountReached"),
|
||||||
|
Forge.getLocalizer().getMessage("lblOK"), null, this::removeDialog, null));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Current.player().addDeck();
|
||||||
|
refreshDeckButtons();
|
||||||
|
select(Current.player().getSelectedDeckIndex());
|
||||||
|
}
|
||||||
|
|
||||||
private void copy() {
|
private void copy() {
|
||||||
if (Current.player().isEmptyDeck(currentSlot)) return;
|
if (Current.player().isEmptyDeck(currentSlot)) return;
|
||||||
int index = Current.player().copyDeck();
|
int index = Current.player().copyDeck();
|
||||||
@@ -79,17 +113,32 @@ public class DeckSelectScene extends UIScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeDelete() {
|
private void promptDelete() {
|
||||||
if (Current.player().isEmptyDeck(currentSlot)) return;
|
|
||||||
Dialog deleteDialog = createGenericDialog(Forge.getLocalizer().getMessage("lblDelete"), Forge.getLocalizer().getMessage("lblAreYouSureProceedDelete"),
|
Dialog deleteDialog = createGenericDialog(Forge.getLocalizer().getMessage("lblDelete"), Forge.getLocalizer().getMessage("lblAreYouSureProceedDelete"),
|
||||||
Forge.getLocalizer().getMessage("lblOK"),
|
Forge.getLocalizer().getMessage("lblOK"),
|
||||||
Forge.getLocalizer().getMessage("lblAbort"), this::delete, this::removeDialog);
|
Forge.getLocalizer().getMessage("lblAbort"), this::clearOrDelete, this::removeDialog);
|
||||||
|
|
||||||
showDialog(deleteDialog);
|
showDialog(deleteDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delete() {
|
/**
|
||||||
|
* Clears or deletes the currently selected deck.
|
||||||
|
*/
|
||||||
|
private void clearOrDelete(){
|
||||||
|
if (currentSlot >= AdventurePlayer.MIN_DECK_COUNT){
|
||||||
Current.player().deleteDeck();
|
Current.player().deleteDeck();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Current.player().clearDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshDeckButtons();
|
||||||
|
select(0);
|
||||||
|
removeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clear() {
|
||||||
|
Current.player().clearDeck();
|
||||||
updateDeckButton(currentSlot);
|
updateDeckButton(currentSlot);
|
||||||
removeDialog();
|
removeDialog();
|
||||||
}
|
}
|
||||||
@@ -117,7 +166,18 @@ public class DeckSelectScene extends UIScene {
|
|||||||
showDialog(renameDialog);
|
showDialog(renameDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextraButton addDeckSlot(String name, int i) {
|
/**
|
||||||
|
* Not sure if this is strictly necessary in Java but wouldn't want to leak before clearing the layout table.
|
||||||
|
*/
|
||||||
|
private void clearDeckButton(int i){
|
||||||
|
if (buttons.containsKey(i)) {
|
||||||
|
TextraButton button = buttons.remove(i);
|
||||||
|
button.clearListeners();
|
||||||
|
button.clearActions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextraButton addDeckButton(String name, int i) {
|
||||||
TextraButton button = Controls.newTextButton("-");
|
TextraButton button = Controls.newTextButton("-");
|
||||||
button.addListener(new ClickListener() {
|
button.addListener(new ClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -131,9 +191,12 @@ public class DeckSelectScene extends UIScene {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
button.setText(Current.player().getDeck(i).getName());
|
||||||
|
Label label = Controls.newLabel(name);
|
||||||
layout.add(Controls.newLabel(name)).pad(2);
|
layout.add(Controls.newLabel(name)).pad(2);
|
||||||
layout.add(button).fill(true, false).expand(true, false).align(Align.left).expandX().pad(2);
|
layout.add(button).fill(true, false).expand(true, false).align(Align.left).expandX().pad(2);
|
||||||
buttons.put(i, button);
|
buttons.put(i, button);
|
||||||
|
labels.put(i, label);
|
||||||
addToSelectable(new Selectable(button));
|
addToSelectable(new Selectable(button));
|
||||||
layout.row();
|
layout.row();
|
||||||
return button;
|
return button;
|
||||||
@@ -158,13 +221,7 @@ public class DeckSelectScene extends UIScene {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enter() {
|
public void enter() {
|
||||||
for (int i = 0; i < AdventurePlayer.NUMBER_OF_DECKS; i++) {
|
refreshDeckButtons();
|
||||||
if (buttons.containsKey(i)) {
|
|
||||||
buttons.get(i).setText(Current.player().getDeck(i).getName());
|
|
||||||
buttons.get(i).getTextraLabel().layout();
|
|
||||||
buttons.get(i).layout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GameHUD.getInstance().switchAudio();
|
GameHUD.getInstance().switchAudio();
|
||||||
select(Current.player().getSelectedDeckIndex());
|
select(Current.player().getSelectedDeckIndex());
|
||||||
performTouch(scrollPane); //can use mouse wheel if available to scroll after selection
|
performTouch(scrollPane); //can use mouse wheel if available to scroll after selection
|
||||||
@@ -175,9 +232,7 @@ public class DeckSelectScene extends UIScene {
|
|||||||
private void rename() {
|
private void rename() {
|
||||||
String text = textInput.getText();
|
String text = textInput.getText();
|
||||||
Current.player().renameDeck(text);
|
Current.player().renameDeck(text);
|
||||||
buttons.get(currentSlot).setText(Current.player().getDeck(currentSlot).getName());
|
updateDeckButton(currentSlot);
|
||||||
buttons.get(currentSlot).getTextraLabel().layout();
|
|
||||||
buttons.get(currentSlot).layout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void edit() {
|
private void edit() {
|
||||||
|
|||||||
@@ -511,13 +511,11 @@ public class EventScene extends MenuScene implements IAfterMatch {
|
|||||||
|
|
||||||
if (match.p1 instanceof AdventureEventData.AdventureEventHuman) {
|
if (match.p1 instanceof AdventureEventData.AdventureEventHuman) {
|
||||||
humanMatch = match;
|
humanMatch = match;
|
||||||
continue;
|
|
||||||
} else if (match.p2 instanceof AdventureEventData.AdventureEventHuman) {
|
} else if (match.p2 instanceof AdventureEventData.AdventureEventHuman) {
|
||||||
AdventureEventData.AdventureEventParticipant placeholder = match.p1;
|
AdventureEventData.AdventureEventParticipant placeholder = match.p1;
|
||||||
match.p1 = match.p2;
|
match.p1 = match.p2;
|
||||||
match.p2 = placeholder;
|
match.p2 = placeholder;
|
||||||
humanMatch = match;
|
humanMatch = match;
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
//Todo: Actually run match simulation here
|
//Todo: Actually run match simulation here
|
||||||
if (MyRandom.percentTrue(50)) {
|
if (MyRandom.percentTrue(50)) {
|
||||||
@@ -530,7 +528,6 @@ public class EventScene extends MenuScene implements IAfterMatch {
|
|||||||
match.winner = match.p2;
|
match.winner = match.p2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (humanMatch != null && humanMatch.round != currentEvent.currentRound)
|
if (humanMatch != null && humanMatch.round != currentEvent.currentRound)
|
||||||
@@ -539,15 +536,17 @@ public class EventScene extends MenuScene implements IAfterMatch {
|
|||||||
DuelScene duelScene = DuelScene.instance();
|
DuelScene duelScene = DuelScene.instance();
|
||||||
EnemySprite enemy = humanMatch.p2.getSprite();
|
EnemySprite enemy = humanMatch.p2.getSprite();
|
||||||
currentEvent.nextOpponent = humanMatch.p2;
|
currentEvent.nextOpponent = humanMatch.p2;
|
||||||
|
advance.setDisabled(true);
|
||||||
FThreads.invokeInEdtNowOrLater(() -> Forge.setTransitionScreen(new TransitionScreen(() -> {
|
FThreads.invokeInEdtNowOrLater(() -> Forge.setTransitionScreen(new TransitionScreen(() -> {
|
||||||
duelScene.initDuels(WorldStage.getInstance().getPlayerSprite(), enemy, false, currentEvent);
|
duelScene.initDuels(WorldStage.getInstance().getPlayerSprite(), enemy, false, currentEvent);
|
||||||
|
advance.setDisabled(false);
|
||||||
Forge.switchScene(duelScene);
|
Forge.switchScene(duelScene);
|
||||||
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), enemy.getAtlasPath(), Current.player().getName(), enemy.getName(), humanMatch.p1.getRecord(), humanMatch.p2.getRecord())));
|
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), enemy.getAtlasPath(), Current.player().getName(), enemy.getName(), humanMatch.p1.getRecord(), humanMatch.p2.getRecord())));
|
||||||
} else {
|
} else {
|
||||||
finishRound();
|
finishRound();
|
||||||
}
|
|
||||||
advance.setDisabled(false);
|
advance.setDisabled(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AdventureEventData.AdventureEventMatch humanMatch = null;
|
AdventureEventData.AdventureEventMatch humanMatch = null;
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,20 @@ import com.badlogic.gdx.graphics.Texture;
|
|||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Group;
|
import com.badlogic.gdx.scenes.scene2d.Group;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Image;
|
import com.badlogic.gdx.scenes.scene2d.ui.Image;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
|
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
||||||
|
import com.badlogic.gdx.utils.SnapshotArray;
|
||||||
import com.github.tommyettinger.textra.TextraButton;
|
import com.github.tommyettinger.textra.TextraButton;
|
||||||
import com.github.tommyettinger.textra.TypingLabel;
|
import com.github.tommyettinger.textra.TypingLabel;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import forge.Forge;
|
import forge.Forge;
|
||||||
|
import forge.adventure.data.AdventureEventData;
|
||||||
import forge.adventure.data.AdventureQuestData;
|
import forge.adventure.data.AdventureQuestData;
|
||||||
|
import forge.adventure.player.AdventurePlayer;
|
||||||
import forge.adventure.pointofintrest.PointOfInterest;
|
import forge.adventure.pointofintrest.PointOfInterest;
|
||||||
import forge.adventure.stage.GameHUD;
|
import forge.adventure.stage.GameHUD;
|
||||||
import forge.adventure.stage.WorldStage;
|
import forge.adventure.stage.WorldStage;
|
||||||
@@ -37,6 +42,9 @@ public class MapViewScene extends UIScene {
|
|||||||
private int index = -1;
|
private int index = -1;
|
||||||
private float avatarX = 0, avatarY = 0;
|
private float avatarX = 0, avatarY = 0;
|
||||||
private Set<Vector2> positions;
|
private Set<Vector2> positions;
|
||||||
|
private final List<TypingLabel> details;
|
||||||
|
private final float maxZoom = 1.2f;
|
||||||
|
private final float minZoom = 0.25f;
|
||||||
private Set<PointOfInterest> bookmark;
|
private Set<PointOfInterest> bookmark;
|
||||||
|
|
||||||
public static MapViewScene instance() {
|
public static MapViewScene instance() {
|
||||||
@@ -49,7 +57,25 @@ public class MapViewScene extends UIScene {
|
|||||||
super(Forge.isLandscapeMode() ? "ui/map.json" : "ui/map_portrait.json");
|
super(Forge.isLandscapeMode() ? "ui/map.json" : "ui/map_portrait.json");
|
||||||
ui.onButtonPress("done", this::done);
|
ui.onButtonPress("done", this::done);
|
||||||
ui.onButtonPress("quest", this::scroll);
|
ui.onButtonPress("quest", this::scroll);
|
||||||
scroll = ui.findActor("map");
|
//TODO:Add Translations for buttons
|
||||||
|
ui.onButtonPress("details", this::details);
|
||||||
|
ui.onButtonPress("events", this::events);
|
||||||
|
ui.onButtonPress("reputation", this::reputation);
|
||||||
|
ui.onButtonPress("names", this::names);
|
||||||
|
ui.onButtonPress("zoomIn", this::zoomIn);
|
||||||
|
ui.onButtonPress("zoomOut", this::zoomOut);
|
||||||
|
scroll = new ScrollPane(null,Controls.getSkin()) {
|
||||||
|
@Override
|
||||||
|
public void addScrollListener() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
scroll.setName("map");
|
||||||
|
scroll.setActor(Controls.newTextraLabel(""));
|
||||||
|
scroll.setWidth(ui.findActor("map").getWidth());
|
||||||
|
scroll.setHeight(ui.findActor("map").getHeight());
|
||||||
|
ui.addActor(scroll);
|
||||||
|
scroll.setZIndex(1);
|
||||||
labels = Lists.newArrayList();
|
labels = Lists.newArrayList();
|
||||||
positions = Sets.newHashSet();
|
positions = Sets.newHashSet();
|
||||||
bookmark = Sets.newHashSet();
|
bookmark = Sets.newHashSet();
|
||||||
@@ -60,16 +86,53 @@ public class MapViewScene extends UIScene {
|
|||||||
img.setPosition(0, 0);
|
img.setPosition(0, 0);
|
||||||
table.addActor(img);
|
table.addActor(img);
|
||||||
table.addActor(miniMapPlayer);
|
table.addActor(miniMapPlayer);
|
||||||
|
miniMapPlayer.setZIndex(2);
|
||||||
|
details = Lists.newArrayList();
|
||||||
|
ui.addListener(new InputListener() {
|
||||||
|
public boolean scrolled(InputEvent event, float x, float y, float scrollAmountX, float scrollAmountY) {
|
||||||
|
event.cancel();
|
||||||
|
scroll.setScrollbarsVisible(true);
|
||||||
|
if (scrollAmountY > 0) {
|
||||||
|
zoomOut();
|
||||||
|
return true;
|
||||||
|
} else if (scrollAmountY < 0) {
|
||||||
|
zoomIn();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stage.setScrollFocus(ui);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test() {
|
||||||
|
img.setPosition((scroll.getScrollPercentX()*2334 +233)*0.1f + 0.9f*img.getX(),(2544-scroll.getScrollPercentY()*2544 +128)*0.1f + 0.9f*img.getY());
|
||||||
|
img.setScale(img.getScaleX()*0.9f);
|
||||||
|
miniMapPlayer.setPosition((scroll.getScrollPercentX()*2334 +233)*0.1f + 0.9f*miniMapPlayer.getX(),(2544-scroll.getScrollPercentY()*2544 +128)*0.1f + 0.9f*miniMapPlayer.getY());
|
||||||
|
miniMapPlayer.setScale(miniMapPlayer.getScaleX()*0.9f);
|
||||||
|
for(Actor actor : table.getChildren()) {
|
||||||
|
if (actor instanceof TypingLabel) {
|
||||||
|
actor.setPosition((scroll.getScrollPercentX() * 2334 + 233) * 0.1f + 0.9f * actor.getX(), (2544 - scroll.getScrollPercentY() * 2544 + 128) * 0.1f + 0.9f * actor.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean done() {
|
public boolean done() {
|
||||||
GameHUD.getInstance().getTouchpad().setVisible(false);
|
GameHUD.getInstance().getTouchpad().setVisible(false);
|
||||||
for (Actor a : table.getChildren()) {
|
SnapshotArray<Actor> allActors = table.getChildren();
|
||||||
if (a instanceof TypingLabel)
|
for (int i = 0; i < allActors.size; i++) {
|
||||||
a.remove();
|
if (allActors.get(i) instanceof TypingLabel) {
|
||||||
|
allActors.get(i).remove();
|
||||||
|
i--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
labels.clear();
|
labels.clear();
|
||||||
positions.clear();
|
positions.clear();
|
||||||
|
details.clear();
|
||||||
|
miniMapPlayer.setScale(1);
|
||||||
|
img.setScale(1);
|
||||||
|
img.setPosition(0,0);
|
||||||
index = -1;
|
index = -1;
|
||||||
Forge.switchToLast();
|
Forge.switchToLast();
|
||||||
return true;
|
return true;
|
||||||
@@ -101,6 +164,134 @@ public class MapViewScene extends UIScene {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void details() {
|
||||||
|
TextraButton detailsButton = ui.findActor("details");
|
||||||
|
if (detailsButton != null) {
|
||||||
|
detailsButton.setVisible(false);
|
||||||
|
detailsButton.setDisabled(true);
|
||||||
|
}
|
||||||
|
TextraButton eventButton = ui.findActor("events");
|
||||||
|
if (eventButton != null) {
|
||||||
|
eventButton.setVisible(true);
|
||||||
|
eventButton.setDisabled(false);
|
||||||
|
}
|
||||||
|
List<PointOfInterest> allPois = Current.world().getAllPointOfInterest();
|
||||||
|
for (PointOfInterest poi : allPois) {
|
||||||
|
for (AdventureEventData data : AdventurePlayer.current().getEvents()) {
|
||||||
|
if (data.sourceID.equals(poi.getID())) {
|
||||||
|
TypingLabel label = Controls.newTypingLabel("[%?BLACKEN] " + data.getCardBlock());
|
||||||
|
table.addActor(label);
|
||||||
|
details.add(label);
|
||||||
|
label.setPosition(img.getScaleX()*(getMapX(poi.getPosition().x) - label.getWidth() / 2) + img.getX(), img.getScaleY()*(getMapY(poi.getPosition().y) - label.getHeight() / 2) + img.getY());
|
||||||
|
label.skipToTheEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void events() {
|
||||||
|
TextraButton eventsButton = ui.findActor("events");
|
||||||
|
if (eventsButton != null) {
|
||||||
|
eventsButton.setVisible(false);
|
||||||
|
eventsButton.setDisabled(true);
|
||||||
|
}
|
||||||
|
TextraButton repButton = ui.findActor("reputation");
|
||||||
|
if (repButton != null) {
|
||||||
|
repButton.setVisible(true);
|
||||||
|
repButton.setDisabled(false);
|
||||||
|
}
|
||||||
|
for (TypingLabel detail : details) {
|
||||||
|
table.removeActor(detail);
|
||||||
|
}
|
||||||
|
List<PointOfInterest> allPois = Current.world().getAllPointOfInterest();
|
||||||
|
details.clear();
|
||||||
|
for (PointOfInterest poi : allPois) {
|
||||||
|
int rep = WorldSave.getCurrentSave().getPointOfInterestChanges(poi.getID()).getMapReputation();
|
||||||
|
if (rep != 0) {
|
||||||
|
TypingLabel label = Controls.newTypingLabel("[%?BLACKEN] " + rep);
|
||||||
|
table.addActor(label);
|
||||||
|
details.add(label);
|
||||||
|
label.setPosition(img.getScaleX()*(getMapX(poi.getPosition().x) - label.getWidth() / 2) + img.getX(), img.getScaleY()*(getMapY(poi.getPosition().y) - label.getHeight() / 2) + img.getY());
|
||||||
|
label.skipToTheEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reputation() {
|
||||||
|
TextraButton repButton = ui.findActor("reputation");
|
||||||
|
if (repButton != null) {
|
||||||
|
repButton.setVisible(false);
|
||||||
|
repButton.setDisabled(true);
|
||||||
|
}
|
||||||
|
TextraButton namesButton = ui.findActor("names");
|
||||||
|
if (namesButton != null) {
|
||||||
|
namesButton.setVisible(true);
|
||||||
|
namesButton.setDisabled(false);
|
||||||
|
}
|
||||||
|
for (TypingLabel detail : details) {
|
||||||
|
table.removeActor(detail);
|
||||||
|
}
|
||||||
|
details.clear();
|
||||||
|
List<PointOfInterest> allPois = Current.world().getAllPointOfInterest();
|
||||||
|
for (PointOfInterest poi : allPois) {
|
||||||
|
if (WorldSave.getCurrentSave().getPointOfInterestChanges(poi.getID()).isVisited()) {
|
||||||
|
if ("cave".equalsIgnoreCase(poi.getData().type) || "dungeon".equalsIgnoreCase(poi.getData().type) || "castle".equalsIgnoreCase(poi.getData().type)) {
|
||||||
|
TypingLabel label = Controls.newTypingLabel("[%?BLACKEN] " + poi.getDisplayName());
|
||||||
|
table.addActor(label);
|
||||||
|
details.add(label);
|
||||||
|
label.setPosition(img.getScaleX()*(getMapX(poi.getPosition().x) - label.getWidth() / 2) + img.getX(), img.getScaleY()*(getMapY(poi.getPosition().y) - label.getHeight() / 2) + img.getY());
|
||||||
|
label.skipToTheEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void names() {
|
||||||
|
TextraButton namesButton = ui.findActor("names");
|
||||||
|
if (namesButton != null) {
|
||||||
|
namesButton.setVisible(false);
|
||||||
|
namesButton.setDisabled(true);
|
||||||
|
}
|
||||||
|
TextraButton detailsButton = ui.findActor("details");
|
||||||
|
if (detailsButton != null) {
|
||||||
|
detailsButton.setVisible(true);
|
||||||
|
detailsButton.setDisabled(false);
|
||||||
|
}
|
||||||
|
for (TypingLabel detail : details) {
|
||||||
|
table.removeActor(detail);
|
||||||
|
}
|
||||||
|
details.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void zoomOut() {
|
||||||
|
if (img.getScaleX()*0.9f > minZoom) {
|
||||||
|
img.setPosition((scroll.getScrollX() + scroll.getWidth()/2) * 0.1f + 0.9f * img.getX(), (scroll.getMaxY() - scroll.getScrollY() + scroll.getHeight()/2) * 0.1f + 0.9f * img.getY());
|
||||||
|
img.setScale(img.getScaleX() * 0.9f);
|
||||||
|
miniMapPlayer.setPosition((scroll.getScrollX() + scroll.getWidth()/2) * 0.1f + 0.9f * miniMapPlayer.getX(), (scroll.getMaxY() - scroll.getScrollY() + scroll.getHeight()/2) * 0.1f + 0.9f * miniMapPlayer.getY());
|
||||||
|
miniMapPlayer.setScale(miniMapPlayer.getScaleX() * 0.9f);
|
||||||
|
for (Actor actor : table.getChildren()) {
|
||||||
|
if (actor instanceof TypingLabel) {
|
||||||
|
actor.setPosition((scroll.getScrollX() + scroll.getWidth()/2) * 0.1f + 0.9f * actor.getX(), (scroll.getMaxY() - scroll.getScrollY() + scroll.getHeight()/2) * 0.1f + 0.9f * actor.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void zoomIn() {
|
||||||
|
if (img.getScaleX()*1.1f < maxZoom) {
|
||||||
|
img.setPosition(-(scroll.getScrollX() + scroll.getWidth()/2) * 0.1f + 1.1f * img.getX(), -(scroll.getMaxY() - scroll.getScrollY() + scroll.getHeight()/2) * 0.1f + 1.1f * img.getY());
|
||||||
|
img.setScale(img.getScaleX() * 1.1f);
|
||||||
|
miniMapPlayer.setPosition(-(scroll.getScrollX() + scroll.getWidth()/2) * 0.1f + 1.1f * miniMapPlayer.getX(), -(scroll.getMaxY() - scroll.getScrollY() + scroll.getHeight()/2) * 0.1f + 1.1f * miniMapPlayer.getY());
|
||||||
|
miniMapPlayer.setScale(miniMapPlayer.getScaleX() * 1.1f);
|
||||||
|
for (Actor actor : table.getChildren()) {
|
||||||
|
if (actor instanceof TypingLabel) {
|
||||||
|
actor.setPosition(-(scroll.getScrollX() + scroll.getWidth()/2) * 0.1f + 1.1f * actor.getX(), -(scroll.getMaxY() - scroll.getScrollY() + scroll.getHeight()/2) * 0.1f + 1.1f * actor.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enter() {
|
public void enter() {
|
||||||
if (miniMapTexture != null)
|
if (miniMapTexture != null)
|
||||||
@@ -135,6 +326,37 @@ public class MapViewScene extends UIScene {
|
|||||||
label.setPosition(getMapX(poi.getPosition().x) - label.getWidth() / 2, getMapY(poi.getPosition().y) - label.getHeight() / 2);
|
label.setPosition(getMapX(poi.getPosition().x) - label.getWidth() / 2, getMapY(poi.getPosition().y) - label.getHeight() / 2);
|
||||||
label.skipToTheEnd();
|
label.skipToTheEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextraButton detailsButton = ui.findActor("details");
|
||||||
|
if (detailsButton != null) {
|
||||||
|
detailsButton.setVisible(true);
|
||||||
|
detailsButton.setDisabled(false);
|
||||||
|
}
|
||||||
|
TextraButton eventButton = ui.findActor("events");
|
||||||
|
if (eventButton != null) {
|
||||||
|
eventButton.setVisible(false);
|
||||||
|
eventButton.setDisabled(true);
|
||||||
|
}
|
||||||
|
TextraButton repButton = ui.findActor("reputation");
|
||||||
|
if (repButton != null) {
|
||||||
|
repButton.setVisible(false);
|
||||||
|
repButton.setDisabled(true);
|
||||||
|
}
|
||||||
|
TextraButton namesButton = ui.findActor("names");
|
||||||
|
if (namesButton != null) {
|
||||||
|
namesButton.setVisible(false);
|
||||||
|
namesButton.setDisabled(true);
|
||||||
|
}
|
||||||
|
TextraButton zoomInButton = ui.findActor("zoomIn");
|
||||||
|
if (zoomInButton != null) {
|
||||||
|
zoomInButton.setVisible(true);
|
||||||
|
zoomInButton.setDisabled(false);
|
||||||
|
}
|
||||||
|
TextraButton zoomOutButton = ui.findActor("zoomOut");
|
||||||
|
if (zoomOutButton != null) {
|
||||||
|
zoomOutButton.setVisible(true);
|
||||||
|
zoomOutButton.setDisabled(false);
|
||||||
|
}
|
||||||
TextraButton questButton = ui.findActor("quest");
|
TextraButton questButton = ui.findActor("quest");
|
||||||
if (questButton != null) {
|
if (questButton != null) {
|
||||||
questButton.setDisabled(labels.isEmpty());
|
questButton.setDisabled(labels.isEmpty());
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ public class MenuScene extends UIScene {
|
|||||||
}
|
}
|
||||||
dialog.show(stage, Actions.show());
|
dialog.show(stage, Actions.show());
|
||||||
dialog.setPosition((stage.getWidth() - dialog.getWidth()) / 2, (stage.getHeight() - dialog.getHeight()) / 2);
|
dialog.setPosition((stage.getWidth() - dialog.getWidth()) / 2, (stage.getHeight() - dialog.getHeight()) / 2);
|
||||||
if (Forge.hasGamepad() && !dialogButtonMap.isEmpty())
|
if (Forge.hasExternalInput() && !dialogButtonMap.isEmpty())
|
||||||
stage.setKeyboardFocus(dialogButtonMap.first());
|
stage.setKeyboardFocus(dialogButtonMap.first());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -159,18 +159,15 @@ public class RewardScene extends UIScene {
|
|||||||
boolean done(boolean skipShowLoot) {
|
boolean done(boolean skipShowLoot) {
|
||||||
GameHUD.getInstance().getTouchpad().setVisible(false);
|
GameHUD.getInstance().getTouchpad().setVisible(false);
|
||||||
if (!skipShowLoot) {
|
if (!skipShowLoot) {
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
showLootOrDone();
|
showLootOrDone();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Shop:
|
case Shop:
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
break;
|
break;
|
||||||
case QuestReward:
|
case QuestReward:
|
||||||
case Loot:
|
case Loot:
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,7 +214,6 @@ public class RewardScene extends UIScene {
|
|||||||
@Override
|
@Override
|
||||||
public void enter() {
|
public void enter() {
|
||||||
autoSell = false;
|
autoSell = false;
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
updateDetailButton();
|
updateDetailButton();
|
||||||
super.enter();
|
super.enter();
|
||||||
}
|
}
|
||||||
@@ -252,7 +248,7 @@ public class RewardScene extends UIScene {
|
|||||||
reward.flip();
|
reward.flip();
|
||||||
}
|
}
|
||||||
}, delay);
|
}, delay);
|
||||||
delay += 0.15f;
|
delay += 0.12f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -342,6 +338,8 @@ public class RewardScene extends UIScene {
|
|||||||
this.shopActor = shopActor;
|
this.shopActor = shopActor;
|
||||||
this.changes = shopActor.getMapStage().getChanges();
|
this.changes = shopActor.getMapStage().getChanges();
|
||||||
addToSelectable(restockButton);
|
addToSelectable(restockButton);
|
||||||
|
} else {
|
||||||
|
doneButton.setText("[+OK]");
|
||||||
}
|
}
|
||||||
for (Actor actor : new Array.ArrayIterator<>(generated)) {
|
for (Actor actor : new Array.ArrayIterator<>(generated)) {
|
||||||
actor.remove();
|
actor.remove();
|
||||||
@@ -406,7 +404,6 @@ public class RewardScene extends UIScene {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Shop:
|
case Shop:
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
String shopName = shopActor.getDescription();
|
String shopName = shopActor.getDescription();
|
||||||
if ((shopName != null && !shopName.isEmpty())) {
|
if ((shopName != null && !shopName.isEmpty())) {
|
||||||
headerLabel.setVisible(true);
|
headerLabel.setVisible(true);
|
||||||
@@ -425,19 +422,16 @@ public class RewardScene extends UIScene {
|
|||||||
headerLabel.setVisible(false);
|
headerLabel.setVisible(false);
|
||||||
headerLabel.setText("");
|
headerLabel.setText("");
|
||||||
restockButton.setVisible(false);
|
restockButton.setVisible(false);
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
break;
|
break;
|
||||||
case Loot:
|
case Loot:
|
||||||
headerLabel.skipToTheEnd();
|
|
||||||
headerLabel.setPosition(restockButton.getX(), restockButton.getY());
|
headerLabel.setPosition(restockButton.getX(), restockButton.getY());
|
||||||
headerLabel.setVisible(true);
|
headerLabel.setVisible(true);
|
||||||
headerLabel.setText("[%?SHINY][;]\u2610 " + Forge.getLocalizer().getMessage("lblAll"));
|
headerLabel.setText("[%?SHINY][;]\u2610 " + Forge.getLocalizer().getMessage("lblAll"));
|
||||||
|
headerLabel.skipToTheEnd();
|
||||||
restockButton.setVisible(false);
|
restockButton.setVisible(false);
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
break;
|
break;
|
||||||
case RewardChoice:
|
case RewardChoice:
|
||||||
restockButton.setVisible(false);
|
restockButton.setVisible(false);
|
||||||
doneButton.setText("[+OK]");
|
|
||||||
headerLabel.setVisible(remainingSelections > 0);
|
headerLabel.setVisible(remainingSelections > 0);
|
||||||
headerLabel.setText(Forge.getLocalizer().getMessage("lblSelectRewards", remainingSelections));
|
headerLabel.setText(Forge.getLocalizer().getMessage("lblSelectRewards", remainingSelections));
|
||||||
doneButton.setDisabled(remainingSelections > 0);
|
doneButton.setDisabled(remainingSelections > 0);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.controllers.Controller;
|
import com.badlogic.gdx.controllers.Controller;
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
@@ -242,6 +243,7 @@ public class UIScene extends Scene {
|
|||||||
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo) {
|
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo) {
|
||||||
return createGenericDialog(title, label, stringYes, stringNo, runnableYes, runnableNo, false, "");
|
return createGenericDialog(title, label, stringYes, stringNo, runnableYes, runnableNo, false, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo, boolean cancelButton, String stringCancel) {
|
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo, boolean cancelButton, String stringCancel) {
|
||||||
Dialog dialog = new Dialog(title == null ? "" : title, Controls.getSkin());
|
Dialog dialog = new Dialog(title == null ? "" : title, Controls.getSkin());
|
||||||
textboxOpen = true;
|
textboxOpen = true;
|
||||||
@@ -340,16 +342,15 @@ public class UIScene extends Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean keyPressed(int keycode) {
|
public boolean keyPressed(int keycode) {
|
||||||
Selectable selection = getSelected();
|
ui.pressDown(keycode);
|
||||||
|
|
||||||
|
Selectable selection = getSelected();
|
||||||
if (KeyBinding.Use.isPressed(keycode)) {
|
if (KeyBinding.Use.isPressed(keycode)) {
|
||||||
if (selection != null) {
|
if (selection != null) {
|
||||||
selection.onPressDown(this);
|
selection.onPressDown(this);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.pressDown(keycode);
|
|
||||||
if (stage.getKeyboardFocus() instanceof SelectBox) {
|
if (stage.getKeyboardFocus() instanceof SelectBox) {
|
||||||
SelectBox box = (SelectBox) stage.getKeyboardFocus();
|
SelectBox box = (SelectBox) stage.getKeyboardFocus();
|
||||||
if (box.getScrollPane().hasParent()) {
|
if (box.getScrollPane().hasParent()) {
|
||||||
@@ -380,17 +381,22 @@ public class UIScene extends Scene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!textboxOpen) {
|
if (!textboxOpen) {
|
||||||
if (KeyBinding.Down.isPressed(keycode))
|
//Allow letter S for TextField since this is binded on down keys
|
||||||
|
if (KeyBinding.Down.isPressed(keycode, !(stage.getKeyboardFocus() instanceof TextField))
|
||||||
|
|| KeyBinding.Down.isPressed(keycode, Input.Keys.S != keycode))
|
||||||
selectNextDown();
|
selectNextDown();
|
||||||
if (KeyBinding.Up.isPressed(keycode))
|
//Allow letter W for TextField since this is binded on up keys
|
||||||
|
if (KeyBinding.Up.isPressed(keycode, !(stage.getKeyboardFocus() instanceof TextField))
|
||||||
|
|| KeyBinding.Up.isPressed(keycode, Input.Keys.W != keycode))
|
||||||
selectNextUp();
|
selectNextUp();
|
||||||
if (!(stage.getKeyboardFocus() instanceof Selector) && !(stage.getKeyboardFocus() instanceof TextField) && !(stage.getKeyboardFocus() instanceof Slider)) {
|
// Allow Right & Left keybinds if not Selector, Slider or Textfield
|
||||||
if (KeyBinding.Right.isPressed(keycode))
|
if (KeyBinding.Right.isPressed(keycode, !(stage.getKeyboardFocus() instanceof Selector)
|
||||||
|
&& !(stage.getKeyboardFocus() instanceof TextField) && !(stage.getKeyboardFocus() instanceof Slider)))
|
||||||
selectNextRight();
|
selectNextRight();
|
||||||
if (KeyBinding.Left.isPressed(keycode))
|
if (KeyBinding.Left.isPressed(keycode, !(stage.getKeyboardFocus() instanceof Selector)
|
||||||
|
&& !(stage.getKeyboardFocus() instanceof TextField) && !(stage.getKeyboardFocus() instanceof Slider)))
|
||||||
selectNextLeft();
|
selectNextLeft();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!dialogShowing()) {
|
if (!dialogShowing()) {
|
||||||
Button pressedButton = ui.buttonPressed(keycode);
|
Button pressedButton = ui.buttonPressed(keycode);
|
||||||
if (pressedButton != null) {
|
if (pressedButton != null) {
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ public class Console extends Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void command(String text) {
|
public void command(String text) {
|
||||||
|
if (text.equalsIgnoreCase("exit")) {
|
||||||
|
toggle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
Cell<Label> newLine=content.add(text);
|
Cell<Label> newLine=content.add(text);
|
||||||
newLine.getActor().setColor(1,1,1,1);
|
newLine.getActor().setColor(1,1,1,1);
|
||||||
newLine.growX().align(Align.left|Align.bottom).row();
|
newLine.growX().align(Align.left|Align.bottom).row();
|
||||||
|
|||||||
@@ -786,6 +786,7 @@ public class GameHUD extends Stage {
|
|||||||
console.toggle();
|
console.toggle();
|
||||||
if (console.isVisible()) {
|
if (console.isVisible()) {
|
||||||
clearAbility();
|
clearAbility();
|
||||||
|
console.setZIndex(ui.getChildren().size);
|
||||||
} else {
|
} else {
|
||||||
updateAbility();
|
updateAbility();
|
||||||
}
|
}
|
||||||
@@ -794,6 +795,12 @@ public class GameHUD extends Stage {
|
|||||||
@Override
|
@Override
|
||||||
public boolean keyUp(int keycode) {
|
public boolean keyUp(int keycode) {
|
||||||
ui.pressUp(keycode);
|
ui.pressUp(keycode);
|
||||||
|
|
||||||
|
Button pressedButton = ui.buttonPressed(keycode);
|
||||||
|
if (pressedButton != null) {
|
||||||
|
pressedButton.fire(eventTouchUp);
|
||||||
|
}
|
||||||
|
|
||||||
return super.keyUp(keycode);
|
return super.keyUp(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,16 +814,17 @@ public class GameHUD extends Stage {
|
|||||||
toggleConsole();
|
toggleConsole();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (keycode == Input.Keys.BACK) {
|
if (KeyBinding.Back.isPressed(keycode)) {
|
||||||
if (console.isVisible()) {
|
if (console.isVisible()) {
|
||||||
toggleConsole();
|
toggleConsole();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (console.isVisible())
|
if (console.isVisible())
|
||||||
return true;
|
return true;
|
||||||
Button pressedButton = ui.buttonPressed(keycode);
|
Button pressedButton = ui.buttonPressed(keycode);
|
||||||
if (pressedButton != null) {
|
if (pressedButton != null) {
|
||||||
performTouch(pressedButton);
|
pressedButton.fire(eventTouchDown);
|
||||||
}
|
}
|
||||||
return super.keyDown(keycode);
|
return super.keyDown(keycode);
|
||||||
}
|
}
|
||||||
@@ -877,7 +885,7 @@ public class GameHUD extends Stage {
|
|||||||
dialogOnlyInput = true;
|
dialogOnlyInput = true;
|
||||||
gameStage.hudIsShowingDialog(true);
|
gameStage.hudIsShowingDialog(true);
|
||||||
MapStage.getInstance().hudIsShowingDialog(true);
|
MapStage.getInstance().hudIsShowingDialog(true);
|
||||||
if (Forge.hasGamepad() && !dialogButtonMap.isEmpty())
|
if (Forge.hasExternalInput() && !dialogButtonMap.isEmpty())
|
||||||
this.setKeyboardFocus(dialogButtonMap.first());
|
this.setKeyboardFocus(dialogButtonMap.first());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public abstract class GameStage extends Stage {
|
|||||||
dialog.setPosition((dialogStage.getWidth() - dialog.getWidth()) / 2, (dialogStage.getHeight() - dialog.getHeight()) / 2);
|
dialog.setPosition((dialogStage.getWidth() - dialog.getWidth()) / 2, (dialogStage.getHeight() - dialog.getHeight()) / 2);
|
||||||
dialogOnlyInput = true;
|
dialogOnlyInput = true;
|
||||||
|
|
||||||
if (Forge.hasGamepad() && !dialogButtonMap.isEmpty())
|
if (Forge.hasExternalInput() && !dialogButtonMap.isEmpty())
|
||||||
dialogStage.setKeyboardFocus(dialogButtonMap.first());
|
dialogStage.setKeyboardFocus(dialogButtonMap.first());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,9 +577,6 @@ public abstract class GameStage extends Stage {
|
|||||||
if (!player.isMoving())
|
if (!player.isMoving())
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
if (KeyBinding.Menu.isPressed(keycode)) {
|
|
||||||
openMenu();
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1132,9 +1132,11 @@ public class MapStage extends GameStage {
|
|||||||
dialog.show(dialogStage, Actions.show());
|
dialog.show(dialogStage, Actions.show());
|
||||||
dialog.setPosition((dialogStage.getWidth() - dialog.getWidth()) / 2, (dialogStage.getHeight() - dialog.getHeight()) / 2);
|
dialog.setPosition((dialogStage.getWidth() - dialog.getWidth()) / 2, (dialogStage.getHeight() - dialog.getHeight()) / 2);
|
||||||
dialogOnlyInput = true;
|
dialogOnlyInput = true;
|
||||||
if (Forge.hasGamepad() && !dialogButtonMap.isEmpty())
|
|
||||||
|
if (Forge.hasExternalInput() && !dialogButtonMap.isEmpty()) {
|
||||||
dialogStage.setKeyboardFocus(dialogButtonMap.first());
|
dialogStage.setKeyboardFocus(dialogButtonMap.first());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ public class WorldStage extends GameStage implements SaveFileContent {
|
|||||||
WorldSave.getCurrentSave().autoSave();
|
WorldSave.getCurrentSave().autoSave();
|
||||||
loadPOI(point.getPointOfInterest());
|
loadPOI(point.getPointOfInterest());
|
||||||
point.getMapSprite().checkOut();
|
point.getMapSprite().checkOut();
|
||||||
|
WorldSave.getCurrentSave().getPointOfInterestChanges(point.getPointOfInterest().getID()).visit();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (point == collidingPoint) {
|
if (point == collidingPoint) {
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ public class Controls {
|
|||||||
this.setWidth(this.layout.getWidth() + (this.style != null && this.style.background != null ? this.style.background.getLeftWidth() + this.style.background.getRightWidth() : 0.0F));
|
this.setWidth(this.layout.getWidth() + (this.style != null && this.style.background != null ? this.style.background.getLeftWidth() + this.style.background.getRightWidth() : 0.0F));
|
||||||
layout();
|
layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Batch batch, float parentAlpha) {
|
||||||
|
batch.setColor(1f, 1f, 1f, 1f); // Set color before drawing each actor, per libGDX docs
|
||||||
|
super.draw(batch, parentAlpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TextButtonFix extends TextraButton {
|
static class TextButtonFix extends TextraButton {
|
||||||
@@ -249,6 +255,27 @@ public class Controls {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public SelectBox<Integer> newComboBox(Integer[] text, int item, Function<Object, Void> func) {
|
||||||
|
SelectBox<Integer> ret = newComboBox();
|
||||||
|
ret.getStyle().listStyle.selection.setTopHeight(4);
|
||||||
|
ret.setItems(text);
|
||||||
|
ret.addListener(new ChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void changed(ChangeEvent event, Actor actor) {
|
||||||
|
try {
|
||||||
|
func.apply(((SelectBox) actor).getSelected());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
func.apply(item);
|
||||||
|
ret.getList().setAlignment(Align.center);
|
||||||
|
ret.setSelected(item);
|
||||||
|
ret.setAlignment(Align.right);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static public TextField newTextField(String text) {
|
static public TextField newTextField(String text) {
|
||||||
return new TextField(text, getSkin());
|
return new TextField(text, getSkin());
|
||||||
}
|
}
|
||||||
@@ -485,10 +512,11 @@ public class Controls {
|
|||||||
private String currencyIcon;
|
private String currencyIcon;
|
||||||
private boolean isShards;
|
private boolean isShards;
|
||||||
private int currencyAmount;
|
private int currencyAmount;
|
||||||
private float animationDelay = 2f; //seconds to wait before replacing intermediate label
|
private float intermediateDuration = 2f; // Seconds to wait before replacing intermediate label
|
||||||
private final String NEGDECOR = "[RED]-";
|
private final String NEGDECOR = "[RED]-";
|
||||||
private final String POSDECOR = "[GREEN]+";
|
private final String POSDECOR = "[GREEN]+";
|
||||||
private final Timer t = new Timer();
|
private final Timer t = new Timer();
|
||||||
|
private boolean isInitializing = true;
|
||||||
|
|
||||||
public AccountingLabel(TextraLabel target, boolean isShards) {
|
public AccountingLabel(TextraLabel target, boolean isShards) {
|
||||||
target.setVisible(false);
|
target.setVisible(false);
|
||||||
@@ -500,50 +528,72 @@ public class Controls {
|
|||||||
if (isShards) {
|
if (isShards) {
|
||||||
currencyAmount = Current.player().getShards();
|
currencyAmount = Current.player().getShards();
|
||||||
currencyIcon = "[+Shards]";
|
currencyIcon = "[+Shards]";
|
||||||
Current.player().onShardsChange(() -> update(AdventurePlayer.current().getShards(), true));
|
Current.player().onShardsChange(() -> {
|
||||||
|
if (!isInitializing) { // Avoid unwanted call to update() during scene initialization, triggering animation
|
||||||
|
update(AdventurePlayer.current().getShards(), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
currencyAmount = Current.player().getGold();
|
currencyAmount = Current.player().getGold();
|
||||||
currencyIcon = "[+Gold] "; //fix space since gold sprite is wider than a single glyph
|
currencyIcon = "[+Gold] "; //fix space since gold sprite is wider than a single glyph
|
||||||
Current.player().onGoldChange(() -> update(AdventurePlayer.current().getGold(), true));
|
Current.player().onGoldChange(() -> {
|
||||||
|
if (!isInitializing) { // Avoid unwanted call to update() during scene initialization, triggering animation
|
||||||
|
update(AdventurePlayer.current().getGold(), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
label.setText(getLabelText(currencyAmount));
|
label.setText(getLabelText(currencyAmount));
|
||||||
setName(label.getName());
|
setName(label.getName());
|
||||||
replaceLabel(label);
|
replaceLabel(label);
|
||||||
|
|
||||||
|
isInitializing = false; // Initialization complete
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAnimationDelay(float animationDelay) {
|
public void setIntermediateDuration(float intermediateDuration) {
|
||||||
this.animationDelay = animationDelay;
|
this.intermediateDuration = intermediateDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getAnimationDelay() {
|
public float getIntermediateDuration() {
|
||||||
return animationDelay;
|
return intermediateDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(int newAmount) {
|
public void update(int newAmount) {
|
||||||
update(newAmount, false);
|
update(newAmount, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(int newAmount, boolean animate) {
|
public void update(int newAmount, boolean animateIntermediate) {
|
||||||
|
|
||||||
if (animate) {
|
if (animateIntermediate) {
|
||||||
TextraLabel temporaryLabel = getUpdateLabel(newAmount);
|
TextraLabel temporaryLabel = getUpdateLabel(newAmount);
|
||||||
currencyAmount = newAmount;
|
currencyAmount = newAmount;
|
||||||
replaceLabel(temporaryLabel);
|
replaceLabel(temporaryLabel);
|
||||||
|
|
||||||
t.schedule(new AccountingLabelUpdater(temporaryLabel), animationDelay);
|
// Add a quick 'bump' animation to the temporary label
|
||||||
|
SequenceAction sequence = new SequenceAction();
|
||||||
|
sequence.addAction(Actions.alpha(0.25f));
|
||||||
|
sequence.addAction(Actions.parallel(
|
||||||
|
Actions.alpha(1f, 0.05f, Interpolation.pow2Out),
|
||||||
|
Actions.moveBy(0f, 2f, 0.05f, Interpolation.pow2Out)
|
||||||
|
));
|
||||||
|
sequence.addAction(Actions.moveBy(0f, -2f, 0.05f, Interpolation.pow2Out));
|
||||||
|
|
||||||
|
temporaryLabel.addAction(sequence);
|
||||||
|
|
||||||
|
t.schedule(new AccountingLabelUpdater(temporaryLabel), intermediateDuration);
|
||||||
} else {
|
} else {
|
||||||
currencyAmount = newAmount;
|
currencyAmount = newAmount;
|
||||||
drawFinalLabel(false);
|
drawFinalLabel(true); // Draw final label with animation since the intermediate label was not used.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawFinalLabel(boolean fadeIn) {
|
private void drawFinalLabel(boolean animateFinal) {
|
||||||
|
|
||||||
TextraLabel finalLabel = getDefaultLabel();
|
TextraLabel finalLabel = getDefaultLabel();
|
||||||
if (fadeIn) {
|
if (animateFinal) {
|
||||||
|
// Add a quick fade-in animation to the final label
|
||||||
SequenceAction sequence = new SequenceAction();
|
SequenceAction sequence = new SequenceAction();
|
||||||
sequence.addAction(Actions.alpha(0.5f));
|
sequence.addAction(Actions.alpha(0.25f));
|
||||||
sequence.addAction(Actions.alpha(1f, 2f, Interpolation.pow2Out));
|
sequence.addAction(Actions.alpha(1f, 0.1f, Interpolation.pow2Out));
|
||||||
finalLabel.addAction(sequence);
|
finalLabel.addAction(sequence);
|
||||||
}
|
}
|
||||||
replaceLabel(finalLabel);
|
replaceLabel(finalLabel);
|
||||||
@@ -556,7 +606,7 @@ public class Controls {
|
|||||||
private TextraLabel getUpdateLabel(int newAmount) {
|
private TextraLabel getUpdateLabel(int newAmount) {
|
||||||
int delta = newAmount - currencyAmount;
|
int delta = newAmount - currencyAmount;
|
||||||
String updateText = delta == 0 ? "" : (delta < 0 ? NEGDECOR + delta * -1 : POSDECOR + delta);
|
String updateText = delta == 0 ? "" : (delta < 0 ? NEGDECOR + delta * -1 : POSDECOR + delta);
|
||||||
return Controls.newTextraLabel(getLabelText(currencyAmount, updateText));
|
return Controls.newTextraLabel(getLabelText(newAmount, updateText));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLabelText(int amount) {
|
private String getLabelText(int amount) {
|
||||||
@@ -579,13 +629,15 @@ public class Controls {
|
|||||||
label.remove();
|
label.remove();
|
||||||
label = newLabel;
|
label = newLabel;
|
||||||
placeholder.getStage().addActor(label);
|
placeholder.getStage().addActor(label);
|
||||||
|
|
||||||
|
label.setZIndex(placeholder.getZIndex() - 1); // Ensure the new label is behind any tooltips that were present
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccountingLabelUpdater extends Timer.Task {
|
private class AccountingLabelUpdater extends Timer.Task {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (label.equals(target)) {
|
if (label.equals(target)) {
|
||||||
drawFinalLabel(true);
|
drawFinalLabel(false); // Passing false to avoid final animation since the intermediate label was animated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,37 +21,40 @@ public enum KeyBinding {
|
|||||||
ExitToWorldMap("ExitToWorldMap", new int[]{Input.Keys.F4, Input.Keys.BUTTON_L2}),
|
ExitToWorldMap("ExitToWorldMap", new int[]{Input.Keys.F4, Input.Keys.BUTTON_L2}),
|
||||||
Bookmark("Bookmark", new int[]{Input.Keys.B, Input.Keys.BUTTON_R2}),
|
Bookmark("Bookmark", new int[]{Input.Keys.B, Input.Keys.BUTTON_R2}),
|
||||||
Use("Use", new int[]{Input.Keys.ENTER, Input.Keys.BUTTON_A}),
|
Use("Use", new int[]{Input.Keys.ENTER, Input.Keys.BUTTON_A}),
|
||||||
Back("Back", new int[] {Input.Keys.ESCAPE,Input.Keys.BUTTON_B}),
|
Back("Back", new int[]{Input.Keys.ESCAPE, Input.Keys.BUTTON_B, Input.Keys.BACK}),
|
||||||
ScrollUp("ScrollUp", new int[]{Input.Keys.PAGE_UP, Input.Keys.BUTTON_L1}),
|
ScrollUp("ScrollUp", new int[]{Input.Keys.PAGE_UP, Input.Keys.BUTTON_L1}),
|
||||||
ScrollDown("ScrollDown", new int[]{Input.Keys.PAGE_DOWN, Input.Keys.BUTTON_R1}),
|
ScrollDown("ScrollDown", new int[]{Input.Keys.PAGE_DOWN, Input.Keys.BUTTON_R1}),
|
||||||
;
|
;
|
||||||
String name;
|
final String name;
|
||||||
int [] bindings;
|
final int[] bindings;
|
||||||
|
|
||||||
KeyBinding(String name, int [] bindings)
|
KeyBinding(String name, int[] bindings) {
|
||||||
{
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.bindings = bindings;
|
this.bindings = bindings;
|
||||||
}
|
}
|
||||||
public boolean isPressed(int key)
|
|
||||||
{
|
public boolean isPressed(int key) {
|
||||||
|
return isPressed(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPressed(int key, Boolean requiredCondition) {
|
||||||
|
if (requiredCondition == null || requiredCondition) {
|
||||||
for (int i = 0; i < bindings.length; i++) {
|
for (int i = 0; i < bindings.length; i++) {
|
||||||
if (key == bindings[i]) {
|
if (key == bindings[i]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The controller binding always has index 1.
|
// The controller binding always has index 1.
|
||||||
static String controllerPrefix="XBox_";
|
final static String controllerPrefix = "XBox_";
|
||||||
|
|
||||||
public String getLabelText(boolean pressed) {
|
public String getLabelText(boolean pressed) {
|
||||||
if(Controllers.getCurrent()!=null)
|
if (Controllers.getCurrent() != null) {
|
||||||
{
|
|
||||||
return "[%120][+" + controllerPrefix + Input.Keys.toString(bindings[1]).replace(" Button", "") + (pressed ? "_pressed]" : "]");
|
return "[%120][+" + controllerPrefix + Input.Keys.toString(bindings[1]).replace(" Button", "") + (pressed ? "_pressed]" : "]");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
if (GuiBase.isAndroid())
|
if (GuiBase.isAndroid())
|
||||||
return "";
|
return "";
|
||||||
return "[%120][+" + Input.Keys.toString(bindings[0]) + (pressed ? "_pressed]" : "]");
|
return "[%120][+" + Input.Keys.toString(bindings[0]) + (pressed ? "_pressed]" : "]");
|
||||||
@@ -59,8 +62,7 @@ public enum KeyBinding {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int controllerButtonToKey(Controller controller,int key)
|
public static int controllerButtonToKey(Controller controller, int key) {
|
||||||
{
|
|
||||||
ControllerMapping map = controller.getMapping();
|
ControllerMapping map = controller.getMapping();
|
||||||
if (key == map.buttonA) return Input.Keys.BUTTON_A;
|
if (key == map.buttonA) return Input.Keys.BUTTON_A;
|
||||||
if (key == map.buttonB) return Input.Keys.BUTTON_B;
|
if (key == map.buttonB) return Input.Keys.BUTTON_B;
|
||||||
@@ -80,10 +82,6 @@ public enum KeyBinding {
|
|||||||
if (key == map.buttonLeftStick) return Input.Keys.BUTTON_THUMBL;
|
if (key == map.buttonLeftStick) return Input.Keys.BUTTON_THUMBL;
|
||||||
if (key == map.buttonRightStick) return Input.Keys.BUTTON_THUMBR;
|
if (key == map.buttonRightStick) return Input.Keys.BUTTON_THUMBR;
|
||||||
|
|
||||||
if(key==map.buttonDpadUp) return Input.Keys.DPAD_UP;
|
|
||||||
if(key==map.buttonDpadDown) return Input.Keys.DPAD_DOWN;
|
|
||||||
if(key==map.buttonDpadLeft) return Input.Keys.DPAD_LEFT;
|
|
||||||
if(key==map.buttonDpadRight) return Input.Keys.DPAD_RIGHT;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,12 @@ import com.badlogic.gdx.math.Vector3;
|
|||||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Group;
|
import com.badlogic.gdx.scenes.scene2d.Group;
|
||||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Image;
|
import com.badlogic.gdx.scenes.scene2d.ui.Image;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Tooltip;
|
import com.badlogic.gdx.scenes.scene2d.ui.Tooltip;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.TooltipManager;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
|
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
||||||
@@ -120,10 +123,10 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
public void onImageFetched() {
|
public void onImageFetched() {
|
||||||
ImageCache.getInstance().clear();
|
ImageCache.getInstance().clear();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(reward.type.equals(Reward.Type.Card)) {
|
if(reward.type.equals(Reward.Type.Card)) {
|
||||||
imageKey = reward.getCard().getImageKey(false);
|
imageKey = reward.getCard().getImageKey(false);
|
||||||
|
PaperCard card = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||||
|
imageKey = card.getCardImageKey();
|
||||||
|
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -220,6 +223,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
reward.setAutoSell(!reward.isAutoSell());
|
reward.setAutoSell(!reward.isAutoSell());
|
||||||
String c = reward.isAutoSell() ? "[%85][GREEN]" : "[%85][GRAY]";
|
String c = reward.isAutoSell() ? "[%85][GREEN]" : "[%85][GRAY]";
|
||||||
autoSell.setText(c + "\uFF04");
|
autoSell.setText(c + "\uFF04");
|
||||||
|
autoSell.getColor().a = reward.isAutoSell() ? 1f : 0.7f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RewardActor(Reward reward, boolean flippable, RewardScene.Type type, boolean showOverlay) {
|
public RewardActor(Reward reward, boolean flippable, RewardScene.Type type, boolean showOverlay) {
|
||||||
@@ -235,6 +239,17 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
case Card: {
|
case Card: {
|
||||||
if (!reward.isNoSell) {
|
if (!reward.isNoSell) {
|
||||||
autoSell = Controls.newTextButton("[%85][GRAY]\uFF04");
|
autoSell = Controls.newTextButton("[%85][GRAY]\uFF04");
|
||||||
|
autoSell.getColor().a = 0.7f; // semi-transparent by default
|
||||||
|
autoSell.addListener(new InputListener() {
|
||||||
|
@Override
|
||||||
|
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
|
||||||
|
if (!reward.isAutoSell()) autoSell.getColor().a = 1f;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
|
||||||
|
if (!reward.isAutoSell()) autoSell.getColor().a = 0.7f;
|
||||||
|
}
|
||||||
|
});
|
||||||
float scale = autoSell.getWidth();
|
float scale = autoSell.getWidth();
|
||||||
autoSell.setSize(scale, scale * 1.2f);
|
autoSell.setSize(scale, scale * 1.2f);
|
||||||
autoSell.addListener(new ClickListener() {
|
autoSell.addListener(new ClickListener() {
|
||||||
@@ -246,7 +261,8 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
hasbackface = reward.getCard().hasBackFace();
|
hasbackface = reward.getCard().hasBackFace();
|
||||||
if (ImageCache.getInstance().imageKeyFileExists(reward.getCard().getImageKey(false)) && !Forge.enableUIMask.equals("Art")) {
|
if (ImageCache.getInstance().imageKeyFileExists(reward.getCard().getImageKey(false)) && !Forge.enableUIMask.equals("Art")) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
File frontFace = ImageKeys.getImageFile(reward.getCard().getImageKey(false));
|
PaperCard card = ImageUtil.getPaperCardFromImageKey(reward.getCard().getImageKey(false));
|
||||||
|
File frontFace = ImageKeys.getImageFile(card.getCardImageKey());
|
||||||
if (frontFace != null) {
|
if (frontFace != null) {
|
||||||
try {
|
try {
|
||||||
Texture front = Forge.getAssets().manager().get(frontFace.getPath(), Texture.class, false);
|
Texture front = Forge.getAssets().manager().get(frontFace.getPath(), Texture.class, false);
|
||||||
@@ -272,7 +288,8 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
//preload card back for performance
|
//preload card back for performance
|
||||||
if (hasbackface) {
|
if (hasbackface) {
|
||||||
if (ImageCache.getInstance().imageKeyFileExists(reward.getCard().getImageKey(true))) {
|
if (ImageCache.getInstance().imageKeyFileExists(reward.getCard().getImageKey(true))) {
|
||||||
File backFace = ImageKeys.getImageFile(reward.getCard().getImageKey(true));
|
PaperCard cardBack = ImageUtil.getPaperCardFromImageKey(reward.getCard().getImageKey(true));
|
||||||
|
File backFace = ImageKeys.getImageFile(cardBack.getCardAltImageKey());
|
||||||
if (backFace != null) {
|
if (backFace != null) {
|
||||||
try {
|
try {
|
||||||
Texture back = Forge.getAssets().manager().get(backFace.getPath(), Texture.class, false);
|
Texture back = Forge.getAssets().manager().get(backFace.getPath(), Texture.class, false);
|
||||||
@@ -396,7 +413,8 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
if (imageKey != "") {
|
if (imageKey != "") {
|
||||||
isBooster = true;
|
isBooster = true;
|
||||||
File file = new File(IMAGE_LIST_QUEST_BOOSTERS_FILE);
|
File file = new File(IMAGE_LIST_QUEST_BOOSTERS_FILE);
|
||||||
try (Scanner scanner = new Scanner(file)) {
|
try {
|
||||||
|
Scanner scanner = new Scanner(file);
|
||||||
String boosterPath = "";
|
String boosterPath = "";
|
||||||
while(scanner.hasNextLine())
|
while(scanner.hasNextLine())
|
||||||
{
|
{
|
||||||
@@ -564,8 +582,8 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
TextureRegionDrawable drawable = new TextureRegionDrawable(ImageCache.getInstance().croppedBorderImage(texture));
|
TextureRegionDrawable drawable = new TextureRegionDrawable(ImageCache.getInstance().croppedBorderImage(texture));
|
||||||
float origW = texture.getWidth();
|
float origW = texture.getWidth();
|
||||||
float origH = texture.getHeight();
|
float origH = texture.getHeight();
|
||||||
float boundW = Scene.getIntendedWidth() * 0.95f;
|
float boundW = GuiBase.isAndroid() ? Scene.getIntendedWidth() * 0.95f : Scene.getIntendedWidth() * 0.7f; // Use smaller size for Desktop
|
||||||
float boundH = Scene.getIntendedHeight() * 0.95f;
|
float boundH = GuiBase.isAndroid() ? Scene.getIntendedHeight() * 0.95f : Scene.getIntendedHeight() * 0.7f; // Use smaller size for Desktop
|
||||||
float newW = origW;
|
float newW = origW;
|
||||||
float newH = origH;
|
float newH = origH;
|
||||||
if (origW > boundW) {
|
if (origW > boundW) {
|
||||||
@@ -843,7 +861,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
super.act(delta);
|
super.act(delta);
|
||||||
if (clicked) {
|
if (clicked) {
|
||||||
if (flipProcess < 1)
|
if (flipProcess < 1)
|
||||||
flipProcess += delta * 2.4;
|
flipProcess += delta * 4;
|
||||||
else
|
else
|
||||||
flipProcess = 1;
|
flipProcess = 1;
|
||||||
|
|
||||||
@@ -1109,11 +1127,17 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
public TextraLabel getStoredLabel() {
|
public TextraLabel getStoredLabel() {
|
||||||
return cLabel;
|
return cLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Batch batch, float parentAlpha) {
|
||||||
|
batch.setColor(1f, 1f, 1f, 1f); // Set color before drawing each actor, per libGDX docs
|
||||||
|
super.draw(batch, parentAlpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImageToolTip extends Tooltip<ComplexTooltip> {
|
class ImageToolTip extends Tooltip<ComplexTooltip> {
|
||||||
public ImageToolTip(ComplexTooltip contents) {
|
public ImageToolTip(ComplexTooltip contents) {
|
||||||
super(contents);
|
super(contents, RewardTooltipManager.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Image getImage() {
|
public Image getImage() {
|
||||||
@@ -1253,4 +1277,30 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
super.draw(batch, parentAlpha);
|
super.draw(batch, parentAlpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend and override TooltipManager to avoid the built-in default animations.
|
||||||
|
*/
|
||||||
|
static class RewardTooltipManager extends TooltipManager {
|
||||||
|
private static RewardTooltipManager instance;
|
||||||
|
|
||||||
|
public static RewardTooltipManager getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new RewardTooltipManager();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void showAction(Tooltip tooltip) {
|
||||||
|
// Overriding showAction for instant tooltip display
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void hideAction(Tooltip tooltip) {
|
||||||
|
tooltip.getContainer().addAction(Actions.sequence(
|
||||||
|
Actions.removeActor() // Remove tooltip without animation
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,6 +247,9 @@ public class ImageCache {
|
|||||||
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
||||||
}
|
}
|
||||||
if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) {
|
if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) {
|
||||||
|
PaperCard card = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||||
|
if (card != null)
|
||||||
|
imageKey = altState ? card.getCardAltImageKey() : card.getCardImageKey();
|
||||||
if (StringUtils.isBlank(imageKey)) {
|
if (StringUtils.isBlank(imageKey)) {
|
||||||
if (useDefaultIfNotFound)
|
if (useDefaultIfNotFound)
|
||||||
return getDefaultImage();
|
return getDefaultImage();
|
||||||
@@ -292,7 +295,7 @@ public class ImageCache {
|
|||||||
image fetcher to update automatically after the card image/s are downloaded*/
|
image fetcher to update automatically after the card image/s are downloaded*/
|
||||||
imageLoaded = false;
|
imageLoaded = false;
|
||||||
if (image != null && imageRecord.get().get(image.toString()) == null)
|
if (image != null && imageRecord.get().get(image.toString()) == null)
|
||||||
imageRecord.get().put(image.toString(), new ImageRecord(Color.valueOf("#171717").toString(), false, getRadius(image))); //black border
|
imageRecord.get().put(image.toString(), new ImageRecord(Color.valueOf("#171717").toString(), false, getRadius(image), image.toString().contains(".fullborder.") || image.toString().contains("tokens"))); //black border
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
@@ -346,7 +349,7 @@ public class ImageCache {
|
|||||||
radius = 22;
|
radius = 22;
|
||||||
updateImageRecord(cardTexture.toString(),
|
updateImageRecord(cardTexture.toString(),
|
||||||
borderless ? Color.valueOf("#171717").toString() : isCloserToWhite(getpixelColor(cardTexture)).getLeft(),
|
borderless ? Color.valueOf("#171717").toString() : isCloserToWhite(getpixelColor(cardTexture)).getLeft(),
|
||||||
!borderless && isCloserToWhite(getpixelColor(cardTexture)).getRight(), radius);
|
!borderless && isCloserToWhite(getpixelColor(cardTexture)).getRight(), radius, cardTexture.toString().contains(".fullborder.") || cardTexture.toString().contains("tokens"));
|
||||||
}
|
}
|
||||||
return cardTexture;
|
return cardTexture;
|
||||||
}
|
}
|
||||||
@@ -441,8 +444,8 @@ public class ImageCache {
|
|||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
public void updateImageRecord(String textureString, String colorValue, Boolean isClosertoWhite, int radius) {
|
public void updateImageRecord(String textureString, String colorValue, Boolean isClosertoWhite, int radius, boolean fullborder) {
|
||||||
imageRecord.get().put(textureString, new ImageRecord(colorValue, isClosertoWhite, radius));
|
imageRecord.get().put(textureString, new ImageRecord(colorValue, isClosertoWhite, radius, fullborder));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRadius(Texture t) {
|
public int getRadius(Texture t) {
|
||||||
@@ -457,6 +460,15 @@ public class ImageCache {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFullBorder(Texture image) {
|
||||||
|
if (image == null)
|
||||||
|
return false;
|
||||||
|
ImageRecord record = imageRecord.get().get(image.toString());
|
||||||
|
if (record == null)
|
||||||
|
return false;
|
||||||
|
return record.isFullBorder;
|
||||||
|
}
|
||||||
|
|
||||||
public FImage getBorder(String textureString) {
|
public FImage getBorder(String textureString) {
|
||||||
ImageRecord record = imageRecord.get().get(textureString);
|
ImageRecord record = imageRecord.get().get(textureString);
|
||||||
if (record == null)
|
if (record == null)
|
||||||
@@ -541,11 +553,13 @@ public class ImageCache {
|
|||||||
String colorValue;
|
String colorValue;
|
||||||
Boolean isCloserToWhite;
|
Boolean isCloserToWhite;
|
||||||
Integer cardRadius;
|
Integer cardRadius;
|
||||||
|
boolean isFullBorder;
|
||||||
|
|
||||||
ImageRecord(String colorString, Boolean closetoWhite, int radius) {
|
ImageRecord(String colorString, Boolean closetoWhite, int radius, boolean fullborder) {
|
||||||
colorValue = colorString;
|
colorValue = colorString;
|
||||||
isCloserToWhite = closetoWhite;
|
isCloserToWhite = closetoWhite;
|
||||||
cardRadius = radius;
|
cardRadius = radius;
|
||||||
|
isFullBorder = fullborder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,21 +34,22 @@ public class CardImage implements FImage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||||
|
CardView cv = CardView.getCardForUi(card);
|
||||||
if (image == null) { //attempt to retrieve card image if needed
|
if (image == null) { //attempt to retrieve card image if needed
|
||||||
image = ImageCache.getInstance().getImage(card);
|
image = ImageCache.getInstance().getImage(card);
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
if (!Forge.enableUIMask.equals("Off")) //render this if mask is still loading
|
if (!Forge.enableUIMask.equals("Off")) //render this if mask is still loading
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top, Forge.enableUIMask.equals("Art"), true);
|
CardImageRenderer.drawCardImage(g, cv, false, x, y, w, h, CardStackPosition.Top, Forge.enableUIMask.equals("Art"), true);
|
||||||
|
|
||||||
return; //can't draw anything if can't be loaded yet
|
return; //can't draw anything if can't be loaded yet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image == ImageCache.getInstance().getDefaultImage() || Forge.enableUIMask.equals("Art")) {
|
if (image == ImageCache.getInstance().getDefaultImage() || Forge.enableUIMask.equals("Art")) {
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top, true, true);
|
CardImageRenderer.drawCardImage(g, cv, false, x, y, w, h, CardStackPosition.Top, true, true);
|
||||||
} else {
|
} else {
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
||||||
else {
|
else {
|
||||||
float radius = (h - w) / 8;
|
float radius = (h - w) / 8;
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import java.util.List;
|
|||||||
|
|
||||||
import forge.ImageKeys;
|
import forge.ImageKeys;
|
||||||
import forge.assets.*;
|
import forge.assets.*;
|
||||||
|
import forge.item.PaperCard;
|
||||||
|
import forge.util.ImageUtil;
|
||||||
import forge.util.TextBounds;
|
import forge.util.TextBounds;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
@@ -156,7 +156,13 @@ public class CardImageRenderer {
|
|||||||
}
|
}
|
||||||
//space for artist
|
//space for artist
|
||||||
textBoxHeight -= 2 * PT_FONT.getCapHeight();
|
textBoxHeight -= 2 * PT_FONT.getCapHeight();
|
||||||
String artist = ObjectUtils.firstNonNull(state.getArtist(), "WOTC");
|
PaperCard paperCard = null;
|
||||||
|
try {
|
||||||
|
paperCard = ImageUtil.getPaperCardFromImageKey(state.getImageKey());
|
||||||
|
} catch (Exception e) {}
|
||||||
|
String artist = "WOTC";
|
||||||
|
if (paperCard != null && !paperCard.getArtist().isEmpty())
|
||||||
|
artist = paperCard.getArtist();
|
||||||
float minTextBoxHeight = 2 * headerHeight;
|
float minTextBoxHeight = 2 * headerHeight;
|
||||||
if (textBoxHeight < minTextBoxHeight) {
|
if (textBoxHeight < minTextBoxHeight) {
|
||||||
artHeight -= (minTextBoxHeight - textBoxHeight); //subtract from art height if text box not big enough otherwise
|
artHeight -= (minTextBoxHeight - textBoxHeight); //subtract from art height if text box not big enough otherwise
|
||||||
@@ -808,7 +814,7 @@ public class CardImageRenderer {
|
|||||||
}
|
}
|
||||||
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane() || (card.getCurrentState().isBattle() && !altState) || (card.getAlternateState() != null && card.getAlternateState().isBattle() && altState))) {
|
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane() || (card.getCurrentState().isBattle() && !altState) || (card.getAlternateState() != null && card.getAlternateState().isBattle() && altState))) {
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
@@ -821,7 +827,7 @@ public class CardImageRenderer {
|
|||||||
} else if (rotateSplit && isCurrentCard && card.isSplitCard() && canshow && !card.isFaceDown()) {
|
} else if (rotateSplit && isCurrentCard && card.isSplitCard() && canshow && !card.isFaceDown()) {
|
||||||
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
|
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getInstance().getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getInstance().getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
@@ -837,7 +843,7 @@ public class CardImageRenderer {
|
|||||||
if (card.isSplitCard() && rotateSplit && isCurrentCard) {
|
if (card.isSplitCard() && rotateSplit && isCurrentCard) {
|
||||||
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
|
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getInstance().getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getInstance().getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
@@ -849,7 +855,7 @@ public class CardImageRenderer {
|
|||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
} else {
|
} else {
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
||||||
else {
|
else {
|
||||||
g.drawImage(ImageCache.getInstance().getBorderImage(image.toString()), ImageCache.getInstance().borderColor(image), x, y, w, h);
|
g.drawImage(ImageCache.getInstance().getBorderImage(image.toString()), ImageCache.getInstance().borderColor(image), x, y, w, h);
|
||||||
@@ -866,7 +872,7 @@ public class CardImageRenderer {
|
|||||||
g.drawImage(sleeves, x, y, w, h);
|
g.drawImage(sleeves, x, y, w, h);
|
||||||
}
|
}
|
||||||
} else if (Forge.enableUIMask.equals("Full") && canshow) {
|
} else if (Forge.enableUIMask.equals("Full") && canshow) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
||||||
else {
|
else {
|
||||||
g.drawImage(ImageCache.getInstance().getBorderImage(image.toString()), ImageCache.getInstance().borderColor(image), x, y, w, h);
|
g.drawImage(ImageCache.getInstance().getBorderImage(image.toString()), ImageCache.getInstance().borderColor(image), x, y, w, h);
|
||||||
|
|||||||
@@ -597,6 +597,7 @@ public class CardRenderer {
|
|||||||
|
|
||||||
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h, CardStackPosition pos) {
|
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h, CardStackPosition pos) {
|
||||||
Texture image = new RendererCachedCardImage(pc, false).getImage();
|
Texture image = new RendererCachedCardImage(pc, false).getImage();
|
||||||
|
final CardView card = CardView.getCardForUi(pc);
|
||||||
float radius = (h - w) / 8;
|
float radius = (h - w) / 8;
|
||||||
float croppedArea = isModernFrame(pc) ? CROP_MULTIPLIER : 0.97f;
|
float croppedArea = isModernFrame(pc) ? CROP_MULTIPLIER : 0.97f;
|
||||||
float minusxy = isModernFrame(pc) ? 0.0f : 0.13f * radius;
|
float minusxy = isModernFrame(pc) ? 0.0f : 0.13f * radius;
|
||||||
@@ -609,7 +610,7 @@ public class CardRenderer {
|
|||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos, true, true);
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos, true, true);
|
||||||
} else {
|
} else {
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
g.drawCardRoundRect(image, null, x, y, w, h, false, false);
|
||||||
else {
|
else {
|
||||||
//tint the border
|
//tint the border
|
||||||
@@ -622,7 +623,6 @@ public class CardRenderer {
|
|||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
}
|
}
|
||||||
if (pc.isFoil()) { //draw foil effect if needed
|
if (pc.isFoil()) { //draw foil effect if needed
|
||||||
final CardView card = CardView.getCardForUi(pc);
|
|
||||||
if (card.getCurrentState().getFoilIndex() == 0) { //if foil finish not yet established, assign a random one
|
if (card.getCurrentState().getFoilIndex() == 0) { //if foil finish not yet established, assign a random one
|
||||||
card.getCurrentState().setFoilIndexOverride(-1);
|
card.getCurrentState().setFoilIndexOverride(-1);
|
||||||
}
|
}
|
||||||
@@ -630,7 +630,7 @@ public class CardRenderer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically
|
//if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos, true, true);
|
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,7 +663,7 @@ public class CardRenderer {
|
|||||||
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON)
|
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON)
|
||||||
&& (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane() || (card.getCurrentState().isBattle() && !showAltState) || (card.getAlternateState() != null && card.getAlternateState().isBattle() && showAltState)) && rotate) {
|
&& (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane() || (card.getCurrentState().isBattle() && !showAltState) || (card.getAlternateState() != null && card.getAlternateState().isBattle() && showAltState)) && rotate) {
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawCardRoundRect(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
@@ -675,7 +675,7 @@ public class CardRenderer {
|
|||||||
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
} else {
|
} else {
|
||||||
if (Forge.enableUIMask.equals("Full") && canshow) {
|
if (Forge.enableUIMask.equals("Full") && canshow) {
|
||||||
if (image.toString().contains(".fullborder."))
|
if (ImageCache.getInstance().isFullBorder(image))
|
||||||
g.drawCardRoundRect(image, crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0);
|
g.drawCardRoundRect(image, crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0);
|
||||||
else {
|
else {
|
||||||
//boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
|
//boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
|
||||||
|
|||||||
@@ -103,22 +103,27 @@ public class CardZoom extends FOverlay {
|
|||||||
if (pc != null) {
|
if (pc != null) {
|
||||||
Card cardW = Card.fromPaperCard(pc, null);
|
Card cardW = Card.fromPaperCard(pc, null);
|
||||||
cardW.setState(CardStateName.SpecializeW, true);
|
cardW.setState(CardStateName.SpecializeW, true);
|
||||||
|
cardW.setImageKey(pc, CardStateName.SpecializeW);
|
||||||
list.add(cardW.getView());
|
list.add(cardW.getView());
|
||||||
|
|
||||||
Card cardU = Card.fromPaperCard(pc, null);
|
Card cardU = Card.fromPaperCard(pc, null);
|
||||||
cardU.setState(CardStateName.SpecializeU, true);;
|
cardU.setState(CardStateName.SpecializeU, true);
|
||||||
|
cardU.setImageKey(pc, CardStateName.SpecializeU);
|
||||||
list.add(cardU.getView());
|
list.add(cardU.getView());
|
||||||
|
|
||||||
Card cardB = Card.fromPaperCard(pc, null);
|
Card cardB = Card.fromPaperCard(pc, null);
|
||||||
cardB.setState(CardStateName.SpecializeB, true);
|
cardB.setState(CardStateName.SpecializeB, true);
|
||||||
|
cardB.setImageKey(pc, CardStateName.SpecializeB);
|
||||||
list.add(cardB.getView());
|
list.add(cardB.getView());
|
||||||
|
|
||||||
Card cardR = Card.fromPaperCard(pc, null);
|
Card cardR = Card.fromPaperCard(pc, null);
|
||||||
cardR.setState(CardStateName.SpecializeR, true);
|
cardR.setState(CardStateName.SpecializeR, true);
|
||||||
|
cardR.setImageKey(pc, CardStateName.SpecializeR);
|
||||||
list.add(cardR.getView());
|
list.add(cardR.getView());
|
||||||
|
|
||||||
Card cardG = Card.fromPaperCard(pc, null);
|
Card cardG = Card.fromPaperCard(pc, null);
|
||||||
cardG.setState(CardStateName.SpecializeG, true);
|
cardG.setState(CardStateName.SpecializeG, true);
|
||||||
|
cardG.setImageKey(pc, CardStateName.SpecializeG);
|
||||||
list.add(cardG.getView());
|
list.add(cardG.getView());
|
||||||
}
|
}
|
||||||
if (!list.isEmpty())
|
if (!list.isEmpty())
|
||||||
|
|||||||
@@ -1997,7 +1997,9 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
|||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
BoosterDraft draft = parentScreen.getDraft();
|
BoosterDraft draft = parentScreen.getDraft();
|
||||||
if (draft == null) { return; }
|
if (draft == null || !draft.hasNextChoice()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CardPool pool = draft.nextChoice();
|
CardPool pool = draft.nextChoice();
|
||||||
int packNumber = draft.getCurrentBoosterIndex() + 1;
|
int packNumber = draft.getCurrentBoosterIndex() + 1;
|
||||||
|
|||||||
@@ -72,6 +72,21 @@ public class FDeckViewer extends FScreen {
|
|||||||
FOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblDeckListCopiedClipboard", deck.getName()));
|
FOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblDeckListCopiedClipboard", deck.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void copyCollectionToClipboard(CardPool pool) {
|
||||||
|
final String nl = System.lineSeparator();
|
||||||
|
final StringBuilder collectionList = new StringBuilder();
|
||||||
|
Set<String> accounted = new HashSet<>();
|
||||||
|
for (final Entry<PaperCard, Integer> entry : pool) {
|
||||||
|
String cardName = entry.getKey().getCardName();
|
||||||
|
if (!accounted.contains(cardName)) {
|
||||||
|
collectionList.append(pool.countByName(cardName)).append(" ").append(cardName).append(nl);
|
||||||
|
accounted.add(cardName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Forge.getClipboard().setContents(collectionList.toString());
|
||||||
|
FOptionPane.showMessageDialog(Forge.getLocalizer().getMessage("lblCollectionCopiedClipboard"));
|
||||||
|
}
|
||||||
|
|
||||||
private final Deck deck;
|
private final Deck deck;
|
||||||
private final CardManager cardManager;
|
private final CardManager cardManager;
|
||||||
private DeckSection currentSection;
|
private DeckSection currentSection;
|
||||||
|
|||||||
@@ -190,4 +190,8 @@ public abstract class FDisplayObject {
|
|||||||
public boolean keyDown(int keyCode) {
|
public boolean keyDown(int keyCode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean keyUp(int keyCode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Name=kavu
|
|||||||
1 Kavu Primarch|TSR|1
|
1 Kavu Primarch|TSR|1
|
||||||
4 Mountain|MH2|1
|
4 Mountain|MH2|1
|
||||||
3 Mountain|MH2|2
|
3 Mountain|MH2|2
|
||||||
2 Punishing Fire|C11|1
|
2 Punishing Fire|CMD|1
|
||||||
2 Raging Kavu|INV|1
|
2 Raging Kavu|INV|1
|
||||||
2 Ram Through|IKO|1
|
2 Ram Through|IKO|1
|
||||||
2 Sacred Foundry|GRN|1
|
2 Sacred Foundry|GRN|1
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<object id="53" template="../../obj/treasure.tx" x="194" y="125"/>
|
<object id="53" template="../../obj/treasure.tx" x="194" y="125"/>
|
||||||
<object id="54" template="../../obj/enemy.tx" x="201.253" y="161.473">
|
<object id="54" template="../../obj/enemy.tx" x="201.253" y="161.473">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="effect" value="{ "startBattleWithCard": [ "Dreadhorde Invasion" }"/>
|
<property name="effect" value="{ "startBattleWithCard": ["Dreadhorde Invasion"]}"/>
|
||||||
<property name="enemy" value="Big Zombie"/>
|
<property name="enemy" value="Big Zombie"/>
|
||||||
<property name="speedModifier" type="float" value="3"/>
|
<property name="speedModifier" type="float" value="3"/>
|
||||||
<property name="threatRange" type="int" value="60"/>
|
<property name="threatRange" type="int" value="60"/>
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
"type": "item",
|
"type": "item",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"probability": 1,
|
"probability": 1,
|
||||||
"itemName": "Lightbringers Boots'"
|
"itemName": "Lightbringers Boots"
|
||||||
}
|
}
|
||||||
]</property>
|
]</property>
|
||||||
<property name="spawn.Easy" type="bool" value="true"/>
|
<property name="spawn.Easy" type="bool" value="true"/>
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<object id="58" template="../../obj/enemy.tx" x="153" y="516">
|
<object id="58" template="../../obj/enemy.tx" x="153" y="516">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="effect" value="{ "startBattleWithCard": [ "Exquisite Blood" }"/>
|
<property name="effect" value="{ "startBattleWithCard": [ "Exquisite Blood" ] }"/>
|
||||||
<property name="enemy" value="Fallen Angel"/>
|
<property name="enemy" value="Fallen Angel"/>
|
||||||
<property name="threatRange" type="int" value="60"/>
|
<property name="threatRange" type="int" value="60"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<tileset firstgid="1" source="../../tileset/main.tsx"/>
|
<tileset firstgid="1" source="../../tileset/main.tsx"/>
|
||||||
<tileset firstgid="10113" source="../../tileset/buildings.tsx"/>
|
<tileset firstgid="10113" source="../../tileset/buildings.tsx"/>
|
||||||
<tileset firstgid="11905" source="../../tileset/dungeon.tsx"/>
|
<tileset firstgid="11905" source="../../tileset/dungeon.tsx"/>
|
||||||
<tileset firstgid="16001" source="../../tileset/main-nocollide.tsx"/>
|
<tileset firstgid="16385" source="../../tileset/main-nocollide.tsx"/>
|
||||||
<layer id="1" name="Background" width="35" height="25">
|
<layer id="1" name="Background" width="35" height="25">
|
||||||
<data encoding="base64" compression="zlib">
|
<data encoding="base64" compression="zlib">
|
||||||
eJybxsnAMG0AMDYwEO4YCm6hBxhIu9HBqFuwg8HmloFOsyMFqLIPtAsgAOSOUbdggsHijlEwCgYzmCM60C4YBaNg6AIAYHk9+Q==
|
eJybxsnAMG0AMDYwEO4YCm6hBxhIu9HBqFuwg8HmloFOsyMFqLIPtAsgAOSOUbdggsHijlEwCgYzmCM60C4YBaNg6AIAYHk9+Q==
|
||||||
@@ -24,12 +24,12 @@
|
|||||||
</layer>
|
</layer>
|
||||||
<layer id="5" name="AboveSprites" width="35" height="25">
|
<layer id="5" name="AboveSprites" width="35" height="25">
|
||||||
<data encoding="base64" compression="zlib">
|
<data encoding="base64" compression="zlib">
|
||||||
eJzNlktuwjAQhp22Ujelq8SqVJUdN2BTIagESH0seyV6jKqAaLsADsAtOEDLgoPwGAtHHqYe26Qh5Je+lfP4PBk7FqLYDBKesnj4iICzQH6kEL/AQv4d28Tue88LrE3f845hiV0iUrNTugyT/TFbHl/L44LzeSfEBQNNE/XzKNnNCffuB1kvDWmuaeh7H6Tb5a2+TwfoAt8wVrs0+ILr4qsh57KUBpWediraRWV+a+ih+nAunNupXK5grAJco77K4xt9JYa0V2wumDGMTYAp49Ik+3aoC+1dri6Yp6oQz8BL1e6CWcdhLm14Voehq99Dv1NIv2BC9passdXJ5rKO/XvKsUJdsq4lmsjRd+rs0JKG9Do1/2O43Ou6zm520IScm961I/5X/Od/7XNxudl6Nksfr2K3iyt5u6j6pv1waPJ24faKkPM+t/fis8Mh0DWRxaUoXNkCTvTB1g==
|
eJzNlk9OAjEUhztI4gZczTQmBHbcwI0hSCIslC1HgmMQlYAu1AN4A5ccAFlwENHX0Ekfz762jMMwv+Rbdf58ffPaqRDF5inhKYuHjwioBLKSQnwBa/l37Cd233tWYG0ePe+YldglIjU7pcss2R+z5XNUHhecRVOIKgNNF/XzPNnNCffuA1kvHWmu6eh7e9LtMrnapw8MgBcYa58bfMF18dWQc9lIg8pYOxXtorJsGMaoPpwL53YqlxqM1YEL1Fd5fKPnxJD2is0F8wpjb8A749Il+3aoC+1dri6Yu5YQ98CwZXfBbOMwl1t4Vp9hoN9Dv1NIv2BC9passdXJ5rKN/XvKsUJdsq4lmsjRd+rscCMN6XVq/sdwudZ1/bjcQRNybppqR/yv+M//2uficrP1bJY+/o7dLq7k7aLqm/bDocnbhdsrQs773N6Lzw6HQNdEFpeicOUXefTD2g==
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="6" name="Clutter" width="35" height="25">
|
<layer id="6" name="Clutter" width="35" height="25">
|
||||||
<data encoding="base64" compression="zlib">
|
<data encoding="base64" compression="zlib">
|
||||||
eJxjYBgF1Ab/RUgTpxSsEIVgEMgF2rEcyA6XhPAXimLXAxK/5s/AcB2Ib/hTzy0HJfDIhSDYK5HchcuN1HDLSjz+J0WcEjAHaCYTElYOQeXbiaFimLi9GKZZPcHUdx8yQHcLDHPI4tYD8xMhQIwaXKDCgoGh0oJ8/dQEO4Du2Eklt5QHUMccEBDGkff2KTAw7FdA0LiAaCDt3RKjyMAQq4igcYHNFLoFOb0QGy6q7PjNZCazbEBOL8SGCyG30KrMBAGQ3eiYEKBVuUSqOwiBRBFMTAmgpr+p5abBDiipB2gNqFkeUwqoWR5TCigtj0cB5QAAqOk3GA==
|
eJxjYBgF1Ab/RUgTpxSsEIVgEMgF2rEcyA6XhPAXimLXAxIPCwSqA+KIQOq55aAEbjnHMAR7JZK7cLmRGm5Zicf/pIhTAuYAzWRCwotDUfl2YqgYJm4vhmkWTyj13YcM0N0CwxyyuPXA/EQIEKMGF6iwYGCotCBfPzXBDqA7dlLJLd+pmPeEceS9fQoMDPsVEDQuMDWI9m6JUWRgiFVE0LiAcTBl9iOnF2LDRZUdv5nMZJYNyOmF2HAh5BZalZkgALIbHRMCtCqXSHUHIZAogokpAdT0N7XcNNgBJfUArQE1y2NKATXLY0oBpeXxKKAcAABkFTay
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="7" name="AboveAboveClutter" width="35" height="25">
|
<layer id="7" name="AboveAboveClutter" width="35" height="25">
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
<object id="49" template="../../obj/gold.tx" x="48.3333" y="126.333"/>
|
<object id="49" template="../../obj/gold.tx" x="48.3333" y="126.333"/>
|
||||||
<object id="50" template="../../obj/enemy.tx" x="298.667" y="182">
|
<object id="50" template="../../obj/enemy.tx" x="298.667" y="182">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="effect" value="{ "startBattleWithCard": [ "Black Market" }"/>
|
<property name="effect" value="{ "startBattleWithCard": ["Black Market"]}"/>
|
||||||
<property name="enemy" value="Cosmic Horror"/>
|
<property name="enemy" value="Cosmic Horror"/>
|
||||||
<property name="threatRange" type="int" value="40"/>
|
<property name="threatRange" type="int" value="40"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="30" height="17" tilewidth="16" tileheight="16" infinite="0" nextlayerid="8" nextobjectid="113">
|
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="30" height="17" tilewidth="16" tileheight="16" infinite="0" nextlayerid="8" nextobjectid="138">
|
||||||
<editorsettings>
|
<editorsettings>
|
||||||
<export target="wastetown..tmx" format="tmx"/>
|
<export target="wastetown..tmx" format="tmx"/>
|
||||||
</editorsettings>
|
</editorsettings>
|
||||||
@@ -106,36 +106,37 @@
|
|||||||
<property name="threatRange" type="int" value="30"/>
|
<property name="threatRange" type="int" value="30"/>
|
||||||
</properties>
|
</properties>
|
||||||
</object>
|
</object>
|
||||||
<object id="87" template="../../obj/enemy.tx" x="278.667" y="203.667">
|
<object id="87" template="../../obj/enemy.tx" x="276.711" y="206.275">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="enemy" value="Monk"/>
|
<property name="enemy" value="Monk"/>
|
||||||
<property name="threatRange" type="int" value="40"/>
|
<property name="threatRange" type="int" value="40"/>
|
||||||
</properties>
|
</properties>
|
||||||
</object>
|
</object>
|
||||||
<object id="88" template="../../obj/exit.tx" x="162.521" y="212.637" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="89" template="../../obj/exit.tx" x="163.046" y="180.468" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="90" template="../../obj/exit.tx" x="114.792" y="180.818" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="91" template="../../obj/exit.tx" x="114.792" y="116.48" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="92" template="../../obj/exit.tx" x="115.142" y="148.299" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="93" template="../../obj/exit.tx" x="162.696" y="117.179" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="94" template="../../obj/exit.tx" x="162.696" y="85.36" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="95" template="../../obj/exit.tx" x="114.792" y="85.36" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="96" template="../../obj/exit.tx" x="162.696" y="149.348" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="97" template="../../obj/exit.tx" x="227.034" y="148.299" width="24.2714" height="6.20943"/>
|
|
||||||
<object id="98" template="../../obj/exit.tx" x="255.357" y="51.7924" width="15.5298" height="6.20943"/>
|
|
||||||
<object id="99" template="../../obj/exit.tx" x="273.714" y="84.6607" width="24.621" height="6.20943"/>
|
|
||||||
<object id="100" template="../../obj/exit.tx" x="274.413" y="117.179" width="24.621" height="6.20943"/>
|
|
||||||
<object id="101" template="../../obj/exit.tx" x="226.16" y="212.288" width="24.621" height="6.20943"/>
|
|
||||||
<object id="102" template="../../obj/exit.tx" x="275.113" y="148.299" width="24.621" height="6.20943"/>
|
|
||||||
<object id="103" template="../../obj/exit.tx" x="227.558" y="180.468" width="24.621" height="6.20943"/>
|
|
||||||
<object id="104" template="../../obj/exit.tx" x="226.16" y="116.83" width="24.621" height="6.20943"/>
|
|
||||||
<object id="105" template="../../obj/exit.tx" x="225.81" y="84.6607" width="24.621" height="6.20943"/>
|
|
||||||
<object id="106" template="../../obj/exit.tx" x="193.291" y="31.5119" width="29.5163" height="35.5811"/>
|
|
||||||
<object id="107" template="../../obj/exit.tx" x="323.016" y="98.6472" width="8.18684" height="24.0422"/>
|
|
||||||
<object id="108" template="../../obj/exit.tx" x="323.191" y="145.677" width="8.18684" height="24.0422"/>
|
|
||||||
<object id="109" template="../../obj/exit.tx" x="98.3579" y="98.8221" width="8.18684" height="24.0422"/>
|
|
||||||
<object id="110" template="../../obj/exit.tx" x="98.0082" y="148.474" width="8.18684" height="24.0422"/>
|
|
||||||
<object id="111" template="../../obj/waypoint.tx" x="201.099" y="238.512"/>
|
<object id="111" template="../../obj/waypoint.tx" x="201.099" y="238.512"/>
|
||||||
<object id="112" template="../../obj/waypoint.tx" x="201.448" y="105.641"/>
|
<object id="112" template="../../obj/waypoint.tx" x="201.448" y="105.641"/>
|
||||||
|
<object id="113" template="../../obj/collision.tx" x="226.244" y="149.837" width="24.0078" height="5.4"/>
|
||||||
|
<object id="114" template="../../obj/collision.tx" x="226.196" y="181.7" width="24.0078" height="5.4"/>
|
||||||
|
<object id="115" template="../../obj/collision.tx" x="226.996" y="213.5" width="24.0078" height="5.4"/>
|
||||||
|
<object id="116" template="../../obj/collision.tx" x="275.396" y="181.9" width="24.0078" height="5.4"/>
|
||||||
|
<object id="117" template="../../obj/collision.tx" x="274.596" y="117.3" width="24.0078" height="5.4"/>
|
||||||
|
<object id="118" template="../../obj/collision.tx" x="274.596" y="148.9" width="24.0078" height="5.4"/>
|
||||||
|
<object id="119" template="../../obj/collision.tx" x="226.596" y="116.7" width="24.0078" height="5.4"/>
|
||||||
|
<object id="120" template="../../obj/collision.tx" x="227.196" y="85.7" width="24.0078" height="5.4"/>
|
||||||
|
<object id="121" template="../../obj/collision.tx" x="274.996" y="85.3" width="24.0078" height="5.4"/>
|
||||||
|
<object id="122" template="../../obj/collision.tx" x="324.196" y="99.5" width="7.0078" height="23"/>
|
||||||
|
<object id="123" template="../../obj/collision.tx" x="323.896" y="147.7" width="7.0078" height="23"/>
|
||||||
|
<object id="124" template="../../obj/collision.tx" x="99.0961" y="147.9" width="7.0078" height="23"/>
|
||||||
|
<object id="125" template="../../obj/collision.tx" x="98.4961" y="100.3" width="7.0078" height="23"/>
|
||||||
|
<object id="126" template="../../obj/collision.tx" x="115.896" y="116.9" width="22.6078" height="6.6"/>
|
||||||
|
<object id="127" template="../../obj/collision.tx" x="115.496" y="148.7" width="22.6078" height="6.6"/>
|
||||||
|
<object id="128" template="../../obj/collision.tx" x="115.696" y="180.9" width="22.6078" height="6.6"/>
|
||||||
|
<object id="129" template="../../obj/collision.tx" x="163.296" y="212.9" width="22.6078" height="6.6"/>
|
||||||
|
<object id="130" template="../../obj/collision.tx" x="163.296" y="180.5" width="22.6078" height="6.6"/>
|
||||||
|
<object id="131" template="../../obj/collision.tx" x="163.696" y="148.5" width="22.6078" height="6.6"/>
|
||||||
|
<object id="132" template="../../obj/collision.tx" x="163.496" y="116.3" width="22.6078" height="6.6"/>
|
||||||
|
<object id="133" template="../../obj/collision.tx" x="163.296" y="84.1" width="22.6078" height="6.6"/>
|
||||||
|
<object id="134" template="../../obj/collision.tx" x="115.696" y="84.1" width="22.6078" height="6.6"/>
|
||||||
|
<object id="135" template="../../obj/collision.tx" x="256.296" y="51.1" width="16.2078" height="8.4"/>
|
||||||
|
<object id="136" template="../../obj/collision.tx" x="192.496" y="31.9" width="31.2078" height="36.8"/>
|
||||||
</objectgroup>
|
</objectgroup>
|
||||||
</map>
|
</map>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="60" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="13" nextobjectid="119">
|
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="60" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="13" nextobjectid="119">
|
||||||
<editorsettings>
|
<editorsettings>
|
||||||
<export target="wastetown..tmx" format="tmx"/>
|
<export target="wastetown..tmx" format="tmx"/>
|
||||||
</editorsettings>
|
</editorsettings>
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
<property name="enemy" value="Greater Sandwurm"/>
|
<property name="enemy" value="Greater Sandwurm"/>
|
||||||
<property name="hidden" type="bool" value="true"/>
|
<property name="hidden" type="bool" value="true"/>
|
||||||
<property name="speedModifier" type="float" value="40"/>
|
<property name="speedModifier" type="float" value="40"/>
|
||||||
<property name="threatRange" type="int" value="30"/>
|
<property name="threatRange" type="int" value="80"/>
|
||||||
</properties>
|
</properties>
|
||||||
</object>
|
</object>
|
||||||
<object id="115" template="../../obj/enemy.tx" x="855.333" y="361.333">
|
<object id="115" template="../../obj/enemy.tx" x="855.333" y="361.333">
|
||||||
@@ -181,7 +181,7 @@
|
|||||||
<property name="enemy" value="Greater Sandwurm"/>
|
<property name="enemy" value="Greater Sandwurm"/>
|
||||||
<property name="hidden" type="bool" value="true"/>
|
<property name="hidden" type="bool" value="true"/>
|
||||||
<property name="speedModifier" type="float" value="40"/>
|
<property name="speedModifier" type="float" value="40"/>
|
||||||
<property name="threatRange" type="int" value="30"/>
|
<property name="threatRange" type="int" value="70"/>
|
||||||
</properties>
|
</properties>
|
||||||
</object>
|
</object>
|
||||||
<object id="116" template="../../obj/enemy.tx" x="294" y="367.333">
|
<object id="116" template="../../obj/enemy.tx" x="294" y="367.333">
|
||||||
@@ -197,7 +197,7 @@
|
|||||||
<property name="enemy" value="Scarab"/>
|
<property name="enemy" value="Scarab"/>
|
||||||
<property name="hidden" type="bool" value="true"/>
|
<property name="hidden" type="bool" value="true"/>
|
||||||
<property name="speedModifier" type="float" value="40"/>
|
<property name="speedModifier" type="float" value="40"/>
|
||||||
<property name="threatRange" type="int" value="50"/>
|
<property name="threatRange" type="int" value="60"/>
|
||||||
</properties>
|
</properties>
|
||||||
</object>
|
</object>
|
||||||
<object id="118" template="../../obj/booster.tx" x="4" y="641.333">
|
<object id="118" template="../../obj/booster.tx" x="4" y="641.333">
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]</property>
|
]</property>
|
||||||
<property name="displayNameOverride" value="Tibalt's Pet Torturer"/>
|
<property name="displayNameOverride" value="Tibalt's Torturer"/>
|
||||||
<property name="effect">{ "startBattleWithCard": [ "Phyrexian Arena","Xander's Wake"]
|
<property name="effect">{ "startBattleWithCard": [ "Phyrexian Arena","Xander's Wake"]
|
||||||
}</property>
|
}</property>
|
||||||
<property name="enemy" value="Torturer"/>
|
<property name="enemy" value="Torturer"/>
|
||||||
|
|||||||
@@ -162,8 +162,8 @@
|
|||||||
"minHeight": 16,
|
"minHeight": 16,
|
||||||
"rightWidth": 4,
|
"rightWidth": 4,
|
||||||
"leftWidth": 4,
|
"leftWidth": 4,
|
||||||
"bottomHeight": 7,
|
"bottomHeight": 8,
|
||||||
"topHeight": 4,
|
"topHeight": 5,
|
||||||
"offsetX": 0,
|
"offsetX": 0,
|
||||||
"offsetY": 0,
|
"offsetY": 0,
|
||||||
"offsetXspeed": 0,
|
"offsetXspeed": 0,
|
||||||
@@ -566,7 +566,7 @@
|
|||||||
"downFontColor": "RGBA_255_255_255_255",
|
"downFontColor": "RGBA_255_255_255_255",
|
||||||
"overFontColor": "RGBA_255_255_255_255",
|
"overFontColor": "RGBA_255_255_255_255",
|
||||||
"focusedFontColor": "RGBA_255_255_255_255",
|
"focusedFontColor": "RGBA_255_255_255_255",
|
||||||
"disabledFontColor": "RGBA_255_255_255_255",
|
"disabledFontColor": "RGBA_204_200_200_255",
|
||||||
"checkedFontColor": "RGBA_255_255_255_255",
|
"checkedFontColor": "RGBA_255_255_255_255",
|
||||||
"checkedDownFontColor": "RGBA_255_255_255_255",
|
"checkedDownFontColor": "RGBA_255_255_255_255",
|
||||||
"checkedOverFontColor": "RGBA_255_255_255_255",
|
"checkedOverFontColor": "RGBA_255_255_255_255",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Deathknightidle.png
|
deathknightidle.png
|
||||||
size: 80,16
|
size: 80,16
|
||||||
format: RGBA8888
|
format: RGBA8888
|
||||||
filter: Nearest,Nearest
|
filter: Nearest,Nearest
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"width": 100,
|
"width": 100,
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"x": 365,
|
"x": 365,
|
||||||
"y": 60
|
"y": 50
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "TextButton",
|
"type": "TextButton",
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
"width": 100,
|
"width": 100,
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"x": 365,
|
"x": 365,
|
||||||
"y": 110
|
"y": 90
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "TextButton",
|
"type": "TextButton",
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
"width": 100,
|
"width": 100,
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"x": 365,
|
"x": 365,
|
||||||
"y": 160
|
"y": 130
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "TextButton",
|
"type": "TextButton",
|
||||||
@@ -62,6 +62,15 @@
|
|||||||
"width": 100,
|
"width": 100,
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"x": 365,
|
"x": 365,
|
||||||
|
"y": 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "add",
|
||||||
|
"text": "tr(lblAddDeck)",
|
||||||
|
"width": 100,
|
||||||
|
"height": 30,
|
||||||
|
"x": 365,
|
||||||
"y": 210
|
"y": 210
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,33 +15,42 @@
|
|||||||
"x": 4,
|
"x": 4,
|
||||||
"y": 4,
|
"y": 4,
|
||||||
"width": 262,
|
"width": 262,
|
||||||
"height": 414
|
"height": 384
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "add",
|
||||||
|
"text": "tr(lblAddDeck)",
|
||||||
|
"width": 130,
|
||||||
|
"height": 30,
|
||||||
|
"x": 4,
|
||||||
|
"y": 388
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "TextButton",
|
"type": "TextButton",
|
||||||
"name": "delete",
|
"name": "delete",
|
||||||
"text": "tr(lblDelete)",
|
"text": "tr(lblDelete)",
|
||||||
"width": 86,
|
"width": 130,
|
||||||
|
"height": 30,
|
||||||
|
"x": 136,
|
||||||
|
"y": 388
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "copy",
|
||||||
|
"text": "tr(lblCopy)",
|
||||||
|
"width": 130,
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"x": 4,
|
"x": 4,
|
||||||
"y": 418
|
"y": 418
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "TextButton",
|
|
||||||
"name": "copy",
|
|
||||||
"text": "tr(lblCopy)",
|
|
||||||
"width": 86,
|
|
||||||
"height": 30,
|
|
||||||
"x": 92,
|
|
||||||
"y": 418
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "TextButton",
|
"type": "TextButton",
|
||||||
"name": "rename",
|
"name": "rename",
|
||||||
"text": "tr(lblRename)",
|
"text": "tr(lblRename)",
|
||||||
"width": 86,
|
"width": 130,
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"x": 180,
|
"x": 136,
|
||||||
"y": 418
|
"y": 418
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,10 +37,10 @@
|
|||||||
{
|
{
|
||||||
"type": "TextButton",
|
"type": "TextButton",
|
||||||
"name": "done",
|
"name": "done",
|
||||||
"text": "[+OK]",
|
"text": "Back",
|
||||||
"width": 48,
|
"width": 48,
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"binding": "Use",
|
"binding": "Back",
|
||||||
"x": 420,
|
"x": 420,
|
||||||
"y": 120
|
"y": 120
|
||||||
} ,
|
} ,
|
||||||
|
|||||||
@@ -28,6 +28,60 @@
|
|||||||
"height": 20,
|
"height": 20,
|
||||||
"x": 415,
|
"x": 415,
|
||||||
"y": 245
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "details",
|
||||||
|
"text": "[%80] Details",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 210,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "events",
|
||||||
|
"text": "[%80] Events",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 210,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "reputation",
|
||||||
|
"text": "[%80] Reputation",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 210,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "names",
|
||||||
|
"text": "[%80] Names",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 210,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "zoomIn",
|
||||||
|
"text": "[%80]+",
|
||||||
|
"width": 20,
|
||||||
|
"height": 20,
|
||||||
|
"x": 5,
|
||||||
|
"y": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "zoomOut",
|
||||||
|
"text": "[%80]-",
|
||||||
|
"width": 20,
|
||||||
|
"height": 20,
|
||||||
|
"x": 455,
|
||||||
|
"y": 5
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,60 @@
|
|||||||
"height": 20,
|
"height": 20,
|
||||||
"x": 205,
|
"x": 205,
|
||||||
"y": 455
|
"y": 455
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "details",
|
||||||
|
"text": "[%80] Details",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 105,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "events",
|
||||||
|
"text": "[%80] Events",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 105,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "reputation",
|
||||||
|
"text": "[%80] Reputation",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 105,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "names",
|
||||||
|
"text": "[%80] Names",
|
||||||
|
"width": 60,
|
||||||
|
"height": 20,
|
||||||
|
"x": 105,
|
||||||
|
"y": 245
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "zoomIn",
|
||||||
|
"text": "[%80]+",
|
||||||
|
"width": 20,
|
||||||
|
"height": 20,
|
||||||
|
"x": 5,
|
||||||
|
"y": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "zoomOut",
|
||||||
|
"text": "[%80]-",
|
||||||
|
"width": 20,
|
||||||
|
"height": 20,
|
||||||
|
"x": 245,
|
||||||
|
"y": 5
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -141,3 +141,4 @@ Pioneer Masters, 3/6/PIO, PIO
|
|||||||
Innistrad Remastered, 3/6/INR, INR
|
Innistrad Remastered, 3/6/INR, INR
|
||||||
Aetherdrift, 3/6/DFT, DFT
|
Aetherdrift, 3/6/DFT, DFT
|
||||||
Tarkir Dragonstorm, 3/6/TDM, TDM
|
Tarkir Dragonstorm, 3/6/TDM, TDM
|
||||||
|
Final Fantasy, 3/6/FIN, FIN
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ PT:3/2
|
|||||||
K:Flying
|
K:Flying
|
||||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigMill | TriggerDescription$ At the beginning of your upkeep, mill a card. If an instant or sorcery card was milled this way, transform CARDNAME.
|
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigMill | TriggerDescription$ At the beginning of your upkeep, mill a card. If an instant or sorcery card was milled this way, transform CARDNAME.
|
||||||
SVar:TrigMill:DB$ Mill | Defined$ You | RememberMilled$ True | SubAbility$ DBTransform
|
SVar:TrigMill:DB$ Mill | Defined$ You | RememberMilled$ True | SubAbility$ DBTransform
|
||||||
SVar:DBTransform:DB$ SetState | Defined$ Self | ConditionDefined$ Remembered | ConditionPresent$ Card.Instant,Card.Sorcery | SubAbility$ Cleanup | Mode$ Transform
|
SVar:DBTransform:DB$ SetState | Defined$ Self | ConditionDefined$ Remembered | ConditionPresent$ Card.Instant,Card.Sorcery | SubAbility$ DBCleanup | Mode$ Transform
|
||||||
SVar:Cleanup:DB$ Cleanup | ClearRemembered$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
DeckHints:Ability$Delirium & Type$Instant|Sorcery
|
DeckHints:Ability$Delirium & Type$Instant|Sorcery
|
||||||
AlternateMode:DoubleFaced
|
AlternateMode:DoubleFaced
|
||||||
Oracle:Flying\nAt the beginning of your upkeep, mill a card. If an instant or sorcery card was milled this way, transform Aberrant Researcher.
|
Oracle:Flying\nAt the beginning of your upkeep, mill a card. If an instant or sorcery card was milled this way, transform Aberrant Researcher.
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ Types:Legendary Creature Spirit Soldier
|
|||||||
PT:3/4
|
PT:3/4
|
||||||
K:Vigilance
|
K:Vigilance
|
||||||
T:Mode$ BecomesTarget | ValidTarget$ Card.Self | ValidSource$ Ability.numTargets EQ1 | TriggerZones$ Battlefield | Execute$ TrigCopy | TriggerDescription$ Whenever CARDNAME becomes the target of an ability that targets only it, you may pay {1}{R/W}. If you do, copy that ability for each other creature you control that ability could target. Each copy targets a different one of those creatures. ({R/W} can be paid with either {R} or {W}.)
|
T:Mode$ BecomesTarget | ValidTarget$ Card.Self | ValidSource$ Ability.numTargets EQ1 | TriggerZones$ Battlefield | Execute$ TrigCopy | TriggerDescription$ Whenever CARDNAME becomes the target of an ability that targets only it, you may pay {1}{R/W}. If you do, copy that ability for each other creature you control that ability could target. Each copy targets a different one of those creatures. ({R/W} can be paid with either {R} or {W}.)
|
||||||
SVar:TrigCopy:AB$ CopySpellAbility | Cost$ 1 RW | Defined$ TriggeredStackInstance | CopyForEachCanTarget$ Creature.YouCtrl
|
SVar:TrigCopy:AB$ CopySpellAbility | Cost$ 1 RW | Defined$ TriggeredSpellAbility | CopyForEachCanTarget$ Creature.YouCtrl
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
Oracle:Vigilance\nWhenever Agrus Kos, Eternal Soldier becomes the target of an ability that targets only it, you may pay {1}{R/W}. If you do, copy that ability for each other creature you control that ability could target. Each copy targets a different one of those creatures. ({R/W} can be paid with either {R} or {W}.)
|
Oracle:Vigilance\nWhenever Agrus Kos, Eternal Soldier becomes the target of an ability that targets only it, you may pay {1}{R/W}. If you do, copy that ability for each other creature you control that ability could target. Each copy targets a different one of those creatures. ({R/W} can be paid with either {R} or {W}.)
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ SVar:Mana:AB$ Mana | Cost$ T Sac<1/CARDNAME/this artifact> | Produced$ Any | Amo
|
|||||||
K:Class:3:4 R:AddTrigger$ TriggerExplosion
|
K:Class:3:4 R:AddTrigger$ TriggerExplosion
|
||||||
SVar:TriggerExplosion:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | ValidSA$ Spell.ManaFromTreasure | Execute$ TrigDamage | TriggerDescription$ Whenever you cast a spell, if mana from a Treasure was spent to cast it, this Class deals damage equal to that spell's mana value to each opponent.
|
SVar:TriggerExplosion:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | ValidSA$ Spell.ManaFromTreasure | Execute$ TrigDamage | TriggerDescription$ Whenever you cast a spell, if mana from a Treasure was spent to cast it, this Class deals damage equal to that spell's mana value to each opponent.
|
||||||
SVar:TrigDamage:DB$ DealDamage | Defined$ Opponent | NumDmg$ X
|
SVar:TrigDamage:DB$ DealDamage | Defined$ Opponent | NumDmg$ X
|
||||||
SVar:X:TriggeredStackInstance$CardManaCostLKI
|
SVar:X:TriggeredSpellAbility$CardManaCostLKI
|
||||||
Oracle:(Gain the next level as a sorcery to add its ability.)\nWhen Alchemist's Talent enters, create two tapped Treasure tokens.\n{1}{R}: Level 2\nTreasures you control have "{T}, Sacrifice this artifact: Add two mana of any one color."\n{4}{R}: Level 3\nWhenever you cast a spell, if mana from a Treasure was spent to cast it, this Class deals damage equal to that spell's mana value to each opponent.
|
Oracle:(Gain the next level as a sorcery to add its ability.)\nWhen Alchemist's Talent enters, create two tapped Treasure tokens.\n{1}{R}: Level 2\nTreasures you control have "{T}, Sacrifice this artifact: Add two mana of any one color."\n{4}{R}: Level 3\nWhenever you cast a spell, if mana from a Treasure was spent to cast it, this Class deals damage equal to that spell's mana value to each opponent.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user