diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index c8ba4c84cf5..92fdcd5a75e 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -264,12 +264,14 @@ public abstract class GameState { } if (c.hasMergedCard()) { + String suffix = c.getTopMergedCard().hasPaperFoil() ? "+" : ""; // we have to go by the current top card name here - newText.append(c.getTopMergedCard().getPaperCard().getName()).append("|Set:") + newText.append(c.getTopMergedCard().getPaperCard().getName()).append(suffix).append("|Set:") .append(c.getTopMergedCard().getPaperCard().getEdition()).append("|Art:") .append(c.getTopMergedCard().getPaperCard().getArtIndex()); } else { - newText.append(c.getPaperCard().getName()).append("|Set:").append(c.getPaperCard().getEdition()) + String suffix = c.hasPaperFoil() ? "+" : ""; + newText.append(c.getPaperCard().getName()).append(suffix).append("|Set:").append(c.getPaperCard().getEdition()) .append("|Art:").append(c.getPaperCard().getArtIndex()); } } @@ -326,8 +328,9 @@ public abstract class GameState { } else if (c.getCurrentStateName().equals(CardStateName.Meld)) { newText.append("|Meld"); if (c.getMeldedWith() != null) { + String suffix = c.getMeldedWith().hasPaperFoil() ? "+" : ""; newText.append(":"); - newText.append(c.getMeldedWith().getName()); + newText.append(c.getMeldedWith().getName()).append(suffix); } } else if (c.getCurrentStateName().equals(CardStateName.Modal)) { newText.append("|Modal"); diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 73cb4c124c9..6c676e98f73 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -410,8 +410,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr view.updateSickness(this); view.updateClassLevel(this); view.updateDraftAction(this); - if (paperCard != null) + if (paperCard != null) { setMarkedColors(paperCard.getMarkedColors()); + setPaperFoil(paperCard.isFoil()); + } } public int getHiddenId() { @@ -2246,6 +2248,14 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr public boolean hasChosenColor(String s) { return chosenColors != null && chosenColors.contains(s); } + + public final boolean hasPaperFoil() { + return view.hasPaperFoil(); + } + public final void setPaperFoil(final boolean v) { + view.updatePaperFoil(v); + } + public final ColorSet getMarkedColors() { if (markedColor == null) { return ColorSet.getNullColor(); diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index 5bf402b30f8..cdb0f16d5cf 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -429,6 +429,12 @@ public class CardView extends GameEntityView { void updateChosenColors(Card c) { set(TrackableProperty.ChosenColors, c.getChosenColors()); } + public boolean hasPaperFoil() { + return get(TrackableProperty.PaperFoil); + } + void updatePaperFoil(boolean v) { + set(TrackableProperty.PaperFoil, v); + } public ColorSet getMarkedColors() { return get(TrackableProperty.MarkedColors); } @@ -1520,8 +1526,8 @@ public class CardView extends GameEntityView { public boolean hasPrintedPT() { return get(TrackableProperty.HasPrintedPT); } - void updateHasPrintedPT(boolean val) { - set(TrackableProperty.HasPrintedPT, val); + void updateHasPrintedPT(boolean v) { + set(TrackableProperty.HasPrintedPT, v); } public String getSetCode() { diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 0068a966f2c..5cef4898c2c 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -37,6 +37,7 @@ public enum TrackableProperty { Secondary(TrackableTypes.BooleanType), DoubleFaced(TrackableTypes.BooleanType), FacedownImageKey(TrackableTypes.StringType), + PaperFoil(TrackableTypes.BooleanType), //TODO? Cloner(TrackableTypes.StringType), @@ -137,7 +138,7 @@ public enum TrackableProperty { AttractionLights(TrackableTypes.IntegerSetType), ChangedColorWords(TrackableTypes.StringMapType), HasChangedColors(TrackableTypes.BooleanType), - HasPrintedPT(TrackableTypes.BooleanType, FreezeMode.IgnoresFreeze), + HasPrintedPT(TrackableTypes.BooleanType), ChangedTypes(TrackableTypes.StringMapType), //check produce mana for BG diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 3317ba0eb12..84ebb47f81e 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -78,6 +78,7 @@ public class Forge implements ApplicationListener { public static KeyInputAdapter keyInputAdapter; private static boolean exited, initialized; public boolean needsUpdate = false; + public static boolean switchClassic = false; public static boolean advStartup = false; public static boolean safeToClose = true; public static boolean magnify = false; @@ -91,6 +92,7 @@ public class Forge implements ApplicationListener { public static String extrawide = "default"; public static float heigtModifier = 0.0f; public static float deltaTime = 0f; + public static float hueFragTime = 0f; private static boolean isloadingaMatch = false; public static boolean autoAIDeckSelection = false; public static boolean showFPS = false; @@ -370,8 +372,8 @@ public class Forge implements ApplicationListener { Config.instance().loadResources(); SpellSmithScene.instance().loadEditions(); GameHUD.getInstance().stopAudio(); + MusicPlaylist.invalidateMusicPlaylist(); if (startScene) { - MusicPlaylist.invalidateMusicPlaylist(); SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MENUS); switchScene(StartScene.instance()); } @@ -728,6 +730,7 @@ public class Forge implements ApplicationListener { } } deltaTime = 0f; + hueFragTime = 0f; } } }); @@ -768,6 +771,9 @@ public class Forge implements ApplicationListener { } public static void switchToClassic() { + if (switchClassic) + return; + switchClassic = true; setTransitionScreen(new TransitionScreen(() -> { ImageCache.getInstance().disposeTextures(); isMobileAdventureMode = false; @@ -778,7 +784,8 @@ public class Forge implements ApplicationListener { clearTransitionScreen(); openHomeDefault(); exited = false; - }, Forge.takeScreenshot(), false, false)); + switchClassic = false; + }, takeScreenshot(), false, false)); } public static void switchToAdventure() { @@ -870,6 +877,9 @@ public class Forge implements ApplicationListener { deltaTime += Gdx.graphics.getDeltaTime(); if (deltaTime > 22.5f) deltaTime = 0f; + hueFragTime += Gdx.graphics.getDeltaTime(); + if (hueFragTime > 6.29f) + hueFragTime = 0f; FContainer screen = currentScreen; diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index 0ad99284545..177ebfe71e8 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -55,6 +55,7 @@ public class Graphics { private final ShaderProgram shaderChromaticAbberation = new ShaderProgram(Shaders.vertPixelateShader, Shaders.fragChromaticAbberation); private final ShaderProgram shaderHueShift = new ShaderProgram(Shaders.vertPixelateShader, Shaders.fragHueShift); private final ShaderProgram shaderRoundedRect = new ShaderProgram(Shaders.vertPixelateShader, Shaders.fragRoundedRect); + private final ShaderProgram shaderRoundedRect2 = new ShaderProgram(Shaders.vertPixelateShader, Shaders.fragRoundedRect2); private final ShaderProgram shaderNoiseFade = new ShaderProgram(Shaders.vertPixelateShader, Shaders.fragNoiseFade); private final ShaderProgram shaderPortal = new ShaderProgram(Shaders.vertPixelateShader, Shaders.fragPortal); private final ShaderProgram shaderPixelateSimple = new ShaderProgram(Shaders.vertPixelateShader, Shaders.fragPixelateSimple); @@ -106,13 +107,28 @@ public class Graphics { } public void dispose() { - batch.dispose(); - shapeRenderer.dispose(); - shaderOutline.dispose(); - shaderGrayscale.dispose(); - shaderUnderwater.dispose(); - shaderWarp.dispose(); - if (dummyTexture != null) dummyTexture.dispose(); + try { + batch.dispose(); + } catch (Exception ignored) {} + try { + shapeRenderer.dispose(); + } catch (Exception ignored) {} + try { + shaderOutline.dispose(); + } catch (Exception ignored) {} + try { + shaderGrayscale.dispose(); + } catch (Exception ignored) {} + try { + shaderUnderwater.dispose(); + } catch (Exception ignored) {} + try { + shaderWarp.dispose(); + } catch (Exception ignored) {} + try { + if (dummyTexture != null) + dummyTexture.dispose(); + } catch (Exception ignored) {} } public Batch getBatch() { @@ -918,13 +934,40 @@ public class Graphics { batch.begin(); } - public void drawCardRoundRect(Texture image, TextureRegion damage_overlay, float x, float y, float w, float h, boolean drawGray, boolean damaged) { + public void drawFoil(float x, float y, float w, float h, float radius) { + drawFoil(x, y, w, h, radius, false); + } + + public void drawFoil(float x, float y, float w, float h, float radius, boolean rotate) { + Texture image = Forge.getAssets().getHolofoil(); if (image == null) return; batch.end(); + shaderRoundedRect2.bind(); + shaderRoundedRect2.setUniformf("u_resolution", image.getWidth(), image.getHeight()); + shaderRoundedRect2.setUniformf("edge_radius", (float)(image.getHeight() / image.getWidth()) * radius); + shaderRoundedRect2.setUniformf("u_time", Forge.hueFragTime); + batch.setShader(shaderRoundedRect2); + batch.begin(); + //draw + if (rotate) + drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, 0, 0, image.getWidth(), image.getHeight(), 90); + else + batch.draw(image, adjustX(x), adjustY(y, h), w, h); + //reset + batch.end(); + batch.setShader(null); + batch.begin(); + } + + public void drawCardRoundRect(Texture image, TextureRegion damage_overlay, float x, float y, float w, float h, boolean drawGray, boolean damaged, boolean foilEffect) { + if (image == null) + return; + float radius = ImageCache.getInstance().getRadius(image); + batch.end(); shaderRoundedRect.bind(); shaderRoundedRect.setUniformf("u_resolution", image.getWidth(), image.getHeight()); - shaderRoundedRect.setUniformf("edge_radius", (float)(image.getHeight() / image.getWidth()) * ImageCache.getInstance().getRadius(image)); + shaderRoundedRect.setUniformf("edge_radius", (float)(image.getHeight() / image.getWidth()) * radius); shaderRoundedRect.setUniformf("u_gray", drawGray ? 0.8f : 0f); batch.setShader(shaderRoundedRect); batch.begin(); @@ -934,22 +977,31 @@ public class Graphics { batch.end(); batch.setShader(null); batch.begin(); + if (foilEffect && !drawGray) { + drawFoil(x, y, w, h, radius); + } if (damage_overlay != null && damaged) batch.draw(damage_overlay, adjustX(x), adjustY(y, h), w, h); } public void drawCardRoundRect(Texture image, float x, float y, float w, float h, float originX, float originY, float rotation) { + drawCardRoundRect(image, x, y, w, h, originX, originY, rotation, 1f, false); + } + + public void drawCardRoundRect(Texture image, float x, float y, float w, float h, float originX, float originY, float rotation, float modR, boolean drawFoil) { if (image == null) return; batch.end(); shaderRoundedRect.bind(); shaderRoundedRect.setUniformf("u_resolution", image.getWidth(), image.getHeight()); - shaderRoundedRect.setUniformf("edge_radius", (float)(image.getHeight() / image.getWidth()) * ImageCache.getInstance().getRadius(image)); + shaderRoundedRect.setUniformf("edge_radius", (float)(image.getHeight() / image.getWidth()) * (ImageCache.getInstance().getRadius(image) * modR)); shaderRoundedRect.setUniformf("u_gray", 0f); batch.setShader(shaderRoundedRect); batch.begin(); //draw drawRotatedImage(image, x, y, w, h, originX, originY, 0, 0, image.getWidth(), image.getHeight(), rotation); + if (drawFoil) + drawFoil(x, y, w, h, modR, true); //reset batch.end(); batch.setShader(null); @@ -1273,13 +1325,25 @@ public class Graphics { } public void drawImage(Texture image, float x, float y, float w, float h) { + drawImage(image, x, y, w, h, false); + } + + public void drawImage(Texture image, float x, float y, float w, float h, boolean drawFoil) { if (image != null) batch.draw(image, adjustX(x), adjustY(y, h), w, h); + if (drawFoil) + drawFoil(x, y, w, h, 0f); } public void drawImage(TextureRegion image, float x, float y, float w, float h) { + drawImage(image, x, y, w, h, false); + } + + public void drawImage(TextureRegion image, float x, float y, float w, float h, boolean drawFoil) { if (image != null) batch.draw(image, adjustX(x), adjustY(y, h), w, h); + if (drawFoil) + drawFoil(x, y, w, h, 0f); } public void drawImage(TextureRegion image, TextureRegion glowImageReference, float x, float y, float w, float h, Color glowColor, boolean selected) { @@ -1509,7 +1573,7 @@ public class Graphics { } public Color borderLining(String c) { - if (c == null || c == "") + if (c == null || "".equals(c)) return Color.valueOf("#fffffd"); int c_r = Integer.parseInt(c.substring(0, 2), 16); int c_g = Integer.parseInt(c.substring(2, 4), 16); diff --git a/forge-gui-mobile/src/forge/GuiMobile.java b/forge-gui-mobile/src/forge/GuiMobile.java index 27e7d68408a..2af4a82bf0a 100644 --- a/forge-gui-mobile/src/forge/GuiMobile.java +++ b/forge-gui-mobile/src/forge/GuiMobile.java @@ -154,7 +154,7 @@ public class GuiMobile implements IGuiBase { } else if (paperCard != null) { Texture cardImage = ImageCache.getInstance().getImage(paperCard.getCardImageKey(), false); if (cardImage != null) - g.drawCardRoundRect(cardImage, null, (background.getWidth() - cardImageWidth) / 2, (background.getHeight() - cardImageHeight) / 3.8f, cardImageWidth, cardImageHeight, false, false); + g.drawCardRoundRect(cardImage, null, (background.getWidth() - cardImageWidth) / 2, (background.getHeight() - cardImageHeight) / 3.8f, cardImageWidth, cardImageHeight, false, false, paperCard.isFoil()); } Gdx.graphics.requestRendering(); //ensure image appears right away diff --git a/forge-gui-mobile/src/forge/Shaders.java b/forge-gui-mobile/src/forge/Shaders.java index 784517459b9..9e6dfdabe2c 100644 --- a/forge-gui-mobile/src/forge/Shaders.java +++ b/forge-gui-mobile/src/forge/Shaders.java @@ -181,6 +181,66 @@ public class Shaders { " }\n" + " gl_FragColor = col*alpha;\n" + "}"; + public static final String fragRoundedRect2 = "#ifdef GL_ES\n" + + "#define LOWP lowp\n" + + "precision mediump float;\n" + + "#else\n" + + "#define LOWP \n" + + "#endif\n" + + "varying vec2 v_texCoords;\n" + + "uniform sampler2D u_texture;\n" + + "uniform vec2 u_resolution;\n" + + "uniform float edge_radius;\n" + + "uniform float u_time;\n" + + "LOWP vec4 color = vec4(1.0,1.0,1.0,1.0);\n" + + "float gradientIntensity = 0.5;\n" + + "const float contrast = 1.5 ;\n" + + "vec3 barronSpline(vec3 x, float shape) {\n" + + " const float turning = 0.5;\n" + + " vec3 d = turning - x;\n" + + " return mix(\n" + + " ((1. - turning) * (x - 1.)) / (1. - (x + shape * d)) + 1.,\n" + + " (turning * x) / (1.0e-20 + (x + shape * d)),\n" + + " step(0.0, d));\n" + + "}\n" + + "\n" + + "vec3 hs(vec3 c, float s) {\n" + + " vec3 m=vec3(cos(s),s=sin(s)*.5774,-s);\n" + + " return c*mat3(m+=(1.-m.x)/3.,m.zxy,m.yzx);\n" + + "}\n" + + "vec3 applyHue(vec3 rgb, float hue)\n" + + "{\n" + + " //rgb = ((rgb + 0.5f) * 1f) - 0.5f;\n" + + " //rgb = barronSpline(rgb, contrast);\n" + + " vec3 k = vec3(0.5774);\n" + + " float c = cos(hue);\n" + + " //Rodrigues' rotation formula\n" + + " return rgb * c + cross(k, rgb) * sin(hue) + k * dot(k, rgb) * (1.0 - c);\n" + + "}\n"+ + "void main() {\n" + + " vec2 uv = v_texCoords;\n" + + " vec2 uv_base_center = uv * 2.0 - 1.0;\n" + + "\n" + + " vec2 half_resolution = u_resolution.xy * 0.5;\n" + + " vec2 abs_rounded_center = half_resolution.xy - edge_radius;\n" + + " vec2 abs_pixel_coord = vec2( abs(uv_base_center.x * half_resolution.x), abs(uv_base_center.y * half_resolution.y) );\n" + + "\n" + + " float alpha = 1.0;\n" + + " LOWP vec4 orig = color * texture2D(u_texture, uv);\n" + + " vec3 col = orig.rgb;\n" + + " vec4 col2 = vec4(applyHue(col, u_time), 1.);\n" + + " //multiply the original texture alpha to render only opaque shifted colors \n" + + " col2.a *= orig.a;\n" + + " uv.y = -1.0 - uv.y;" + + " uv.x += sin(uv.y*12.0+u_time)/4.0;" + + " if (abs_pixel_coord.x > abs_rounded_center.x && abs_pixel_coord.y > abs_rounded_center.y) {\n" + + " float r = length(abs_pixel_coord - abs_rounded_center);\n" + + " alpha = smoothstep(edge_radius, edge_radius - gradientIntensity, r);\n" + + " \n" + + " }\n" + + " //alpha here is the rounded edges to be removed \n" + + " gl_FragColor = col2*alpha;\n" + + "}"; public static final String fragHueShift = "#ifdef GL_ES\n" + "#define LOWP lowp\n" + "precision mediump float;\n" + diff --git a/forge-gui-mobile/src/forge/assets/Assets.java b/forge-gui-mobile/src/forge/assets/Assets.java index 65852e50749..c345730c2dc 100644 --- a/forge-gui-mobile/src/forge/assets/Assets.java +++ b/forge-gui-mobile/src/forge/assets/Assets.java @@ -30,6 +30,8 @@ import forge.localinstance.skin.FSkinProp; import java.util.HashMap; import java.util.Map; +import static forge.assets.FSkin.getDefaultSkinFile; + public class Assets implements Disposable { private MemoryTrackingAssetManager manager; private HashMap fonts; @@ -51,6 +53,7 @@ public class Assets implements Disposable { private TextureParameter textureParameter; private ObjectMap textrafonts; private int cFB = 0, cFBVal = 0, cTM = 0, cTMVal = 0, cSF = 0, cSFVal = 0, cCF = 0, cCFVal = 0; + private Texture holofoil; public Assets() { String titleFilename = Forge.isLandscapeMode() ? "title_bg_lq.png" : "title_bg_lq_portrait.png"; @@ -354,6 +357,12 @@ public class Assets implements Disposable { return dummy; } + public Texture getHolofoil() { + if (holofoil == null) { + holofoil = getTexture(getDefaultSkinFile("holofoil.png")); + } + return holofoil; + } public Font getTextraFont(BitmapFont bitmapFont, TextureAtlas item_atlas, TextureAtlas pixelmana_atlas) { if (textrafonts == null) textrafonts = new ObjectMap<>(); diff --git a/forge-gui-mobile/src/forge/assets/FSkin.java b/forge-gui-mobile/src/forge/assets/FSkin.java index 617cd78a98b..f8002076b12 100644 --- a/forge-gui-mobile/src/forge/assets/FSkin.java +++ b/forge-gui-mobile/src/forge/assets/FSkin.java @@ -180,6 +180,7 @@ public class FSkin { Forge.getAssets().loadTexture(getDefaultSkinFile("overlay_alpha.png")); Forge.getAssets().loadTexture(getDefaultSkinFile("spiral.png")); Forge.getAssets().loadTexture(getDefaultSkinFile("splatter.png")); + Forge.getAssets().loadTexture(getDefaultSkinFile("holofoil.png")); if (splashScreen != null) { final FileHandle f = getSkinFile("bg_splash.png"); diff --git a/forge-gui-mobile/src/forge/card/CardImage.java b/forge-gui-mobile/src/forge/card/CardImage.java index a354baca159..85d24429557 100644 --- a/forge-gui-mobile/src/forge/card/CardImage.java +++ b/forge-gui-mobile/src/forge/card/CardImage.java @@ -50,7 +50,7 @@ public class CardImage implements FImage { } else { if (Forge.enableUIMask.equals("Full")) { if (ImageCache.getInstance().isFullBorder(image)) - g.drawCardRoundRect(image, null, x, y, w, h, false, false); + g.drawCardRoundRect(image, null, x, y, w, h, false, false, false); else { float radius = (h - w) / 8; g.drawborderImage(ImageCache.getInstance().borderColor(image), x, y, w, h); diff --git a/forge-gui-mobile/src/forge/card/CardImageRenderer.java b/forge-gui-mobile/src/forge/card/CardImageRenderer.java index a6a4f2d912b..09c72856361 100644 --- a/forge-gui-mobile/src/forge/card/CardImageRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardImageRenderer.java @@ -10,8 +10,7 @@ import java.util.List; import forge.ImageKeys; import forge.assets.*; import forge.item.PaperCard; -import forge.util.ImageUtil; -import forge.util.TextBounds; +import forge.util.*; import org.apache.commons.lang3.StringUtils; import com.badlogic.gdx.graphics.Color; @@ -35,8 +34,6 @@ import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; import forge.screens.FScreen; import forge.screens.match.MatchController; -import forge.util.CardTranslation; -import forge.util.Utils; public class CardImageRenderer { private static final float BASE_IMAGE_WIDTH = 360; @@ -791,6 +788,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) { + drawZoom(g, card, gameView, altState, x, y, w, h, dispW, dispH, isCurrentCard, 1f); + } + 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, float modR) { boolean canshow = MatchController.instance.mayView(card); String key = card.getState(altState).getImageKey(); Texture image = new CachedCardImageRenderer(key).getImage(); @@ -814,33 +814,31 @@ public class CardImageRenderer { float new_h = h * wh_Adj; float new_x = ForgeConstants.isGdxPortLandscape && isCurrentCard ? (dispW - new_w) / 2 : x; float new_y = ForgeConstants.isGdxPortLandscape && isCurrentCard ? (dispH - new_h) / 2 : y; - float new_xRotate = (dispW - new_h) / 2; - float new_yRotate = (dispH - new_w) / 2; - boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS); - boolean rotatePlane = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON); float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f; float minusxy = isModernFrame(card) ? 0.0f : 0.13f * radius; if (card.getCurrentState().getSetCode().equals("LEA") || card.getCurrentState().getSetCode().equals("LEB")) { croppedArea = 0.975f; minusxy = 0.135f * radius; } - if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane() || (card.getCurrentState().isBattle() && !altState) || (card.getAlternateState() != null && card.getAlternateState().isBattle() && altState))) { + if (canshow && CardRendererUtils.needsRotation(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON, card, altState)) { if (Forge.enableUIMask.equals("Full")) { if (ImageCache.getInstance().isFullBorder(image)) g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90); else { g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90); g.drawRotatedImage(ImageCache.getInstance().croppedBorderImage(image), new_x + radius / 2 - minusxy, new_y + radius / 2 - minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2 - minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2 - minusxy) + (new_h * croppedArea) / 2, -90); + if (CardRendererUtils.drawFoil(card)) + g.drawFoil(new_x, new_y, new_w, new_h, modR, true); } } else if (Forge.enableUIMask.equals("Crop")) { g.drawRotatedImage(ImageCache.getInstance().croppedBorderImage(image), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 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() && canshow && !card.isFaceDown()) { + } else if (canshow && CardRendererUtils.needsRotation(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS, card, altState)) { boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath"); if (Forge.enableUIMask.equals("Full")) { if (ImageCache.getInstance().isFullBorder(image)) - g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90); + g.drawCardRoundRect(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90, modR, CardRendererUtils.drawFoil(card)); else { g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getInstance().getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90); g.drawRotatedImage(ImageCache.getInstance().croppedBorderImage(image), new_x + radius / 2 - minusxy, new_y + radius / 2 - minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2 - minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2 - minusxy) + (new_h * croppedArea) / 2, isAftermath ? 90 : -90); @@ -852,7 +850,7 @@ public class CardImageRenderer { } else { if (card.isFaceDown() && ZoneType.Exile.equals(card.getZone())) { if (card.isForeTold() || altState) { - if (card.isSplitCard() && rotateSplit && isCurrentCard) { + if (CardRendererUtils.needsRotation(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS, card, altState) && isCurrentCard) { boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath"); if (Forge.enableUIMask.equals("Full")) { if (ImageCache.getInstance().isFullBorder(image)) @@ -868,7 +866,7 @@ public class CardImageRenderer { } else { if (Forge.enableUIMask.equals("Full")) { if (ImageCache.getInstance().isFullBorder(image)) - g.drawCardRoundRect(image, null, x, y, w, h, false, false); + g.drawCardRoundRect(image, null, x, y, w, h, false, false, CardRendererUtils.drawFoil(card)); else { g.drawImage(ImageCache.getInstance().getBorderImage(image.toString()), ImageCache.getInstance().borderColor(image), x, y, w, h); g.drawImage(ImageCache.getInstance().croppedBorderImage(image), x + radius / 2.4f - minusxy, y + radius / 2 - minusxy, w * croppedArea, h * croppedArea); @@ -885,7 +883,7 @@ public class CardImageRenderer { } } else if (Forge.enableUIMask.equals("Full") && canshow) { if (ImageCache.getInstance().isFullBorder(image)) - g.drawCardRoundRect(image, null, x, y, w, h, false, false); + g.drawCardRoundRect(image, null, x, y, w, h, false, false, CardRendererUtils.drawFoil(card)); else { g.drawImage(ImageCache.getInstance().getBorderImage(image.toString()), ImageCache.getInstance().borderColor(image), x, y, w, h); g.drawImage(ImageCache.getInstance().croppedBorderImage(image), x + radius / 2.4f - minusxy, y + radius / 2 - minusxy, w * croppedArea, h * croppedArea); @@ -900,7 +898,8 @@ public class CardImageRenderer { } } } - CardRenderer.drawFoilEffect(g, card, x, y, w, h, isCurrentCard && canshow && image != ImageCache.getInstance().getDefaultImage()); + if (canshow && !Forge.enableUIMask.equals("Full") && CardRendererUtils.drawFoil(card)) + g.drawFoil(x, y, w, h, 0f, CardRendererUtils.needsRotation(card, altState)); } public static void drawDetails(Graphics g, CardView card, GameView gameView, boolean altState, float x, float y, float w, float h) { diff --git a/forge-gui-mobile/src/forge/card/CardRenderer.java b/forge-gui-mobile/src/forge/card/CardRenderer.java index 90bc944573e..0c04afa22a0 100644 --- a/forge-gui-mobile/src/forge/card/CardRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardRenderer.java @@ -53,7 +53,6 @@ import forge.gui.card.CardDetailUtil.DetailColors; import forge.item.IPaperCard; import forge.item.InventoryItem; import forge.localinstance.properties.ForgeConstants.CounterDisplayType; -import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; import forge.localinstance.skin.FSkinProp; import forge.model.FModel; @@ -605,28 +604,29 @@ public class CardRenderer { croppedArea = 0.975f; minusxy = 0.135f * radius; } + if (pc.isFoil()) { //draw foil effect if needed + if (card.getCurrentState().getFoilIndex() == 0) { //if foil finish not yet established, assign a random one + card.getCurrentState().setFoilIndexOverride(-1); + } + } if (image != null) { if (image == ImageCache.getInstance().getDefaultImage() || Forge.enableUIMask.equals("Art")) { CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos, true, true); } else { if (Forge.enableUIMask.equals("Full")) { if (ImageCache.getInstance().isFullBorder(image)) - g.drawCardRoundRect(image, null, x, y, w, h, false, false); + g.drawCardRoundRect(image, null, x, y, w, h, false, false, CardRendererUtils.drawFoil(card)); else { //tint the border g.drawImage(ImageCache.getInstance().getBorderImage(image.toString()), ImageCache.getInstance().borderColor(image), x, y, w, h); g.drawImage(ImageCache.getInstance().croppedBorderImage(image), x + radius / 2.4f - minusxy, y + radius / 2 - minusxy, w * croppedArea, h * croppedArea); + if (CardRendererUtils.drawFoil(card)) + g.drawFoil(x, y, w, h, radius); } } else if (Forge.enableUIMask.equals("Crop")) { - g.drawImage(ImageCache.getInstance().croppedBorderImage(image), x, y, w, h); + g.drawImage(ImageCache.getInstance().croppedBorderImage(image), x, y, w, h, CardRendererUtils.drawFoil(card)); } else - g.drawImage(image, x, y, w, h); - } - if (pc.isFoil()) { //draw foil effect if needed - if (card.getCurrentState().getFoilIndex() == 0) { //if foil finish not yet established, assign a random one - card.getCurrentState().setFoilIndexOverride(-1); - } - drawFoilEffect(g, card, x, y, w, h, false); + g.drawImage(image, x, y, w, h, CardRendererUtils.drawFoil(card)); } } else { //if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically @@ -652,59 +652,56 @@ public class CardRenderer { minusxy = 0.135f * radius; } if (image != null) { + float cardR = ImageCache.getInstance().getRadius(image); if (image == ImageCache.getInstance().getDefaultImage() || Forge.enableUIMask.equals("Art")) { - CardImageRenderer.drawCardImage(g, card, showAltState, x, y, w, h, pos, true, false, isChoiceList, !showCardIdOverlay(card)); + CardImageRenderer.drawCardImage(g, card, showAltState, x, y, w, h, pos, true, false, isChoiceList, !CardRendererUtils.showCardIdOverlay(card)); } else if (showsleeves) { if (!card.isForeTold()) - g.drawCardImage(sleeves, crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0); + g.drawCardImage(sleeves, crack_overlay, x, y, w, h, CardRendererUtils.drawGray(card), CardRendererUtils.drawCracks(card, magnify)); else - g.drawCardImage(image, crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0); + g.drawCardImage(image, crack_overlay, x, y, w, h, CardRendererUtils.drawGray(card), CardRendererUtils.drawCracks(card, magnify)); } else { - if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON) - && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane() || (card.getCurrentState().isBattle() && !showAltState) || (card.getAlternateState() != null && card.getAlternateState().isBattle() && showAltState)) && rotate) { + if (rotate) { + float rotation = CardRendererUtils.hasAftermath(card) ? 90 : -90; if (Forge.enableUIMask.equals("Full")) { if (ImageCache.getInstance().isFullBorder(image)) - g.drawCardRoundRect(image, x, y, w, h, x + w / 2, y + h / 2, -90); + g.drawCardRoundRect(image, x, y, w, h, x + w / 2, y + h / 2, rotation); else { - g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90); - g.drawRotatedImage(ImageCache.getInstance().croppedBorderImage(image), x + radius / 2.3f - minusxy, y + radius / 2 - minusxy, w * croppedArea, h * croppedArea, (x + radius / 2.3f - minusxy) + (w * croppedArea) / 2, (y + radius / 2 - minusxy) + (h * croppedArea) / 2, -90); + g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, rotation); + g.drawRotatedImage(ImageCache.getInstance().croppedBorderImage(image), x + radius / 2.3f - minusxy, y + radius / 2 - minusxy, w * croppedArea, h * croppedArea, (x + radius / 2.3f - minusxy) + (w * croppedArea) / 2, (y + radius / 2 - minusxy) + (h * croppedArea) / 2, rotation); } + } else if (Forge.enableUIMask.equals("Crop")) { - g.drawRotatedImage(ImageCache.getInstance().croppedBorderImage(image), x, y, w, h, x + w / 2, y + h / 2, -90); + g.drawRotatedImage(ImageCache.getInstance().croppedBorderImage(image), x, y, w, h, x + w / 2, y + h / 2, rotation); } else - g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90); + g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, rotation); } else { if (Forge.enableUIMask.equals("Full") && canshow) { if (ImageCache.getInstance().isFullBorder(image)) - g.drawCardRoundRect(image, crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0); + g.drawCardRoundRect(image, crack_overlay, x, y, w, h, CardRendererUtils.drawGray(card), CardRendererUtils.drawCracks(card, magnify), CardRendererUtils.drawFoil(card)); else { //boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors(); g.drawBorderImage(ImageCache.getInstance().getBorderImage(image.toString(), canshow), ImageCache.getInstance().borderColor(image), ImageCache.getInstance().getTint(card, image), x, y, w, h, false); //tint check for changed colors - g.drawCardImage(ImageCache.getInstance().croppedBorderImage(image), crack_overlay, x + radius / 2.4f - minusxy, y + radius / 2 - minusxy, w * croppedArea, h * croppedArea, drawGray(card), magnify ? false : card.getDamage() > 0); + g.drawCardImage(ImageCache.getInstance().croppedBorderImage(image), crack_overlay, x + radius / 2.4f - minusxy, y + radius / 2 - minusxy, w * croppedArea, h * croppedArea, CardRendererUtils.drawGray(card), CardRendererUtils.drawCracks(card, magnify)); } } else if (Forge.enableUIMask.equals("Crop") && canshow) { - g.drawCardImage(ImageCache.getInstance().croppedBorderImage(image), crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0); + g.drawCardImage(ImageCache.getInstance().croppedBorderImage(image), crack_overlay, x, y, w, h, CardRendererUtils.drawGray(card), CardRendererUtils.drawCracks(card, magnify)); } else { if (canshow) - g.drawCardImage(image, crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0); + g.drawCardImage(image, crack_overlay, x, y, w, h, CardRendererUtils.drawGray(card), CardRendererUtils.drawCracks(card, magnify)); else // draw card back sleeves - g.drawCardImage(sleeves, crack_overlay, x, y, w, h, drawGray(card), magnify ? false : card.getDamage() > 0); + g.drawCardImage(sleeves, crack_overlay, x, y, w, h, CardRendererUtils.drawGray(card), CardRendererUtils.drawCracks(card, magnify)); } } } - drawFoilEffect(g, card, x, y, w, h, false); + if (canshow && CardRendererUtils.drawFoil(card)) + g.drawFoil(x, y, w, h, Forge.enableUIMask.equals("Full") ? cardR : 0f, !Forge.enableUIMask.equals("Art") && rotate); } else { //if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically - CardImageRenderer.drawCardImage(g, card, showAltState, x, y, w, h, pos, true, false, isChoiceList, !showCardIdOverlay(card)); + CardImageRenderer.drawCardImage(g, card, showAltState, x, y, w, h, pos, true, false, isChoiceList, !CardRendererUtils.showCardIdOverlay(card)); } } - private static boolean drawGray(CardView c) { - if (c == null) - return false; - return c.wasDestroyed() || c.isPhasedOut(); - } - public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) { drawCardWithOverlays(g, card, x, y, w, h, pos, false, false, false); } @@ -757,7 +754,7 @@ public class CardRenderer { } } - if (canShow && showCardIdOverlay(card)) { + if (canShow && CardRendererUtils.showCardIdOverlay(card)) { FSkinFont idFont = FSkinFont.forHeight(h * 0.11f); float idHeight = idFont.getCapHeight(); g.drawOutlinedText(String.valueOf(card.getId()), idFont, Color.WHITE, Color.BLACK, x + padding, y + h - idHeight - padding, w, h, false, Align.left, false); @@ -805,7 +802,7 @@ public class CardRenderer { CardFaceSymbols.drawSymbol("sacrifice", g, (x + (w / 2)) - sacSymbolSize / 2, (y + (h / 2)) - sacSymbolSize / 2, otherSymbolsSize, otherSymbolsSize); } - if (onTop && showCardPowerOverlay(card) && (canShow || card.isFaceDown())) { //make sure card p/t box appears on top + if (onTop && CardRendererUtils.showCardPowerOverlay(card) && (canShow || card.isFaceDown())) { //make sure card p/t box appears on top //only needed if on top since otherwise P/T will be hidden drawPtBox(g, card, details, color, x, y, w, h); } @@ -822,8 +819,8 @@ public class CardRenderer { g.setAlphaComposite(0.6f); } if (ZoneType.Battlefield.equals(card.getZone()) && onTop) { - drawAbilityIcons(g, card, cx, cy, cw, ch, cx + ((cw * 2) / 2.3f), cy, cw / 5.5f, cw / 5.7f, showAbilityIcons(card)); - } else if (canShow && !ZoneType.Battlefield.equals(card.getZone()) && showAbilityIcons(card)) { + drawAbilityIcons(g, card, cx, cy, cw, ch, cx + ((cw * 2) / 2.3f), cy, cw / 5.5f, cw / 5.7f, CardRendererUtils.showAbilityIcons(card)); + } else if (canShow && !ZoneType.Battlefield.equals(card.getZone()) && CardRendererUtils.showAbilityIcons(card)) { //draw indicator for flash or can be cast at instant speed, enabled if show ability icons is enabled String keywordKey = card.getCurrentState().getKeywordKey(); String abilityText = card.getCurrentState().getAbilityText(); @@ -836,7 +833,7 @@ public class CardRenderer { } //draw name and mana cost overlays if card is small or default card image being used if (h <= NAME_COST_THRESHOLD && canShow) { - if (showCardNameOverlay(card)) { + if (CardRendererUtils.showCardNameOverlay(card)) { float multiplier; switch (Forge.extrawide) { case "default": @@ -854,7 +851,7 @@ public class CardRenderer { } g.drawOutlinedText(CardTranslation.getTranslatedName(details.getName()), FSkinFont.forHeight(h * multiplier), Color.WHITE, Color.BLACK, cx + padding - 1f, cy + padding, cw - 2 * padding, ch * 0.4f, true, Align.left, false, true); } - if (showCardManaCostOverlay(card)) { + if (CardRendererUtils.showCardManaCostOverlay(card)) { float manaSymbolSize = w / 4.5f; if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack && card.getZone() != ZoneType.Battlefield) { if (isChoiceList) { @@ -1442,67 +1439,6 @@ public class CardRenderer { CardFaceSymbols.drawManaCost(g, cost, x + (w - manaCostWidth) / 2, y + (h - manaSymbolSize) / 2, manaSymbolSize); } - public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) { - if (card.getCurrentState().isBattle()) - return; - if (card.getAlternateState() != null && card.getCurrentState().isBattle()) - return; - //todo add support for battle, better to move the render inside the draw method for card in the future or a general foil effect shader.. - float new_x = x; - float new_y = y; - float new_w = w; - float new_h = h; - float radius = (h - w) / 8; - float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f; - float minusxy = isModernFrame(card) ? 0.0f : 0.13f * radius; - if (card.getCurrentState().getSetCode().equals("LEA") || card.getCurrentState().getSetCode().equals("LEB")) { - croppedArea = 0.975f; - minusxy = 0.135f * radius; - } - if (Forge.enableUIMask.equals("Full")) { - new_x += radius / 2.4f - minusxy; - new_y += radius / 2 - minusxy; - new_w = w * croppedArea; - new_h = h * croppedArea; - } - 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), new_x, new_y, new_w, new_h, rotateSplit); - } - } - } - - private static boolean isPreferenceEnabled(FPref preferenceName) { - return FModel.getPreferences().getPrefBoolean(preferenceName); - } - - private static boolean isShowingOverlays(CardView card) { - return isPreferenceEnabled(FPref.UI_SHOW_CARD_OVERLAYS) && card != null; - } - - private static boolean showCardNameOverlay(CardView card) { - return isShowingOverlays(card) && isPreferenceEnabled(FPref.UI_OVERLAY_CARD_NAME); - } - - private static boolean showCardPowerOverlay(CardView card) { - return isShowingOverlays(card) && isPreferenceEnabled(FPref.UI_OVERLAY_CARD_POWER); - } - - private static boolean showCardManaCostOverlay(CardView card) { - return isShowingOverlays(card) && - isPreferenceEnabled(FPref.UI_OVERLAY_CARD_MANA_COST); - } - - public static boolean showAbilityIcons(CardView card) { - return isShowingOverlays(card) && isPreferenceEnabled(FPref.UI_OVERLAY_ABILITY_ICONS); - } - - private static boolean showCardIdOverlay(CardView card) { - return card.getId() > 0 && isShowingOverlays(card) && isPreferenceEnabled(FPref.UI_OVERLAY_CARD_ID); - } - //TODO Make FSkinFont accept more than one kind of font and merge this with it private static void generateFontForCounters(final int fontSize) { diff --git a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java index 2a5b7d6a8ea..2c1461285c7 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java @@ -18,6 +18,7 @@ import forge.gui.interfaces.IGuiGame; import forge.screens.match.views.VField; import forge.screens.match.views.VReveal; import forge.toolbox.FDisplayObject; +import forge.util.CardRendererUtils; import forge.util.Utils; import forge.util.collect.FCollectionView; import org.apache.commons.lang3.tuple.Pair; @@ -404,36 +405,43 @@ public class MatchScreen extends FScreen { if (object instanceof FCardPanel cardPanel) { try { if (cardPanel.isHovered()) { - VPlayerPanel vPlayerPanel = getPlayerPanel(cardPanel.getCard().getController()); + CardView cardView = cardPanel.getCard(); + VPlayerPanel vPlayerPanel = getPlayerPanel(cardView.getController()); if (vPlayerPanel == null) - vPlayerPanel = getPlayerPanel(cardPanel.getCard().getOwner()); + vPlayerPanel = getPlayerPanel(cardView.getOwner()); if (vPlayerPanel != null) { - float cardW = getHeight() * 0.45f; + boolean rotate = CardRendererUtils.needsRotation(cardView) && !Forge.magnifyShowDetails; + boolean inBattlefield = ZoneType.Battlefield.equals(cardView.getZone()); + float mul = 0.45f; + float div = inBattlefield ? cardPanel.isTapped() ? 2.7f : 2.4f : 1.6f; + float adjX = rotate ? cardPanel.getWidth() / div : 0f; + float adjY = rotate ? cardPanel.getHeight() / 2.2f : 0f; + float cardW = getHeight() * mul; float cardH = FCardPanel.ASPECT_RATIO * cardW; - float cardX = !ZoneType.Battlefield.equals(cardPanel.getCard().getZone()) - ? cardPanel.screenPos.x - cardW : cardPanel.screenPos.x + (cardPanel.isTapped() - ? cardPanel.getWidth() : cardPanel.getWidth() / 1.4f); + float cardX = !inBattlefield ? cardPanel.screenPos.x - (cardW + adjX) + : cardPanel.screenPos.x + (cardPanel.isTapped() ? cardPanel.getWidth() + : cardPanel.getWidth() / 1.4f) + adjX; if (vPlayerPanel.getSelectedTab() != null && vPlayerPanel.getSelectedTab().isVisible() && cardX > vPlayerPanel.getSelectedTab().getDisplayArea().getLeft()) { - cardX = cardPanel.screenPos.x - cardW; + cardX = cardPanel.screenPos.x - (cardW + adjX); } - if ((cardX + cardW) > scroller.getWidth() + scroller.getLeft()) - cardX = cardPanel.screenPos.x - cardW; + if ((cardX + cardW + adjX) > scroller.getWidth() + scroller.getLeft()) + cardX = cardPanel.screenPos.x - (cardW + adjX); if (vPlayerPanel.getCommandZone() != null && vPlayerPanel.getCommandZone().isVisible() && cardX > vPlayerPanel.getCommandZone().screenPos.x) - cardX = cardPanel.screenPos.x - cardW; - float cardY = (cardPanel.screenPos.y - cardH) + cardPanel.getHeight(); + cardX = cardPanel.screenPos.x - (cardW + adjX); + float cardY = (cardPanel.screenPos.y - (cardH - adjY)) + cardPanel.getHeight(); if (vPlayerPanel.getPlayer() == bottomPlayerPanel.getPlayer()) { - cardY = bottomPlayerPrompt.screenPos.y - cardH; + cardY = bottomPlayerPrompt.screenPos.y - (cardH - adjY); } else if (cardY < vPlayerPanel.getField().screenPos.y && vPlayerPanel.getPlayer() != bottomPlayerPanel.getPlayer()) { - cardY = vPlayerPanel.getField().screenPos.y; - if ((cardY + cardH) > bottomPlayerPrompt.screenPos.y) - cardY = bottomPlayerPrompt.screenPos.y - cardH; + cardY = vPlayerPanel.getField().screenPos.y - adjY; + if ((cardY + (cardH - adjY)) > bottomPlayerPrompt.screenPos.y) + cardY = bottomPlayerPrompt.screenPos.y - (cardH - adjY); } if (Forge.magnifyShowDetails) - CardImageRenderer.drawDetails(g, cardPanel.getCard(), MatchController.instance.getGameView(), false, cardX, cardY, cardW, cardH); + CardImageRenderer.drawDetails(g, cardView, MatchController.instance.getGameView(), false, cardX, cardY, cardW, cardH); else - CardRenderer.drawCard(g, cardPanel.getCard(), cardX, cardY, cardW, cardH, CardRenderer.CardStackPosition.Top, false, false, false, true); + CardRenderer.drawCard(g, cardView, cardX, cardY, cardW, cardH, CardRenderer.CardStackPosition.Top, rotate, false, false, true); } } } catch (Exception e) { @@ -888,11 +896,11 @@ public class MatchScreen extends FScreen { g.drawRipple(image, x, y, w, h, 1 - percentage); if ("Day".equalsIgnoreCase(dt)) { g.setAlphaComposite(percentage); - g.drawNightDay(image, x, y, w, h, 100f, true, 1 - percentage); + g.drawNightDay(image, x, y, w, h, 100f, true, 0/*1 - percentage*/); // disable extra ripples g.setAlphaComposite(oldAlpha); } else if ("Night".equalsIgnoreCase(dt)) { g.setAlphaComposite(percentage); - g.drawNightDay(image, x, y, w, h, -100f, true, 1 - percentage); + g.drawNightDay(image, x, y, w, h, -100f, true, 0/*1 - percentage*/); // disable extra ripples g.setAlphaComposite(oldAlpha); } } else { diff --git a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java index 4caffab2cba..a96fdd785a6 100644 --- a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java +++ b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java @@ -41,6 +41,7 @@ import forge.localinstance.skin.IHasSkinProp; import forge.screens.match.MatchController; import forge.screens.match.views.VAvatar; import forge.screens.match.views.VStack; +import forge.util.CardRendererUtils; import forge.util.TextUtil; import forge.util.Utils; @@ -440,33 +441,6 @@ public class FChoiceList extends FList implements ActivateHandler { } } - //simple check for cardview needed on some special renderer for cards - private boolean showAlternate(CardView cardView, String value) { - if (cardView == null) - return false; - if (cardView.isFaceDown()) - return false; - boolean showAlt = false; - if (cardView.hasAlternateState()) { - if (cardView.hasBackSide()) - showAlt = value.contains(cardView.getBackSideName()) || cardView.getAlternateState().getAbilityText().contains(value); - else if (cardView.hasSecondaryState()) - showAlt = value.equals(cardView.getAlternateState().getAbilityText()); - else if (cardView.isSplitCard()) { - //special case if aftermath cards can be cast from graveyard like yawgmoths will, you will have choices - if (cardView.getAlternateState().getOracleText().contains("Aftermath")) - showAlt = cardView.getAlternateState().getOracleText().contains(value); - else { - if (cardView.isRoom()) // special case for room cards - showAlt = cardView.getAlternateState().getName().equalsIgnoreCase(value); - else - showAlt = value.equals(cardView.getAlternateState().getAbilityText()); - } - } - } - return showAlt; - } - //special renderer for cards protected class PaperCardItemRenderer extends ItemRenderer { @Override @@ -575,7 +549,7 @@ public class FChoiceList extends FList implements ActivateHandler { } } CardView cv = ((IHasCardView) value).getCardView(); - CardZoom.show(cv, showAlternate(cv, value.toString())); + CardZoom.show(cv, CardRendererUtils.canShowAlternate(cv, value.toString())); } catch (Exception ignored) { //fixme: java.lang.ClassCastException for cards like Subtlety which should be cancelable instead... } @@ -595,7 +569,7 @@ public class FChoiceList extends FList implements ActivateHandler { } } CardView cv = ((IHasCardView) value).getCardView(); - CardZoom.show(cv, showAlternate(cv, value.toString())); + CardZoom.show(cv, CardRendererUtils.canShowAlternate(cv, value.toString())); } catch (Exception ignored) { //fixme: java.lang.ClassCastException for cards like Subtlety which should be cancelable instead... } @@ -612,7 +586,7 @@ public class FChoiceList extends FList implements ActivateHandler { if (morph != null) { g.drawImage(morph, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT); } else if (cv != null) { - boolean showAlternate = showAlternate(cv, value.toString()); + boolean showAlternate = CardRendererUtils.canShowAlternate(cv, value.toString()); if (!cv.isFaceDown()) CardRenderer.drawCardWithOverlays(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true); else @@ -620,7 +594,7 @@ public class FChoiceList extends FList implements ActivateHandler { } } else { if (cv != null) { - boolean showAlternate = showAlternate(cv, value.toString()); + boolean showAlternate = CardRendererUtils.canShowAlternate(cv, value.toString()); if (!cv.isFaceDown()) CardRenderer.drawCardWithOverlays(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true); else diff --git a/forge-gui-mobile/src/forge/util/CardRendererUtils.java b/forge-gui-mobile/src/forge/util/CardRendererUtils.java new file mode 100644 index 00000000000..0a5c139fcae --- /dev/null +++ b/forge-gui-mobile/src/forge/util/CardRendererUtils.java @@ -0,0 +1,119 @@ +package forge.util; + +import forge.Forge; +import forge.game.card.CardView; +import forge.localinstance.properties.ForgePreferences; +import forge.model.FModel; +import forge.screens.match.MatchController; + +public class CardRendererUtils { + public static boolean needsRotation(final CardView card) { + return needsRotation(card.isSplitCard() ? ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS + : ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON, card, canShowAlternate(card, card.getName())); + } + public static boolean needsRotation(final CardView card, final boolean altState) { + return needsRotation(card.isSplitCard() ? ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS + : ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON, card, altState); + } + public static boolean needsRotation(final ForgePreferences.FPref fPref, final CardView card, boolean altState) { + if (isPreferenceEnabled(fPref)) { + if (Forge.enableUIMask.equals("Art")) + return false; + switch (fPref) { + case UI_ROTATE_SPLIT_CARDS -> { + return card.isSplitCard() && MatchController.instance.mayView(card) && !card.isFaceDown(); + } + case UI_ROTATE_PLANE_OR_PHENOMENON -> { + return card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane() + || (card.getCurrentState().isBattle() && !altState) + || (card.getAlternateState() != null && card.getAlternateState().isBattle() && altState); + } + default -> { + return false; + } + } + } + return false; + } + public static boolean canShowAlternate(final CardView card, final String reference) { + if (card == null) + return false; + if (card.isFaceDown()) + return false; + boolean showAlt = false; + if (card.hasAlternateState()) { + if (card.hasBackSide()) + showAlt = reference.contains(card.getBackSideName()) || card.getAlternateState().getAbilityText().contains(reference); + else if (card.hasSecondaryState()) + showAlt = reference.equals(card.getAlternateState().getAbilityText()); + else if (card.isSplitCard()) { + //special case if aftermath cards can be cast from graveyard like yawgmoths will, you will have choices + if (card.getAlternateState().getOracleText().contains("Aftermath")) + showAlt = card.getAlternateState().getOracleText().contains(reference); + else { + if (card.isRoom()) // special case for room cards + showAlt = card.getAlternateState().getName().equalsIgnoreCase(reference); + else + showAlt = reference.equals(card.getAlternateState().getAbilityText()); + } + } + } + return showAlt; + } + public static boolean hasAftermath(final CardView card) { + if (card.hasAlternateState()) + return card.getAlternateState().hasAftermath(); + return false; + } + + + public static boolean isPreferenceEnabled(final ForgePreferences.FPref preferenceName) { + return FModel.getPreferences().getPrefBoolean(preferenceName); + } + + public static boolean isShowingOverlays(final CardView card) { + return isPreferenceEnabled(ForgePreferences.FPref.UI_SHOW_CARD_OVERLAYS) && card != null; + } + + public static boolean showCardNameOverlay(final CardView card) { + return isShowingOverlays(card) && isPreferenceEnabled(ForgePreferences.FPref.UI_OVERLAY_CARD_NAME); + } + + public static boolean showCardPowerOverlay(final CardView card) { + return isShowingOverlays(card) && isPreferenceEnabled(ForgePreferences.FPref.UI_OVERLAY_CARD_POWER); + } + + public static boolean showCardManaCostOverlay(final CardView card) { + return isShowingOverlays(card) && + isPreferenceEnabled(ForgePreferences.FPref.UI_OVERLAY_CARD_MANA_COST); + } + + public static boolean showAbilityIcons(final CardView card) { + return isShowingOverlays(card) && isPreferenceEnabled(ForgePreferences.FPref.UI_OVERLAY_ABILITY_ICONS); + } + + public static boolean showCardIdOverlay(final CardView card) { + return card.getId() > 0 && isShowingOverlays(card) && isPreferenceEnabled(ForgePreferences.FPref.UI_OVERLAY_CARD_ID); + } + + public static boolean drawGray(final CardView card) { + if (card == null) + return false; + return card.wasDestroyed() || card.isPhasedOut(); + } + public static boolean drawFoil(final CardView card) { + if (card == null) + return false; + if (isPreferenceEnabled(ForgePreferences.FPref.UI_OVERLAY_FOIL_EFFECT)) + return card.hasPaperFoil(); // TODO the Card BG should be the texture instead of the Foil Overlay + return false; + } + public static boolean drawCracks(final CardView card, final boolean isMagnify) { + if (card == null) + return false; + if (isMagnify) + return false; + return card.getDamage() > 0; + } + +} diff --git a/forge-gui/res/skins/default/holofoil.png b/forge-gui/res/skins/default/holofoil.png new file mode 100644 index 00000000000..af338fadf9c Binary files /dev/null and b/forge-gui/res/skins/default/holofoil.png differ