mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Merge remote-tracking branch 'remotes/core/master' into newBranch
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,7 +463,7 @@ public class FSkinFont {
|
||||
+ "驽驾驿骁骂骄骆骇验骏骐骑骗骚骤骨骰骷骸骼髅髓高鬃鬓鬣鬼魁魂魄"
|
||||
+ "魅魇魈魏魔鰴鱼鲁鲜鲤鲨鲮鲸鲽鳃鳄鳍鳐鳗鳝鳞鸟鸠鸡鸢鸣鸦鸽鹅鹉"
|
||||
+ "鹊鹏鹗鹞鹤鹦鹫鹭鹰鹿麋麒麟麦麻黄黎黏黑默黛黜點黠黯鼎鼓鼠鼬鼹"
|
||||
+ "鼻齐齑齿龇龙龟!(),/:;?~";
|
||||
+ "鼻齐齑齿龇龙龟伸!(),/:;?~";
|
||||
|
||||
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
|
||||
final FreeTypeFontParameter parameter = new FreeTypeFontParameter();
|
||||
|
||||
@@ -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,38 +54,34 @@ 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,
|
||||
@@ -99,7 +98,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 +117,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 +131,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 +144,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 +169,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; }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user