Compare commits

...

104 Commits

Author SHA1 Message Date
Blacksmith
9a30d78f54 [maven-release-plugin] prepare release forge-1.6.30 2019-11-11 02:45:50 +00:00
Blacksmith
db98ce160b Update README.txt for release 2019-11-11 02:43:16 +00:00
Sol
ce8b5b53e0 Merge branch 'update-release-files' into 'master'
Update Release files

See merge request core-developers/forge!2276
2019-11-11 02:32:02 +00:00
Sol
0c4055726c Update ANNOUNCEMENTS.txt 2019-11-11 02:26:43 +00:00
Michael Kamensky
64ae4bae0c Merge branch 'newBranch' into 'master'
Update some GUI elements on Mobile Networkplay

See merge request core-developers/forge!2274
2019-11-10 06:21:46 +00:00
Anthony Calosa
044cc793e8 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-09 21:04:48 +08:00
Michael Kamensky
e310dc30d7 Merge branch 'pioneerdeckgen' into 'master'
Updated standard deckgen data

See merge request core-developers/forge!2275
2019-11-09 11:41:28 +00:00
Anthony Calosa
f239755249 Fix "controls" when alternating human vs ai, then ai vs ai play on mobile forge,
update refreshfield, update targeting arrows on 3 to 4 players
(shows attacked player on 3/4 player match...)
2019-11-09 19:28:21 +08:00
austinio7116
57686c0554 Updated standard deckgen data
(cherry picked from commit 75f1a60)
2019-11-09 09:04:06 +00:00
Anthony Calosa
5ecde572c3 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-09 06:27:14 +08:00
Anthony Calosa
23e9974950 Update some GUI elements on networkplay -> client 2019-11-09 06:20:13 +08:00
Anthony Calosa
ec98d128f1 prevent npe mojhosto 2019-11-09 06:16:58 +08:00
swordshine
5c07951604 Merge branch 'german-translation' into 'master'
fix typos

See merge request core-developers/forge!2273
2019-11-08 00:43:36 +00:00
Dagin Svezek
7be34625f6 fix typos 2019-11-07 14:03:24 +00:00
swordshine
5f6cb893ef Merge branch 'master' into 'master'
Added puzzle PS_ELD4. Added the relevant functionality to GateState and fixed a NPE.

See merge request core-developers/forge!2271
2019-11-07 06:17:25 +00:00
Agetian
3b636be2fe Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master 2019-11-07 08:10:19 +03:00
Agetian
1af940b034 - Simpler adventure card detection. 2019-11-07 08:08:03 +03:00
Agetian
8cb1789e60 - Added puzzle PS_ELD4.
- Added OnAdventure functionality to game states.
- Fixed a NPE when dev-adding a card to exile.
2019-11-07 08:06:31 +03:00
Michael Kamensky
01782de3a6 Merge branch 'patch-7' into 'master'
Update de-DE.properties from forum (twosat user)

See merge request core-developers/forge!2270
2019-11-07 04:02:59 +00:00
Michael Kamensky
3a7e35c51d Merge branch 'cardtranslationforgecore' into 'master'
Moved CardTranslation to forge-core.

See merge request core-developers/forge!2253
2019-11-07 04:02:57 +00:00
swordshine
bff24a1d3d Merge branch 'patch-6' into 'master'
Replace sprite_icons.png in darkred skin

See merge request core-developers/forge!2269
2019-11-07 00:52:17 +00:00
swordshine
8a075000a2 Merge branch 'patch-5' into 'master'
Replace bg_splash.png in Darkred skin

See merge request core-developers/forge!2268
2019-11-07 00:52:05 +00:00
Churrufli
5e0761d085 Update de-DE.properties from forum (twosat user) 2019-11-06 23:33:57 +00:00
Churrufli
2184ddf1bb Replace sprite_icons.png in darkred skin 2019-11-06 17:54:06 +00:00
Churrufli
fd032f6ccd Replace bg_splash.png in Darkred skin 2019-11-06 17:52:30 +00:00
Hans Mackowiak
164c819523 Merge branch 'patch-5' into 'master'
Update dread_warlock: added Warlock type

See merge request core-developers/forge!2267
2019-11-06 15:06:41 +00:00
Hans Mackowiak
987043ead2 Update dread_warlock: added Warlock type 2019-11-06 15:06:41 +00:00
swordshine
4aa9c224d0 Merge branch 'pioneerrandomquestworld' into 'master'
Pioneer random quest mode

See merge request core-developers/forge!2266
2019-11-06 08:32:13 +00:00
swordshine
2ac6fa4542 Merge branch 'elddeckgendata' into 'master'
Updated Modern and Standard Deckgen Data

See merge request core-developers/forge!2265
2019-11-06 08:31:48 +00:00
swordshine
2797f95cd3 Merge branch 'master' into 'master'
update simplified chinese translation

See merge request core-developers/forge!2264
2019-11-06 08:31:33 +00:00
austinio7116
5eb9be6248 Pioneer random quest mode 2019-11-06 08:07:21 +00:00
austinio7116
23eebf9037 Updated Modern and Standard Deckgen Data 2019-11-06 06:17:41 +00:00
CCTV-1
b59adab68d added missing translation label 2019-11-06 10:45:44 +08:00
CCTV-1
b2d44105be update simplified chinese translation 2019-11-06 10:44:19 +08:00
swordshine
2235546f2a Merge branch 'translation10' into 'master'
More translations: New menu settings, Search, Priority, PayMana, Discard, Order, Exile, Delve, ...

See merge request core-developers/forge!2251
2019-11-06 01:04:53 +00:00
swordshine
59d104f68b Merge branch 'pioneerdeckgen' into 'master'
Pioneer deckgen

See merge request core-developers/forge!2263
2019-11-06 01:04:07 +00:00
swordshine
6abdfd391d Merge branch '1191-format-pioneer' into 'master'
Resolve "Format: pioneer"

Closes #1191

See merge request core-developers/forge!2250
2019-11-06 01:04:02 +00:00
Hans Mackowiak
a6ff0b5b10 Resolve "Format: pioneer" 2019-11-06 01:04:02 +00:00
austinio7116
02969cfe5b Pioneer archetype deck generation added to UI 2019-11-05 23:02:58 +00:00
austinio7116
c6a2c35850 Pioneer initial meta
(cherry picked from commit af89555)
2019-11-05 22:37:00 +00:00
maustin
4c0a71f37d Merge branch '1191-format-pioneer' of https://git.cardforge.org/core-developers/forge into pioneerdeckgen 2019-11-05 22:36:19 +00:00
Hans Mackowiak
74e3bd1895 Pionier: November 2019 Banned cards 2019-11-05 12:05:34 +00:00
Hans Mackowiak
121c9f5012 add PioneerPredicate to magicDb 2019-11-05 08:36:19 +00:00
Hans Mackowiak
7b1cd816b7 Update formats 2019-11-05 08:25:43 +00:00
Michael Kamensky
6a76cc8bc6 Merge branch 'newBranch' into 'master'
Update Network and Dependency files

See merge request core-developers/forge!2259
2019-11-04 16:44:48 +00:00
swordshine
9b9c38126e Merge branch '1200-memory-theft-allows-discarding-of-a-land' into 'master'
Resolve "Memory Theft allows discarding of a land"

Closes #1200

See merge request core-developers/forge!2261
2019-11-04 14:26:01 +00:00
Michael Kamensky
e4ee0c768f Merge branch 'ManaPoolHiddenCleanup' into 'master'
ManaPool: no hidden keyword there, so no need for extra cleanup

See merge request core-developers/forge!2262
2019-11-04 13:46:08 +00:00
Hans Mackowiak
340de153c8 ManaPool: no hidden keyword there, so no need for extra cleanup 2019-11-04 13:46:08 +00:00
Hans Mackowiak
2bf477102d Update memory_theft: add nonLand part 2019-11-04 09:42:30 +00:00
Anthony Calosa
42a15b40b3 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-04 07:47:27 +08:00
Michael Kamensky
a2589cd433 Merge branch 'patch-5' into 'master'
Update net-decks.txt adding Current Pioneer Decks

See merge request core-developers/forge!2260
2019-11-03 13:49:24 +00:00
Churrufli
7ec7025ed4 Update net-decks.txt adding Current Pioneer Decks 2019-11-03 07:40:41 +00:00
Anthony Calosa
5edeb6df94 removed config (log4j2 uses alternate config via xml) 2019-11-02 10:12:59 +08:00
Anthony Calosa
001a1981cf update log4j 1.2.17 -> log4j 2.11.2
(log4j 2.12.x latest needs higher Android API)
2019-11-02 10:07:13 +08:00
Anthony Calosa
446fb59473 some device are looking for this file so include it on storage
java.io.FileNotFoundException:
/storage/emulated/0/Forge/src/main/resources/log4jConfig.config
(No such file or directory)
2019-11-01 21:42:24 +08:00
Anthony Calosa
3b58d6df42 refactor rename 2019-11-01 17:46:14 +08:00
Anthony Calosa
a80c683901 support android 6 (slow networkplay) tested with two Android 6 device 2019-11-01 17:34:42 +08:00
Anthony Calosa
a5b65eaaed add old de/serialization for android 7.1 and below 2019-11-01 15:03:30 +08:00
Anthony Calosa
31182289b7 Update dependency and use custom de/encoder for netty 2019-11-01 12:41:30 +08:00
Anthony Calosa
85eb740264 aifixes NPE 2019-11-01 12:40:40 +08:00
Anthony Calosa
4318e23a40 support UST extended art 2019-11-01 12:39:57 +08:00
Hans Mackowiak
4ca7352d5c Merge branch 'fix-staticabilitycanttarget' into 'master'
Fix StaticAbilityCantTarget check not calling the common routine.

See merge request core-developers/forge!2258
2019-10-29 19:46:37 +00:00
Michael Kamensky
84905bd726 Fix StaticAbilityCantTarget check not calling the common routine. 2019-10-29 19:46:37 +00:00
swordshine
18e16368be Merge branch 'master' into 'master'
Added puzzle PS_ELD3 - Possibility Storm - Throne of Eldraine 03

See merge request core-developers/forge!2257
2019-10-29 07:51:49 +00:00
Agetian
7ed84c4c3f - Added puzzle PS_ELD3. 2019-10-29 09:34:39 +03:00
Michael Kamensky
f334211395 Merge branch 'newBranch' into 'master'
Mobile Forge: Card Sleeves & Round Border Refactor

See merge request core-developers/forge!2255
2019-10-26 14:46:09 +00:00
Anthony Calosa
42f4126aff Prepare Sleeve for Desktop... 2019-10-25 15:37:13 +08:00
Anthony Calosa
5790e29daa Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-10-25 14:22:07 +08:00
Anthony Calosa
88a4a2c6cf Update 2019-10-25 14:21:25 +08:00
swordshine
90b72fc11e Merge branch '1194-resolute-rider-has-incorrect-activated-ability-cost' into 'master'
Resolve "Resolute Rider has incorrect activated ability cost"

Closes #1194

See merge request core-developers/forge!2256
2019-10-24 08:46:54 +00:00
Hans Mackowiak
00391df1f0 Fix Resolute Rider 2019-10-24 07:46:00 +00:00
swordshine
15de0c0bba Merge branch 'master' into 'master'
Added puzzle PS_ELD2 - Possibility Storm - Throne of Eldraine 02

See merge request core-developers/forge!2254
2019-10-24 01:00:06 +00:00
Agetian
a2fdce9be9 - Added puzzle PS_ELD2. 2019-10-23 22:42:52 +03:00
klaxnek
fa6fce9589 Moved CardTranslation to forge-core. We need it to translate card info in forge-game. 2019-10-23 11:47:21 +02:00
Anthony Calosa
cc1f03fc94 Update 2019-10-23 12:57:36 +08:00
Anthony Calosa
8b25f6f129 Fix Foil Overlay when Round Border is enabled 2019-10-23 11:57:56 +08:00
Anthony Calosa
b37937421c Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-10-23 11:52:52 +08:00
klaxnek
4c3e4f2170 Translate PlayerControllerHuman.java. Discard, order of cards, delve, exile. 2019-10-22 13:23:57 +02:00
klaxnek
dc12c50c1a Forgot lblCleanupPhase 2019-10-22 12:56:53 +02:00
klaxnek
2b986f5bac Translate PlayerControllerHuman.java. Discard cards 2019-10-22 12:50:15 +02:00
klaxnek
2accf7543e Translated Input Pay Mana. Expanded sentences in order to translate them. 2019-10-22 12:08:28 +02:00
klaxnek
ba37189410 Translate InputPassPriority.java 2019-10-22 11:36:36 +02:00
Hans Mackowiak
d578eee402 Add Pioneer Format 2019-10-22 08:47:00 +00:00
Hans Mackowiak
5107d89ef5 GameFormat: add Píoneer 2019-10-22 08:45:07 +00:00
Hans Mackowiak
72b8b5c98e Update StaticData: are the Predicates even used? 2019-10-22 08:42:12 +00:00
Anthony Calosa
402885391f Card Sleeves 2019-10-22 16:12:03 +08:00
klaxnek
b4d153ab3b Translate Search word in search filters 2019-10-22 09:51:03 +02:00
klaxnek
1a0cb62ac8 Translate Preload Extended Art 2019-10-22 09:42:16 +02:00
klaxnek
c0baf70c59 Translate new Settings menú 2019-10-22 09:37:05 +02:00
swordshine
166cf2623c Merge branch 'master' into 'master'
update Simplified Chinese translation

See merge request core-developers/forge!2249
2019-10-22 06:02:17 +00:00
CCTV-1
8567b69073 update 'Draft, Gauntlet and Puzzle Screens' Simplified Chinese translation 2019-10-22 13:01:37 +08:00
swordshine
3a4271e66d Merge branch 'updatetranslation' into 'master'
update new settings translation

See merge request core-developers/forge!2246
2019-10-22 03:05:25 +00:00
swordshine
8b723aebd9 Merge branch 'master' into 'master'
update BitmapFontWriter.java to latest version

See merge request core-developers/forge!2243
2019-10-22 03:05:18 +00:00
swordshine
eb59d6c86b Merge branch 'translation09' into 'master'
Mobile: Translate Draft, Gauntlet and Puzzle Screens.

See merge request core-developers/forge!2228
2019-10-22 03:05:04 +00:00
Sol
a291b75dd9 Merge branch 'patch-4' into 'master'
Questing Beast: fix Damage Trigger

See merge request core-developers/forge!2247
2019-10-22 00:41:25 +00:00
Hans Mackowiak
f1a76e1e76 Questing Beast: fix Damage Trigger 2019-10-22 00:41:25 +00:00
Sol
a391f7414f Merge branch 'updateBanList' into 'master'
BanList 2019-10-21

