Refactor Foil Effect for Mobile

Should fix rendering for Full, Crop and Art renders
This commit is contained in:
Anthony Calosa
2025-07-29 19:42:01 +08:00
parent f5e96bc756
commit 3b4c417549
17 changed files with 387 additions and 187 deletions

View File

@@ -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");

View File

@@ -410,8 +410,10 @@ public class Card extends GameEntity implements Comparable<Card>, 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<Card>, 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();

View File

@@ -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() {

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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" +

View File

@@ -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<Integer, FSkinFont> fonts;
@@ -51,6 +53,7 @@ public class Assets implements Disposable {
private TextureParameter textureParameter;
private ObjectMap<String, Font> 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<>();

View File

@@ -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");

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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<T> extends FList<T> 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<T> extends FList<T> 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<T> extends FList<T> 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<T> extends FList<T> 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<T> extends FList<T> 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

View File

@@ -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;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB