diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index a783f1f9674..91a14362601 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.math.Matrix4; @@ -37,8 +38,75 @@ public class Graphics { private int failedClipCount; private float alphaComposite = 1; private int transformCount = 0; + private String sVertex = "uniform mat4 u_projTrans;\n" + + "\n" + + "attribute vec4 a_position;\n" + + "attribute vec2 a_texCoord0;\n" + + "attribute vec4 a_color;\n" + + "\n" + + "varying vec4 v_color;\n" + + "varying vec2 v_texCoord;\n" + + "\n" + + "uniform vec2 u_viewportInverse;\n" + + "\n" + + "void main() {\n" + + " gl_Position = u_projTrans * a_position;\n" + + " v_texCoord = a_texCoord0;\n" + + " v_color = a_color;\n" + + "}"; + private String sFragment = "#ifdef GL_ES\n" + + "precision mediump float;\n" + + "precision mediump int;\n" + + "#endif\n" + + "\n" + + "uniform sampler2D u_texture;\n" + + "\n" + + "// The inverse of the viewport dimensions along X and Y\n" + + "uniform vec2 u_viewportInverse;\n" + + "\n" + + "// Color of the outline\n" + + "uniform vec3 u_color;\n" + + "\n" + + "// Thickness of the outline\n" + + "uniform float u_offset;\n" + + "\n" + + "// Step to check for neighbors\n" + + "uniform float u_step;\n" + + "\n" + + "varying vec4 v_color;\n" + + "varying vec2 v_texCoord;\n" + + "\n" + + "#define ALPHA_VALUE_BORDER 0.5\n" + + "\n" + + "void main() {\n" + + " vec2 T = v_texCoord.xy;\n" + + "\n" + + " float alpha = 0.0;\n" + + " bool allin = true;\n" + + " for( float ix = -u_offset; ix < u_offset; ix += u_step )\n" + + " {\n" + + " for( float iy = -u_offset; iy < u_offset; iy += u_step )\n" + + " {\n" + + " float newAlpha = texture2D(u_texture, T + vec2(ix, iy) * u_viewportInverse).a;\n" + + " allin = allin && newAlpha > ALPHA_VALUE_BORDER;\n" + + " if (newAlpha > ALPHA_VALUE_BORDER && newAlpha >= alpha)\n" + + " {\n" + + " alpha = newAlpha;\n" + + " }\n" + + " }\n" + + " }\n" + + " if (allin)\n" + + " {\n" + + " alpha = 0.0;\n" + + " }\n" + + "\n" + + " gl_FragColor = vec4(u_color,alpha);\n" + + "}"; + + private final ShaderProgram shaderOutline = new ShaderProgram(sVertex, sFragment); public Graphics() { + ShaderProgram.pedantic = false; } public void begin(float regionWidth0, float regionHeight0) { @@ -60,6 +128,7 @@ public class Graphics { public void dispose() { batch.dispose(); shapeRenderer.dispose(); + shaderOutline.dispose(); } public SpriteBatch getBatch() { @@ -604,6 +673,56 @@ public class Graphics { public void drawImage(TextureRegion image, float x, float y, float w, float h) { batch.draw(image, adjustX(x), adjustY(y, h), w, h); } + public void drawImage(TextureRegion image, TextureRegion glowImageReference, float x, float y, float w, float h, Color glowColor, boolean selected) { + //1st image is the image on top of the shader, 2nd image is for the outline reference for the shader glow... + // if the 1st image don't have transparency in the middle (only on the sides, top and bottom, use the 1st image as outline reference... + if (!selected) { + batch.draw(image, adjustX(x), adjustY(y, h), w, h); + } else { + batch.end(); + shaderOutline.begin(); + shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h)); + shaderOutline.setUniformf("u_offset", 3f); + shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f)); + shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b)); + shaderOutline.end(); + batch.setShader(shaderOutline); + batch.begin(); + //glow + batch.draw(glowImageReference, adjustX(x), adjustY(y, h), w, h); + batch.end(); + batch.setShader(null); + batch.begin(); + //img + batch.draw(image, adjustX(x), adjustY(y, h), w, h); + } + } + public void drawDeckBox(FImage cardArt, float scale, TextureRegion image, TextureRegion glowImageReference, float x, float y, float w, float h, Color glowColor, boolean selected) { + float yBox = y-(h*0.25f); + if (!selected) { + cardArt.draw(this,x+((w-w*scale)/2), y+((h-h*scale)/3f), w*scale, h*scale/1.85f); + batch.draw(image, adjustX(x), adjustY(yBox, h), w, h); + } else { + batch.end(); + shaderOutline.begin(); + shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h)); + shaderOutline.setUniformf("u_offset", 3f); + shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f)); + shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b)); + shaderOutline.end(); + batch.setShader(shaderOutline); + batch.begin(); + //glow + batch.draw(glowImageReference, adjustX(x), adjustY(yBox, h), w, h); + batch.end(); + batch.setShader(null); + batch.begin(); + //cardart + cardArt.draw(this,x+((w-w*scale)/2), y+((h-h*scale)/3f), w*scale, h*scale/1.85f); + //deckbox + batch.draw(image, adjustX(x), adjustY(yBox, h), w, h); + } + } public void drawRepeatingImage(Texture image, float x, float y, float w, float h) { if (startClip(x, y, w, h)) { //only render if clip successful, otherwise it will escape bounds diff --git a/forge-gui-mobile/src/forge/assets/FSkin.java b/forge-gui-mobile/src/forge/assets/FSkin.java index 9f716df533a..1f9eacd9571 100644 --- a/forge-gui-mobile/src/forge/assets/FSkin.java +++ b/forge-gui-mobile/src/forge/assets/FSkin.java @@ -30,7 +30,8 @@ public class FSkin { private static final Map images = new HashMap<>(512); private static final Map avatars = new HashMap<>(150); private static final Map sleeves = new HashMap<>(64); - private static final Map borders = new HashMap<>(2); + private static final Map borders = new HashMap<>(); + private static final Map deckbox = new HashMap<>(); private static Array allSkins; private static FileHandle preferredDir; @@ -196,6 +197,7 @@ public class FSkin { final FileHandle f10 = getDefaultSkinFile(ForgeConstants.SPRITE_BORDER_FILE); final FileHandle f11 = getSkinFile(ForgeConstants.SPRITE_BUTTONS_FILE); final FileHandle f12 = getSkinFile(ForgeConstants.SPRITE_START_FILE); + final FileHandle f13 = getDefaultSkinFile(ForgeConstants.SPRITE_DECKBOX_FILE); try { textures.put(f1.path(), new Texture(f1)); @@ -331,10 +333,20 @@ public class FSkin { FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500)); } } - + //borders 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)); + //deckboxes + Texture deckboxes = new Texture(f13, textureFilter); + if (textureFilter) + deckboxes.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + //gold bg + FSkin.deckbox.put(0, new TextureRegion(deckboxes, 2, 2, 488, 680)); + //deck box for card art + FSkin.deckbox.put(1, new TextureRegion(deckboxes, 492, 2, 488, 680)); + //generic deck box + FSkin.deckbox.put(2, new TextureRegion(deckboxes, 982, 2, 488, 680)); preferredIcons.dispose(); pxDefaultAvatars.dispose(); @@ -430,5 +442,9 @@ public class FSkin { return borders; } + public static Map getDeckbox() { + return deckbox; + } + public static boolean isLoaded() { return loaded; } } diff --git a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java index 86942c1c3d9..96f355dd730 100644 --- a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java +++ b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java @@ -190,11 +190,17 @@ public class CardFaceSymbols { } public static void drawColorSet(Graphics g, ColorSet colorSet, float x, float y, final float imageSize) { + drawColorSet(g, colorSet, x, y, imageSize, false); + } + public static void drawColorSet(Graphics g, ColorSet colorSet, float x, float y, final float imageSize, boolean vertical) { final float dx = imageSize; for (final ManaCostShard s : colorSet.getOrderedShards()) { drawSymbol(s.getImageKey(), g, x, y, imageSize, imageSize); - x += dx; + if (!vertical) + x += dx; + else + y += dx; } } diff --git a/forge-gui-mobile/src/forge/deck/FDeckChooser.java b/forge-gui-mobile/src/forge/deck/FDeckChooser.java index 36378199774..ced6c89aa6d 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckChooser.java +++ b/forge-gui-mobile/src/forge/deck/FDeckChooser.java @@ -63,6 +63,7 @@ public class FDeckChooser extends FScreen { private Callback callback; private NetDeckCategory netDeckCategory; private boolean refreshingDeckType; + private boolean firstactivation = true; private final DeckManager lstDecks; private final FButton btnNewDeck = new FButton(Localizer.getInstance().getMessage("lblNewDeck")); @@ -226,6 +227,11 @@ public class FDeckChooser extends FScreen { @Override public void onActivate() { + //somehow a loaded deck state from startup don't refresh accordingly for imageview so refresh it on first activation + if(firstactivation) { + needRefreshOnActivate = true; + firstactivation = false; + } if (needRefreshOnActivate) { needRefreshOnActivate = false; refreshDecksList(selectedDeckType, true, null); diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java index d061dbc78e1..064425773bc 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java @@ -1,17 +1,22 @@ package forge.itemmanager.views; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import forge.Forge; import forge.Forge.KeyInputAdapter; import forge.Graphics; import forge.assets.FImage; +import forge.assets.FImageComplex; +import forge.assets.FSkin; import forge.assets.FSkinColor; import forge.assets.FSkinImage; import forge.assets.FSkinColor.Colors; import forge.assets.FSkinFont; import forge.assets.ImageCache; +import forge.card.CardFaceSymbols; import forge.card.CardRenderer; import forge.card.CardRenderer.CardStackPosition; import forge.card.CardZoom; +import forge.card.ColorSet; import forge.deck.ArchetypeDeckGenerator; import forge.deck.CardThemedDeckGenerator; import forge.deck.CommanderDeckGenerator; @@ -36,6 +41,7 @@ import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FLabel; import forge.toolbox.FScrollPane; import forge.util.Localizer; +import forge.util.TextUtil; import forge.util.Utils; import java.util.ArrayList; @@ -869,7 +875,7 @@ public class ImageView extends ItemView { ItemInfo item = getItemAtPoint(x + getLeft(), y + getTop()); if (item != null) { if(item.getKey() instanceof CardThemedDeckGenerator || item.getKey() instanceof CommanderDeckGenerator - || item.getKey() instanceof ArchetypeDeckGenerator){ + || item.getKey() instanceof ArchetypeDeckGenerator || item.getKey() instanceof DeckProxy){ FDeckViewer.show(((DeckProxy)item.getKey()).getDeck()); return true; } @@ -922,6 +928,7 @@ public class ImageView extends ItemView { private int index; private CardStackPosition pos; private boolean selected; + private final float IMAGE_SIZE = CardRenderer.MANA_SYMBOL_SIZE; private ItemInfo(T item0, Group group0) { item = item0; @@ -954,30 +961,89 @@ public class ImageView extends ItemView { final float y = getTop() - group.getTop() - getScrollValue(); final float w = getWidth(); final float h = getHeight(); - - if (selected) { //if round border is enabled, the select highlight is also rounded.. - if (Forge.enableUIMask) { - //fillroundrect has rough/aliased corner - g.fillRoundRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, - w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE, (h - w) / 10); - //drawroundrect has GL_SMOOTH to `smoothen/faux` the aliased corner - g.drawRoundRect(1f, Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, - w + 1.5f * SEL_BORDER_SIZE, h + 1.5f * SEL_BORDER_SIZE, (h - w) / 10); + Texture dpImg = null; + boolean deckSelectMode = false; + if (item instanceof DeckProxy) { + dpImg = ImageCache.getImage(item); + deckSelectMode = true; + } + if (selected) { + if (!deckSelectMode) { + //if round border is enabled, the select highlight is also rounded.. + if (Forge.enableUIMask) { + //fillroundrect has rough/aliased corner + g.fillRoundRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE, (h - w) / 10); + //drawroundrect has GL_SMOOTH to `smoothen/faux` the aliased corner + g.drawRoundRect(1f, Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 1.5f * SEL_BORDER_SIZE, h + 1.5f * SEL_BORDER_SIZE, (h - w) / 10); + } + else //default rectangle highlight + g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); } - else //default rectangle highlight - g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, - w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); } if (item instanceof PaperCard) { - CardRenderer.drawCard(g, (PaperCard)item, x, y, w, h, pos); - } - else { + CardRenderer.drawCard(g, (PaperCard) item, x, y, w, h, pos); + } else if (deckSelectMode) { + DeckProxy dp = ((DeckProxy) item); + ColorSet deckColor = dp.getColor(); + float scale = 0.75f; + + if (dpImg != null) {//generated decks have missing info... + if (Forge.enableUIMask){ + //commander bg + g.drawImage(FSkin.getDeckbox().get(0), FSkin.getDeckbox().get(0), x, y, w, h, Color.GREEN, selected); + TextureRegion tr = ImageCache.croppedBorderImage(dpImg); + g.drawImage(tr, x+(w-w*scale)/2, y+(h-h*scale)/1.5f, w*scale, h*scale); + } else { + if (selected) + g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); + g.drawImage(dpImg, x, y, w, h); + } + //fake labelname shadow + g.drawText(item.getName(), GROUP_HEADER_FONT, Color.BLACK, (x + PADDING)-1f, (y + PADDING*2)+1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false); + //labelname + g.drawText(item.getName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING*2, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false); + } else { + if (!dp.isGeneratedDeck()){ + FImageComplex cardArt = CardRenderer.getCardArt(dp.getHighestCMCCard().getImageKey(false), false, false, false); + //draw the deckbox + if (cardArt != null){ + g.drawDeckBox(cardArt, scale, FSkin.getDeckbox().get(1), FSkin.getDeckbox().get(2), x, y, w, h, Color.GREEN, selected); + } + } else { + //generic box + g.drawImage(FSkin.getDeckbox().get(2), FSkin.getDeckbox().get(2), x, y-(h*0.25f), w, h, Color.GREEN, selected); + } + if (deckColor != null) { + //deck color identity + float symbolSize = IMAGE_SIZE; + if (Forge.isLandscapeMode()) { + if (columnCount == 4) + symbolSize = IMAGE_SIZE * 1.5f; + else if (columnCount == 3) + symbolSize = IMAGE_SIZE * 2f; + else if (columnCount == 2) + symbolSize = IMAGE_SIZE * 3f; + else if (columnCount == 1) + symbolSize = IMAGE_SIZE * 4f; + } else { + if (columnCount > 2) + symbolSize = IMAGE_SIZE * (0.5f); + } + //vertical mana icons + CardFaceSymbols.drawColorSet(g, deckColor, x +(w-symbolSize), y+(h/8), symbolSize, true); + } + String deckname = TextUtil.fastReplace(item.getName(),"] #", "]\n#"); + //deckname fakeshadow + g.drawText(deckname, GROUP_HEADER_FONT, Color.BLACK, (x + PADDING)-1f, (y + (h/10) + PADDING)+1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, true); + //deck name + g.drawText(deckname, GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + (h/10) + PADDING, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, true); + } + } else { Texture img = ImageCache.getImage(item); if (img != null) { g.drawImage(img, x, y, w, h); - } - else { + } else { g.fillRect(Color.BLACK, x, y, w, h); g.drawText(item.getName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false); } diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java index 239baa355d3..92953a47b3d 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java @@ -101,17 +101,22 @@ public class ConquestRewardDialog extends FScrollPane { float startX = x; int cardCount = cardRevealers.size(); - cardRevealers.get(0).setBounds(x, y, cardWidth, cardHeight); - for (int i = 1; i < cardCount; i++) { - if (i % columnCount == 0) { - x = startX; - y += cardHeight + PADDING; + try { + cardRevealers.get(0).setBounds(x, y, cardWidth, cardHeight); + for (int i = 1; i < cardCount; i++) { + if (i % columnCount == 0) { + x = startX; + y += cardHeight + PADDING; + } + else { + x += cardWidth + PADDING; + } + cardRevealers.get(i).setBounds(x, y, cardWidth, cardHeight); } - else { - x += cardWidth + PADDING; - } - cardRevealers.get(i).setBounds(x, y, cardWidth, cardHeight); + } catch (Exception ex) { + System.err.println(ex.getMessage()); } + return new ScrollBounds(visibleWidth, y + cardHeight + PADDING); } diff --git a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java index 96e19487634..cef977a37fb 100644 --- a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java +++ b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java @@ -13,10 +13,13 @@ import forge.assets.FSkinProp; import forge.assets.IHasSkinProp; import forge.assets.TextRenderer; import forge.assets.FSkinColor.Colors; +import forge.card.CardFaceSymbols; import forge.card.CardRenderer; import forge.card.CardZoom; import forge.card.CardRenderer.CardStackPosition; import forge.card.CardZoom.ActivateHandler; +import forge.card.mana.ManaCost; +import forge.card.mana.ManaCostParser; import forge.game.card.CardView; import forge.game.card.IHasCardView; import forge.game.player.PlayerView; @@ -29,8 +32,11 @@ import forge.itemmanager.filters.ItemFilter; import forge.screens.match.MatchController; import forge.screens.match.views.VAvatar; import forge.screens.match.views.VStack; +import forge.util.TextUtil; import forge.util.Utils; +import static forge.card.CardRenderer.MANA_SYMBOL_SIZE; + public class FChoiceList extends FList implements ActivateHandler { public static final FSkinColor ITEM_COLOR = FSkinColor.get(Colors.CLR_ZEBRA); public static final FSkinColor ALT_ITEM_COLOR = ITEM_COLOR.getContrastColor(-20); @@ -337,7 +343,17 @@ public class FChoiceList extends FList implements ActivateHandler { @Override public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) { - g.drawText(getChoiceText(value), font, foreColor, x, y, w, h, allowDefaultItemWrap(), Align.left, true); + //update manacost text to draw symbols instead + if (value.toString().contains(" {")){ + String[] values = value.toString().split(" "); + String cost = TextUtil.fastReplace(values[1],"}{", " "); + cost = TextUtil.fastReplace(TextUtil.fastReplace(cost,"{", ""),"}", ""); + ManaCost manaCost = new ManaCost(new ManaCostParser(cost)); + CardFaceSymbols.drawManaCost(g, manaCost, x + font.getBounds(values[0]+" ").width, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE); + g.drawText(values[0], font, foreColor, x, y, w, h, allowDefaultItemWrap(), Align.left, true); + } else { + g.drawText(getChoiceText(value), font, foreColor, x, y, w, h, allowDefaultItemWrap(), Align.left, true); + } } } protected class NumberRenderer extends DefaultItemRenderer { diff --git a/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt b/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt index 9ed13fe961e..4d9fd8a3918 100755 --- a/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt +++ b/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt @@ -12,4 +12,5 @@ SVar:X:Count$xPaid SVar:Y:Count$RememberedSize SVar:XLands:Number$0 DeckHas:Ability$Sacrifice +AI:RemoveDeck:All Oracle:Sacrifice X lands. For each land sacrificed this way, draw a card. You may play X additional lands this turn. Lands you control enter the battlefield tapped this turn. diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 5ae207c3d69..a2e1662921d 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -494,6 +494,7 @@ lblCreateaDeck=Erzeuge ein Deck. #CSubmenuQuestPrefs.java lblEnteraNumber=Nummer eingeben lblSavefailed=Speichern fehlgeschlagen +lblEnteraDecimal=Eine Zahl eingeben #DialogChooseFormats.java cbWantReprints=Erlaube passende Drucke aus anderen Sets lblChooseFormats=Wähle Format @@ -734,6 +735,8 @@ lblWinsperDraftRotation=Siege pro Draft notwendig ttWinsperDraftRotation=Wenn ein Draft nicht soweit fertig gespielt wird, wird er entfernt oder ersetzt. lblRotationType=Austauschtyp ttRotationType=Bei 0 verschwinden alte Drafts, bei 1 wird er durch einen neuen ersetzt. +lblWildOpponentMultiplier=Wild-Multiplikator +lblWildOpponentNumber=Anzahl der Wild-Gegner #StatTypeFilter.java lblclicktotoogle=Klicke zum Umschalten des Filters, Rechtsklick für Einzelanzeige von: #SItemManagerUtil.java @@ -2587,7 +2590,5 @@ lblEnterMessageToSend=Nachricht zum Senden eingeben lblDetectedInvalidHostAddress=Ungültige Host-Adresse ({0}) wurde festgestellt. #Player.java lblChooseACompanion=Wähle einen Gefährten -lblWildOpponentMultiplier=Wild-Multiplikator -lblEnteraDecimal=Eine Zahl eingeben -lblWildOpponentNumber=Anzahl der Wild-Gegner +#QuestPreferences.java lblWildOpponentNumberError=Anzahl der Wild-Gegner kann nur 0 bis 3 sein diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 458070f8a55..5c9b42477b9 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -494,6 +494,7 @@ lblCreateaDeck=Create a Deck. #CSubmenuQuestPrefs.java lblEnteraNumber=Enter a number lblSavefailed=Save failed +lblEnteraDecimal=Enter a decimal #DialogChooseFormats.java cbWantReprints=Allow compatible reprints from other sets lblChooseFormats=Choose formats @@ -734,6 +735,8 @@ lblWinsperDraftRotation=Wins per Draft Rotation ttWinsperDraftRotation=If a Draft is not played for this many match wins, it will be removed or replaced. lblRotationType=Rotation Type ttRotationType=If set to 0, old drafts disappear, if set to 1, they are replaced with another one using different sets. +lblWildOpponentNumber=Number of Wild Opponents +lblWildOpponentMultiplier=Wild Multiplier #StatTypeFilter.java lblclicktotoogle=click to toggle the filter, right-click to show only #SItemManagerUtil.java @@ -2587,7 +2590,5 @@ lblEnterMessageToSend=Enter message to send lblDetectedInvalidHostAddress=Invalid host address ({0}) was detected. #Player.java lblChooseACompanion=Choose a companion -lblWildOpponentMultiplier=Wild Multiplier -lblEnteraDecimal=Enter a decimal -lblWildOpponentNumber=Number of Wild Opponents +#QuestPreferences.java lblWildOpponentNumberError=Wild Opponents can only be 0 to 3 diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 40e1e85db28..e83dd200203 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -494,6 +494,7 @@ lblCreateaDeck=Crear un Mazo. #CSubmenuQuestPrefs.java lblEnteraNumber=Ingrese un numero lblSavefailed=Error al guardar +lblEnteraDecimal=Enter a decimal #DialogChooseFormats.java cbWantReprints=Permitir reimpresiones compatibles de otras ediciones. lblChooseFormats=Elije Formatos @@ -734,6 +735,8 @@ lblWinsperDraftRotation=Victorias Rotación de Draft ttWinsperDraftRotation=Si no se juega un Draft para esta cantidad de victorias, se eliminará o reemplazará. lblRotationType=Tipo de Rotación ttRotationType=Si se establece en 0, los anteriores Draft desaparecen, si se establece en 1, se reemplazan por otros que utilizan sets diferentes. +lblWildOpponentNumber=Number of Wild Opponents +lblWildOpponentMultiplier=Wild Multiplier #StatTypeFilter.java lblclicktotoogle=haga clic para alternar el filtro, haga clic con el botón derecho para mostrar solo #SItemManagerUtil.java @@ -2587,3 +2590,5 @@ lblEnterMessageToSend=Ingrese el mensaje para enviar lblDetectedInvalidHostAddress=Se detectó una dirección de host no válida ({0}). #Player.java lblChooseACompanion=Elige un compañero +#QuestPreferences.java +lblWildOpponentNumberError=Wild Opponents can only be 0 to 3 diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index f4d2e2f1a89..96c7839a639 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -494,6 +494,7 @@ lblCreateaDeck=Crea un mazzo. #CSubmenuQuestPrefs.java lblEnteraNumber=Inserisci un numero lblSavefailed=Salvataggio fallito +lblEnteraDecimal=Enter a decimal #DialogChooseFormats.java cbWantReprints=Consenti ristampe compatibili da altri set lblChooseFormats=Scegli i formati @@ -734,6 +735,8 @@ lblWinsperDraftRotation=Vittorie per Draft Rotation ttWinsperDraftRotation=Se una Draft non viene giocata per questo numero di vittorie, verrà rimossa o sostituita. lblRotationType=Tipo di rotazione ttRotationType=Se impostato su 0, le vecchie bozze scompaiono, se impostate su 1, vengono sostituite con un''altra utilizzando set diversi. +lblWildOpponentNumber=Number of Wild Opponents +lblWildOpponentMultiplier=Wild Multiplier #StatTypeFilter.java lblclicktotoogle=fai clic per attivare o disattivare il filtro, fai clic con il pulsante destro del mouse per mostrare solo #SItemManagerUtil.java @@ -2586,4 +2589,6 @@ lblEnterMessageToSend=Enter message to send #OnlineLobbyScreen.java lblDetectedInvalidHostAddress=Invalid host address ({0}) was detected. #Player.java -lblChooseACompanion=Choose a companion \ No newline at end of file +lblChooseACompanion=Choose a companion +#QuestPreferences.java +lblWildOpponentNumberError=Wild Opponents can only be 0 to 3 diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 9f3f3203536..e4da49ae03f 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -494,6 +494,7 @@ lblCreateaDeck=创建一个套牌 #CSubmenuQuestPrefs.java lblEnteraNumber=输入一个数 lblSavefailed=保存错误 +lblEnteraDecimal=输入一个十进制小数 #DialogChooseFormats.java cbWantReprints=允许来自其他系列的重印牌 lblChooseFormats=选择赛制 @@ -734,6 +735,8 @@ lblWinsperDraftRotation=每次轮抓胜利轮替 ttWinsperDraftRotation=如果轮抓没有赢这么多场,那么它将被删除或者替换。 lblRotationType=轮替类型 ttRotationType=如果设置为0,旧系列消失,如果设置为1,则用不同系列替换。 +lblWildOpponentNumber=野外对手数量 +lblWildOpponentMultiplier=野外对手倍数 #StatTypeFilter.java lblclicktotoogle=单击以切换筛选器,右键单机以仅显示 #SItemManagerUtil.java @@ -2586,4 +2589,6 @@ lblEnterMessageToSend=输入要发送的信息 #OnlineLobbyScreen.java lblDetectedInvalidHostAddress=检测到无效的主机地址({0})。 #Player.java -lblChooseACompanion=选择一个行侣 \ No newline at end of file +lblChooseACompanion=选择一个行侣 +#QuestPreferences.java +lblWildOpponentNumberError=野外对手数只能在0-3之间 diff --git a/forge-gui/res/skins/darkforge/sprite_avatars.png b/forge-gui/res/skins/darkforge/sprite_avatars.png new file mode 100644 index 00000000000..12dbcbb61ed Binary files /dev/null and b/forge-gui/res/skins/darkforge/sprite_avatars.png differ diff --git a/forge-gui/res/skins/default/sprite_deckbox.png b/forge-gui/res/skins/default/sprite_deckbox.png new file mode 100644 index 00000000000..104d2018f0e Binary files /dev/null and b/forge-gui/res/skins/default/sprite_deckbox.png differ diff --git a/forge-gui/src/main/java/forge/deck/DeckProxy.java b/forge-gui/src/main/java/forge/deck/DeckProxy.java index 01e46db5ecf..85941f113f3 100644 --- a/forge-gui/src/main/java/forge/deck/DeckProxy.java +++ b/forge-gui/src/main/java/forge/deck/DeckProxy.java @@ -1,11 +1,15 @@ package forge.deck; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.Map.Entry; +import forge.card.CardSplitType; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Function; @@ -260,6 +264,29 @@ public class DeckProxy implements InventoryItem { return highestRarity; } + public PaperCard getHighestCMCCard() { + PaperCard key = null; + Map keyCMC = new HashMap<>(64); + + for (final Entry pc : getDeck().getAllCardsInASinglePool()) { + if (pc.getKey().getRules().getManaCost() != null) { + if (pc.getKey().getRules().getSplitType() != CardSplitType.Split) + keyCMC.put(pc.getKey(),pc.getKey().getRules().getManaCost().getCMC()); + } + } + + if (!keyCMC.isEmpty()) { + int max = Collections.max(keyCMC.values()); + //get any max cmc + for (Entry entry : keyCMC.entrySet()) { + if (entry.getValue()==max) { + return entry.getKey(); + } + } + } + return key; + } + public Set getFormats() { if (formats == null) { formats = FModel.getFormats().getAllFormatsOfDeck(getDeck()); diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java index bf1de97acb9..7834cdb58cf 100644 --- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java +++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java @@ -100,6 +100,7 @@ public final class ForgeConstants { public static final String SPRITE_ABILITY_FILE = "sprite_ability.png"; public static final String SPRITE_BORDER_FILE = "sprite_border.png"; public static final String SPRITE_BUTTONS_FILE = "sprite_buttons.png"; + public static final String SPRITE_DECKBOX_FILE = "sprite_deckbox.png"; public static final String SPRITE_START_FILE = "sprite_start.png"; public static final String SPRITE_MANAICONS_FILE = "sprite_manaicons.png"; public static final String SPRITE_AVATARS_FILE = "sprite_avatars.png"; diff --git a/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java b/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java index 633d4d602ee..22fe331d71a 100644 --- a/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java +++ b/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java @@ -18,16 +18,15 @@ import org.apache.commons.lang3.StringUtils; import forge.ImageKeys; import forge.deck.Deck; +import forge.deck.DeckProxy; import forge.deck.io.DeckSerializer; import forge.deck.io.DeckStorage; -import forge.model.FModel; import forge.quest.QuestEvent; import forge.quest.QuestEventDifficulty; import forge.quest.QuestEventDuel; import forge.util.FileSection; import forge.util.FileUtil; import forge.util.TextUtil; -import forge.util.storage.IStorage; import forge.util.storage.StorageReaderFolder; public class MainWorldDuelReader extends StorageReaderFolder { @@ -77,10 +76,11 @@ public class MainWorldDuelReader extends StorageReaderFolder { } // then I add wild decks in constructed directory - IStorage constructedDecks = FModel.getDecks().getConstructed(); - Iterator it = constructedDecks.iterator(); + Iterable constructedDecks = DeckProxy.getAllConstructedDecks(); + Iterator it = constructedDecks.iterator(); + while(it.hasNext()) { - Deck currDeck = (Deck) it.next(); + Deck currDeck = it.next().getDeck(); final QuestEventDuel newDeck = read(currDeck); String newKey = keySelector.apply(newDeck); if (result.containsKey(newKey)) {