See merge request core-developers/forge!2248
2019-10-22 00:40:49 +00:00
Hans Mackowiak
299de54ba5 BanList 2019-10-21 2019-10-22 00:40:49 +00:00
CCTV-1
37bae14dfd update Simplified Chinese characters list 2019-10-19 10:26:43 +08:00
CCTV-1
d780aa43d4 update new settings translation 2019-10-18 18:30:59 +08:00
CCTV-1
91534776d1 convert \t to four spaces,makes the diff able to read 2019-10-17 11:07:00 +08:00
CCTV-1
31bb611ecf update BitmapFontWriter.java to latest version(https://github.com/libgdx/libgdx/blob/master/extensions/gdx-tools/src/com/badlogic/gdx/tools/bmfont/BitmapFontWriter.java) 2019-10-15 18:35:16 +08:00
Peter
53c88f0302 Added to contributors XD 2019-10-07 22:40:45 +02:00
Peter
ad1cc78578 Mobile: Translate Draft, Gauntlet and Puzzle Screens.
Fixed crash in LoadGameMenu (wrong translated enum...)
2019-10-07 22:39:00 +02:00
138 changed files with 2105 additions and 617 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-ai</artifactId>

View File

@@ -1281,7 +1281,8 @@ public class AiBlockController {
oppCreatureCount = ComputerUtil.countUsefulCreatures(attackersLeft.get(0).getController());
}
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
if (attacker != null && attacker.getOwner() != null)
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
// Temporarily controlled object - don't trade with it
// TODO: find a more reliable way to figure out that control will be reestablished next turn
return false;

View File

@@ -11,10 +11,7 @@ import forge.game.Game;
import forge.game.GameEntity;
import forge.game.ability.AbilityFactory;
import forge.game.ability.effects.DetachedCardEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.card.token.TokenInfo;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
@@ -24,6 +21,7 @@ import forge.game.mana.ManaPool;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.ability.AbilityKey;
import forge.game.trigger.TriggerType;
@@ -362,6 +360,12 @@ public abstract class GameState {
if (c.isFaceDown()) {
newText.append("|FaceDown"); // Exiled face down
}
if (c.isAdventureCard() && c.getZone().is(ZoneType.Exile)) {
// TODO: this will basically default all exiled cards with Adventure to being "On Adventure".
// Need to figure out a better way to detect if it's actually on adventure.
newText.append("|OnAdventure");
}
}
if (zoneType == ZoneType.Battlefield || zoneType == ZoneType.Exile) {
@@ -1202,6 +1206,16 @@ public abstract class GameState {
c.setState(CardStateName.Flipped, true);
} else if (info.startsWith("Meld")) {
c.setState(CardStateName.Meld, true);
} else if (info.startsWith("OnAdventure")) {
String abAdventure = "DB$ Effect | RememberObjects$ Self | StaticAbilities$ Play | ExileOnMoved$ Exile | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.nonCopiedSpell";
AbilitySub saAdventure = (AbilitySub)AbilityFactory.getAbility(abAdventure, c);
StringBuilder sbPlay = new StringBuilder();
sbPlay.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure");
sbPlay.append(" | AffectedZone$ Exile | Description$ You may cast the card.");
saAdventure.setSVar("Play", sbPlay.toString());
saAdventure.setActivatingPlayer(c.getOwner());
saAdventure.resolve();
c.setExiledWith(c); // This seems to be the way it's set up internally. Potentially not needed here?
} else if (info.startsWith("IsCommander")) {
// TODO: This doesn't seem to properly restore the ability to play the commander. Why?
c.setCommander(true);

View File

@@ -45,6 +45,8 @@ public class FightAi extends SpellAbilityAi {
aiCreatures = ComputerUtil.getSafeTargets(ai, sa, aiCreatures);
List<Card> humCreatures = ai.getOpponents().getCreaturesInPlay();
humCreatures = CardLists.getTargetableCards(humCreatures, sa);
if (humCreatures.isEmpty())
return false; //prevent IndexOutOfBoundsException on MOJHOSTO variant
// assumes the triggered card belongs to the ai
if (sa.hasParam("Defined")) {

View File

@@ -63,6 +63,7 @@ public class SacrificeAi extends SpellAbilityAi {
final boolean destroy = sa.hasParam("Destroy");
Player opp = ai.getWeakestOpponent();
if (tgt != null) {
sa.resetTargets();
if (!opp.canBeTargetedBy(sa)) {
@@ -74,8 +75,16 @@ public class SacrificeAi extends SpellAbilityAi {
num = (num == null) ? "1" : num;
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), num, sa);
List<Card> list =
CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
List<Card> list = null;
try {
list = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
} catch (NullPointerException e) {
return false;
} finally {
if (list == null)
return false;
}//prevent NPE on MoJhoSto
for (Card c : list) {
if (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) > 3) {
return false;

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-core</artifactId>
@@ -21,7 +21,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.8.1</version>
</dependency>
</dependencies>

View File

@@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils;
public abstract class LobbyPlayer {
protected String name;
private int avatarIndex = -1;
private int sleeveIndex = -1;
private String avatarCardImageKey;
public LobbyPlayer(String name) {
@@ -59,9 +60,15 @@ public abstract class LobbyPlayer {
public int getAvatarIndex() {
return avatarIndex;
}
public int getSleeveIndex() {
return sleeveIndex;
}
public void setAvatarIndex(int avatarIndex) {
this.avatarIndex = avatarIndex;
}
public void setSleeveIndex(int sleeveIndex) {
this.sleeveIndex = sleeveIndex;
}
public String getAvatarCardImageKey() {
return avatarCardImageKey;

View File

@@ -35,6 +35,7 @@ public class StaticData {
private Predicate<PaperCard> standardPredicate;
private Predicate<PaperCard> brawlPredicate;
private Predicate<PaperCard> pioneerPredicate;
private Predicate<PaperCard> modernPredicate;
private Predicate<PaperCard> commanderPredicate;
private Predicate<PaperCard> oathbreakerPredicate;
@@ -197,13 +198,13 @@ public class StaticData {
public TokenDb getAllTokens() { return allTokens; }
public Predicate<PaperCard> getStandardPredicate() {
return standardPredicate;
}
public void setStandardPredicate(Predicate<PaperCard> standardPredicate) { this.standardPredicate = standardPredicate; }
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = standardPredicate; }
public void setPioneerPredicate(Predicate<PaperCard> pioneerPredicate) { this.pioneerPredicate = pioneerPredicate; }
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = modernPredicate; }
public void setCommanderPredicate(Predicate<PaperCard> commanderPredicate) { this.commanderPredicate = commanderPredicate; }
@@ -211,9 +212,11 @@ public class StaticData {
public void setBrawlPredicate(Predicate<PaperCard> brawlPredicate) { this.brawlPredicate = brawlPredicate; }
public Predicate<PaperCard> getModernPredicate() {
return modernPredicate;
}
public Predicate<PaperCard> getStandardPredicate() { return standardPredicate; }
public Predicate<PaperCard> getPioneerPredicate() { return pioneerPredicate; }
public Predicate<PaperCard> getModernPredicate() { return modernPredicate; }
public Predicate<PaperCard> getCommanderPredicate() { return commanderPredicate; }

View File

@@ -1,9 +1,6 @@
package forge.card;
package forge.util;
import com.esotericsoftware.minlog.Log;
import com.google.common.base.Charsets;
import forge.properties.ForgeConstants;
import forge.util.LineReader;
import java.io.FileInputStream;
import java.io.IOException;
@@ -15,12 +12,12 @@ public class CardTranslation {
private static Map <String, String> translatednames;
private static Map <String, String> translatedtypes;
private static Map <String, String> translatedoracles;
private static String languageSelected;
private static String languageSelected = "en-US";
private static void readTranslationFile(String language) {
private static void readTranslationFile(String language, String languagesDirectory) {
String filename = "cardnames-" + language + ".txt";
try (LineReader translationFile = new LineReader(new FileInputStream(ForgeConstants.LANG_DIR + filename), Charsets.UTF_8)) {
try (LineReader translationFile = new LineReader(new FileInputStream(languagesDirectory + filename), Charsets.UTF_8)) {
for (String line : translationFile.readLines()) {
String[] matches = line.split("\\|");
if (matches.length >= 2) {
@@ -34,7 +31,7 @@ public class CardTranslation {
}
}
} catch (IOException e) {
Log.error("Error reading translation file: cardnames-" + language + ".txt");
System.err.println("Error reading translation file: cardnames-" + language + ".txt");
}
}
@@ -66,7 +63,7 @@ public class CardTranslation {
}
public static HashMap<String, String> getTranslationTexts(String cardname, String altcardname) {
HashMap<String, String> translations = new HashMap<String, String>();
HashMap<String, String> translations = new HashMap<>();
translations.put("name", getTranslatedName(cardname));
translations.put("oracle", getTranslatedOracle(cardname));
translations.put("altname", getTranslatedName(altcardname));
@@ -78,14 +75,14 @@ public class CardTranslation {
return !languageSelected.equals("en-US");
}
public static void preloadTranslation(String language) {
public static void preloadTranslation(String language, String languagesDirectory) {
languageSelected = language;
if (needsTranslation()) {
translatednames = new HashMap<>();
translatedtypes = new HashMap<>();
translatedoracles = new HashMap<>();
readTranslationFile(languageSelected);
readTranslationFile(languageSelected, languagesDirectory);
}
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-game</artifactId>
@@ -32,8 +32,8 @@
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-log4j</artifactId>
<version>1.7.5</version>
<artifactId>sentry-log4j2</artifactId>
<version>1.7.27</version>
</dependency>
</dependencies>

View File

@@ -701,7 +701,9 @@ public class GameAction {
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.Cause, cause);
runParams.put(AbilityKey.Origin, origin.getZoneType().name());
if (origin != null) { // is generally null when adding via dev mode
runParams.put(AbilityKey.Origin, origin.getZoneType().name());
}
if (params != null) {
runParams.putAll(params);
}

View File

@@ -47,7 +47,7 @@ import java.util.Map.Entry;
public class GameFormat implements Comparable<GameFormat> {
private final String name;
public enum FormatType {Sanctioned, Casual, Historic, Digital, Custom}
public enum FormatSubType {Block, Standard, Extended, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom}
public enum FormatSubType {Block, Standard, Extended, Pioneer, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom}
// contains allowed sets, when empty allows all sets
private FormatType formatType;
@@ -290,6 +290,7 @@ public class GameFormat implements Comparable<GameFormat> {
private List<String> coreFormats = new ArrayList<>();
{
coreFormats.add("Standard.txt");
coreFormats.add("Pioneer.txt");
coreFormats.add("Modern.txt");
coreFormats.add("Legacy.txt");
coreFormats.add("Vintage.txt");
@@ -468,6 +469,10 @@ public class GameFormat implements Comparable<GameFormat> {
return this.map.get("Extended");
}
public GameFormat getPioneer() {
return this.map.get("Pioneer");
}
public GameFormat getModern() {
return this.map.get("Modern");
}

View File

@@ -234,7 +234,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
final Card host = sa.getHostCard();
if (mana.addsKeywords(sa) && mana.addsKeywordsType()
&& host.getType().hasStringType(mana.getManaAbility().getAddsKeywordsType())) {
final long timestamp = sa.getHostCard().getGame().getNextTimestamp();
final long timestamp = host.getGame().getNextTimestamp();
final List<String> kws = Arrays.asList(mana.getAddedKeywords().split(" & "));
host.addChangedCardKeywords(kws, null, false, false, timestamp);
if (mana.addsKeywordsUntil()) {
@@ -243,14 +243,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
@Override
public void run() {
if (!kws.isEmpty()) {
for (String kw : kws) {
if (kw.startsWith("HIDDEN")) {
sa.getHostCard().removeHiddenExtrinsicKeyword(kw);
}
}
host.removeChangedCardKeywords(timestamp);
}
host.removeChangedCardKeywords(timestamp);
host.getGame().fireEvent(new GameEventCardStatsChanged(host));
}
};
@@ -261,10 +254,10 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
}
}
if (mana.addsCounters(sa)) {
mana.getManaAbility().createETBCounters(sa.getHostCard());
mana.getManaAbility().createETBCounters(host);
}
if (mana.triggersWhenSpent()) {
mana.getManaAbility().addTriggersWhenSpent(sa, sa.getHostCard());
mana.getManaAbility().addTriggersWhenSpent(sa, host);
}
}
return true;

View File

@@ -44,7 +44,16 @@ public enum PhaseType {
nameForScripts = name_for_scripts;
}
public final boolean phaseforUpdateField() {
boolean result =
((ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(UNTAP)
&& ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(COMBAT_FIRST_STRIKE_DAMAGE))
|| (ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(MAIN2)
&& ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(CLEANUP)));
return result;
}
public final boolean isAfter(final PhaseType phase) {
return ALL_PHASES.indexOf(this) > ALL_PHASES.indexOf(phase);
}

View File

@@ -2430,6 +2430,7 @@ public class Player extends GameEntity implements Comparable<Player> {
controllerCreator = ctrlr;
controller = ctrlr;
updateAvatar();
updateSleeve();
view.updateIsAI(this);
view.updateLobbyPlayerName(this);
}
@@ -2439,6 +2440,10 @@ public class Player extends GameEntity implements Comparable<Player> {
view.updateAvatarCardImageKey(this);
}
public void updateSleeve() {
view.updateSleeveIndex(this);
}
/**
* Run a procedure using a different controller
*/

View File

@@ -85,6 +85,13 @@ public class PlayerView extends GameEntityView {
set(TrackableProperty.AvatarCardImageKey, p.getLobbyPlayer().getAvatarCardImageKey());
}
public int getSleeveIndex() {
return get(TrackableProperty.SleeveIndex);
}
void updateSleeveIndex(Player p) {
set(TrackableProperty.SleeveIndex, p.getLobbyPlayer().getSleeveIndex());
}
public String getCurrentPlaneName() { return get(TrackableProperty.CurrentPlane); }
void updateCurrentPlaneName( String plane ) {
set(TrackableProperty.CurrentPlane, plane);

View File

@@ -124,7 +124,7 @@ public class StaticAbilityCantTarget {
}
}
return true;
return common(st, spellAbility);
}
protected static boolean common(final StaticAbility st, final SpellAbility spellAbility) {

View File

@@ -122,6 +122,7 @@ public enum TrackableProperty {
LobbyPlayerName(TrackableTypes.StringType),
AvatarIndex(TrackableTypes.IntegerType),
AvatarCardImageKey(TrackableTypes.StringType),
SleeveIndex(TrackableTypes.IntegerType),
Opponents(TrackableTypes.PlayerViewCollectionType),
Life(TrackableTypes.IntegerType),
PoisonCounters(TrackableTypes.IntegerType),

View File

@@ -19,7 +19,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-gui-android</artifactId>
@@ -81,17 +81,17 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1-android</version>
<version>28.1-android</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>xmlpull</groupId>

View File

@@ -27,6 +27,8 @@
-dontwarn java.lang.**
-dontwarn org.slf4j.**
-dontwarn javax.**
-dontwarn org.apache.logging.log4j.**
-dontwarn module-info
# mandatory proguard rules for cache2k to keep the core implementation
-dontwarn org.cache2k.impl.xmlConfiguration.**
@@ -48,6 +50,7 @@
-keep class com.google.guava.** { *; }
-keep class com.google.common.** { *; }
-keep class io.sentry.event.Event { *; }
-keep class io.netty.util.internal.logging.** { *; }
-keepclassmembers class com.badlogic.gdx.backends.android.AndroidInput* {
<init>(com.badlogic.gdx.Application, android.content.Context, java.lang.Object, com.badlogic.gdx.backends.android.AndroidApplicationConfiguration);

View File

@@ -14,6 +14,7 @@ import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
@@ -71,7 +72,8 @@ public class Main extends AndroidApplication {
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
initialize(Forge.getApp(new AndroidClipboard(), adapter, assetsDir));
boolean value = Build.VERSION.SDK_INT >= 26;
initialize(Forge.getApp(new AndroidClipboard(), adapter, assetsDir, value));
}
/*@Override

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-gui-desktop</artifactId>
@@ -142,12 +142,12 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1-android</version>
<version>28.1-android</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
<version>1.4.11.1</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
@@ -168,9 +168,14 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.googlecode</groupId>
@@ -180,7 +185,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>

View File

@@ -202,6 +202,14 @@ public class GuiDesktop implements IGuiBase {
return 0;
}
@Override
public int getSleevesCount() {
if (FSkin.isLoaded()) {
return FSkin.getSleeves().size();
}
return 0;
}
@Override
public String showFileDialog(final String title, final String defaultDir) {
final JFileChooser fc = new JFileChooser(defaultDir);

View File

@@ -383,6 +383,11 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
updateMatrix(FModel.getFormats().getStandard());
}
break;
case PIONEER_CARDGEN_DECK:
if(FModel.isdeckGenMatrixLoaded()) {
updateMatrix(FModel.getFormats().getPioneer());
}
break;
case MODERN_CARDGEN_DECK:
if(FModel.isdeckGenMatrixLoaded()) {
updateMatrix(FModel.getFormats().getModern());

View File

@@ -14,6 +14,7 @@ import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JPopupMenu;
import forge.screens.home.sanctioned.SleeveSelector;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils;
@@ -66,7 +67,8 @@ public class PlayerPanel extends FPanel {
private final FLabel nameRandomiser;
private final FLabel avatarLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build();
private int avatarIndex;
private final FLabel sleeveLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build();
private int avatarIndex, sleeveIndex;
private final FTextField txtPlayerName = new FTextField.Builder().build();
private FRadioButton radioHuman;
@@ -127,6 +129,10 @@ public class PlayerPanel extends FPanel {
createAvatar();
this.add(avatarLabel, "spany 2, width 80px, height 80px");
/*TODO Layout and Override for PC*/
//createSleeve();
//this.add(sleeveLabel, "spany 2, width 60px, height 80px");
createNameEditor();
this.add(lobby.newLabel(localizer.getMessage("lblName") +":"), "w 40px, h 30px, gaptop 5px");
this.add(txtPlayerName, "h 30px, pushx, growx");
@@ -204,6 +210,10 @@ public class PlayerPanel extends FPanel {
avatarLabel.setIcon(FSkin.getAvatars().get(Integer.valueOf(type == LobbySlotType.OPEN ? -1 : avatarIndex)));
avatarLabel.repaintSelf();
sleeveLabel.setEnabled(mayEdit);
sleeveLabel.setIcon(FSkin.getSleeves().get(Integer.valueOf(type == LobbySlotType.OPEN ? -1 : sleeveIndex)));
sleeveLabel.repaintSelf();
txtPlayerName.setEnabled(mayEdit);
txtPlayerName.setText(type == LobbySlotType.OPEN ? StringUtils.EMPTY : playerName);
nameRandomiser.setEnabled(mayEdit);
@@ -332,6 +342,62 @@ public class PlayerPanel extends FPanel {
}
};
/** Listens to sleeve buttons and gives the appropriate player focus. */
private final FocusAdapter sleeveFocusListener = new FocusAdapter() {
@Override
public void focusGained(final FocusEvent e) {
lobby.changePlayerFocus(index);
}
};
private final FMouseAdapter sleeveMouseListener = new FMouseAdapter() {
@Override public final void onLeftClick(final MouseEvent e) {
if (!sleeveLabel.isEnabled()) {
return;
}
final FLabel sleeve = (FLabel)e.getSource();
lobby.changePlayerFocus(index);
sleeve.requestFocusInWindow();
final SleeveSelector sSel = new SleeveSelector(playerName, sleeveIndex, lobby.getUsedSleeves());
for (final FLabel lbl : sSel.getSelectables()) {
lbl.setCommand(new UiCommand() {
@Override
public void run() {
setSleeveIndex(Integer.valueOf(lbl.getName().substring(11)));
sSel.setVisible(false);
}
});
}
sSel.setVisible(true);
sSel.dispose();
if (index < 2) {
lobby.updateSleevePrefs();
}
lobby.firePlayerChangeListener(index);
}
@Override public final void onRightClick(final MouseEvent e) {
if (!sleeveLabel.isEnabled()) {
return;
}
lobby.changePlayerFocus(index);
sleeveLabel.requestFocusInWindow();
setRandomSleeve();
if (index < 2) {
lobby.updateSleevePrefs();
}
}
};
private void updateVariantControlsVisibility() {
final boolean isOathbreaker = lobby.hasVariant(GameType.Oathbreaker);
final boolean isTinyLeaders = lobby.hasVariant(GameType.TinyLeaders);
@@ -703,6 +769,20 @@ public class PlayerPanel extends FPanel {
avatarLabel.addMouseListener(avatarMouseListener);
}
private void createSleeve() {
final String[] currentPrefs = FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(",");
if (index < currentPrefs.length) {
sleeveIndex = Integer.parseInt(currentPrefs[index]);
sleeveLabel.setIcon(FSkin.getSleeves().get(sleeveIndex));
} else {
setRandomSleeve(false);
}
sleeveLabel.setToolTipText("L-click: Select sleeve. R-click: Randomize sleeve.");
sleeveLabel.addFocusListener(sleeveFocusListener);
sleeveLabel.addMouseListener(sleeveMouseListener);
}
/** Applies a random avatar, avoiding avatars already used. */
private void setRandomAvatar() {
setRandomAvatar(true);
@@ -721,6 +801,24 @@ public class PlayerPanel extends FPanel {
}
}
/** Applies a random sleeve, avoiding sleeve already used. */
private void setRandomSleeve() {
setRandomSleeve(true);
}
private void setRandomSleeve(final boolean fireListeners) {
int random = 0;
final List<Integer> usedSleeves = lobby.getUsedSleeves();
do {
random = MyRandom.getRandom().nextInt(FSkin.getSleeves().size());
} while (usedSleeves.contains(random));
setSleeveIndex(random);
if (fireListeners) {
lobby.firePlayerChangeListener(index);
}
}
private final FSkin.LineSkinBorder focusedBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3);
private final FSkin.LineSkinBorder defaultBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_THEME).alphaColor(200), 2);
@@ -746,6 +844,16 @@ public class PlayerPanel extends FPanel {
avatarLabel.repaintSelf();
}
public int getSleeveIndex() {
return sleeveIndex;
}
public void setSleeveIndex(final int sleeveIndex0) {
sleeveIndex = sleeveIndex0;
final SkinImage icon = FSkin.getSleeves().get(sleeveIndex);
sleeveLabel.setIcon(icon);
sleeveLabel.repaintSelf();
}
public int getTeam() {
return teamComboBox.getSelectedIndex();
}

View File

@@ -3,6 +3,7 @@ package forge.screens.home;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.GuiBase;
import forge.UiCommand;
import forge.ai.AIOption;
import forge.deck.*;
@@ -222,6 +223,7 @@ public class VLobby implements ILobbyView {
DeckType selectedDeckType = deckChooser.getSelectedDeckType();
switch (selectedDeckType){
case STANDARD_CARDGEN_DECK:
case PIONEER_CARDGEN_DECK:
case MODERN_CARDGEN_DECK:
case LEGACY_CARDGEN_DECK:
case VINTAGE_CARDGEN_DECK:
@@ -258,6 +260,9 @@ public class VLobby implements ILobbyView {
addPlayerBtn.setEnabled(activePlayersNum < MAX_PLAYERS);
final boolean allowNetworking = lobby.isAllowNetworking();
GuiBase.setNetworkplay(allowNetworking);
ImmutableList<VariantCheckBox> vntBoxes = null;
if (allowNetworking) {
vntBoxes = vntBoxesNetwork;
@@ -397,7 +402,7 @@ public class VLobby implements ILobbyView {
private UpdateLobbyPlayerEvent getSlot(final int index) {
final PlayerPanel panel = playerPanels.get(index);
return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions());
return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), -1/*TODO panel.getSleeveIndex()*/, panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions());
}
/** Builds the actual deck panel layouts for each player.
@@ -858,6 +863,15 @@ public class VLobby implements ILobbyView {
prefs.save();
}
/** Saves sleeve prefs for players one and two. */
void updateSleevePrefs() {
final int pOneIndex = playerPanels.get(0).getSleeveIndex();
final int pTwoIndex = playerPanels.get(1).getSleeveIndex();
prefs.setPref(FPref.UI_SLEEVES, pOneIndex + "," + pTwoIndex);
prefs.save();
}
/** Adds a pre-styled FLabel component with the specified title. */
FLabel newLabel(final String title) {
return new FLabel.Builder().text(title).fontSize(14).fontStyle(Font.ITALIC).build();
@@ -871,6 +885,14 @@ public class VLobby implements ILobbyView {
return usedAvatars;
}
List<Integer> getUsedSleeves() {
final List<Integer> usedSleeves = Lists.newArrayListWithCapacity(MAX_PLAYERS);
for (final PlayerPanel pp : playerPanels) {
usedSleeves.add(pp.getSleeveIndex());
}
return usedSleeves;
}
private static final ImmutableList<String> genderOptions = ImmutableList.of("Male", "Female", "Any"),
typeOptions = ImmutableList.of("Fantasy", "Generic", "Any");

View File

@@ -72,6 +72,7 @@ public enum CSubmenuGauntletQuick implements ICDoc {
if (view.getBoxColorDecks().isSelected()) { allowedDeckTypes.add(DeckType.COLOR_DECK); }
if (view.getBoxStandardColorDecks().isSelected()) { allowedDeckTypes.add(DeckType.STANDARD_COLOR_DECK); }
if (view.getBoxStandardGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.STANDARD_CARDGEN_DECK); }
if (view.getBoxPioneerGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.PIONEER_CARDGEN_DECK); }
if (view.getBoxModernGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.MODERN_CARDGEN_DECK); }
if (view.getBoxLegacyGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.LEGACY_CARDGEN_DECK); }
if (view.getBoxVintageGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.VINTAGE_CARDGEN_DECK); }

View File

@@ -56,6 +56,7 @@ public enum VSubmenuGauntletQuick implements IVSubmenu<CSubmenuGauntletQuick> {
private final JCheckBox boxColorDecks = new FCheckBox(DeckType.COLOR_DECK.toString());
private final JCheckBox boxStandardColorDecks = new FCheckBox(DeckType.STANDARD_COLOR_DECK.toString());
private final JCheckBox boxStandardCardgenDecks = new FCheckBox(DeckType.STANDARD_CARDGEN_DECK.toString());
private final JCheckBox boxPioneerCardgenDecks = new FCheckBox(DeckType.PIONEER_CARDGEN_DECK.toString());
private final JCheckBox boxModernCardgenDecks = new FCheckBox(DeckType.MODERN_CARDGEN_DECK.toString());
private final JCheckBox boxLegacyCardgenDecks = new FCheckBox(DeckType.LEGACY_CARDGEN_DECK.toString());
private final JCheckBox boxVintageCardgenDecks = new FCheckBox(DeckType.VINTAGE_CARDGEN_DECK.toString());
@@ -88,11 +89,13 @@ public enum VSubmenuGauntletQuick implements IVSubmenu<CSubmenuGauntletQuick> {
boxStandardColorDecks.setSelected(true);
if(FModel.isdeckGenMatrixLoaded()) {
boxStandardCardgenDecks.setSelected(true);
boxPioneerCardgenDecks.setSelected(true);
boxModernCardgenDecks.setSelected(true);
boxLegacyCardgenDecks.setSelected(true);
boxVintageCardgenDecks.setSelected(true);
}else{
boxStandardCardgenDecks.setSelected(false);
boxPioneerCardgenDecks.setSelected(false);
boxModernCardgenDecks.setSelected(false);
boxLegacyCardgenDecks.setSelected(false);
boxVintageCardgenDecks.setSelected(false);
@@ -121,6 +124,7 @@ public enum VSubmenuGauntletQuick implements IVSubmenu<CSubmenuGauntletQuick> {
pnlOptions.add(boxColorDecks, "w 96%!, h 30px!, gap 2% 0 0 5px");
if(FModel.isdeckGenMatrixLoaded()) {
pnlOptions.add(boxStandardCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px");
pnlOptions.add(boxPioneerCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px");
pnlOptions.add(boxModernCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px");
pnlOptions.add(boxLegacyCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px");
pnlOptions.add(boxVintageCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px");
@@ -221,6 +225,9 @@ public enum VSubmenuGauntletQuick implements IVSubmenu<CSubmenuGauntletQuick> {
public JCheckBox getBoxModernGenDecks() {
return boxModernCardgenDecks;
}
public JCheckBox getBoxPioneerGenDecks() {
return boxPioneerCardgenDecks;
}
public JCheckBox getBoxLegacyGenDecks() {
return boxLegacyCardgenDecks;
}

View File

@@ -0,0 +1,71 @@
package forge.screens.home.sanctioned;
import forge.gui.WrapLayout;
import forge.toolbox.FLabel;
import forge.toolbox.FScrollPane;
import forge.toolbox.FSkin;
import forge.view.FDialog;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@SuppressWarnings("serial")
public class SleeveSelector extends FDialog {
private final List<FLabel> selectables = new ArrayList<>();
private final Map<Integer, FSkin.SkinImage> sleeveMap = FSkin.getSleeves();
public SleeveSelector(final String playerName, final int currentIndex, final Collection<Integer> usedIndices) {
this.setTitle("Select Sleeve for " + playerName);
final JPanel pnlSleevePics = new JPanel(new WrapLayout());
pnlSleevePics.setOpaque(false);
pnlSleevePics.setOpaque(false);
final FLabel initialSelection = makeSleeveLabel(sleeveMap.get(currentIndex), currentIndex, currentIndex);
pnlSleevePics.add(initialSelection);
for (final Integer i : sleeveMap.keySet()) {
if (currentIndex != i) {
pnlSleevePics.add(makeSleeveLabel(sleeveMap.get(i), i, currentIndex));
}
}
final int width = this.getOwner().getWidth() * 3 / 4;
final int height = this.getOwner().getHeight() * 3 / 4;
this.setPreferredSize(new Dimension(width, height));
this.setSize(width, height);
final FScrollPane scroller = new FScrollPane(pnlSleevePics, false);
scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
this.add(scroller, "w 100%-24px!, pushy, growy, gap 12px 0 0 0");
this.setDefaultFocus(initialSelection);
}
private FLabel makeSleeveLabel(final FSkin.SkinImage img0, final int index0, final int oldIndex) {
final FLabel lbl = new FLabel.Builder().icon(img0).iconScaleFactor(0.95).iconAlignX(SwingConstants.CENTER)
.iconInBackground(true).hoverable(true).selectable(true).selected(oldIndex == index0)
.unhoveredAlpha(oldIndex == index0 ? 0.9f : 0.7f).build();
final Dimension size = new Dimension(60, 80);
lbl.setPreferredSize(size);
lbl.setMaximumSize(size);
lbl.setMinimumSize(size);
lbl.setName("SleeveLabel" + index0);
if (oldIndex == index0) {
lbl.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3));
}
selectables.add(lbl);
return lbl;
}
public List<FLabel> getSelectables() {
return this.selectables;
}
}

View File

@@ -859,6 +859,7 @@ public class FSkin {
}
private static Map<Integer, SkinImage> avatars;
private static Map<Integer, SkinImage> sleeves;
private static Map<Integer, Font> fixedFonts = new HashMap<>();
public static Font getFixedFont() {
@@ -1039,7 +1040,7 @@ public class FSkin {
private static String preferredDir;
private static String preferredName;
private static BufferedImage bimDefaultSprite, bimFavIcon, bimPreferredSprite, bimFoils, bimQuestDraftDeck,
bimOldFoils, bimDefaultAvatars, bimPreferredAvatars, bimTrophies, bimAbilities, bimManaIcons;
bimOldFoils, bimDefaultAvatars, bimPreferredAvatars, bimTrophies, bimAbilities, bimManaIcons, bimDefaultSleeve, bimDefaultSleeve2;
private static int x0, y0, w0, h0, newW, newH, preferredW, preferredH;
private static int[] tempCoords;
private static int defaultFontSize = 12;
@@ -1173,6 +1174,8 @@ public class FSkin {
final File f9 = new File(defaultDir + ForgeConstants.SPRITE_FAVICONS_FILE);
final File f10 = new File(defaultDir + ForgeConstants.SPRITE_ABILITY_FILE);
final File f11 = new File(defaultDir + ForgeConstants.SPRITE_MANAICONS_FILE);
final File f12 = new File(defaultDir + ForgeConstants.SPRITE_SLEEVES_FILE);
final File f13 = new File(defaultDir + ForgeConstants.SPRITE_SLEEVES2_FILE);
try {
int p = 0;
@@ -1190,6 +1193,10 @@ public class FSkin {
FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p);
bimDefaultAvatars = ImageIO.read(f4);
FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p);
bimDefaultSleeve = ImageIO.read(f12);
FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p);
bimDefaultSleeve2 = ImageIO.read(f13);
FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p);
bimTrophies = ImageIO.read(f7);
FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p);
bimQuestDraftDeck = ImageIO.read(f8);
@@ -1255,6 +1262,8 @@ public class FSkin {
// Assemble avatar images
assembleAvatars();
// Sleeves
assembleSleeves();
// Images loaded; can start UI init.
FView.SINGLETON_INSTANCE.setSplashProgessBarMessage("Creating display components.");
@@ -1266,6 +1275,8 @@ public class FSkin {
bimOldFoils.flush();
bimPreferredSprite.flush();
bimDefaultAvatars.flush();
bimDefaultSleeve.flush();
bimDefaultSleeve2.flush();
bimQuestDraftDeck.flush();
bimTrophies.flush();
bimAbilities.flush();
@@ -1278,6 +1289,8 @@ public class FSkin {
bimOldFoils = null;
bimPreferredSprite = null;
bimDefaultAvatars = null;
bimDefaultSleeve = null;
bimDefaultSleeve2 = null;
bimPreferredAvatars = null;
bimQuestDraftDeck = null;
bimTrophies = null;
@@ -1379,6 +1392,10 @@ public class FSkin {
return avatars;
}
public static Map<Integer, SkinImage> getSleeves() {
return sleeves;
}
public static boolean isLoaded() { return loaded; }
/**
@@ -1482,6 +1499,34 @@ public class FSkin {
}
}
private static void assembleSleeves() {
sleeves = new HashMap<>();
int counter = 0;
Color pxTest;
final int pw = bimDefaultSleeve.getWidth();
final int ph = bimDefaultSleeve.getHeight();
for (int j = 0; j < ph; j += 500) {
for (int i = 0; i < pw; i += 360) {
pxTest = getColorFromPixel(bimDefaultSleeve.getRGB(i + 180, j + 250));
if (pxTest.getAlpha() == 0) { continue; }
sleeves.put(counter++, new SkinImage(bimDefaultSleeve.getSubimage(i, j, 360, 500)));
}
}
//2nd set
final int aw = bimDefaultSleeve2.getWidth();
final int ah = bimDefaultSleeve2.getHeight();
for (int j = 0; j < ah; j += 500) {
for (int i = 0; i < aw; i += 360) {
pxTest = getColorFromPixel(bimDefaultSleeve2.getRGB(i + 180, j + 250));
if (pxTest.getAlpha() == 0) { continue; }
sleeves.put(counter++, new SkinImage(bimDefaultSleeve2.getSubimage(i, j, 360, 500)));
}
}
}
private static void setImage(final FSkinProp s0, final BufferedImage bim) {
tempCoords = s0.getCoords();
x0 = tempCoords[0];

View File

@@ -49,6 +49,9 @@ public final class Main {
//setup GUI interface
GuiBase.setInterface(new GuiDesktop());
//set PropertyConfig log4j to true
GuiBase.enablePropertyConfig(true);
//install our error handler
ExceptionHandler.registerErrorHandling();

View File

@@ -21,7 +21,6 @@ import forge.CachedCardImage;
import forge.FThreads;
import forge.StaticData;
import forge.card.CardEdition;
import forge.card.CardTranslation;
import forge.card.mana.ManaCost;
import forge.game.card.Card;
import forge.game.card.CardView;
@@ -39,6 +38,7 @@ import forge.screens.match.CMatchUI;
import forge.toolbox.CardFaceSymbols;
import forge.toolbox.FSkin.SkinnedPanel;
import forge.toolbox.IDisposable;
import forge.util.CardTranslation;
import forge.view.arcane.util.OutlinedLabel;
import javax.swing.*;

View File

@@ -12,7 +12,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-gui-ios</artifactId>

View File

@@ -29,7 +29,7 @@ public class Main extends IOSApplication.Delegate {
final IOSApplicationConfiguration config = new IOSApplicationConfiguration();
config.useAccelerometer = false;
config.useCompass = false;
final ApplicationListener app = Forge.getApp(new IOSClipboard(), new IOSAdapter(), assetsDir);
final ApplicationListener app = Forge.getApp(new IOSClipboard(), new IOSAdapter(), assetsDir, false);
final IOSApplication iosApp = new IOSApplication(app, config);
return iosApp;
}

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-gui-mobile-dev</artifactId>

View File

@@ -93,7 +93,7 @@ public class Main {
config.useHDPI = desktopMode; // enable HiDPI on Mac OS
new LwjglApplication(Forge.getApp(new LwjglClipboard(), new DesktopAdapter(switchOrientationFile),
desktopMode ? desktopModeAssetsDir : assetsDir), config);
desktopMode ? desktopModeAssetsDir : assetsDir, true), config);
}
private static class DesktopAdapter implements IDeviceAdapter {

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-gui-mobile</artifactId>
@@ -48,17 +48,17 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1-android</version>
<version>28.1-android</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>

View File

@@ -10,7 +10,6 @@ import forge.assets.AssetsDownloader;
import forge.assets.FSkin;
import forge.assets.FSkinFont;
import forge.assets.ImageCache;
import forge.card.CardTranslation;
import forge.error.BugReporter;
import forge.error.ExceptionHandler;
import forge.interfaces.IDeviceAdapter;
@@ -31,6 +30,7 @@ import forge.toolbox.FGestureAdapter;
import forge.toolbox.FOptionPane;
import forge.toolbox.FOverlay;
import forge.util.Callback;
import forge.util.CardTranslation;
import forge.util.FileUtil;
import forge.util.Localizer;
import forge.util.Utils;
@@ -67,11 +67,12 @@ public class Forge implements ApplicationListener {
public static boolean enablePreloadExtendedArt = false;
public static String locale = "en-US";
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0) {
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value) {
if (GuiBase.getInterface() == null) {
clipboard = clipboard0;
deviceAdapter = deviceAdapter0;
GuiBase.setInterface(new GuiMobile(assetDir0));
GuiBase.enablePropertyConfig(value);
}
return app;
}
@@ -129,13 +130,13 @@ public class Forge implements ApplicationListener {
FSkinFont.preloadAll(locale);
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblLoadingCardTranslations"));
CardTranslation.preloadTranslation(locale);
CardTranslation.preloadTranslation(locale, ForgeConstants.LANG_DIR);
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblFinishingStartup"));
//add reminder to preload
if (enablePreloadExtendedArt)
splashScreen.getProgressBar().setDescription("Preload Extended Art...");
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblPreloadExtendedArt"));
Gdx.app.postRunnable(new Runnable() {
@Override
public void run() {

View File

@@ -244,6 +244,14 @@ public class GuiMobile implements IGuiBase {
return 0;
}
@Override
public int getSleevesCount() {
if (FSkin.isLoaded()) {
return FSkin.getSleeves().size();
}
return 0;
}
@Override
public String showFileDialog(final String title, final String defaultDir) {
return ForgeConstants.USER_GAMES_DIR + "Test.fgs"; //TODO: Show dialog

View File

@@ -16,7 +16,6 @@
package forge.assets;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.PixmapIO;
@@ -25,29 +24,30 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph;
import com.badlogic.gdx.graphics.g2d.PixmapPacker.Page;
import com.badlogic.gdx.utils.Array;
/** A utility to output BitmapFontData to a FNT file. This can be useful for caching the result from TrueTypeFont, for faster load
* times.
*
* The font format is from the AngelCodeFont BMFont tool.
*
* @author mattdesl AKA davedes */
/**
* This file is 'borrowed' from gdx-tools in the libgdx source
*/
public class BitmapFontWriter {
/** A utility to output BitmapFontData to a FNT file. This can be useful for caching the result from TrueTypeFont, for faster load
* times.
* <p>
* The font file format is from the AngelCodeFont BMFont tool.
* <p>
* Output is nearly identical to the FreeType settting in the Hiero tool {@Link com.badlogic.gdx.tools.hiero.Hiero}. BitmapFontWriter gives more flexibility, eg
* borders and shadows can be used. Hiero is able to avoid outputting the same glyph image more than once if multiple character
* codes have the exact same glyph.
* @author mattdesl AKA davedes */
public class BitmapFontWriter {
/** The output format. */
public enum OutputFormat {
public static enum OutputFormat {
/** AngelCodeFont text format */
Text,
/** AngelCodeFont XML format */
XML
XML;
}
/** The output format */
private static OutputFormat format = OutputFormat.Text;
@@ -55,26 +55,25 @@ import com.badlogic.gdx.utils.Array;
* Pixi.js).
*
* @param fmt the output format to use */
public static void setOutputFormat(OutputFormat fmt) {
if (fmt==null)
throw new NullPointerException("format cannot be null");
public static void setOutputFormat (OutputFormat fmt) {
if (fmt == null) throw new NullPointerException("format cannot be null");
format = fmt;
}
/** Returns the currently used output format.
* @return the output format */
public static OutputFormat getOutputFormat() {
public static OutputFormat getOutputFormat () {
return format;
}
/** The Padding parameter for FontInfo. */
public static class Padding {
public int up, down, left, right;
public Padding() {
public Padding () {
}
public Padding(int up, int down, int left, int right) {
public Padding (int up, int down, int left, int right) {
this.up = up;
this.down = down;
this.left = left;
@@ -87,8 +86,8 @@ import com.badlogic.gdx.utils.Array;
public int horizontal, vertical;
}
/** The font "info" line; this will be ignored by LibGDX's BitmapFont reader,
* but useful for clean and organized output. */
/** The font "info" line; everything except padding and override metrics are ignored by LibGDX's BitmapFont reader, it is otherwise just useful for
* clean and organized output. */
public static class FontInfo {
/** Face name */
public String face;
@@ -113,32 +112,55 @@ import com.badlogic.gdx.utils.Array;
/** Horizontal/vertical spacing that was applied to font */
public Spacing spacing = new Spacing();
public int outline = 0;
public FontInfo() {
/** Override metrics */
public boolean hasOverrideMetrics;
public float ascent;
public float descent;
public float down;
public float capHeight;
public float lineHeight;
public float spaceXAdvance;
public float xHeight;
public FontInfo () {
}
public FontInfo(String face, int size) {
public FontInfo (String face, int size) {
this.face = face;
this.size = size;
}
public void overrideMetrics (BitmapFontData data) {
hasOverrideMetrics = true;
ascent = data.ascent;
descent = data.descent;
down = data.down;
capHeight = data.capHeight;
lineHeight = data.lineHeight;
spaceXAdvance = data.spaceXadvance;
xHeight = data.xHeight;
}
}
private static String quote(Object params) {
private static String quote (Object params) {
return quote(params, false);
}
private static String quote(Object params, boolean spaceAfter) {
private static String quote (Object params, boolean spaceAfter) {
if (BitmapFontWriter.getOutputFormat() == OutputFormat.XML)
return "\"" + params.toString().trim() + "\"" + (spaceAfter ? " " : "");
else
return params.toString();
}
/** Writes the given BitmapFontData to a file, using the specified <tt>pageRefs</tt> strings as the image paths for each texture
* page. The glyphs in BitmapFontData have a "page" id, which references the index of the pageRef you specify here.
/** Writes the given BitmapFontData to a file, using the specified <tt>pageRefs</tt> strings as the image paths for each
* texture page. The glyphs in BitmapFontData have a "page" id, which references the index of the pageRef you specify here.
*
* The FontInfo parameter is useful for cleaner output; such as including a size and font face name hint. However, it can be
* null to use default values. Ultimately, LibGDX ignores the "info" line when reading back fonts.
* null to use default values. LibGDX ignores most of the "info" line when reading back fonts, only padding is used. Padding
* also affects the size, location, and offset of the glyphs that are output.
*
* Likewise, the scaleW and scaleH are only for cleaner output. They are currently ignored by LibGDX's reader. For maximum
* compatibility with other BMFont tools, you should use the width and height of your texture pages (each page should be the
@@ -150,21 +172,22 @@ import com.badlogic.gdx.utils.Array;
* @param info the optional info for the file header; can be null
* @param scaleW the width of your texture pages
* @param scaleH the height of your texture pages */
public static void writeFont (BitmapFontData fontData, String[] pageRefs, FileHandle outFntFile, FontInfo info, int scaleW, int scaleH) {
if (info==null) {
public static void writeFont (BitmapFontData fontData, String[] pageRefs, FileHandle outFntFile, FontInfo info, int scaleW,
int scaleH) {
if (info == null) {
info = new FontInfo();
info.face = outFntFile.nameWithoutExtension();
}
int lineHeight = (int)fontData.lineHeight;
int pages = pageRefs.length;
int packed = 0;
int base = (int)((fontData.capHeight) + (fontData.flipped ? -fontData.ascent : fontData.ascent));
OutputFormat fmt = BitmapFontWriter.getOutputFormat();
boolean xml = fmt == OutputFormat.XML;
boolean xml = fmt == OutputFormat.XML;
StringBuilder buf = new StringBuilder();
if (xml) {
buf.append("<font>\n");
}
@@ -172,152 +195,129 @@ import com.badlogic.gdx.utils.Array;
String xmlCloseSelf = xml ? "/>" : "";
String xmlTab = xml ? "\t" : "";
String xmlClose = xml ? ">" : "";
String xmlQuote = xml ? "\"" : "";
String alphaChnlParams =
xml ? " alphaChnl=\"0\" redChnl=\"0\" greenChnl=\"0\" blueChnl=\"0\""
: " alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0";
//INFO LINE
buf.append(xmlOpen)
.append("info face=\"")
.append(info.face==null ? "" : info.face.replaceAll("\"", "'"))
.append("\" size=").append( quote(info.size) )
.append(" bold=").append( quote(info.bold ? 1 : 0) )
.append(" italic=").append( quote(info.italic ? 1 : 0) )
.append(" charset=\"").append(info.charset==null ? "" : info.charset)
.append("\" unicode=").append( quote(info.unicode ? 1 : 0) )
.append(" stretchH=").append( quote(info.stretchH) )
.append(" smooth=").append( quote(info.smooth ? 1 : 0) )
.append(" aa=").append( quote(info.aa) )
.append(" padding=")
.append(xmlQuote)
.append(info.padding.up).append(",")
.append(info.padding.down).append(",")
.append(info.padding.left).append(",")
.append(info.padding.right)
.append(xmlQuote)
.append(" spacing=")
.append(xmlQuote)
.append(info.spacing.horizontal).append(",")
.append(info.spacing.vertical)
.append(xmlQuote)
.append(xmlCloseSelf)
String alphaChnlParams = xml ? " alphaChnl=\"0\" redChnl=\"0\" greenChnl=\"0\" blueChnl=\"0\""
: " alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0";
// INFO LINE
buf.append(xmlOpen).append("info face=\"").append(info.face == null ? "" : info.face.replaceAll("\"", "'"))
.append("\" size=").append(quote(info.size)).append(" bold=").append(quote(info.bold ? 1 : 0)).append(" italic=")
.append(quote(info.italic ? 1 : 0)).append(" charset=\"").append(info.charset == null ? "" : info.charset)
.append("\" unicode=").append(quote(info.unicode ? 1 : 0)).append(" stretchH=").append(quote(info.stretchH))
.append(" smooth=").append(quote(info.smooth ? 1 : 0)).append(" aa=").append(quote(info.aa)).append(" padding=")
.append(xmlQuote).append(info.padding.up).append(",").append(info.padding.right).append(",").append(info.padding.down)
.append(",").append(info.padding.left).append(xmlQuote).append(" spacing=").append(xmlQuote)
.append(info.spacing.horizontal).append(",").append(info.spacing.vertical).append(xmlQuote).append(xmlCloseSelf)
.append("\n");
//COMMON line
buf.append(xmlOpen)
.append("common lineHeight=").append( quote(lineHeight) )
.append(" base=").append( quote(base) )
.append(" scaleW=").append( quote(scaleW) )
.append(" scaleH=").append( quote(scaleH) )
.append(" pages=").append( quote(pages) )
.append(" packed=").append( quote(packed) )
.append(alphaChnlParams)
.append(xmlCloseSelf)
.append("\n");
if (xml)
buf.append("\t<pages>\n");
//PAGES
for (int i=0; i<pageRefs.length; i++) {
buf.append(xmlTab)
.append(xmlOpen)
.append("page id=")
.append( quote(i) )
.append(" file=\"")
.append(pageRefs[i])
.append("\"")
.append(xmlCloseSelf)
.append("\n");
// COMMON line
buf.append(xmlOpen).append("common lineHeight=").append(quote(lineHeight)).append(" base=").append(quote(base))
.append(" scaleW=").append(quote(scaleW)).append(" scaleH=").append(quote(scaleH)).append(" pages=").append(quote(pages))
.append(" packed=").append(quote(packed)).append(alphaChnlParams).append(xmlCloseSelf).append("\n");
if (xml) buf.append("\t<pages>\n");
// PAGES
for (int i = 0; i < pageRefs.length; i++) {
buf.append(xmlTab).append(xmlOpen).append("page id=").append(quote(i)).append(" file=\"").append(pageRefs[i])
.append("\"").append(xmlCloseSelf).append("\n");
}
if (xml)
buf.append("\t</pages>\n");
//CHARS
Array<Glyph> glyphs = new Array<>(256);
for (int i=0; i<fontData.glyphs.length; i++) {
if (fontData.glyphs[i]==null)
continue;
for (int j=0; j<fontData.glyphs[i].length; j++) {
if (fontData.glyphs[i][j]!=null) {
if (xml) buf.append("\t</pages>\n");
// CHARS
Array<Glyph> glyphs = new Array<Glyph>(256);
for (int i = 0; i < fontData.glyphs.length; i++) {
if (fontData.glyphs[i] == null) continue;
for (int j = 0; j < fontData.glyphs[i].length; j++) {
if (fontData.glyphs[i][j] != null) {
glyphs.add(fontData.glyphs[i][j]);
}
}
}
buf.append(xmlOpen)
.append("chars count=").append(quote(glyphs.size))
.append(xmlClose)
.append("\n");
//CHAR definitions
for (int i=0; i<glyphs.size; i++) {
buf.append(xmlOpen).append("chars count=").append(quote(glyphs.size)).append(xmlClose).append("\n");
int padLeft = 0, padRight = 0, padTop = 0, padX = 0, padY = 0;
if (info != null) {
padTop = info.padding.up;
padLeft = info.padding.left;
padRight = info.padding.right;
padX = padLeft + padRight;
padY = info.padding.up + info.padding.down;
}
// CHAR definitions
for (int i = 0; i < glyphs.size; i++) {
Glyph g = glyphs.get(i);
buf.append(xmlTab)
.append(xmlOpen)
.append("char id=")
.append(quote( String.format("%-5s", g.id), true ))
.append("x=").append(quote( String.format("%-5s", g.srcX), true ) )
.append("y=").append(quote( String.format("%-5s", g.srcY), true ) )
.append("width=").append(quote( String.format("%-5s", g.width), true ) )
.append("height=").append(quote( String.format("%-5s", g.height), true ) )
.append("xoffset=").append(quote( String.format("%-5s", g.xoffset), true ) )
.append("yoffset=").append(quote( String.format("%-5s", fontData.flipped ? g.yoffset : -(g.height + g.yoffset) ), true ) )
.append("xadvance=").append(quote( String.format("%-5s", g.xadvance), true ) )
.append("page=").append(quote( String.format("%-5s", g.page), true ) )
.append("chnl=").append(quote(0, true))
.append(xmlCloseSelf)
boolean empty = g.width == 0 || g.height == 0;
buf.append(xmlTab).append(xmlOpen).append("char id=").append(quote(String.format("%-6s", g.id), true)).append("x=")
.append(quote(String.format("%-5s", empty ? 0 : g.srcX), true)).append("y=")
.append(quote(String.format("%-5s", empty ? 0 : g.srcY), true)).append("width=")
.append(quote(String.format("%-5s", empty ? 0 : g.width), true)).append("height=")
.append(quote(String.format("%-5s", empty ? 0 : g.height), true)).append("xoffset=")
.append(quote(String.format("%-5s", g.xoffset - padLeft), true)).append("yoffset=")
.append(quote(String.format("%-5s", fontData.flipped ? g.yoffset + padTop : -(g.height + (g.yoffset + padTop))), true))
.append("xadvance=").append(quote(String.format("%-5s", g.xadvance), true)).append("page=")
.append(quote(String.format("%-5s", g.page), true)).append("chnl=").append(quote(0, true)).append(xmlCloseSelf)
.append("\n");
}
if (xml)
buf.append("\t</chars>\n");
//KERNINGS
if (xml) buf.append("\t</chars>\n");
// KERNINGS
int kernCount = 0;
StringBuilder kernBuf = new StringBuilder();
StringBuilder kernBuf = new StringBuilder();
for (int i = 0; i < glyphs.size; i++) {
for (int j = 0; j < glyphs.size; j++) {
Glyph first = glyphs.get(i);
Glyph second = glyphs.get(j);
int kern = first.getKerning((char)second.id);
if (kern!=0) {
if (kern != 0) {
kernCount++;
kernBuf.append(xmlTab)
.append(xmlOpen)
.append("kerning first=").append(quote(first.id))
.append(" second=").append(quote(second.id))
.append(" amount=").append(quote(kern, true))
.append(xmlCloseSelf)
.append("\n");
kernBuf.append(xmlTab).append(xmlOpen).append("kerning first=").append(quote(first.id)).append(" second=")
.append(quote(second.id)).append(" amount=").append(quote(kern, true)).append(xmlCloseSelf).append("\n");
}
}
}
//KERN info
buf.append(xmlOpen)
.append("kernings count=").append(quote(kernCount))
.append(xmlClose)
.append("\n");
// KERN info
buf.append(xmlOpen).append("kernings count=").append(quote(kernCount)).append(xmlClose).append("\n");
buf.append(kernBuf);
if (xml) {
buf.append("\t</kernings>\n");
}
// Override metrics
if (info.hasOverrideMetrics) {
if (xml) buf.append("\t<metrics>\n");
buf.append(xmlTab).append(xmlOpen)
.append("metrics ascent=").append(quote(info.ascent, true))
.append(" descent=").append(quote(info.descent, true))
.append(" down=").append(quote(info.down, true))
.append(" capHeight=").append(quote(info.capHeight, true))
.append(" lineHeight=").append(quote(info.lineHeight, true))
.append(" spaceXAdvance=").append(quote(info.spaceXAdvance, true))
.append(" xHeight=").append(quote(info.xHeight, true))
.append(xmlCloseSelf).append("\n");
if (xml) buf.append("\t</metrics>\n");
}
if (xml) {
buf.append("</font>");
}
String charset = info.charset;
if (charset!=null&&charset.length()==0)
charset = null;
if (charset != null && charset.length() == 0) charset = null;
outFntFile.writeString(buf.toString(), false, charset);
}
/** A utility method which writes the given font data to a file.
*
* The specified pixmaps are written to the parent directory of <tt>outFntFile</tt>, using that file's name without an
@@ -337,8 +337,8 @@ import com.badlogic.gdx.utils.Array;
* @param info the optional font info for the header file, can be null */
public static void writeFont (BitmapFontData fontData, Pixmap[] pages, FileHandle outFntFile, FontInfo info) {
String[] pageRefs = writePixmaps(pages, outFntFile.parent(), outFntFile.nameWithoutExtension());
//write the font data
// write the font data
writeFont(fontData, pageRefs, outFntFile, info, pages[0].getWidth(), pages[0].getHeight());
}
@@ -357,18 +357,17 @@ import com.badlogic.gdx.utils.Array;
* @param fileName the file names for the output images
* @return the array of string references to be used with <tt>writeFont</tt> */
public static String[] writePixmaps (Pixmap[] pages, FileHandle outputDir, String fileName) {
if (pages==null || pages.length==0)
throw new IllegalArgumentException("no pixmaps supplied to BitmapFontWriter.write");
if (pages == null || pages.length == 0) throw new IllegalArgumentException("no pixmaps supplied to BitmapFontWriter.write");
String[] pageRefs = new String[pages.length];
for (int i=0; i<pages.length; i++) {
String ref = pages.length==1 ? (fileName+".png") : (fileName+"_"+i+".png");
//the ref for this image
for (int i = 0; i < pages.length; i++) {
String ref = pages.length == 1 ? (fileName + ".png") : (fileName + "_" + i + ".png");
// the ref for this image
pageRefs[i] = ref;
//write the PNG in that directory
// write the PNG in that directory
PixmapIO.writePNG(outputDir.child(ref), pages[i]);
}
return pageRefs;
@@ -383,9 +382,9 @@ import com.badlogic.gdx.utils.Array;
* @return the file refs */
public static String[] writePixmaps (Array<Page> pages, FileHandle outputDir, String fileName) {
Pixmap[] pix = new Pixmap[pages.size];
for (int i=0; i<pages.size; i++) {
for (int i = 0; i < pages.size; i++) {
pix[i] = pages.get(i).getPixmap();
}
return writePixmaps(pix, outputDir, fileName);
}
}
}

View File

@@ -1,11 +1,10 @@
package forge.assets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.badlogic.gdx.utils.Array;
import forge.Forge;
import org.apache.commons.lang3.text.WordUtils;
import com.badlogic.gdx.Gdx;
@@ -30,8 +29,10 @@ import forge.toolbox.FProgressBar;
public class FSkin {
private static final Map<FSkinProp, FSkinImage> images = new HashMap<>();
private static final Map<Integer, TextureRegion> avatars = new HashMap<>();
private static final Map<Integer, TextureRegion> sleeves = new HashMap<>();
private static final Map<Integer, TextureRegion> borders = new HashMap<>();
private static List<String> allSkins;
private static Array<String> allSkins;
private static FileHandle preferredDir;
private static String preferredName;
private static boolean loaded = false;
@@ -98,12 +99,12 @@ public class FSkin {
else {
if (splashScreen != null) {
if (allSkins == null) { //initialize
allSkins = new ArrayList<>();
final List<String> skinDirectoryNames = getSkinDirectoryNames();
allSkins = new Array<>();
final Array<String> skinDirectoryNames = getSkinDirectoryNames();
for (final String skinDirectoryName : skinDirectoryNames) {
allSkins.add(WordUtils.capitalize(skinDirectoryName.replace('_', ' ')));
}
Collections.sort(allSkins);
allSkins.sort();
}
}
@@ -172,6 +173,9 @@ public class FSkin {
}
avatars.clear();
sleeves.clear();
boolean textureFilter = Forge.isTextureFilteringEnabled();
final Map<String, Texture> textures = new HashMap<>();
@@ -183,6 +187,9 @@ public class FSkin {
final FileHandle f5 = getSkinFile(ForgeConstants.SPRITE_AVATARS_FILE);
final FileHandle f6 = getDefaultSkinFile(SourceFile.OLD_FOILS.getFilename());
final FileHandle f7 = getDefaultSkinFile(ForgeConstants.SPRITE_MANAICONS_FILE);
final FileHandle f8 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES_FILE);
final FileHandle f9 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES2_FILE);
final FileHandle f10 = getDefaultSkinFile(ForgeConstants.SPRITE_BORDER_FILE);
try {
textures.put(f1.path(), new Texture(f1));
@@ -218,16 +225,25 @@ public class FSkin {
//assemble avatar textures
int counter = 0;
int scount = 0;
Color pxTest;
Pixmap pxDefaultAvatars, pxPreferredAvatars;
Texture txDefaultAvatars, txPreferredAvatars;
Pixmap pxDefaultAvatars, pxPreferredAvatars, pxDefaultSleeves;
Texture txDefaultAvatars, txPreferredAvatars, txDefaultSleeves;
pxDefaultAvatars = new Pixmap(f4);
txDefaultAvatars = new Texture(f4);
pxDefaultSleeves = new Pixmap(f8);
txDefaultAvatars = new Texture(f4, textureFilter);
if (textureFilter)
txDefaultAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
txDefaultSleeves = new Texture(f8, textureFilter);
if (textureFilter)
txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
if (f5.exists()) {
pxPreferredAvatars = new Pixmap(f5);
txPreferredAvatars = new Texture(f5);
txPreferredAvatars = new Texture(f5, textureFilter);
if (textureFilter)
txPreferredAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
final int pw = pxPreferredAvatars.getWidth();
final int ph = pxPreferredAvatars.getHeight();
@@ -255,8 +271,42 @@ public class FSkin {
}
}
final int sw = pxDefaultSleeves.getWidth();
final int sh = pxDefaultSleeves.getHeight();
for (int j = 0; j < sh; j += 500) {
for (int i = 0; i < sw; i += 360) {
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500));
}
}
//re init second set of sleeves
pxDefaultSleeves = new Pixmap(f9);
txDefaultSleeves = new Texture(f9, textureFilter);
if (textureFilter)
txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
final int sw2 = pxDefaultSleeves.getWidth();
final int sh2 = pxDefaultSleeves.getHeight();
for (int j = 0; j < sh2; j += 500) {
for (int i = 0; i < sw2; i += 360) {
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
if (pxTest.a == 0) { continue; }
FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500));
}
}
Texture bordersBW = new Texture(f10);
FSkin.borders.put(0, new TextureRegion(bordersBW, 2, 2, 672, 936));
FSkin.borders.put(1, new TextureRegion(bordersBW, 676, 2, 672, 936));
preferredIcons.dispose();
pxDefaultAvatars.dispose();
pxDefaultSleeves.dispose();;
}
catch (final Exception e) {
System.err.println("FSkin$loadFull: Missing a sprite (default icons, "
@@ -314,8 +364,8 @@ public class FSkin {
*
* @return the skins
*/
public static List<String> getSkinDirectoryNames() {
final List<String> mySkins = new ArrayList<>();
public static Array<String> getSkinDirectoryNames() {
final Array<String> mySkins = new Array<>();
final FileHandle dir = Gdx.files.absolute(ForgeConstants.SKINS_DIR);
for (FileHandle skinFile : dir.list()) {
@@ -340,5 +390,13 @@ public class FSkin {
return avatars;
}
public static Map<Integer, TextureRegion> getSleeves() {
return sleeves;
}
public static Map<Integer, TextureRegion> getBorders() {
return borders;
}
public static boolean isLoaded() { return loaded; }
}

View File

@@ -463,7 +463,7 @@ public class FSkinFont {
+ "驽驾驿骁骂骄骆骇验骏骐骑骗骚骤骨骰骷骸骼髅髓高鬃鬓鬣鬼魁魂魄"
+ "魅魇魈魏魔鰴鱼鲁鲜鲤鲨鲮鲸鲽鳃鳄鳍鳐鳗鳝鳞鸟鸠鸡鸢鸣鸦鸽鹅鹉"
+ "鹊鹏鹗鹞鹤鹦鹫鹭鹰鹿麋麒麟麦麻黄黎黏黑默黛黜點黠黯鼎鼓鼠鼬鼹"
+ "鼻齐齑齿龇龙龟!(),/:;?~";
+ "鼻齐齑齿龇龙龟";
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
final FreeTypeFontParameter parameter = new FreeTypeFontParameter();

View File

@@ -214,6 +214,16 @@ public class ImageCache {
return Color.valueOf("#fffffd");
return Color.valueOf("#171717");
}
public static int getFSkinBorders(CardView c) {
if (c == null)
return 0;
CardView.CardStateView state = c.getCurrentState();
CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode());
if (ed != null && ed.isWhiteBorder() && state.getFoilIndex() == 0)
return 1;
return 0;
}
public static boolean isExtendedArt(CardView c) {
if (c == null)
return false;

View File

@@ -21,9 +21,10 @@ final class ImageLoader extends CacheLoader<String, Texture> {
boolean extendedArt = false;
boolean textureFilter = Forge.isTextureFilteringEnabled();
if (key.length() > 4){
if ((key.substring(0,4).contains("MPS_"))) //TODO add sets to get all extended art???
if ((key.substring(0,4).contains("MPS_"))) //MPS_ sets
extendedArt = true;
else if ((key.substring(0,3).contains("UST"))) //Unstable Set
extendedArt = true;
//use generated extended art... it will preload the cache at startup so... yeah! :)
}
File file = ImageKeys.getImageFile(key);
if (file != null) {

View File

@@ -6,7 +6,10 @@ import com.badlogic.gdx.utils.Align;
import com.google.common.collect.ImmutableList;
import forge.Forge;
import forge.Graphics;
import forge.ImageKeys;
import forge.assets.FBufferedImage;
import forge.assets.FImage;
import forge.assets.FSkin;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
@@ -25,6 +28,7 @@ import forge.properties.ForgeConstants;
import forge.properties.ForgePreferences;
import forge.screens.FScreen;
import forge.screens.match.MatchController;
import forge.util.CardTranslation;
import forge.util.Utils;
import org.apache.commons.lang3.StringUtils;
@@ -326,7 +330,9 @@ public class CardImageRenderer {
}
public static void drawZoom(Graphics g, CardView card, GameView gameView, boolean altState, float x, float y, float w, float h, float dispW, float dispH, boolean isCurrentCard) {
boolean canshow = MatchController.instance.mayView(card);
final Texture image = ImageCache.getImage(card.getState(altState).getImageKey(MatchController.instance.getLocalPlayers()), true);
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
if (image == null) { //draw details if can't draw zoom
drawDetails(g, card, gameView, altState, x, y, w, h);
return;
@@ -337,8 +343,6 @@ public class CardImageRenderer {
return;
}
boolean canLook = MatchController.instance.mayView(card);
if (image == ImageCache.defaultImage) { //support drawing card image manually if card image not found
drawCardImage(g, card, altState, x, y, w, h, CardStackPosition.Top);
}
@@ -358,47 +362,43 @@ public class CardImageRenderer {
if (ImageCache.isExtendedArt(card))
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
else {
if (rotatePlane)
g.drawfillBorder(3, ImageCache.borderColor(card), new_xRotate, new_yRotate, new_h, new_w, radius);
else
g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius);
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x+radius/2.3f, new_y+radius/2, new_w*0.96f, new_h*0.96f, (new_x+radius/2.3f) + (new_w*0.96f) / 2, (new_y+radius/2) + (new_h*0.96f) / 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);
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x+radius/2, new_y+radius/2, new_w*0.96f, new_h*0.96f, (new_x+radius/2) + (new_w*0.96f) / 2, (new_y+radius/2) + (new_h*0.96f) / 2, -90);
}
}
else
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
} else if (rotateSplit && isCurrentCard && card.isSplitCard() && canLook) {
} else if (rotateSplit && isCurrentCard && card.isSplitCard() && canshow) {
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
if (Forge.enableUIMask) {
if (ImageCache.isExtendedArt(card))
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 {
if (rotateSplit)
g.drawfillBorder(3, ImageCache.borderColor(card), new_xRotate, new_yRotate, new_h, new_w, radius);
else
g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius);
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x + radius / 2.3f, new_y + radius / 2, new_w * 0.96f, new_h * 0.96f, (new_x + radius / 2.3f) + (new_w * 0.96f) / 2, (new_y + radius / 2) + (new_h * 0.96f) / 2, isAftermath ? 90 : -90);
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.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(ImageCache.croppedBorderImage(image), new_x + radius / 2, new_y + radius / 2, new_w * 0.96f, new_h * 0.96f, (new_x + radius / 2) + (new_w * 0.96f) / 2, (new_y + radius / 2) + (new_h * 0.96f) / 2, isAftermath ? 90 : -90);
}
}
else
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 {
if (Forge.enableUIMask) {
if (Forge.enableUIMask && canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey())) {
if (ImageCache.isExtendedArt(card))
g.drawImage(image, x, y, w, h);
else {
g.drawImage(ImageCache.getBorderImage(card, canLook), x, y, w, h);
g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h);
g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
}
}
else
g.drawImage(image, x, y, w, h);
else {
if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey()))
g.drawImage(image, x, y, w, h);
else // sleeve
g.drawImage(sleeves, x, y, w, h);
}
}
}
CardRenderer.drawFoilEffect(g, card, x, y, w, h, isCurrentCard && canLook && image != ImageCache.defaultImage);
CardRenderer.drawFoilEffect(g, card, x, y, w, h, isCurrentCard && canshow && image != ImageCache.defaultImage);
}
public static void drawDetails(Graphics g, CardView card, GameView gameView, boolean altState, float x, float y, float w, float h) {

View File

@@ -19,9 +19,12 @@ import forge.CachedCardImage;
import forge.Forge;
import forge.FThreads;
import forge.Graphics;
import forge.ImageKeys;
import forge.StaticData;
import forge.assets.FImage;
import forge.assets.FImageComplex;
import forge.assets.FRotatedImage;
import forge.assets.FSkin;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
@@ -46,6 +49,7 @@ import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.screens.match.MatchController;
import forge.toolbox.FList;
import forge.util.CardTranslation;
import forge.util.Utils;
import org.apache.commons.lang3.StringUtils;
import forge.util.TextBounds;
@@ -430,7 +434,9 @@ public class CardRenderer {
}
}
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean rotate) {
boolean canshow = MatchController.instance.mayView(card) && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getCurrentState().getImageKey());
Texture image = new RendererCachedCardImage(card, false).getImage();
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
float radius = (h - w)/8;
if (image != null) {
@@ -444,7 +450,7 @@ public class CardRenderer {
if (ImageCache.isExtendedArt(card))
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
else {
g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius);
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
g.drawRotatedImage(ImageCache.croppedBorderImage(image), x+radius/2.3f, y+radius/2, w*0.96f, h*0.96f, (x+radius/2.3f) + (w*0.96f) / 2, (y+radius/2) + (h*0.96f) / 2, -90);
}
}
@@ -452,17 +458,21 @@ public class CardRenderer {
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
}
else {
if (Forge.enableUIMask) {
if (Forge.enableUIMask && canshow) {
if (ImageCache.isExtendedArt(card))
g.drawImage(image, x, y, w, h);
else {
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
g.drawBorderImage(ImageCache.getBorderImage(card, MatchController.instance.mayView(card)), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
g.drawBorderImage(ImageCache.getBorderImage(card, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
}
}
else
g.drawImage(image, x, y, w, h);
else {
if (canshow)
g.drawImage(image, x, y, w, h);
else // draw card back sleeves
g.drawImage(sleeves, x, y, w, h);
}
}
}
drawFoilEffect(g, card, x, y, w, h, false);
@@ -1113,11 +1123,15 @@ public class CardRenderer {
}
public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) {
float new_x = x; float new_y = y; float new_w = w; float new_h = h; float radius = (h - w)/8;
if (Forge.enableUIMask) {
new_x += radius/2.4f; new_y += radius/2; new_w = w * 0.96f; new_h = h * 0.96f;
}
if (isPreferenceEnabled(FPref.UI_OVERLAY_FOIL_EFFECT) && MatchController.instance.mayView(card)) {
boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer;
int foil = card.getCurrentState().getFoilIndex();
if (foil > 0) {
CardFaceSymbols.drawOther(g, String.format("foil%02d", foil), x, y, w, h, rotateSplit);
CardFaceSymbols.drawOther(g, String.format("foil%02d", foil), new_x, new_y, new_w, new_h, rotateSplit);
}
}
}

View File

@@ -20,6 +20,7 @@ import forge.toolbox.FOptionPane;
import forge.toolbox.FTextField;
import forge.toolbox.FEvent.FEventHandler;
import forge.util.Callback;
import forge.util.Localizer;
public class GameEntityPicker extends TabPageScreen<GameEntityPicker> {
private final FOptionPane optionPane;
@@ -73,7 +74,7 @@ public class GameEntityPicker extends TabPageScreen<GameEntityPicker> {
super(caption0 + " (" + items.size() + ")", icon0);
txtSearch = add(new FTextField());
txtSearch.setFont(FSkinFont.get(12));
txtSearch.setGhostText("Search");
txtSearch.setGhostText(Localizer.getInstance().getMessage("lblSearch"));
txtSearch.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {

View File

@@ -149,6 +149,7 @@ public class FDeckChooser extends FScreen {
@Override
public void handleEvent(FEvent e) {
if (selectedDeckType != DeckType.STANDARD_COLOR_DECK && selectedDeckType != DeckType.STANDARD_CARDGEN_DECK
&& selectedDeckType != DeckType.PIONEER_CARDGEN_DECK
&& selectedDeckType != DeckType.MODERN_CARDGEN_DECK && selectedDeckType != DeckType.LEGACY_CARDGEN_DECK
&& selectedDeckType != DeckType.VINTAGE_CARDGEN_DECK && selectedDeckType != DeckType.MODERN_COLOR_DECK &&
selectedDeckType != DeckType.COLOR_DECK && selectedDeckType != DeckType.THEME_DECK
@@ -172,6 +173,9 @@ public class FDeckChooser extends FScreen {
else if (selectedDeckType == DeckType.STANDARD_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.PIONEER_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
else if (selectedDeckType == DeckType.MODERN_CARDGEN_DECK){
DeckgenUtil.randomSelect(lstDecks);
}
@@ -296,6 +300,7 @@ public class FDeckChooser extends FScreen {
case RANDOM_CARDGEN_COMMANDER_DECK:
case RANDOM_COMMANDER_DECK:
case MODERN_CARDGEN_DECK:
case PIONEER_CARDGEN_DECK:
case LEGACY_CARDGEN_DECK:
case VINTAGE_CARDGEN_DECK:
case MODERN_COLOR_DECK:
@@ -486,6 +491,7 @@ public class FDeckChooser extends FScreen {
cmbDeckTypes.addItem(DeckType.STANDARD_COLOR_DECK);
if(FModel.isdeckGenMatrixLoaded()) {
cmbDeckTypes.addItem(DeckType.STANDARD_CARDGEN_DECK);
cmbDeckTypes.addItem(DeckType.PIONEER_CARDGEN_DECK);
cmbDeckTypes.addItem(DeckType.MODERN_CARDGEN_DECK);
cmbDeckTypes.addItem(DeckType.LEGACY_CARDGEN_DECK);
cmbDeckTypes.addItem(DeckType.VINTAGE_CARDGEN_DECK);
@@ -698,6 +704,14 @@ public class FDeckChooser extends FScreen {
}
config = ItemManagerConfig.STRING_ONLY;
break;
case PIONEER_CARDGEN_DECK:
maxSelections = 1;
pool= new ArrayList<>();
if(FModel.isdeckGenMatrixLoaded()) {
pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().getPioneer(), isAi);
}
config = ItemManagerConfig.STRING_ONLY;
break;
case MODERN_CARDGEN_DECK:
maxSelections = 1;
pool= new ArrayList<>();
@@ -1077,6 +1091,7 @@ public class FDeckChooser extends FScreen {
DeckType.STANDARD_COLOR_DECK,
DeckType.STANDARD_CARDGEN_DECK,
DeckType.MODERN_COLOR_DECK,
DeckType.PIONEER_CARDGEN_DECK,
DeckType.MODERN_CARDGEN_DECK,
DeckType.LEGACY_CARDGEN_DECK,
DeckType.VINTAGE_CARDGEN_DECK,
@@ -1085,6 +1100,7 @@ public class FDeckChooser extends FScreen {
);
if (!FModel.isdeckGenMatrixLoaded()) {
deckTypes.remove(DeckType.STANDARD_CARDGEN_DECK);
deckTypes.remove(DeckType.PIONEER_CARDGEN_DECK);
deckTypes.remove(DeckType.MODERN_CARDGEN_DECK);
deckTypes.remove(DeckType.LEGACY_CARDGEN_DECK);
deckTypes.remove(DeckType.VINTAGE_CARDGEN_DECK);

View File

@@ -13,6 +13,7 @@ import forge.toolbox.FDisplayObject;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FTextField;
import forge.util.Localizer;
public class TextSearchFilter<T extends InventoryItem> extends ItemFilter<T> {
@@ -78,10 +79,10 @@ public class TextSearchFilter<T extends InventoryItem> extends ItemFilter<T> {
}
public String getCaption() {
return txtSearch.getGhostText().substring("Search ".length());
return txtSearch.getGhostText().substring((Localizer.getInstance().getMessage("lblSearch") + " ").length());
}
public void setCaption(String caption0) {
txtSearch.setGhostText("Search " + caption0);
txtSearch.setGhostText(Localizer.getInstance().getMessage("lblSearch") + " " + caption0);
}
protected class SearchField extends FTextField {
@@ -89,7 +90,7 @@ public class TextSearchFilter<T extends InventoryItem> extends ItemFilter<T> {
private SearchField() {
setFont(FONT);
setGhostText("Search");
setGhostText(Localizer.getInstance().getMessage("lblSearch"));
setHeight(getDefaultHeight(DEFAULT_FONT)); //set height based on default filter font
}

View File

@@ -37,7 +37,7 @@ public class AvatarSelector extends FScreen {
}
private static final float PADDING = Utils.scale(5);
private static final int COLUMNS = 4;
private static final int COLUMNS = 5;
private final int currentIndex;
private final List<Integer> usedAvatars;

View File

@@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import forge.GuiBase;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
@@ -301,13 +302,20 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
}
/** Saves avatar prefs for players one and two. */
void updateAvatarPrefs() {
void updateAvatarPrefs() {
int pOneIndex = playerPanels.get(0).getAvatarIndex();
int pTwoIndex = playerPanels.get(1).getAvatarIndex();
prefs.setPref(FPref.UI_AVATARS, pOneIndex + "," + pTwoIndex);
prefs.save();
}
void updateSleevePrefs() {
int pOneIndex = playerPanels.get(0).getSleeveIndex();
int pTwoIndex = playerPanels.get(1).getSleeveIndex();
prefs.setPref(FPref.UI_SLEEVES, pOneIndex + "," + pTwoIndex);
prefs.save();
}
/** Updates the avatars from preferences on update. */
private void updatePlayersFromPrefs() {
@@ -320,6 +328,13 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
playerPanels.get(i).setAvatarIndex(avatarIndex);
}
// Sleeves
String[] sleevePrefs = prefs.getPref(FPref.UI_SLEEVES).split(",");
for (int i = 0; i < sleevePrefs.length; i++) {
int sleeveIndex = Integer.parseInt(sleevePrefs[i]);
playerPanels.get(i).setSleeveIndex(sleeveIndex);
}
// Name
String prefName = prefs.getPref(FPref.PLAYER_NAME);
playerPanels.get(0).setPlayerName(StringUtils.isBlank(prefName) ? Localizer.getInstance().getMessage("lblHuman") : prefName);
@@ -334,6 +349,15 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
return usedAvatars;
}
List<Integer> getUsedSleeves() {
List<Integer> usedSleeves = Arrays.asList(-1,-1,-1,-1,-1,-1,-1,-1);
int i = 0;
for (PlayerPanel pp : playerPanels) {
usedSleeves.set(i++, pp.getSleeveIndex());
}
return usedSleeves;
}
List<String> getPlayerNames() {
List<String> names = new ArrayList<>();
for (PlayerPanel pp : playerPanels) {
@@ -350,6 +374,10 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
return playerPanels.get(i).getAvatarIndex();
}
public int getPlayerSleeve(int i) {
return playerPanels.get(i).getSleeveIndex();
}
/////////////////////////////////////////////
//========== Various listeners in build order
@@ -448,6 +476,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
DeckType selectedDeckType = deckChooser.getSelectedDeckType();
switch (selectedDeckType){
case STANDARD_CARDGEN_DECK:
case PIONEER_CARDGEN_DECK:
case MODERN_CARDGEN_DECK:
case LEGACY_CARDGEN_DECK:
case VINTAGE_CARDGEN_DECK:
@@ -498,6 +527,9 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
updateVariantSelection();
final boolean allowNetworking = lobby.isAllowNetworking();
GuiBase.setNetworkplay(allowNetworking);
for (int i = 0; i < cbPlayerCount.getSelectedItem(); i++) {
final boolean hasPanel = i < playerPanels.size();
if (i < playerCount) {
@@ -527,8 +559,18 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
final LobbySlotType type = slot.getType();
panel.setType(type);
panel.setPlayerName(slot.getName());
panel.setAvatarIndex(slot.getAvatarIndex());
if (type != LobbySlotType.AI) {
panel.setPlayerName(slot.getName());
panel.setAvatarIndex(slot.getAvatarIndex());
panel.setSleeveIndex(slot.getSleeveIndex());
} else {
//AI: this one overrides the setplayername if blank
if (panel.getPlayerName().isEmpty())
panel.setPlayerName(slot.getName());
//AI: override settings if somehow player changes it for AI
slot.setAvatarIndex(panel.getAvatarIndex());
slot.setSleeveIndex(panel.getSleeveIndex());
}
panel.setTeam(slot.getTeam());
panel.setIsReady(slot.isReady());
panel.setIsDevMode(slot.isDevMode());
@@ -631,6 +673,18 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
}
}
void updateAvatar(final int index, final int avatarIndex) {
if (playerChangeListener != null) {
playerChangeListener.update(index, UpdateLobbyPlayerEvent.avatarUpdate(avatarIndex));
}
}
void updateSleeve(final int index, final int sleeveIndex) {
if (playerChangeListener != null) {
playerChangeListener.update(index, UpdateLobbyPlayerEvent.sleeveUpdate(sleeveIndex));
}
}
void setReady(final int index, final boolean ready) {
if (ready) {
updateDeck(index);
@@ -667,7 +721,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
private UpdateLobbyPlayerEvent getSlot(final int index) {
final PlayerPanel panel = playerPanels.get(index);
return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions());
return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getSleeveIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions());
}
public List<PlayerPanel> getPlayerPanels() {

View File

@@ -59,7 +59,8 @@ public class PlayerPanel extends FContainer {
private final FLabel nameRandomiser;
private final FLabel avatarLabel = new FLabel.Builder().opaque(true).iconScaleFactor(0.99f).alphaComposite(1).iconInBackground(true).build();
private int avatarIndex;
private final FLabel sleeveLabel = new FLabel.Builder().opaque(true).iconScaleFactor(0.99f).alphaComposite(1).iconInBackground(true).build();
private int avatarIndex, sleeveIndex;
final Localizer localizer = Localizer.getInstance();
private final FTextField txtPlayerName = new FTextField(localizer.getMessage("lblPlayerName"));
@@ -98,6 +99,7 @@ public class PlayerPanel extends FContainer {
setType(slot.getType());
setPlayerName(slot.getName());
setAvatarIndex(slot.getAvatarIndex());
setSleeveIndex(slot.getSleeveIndex());
devModeSwitch = new FToggleSwitch(localizer.getMessage("lblNormal"), localizer.getMessage("lblDevMode"));
devModeSwitch.setVisible(isNetworkHost());
@@ -189,6 +191,9 @@ public class PlayerPanel extends FContainer {
createAvatar();
add(avatarLabel);
createSleeve();
add(sleeveLabel);
createNameEditor();
add(newLabel(localizer.getMessage("lblName") + ":"));
add(txtPlayerName);
@@ -299,12 +304,16 @@ public class PlayerPanel extends FContainer {
float y = PADDING;
float fieldHeight = txtPlayerName.getHeight();
float avatarSize = 2 * fieldHeight + PADDING;
float sleeveSize = 2 * fieldHeight + PADDING;
float sleeveSizeW = (sleeveSize/4)*3;
float dy = fieldHeight + PADDING;
avatarLabel.setBounds(x, y, avatarSize, avatarSize);
x += avatarSize + PADDING;
sleeveLabel.setBounds(x, y, sleeveSizeW, sleeveSize);
x += sleeveSizeW + PADDING;
float w = width - x - fieldHeight - 2 * PADDING;
txtPlayerName.setBounds(x, y, w, fieldHeight);
txtPlayerName.setBounds(x, y, w, fieldHeight); //add space for card back
x += w + PADDING;
nameRandomiser.setBounds(x, y, fieldHeight, fieldHeight);
@@ -312,8 +321,8 @@ public class PlayerPanel extends FContainer {
humanAiSwitch.setSize(humanAiSwitch.getAutoSizeWidth(fieldHeight), fieldHeight);
x = width - humanAiSwitch.getWidth() - PADDING;
humanAiSwitch.setPosition(x, y);
w = x - avatarSize - 3 * PADDING;
x = avatarSize + 2 * PADDING;
w = x - (avatarSize+sleeveSizeW+PADDING) - 3 * PADDING;
x = (avatarSize+sleeveSizeW+PADDING) + 2 * PADDING;
if (cbArchenemyTeam.isVisible()) {
cbArchenemyTeam.setBounds(x, y, w, fieldHeight);
}
@@ -411,6 +420,7 @@ public class PlayerPanel extends FContainer {
//update may edit in-case it changed as a result of the AI change
setMayEdit(screen.getLobby().mayEdit(index));
setAvatarIndex(slot.getAvatarIndex());
setSleeveIndex(slot.getSleeveIndex());
setPlayerName(slot.getName());
}
}
@@ -470,6 +480,7 @@ public class PlayerPanel extends FContainer {
setAvatarIndex(result);
if (index < 2) {
screen.updateAvatar(index, result);
screen.updateAvatarPrefs();
}
if (allowNetworking) {
@@ -480,6 +491,26 @@ public class PlayerPanel extends FContainer {
}
};
private FEventHandler sleeveCommand = new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
SleevesSelector.show(getPlayerName(), sleeveIndex, screen.getUsedSleeves(), new Callback<Integer>() {
@Override
public void run(Integer result) {
setSleeveIndex(result);
if (index < 2) {
screen.updateSleeve(index, result);
screen.updateSleevePrefs();
}
if (allowNetworking) {
screen.firePlayerChangeListener(index);
}
}
});
}
};
public void setDeckSelectorButtonText(String text) {
btnDeck.setText(text);
}
@@ -664,6 +695,17 @@ public class PlayerPanel extends FContainer {
avatarLabel.setCommand(avatarCommand);
}
private void createSleeve() {
String[] currentPrefs = prefs.getPref(FPref.UI_SLEEVES).split(",");
if (index < currentPrefs.length) {
setSleeveIndex(Integer.parseInt(currentPrefs[index]));
}
else {
setSleeveIndex(SleevesSelector.getRandomSleeves(screen.getUsedSleeves()));
}
sleeveLabel.setCommand(sleeveCommand);
}
public void setAvatarIndex(int newAvatarIndex) {
avatarIndex = newAvatarIndex;
if (avatarIndex != -1) {
@@ -674,10 +716,24 @@ public class PlayerPanel extends FContainer {
}
}
public void setSleeveIndex(int newSleeveIndex) {
sleeveIndex = newSleeveIndex;
if (sleeveIndex != -1) {
sleeveLabel.setIcon(new FTextureRegionImage(FSkin.getSleeves().get(newSleeveIndex)));
}
else {
sleeveLabel.setIcon(null);
}
}
public int getAvatarIndex() {
return avatarIndex;
}
public int getSleeveIndex() {
return sleeveIndex;
}
public void setPlayerName(String string) {
txtPlayerName.setText(string);
}
@@ -759,6 +815,7 @@ public class PlayerPanel extends FContainer {
if (mayEdit == mayEdit0) { return; }
mayEdit = mayEdit0;
avatarLabel.setEnabled(mayEdit);
sleeveLabel.setEnabled(mayEdit);
txtPlayerName.setEnabled(mayEdit);
nameRandomiser.setEnabled(mayEdit);
humanAiSwitch.setEnabled(mayEdit);

View File

@@ -0,0 +1,119 @@
package forge.screens.constructed;
import forge.Forge;
import forge.assets.FImage;
import forge.assets.FSkin;
import forge.assets.FSkinImage;
import forge.assets.FTextureRegionImage;
import forge.screens.FScreen;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.toolbox.FScrollPane;
import forge.util.Callback;
import forge.util.MyRandom;
import forge.util.Utils;
import java.util.List;
import java.util.Map;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Align;
public class SleevesSelector extends FScreen {
public static int getRandomSleeves(List<Integer> usedSleeves) {
int random = 0;
do {
random = MyRandom.getRandom().nextInt(FSkin.getSleeves().size());
} while (usedSleeves.contains(random));
return random;
}
public static void show(final String playerName, final int currentIndex0, final List<Integer> usedSleeves0, final Callback<Integer> callback0) {
SleevesSelector selector = new SleevesSelector(playerName, currentIndex0, usedSleeves0, callback0);
Forge.openScreen(selector);
}
private static final float PADDING = Utils.scale(5);
private static final int COLUMNS = 5;
private final int currentIndex;
private final List<Integer> usedSleeves;
private final Callback<Integer> callback;
private final FScrollPane scroller = new FScrollPane() {
@Override
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
int rowCount = 0;
float x = PADDING;
float y = PADDING;
float labelSize = (visibleWidth - (COLUMNS + 1) * PADDING) / COLUMNS;
for (FDisplayObject lbl : scroller.getChildren()) {
if (rowCount == COLUMNS) { //wrap to next line
x = PADDING;
y += labelSize + PADDING;
rowCount = 0;
}
lbl.setBounds(x, y, labelSize, labelSize);
x += labelSize + PADDING;
rowCount++;
}
return new ScrollBounds(visibleWidth, y + labelSize + PADDING);
}
};
private SleevesSelector(final String playerName, final int currentIndex0, final List<Integer> usedSleeves0, final Callback<Integer> callback0) {
super("Select Sleeves for " + playerName);
currentIndex = currentIndex0;
usedSleeves = usedSleeves0;
callback = callback0;
//add label for selecting random sleeves first
addSleevesLabel(FSkinImage.UNKNOWN, -1);
//add label for currently selected sleeves next
final Map<Integer, TextureRegion> sleeveMap = FSkin.getSleeves();
addSleevesLabel(new FTextureRegionImage(sleeveMap.get(currentIndex)), currentIndex);
//add label for remaining sleeves
for (final Integer i : sleeveMap.keySet()) {
if (currentIndex != i) {
addSleevesLabel(new FTextureRegionImage(sleeveMap.get(i)), i);
}
}
add(scroller);
}
private void addSleevesLabel(final FImage img, final int index) {
final FLabel lbl = new FLabel.Builder().icon(img).iconScaleFactor(0.99f).align(Align.center)
.iconInBackground(true).selectable(true).selected(currentIndex == index)
.build();
if (index == -1) {
lbl.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
callback.run(getRandomSleeves(usedSleeves));
Forge.back();
}
});
}
else {
lbl.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
callback.run(index);
Forge.back();
}
});
}
scroller.add(lbl);
}
@Override
protected void doLayout(float startY, float width, float height) {
scroller.setBounds(0, startY, width, height - startY);
}
}

View File

@@ -23,15 +23,18 @@ import forge.toolbox.FTextArea;
import forge.toolbox.GuiChoose;
import forge.toolbox.ListChooser;
import forge.util.Callback;
import forge.util.Localizer;
import forge.util.Utils;
public class NewGauntletScreen extends LaunchScreen {
private static final float PADDING = Utils.scale(10);
private final Localizer localizer = Localizer.getInstance();
private final FTextArea lblDesc = add(new FTextArea(false,
"In Gauntlet mode, you select a deck and play against multiple opponents.\n\n" +
"Configure how many opponents you wish to face and what decks or types of decks they will play.\n\n" +
"Then, try to beat all AI opponents without losing a match."));
localizer.getMessage("lblGauntletText1") + "\n\n" +
localizer.getMessage("lblGauntletText2") + "\n\n" +
localizer.getMessage("lblGauntletText3")));
public NewGauntletScreen() {
super(null, NewGameMenu.getMenu());
@@ -51,44 +54,41 @@ public class NewGauntletScreen extends LaunchScreen {
@Override
protected void startMatch() {
GuiChoose.oneOrNone("Select a Gauntlet Type", new String[] {
"Quick Gauntlet",
"Custom Gauntlet",
"Gauntlet Contest",
GuiChoose.oneOrNone(localizer.getMessage("lblSelectGauntletType"), new String[] {
localizer.getMessage("lblQuickGauntlet"),
localizer.getMessage("lblCustomGauntlet"),
localizer.getMessage("lblGauntletContest"),
}, new Callback<String>() {
@Override
public void run(String result) {
if (result == null) { return; }
switch (result) {
case "Quick Gauntlet":
if (localizer.getMessage("lblQuickGauntlet").equals(result)) {
createQuickGauntlet();
break;
case "Custom Gauntlet":
} else if(localizer.getMessage("lblCustomGauntlet").equals(result)) {
createCustomGauntlet();
break;
default:
} else {
createGauntletContest();
break;
}
}
});
}
private void createQuickGauntlet() {
GuiChoose.getInteger("How many opponents are you willing to face?", 3, 50, new Callback<Integer>() {
GuiChoose.getInteger(localizer.getMessage("lblHowManyOpponents"), 3, 50, new Callback<Integer>() {
@Override
public void run(final Integer numOpponents) {
if (numOpponents == null) { return; }
ListChooser<DeckType> chooser = new ListChooser<>(
"Choose allowed deck types for opponents", 0, 11, Arrays.asList(DeckType.CUSTOM_DECK,
localizer.getMessage("lblChooseAllowedDeckTypeOpponents"), 0, 11, Arrays.asList(DeckType.CUSTOM_DECK,
DeckType.PRECONSTRUCTED_DECK,
DeckType.QUEST_OPPONENT_DECK,
DeckType.COLOR_DECK,
DeckType.STANDARD_COLOR_DECK,
DeckType.STANDARD_CARDGEN_DECK,
DeckType.MODERN_COLOR_DECK,
DeckType.PIONEER_CARDGEN_DECK,
DeckType.MODERN_CARDGEN_DECK,
DeckType.LEGACY_CARDGEN_DECK,
DeckType.VINTAGE_CARDGEN_DECK,
@@ -99,7 +99,7 @@ public class NewGauntletScreen extends LaunchScreen {
return;
}
FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback<Deck>() {
FDeckChooser.promptForDeck(localizer.getMessage("lblSelectYourDeck"), GameType.Gauntlet, false, new Callback<Deck>() {
@Override
public void run(Deck userDeck) {
if (userDeck == null) {
@@ -118,7 +118,7 @@ public class NewGauntletScreen extends LaunchScreen {
}
private void createCustomGauntlet() {
GuiChoose.getInteger("How many opponents are you willing to face?", 3, 50, new Callback<Integer>() {
GuiChoose.getInteger(localizer.getMessage("lblHowManyOpponents"), 3, 50, new Callback<Integer>() {
@Override
public void run(final Integer numOpponents) {
if (numOpponents == null) { return; }
@@ -132,7 +132,7 @@ public class NewGauntletScreen extends LaunchScreen {
private void promptForAiDeck(final GauntletData gauntlet, final int numOpponents) {
final int opponentNum = gauntlet.getDecks().size() + 1;
FDeckChooser.promptForDeck("Select Deck for Opponent " + opponentNum + " / " + numOpponents, GameType.Gauntlet, true, new Callback<Deck>() {
FDeckChooser.promptForDeck(localizer.getMessage("lblSelectDeckForOpponent") + " " + opponentNum + " / " + numOpponents, GameType.Gauntlet, true, new Callback<Deck>() {
@Override
public void run(Deck aiDeck) {
if (aiDeck == null) { return; }
@@ -145,7 +145,7 @@ public class NewGauntletScreen extends LaunchScreen {
}
else {
//once all ai decks have been selected, prompt for user deck
FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback<Deck>() {
FDeckChooser.promptForDeck(localizer.getMessage("lblSelectYourDeck"), GameType.Gauntlet, false, new Callback<Deck>() {
@Override
public void run(Deck userDeck) {
if (userDeck == null) { return; }
@@ -170,12 +170,12 @@ public class NewGauntletScreen extends LaunchScreen {
}
}
GuiChoose.oneOrNone("Select Gauntlet Contest", contests, new Callback<GauntletData>() {
GuiChoose.oneOrNone(localizer.getMessage("lblSelectGauntletContest"), contests, new Callback<GauntletData>() {
@Override
public void run(final GauntletData contest) {
if (contest == null) { return; }
FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback<Deck>() {
FDeckChooser.promptForDeck(localizer.getMessage("lblSelectYourDeck"), GameType.Gauntlet, false, new Callback<Deck>() {
@Override
public void run(final Deck userDeck) {
if (userDeck == null) { return; }

View File

@@ -19,15 +19,13 @@ import forge.toolbox.FEvent.FEventHandler;
import forge.util.Localizer;
public class LoadGameMenu extends FPopupMenu {
final static Localizer localizer = Localizer.getInstance();
public enum LoadGameScreen {
BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.HAND, LoadDraftScreen.class),
SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.PACK, LoadSealedScreen.class),
QuestMode(localizer.getMessage("lblQuestMode"), FSkinImage.QUEST_ZEP, LoadQuestScreen.class),
PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MULTIVERSE, LoadConquestScreen.class),
Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class);
BoosterDraft("Booster Draft", FSkinImage.HAND, LoadDraftScreen.class),
SealedDeck("Sealed Deck", FSkinImage.PACK, LoadSealedScreen.class),
QuestMode("Quest Mode", FSkinImage.QUEST_ZEP, LoadQuestScreen.class),
PlanarConquest("Planar Conquest", FSkinImage.MULTIVERSE, LoadConquestScreen.class),
Gauntlet("Gauntlet", FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class);
private final FMenuItem item;
private final Class<? extends FScreen> screenClass;
private FScreen screen;
@@ -47,7 +45,7 @@ public class LoadGameMenu extends FPopupMenu {
if (screen == null) { //don't initialize screen until it's opened the first time
try {
screen = screenClass.newInstance();
screen.setHeaderCaption(localizer.getMessage("lblLoadGame") + " - " + item.getText());
screen.setHeaderCaption(Localizer.getInstance().getMessage("lblLoadGame") + " - " + item.getText());
}
catch (Exception e) {
e.printStackTrace();

View File

@@ -18,6 +18,7 @@ import forge.toolbox.FOptionPane;
import forge.toolbox.FTextArea;
import forge.toolbox.GuiChoose;
import forge.util.Callback;
import forge.util.Localizer;
import forge.util.Utils;
import java.util.ArrayList;
import java.util.Collections;
@@ -28,10 +29,9 @@ public class PuzzleScreen extends LaunchScreen {
private static final float PADDING = Utils.scale(10);
private final FTextArea lblDesc = add(new FTextArea(false,
"Puzzle Mode loads in a puzzle that you have to win in a predetermined time/way.\n\n" +
"To begin, press the Start button below, then select a puzzle from a list.\n\n" +
"Your objective will be displayed in a pop-up window when the puzzle starts and also " +
"specified on a special effect card which will be placed in your command zone."));
Localizer.getInstance().getMessage("lblPuzzleText1") + "\n\n" +
Localizer.getInstance().getMessage("lblPuzzleText2") + "\n\n" +
Localizer.getInstance().getMessage("lblPuzzleText3")));
public PuzzleScreen() {
super(null, NewGameMenu.getMenu());
@@ -54,10 +54,10 @@ public class PuzzleScreen extends LaunchScreen {
final ArrayList<Puzzle> puzzles = PuzzleIO.loadPuzzles();
Collections.sort(puzzles);
GuiChoose.one("Choose a puzzle", puzzles, new Callback<Puzzle>() {
GuiChoose.one(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback<Puzzle>() {
@Override
public void run(final Puzzle chosen) {
LoadingOverlay.show("Loading the puzzle...", new Runnable() {
LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() {
@Override
public void run() {
// Load selected puzzle

View File

@@ -30,6 +30,7 @@ import forge.match.HostedMatch;
import forge.model.FModel;
import forge.player.GamePlayerUtil;
import forge.toolbox.FComboBox;
import forge.util.Localizer;
import forge.util.gui.SGuiChoose;
import java.util.ArrayList;
import java.util.List;
@@ -37,20 +38,20 @@ import java.util.List;
public class LoadDraftScreen extends LaunchScreen {
private final DeckManager lstDecks = add(new DeckManager(GameType.Draft));
private final FLabel lblTip = add(new FLabel.Builder()
.text("Double-tap to edit deck (Long-press to view)")
.text(Localizer.getInstance().getMessage("lblDoubleTapToEditDeck"))
.textColor(FLabel.INLINE_LABEL_COLOR)
.align(Align.center).font(FSkinFont.get(12)).build());
private final FSkinFont GAME_MODE_FONT= FSkinFont.get(12);
private final FLabel lblMode = add(new FLabel.Builder().text("Mode:").font(GAME_MODE_FONT).build());
private final FLabel lblMode = add(new FLabel.Builder().text(Localizer.getInstance().getMessage("lblMode")).font(GAME_MODE_FONT).build());
private final FComboBox<String> cbMode = add(new FComboBox<>());
public LoadDraftScreen() {
super(null, LoadGameMenu.getMenu());
cbMode.setFont(GAME_MODE_FONT);
cbMode.addItem("Gauntlet");
cbMode.addItem("Single Match");
cbMode.addItem(Localizer.getInstance().getMessage("lblGauntlet"));
cbMode.addItem(Localizer.getInstance().getMessage("lblSingleMatch"));
lstDecks.setup(ItemManagerConfig.DRAFT_DECKS);
lstDecks.setItemActivateHandler(new FEventHandler() {
@@ -98,17 +99,18 @@ public class LoadDraftScreen extends LaunchScreen {
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
Localizer localizer = Localizer.getInstance();
final DeckProxy humanDeck = lstDecks.getSelectedItem();
if (humanDeck == null) {
FOptionPane.showErrorDialog("You must select an existing deck or build a deck from a new booster draft game.", "No Deck");
FOptionPane.showErrorDialog(localizer.getMessage("lblYouMustSelectExistingDeck"), localizer.getMessage("lblNoDeck"));
return;
}
// TODO: if booster draft tournaments are supported in the future, add the possibility to choose them here
final boolean gauntlet = cbMode.getSelectedItem().equals("Gauntlet");
final boolean gauntlet = cbMode.getSelectedItem().equals(localizer.getMessage("lblGauntlet"));
if (gauntlet) {
final Integer rounds = SGuiChoose.getInteger("How many opponents are you willing to face?",
final Integer rounds = SGuiChoose.getInteger(localizer.getMessage("lblHowManyOpponents"),
1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size());
if (rounds == null) {
return;
@@ -121,7 +123,7 @@ public class LoadDraftScreen extends LaunchScreen {
return;
}
LoadingOverlay.show("Loading new game...", new Runnable() {
LoadingOverlay.show(localizer.getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
FModel.getGauntletMini().resetGauntletDraft();
@@ -131,7 +133,7 @@ public class LoadDraftScreen extends LaunchScreen {
}
});
} else {
final Integer aiIndex = SGuiChoose.getInteger("Which opponent would you like to face?",
final Integer aiIndex = SGuiChoose.getInteger(localizer.getMessage("lblWhichOpponentWouldYouLikeToFace"),
1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size());
if (aiIndex == null) {
return; // Cancel was pressed
@@ -146,7 +148,7 @@ public class LoadDraftScreen extends LaunchScreen {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show("Loading new game...", new Runnable() {
LoadingOverlay.show(localizer.getMessage("lblLoadingNewGame"), new Runnable() {
@Override
public void run() {
if (!checkDeckLegality(humanDeck)) {
@@ -177,7 +179,7 @@ public class LoadDraftScreen extends LaunchScreen {
if (FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) {
String errorMessage = GameType.Draft.getDeckFormat().getDeckConformanceProblem(humanDeck.getDeck());
if (errorMessage != null) {
FOptionPane.showErrorDialog("Your deck " + errorMessage + "\nPlease edit or choose a different deck.", "Invalid Deck");
FOptionPane.showErrorDialog(Localizer.getInstance().getMessage("lblInvalidDeckDesc").replace("%n", errorMessage), Localizer.getInstance().getMessage("lblInvalidDeck"));
return false;
}
}

View File

@@ -11,6 +11,7 @@ import forge.screens.LoadingOverlay;
import forge.screens.home.NewGameMenu;
import forge.toolbox.FLabel;
import forge.toolbox.FTextArea;
import forge.util.Localizer;
import forge.util.ThreadUtil;
import forge.util.Utils;
import forge.util.gui.SGuiChoose;
@@ -19,9 +20,9 @@ public class NewDraftScreen extends LaunchScreen {
private static final float PADDING = Utils.scale(10);
private final FTextArea lblDesc = add(new FTextArea(false,
"In Draft mode, three booster packs are rotated around eight players.\n\n" +
"Build a deck from the cards you choose. The AI will do the same.\n\n" +
"Then, play against any number of the AI opponents."));
Localizer.getInstance().getMessage("lblDraftText1") + "\n\n" +
Localizer.getInstance().getMessage("lblDraftText2") + "\n\n" +
Localizer.getInstance().getMessage("lblDraftText3")));
public NewDraftScreen() {
super(null, NewGameMenu.getMenu());
@@ -44,7 +45,7 @@ public class NewDraftScreen extends LaunchScreen {
ThreadUtil.invokeInGameThread(new Runnable() { //must run in game thread to prevent blocking UI thread
@Override
public void run() {
final LimitedPoolType poolType = SGuiChoose.oneOrNone("Choose Draft Format", LimitedPoolType.values());
final LimitedPoolType poolType = SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblChooseDraftFormat"), LimitedPoolType.values());
if (poolType == null) { return; }
final BoosterDraft draft = BoosterDraft.createDraft(poolType);
@@ -53,7 +54,7 @@ public class NewDraftScreen extends LaunchScreen {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
LoadingOverlay.show("Loading new draft...", new Runnable() {
LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingNewDraft"), new Runnable() {
@Override
public void run() {
Forge.openScreen(new DraftingProcessScreen(draft, EditorType.Draft, null));

View File

@@ -12,6 +12,7 @@ import forge.screens.LaunchScreen;
import forge.screens.home.NewGameMenu;
import forge.toolbox.FLabel;
import forge.toolbox.FTextArea;
import forge.util.Localizer;
import forge.util.ThreadUtil;
import forge.util.Utils;
@@ -19,9 +20,9 @@ public class NewSealedScreen extends LaunchScreen {
private static final float PADDING = Utils.scale(10);
private final FTextArea lblDesc = add(new FTextArea(false,
"In Sealed mode, you build a deck from booster packs (maximum 10).\n\n" +
"Build a deck from the cards you receive. A number of AI opponents will do the same.\n\n" +
"Then, play against each of the AI opponents."));
Localizer.getInstance().getMessage("lblSealedText2") + "\n\n" +
Localizer.getInstance().getMessage("lblSealedText3") + "\n\n" +
Localizer.getInstance().getMessage("lblSealedText4")));
public NewSealedScreen() {
super(null, NewGameMenu.getMenu());

View File

@@ -7,6 +7,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import forge.FThreads;
import forge.assets.FSkinImage;
import forge.util.Localizer;
import org.apache.commons.lang3.StringUtils;
@@ -68,6 +70,8 @@ public class MatchController extends AbstractGuiGame {
private static final Map<String, FImage> avatarImages = new HashMap<>();
private static final Map<String, FImage> sleeveImages = new HashMap<>();
private static HostedMatch hostedMatch;
private static MatchScreen view;
@@ -100,12 +104,34 @@ public class MatchController extends AbstractGuiGame {
return avatar;
}
public static FImage getPlayerSleeve(final PlayerView p) {
if (p == null)
return FSkinImage.UNKNOWN;
final String lp = p.getLobbyPlayerName();
FImage sleeve = sleeveImages.get(lp);
if (sleeve == null) {
sleeve = new FTextureRegionImage(FSkin.getSleeves().get(p.getSleeveIndex()));
}
return sleeve;
}
@Override
public void refreshCardDetails(final Iterable<CardView> cards) {
//ensure cards appear in the correct row of the field
/*//ensure cards appear in the correct row of the field
for (final VPlayerPanel pnl : view.getPlayerPanels().values()) {
pnl.getField().update();
}
}*/
}
@Override
public void refreshField() {
if(getGameView() == null)
return;
if(getGameView().getPhase() == null)
return;
if (getGameView().getPhase().phaseforUpdateField())
for (final VPlayerPanel pnl : view.getPlayerPanels().values())
pnl.getField().update();
}
public boolean hotSeatMode() {
@@ -363,6 +389,42 @@ public class MatchController extends AbstractGuiGame {
}
}
@Override
public void setSelectables(final Iterable<CardView> cards) {
super.setSelectables(cards);
// update zones on tabletop and floating zones - non-selectable cards may be rendered differently
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public final void run() {
for (final PlayerView p : getGameView().getPlayers()) {
if ( p.getCards(ZoneType.Battlefield) != null ) {
updateCards(p.getCards(ZoneType.Battlefield));
}
if ( p.getCards(ZoneType.Hand) != null ) {
updateCards(p.getCards(ZoneType.Hand));
}
}
}
});
}
@Override
public void clearSelectables() {
super.clearSelectables();
// update zones on tabletop and floating zones - non-selectable cards may be rendered differently
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public final void run() {
for (final PlayerView p : getGameView().getPlayers()) {
if ( p.getCards(ZoneType.Battlefield) != null ) {
updateCards(p.getCards(ZoneType.Battlefield));
}
if ( p.getCards(ZoneType.Hand) != null ) {
updateCards(p.getCards(ZoneType.Hand));
}
}
}
});
}
@Override
public void afterGameEnd() {
Forge.back();

View File

@@ -376,6 +376,14 @@ public class MatchScreen extends FScreen {
TargetingOverlay.drawArrow(g, blocker, attacker);
}
}
//player
if (is4Player() || is3Player()) {
int numplayers = is3Player() ? 3 : 4;
for (final PlayerView p : game.getPlayers()) {
if (combat.getAttackersOf(p).contains(attacker))
TargetingOverlay.drawArrow(g, attacker, p, numplayers);
}
}
}
}
@@ -395,7 +403,7 @@ public class MatchScreen extends FScreen {
return getActivePrompt().getBtnCancel().trigger(); //trigger Cancel if can't trigger OK
case Keys.ESCAPE:
if (!FModel.getPreferences().getPrefBoolean(FPref.UI_ALLOW_ESC_TO_END_TURN)) {
if (getActivePrompt().getBtnCancel().getText().equals("End Turn")) {
if (getActivePrompt().getBtnCancel().getText().equals(Localizer.getInstance().getMessage("lblEndTurn"))) {
return false;
}
}

View File

@@ -79,6 +79,11 @@ public class TargetingOverlay {
CardAreaPanel.get(endCard).getTargetingArrowOrigin(),
connects);
}
public static void drawArrow(Graphics g, CardView startCard, PlayerView targetPlayer, int numplayers) {
drawArrow(g, CardAreaPanel.get(startCard).getTargetingArrowOrigin(),
MatchController.getView().getPlayerPanel(targetPlayer).getAvatar().getTargetingArrowOrigin(numplayers),
ArcConnection.FoesAttacking);
}
public static void drawArrow(Graphics g, Vector2 start, CardView targetCard, ArcConnection connects) {
drawArrow(g, start,
CardAreaPanel.get(targetCard).getTargetingArrowOrigin(),

View File

@@ -45,10 +45,15 @@ public class VAvatar extends FDisplayObject {
}
public Vector2 getTargetingArrowOrigin() {
return getTargetingArrowOrigin(2);
}
public Vector2 getTargetingArrowOrigin(int numplayers) {
Vector2 origin = new Vector2(screenPos.x, screenPos.y);
origin.x += WIDTH * 0.75f;
if (origin.y < MatchController.getView().getHeight() / 2) {
float modx = numplayers > 2 ? 0.25f : 0.75f;
origin.x += WIDTH * modx;
if (origin.y < MatchController.getView().getHeight() / numplayers) {
origin.y += HEIGHT * 0.75f; //target bottom right corner if on top half of screen
}
else {

View File

@@ -53,21 +53,24 @@ public class ControlWinLose {
view.hide();
saveOptions();
MatchController.getHostedMatch().continueMatch();
try { MatchController.getHostedMatch().continueMatch();
} catch (NullPointerException e) {}
}
/** Action performed when "restart" button is pressed in default win/lose UI. */
public void actionOnRestart() {
view.hide();
saveOptions();
MatchController.getHostedMatch().restartMatch();
try { MatchController.getHostedMatch().restartMatch();
} catch (NullPointerException e) {}
}
/** Action performed when "quit" button is pressed in default win/lose UI. */
public void actionOnQuit() {
// Reset other stuff
saveOptions();
MatchController.getHostedMatch().endCurrentGame();
try { MatchController.getHostedMatch().endCurrentGame();
} catch (NullPointerException e) {}
view.hide();
}

View File

@@ -302,8 +302,8 @@ public class SettingsPage extends TabPage<SettingsScreen> {
localizer.getMessage("nlDisableCardEffect")),
4);
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_BORDER_MASKING,
"Enable Round Border Mask",
"When enabled, the card corners are rounded (Preferably Card with Full Borders)."){
localizer.getMessage("lblEnableRoundBorder"),
localizer.getMessage("nlEnableRoundBorder")){
@Override
public void select() {
super.select();
@@ -312,8 +312,8 @@ public class SettingsPage extends TabPage<SettingsScreen> {
}
},4);
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART,
"Preload Extended Art Cards",
"When enabled, Preloads Extended Art Cards to Cache on Startup."){
localizer.getMessage("lblPreloadExtendedArtCards"),
localizer.getMessage("nlPreloadExtendedArtCards")){
@Override
public void select() {
super.select();
@@ -322,8 +322,8 @@ public class SettingsPage extends TabPage<SettingsScreen> {
}
},4);
lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_FPS,
"Show FPS Display",
"When enabled, show the FPS Display (Experimental)."){
localizer.getMessage("lblShowFPSDisplay"),
localizer.getMessage("nlShowFPSDisplay")){
@Override
public void select() {
super.select();

View File

@@ -1 +1,84 @@
This file is automatically updated by our release bot on Discord, Blacksmith. It is created from the files present in the 'release-files' directory. Please do not hand-edit this file if using the bot to perform a release, as your changes will be overwritten.
Forge: 11/11/2019 ver 1.6.30
19439 cards in total.
--------------
Release Notes:
--------------
- Bug fixes -
As always, this release of Forge features an assortment of bug fixes and improvements based on user feedback during the previous release run.
-------------
Known Issues:
-------------
Known issues are here: https://git.cardforge.org/core-developers/forge/issues
Feel free to report your own there if you have any.
-------------
Installation:
-------------
The Forge archive includes a MANUAL.txt file and we ask that you spend a few minutes reading this file as it contains some information that may prove useful. We do tend to update this file at times and you should quickly read this file and look for new information for each and every new release. Thank you.
The archive format used for the Forge distribution is ".tar.bz2". There are utilities for Windows, Mac OS and the various *nix's that can be used to extract/decompress these ".tar.bz2" archives. We recommend that you extract/decompress the Forge archive into a new and unused folder.
Some people use the Windows application 7zip. This utility can be found at http://www.7-zip.org/download.html. Mac users can double click on the archive and the application Archive Utility will launch and extract the archive. Mac users do not need to download a separate utility.
Once the Forge archive has been decompressed you should then be able to launch Forge by using the included launcher. Launching Forge by double clicking on the forge jar file in the past caused a java heap space error. Forge's memory requirements have increased over time and the launchers increase the java heap space available to Forge. Currently you can launch Forge by double clicking on the forge jar file without a java heap space error but this is likely to change as we add in more sounds, icons, etc.
- The Mac OS application version -
We provide separate macOS builds of desktop and mobile (backported) Forge packaged as native Mac applications. Please check the relevant thread for details and download links.
- Online Multiplayer -
For local network play you should only need two systems running Forge. One to host and one to join and play. For remote (over the Internet) play you will need to ensure that the port used (36743 by default) is forwarded to the hosting machine.
--------------------
Active Contributors:
--------------------
Agetian
apantel
Austinio7116
Churrufli
DrDev
excessum
Flair
Gos
Hanmac
Indigo Dragon
Jamin Collins
kevlahnota
klaxnek
KrazyTheFox
leriomaggio
Luke
Marek14
mcrawford620
Meerkov
Myrd
nefigah
OgreBattlecruiser
pfps
Ryan1729
Seravy
Sirspud
Sloth
slyfox7777777
Sol
Swordshine
tjtillman
tojammot
torridus
Xyx
Zuchinni
(If you think your name should be on this list, add it with your next contribution)
(Quest icons used created by Teekatas, from his Legendora set http://raindropmemory.deviantart.com)
(Thanks to the XMage team for permission to use their targeting arrows.)
(Thanks to http://www.freesound.org/browse/ for providing some sound files.)

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.30</version>
</parent>
<artifactId>forge-gui</artifactId>
@@ -39,28 +39,33 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1-android</version>
<version>28.1-android</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
<version>1.4.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.25.Final</version>
<version>4.1.43.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.fourthline.cling</groupId>
@@ -72,6 +77,11 @@
<artifactId>slf4j-simple</artifactId>
<version>1.7.22</version>
</dependency>
<dependency>
<groupId>org.mapdb</groupId>
<artifactId>elsa</artifactId>
<version>3.0.0-M7</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,6 +1,8 @@
#Add one announcement per line
Throne of Eldraine pre-release!
Updated Libgdx from 1.5.5 to 1.9.10 ([url=https://github.com/libgdx/libgdx/blob/master/CHANGES]detailed changes are here[/url]).
Throne of Eldraine fixes
Pioneer is here!
Some fancy looking UI stuff was added. Card Sleeves and Keyword Icons
Continued work on Translations
[b]Forge now requires Java 8 (or newer). You will not be able to start the game if you are not yet running Java 8.[/b]
For some reason Oracle hates Forge and version 1.8.0_211 does bad things with Forge for unknown reasons. Downgrade to 202 for a beter time.
https://www.oracle.com/technetwork/java/javase/downloads/java-archive-javase8-2177648.html

View File

@@ -10,6 +10,7 @@ Hanmac
Indigo Dragon
Jamin Collins
kevlahnota
klaxnek
KrazyTheFox
leriomaggio
Luke

View File

@@ -1,6 +1,6 @@
Name:Dread Warlock
ManaCost:1 B B
Types:Creature Human Wizard
Types:Creature Human Wizard Warlock
PT:2/2
K:CantBeBlockedBy Creature.nonBlack
SVar:Picture:http://www.wizards.com/global/images/magic/general/dread_warlock.jpg

View File

@@ -1,6 +1,6 @@
Name:Memory Theft
ManaCost:2 B
Types:Sorcery
A:SP$ Discard | Cost$ 2 B | ValidTgts$ Opponent | Mode$ RevealYouChoose | NumCards$ 1 | SubAbility$ DBChangeZone | SpellDescription$ Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard.
A:SP$ Discard | Cost$ 2 B | ValidTgts$ Opponent | Mode$ RevealYouChoose | NumCards$ 1 | DiscardValid$ Card.nonLand | SubAbility$ DBChangeZone | SpellDescription$ Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard.
SVar:DBChangeZone:DB$ ChangeZone | ChangeType$ Card.AdventureCard+TargetedPlayerCtrl | Origin$ Exile | Destination$ Graveyard | Hidden$ True
Oracle:Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard.

View File

@@ -7,7 +7,7 @@ K:Deathtouch
K:Haste
K:CantBeBlockedBy Creature.powerLE2
S:Mode$ CantPreventDamage | IsCombat$ True | ValidSource$ Creature.YouCtrl | Description$ Combat damage that would be dealt by creatures you control cant be prevented.
T:Mode$ DamageDone | ValidSource$ Creature.YouCtrl | ValidTarget$ Opponent | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ MoreDamage | TriggerDescription$ Whenever CARDNAME deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls.
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Opponent | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ MoreDamage | TriggerDescription$ Whenever CARDNAME deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls.
SVar:MoreDamage:DB$ DealDamage | ValidTgts$ Planeswalker.ControlledBy TriggeredTarget | TgtPrompt$ Select target planeswalker that player controls | NumDmg$ X | References$ X
SVar:X:TriggerCount$DamageAmount
Oracle:Vigilance, deathtouch, haste\nQuesting Beast cant be blocked by creatures with power 2 or less.\nCombat damage that would be dealt by creatures you control cant be prevented.\nWhenever Questing Beast deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls.

View File

@@ -3,6 +3,6 @@ ManaCost:W/B W/B W/B W/B
Types:Creature Human Knight
PT:4/2
A:AB$ Pump | Cost$ W/B W/B | KW$ Lifelink | Defined$ Self | SpellDescription$ CARDNAME gains lifelink until end of turn.
A:AB$ Pump | Cost$ W/B W/B W/B W/B | KW$ Indestructible | Defined$ Self | SpellDescription$ CARDNAME gains indestructible until end of turn.
A:AB$ Pump | Cost$ W/B W/B W/B | KW$ Indestructible | Defined$ Self | SpellDescription$ CARDNAME gains indestructible until end of turn.
DeckHas:Ability$LifeGain
Oracle:{W/B}{W/B}: Resolute Rider gains lifelink until end of turn.\n{W/B}{W/B}{W/B}{W/B}: Resolute Rider gains indestructible until end of turn.
Oracle:{W/B}{W/B}: Resolute Rider gains lifelink until end of turn.\n{W/B}{W/B}{W/B}: Resolute Rider gains indestructible until end of turn.

Binary file not shown.

Binary file not shown.

View File

@@ -4,4 +4,4 @@ Order:108
Subtype:Custom
Type:Casual
Rarities:L, C
Banned:Gush;Gitaxian Probe;Daze
Banned:Gush;Gitaxian Probe;Daze;Arcum's Astrolabe

View File

@@ -1,6 +1,6 @@
[format]
Name:Modern
Order:102
Order:103
Subtype:Modern
Type:Sanctioned
Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MM2, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD

View File

@@ -0,0 +1,7 @@
[format]
Name:Pioneer
Order:102
Subtype:Pioneer
Type:Sanctioned
Sets:RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, HOU, XLN, RIX, DOM, M19, GRN, RNA, WAR, M20, ELD
Banned:Bloodstained Mire; Flooded Strand; Polluted Delta; Windswept Heath; Wooded Foothills; Felidar Guardian; Leyline of Abundance; Oath of Nissa

View File

@@ -4,4 +4,4 @@ Order:101
Subtype:Standard
Type:Sanctioned
Sets:GRN, RNA, WAR, M20, ELD
Banned:
Banned:Field of the Dead

View File

@@ -41,7 +41,7 @@ txerrFailedtodeletelayoutfile=Fehler beim Löschen der Layout-Datei.
#VSubmenuPreferences.java
Preferences=Einstellungen
btnReset=Alles zurücksetzen
btnDeleteMatchUI=SpielfeldLayout zurücksetzen
btnDeleteMatchUI=Spielfeld-Layout zurücksetzen
btnDeleteEditorUI=Editor-Layout zurücksetzen
btnDeleteWorkshopUI=Workshop-Layout zurücksetzen
btnUserProfileUI=Öffne Benutzer-Verzeichnis
@@ -179,8 +179,8 @@ KeyboardShortcuts=Tastenkombinationen
lblAchievements=Errungenschaften
# VSubmenuDownloaders.java
btnDownloadSetPics=Bilder(LQ) Sets herunterladen
btnDownloadPics=Bilder(LQ) Karten herunterladen
btnDownloadPicsHQ=Bilder(HQ) Karten herunterladen (Sehr langsam!)
btnDownloadPics=Bilder(LQ) Karten herunterladen
btnDownloadQuestImages=Bilder für Quests herunterladen
btnDownloadAchievementImages=Bilder für Erfolge herunterladen
btnReportBug=Einen Fehler melden
@@ -548,6 +548,7 @@ lblPreconstructedDecks=Vorkonstruiertes Deck
lblQuestOpponentDecks=Quest-Gegner-Deck
lblRandomColorDecks=Decks - zufällige Farben
lblRandomStandardArchetypeDecks=Decks - zufälliger Standard-Archetyp
lblRandomPioneerArchetypeDecks=Decks - zufälliger Pioneer-Archetyp
lblRandomModernArchetypeDecks=Decks - zufälliger Modern-Archetyp
lblRandomLegacyArchetypeDecks=Decks - zufälliger Legacy-Archetyp
lblRandomVintageArchetypeDecks=Decks - zufälliger Vintage-Archetyp
@@ -628,7 +629,7 @@ titleUnlocked=%n freigeschaltet!
lblStartADuel=Starte eine Duell.
lblSelectAQuestDeck=Wähle ein Quest-Deck
lblInvalidDeck=Unzulässiges Deck
lblInvalidDeckDesc=Dein Deck %n. Bitte ändern oder anderes Deck wählen.
lblInvalidDeckDesc=Dein Deck %n\nBitte ändern oder anderes Deck wählen.
#VSubmenuQuestPrefs.java
lblQuestPreferences=Quest-Einstellungen
lblRewardsError=Fehler bei Belohnungen
@@ -795,7 +796,7 @@ lbltodeck=zum Deck
lblfromdeck=vom Deck
lbltosideboard=zum Sideboard
lblfromsideboard=vom Sideboard
lblascommander=als Kommandeur
lblascommander=als General
lblasoathbreaker=als "Eidbrecher"
lblassignaturespell=als "Signatur"-Spruch
lblasavatar=als Avatar
@@ -950,6 +951,12 @@ nlShowMatchBackground=Zeige Bilder im Spielfeldhintergrund.
nlTheme=Wähle ein Thema um die Bildschirmanzeigen anzupassen.
nlVibrateAfterLongPress=Aktiviert Vibration bei langen Druck, z.B. beim Zoomen.
nlVibrateWhenLosingLife=Aktiviert Vibration bei Lebenspunktverlust.
lblEnableRoundBorder=Aktiviere Maske mit runden Ränder
nlEnableRoundBorder=Wenn aktiviert, werden Kartenecken abgerundet. Vorzugsweise bei Karten mit vollem Rand.
lblPreloadExtendedArtCards=Erw. Kartenbilder bei Start laden
nlPreloadExtendedArtCards=Wenn aktiviert, werden erweiterte Kartenbilder bereits beim Start in den Speicher geladen.
lblShowFPSDisplay=FPS-Anzeige
nlShowFPSDisplay=Aktiviert die Frames-per-second-Anzeige (Experimentell).
#MatchScreen.java
lblPlayers=Spieler
lblLog=Bericht
@@ -980,12 +987,13 @@ lblToMainDeck=zum Haupt-Deck
lblHowMany=wie viel?
lblInventory=Inhaltsverzeichnis
lblCollection=Sammlung
lblCommanders=Komandeure
lblCommanders=Generäle
lblOathbreakers=Eidbrecher
#Forge.java
lblLoadingFonts=Lade Schriftarten...
lblLoadingCardTranslations=Lade Karten-Übersetzungen...
lblFinishingStartup=Letzte Vorbereitungen...
lblPreloadExtendedArt=Lade erweiterte Bilder...
#LobbyScreen.java
lblMore=Mehr...
lblLoadingNewGame=Lade neues Spiel...
@@ -1088,7 +1096,7 @@ lblStormCount=Sturmzähler
#PlayerControllerHuman.java
lblYouHaveWonTheCoinToss=%s, du hast den Münzwurf gewonnen.
lblYouLostTheLastGame=%s, du hast das letzte Spiel verloren.
lblWouldYouLiketoPlayorDraw=Willst du lieber zuerst spielen oder ziehen.
lblWouldYouLiketoPlayorDraw=Willst du lieber zuerst spielen oder ziehen?
lblWhoWouldYouLiketoStartthisGame=Wer soll das Spiel beginnen? (Klicke auf das Portrait.)
lblPlay=Spielen
lblDraw=Ziehen
@@ -1140,6 +1148,28 @@ lblArrangeCardsToBePutOnTopOfYourLibrary=Ordne Karten, welche unter die Biblioth
lblTopOfLibrary=Oben auf Bibliothek
lblSelectCardsToBePutIntoTheGraveyard=Wähle Karten, welche auf den Friedhof gelegt werden sollen
lblCardsToPutInTheGraveyard=Karten, welche auf den Friedhof gelegt werden sollen
lblDiscardUpToNCards=Werfe bis zu %d Karte(n) ab
lblDiscardNCards=Werfe %d Karte(n) ab
lblSelectNCardsToDiscardUnlessDiscarduType=Wähle bis zu %d Karte(n) zum abwerfen, außer du wirfst eine %s ab.
lblCleanupPhase=Aufräumphase
lblSelectCardsToDiscardHandDownMaximum=Werfe %d Karte(n) ab um dein Handmaximum von %max Karte(n) zu erfüllen.
lblChooseMinCardToDiscard=Wähle %d Karte(n) zm Abwerfen
lblDiscarded=Abgeworfen
lblChooseDamageOrderFor=Wähle Schadensreihenfolge für %s
lblDamagedFirst=Zuerst geschädigt
lblChooseBlockerAfterWhichToPlaceAttackert=Wähle Blocker für Platz %s in der Schadensreihenfolge; Abbrechen für ersten Platz
lblPutCardOnTopOrBottomLibrary=Lege %s auf oder unter deine Bibliothek?
lblChooseOrderCardsPutIntoLibrary=Wähle die Reihenfolge der Karten, in der sie in die Bibliothek gelegt werden
lblClosestToTop=Zuoberst
lblChooseOrderCardsPutOntoBattlefield=Wähle die Reihenfolge der Karten, in der sie auf das Spielfeld gebracht werden
lblPutFirst=Lege zuerst
lblChooseOrderCardsPutIntoGraveyard=Wähle die Reihenfolge der Karten, in der sie in den Friedhof gelegt werden
lblClosestToBottom=Zuunterst
lblChooseOrderCardsPutIntoPlanarDeck=Wähle die Reihenfolge der Karten, in der sie in das Weltendeck gelegt werden
lblChooseOrderCardsPutIntoSchemeDeck=Wähle die Reihenfolge der Karten, in der sie in den Verschwörungsdeck gelegt werden
lblChooseOrderCopiesCast=Wähle die Reihenfolge für die Kopien
lblDelveHowManyCards=Wühlen - Wie viele Karten?
lblExileWhichCard=Schicke welche Karte ins Exil?
#AbstractGuiGame.java
lblConcedeCurrentGame=Das Spiel wird als verloren gewertet.\n\nTrotzdem aufgeben?
lblConcedeTitle=Spiel verloren geben?
@@ -1171,4 +1201,41 @@ btnQuitMatch=Beende Partie
lblItsADraw=Es ist ein Unentschieden!
lblTeamWon=Team %s hat gewonnen!
lblWinnerWon=%s hat gewonnen!
lblGameLog=Spiel-Aufzeichnung
lblGameLog=Spiel-Bericht
#NewDraftScreen.java
lblLoadingNewDraft=Lade neuen Draft...
#LoadDraftScreen.java
lblDoubleTapToEditDeck=Doppelklick zum Bearbeiten. Lange drücken für Anzeige.
lblMode=Modus:
lblYouMustSelectExistingDeck=Du mußt eine bestehendes Deck wählen oder ein neues Draft-Deck erstellen.
lblWhichOpponentWouldYouLikeToFace=Wähle deinen Gegner!
lblSingleMatch=Einzelnes Spiel
#NewGauntletScreen.java
lblGauntletText1=Beim Spießrutenlauf wählst du ein Deck und tritts gegen mehrer Gegner an.
lblGauntletText2=Wähle die Anzahl der Gegener und welche Art Deck sie spielen sollen.
lblGauntletText3=Dann versuche alle Gegner zu besiegen auche ein Spiel zu verlieren.
lblSelectGauntletType=Wähle die Art des Spießrutenlaufs
lblCustomGauntlet=angepaßter Spießrutenlauf
lblGauntletContest=Wettbewerb
lblSelectYourDeck=Wähle dein Deck
lblSelectDeckForOpponent=Wähle Deck für Gegner
lblSelectGauntletContest=Wähle Wettbewerb
#PuzzleScreen.java
lblPuzzleText1=Der puzzle-Modus lädt ein Puzzle, welches du auf eine bestimmte Art zu gewinnen hast.
lblPuzzleText2=Drücke Start und wähle ein Puzzle aus der Liste.
lblPuzzleText3=Zu Beginn wird dir in einem Fenster dein Ziel erklärt, und auch eventuelle spezielle Karten in deiner Kommandozone.
lblChooseAPuzzle=Wähle ein Puzzle
lblLoadingThePuzzle=Lade das Puzzle...
#InputPassPriority.java
lblCastSpell=Einen Zauberspruch sprechen
lblPlayLand=Spiele ein Land
lblActivateAbility=Aktiviere Fähigkeit
lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=Du hast noch unverbrauchtes Mana, welches verloren geht, wenn du die Priorität abgibst.
lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=Du wirst Manabrand erleiden, in Höhe des verlorenen Manas.
lblManaFloating=Unverbrauchtes Mana
#InputPayManaOfCostPayment.java
lblPayManaCost=Zahle die Spruchkosten:
lblLifePaidForPhyrexianMana=(%d Leben wurde bezahlt für phyrexianisches Mana)
lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Klicke auf deine Lebenspunkte um phyrexianisches Mana zu bezahlen.
lblClickOnYourLifeTotalToPayLifeForBlackMana=Klicke auf deine Lebenspunkte um schwarzes Mana zu bezahlen.
lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Klicke auf deine Lebenspunkte um phyrexianisches oder schwarzes Mana zu bezahlen.

View File

@@ -548,6 +548,7 @@ lblPreconstructedDecks=Preconstructed Decks
lblQuestOpponentDecks=Quest Opponent Decks
lblRandomColorDecks=Random Color Decks
lblRandomStandardArchetypeDecks=Random Standard Archetype Decks
lblRandomPioneerArchetypeDecks=Random Pioneer Archetype Decks
lblRandomModernArchetypeDecks=Random Modern Archetype Decks
lblRandomLegacyArchetypeDecks=Random Legacy Archetype Decks
lblRandomVintageArchetypeDecks=Random Vintage Archetype Decks
@@ -628,7 +629,7 @@ titleUnlocked=%n unlocked!
lblStartADuel=Start a duel.
lblSelectAQuestDeck=Please select a Quest Deck.
lblInvalidDeck=Invalid Deck
lblInvalidDeckDesc=Your deck %n Please edit or choose a different deck.
lblInvalidDeckDesc=Your deck %n\nPlease edit or choose a different deck.
#VSubmenuQuestPrefs.java
lblQuestPreferences=Quest Preferences
lblRewardsError=Rewards Error
@@ -950,6 +951,12 @@ nlShowMatchBackground=Show match background image on battlefield, otherwise back
nlTheme=Sets the theme that determines how display components are skinned.
nlVibrateAfterLongPress=Enable quick vibration to signify a long press, such as for card zooming.
nlVibrateWhenLosingLife=Enable vibration when your player loses life or takes damage during a game.
lblEnableRoundBorder=Enable Round Border Mask
nlEnableRoundBorder=When enabled, the card corners are rounded (Preferably Card with Full Borders).
lblPreloadExtendedArtCards=Preload Extended Art Cards
nlPreloadExtendedArtCards=When enabled, Preloads Extended Art Cards to Cache on Startup.
lblShowFPSDisplay=Show FPS Display
nlShowFPSDisplay=When enabled, show the FPS Display (Experimental).
#MatchScreen.java
lblPlayers=Players
lblLog=Log
@@ -986,6 +993,7 @@ lblOathbreakers=Oathbreakers
lblLoadingFonts=Loading fonts...
lblLoadingCardTranslations=Loading card translations...
lblFinishingStartup=Finishing startup...
lblPreloadExtendedArt=Preload Extended Art...
#LobbyScreen.java
lblMore=More...
lblLoadingNewGame=Loading new game...
@@ -1140,6 +1148,28 @@ lblArrangeCardsToBePutOnTopOfYourLibrary=Arrange cards to be put on top of your
lblTopOfLibrary=Top of Library
lblSelectCardsToBePutIntoTheGraveyard=Select cards to be put into the graveyard
lblCardsToPutInTheGraveyard=Cards to put in the graveyard
lblDiscardUpToNCards=Discard up to %d card(s)
lblDiscardNCards=Discard %d card(s)
lblSelectNCardsToDiscardUnlessDiscarduType=Select %d card(s) to discard, unless you discard a %s.
lblCleanupPhase=Cleanup Phase
lblSelectCardsToDiscardHandDownMaximum=Select %d card(s) to discard to bring your hand down to the maximum of %max cards.
lblChooseMinCardToDiscard=Choose %d card(s) to discard
lblDiscarded=Discarded
lblChooseDamageOrderFor=Choose Damage Order for %s
lblDamagedFirst=Damaged First
lblChooseBlockerAfterWhichToPlaceAttackert=Choose blocker after which to place %s in damage order; cancel to place it first
lblPutCardOnTopOrBottomLibrary=Put %s on the top or bottom of your library?
lblChooseOrderCardsPutIntoLibrary=Choose order of cards to put into the library
lblClosestToTop=Closest to top
lblChooseOrderCardsPutOntoBattlefield=Choose order of cards to put onto the battlefield
lblPutFirst=Put first
lblChooseOrderCardsPutIntoGraveyard=Choose order of cards to put into the graveyard
lblClosestToBottom=Closest to bottom
lblChooseOrderCardsPutIntoPlanarDeck=Choose order of cards to put into the planar deck
lblChooseOrderCardsPutIntoSchemeDeck=Choose order of cards to put into the scheme deck
lblChooseOrderCopiesCast=Choose order of copies to cast
lblDelveHowManyCards=Delve how many cards?
lblExileWhichCard=Exile which card?
#AbstractGuiGame.java
lblConcedeCurrentGame=This will concede the current game and you will lose.\n\nConcede anyway?
lblConcedeTitle=Concede Game?
@@ -1171,4 +1201,41 @@ btnQuitMatch=Quit Match
lblItsADraw=It's a draw!
lblTeamWon=Team %s won!
lblWinnerWon=%s won!
lblGameLog=Game Log
lblGameLog=Game Log
#NewDraftScreen.java
lblLoadingNewDraft=Loading new draft...
#LoadDraftScreen.java
lblDoubleTapToEditDeck=Double-tap to edit deck (Long-press to view)
lblMode=Mode:
lblYouMustSelectExistingDeck=You must select an existing deck or build a deck from a new booster draft game.
lblWhichOpponentWouldYouLikeToFace=Which opponent would you like to face?
lblSingleMatch=Single Match
#NewGauntletScreen.java
lblGauntletText1=In Gauntlet mode, you select a deck and play against multiple opponents.
lblGauntletText2=Configure how many opponents you wish to face and what decks or types of decks they will play.
lblGauntletText3=Then, try to beat all AI opponents without losing a match.
lblSelectGauntletType=Select a Gauntlet Type
lblCustomGauntlet=Custom Gauntlet
lblGauntletContest=Gauntlet Contest
lblSelectYourDeck=Select Your Deck
lblSelectDeckForOpponent=Select Deck for Opponent
lblSelectGauntletContest=Select Gauntlet Contest
#PuzzleScreen.java
lblPuzzleText1=Puzzle Mode loads in a puzzle that you have to win in a predetermined time/way.
lblPuzzleText2=To begin, press the Start button below, then select a puzzle from a list.
lblPuzzleText3=Your objective will be displayed in a pop-up window when the puzzle starts and also specified on a special effect card which will be placed in your command zone.
lblChooseAPuzzle=Choose a puzzle
lblLoadingThePuzzle=Loading the puzzle...
#InputPassPriority.java
lblCastSpell=cast spell
lblPlayLand=play land
lblActivateAbility=activate ability
lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=You have mana floating in your mana pool that could be lost if you pass priority now.
lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=You will take mana burn damage equal to the amount of floating mana lost this way.
lblManaFloating=Mana Floating
#InputPayManaOfCostPayment.java
lblPayManaCost=Pay Mana Cost:
lblLifePaidForPhyrexianMana=(%d life paid for phyrexian mana)
lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Click on your life total to pay life for phyrexian mana.
lblClickOnYourLifeTotalToPayLifeForBlackMana=Click on your life total to pay life for black mana.
lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Click on your life total to pay life for phyrexian mana or black mana.

View File

@@ -548,6 +548,7 @@ lblPreconstructedDecks=Mazos Preconstruidos
lblQuestOpponentDecks=Mazos de los Oponentes de la Aventura
lblRandomColorDecks=Mazos Aleatorios por Color
lblRandomStandardArchetypeDecks=Mazos Standard por Arquetipo
lblRandomPioneerArchetypeDecks=Random Pioneer Archetype Decks
lblRandomModernArchetypeDecks=Mazos Modern por Arquetipo
lblRandomLegacyArchetypeDecks=Mazos Legacy por Arquetipo
lblRandomVintageArchetypeDecks=Mazos Vintage por Arquetipo
@@ -628,7 +629,7 @@ titleUnlocked=%n desbloqueado!
lblStartADuel=Comienza un duelo.
lblSelectAQuestDeck=Por favor, seleccione un mazo de aventura.
lblInvalidDeck=Mazo no válido
lblInvalidDeckDesc=Su mazo %n Por favor, edite o elija un mazo diferente.
lblInvalidDeckDesc=Su mazo %n\nPor favor, edite o elija un mazo diferente.
#VSubmenuQuestPrefs.java
lblQuestPreferences=Preferencias de la Aventura
lblRewardsError=Error de recompensas
@@ -950,6 +951,12 @@ nlShowMatchBackground=Muestra la imagen de fondo de la partida en el campo de ba
nlTheme=Establece el tema que determina el aspecto global del juego.
nlVibrateAfterLongPress=Habilita la vibración rápida cuando se realice una pulsación prolongada, como p.ej. al realizar zoom de la carta.
nlVibrateWhenLosingLife=Habilita la vibración cuando tu jugador pierde vida o sufre daños durante un juego.
lblEnableRoundBorder=Habilitar máscara de bordes redondeados
nlEnableRoundBorder=Cuando está habilitado, las esquinas de las cartas se redondean (Preferiblemente Cartas con bordes completos).
lblPreloadExtendedArtCards=Precargar Cartas de Arte Extendido
nlPreloadExtendedArtCards=Cuando está habilitado, carga previamente las cartas de arte ampliadas en la caché al iniciar el programa.
lblShowFPSDisplay=Mostrar FPS
nlShowFPSDisplay=Cuando está habilitado, muestra los FPS (Experimental).
#MatchScreen.java
lblPlayers=Jugadores
lblLog=Log
@@ -986,6 +993,7 @@ lblOathbreakers=Oathbreakers
lblLoadingFonts=Cargando fuentes...
lblLoadingCardTranslations=Cargando traducciones de cartas...
lblFinishingStartup=Finalizando el arranque...
lblPreloadExtendedArt=Precargando Arte Extendido...
#LobbyScreen.java
lblMore=Más...
lblLoadingNewGame=Cargando nueva partida...
@@ -1140,6 +1148,28 @@ lblArrangeCardsToBePutOnTopOfYourLibrary=Organizar las cartas para colocarlas en
lblTopOfLibrary=Parte Superior de la Biblioteca
lblSelectCardsToBePutIntoTheGraveyard=Selecciona las cartas para ponerlas en el Cementerio
lblCardsToPutInTheGraveyard=Cartas para poner en el Cementerio
lblDiscardUpToNCards=Descarta hasta %d carta(s)
lblDiscardNCards=Descarta %d carta(s)
lblSelectNCardsToDiscardUnlessDiscarduType=Selecciona %d carta(s) para descartar, a menos que descartes un %s.
lblCleanupPhase=Fase de Limpieza
lblSelectCardsToDiscardHandDownMaximum=Selecciona %d carta(s) a descartar para reducir tu mano al máximo de %max cartas.
lblChooseMinCardToDiscard=Elige %d carta(s) para descartar
lblDiscarded=Descartado
lblChooseDamageOrderFor=Selecciona el Orden de Daños para %s
lblDamagedFirst=Dañado Primero
lblChooseBlockerAfterWhichToPlaceAttackert=Elige un bloqueador después del cual colocar %s en el orden de daño; cancela para colocarlo primero.
lblPutCardOnTopOrBottomLibrary=¿Poner %s en la parte superior o inferior de tu biblioteca?
lblChooseOrderCardsPutIntoLibrary=Elige el orden de las cartas para poner en la biblioteca
lblClosestToTop=Más cerca de la parte superior
lblChooseOrderCardsPutOntoBattlefield=Elige el orden de las cartas que quieres poner en el campo de batalla
lblPutFirst=Poner en primer lugar
lblChooseOrderCardsPutIntoGraveyard=Elige el orden de las cartas para poner en el cementerio
lblClosestToBottom=Más cerca de la parte inferior
lblChooseOrderCardsPutIntoPlanarDeck=Elige el orden de las cartas que quieres poner en el mazo planar
lblChooseOrderCardsPutIntoSchemeDeck=Elige el orden de las cartas que quieres poner en el mazo scheme
lblChooseOrderCopiesCast=Elige el orden de las copias que se van a invocar
lblDelveHowManyCards=¿Excavar cuántas cartas?
lblExileWhichCard=¿Exiliar qué carta?
#AbstractGuiGame.java
lblConcedeCurrentGame=Esto concederá la partida actual y perderás.\n\n¿Conceder de todos modos?
lblConcedeTitle=¿Conceder Partida?
@@ -1171,4 +1201,41 @@ btnQuitMatch=Salir de la Partida
lblItsADraw=¡Es un empate!
lblTeamWon=¡El equipo %s ha ganado!
lblWinnerWon=¡%s ha ganado!
lblGameLog=Registro del Juego
lblGameLog=Registro del Juego
#NewDraftScreen.java
lblLoadingNewDraft=Cargando nuevo Draft...
#LoadDraftScreen.java
lblDoubleTapToEditDeck=Pulsa 2 veces para editar el mazo (Pulsación prologanda para ver)
lblMode=Modo:
lblYouMustSelectExistingDeck=Debes seleccionar un mazo existente o construir un mazo a partir de un nuevo juego de booster draft.
lblWhichOpponentWouldYouLikeToFace=¿A qué oponente te gustaría enfrentarte?
lblSingleMatch=Partida individual
#NewGauntletScreen.java
lblGauntletText1=En el modo Desafío, selecciona un mazo y juega contra varios oponentes.
lblGauntletText2=Configura a cuántos oponentes deseas enfrentarte y qué mazos o tipos de mazos jugarán.
lblGauntletText3=Luego, intenta derrotar a todos los oponentes de la IA sin perder una partida.
lblSelectGauntletType=Seleccione el Tipo de Desafío
lblCustomGauntlet=Desafío Personalizado
lblGauntletContest=Concurso de Desafío
lblSelectYourDeck=Seleccciona Tu Mazo
lblSelectDeckForOpponent=Seleccionar Mazo para el Oponente
lblSelectGauntletContest=Seleccionar Concurso de Desafío
#PuzzleScreen.java
lblPuzzleText1=En el Modo Puzzle se carga un rompecabezas que tienes que ganar en un tiempo/forma predeterminados.
lblPuzzleText2=Para comenzar, pulsa el botón Inicio y selecciona un puzzle de una lista.
lblPuzzleText3=Tu objetivo se mostrará en una ventana emergente cuando se inicie el puzzle y también se especificará en una carta de efectos especiales que se colocará en tu zona de comandos.
lblChooseAPuzzle=Elige un puzzle
lblLoadingThePuzzle=Cargando el puzzle...
#InputPassPriority.java
lblCastSpell=lanzar hechizo
lblPlayLand=jugar tierra
lblActivateAbility=activar abilidad
lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=Tienes maná flotando en tu pool de maná que podría perderse si pasas la prioridad ahora.
lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=Recibirás un daño por quemadura de maná igual a la cantidad de maná flotante perdido de esta manera.
lblManaFloating=Maná Flotante
#InputPayManaOfCostPayment.java
lblPayManaCost=Paga el coste de maná:
lblLifePaidForPhyrexianMana=(%d de vida pagado por el maná filaxiano)
lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Haga clic en el total de su vida para pagar la vida por el maná filaxiano.
lblClickOnYourLifeTotalToPayLifeForBlackMana=Haga clic en el total de su vida para pagar la vida de maná negro.
lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Haga clic en el total de su vida para pagar la vida por maná filoxiano o maná negro.

View File

@@ -1,21 +1,21 @@
language.name=Chinese (CN)
#SplashScreen.java
splash.loading.examining-cards=加载牌,检查文件夹
splash.loading.cards-folders=从文件夹加载牌
splash.loading.cards-archive=从存档中加载牌
splash.loading.examining-cards=加载牌,检查文件夹
splash.loading.cards-folders=从文件夹加载
splash.loading.cards-archive=从存档中加载
splash.loading.decks=加载套牌
splash.loading.processingimagesprites=处理精灵图
#FControl.java
lblOpeningMainWindow=打开主窗口中
lblCloseScreen=关闭屏幕
txCloseAction1=Forge现在支持选项卡导航可以轻松关闭和切换不同屏幕。因此不再需要使用右上角X按钮关闭当前屏幕并返回
txCloseAction2=选择右上角的X按钮选择接下来将要进行的作。此选项保留给未来使用,将不会再看到此消息,可以随时在“首选项”中更改此行为
titCloseAction=选择的关闭
txCloseAction1=Forge现在支持选项卡导航可以轻松关闭和切换不同屏幕。因此不再需要使用右上角X按钮关闭当前屏幕并返回
txCloseAction2=通过右上角的X按钮选择将要进行的作。此选项保留给未来使用,将不会再看到此消息,可以随时在“首选项”中更改此行为
titCloseAction=选择的关闭动
lblAreYouSureYouWishRestartForge=你确定要重启Forge吗
lblAreYouSureYouWishExitForge=你确定要退出Forge吗
lblOneOrMoreGamesActive=一个或多个游戏正处于活动状态
lblerrLoadingLayoutFile=无法读取的布局文件:%s。按OK然后删除。\n游戏将以默认布局进行。
lblLoadingQuest=加载时空竞逐中...
lblerrLoadingLayoutFile=无法读取的布局文件:%s。按OK然后删除。\n游戏将以默认布局进行。
lblLoadingQuest=加载冒险之旅...
#FScreen.java
lblHome=主页
lblWorkshop=作坊页面
@@ -30,13 +30,13 @@ lblDraftDeckEditor=轮抓套牌编辑器
lblSealedDeckEditor=现开套牌编辑器
lblTokenViewer=衍生物查看器
lblCloseViewer=关闭查看器
lblQuestDeckEditor=竞逐套牌编辑器
lblQuestTournamentDeckEditor=竞逐比赛套牌编辑器
lblSpellShop=轮替商店
lblQuestDeckEditor=冒险套牌编辑器
lblQuestTournamentDeckEditor=冒险比赛套牌编辑器
lblSpellShop=卡牌商店
lblLeaveShop=离开商店
lblLeaveDraft=离开轮抓
lblBazaar=珍宝集市
lblConcedeGame=让出这场游戏
lblConcedeGame=这场游戏认输
txerrFailedtodeletelayoutfile=删除布局文件失败。
#VSubmenuPreferences.java
Preferences=偏好
@@ -62,7 +62,7 @@ cbEnableAICheats=允许人工智能作弊
cbManaBurn=法术力灼烧
cbManaLostPrompt=提示法术力池将要清空
cbDevMode=开发人员模式
cbLoadCardsLazily=惰性加载牌脚本
cbLoadCardsLazily=惰性加载牌脚本
cbLoadHistoricFormats=加载史记赛制
cbWorkshopSyntax=作坊语法检查
cbEnforceDeckLegality=套牌一致性
@@ -74,7 +74,7 @@ cbCloneImgSource=复制使用原始的图片
cbScaleLarger=将图像缩放的更大
cbRenderBlackCardBorders=渲染黑卡边框
cbLargeCardViewers=使用大图查看器
cbSmallDeckViewer=使用小套牌查看器
cbSmallDeckViewer=使用小查看器
cbDisplayFoil=显示闪卡
cbRandomFoil=随机闪卡
cbRandomArtInPools=在生成的卡池中随机加入闪卡
@@ -102,7 +102,7 @@ cbpGameLogEntryType=游戏日志详细程度
cbpCloseAction=关闭动作
cbpDefaultFontSize=默认字体大小
cbpAiProfiles=人工智能强度
cbpDisplayCurrentCardColors=显示牌颜色详情
cbpDisplayCurrentCardColors=显示牌颜色详情
cbpAutoYieldMode=自动让过
cbpCounterDisplayType=计数器显示类型
cbpCounterDisplayLocation=计数器显示区域
@@ -141,13 +141,13 @@ nlSingletons=禁止在生成的套牌中非地牌重复出现
nlRemoveArtifacts=在生成的套牌中禁用神器牌
nlCardBased=构建具有更多协同效应的套牌(需要重启)
DeckEditorOptions=套牌编辑器选项
nlFilterLandsByColorId=当使用牌颜色筛选器时,过滤地可以更容易找到产数相关法术力的地
nlFilterLandsByColorId=当使用牌颜色筛选器时,过滤地可以更容易找到产数相关法术力的地
AdvancedSettings=高级设置
nlDevMode=启用在开发期间进行测试的功能菜单
nlWorkshopSyntax=在作坊中启用牌脚本检查。注意:该功能任在测试阶段。
nlWorkshopSyntax=在作坊中启用牌脚本检查。注意:该功能任在测试阶段。
nlGameLogEntryType=更改游戏中日志显示的信息量。排序为最少到最详细。
nlCloseAction=更改单击右上角X按钮时的行为
nlLoadCardsLazily=如果打开该选项Forge将在使用到牌脚本时才加载(警告:实验状态)。
nlCloseAction=更改单击右上角X按钮时的动作
nlLoadCardsLazily=如果打开该选项Forge将在使用到牌脚本时才加载(警告:实验状态)。
nlLoadHistoricFormats=如果打开Forge将加载史记赛制这个能会导致游戏载入时间变长。
GraphicOptions=图形选项
nlDefaultFontSize=UI中字体的默认大小。所有字体元素都相对于此缩放。需要重启
@@ -155,21 +155,21 @@ cbpMulliganRule = 调度规则
nlImageFetcher=允许从在线资源中实时获取缺失的图片
nlDisplayFoil=显示闪卡
nlRandomFoil=随机将牌设置为闪卡
nlScaleLarger=允许牌图片缩放为初始大小
nlScaleLarger=允许牌图片缩放为初始大小
nlRenderBlackCardBorders=为牌周围渲染黑色边框
nlLargeCardViewers=是所有牌看起来更大以便高分辨率图片看起来更舒适,不适合低分辨率设备使用
nlSmallDeckViewer=将套牌查看器设置为800X600而不是按屏幕大小等比缩放
nlRandomArtInPools=限制赛生成的卡池中带有闪卡。
nlUiForTouchScreen=增加一些UI元素以提高触屏体验需要重启
nlCompactPrompt=隐藏标题并在“提示”窗格中使用较小的字体使其更紧凑。
nlHideReminderText=在“牌详情“窗格中隐藏提醒文本
nlHideReminderText=在“牌详情“窗格中隐藏提醒文本
nlOpenPacksIndiv=打开肥包或者补充盒的时候一包一包开。
nlTokensInSeparateRow=生物与衍生物分不同的行显示。
nlStackCreatures=在战场上如同地、神器、结界一般堆叠一样的生物。
nlTimedTargOverlay=启用基于限制目标的覆盖优化以减少CPU使用率仅在旧设备上需要使用需要重启游戏
nlCounterDisplayType=选择指示物的样式。基于文本还是基于图片还是二者混合。
nlCounterDisplayLocation=确定牌上指示物的位置:靠近底部还是顶部
nlDisplayCurrentCardColors=在牌详情窗格中显示当前牌的颜色
nlCounterDisplayLocation=确定牌上指示物的位置:靠近底部还是顶部
nlDisplayCurrentCardColors=牌详情窗格中显示当前牌的颜色
SoundOptions=声音选项
nlEnableSounds=在游戏中启用声音效果
nlEnableMusic=在游戏中启用背景音乐
@@ -188,18 +188,18 @@ btnListImageData=统计牌和图片数据
lblListImageData=统计Forge实现且缺少的图片的牌
btnImportPictures=导入数据
btnHowToPlay=如何玩
btnDownloadPrices=下载牌价格
btnDownloadPrices=下载牌价格
btnLicensing=许可证详情
lblDownloadPics=下载缺省牌的图片
lblDownloadPicsHQ=下载缺省牌的高清图片
lblDownloadSetPics=下载每张牌的图片(每张牌出现一次)
lblDownloadQuestImages=下载冒险之旅里使用的衍生物与图标
lblDownloadAchievementImages=下载成就图片,让你的奖杯更引人注目。
lblDownloadPrices=下载牌商店最新的价格表
lblDownloadPrices=下载牌商店最新的价格表
lblYourVersionOfJavaIsTooOld=你的Java版本太旧无法开始下载内容
lblPleaseUpdateToTheLatestVersionOfJava=请更新到最新版本的JRE
lblYoureRunning=你在运行
lblYouNeedAtLeastJavaVersion=的JRE版本至少需要为1.8.0_101。
lblYouNeedAtLeastJavaVersion=的JRE版本至少需要为1.8.0_101。
lblImportPictures=从本地目录导入数据
lblReportBug=什么东西坏了?
lblHowToPlay=游戏规则。
@@ -230,7 +230,7 @@ lblGameSettings=游戏设置
#VLobby.java
lblHeaderConstructedMode=游戏模式:构筑
lblGetNewRandomName=获取一个随机名称
lbltypeofName=想要生成什么类型的名称?
lbltypeofName=想要生成什么类型的名称?
lblconfirmName=你想使用名称%s还是想重试
lblUseThisName=使用这个名称
lblTryAgain=再试一次
@@ -299,7 +299,7 @@ lblAlphaStrike=先攻
lblEndTurn=结束回合
lblTargetingArcs=瞄准弧
lblOff=关闭
lblCardMouseOver=悬停
lblCardMouseOver=牌悬停
lblAlwaysOn=总是打开
lblAutoYields=自动让过
lblDeckList=套牌列表
@@ -357,7 +357,7 @@ lblDraftText3=然后对抗一个或多个人工智能对手
lblNewBoosterDraftGame=新的补充包轮抓
lblDraftDecks=轮抓套牌
#CSubmenuDraft.java
lblNoDeckSelected=没有为人类选择套牌。\n可能要建立一个新的套牌)
lblNoDeckSelected=没有为人类选择套牌。\n可能要建立一个新的套牌)
lblNoDeck=没有套牌
lblChooseDraftFormat=选择轮抓模式
#VSubmenuSealed.java
@@ -365,7 +365,7 @@ lblSealedDeck=现开
lblSealedDecks=现开套牌
lblHeaderSealed=游戏模式:现开
lblSealedText1=构建或选择一个套牌
lblSealedText2=在现开模式中,可以从补充包里最多10个构建一套牌
lblSealedText2=在现开模式中,可以从补充包里最多10个构建一套牌
lblSealedText3=从你得到的牌中组一套牌。人工智能也会这样做
lblSealedText4=然后对抗一个或多个人工智能对手
btnBuildNewSealedDeck=构建新的现开套牌
@@ -392,7 +392,7 @@ lblGauntlet=决斗
lblTournament=锦标赛
lblQuest=冒险
lblQuestDraft=冒险轮抓
lblPlanarConquest=时空竞逐征服
lblPlanarConquest=时空征服
lblPuzzle=谜题
lblPuzzleDesc=从给定的游戏状态解谜
lblDeckManager=套牌管理
@@ -425,7 +425,7 @@ lblNextChallengeNotYet=没有确定下次胜利后的挑战
btnUnlockSets=解锁系列
btnTravel=时空旅行
btnBazaar=珍宝集市
btnSpellShop=商店
btnSpellShop=牌商店
cbSummonPlant=召唤植物
cbLaunchZeppelin=启动飞艇
#VSubmenuQuest.java
@@ -448,7 +448,7 @@ lblCustomdeck=自定义套牌
lblDefineCustomFormat=定义自定义赛制
lblSelectFormat=选择赛制
lblStartWithAllCards=从所选系列的所有牌开始
lblAllowDuplicateCards=允许重复的牌
lblAllowDuplicateCards=允许重复的
lblStartingPoolDistribution=初始牌池分配
lblChooseDistribution=选择分配
lblPrizedCards=奖励卡
@@ -505,9 +505,9 @@ lblColors=颜色
lblnoSettings=没有可用于此选择的设置
lblDistribution=分配
lblHoverforDescription=将鼠标悬停在每个选项上以获得更详细的说明
lblradBalanced=“均衡”将在每种选定的颜色中提供数量均衡的牌
lblradRandom=“随机”将随机分配牌和颜色。
lblradSurpriseMe=随机挑选颜色并提供数量均衡的随机牌
lblradBalanced=“均衡”将在每种选定的颜色中提供数量均衡的牌。
lblradRandom=“随机”将随机分配牌和颜色。
lblradSurpriseMe=随机挑选颜色并提供数量均衡的随机牌。
lblradBoosters=忽略所有颜色设置,从指定数量的补充包中生成牌池
lblcbxArtifacts=选择后无论选择的颜色如何,神器都包涵在牌池中,这模拟了旧牌池的行为。
#VSubmenuChallenges.java
@@ -548,6 +548,7 @@ lblPreconstructedDecks=预组套牌
lblQuestOpponentDecks=冒险之旅套牌
lblRandomColorDecks=随机颜色套牌
lblRandomStandardArchetypeDecks=随机标准原型套牌
lblRandomPioneerArchetypeDecks=随机先驱原型套牌
lblRandomModernArchetypeDecks=随机摩登原型套牌
lblRandomLegacyArchetypeDecks=随机薪传原型套牌
lblRandomVintageArchetypeDecks=随机特选原型套牌
@@ -620,7 +621,7 @@ lblBuildAndSelectaDeck=构建,然后在“冒险套牌”子菜单中选择一
lblCurrentDeck=你现在的套牌是%n
PleaseCreateAQuestBefore=请在%n之前创建套牌。
lblNoQuest=没有探索
lblVisitTheSpellShop=参观牌张商店
lblVisitTheSpellShop=进入卡牌商店
lblVisitTheBazaar=参观珍宝集市
lblUnlockEditions=解锁新的时空
lblUnlocked=你已经成功解锁%n
@@ -628,7 +629,7 @@ titleUnlocked=%n解锁
lblStartADuel=开始决斗!
lblSelectAQuestDeck=请选择一个冒险套牌。
lblInvalidDeck=错误的套牌
lblInvalidDeckDesc=的套牌%n请编辑或者选择其他套牌
lblInvalidDeckDesc=的套牌%n请编辑或者选择其他套牌
#VSubmenuQuestPrefs.java
lblQuestPreferences=冒险偏好
lblRewardsError=奖励错误
@@ -672,7 +673,7 @@ lblStartingCredits=初始积分
lblWinsforNewChallenge=新挑战所需的胜利
lblStartingSnowLands=初始雪境地
lblColorBias=颜色偏差1-100%
ttColorBias=初始卡池中您选择的颜色百分比
ttColorBias=初始卡池中的颜色百分比
lblPenaltyforLoss=失败补偿
lblMoreDuelChoices=更多决斗选择
lblCommon=
@@ -695,11 +696,11 @@ lblCardSalePercentageCap=出售牌的系数上限
lblCardSalePriceCap=出售牌的价格上限
lblWinstoUncapSalePrice=胜利解锁价格系数
lblPlaysetSize=玩家收藏大小
ttPlaysetSize=在售卖牌时要保留的牌数量
ttPlaysetSize=在售卖牌时要保留的牌数量
lblPlaysetSizeBasicLand=玩家收藏大小:基本地
ttPlaysetSizeBasicLand=在售卖牌时要保留的基本地数量
ttPlaysetSizeBasicLand=在售卖牌时要保留的基本地数量
lblPlaysetSizeAnyNumber=玩家收藏大小:任意数量
ttPlaysetSizeAnyNumber=售卖牌时不保留牌张
ttPlaysetSizeAnyNumber=售卖牌时不保留
lblItemLevelRestriction=物品等级限制
lblFoilfilterAlwaysOn=闪卡过滤器始终开启
lblRatingsfilterAlwaysOn=评级过滤器始终开启。
@@ -767,7 +768,7 @@ lblRemove4ofcard=移除4张牌
ttRemove4ofcard=最多可以将4张所选牌从当前套牌移除
lblAddBasicLands=添加基本地
ttAddBasicLands=添加基本地到套牌
lblCardCatalog=目录
lblCardCatalog=牌目录
lblJumptoprevioustable=跳转到上一个表格
lblJumptopnexttable=跳转到下一个表格
lblJumptotextfilter=跳转到文本筛选器
@@ -883,7 +884,7 @@ lblQty=数量
lblQuantity=数量
lblSide=备牌
lblSideboard=备牌
lblNew=
lblNew=获得
lblOwned=拥有
lblPower=力量
ttPower=力量
@@ -904,8 +905,8 @@ lblAutomaticBugReports=自动报告BUG
lblBattlefieldTextureFiltering=战场纹理过滤
lblCompactListItems=紧凑的项目列表
lblCompactTabs=紧凑标签
lblCardOverlays=叠加层
lblDisableCardEffect=禁用牌“效果”图
lblCardOverlays=牌叠加层
lblDisableCardEffect=禁用牌“效果”图
lblDynamicBackgroundPlanechase=动态时空背景
lblGameplayOptions=游戏选项
lblGeneralSettings=常规设置
@@ -915,14 +916,14 @@ lblLater=以后
lblMinimizeScreenLock=锁屏时最小化
lblOrderGraveyard=坟场顺序
lblRestartForge=重启Forge
lblRestartForgeDescription=必须重启Forge才能使此更改生效
lblRestartForgeDescription=必须重启Forge才能使此更改生效
lblRotateZoomPlanesPhenomena=旋转缩放时空/异象图
lblRotateZoomSplit=旋转缩放连体牌
lblShowAbilityIconsOverlays=显示异能图标
lblShowCardIDOverlays=显示牌ID叠加层
lblShowCardManaCostOverlays=显示牌法术力费用叠加层
lblShowCardNameOverlays=显示牌名称叠加层
lblShowCardOverlays=显示牌叠加层
lblShowCardIDOverlays=显示牌ID叠加层
lblShowCardManaCostOverlays=显示牌法术力费用叠加层
lblShowCardNameOverlays=显示牌名称叠加层
lblShowCardOverlays=显示牌叠加层
lblShowCardPTOverlays=显示攻击/防御叠加层
lblShowMatchBackground=显示比赛背景
lblVibrateAfterLongPress=长按后震动
@@ -930,26 +931,32 @@ lblVibrateWhenLosingLife=失去生命时震动
lblVibrationOptions=振动选项
nlAutomaticBugReports=在没有提示的情况下自动向开发人员报告错误
nlBattlefieldTextureFiltering=在战场上过滤闪卡特效,使其在大屏幕上不像素化(需要重启,可能会降低性能)。
nlCompactListItems=默认情况下,在所有视图列表中只显示牌和套牌的单行文本。
nlCompactListItems=默认情况下,在所有视图列表中只显示牌和套牌的单行文本。
nlCompactTabs=在标签页屏幕顶部显示较小的标签(例如此屏幕)。
nlDisableCardEffect=禁用“效果”卡的缩放图片。
nlDynamicBackgroundPlanechase=使用当前时空图片作为背景时空图片必须位于cache/pics/planechase文件夹中
nlHotSeatMode=当用两个人类玩家开始游戏的时候,用单个提示控制两个玩家。
nlLandscapeMode=使用横向(水平)而不是纵向(垂直)。
nlMinimizeScreenLock=锁定屏幕时最小化Forge锁屏以后出现图形故障使用
nlOrderGraveyard=确定何时让玩家确定同时进入坟场的牌的顺序(绝不/总是/只对有关牌)。
nlOrderGraveyard=确定何时让玩家确定同时进入坟场的牌的顺序(绝不/总是/只对有关牌)。
nlRotateZoomPlanesPhenomena=旋转缩放时空或异象图片。
nlRotateZoomSplit=旋转缩放连体牌图片。
nlShowAbilityIconsOverlays=在牌上显示异能图标,否则他们被隐藏。
nlShowCardIDOverlays=显示牌的ID叠加层否则他们被隐藏。
nlShowCardManaCostOverlays=显示牌的法术力费用叠加层,否则他们被隐藏。
nlShowCardNameOverlays=显示牌的名称费用叠加层,否则他们被隐藏。
nlShowCardOverlays=显示牌名称,法术力费用,力量/防御和ID叠加层否则他们被隐藏。
nlShowAbilityIconsOverlays=牌上显示异能图标,否则他们被隐藏。
nlShowCardIDOverlays=显示牌的ID叠加层否则他们被隐藏。
nlShowCardManaCostOverlays=显示牌的法术力费用叠加层,否则他们被隐藏。
nlShowCardNameOverlays=显示牌的名称费用叠加层,否则他们被隐藏。
nlShowCardOverlays=显示牌名称,法术力费用,力量/防御和ID叠加层否则他们被隐藏。
nlShowCardPTOverlays=显示力量/防御/忠诚叠加层,否则他们被隐藏。
nlShowMatchBackground=在战场显示背景图片,否则显示背景纹理。
nlTheme=设置显示的组件使用的外观主题。
nlVibrateAfterLongPress=启用长按触发震动,例如长按缩放牌图片。
nlVibrateAfterLongPress=启用长按触发震动,例如长按缩放牌图片。
nlVibrateWhenLosingLife=启用当玩家在游戏中失去生命或收到伤害时震动。
lblEnableRoundBorder=启用圆角边框掩码
nlEnableRoundBorder=启用后,卡牌边框会变成圆角(带有完整边框的卡牌图片效果最好)。
lblPreloadExtendedArtCards=预加载拉伸卡图
nlPreloadExtendedArtCards=启用后,拉伸卡图将在启动时加载到缓存。
lblShowFPSDisplay=显示当前的FPS值
nlShowFPSDisplay=启用后将在画面左上角显示当前Forge的FPS实验性特性
#MatchScreen.java
lblPlayers=玩家列表
lblLog=日志
@@ -973,7 +980,7 @@ lblChangePreferredArt=改变首选卡图
lblSelectPreferredArt=选择首选的卡图版本
lblTo=
lblAvatar=头像
lblCards=
lblCards=
lblPlanes=时空
lblSchemes=阴谋
lblToMainDeck=到主牌
@@ -984,8 +991,9 @@ lblCommanders=指挥官
lblOathbreakers=破誓者
#Forge.java
lblLoadingFonts=加载字体中
lblLoadingCardTranslations=加载牌翻译中
lblLoadingCardTranslations=加载牌翻译中
lblFinishingStartup=完成启动
lblPreloadExtendedArt=预加载拉伸卡图
#LobbyScreen.java
lblMore=更多
lblLoadingNewGame=载入新游戏中
@@ -1038,11 +1046,11 @@ lblNoPlayerPriorityNoDeckListViewed=现在玩家没有优先权,因此无法
#FilesPage.java
lblFiles=文件
lblStorageLocations=储存位置
lblCardPicsLocation=图片位置
lblCardPicsLocation=牌图片位置
lblDecksLocation=套牌位置
lblDataLocation=数据位置(例如 设置和探索模式)
lblImageCacheLocation=图片缓存位置
lblRestartForgeMoveFilesNewLocation=必须重启Forge才能使此更改生效。执行此操作之前请确保将所有必要的文件移动到新的位置。
lblRestartForgeMoveFilesNewLocation=必须重启Forge才能使此更改生效。执行此操作之前请确保将所有必要的文件移动到新的位置。
lblRestartRequired=需要重启
lblSelect=选择%s
#AddBasicLandsDialog.java
@@ -1050,17 +1058,17 @@ lblLandSet=地牌的系列
lblAddBasicLandsAutoSuggest=添加基本地到%s\n双击自动添加
lblAssortedArt=各种画
lblCardArt=卡图%d
lblNonLandCount=%d张非地
lblOldLandCount=%d张地
lblNewLandCount=添加%d张地
lblNonLandCount=%d张非地
lblOldLandCount=%d张地
lblNewLandCount=添加%d张地
lblNewTotalCount=%d张牌
#FDeckImportDialog.java
lblImportLatestVersionCard=导入牌的最新版本
lblImportLatestVersionCard=导入牌的最新版本
lblUseOnlySetsReleasedBefore=只用之前上市系列的版本:
lblUseOnlyCoreAndExpansionSets=只使用核心系列和拓展系列
lblFollowingCardsCannotBeImported=由于拼写错误系列限制或forge尚未实现以下牌没有被导入:
lblFollowingCardsCannotBeImported=由于拼写错误系列限制或forge尚未实现以下牌没有被导入:
lblImportRemainingCards=导入剩余的卡?
lblNoKnownCardsOnClipboard=在剪切板找不到已知的牌。\n\n将套牌列表复制到剪切板然后重新打开此对话框。
lblNoKnownCardsOnClipboard=在剪切板找不到已知的牌。\n\n将套牌列表复制到剪切板然后重新打开此对话框。
#FDeckViewer.java
lblDeckListCopiedClipboard=套牌列表'%s'已经复制到剪切板
#FSideboardDialog.java
@@ -1092,11 +1100,11 @@ lblWouldYouLiketoPlayorDraw=你想先手还是后手?
lblWhoWouldYouLiketoStartthisGame=你想谁先开始游戏?(单击头像)
lblPlay=先手
lblDraw=后手
lblTooFewCardsMainDeck=主牌中牌数过少(最少为%s请重新修改套牌。
lblTooManyCardsSideboard=备牌中牌数过多(最多为%s请重新修改套牌。
lblTooFewCardsMainDeck=主牌中牌数过少(最少为%s请重新修改套牌。
lblTooManyCardsSideboard=备牌中牌数过多(最多为%s请重新修改套牌。
lblAssignCombatDamageWerentBlocked=是否要像没有被阻挡一样分配战斗伤害?
lblChosenCards=选择牌
lblAttacker=
lblAttacker=攻者
lblTriggeredby=触发者
lblChooseWhichCardstoReveal=选择要展示的牌
lblChooseCardsActivateOpeningHandandOrder=选择要展示的手牌和顺序
@@ -1110,16 +1118,16 @@ lblPleaseDefineanActionSequenceFirst=请先定义一个动作序列。
lblRememberActionSequence=记住动作序列
lblYouMustHavePrioritytoUseThisFeature=你必须有使用此功能的优先权。
lblNameTheCard=命名牌
lblWhichPlayerShouldRoll=那个玩家掷骰子?
lblWhichPlayerShouldRoll=哪位玩家掷骰子?
lblChooseResult=选择结果
lblChosenCardNotPermanentorCantExistIndependentlyontheBattleground=选择的牌不是永久物,也不能在战场单独存在。\n如果你想释放费永久物咒语或者你想释放永久物咒语并将之放于堆叠上请按"Cast Spell/Play Land"按钮。
lblError=错误
lblWinGame=赢得这局游戏
lblSetLifetoWhat=设定生命值为多少?
lblSetLifeforWhichPlayer=设定哪牌手的生命值?
lblSetLifeforWhichPlayer=设定哪牌手的生命值?
lblChoosePermanentstoTap=选择要横置的永久物
lblChoosePermanentstoUntap=选择要重置的永久物
lblWhichTypeofCounter=种指示物?
lblWhichTypeofCounter=种指示物?
lblHowManyCounters=多少指示物?
lblRemoveCountersFromWhichCard=从哪张牌移除指示物?
lblAddCountersToWhichCard=添加指示物到哪张牌?
@@ -1127,23 +1135,45 @@ lblChooseaCard=选择一张牌
lblNoPlayerPriorityDeckCantBeTutoredFrom=目前没有玩家拥有优先权,因此无法从其套牌导师。
lblNoPlayerPriorityGameStateCannotBeSetup=目前没有玩家拥有优先权,因此无法设置游戏状态。
lblErrorLoadingBattleSetupFile=加载战场设置文件出错!
lblSelectCardstoAddtoYourDeck=选择要添加到套牌的牌
lblSelectCardstoAddtoYourDeck=选择要添加到套牌的牌。
lblAddTheseToMyDeck=添加这些到我的套牌
lblChooseaPile=选择一堆
lblSelectOrderForSimultaneousAbilities=选择同时触发的异能的结算顺序
lblReorderSimultaneousAbilities=重新对同时触发异能的结算顺序进行排序
lblResolveFirst=先结算
lblMoveCardstoToporBbottomofLibrary=将牌移动到牌库顶或底
lblSelectCardsToBeOutOnTheBottomOfYourLibrary=选择要放到牌库底的牌
lblCardsToPutOnTheBottom=放到底部的牌
lblArrangeCardsToBePutOnTopOfYourLibrary=为放于牌库顶的牌排序
lblMoveCardstoToporBbottomofLibrary=牌移动到牌库顶或底
lblSelectCardsToBeOutOnTheBottomOfYourLibrary=选择要放到牌库底的
lblCardsToPutOnTheBottom=放到底部的
lblArrangeCardsToBePutOnTopOfYourLibrary=为放于牌库顶的牌排序
lblTopOfLibrary=牌库顶
lblSelectCardsToBePutIntoTheGraveyard=选择要放于坟场的牌
lblCardsToPutInTheGraveyard=放于坟场的牌
lblSelectCardsToBePutIntoTheGraveyard=选择要放于坟场的
lblCardsToPutInTheGraveyard=放于坟场的
lblDiscardUpToNCards=最多弃%d张牌
lblDiscardNCards=弃%d张牌
lblSelectNCardsToDiscardUnlessDiscarduType=选择要丢弃的%d张牌除非你丢弃%s。
lblCleanupPhase=清除步骤
lblSelectCardsToDiscardHandDownMaximum=选择要丢弃的%d张牌以使你的手牌数量减少到%max张。
lblChooseMinCardToDiscard=选择%d张牌弃掉
lblDiscarded=弃牌
lblChooseDamageOrderFor=选择%s造成伤害的顺序
lblDamagedFirst=先造成伤害
lblChooseBlockerAfterWhichToPlaceAttackert=选择%s后造成伤害的阻挡者; cancel to place it first
lblPutCardOnTopOrBottomLibrary=将%s放到牌库顶还是底
lblChooseOrderCardsPutIntoLibrary=选择要放入牌库中的牌的顺序
lblClosestToTop=最接近顶部
lblChooseOrderCardsPutOntoBattlefield=选择要放入战场中的牌的顺序
lblPutFirst=放在最前
lblChooseOrderCardsPutIntoGraveyard=选择要放入坟场中的牌的顺序
lblClosestToBottom=最接近底部
lblChooseOrderCardsPutIntoPlanarDeck=选择要放入时空竞逐套牌中的牌的顺序
lblChooseOrderCardsPutIntoSchemeDeck=选择要放入魔王套牌中的牌的顺序
lblChooseOrderCopiesCast=选择要复制品的释放顺序。
lblDelveHowManyCards=掘穴多少张牌?
lblExileWhichCard=放逐哪张牌?
#AbstractGuiGame.java
lblConcedeCurrentGame=将让出这局游戏,而你将输掉。\n\n一定要让出吗?
lblConcedeTitle=让出这局游戏?
lblConcede=让出
lblConcedeCurrentGame=局游戏认输。\n\n确认吗?
lblConcedeTitle=这局游戏认输?
lblConcede=认输
lblCloseGameSpectator=这将关闭游戏,你将无法继续观看它。\n\n一定要关闭吗
lblCloseGame=关闭游戏?
lblWaitingForOpponent=等待对手中
@@ -1153,16 +1183,16 @@ lblEnterNumberBetweenMinAndMax=输入介于%min到%max之间的数字
lblEnterNumberGreaterThanOrEqualsToMin=输入一个大于等于%min的数字
lblEnterNumberLessThanOrEqualsToMax=输入一个小于等于%max的数字
#PlayerOutcome.java
lblWonBecauseAllOpponentsHaveLost=由于所有对手都输了所以你赢了
lblWonDueToEffectOf=受'%s'的影响而获胜了
lblConceded=已经让出
lblWonBecauseAllOpponentsHaveLost=所有对手都输了而赢得胜利
lblWonDueToEffectOf=受'%s'的影响赢得胜利
lblConceded=已经认输
lblLostTryingToDrawCardsFromEmptyLibrary=尝试从为空的牌库中抓牌而输
lblLostBecauseLifeTotalReachedZero=生命值为0而输
lblLostBecauseOfObtainingTenPoisonCounters=中毒指示物达到10而输
lblLostBecauseAnOpponentHasWonBySpell=因对手用咒语'%s'获胜而输
lblLostDueToEffectOfSpell=受咒语'%s'的影响而输
lblLostDueToAccumulationOf21DamageFromGenerals=受到大于21点主将伤害而输
lblAcceptedThatTheGameIsADraw=已经接受此局游戏平局
lblAcceptedThatTheGameIsADraw=此局游戏平局
lblLostForUnknownReasonBug=由于未知错误而输(这是一个错误)
#ViewWinLose.java
btnNextGame=下一局游戏
@@ -1171,4 +1201,41 @@ btnQuitMatch=退出比赛
lblItsADraw=平局!
lblTeamWon=队伍%s胜利了
lblWinnerWon=%s胜利了
lblGameLog=游戏日志
lblGameLog=游戏日志
#NewDraftScreen.java
lblLoadingNewDraft=加载新的轮抽中
#LoadDraftScreen.java
lblDoubleTapToEditDeck=双击以编辑套牌(长按可以查看)
lblMode=模式:
lblYouMustSelectExistingDeck=你必须选择一个已有的卡组或者从新的补充包轮抽游戏中构筑一个卡组。
lblWhichOpponentWouldYouLikeToFace=你想面对哪个对手?
lblSingleMatch=单场比赛
#NewGauntletScreen.java
lblGauntletText1=在决斗模式下,你可以选择一套牌与多个对手进行对战。
lblGauntletText2=设置你想面对的对手数量以及他们所使用的套牌类型或者套牌。
lblGauntletText3=然后,尝试击败所有人工智能对手而不输掉一场比赛。
lblSelectGauntletType=选择一个决斗类型
lblCustomGauntlet=自定义决斗
lblGauntletContest=决斗竞赛
lblSelectYourDeck=选择你的套牌
lblSelectDeckForOpponent=选择对手的套牌
lblSelectGauntletContest=选择决斗竞赛
#PuzzleScreen.java
lblPuzzleText1=解谜模式会加载一个谜题,你必须在预定的时间/方式中获胜。
lblPuzzleText2=首先,按下面的开始按钮,然后从列表中选择一个谜题。
lblPuzzleText3=当解谜开始的时候,该谜题的要求将会显示在弹窗中,并且还会在指挥官区域放置一张特殊效应卡指示这个谜题的要求。
lblChooseAPuzzle=选择一个谜题
lblLoadingThePuzzle=加载新的谜题中
#InputPassPriority.java
lblCastSpell=释放咒语
lblPlayLand=使用地
lblActivateAbility=启动式异能
lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=你的法术力池中还有剩余的法术力,如果现在让过优先权,这些法术力可能会丢失。
lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=你将受到等同于通过这种方式失去的剩余法术力数量的法术力灼烧伤害。
lblManaFloating=剩余法术力
#InputPayManaOfCostPayment.java
lblPayManaCost=支付法术力:
lblLifePaidForPhyrexianMana=(以%d生命支付了非瑞克西亚法术力
lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=单击你的总生命,以生命值支付非瑞克西亚法术力。
lblClickOnYourLifeTotalToPayLifeForBlackMana=单击你的总生命,以生命值支付黑色法术力。
lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=单击你的总生命,以生命值支付黑色或非瑞克西亚法术力。

View File

@@ -33,4 +33,5 @@ Genetic Algorithm AI Decks | https://downloads.cardforge.org/decks/geneticalgori
Current Standard Metagame | https://downloads.cardforge.org/decks/currentstandardmetagame.zip
Current Modern Metagame | https://downloads.cardforge.org/decks/currentmodernmetagame.zip
Current Legacy Metagame | https://downloads.cardforge.org/decks/currentlegacymetagame.zip
Current Pauper Metagame | https://downloads.cardforge.org/decks/currentpaupermetagame.zip
Current Pauper Metagame | https://downloads.cardforge.org/decks/currentpaupermetagame.zip
Current Pioneer Decks | https://downloads.cardforge.org/decks/currentpioneerdecks.zip

View File

@@ -0,0 +1,16 @@
[metadata]
Name:Possibility Storm - Throne of Eldraine #02
URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/133.-ELD2-1.jpg
Goal:Win
Turns:1
Difficulty:Uncommon
Description:Win this turn. Your Sentinel's Mark is attached to your Tajic, Legion's Edge, and your opponent's Sentinel Mark is attached to their Harmonious Archon. Neither was cast this turn. Remember that your solution must satisfy all possible blocking scenarios!
[state]
humanlife=20
ailife=8
turn=1
activeplayer=human
activephase=MAIN1
humanhand=Silverflame Squire;Arrester's Zeal;Burn Bright;Torch Courier
humanbattlefield=Ferocity of the Wilds;Torbran, Thane of Red Fell;Tajic, Legion's Edge|Id:1;Sentinel's Mark|AttachedTo:1;Sacred Foundry|NoETBTrigs;Mountain;Mountain;Plains
aibattlefield=Harmonious Archon|Id:2;Sentinel's Mark|AttachedTo:2;t:Human,P:1,T:1,Cost:no cost,Color:W,Types:Creature-Human,Keywords:,Image:w_1_1_human_eld;t:Human,P:1,T:1,Cost:no cost,Color:W,Types:Creature-Human,Keywords:,Image:w_1_1_human_eld

View File

@@ -0,0 +1,18 @@
[metadata]
Name:Possibility Storm - Throne of Eldraine #03
URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/134.-ELD3.jpg
Goal:Win
Turns:1
Difficulty:Mythic
Description:Win this turn. Your opponent owns a Beanstalk Giant in exile. You have a Cryptic Caves in your graveyard.
[state]
humanlife=1
ailife=7
turn=1
activeplayer=human
activephase=MAIN1
humanhand=Giant Opportunity;Overgrown Tomb;Shepherd of the Flock;Overcome;Outmuscle
humangraveyard=Cryptic Caves
humanbattlefield=Wandermare;Kaya, Orzhov Usurper|Counters:LOYALTY=5;Vengeful Warchief;Trollbred Guardian;Jiang Yanggu, Wildcrafter|Counters:LOYALTY=1;Overgrown Tomb|NoETBTrigs;Overgrown Tomb|NoETBTrigs;Godless Shrine|NoETBTrigs;Godless Shrine|NoETBTrigs
aibattlefield=End-Raze Forerunners;Wardscale Crocodile
aiexile=Beanstalk Giant

View File

@@ -0,0 +1,20 @@
[metadata]
Name:Possibility Storm - Throne of Eldraine #04
URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/135.-ELD4-1.jpg
Goal:Win
Turns:1
Difficulty:Uncommon
Description:Win this turn. You have not played a land yet this turn. You own an Animating Faerie "on an adventure" in exile. Note that Bring to Life turned Enchanted Carriage into a 0/0 with four +1/+1 counters.
[state]
humanlife=20
ailife=10
humanlandsplayed=0
turn=1
activeplayer=human
activephase=MAIN1
humanhand=Witch's Oven;Island;Taste of Death;Undercity Uprising
humanbattlefield=Wicked Wolf;Oko, Thief of Crowns|Counters:LOYALTY=1;Nullhide Ferox;Enchanted Carriage|Id:1;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs
humanexile=Animating Faerie|OnAdventure
aibattlefield=Loyal Pegasus;Gate Colossus;Dawning Angel
humanprecast=Enchanted Carriage:TrigToken;Bring To Life:1->1
removesummoningsickness=true

View File

@@ -1,5 +1,6 @@
Name:Main world
Name:Random Standard
Name:Random Pioneer
Name:Random Modern
Name:Random Commander
Name:Amonkhet|Dir:Amonkhet|Sets:AKH, HOU

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 KiB

After

Width:  |  Height:  |  Size: 687 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 KiB

View File

@@ -13,6 +13,8 @@ public class FThreads {
* @param mustBeEDT &emsp; boolean: true = exception if not EDT, false = exception if EDT
*/
public static void assertExecutedByEdt(final boolean mustBeEDT) {
if (GuiBase.isNetworkplay())
return; //don't check for networkplay
if (isGuiThread() != mustBeEDT) {
final StackTraceElement[] trace = Thread.currentThread().getStackTrace();
final String methodName = trace[2].getClassName() + "." + trace[2].getMethodName();

View File

@@ -4,6 +4,8 @@ import forge.interfaces.IGuiBase;
public class GuiBase {
private static IGuiBase guiInterface;
private static boolean propertyConfig = true;
private static boolean networkplay = false;
public static IGuiBase getInterface() {
return guiInterface;
@@ -11,4 +13,16 @@ public class GuiBase {
public static void setInterface(IGuiBase i0) {
guiInterface = i0;
}
public static void enablePropertyConfig(boolean value) {
propertyConfig = value;
}
public static boolean isNetworkplay() {
return networkplay;
}
public static void setNetworkplay(boolean value) {
networkplay = value;
}
public static boolean hasPropertyConfig() {
return propertyConfig;
}
}

View File

@@ -14,6 +14,7 @@ import forge.item.SealedProduct;
import forge.model.FModel;
import forge.properties.ForgeConstants;
import forge.properties.ForgePreferences;
import forge.util.CardTranslation;
import forge.util.Lang;
import org.apache.commons.lang3.StringUtils;

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