diff --git a/src/client/java/minicraft/core/Renderer.java b/src/client/java/minicraft/core/Renderer.java index 8d92bab9d..3a4d66464 100644 --- a/src/client/java/minicraft/core/Renderer.java +++ b/src/client/java/minicraft/core/Renderer.java @@ -203,7 +203,7 @@ private static void renderLevel() { for (int y = 0; y < 28; y++) for (int x = 0; x < 48; x++) { // Creates the background for the sky (and dungeon) level: - screen.render(x * 8 - ((xScroll / 4) & 7), y * 8 - ((yScroll / 4) & 7), 0, 0, 0, cloud); + screen.render(null, x * 8 - ((xScroll / 4) & 7), y * 8 - ((yScroll / 4) & 7), 0, 0, 0, cloud); } } @@ -226,7 +226,7 @@ private static void renderGui() { // This draws the black square where the selected item would be if you were holding it if (!isMode("minicraft.settings.mode.creative") || player.activeItem != null) { for (int x = 10; x < 26; x++) { - screen.render(x * 8, Screen.h - 8, 5, 2, 0, hudSheet.getSheet()); + screen.render(null, x * 8, Screen.h - 8, 5, 2, 0, hudSheet.getSheet()); } } @@ -242,11 +242,11 @@ private static void renderGui() { int ac = player.getInventory().count(Items.arrowItem); // "^" is an infinite symbol. if (isMode("minicraft.settings.mode.creative") || ac >= 10000) - Font.drawBackground(" x" + "^", screen, 84, Screen.h - 16); + Font.drawBackground(null, " x" + "^", screen, 84, Screen.h - 16); else - Font.drawBackground(" x" + ac, screen, 84, Screen.h - 16); + Font.drawBackground(null, " x" + ac, screen, 84, Screen.h - 16); // Displays the arrow icon - screen.render(10 * 8 + 4, Screen.h - 16, 4, 1, 0, hudSheet.getSheet()); + screen.render(null, 10 * 8 + 4, Screen.h - 16, 4, 1, 0, hudSheet.getSheet()); } } @@ -364,16 +364,16 @@ private static void renderGui() { for (int i = 1; i <= 30; i++) { // Renders your current red default hearts, golden hearts for 20 HP, obsidian hearts for 30 HP, or black hearts for damaged health. if (i < 11) { - screen.render((i - 1) * 8, Screen.h - 16, 0, 1, 0, hudSheet.getSheet()); // Empty Hearts + screen.render(null, (i - 1) * 8, Screen.h - 16, 0, 1, 0, hudSheet.getSheet()); // Empty Hearts } if (i < player.health + 1 && i < 11) { - screen.render((i - 1) * 8, Screen.h - 16, 0, 0, 0, hudSheet.getSheet()); // Red Hearts + screen.render(null, (i - 1) * 8, Screen.h - 16, 0, 0, 0, hudSheet.getSheet()); // Red Hearts } if (i < player.health + 1 && i < 21 && i >= 11) { - screen.render((i - 11) * 8, Screen.h - 16, 0, 2, 0, hudSheet.getSheet()); // Yellow Hearts + screen.render(null, (i - 11) * 8, Screen.h - 16, 0, 2, 0, hudSheet.getSheet()); // Yellow Hearts } if (i < player.health + 1 && i >= 21) { - screen.render((i - 21) * 8, Screen.h - 16, 0, 3, 0, hudSheet.getSheet()); // Obsidian Hearts + screen.render(null, (i - 21) * 8, Screen.h - 16, 0, 3, 0, hudSheet.getSheet()); // Obsidian Hearts } } for (int i = 0; i < Player.maxStat; i++) { @@ -381,30 +381,30 @@ private static void renderGui() { // Renders armor int armor = player.armor * Player.maxStat / Player.maxArmor; if (i <= armor && player.curArmor != null) { - screen.render(i * 8, Screen.h - 24, player.curArmor.sprite); + screen.render(null, i * 8, Screen.h - 24, player.curArmor.sprite); } if (player.staminaRechargeDelay > 0) { // Creates the white/gray blinking effect when you run out of stamina. if (player.staminaRechargeDelay / 4 % 2 == 0) { - screen.render(i * 8, Screen.h - 8, 1, 2, 0, hudSheet.getSheet()); + screen.render(null, i * 8, Screen.h - 8, 1, 2, 0, hudSheet.getSheet()); } else { - screen.render(i * 8, Screen.h - 8, 1, 1, 0, hudSheet.getSheet()); + screen.render(null, i * 8, Screen.h - 8, 1, 1, 0, hudSheet.getSheet()); } } else { // Renders your current stamina, and uncharged gray stamina. if (i < player.stamina) { - screen.render(i * 8, Screen.h - 8, 1, 0, 0, hudSheet.getSheet()); + screen.render(null, i * 8, Screen.h - 8, 1, 0, 0, hudSheet.getSheet()); } else { - screen.render(i * 8, Screen.h - 8, 1, 1, 0, hudSheet.getSheet()); + screen.render(null, i * 8, Screen.h - 8, 1, 1, 0, hudSheet.getSheet()); } } // Renders hunger if (i < player.hunger) { - screen.render(i * 8 + (Screen.w - 80), Screen.h - 16, 2, 0, 0, hudSheet.getSheet()); + screen.render(null, i * 8 + (Screen.w - 80), Screen.h - 16, 2, 0, 0, hudSheet.getSheet()); } else { - screen.render(i * 8 + (Screen.w - 80), Screen.h - 16, 2, 1, 0, hudSheet.getSheet()); + screen.render(null, i * 8 + (Screen.w - 80), Screen.h - 16, 2, 1, 0, hudSheet.getSheet()); } } } @@ -438,20 +438,20 @@ public static void renderBossbar(int length, String title) { int ACTIVE_BOSSBAR = 5; // sprite x position - screen.render(x + (max_bar_length * 2), y, 0, INACTIVE_BOSSBAR, 1, hudSheet.getSheet()); // left corner + screen.render(null, x + (max_bar_length * 2), y, 0, INACTIVE_BOSSBAR, 1, hudSheet.getSheet()); // left corner // The middle for (int bx = 0; bx < max_bar_length; bx++) { for (int by = 0; by < 1; by++) { - screen.render(x + bx * 2, y + by * 8, 3, INACTIVE_BOSSBAR, 0, hudSheet.getSheet()); + screen.render(null, x + bx * 2, y + by * 8, 3, INACTIVE_BOSSBAR, 0, hudSheet.getSheet()); } } - screen.render(x - 5, y, 0, ACTIVE_BOSSBAR, 0, hudSheet.getSheet()); // right corner + screen.render(null, x - 5, y, 0, ACTIVE_BOSSBAR, 0, hudSheet.getSheet()); // right corner for (int bx = 0; bx < bar_length; bx++) { for (int by = 0; by < 1; by++) { - screen.render(x + bx * 2, y + by * 8, 3, ACTIVE_BOSSBAR, 0, hudSheet.getSheet()); + screen.render(null, x + bx * 2, y + by * 8, 3, ACTIVE_BOSSBAR, 0, hudSheet.getSheet()); } } @@ -553,24 +553,24 @@ private static void renderFocusNagger() { int h = 1; // Renders the four corners of the box - screen.render(xx - 8, yy - 8, 0, 6, 0, hudSheet.getSheet()); - screen.render(xx + w * 8, yy - 8, 0, 6, 1, hudSheet.getSheet()); - screen.render(xx - 8, yy + 8, 0, 6, 2, hudSheet.getSheet()); - screen.render(xx + w * 8, yy + 8, 0, 6, 3, hudSheet.getSheet()); + screen.render(null, xx - 8, yy - 8, 0, 6, 0, hudSheet.getSheet()); + screen.render(null, xx + w * 8, yy - 8, 0, 6, 1, hudSheet.getSheet()); + screen.render(null, xx - 8, yy + 8, 0, 6, 2, hudSheet.getSheet()); + screen.render(null, xx + w * 8, yy + 8, 0, 6, 3, hudSheet.getSheet()); // Renders each part of the box... for (int x = 0; x < w; x++) { - screen.render(xx + x * 8, yy - 8, 1, 6, 0, hudSheet.getSheet()); // ...Top part - screen.render(xx + x * 8, yy + 8, 1, 6, 2, hudSheet.getSheet()); // ...Bottom part + screen.render(null, xx + x * 8, yy - 8, 1, 6, 0, hudSheet.getSheet()); // ...Top part + screen.render(null, xx + x * 8, yy + 8, 1, 6, 2, hudSheet.getSheet()); // ...Bottom part } for (int y = 0; y < h; y++) { - screen.render(xx - 8, yy + y * 8, 2, 6, 0, hudSheet.getSheet()); // ...Left part - screen.render(xx + w * 8, yy + y * 8, 2, 6, 1, hudSheet.getSheet()); // ...Right part + screen.render(null, xx - 8, yy + y * 8, 2, 6, 0, hudSheet.getSheet()); // ...Left part + screen.render(null, xx + w * 8, yy + y * 8, 2, 6, 1, hudSheet.getSheet()); // ...Right part } // The middle for (int x = 0; x < w; x++) { - screen.render(xx + x * 8, yy, 3, 6, 0, hudSheet.getSheet()); + screen.render(null, xx + x * 8, yy, 3, 6, 0, hudSheet.getSheet()); } // Renders the focus nagger text with a flash effect... diff --git a/src/client/java/minicraft/entity/Arrow.java b/src/client/java/minicraft/entity/Arrow.java index 8b565c286..88c62b79e 100644 --- a/src/client/java/minicraft/entity/Arrow.java +++ b/src/client/java/minicraft/entity/Arrow.java @@ -94,6 +94,6 @@ public boolean isSolid() { @Override public void render(Screen screen) { - screen.render(x - 4, y - 4, sprite); + screen.render(null, x - 4, y - 4, sprite); } } diff --git a/src/client/java/minicraft/entity/FireSpark.java b/src/client/java/minicraft/entity/FireSpark.java index 6a67764de..c753d75c5 100644 --- a/src/client/java/minicraft/entity/FireSpark.java +++ b/src/client/java/minicraft/entity/FireSpark.java @@ -99,8 +99,8 @@ public void render(Screen screen) { int xt = 8; int yt = 13; - screen.render(x - 4, y - 4 + 2, sprite.getSprite(), randmirror, false, Color.BLACK); // renders the shadow on the ground - screen.render(x - 4, y - 4 - 2, sprite.getSprite(), randmirror, false, Color.RED); // Renders the spark + screen.render(null, x - 4, y - 4 + 2, sprite.getSprite(), randmirror, false, Color.BLACK); // renders the shadow on the ground + screen.render(null, x - 4, y - 4 - 2, sprite.getSprite(), randmirror, false, Color.RED); // Renders the spark } /** diff --git a/src/client/java/minicraft/entity/ItemEntity.java b/src/client/java/minicraft/entity/ItemEntity.java index f12622bf1..a02f3bc1a 100644 --- a/src/client/java/minicraft/entity/ItemEntity.java +++ b/src/client/java/minicraft/entity/ItemEntity.java @@ -128,8 +128,8 @@ public void render(Screen screen) { if (time / 6 % 2 == 0) return; } - screen.render(x - 4, y - 4, item.sprite.getSprite(), 0, false, Color.get(0, 31)); // Item shadow - screen.render(x - 4, y - 4 - (int) zz, item.sprite); // Item + screen.render(null, x - 4, y - 4, item.sprite.getSprite(), 0, false, Color.get(0, 31)); // Item shadow + screen.render(null, x - 4, y - 4 - (int) zz, item.sprite); // Item } @Override diff --git a/src/client/java/minicraft/entity/Spark.java b/src/client/java/minicraft/entity/Spark.java index 049d45d88..8438d4cf8 100644 --- a/src/client/java/minicraft/entity/Spark.java +++ b/src/client/java/minicraft/entity/Spark.java @@ -78,8 +78,8 @@ public void render(Screen screen) { } sprite.setMirror(randmirror); - screen.render(x - 4, y - 4 + 2, sprite.getSprite(), 0, false, Color.BLACK); // renders the shadow on the ground - screen.render(x - 4, y - 4 - 2, sprite); // Renders the spark + screen.render(null, x - 4, y - 4 + 2, sprite.getSprite(), 0, false, Color.BLACK); // renders the shadow on the ground + screen.render(null, x - 4, y - 4 - 2, sprite); // Renders the spark } /** diff --git a/src/client/java/minicraft/entity/furniture/Furniture.java b/src/client/java/minicraft/entity/furniture/Furniture.java index 2f0cc22a8..bca79b017 100644 --- a/src/client/java/minicraft/entity/furniture/Furniture.java +++ b/src/client/java/minicraft/entity/furniture/Furniture.java @@ -73,7 +73,7 @@ public void tick() { * Draws the furniture on the screen. */ public void render(Screen screen) { - screen.render(x - 8, y - 8, sprite); + screen.render(null, x - 8, y - 8, sprite); } /** diff --git a/src/client/java/minicraft/entity/mob/MobAi.java b/src/client/java/minicraft/entity/mob/MobAi.java index 00c2df1eb..570d48928 100644 --- a/src/client/java/minicraft/entity/mob/MobAi.java +++ b/src/client/java/minicraft/entity/mob/MobAi.java @@ -135,9 +135,9 @@ public void render(Screen screen) { LinkedSprite curSprite = sprites[dir.getDir()][(walkDist >> 3) % sprites[dir.getDir()].length]; if (hurtTime > 0) { - screen.render(xo, yo, curSprite.getSprite(), true); + screen.render(null, xo, yo, curSprite.getSprite(), true); } else { - screen.render(xo, yo, curSprite.getSprite()); + screen.render(null, xo, yo, curSprite.getSprite()); } } diff --git a/src/client/java/minicraft/entity/mob/Player.java b/src/client/java/minicraft/entity/mob/Player.java index 385e78052..a32902f29 100644 --- a/src/client/java/minicraft/entity/mob/Player.java +++ b/src/client/java/minicraft/entity/mob/Player.java @@ -865,21 +865,21 @@ public void render(Screen screen) { // animation effect if (tickTime / 8 % 2 == 0) { - screen.render(xo + 0, yo + 3, 5, 0, 0, hudSheet.getSheet()); // Render the water graphic - screen.render(xo + 8, yo + 3, 5, 0, 1, hudSheet.getSheet()); // Render the mirrored water graphic to the right. + screen.render(null, xo + 0, yo + 3, 5, 0, 0, hudSheet.getSheet()); // Render the water graphic + screen.render(null, xo + 8, yo + 3, 5, 0, 1, hudSheet.getSheet()); // Render the mirrored water graphic to the right. } else { - screen.render(xo + 0, yo + 3, 5, 1, 0, hudSheet.getSheet()); - screen.render(xo + 8, yo + 3, 5, 1, 1, hudSheet.getSheet()); + screen.render(null, xo + 0, yo + 3, 5, 1, 0, hudSheet.getSheet()); + screen.render(null, xo + 8, yo + 3, 5, 1, 1, hudSheet.getSheet()); } } else if (level.getTile(x >> 4, y >> 4) == Tiles.get("lava")) { if (tickTime / 8 % 2 == 0) { - screen.render(xo + 0, yo + 3, 6, 0, 1, hudSheet.getSheet()); // Render the lava graphic - screen.render(xo + 8, yo + 3, 6, 0, 0, hudSheet.getSheet()); // Render the mirrored lava graphic to the right. + screen.render(null, xo + 0, yo + 3, 6, 0, 1, hudSheet.getSheet()); // Render the lava graphic + screen.render(null, xo + 8, yo + 3, 6, 0, 0, hudSheet.getSheet()); // Render the mirrored lava graphic to the right. } else { - screen.render(xo + 0, yo + 3, 6, 1, 1, hudSheet.getSheet()); - screen.render(xo + 8, yo + 3, 6, 1, 0, hudSheet.getSheet()); + screen.render(null, xo + 0, yo + 3, 6, 1, 1, hudSheet.getSheet()); + screen.render(null, xo + 8, yo + 3, 6, 1, 0, hudSheet.getSheet()); } } } @@ -887,10 +887,10 @@ public void render(Screen screen) { // Renders indicator for what tile the item will be placed on if (activeItem instanceof TileItem && !isSwimming()) { Point t = getInteractionTile(); - screen.render(t.x * 16, t.y * 16, 3, 2, 0, hudSheet.getSheet()); - screen.render(t.x * 16 + 8, t.y * 16, 3, 2, 1, hudSheet.getSheet()); - screen.render(t.x * 16, t.y * 16 + 8, 3, 2, 2, hudSheet.getSheet()); - screen.render(t.x * 16 + 8, t.y * 16 + 8, 3, 2, 3, hudSheet.getSheet()); + screen.render(null, t.x * 16, t.y * 16, 3, 2, 0, hudSheet.getSheet()); + screen.render(null, t.x * 16 + 8, t.y * 16, 3, 2, 1, hudSheet.getSheet()); + screen.render(null, t.x * 16, t.y * 16 + 8, 3, 2, 2, hudSheet.getSheet()); + screen.render(null, t.x * 16 + 8, t.y * 16 + 8, 3, 2, 3, hudSheet.getSheet()); } // Makes the player white if they have just gotten hurt @@ -906,16 +906,16 @@ public void render(Screen screen) { // This makes falling look really cool. int spriteToUse = Math.round(onFallDelay / 2f) % carrySprites.length; curSprite = carrySprites[spriteToUse][(walkDist >> 3) & 1]; - screen.render(xo, yo - 4 * onFallDelay, curSprite.setColor(shirtColor)); + screen.render(null, xo, yo - 4 * onFallDelay, curSprite.setColor(shirtColor)); } else { curSprite = spriteSet[dir.getDir()][(walkDist >> 3) & 1]; // Gets the correct sprite to render. // Render each corner of the sprite if (isSwimming()) { Sprite sprite = curSprite.getSprite(); - screen.render(xo, yo, sprite.spritePixels[0][0], shirtColor); - screen.render(xo + 8, yo, sprite.spritePixels[0][1], shirtColor); + screen.render(null, xo, yo, sprite.spritePixels[0][0], shirtColor); + screen.render(null, xo + 8, yo, sprite.spritePixels[0][1], shirtColor); } else { // Don't render the bottom half if swimming. - screen.render(xo, yo - 4 * onFallDelay, curSprite.setColor(shirtColor)); + screen.render(null, xo, yo - 4 * onFallDelay, curSprite.setColor(shirtColor)); } } @@ -923,31 +923,31 @@ public void render(Screen screen) { if (attackTime > 0) { switch (attackDir) { case UP: // If currently attacking upwards... - screen.render(xo + 0, yo - 4, 3, 0, 0, hudSheet.getSheet()); // Render left half-slash - screen.render(xo + 8, yo - 4, 3, 0, 1, hudSheet.getSheet()); // Render right half-slash (mirror of left). + screen.render(null, xo + 0, yo - 4, 3, 0, 0, hudSheet.getSheet()); // Render left half-slash + screen.render(null, xo + 8, yo - 4, 3, 0, 1, hudSheet.getSheet()); // Render right half-slash (mirror of left). if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { // If the player had an item when they last attacked... - screen.render(xo + 4, yo - 4, attackItem.sprite.getSprite(), 1, false); // Then render the icon of the item, mirrored + screen.render(null, xo + 4, yo - 4, attackItem.sprite.getSprite(), 1, false); // Then render the icon of the item, mirrored } break; case LEFT: // Attacking to the left... (Same as above) - screen.render(xo - 4, yo, 4, 0, 1, hudSheet.getSheet()); - screen.render(xo - 4, yo + 8, 4, 0, 3, hudSheet.getSheet()); + screen.render(null, xo - 4, yo, 4, 0, 1, hudSheet.getSheet()); + screen.render(null, xo - 4, yo + 8, 4, 0, 3, hudSheet.getSheet()); if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { - screen.render(xo - 4, yo + 4, attackItem.sprite.getSprite(), 1, false); + screen.render(null, xo - 4, yo + 4, attackItem.sprite.getSprite(), 1, false); } break; case RIGHT: // Attacking to the right (Same as above) - screen.render(xo + 8 + 4, yo, 4, 0, 0, hudSheet.getSheet()); - screen.render(xo + 8 + 4, yo + 8, 4, 0, 2, hudSheet.getSheet()); + screen.render(null, xo + 8 + 4, yo, 4, 0, 0, hudSheet.getSheet()); + screen.render(null, xo + 8 + 4, yo + 8, 4, 0, 2, hudSheet.getSheet()); if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { - screen.render(xo + 8 + 4, yo + 4, attackItem.sprite.getSprite()); + screen.render(null, xo + 8 + 4, yo + 4, attackItem.sprite.getSprite()); } break; case DOWN: // Attacking downwards (Same as above) - screen.render(xo + 0, yo + 8 + 4, 3, 0, 2, hudSheet.getSheet()); - screen.render(xo + 8, yo + 8 + 4, 3, 0, 3, hudSheet.getSheet()); + screen.render(null, xo + 0, yo + 8 + 4, 3, 0, 2, hudSheet.getSheet()); + screen.render(null, xo + 8, yo + 8 + 4, 3, 0, 3, hudSheet.getSheet()); if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { - screen.render(xo + 4, yo + 8 + 4, attackItem.sprite.getSprite()); + screen.render(null, xo + 4, yo + 8 + 4, attackItem.sprite.getSprite()); } break; case NONE: @@ -959,16 +959,16 @@ public void render(Screen screen) { if (isFishing) { switch (dir) { case UP: - screen.render(xo + 4, yo - 4, activeItem.sprite.getSprite(), 1, false); + screen.render(null, xo + 4, yo - 4, activeItem.sprite.getSprite(), 1, false); break; case LEFT: - screen.render(xo - 4, yo + 4, activeItem.sprite.getSprite(), 1, false); + screen.render(null, xo - 4, yo + 4, activeItem.sprite.getSprite(), 1, false); break; case RIGHT: - screen.render(xo + 8 + 4, yo + 4, activeItem.sprite.getSprite()); + screen.render(null, xo + 8 + 4, yo + 4, activeItem.sprite.getSprite()); break; case DOWN: - screen.render(xo + 4, yo + 8 + 4, activeItem.sprite.getSprite()); + screen.render(null, xo + 4, yo + 8 + 4, activeItem.sprite.getSprite()); break; case NONE: break; diff --git a/src/client/java/minicraft/entity/mob/Sheep.java b/src/client/java/minicraft/entity/mob/Sheep.java index f8c1dc583..aba835d4e 100644 --- a/src/client/java/minicraft/entity/mob/Sheep.java +++ b/src/client/java/minicraft/entity/mob/Sheep.java @@ -35,9 +35,9 @@ public void render(Screen screen) { LinkedSprite curSprite = curAnim[dir.getDir()][(walkDist >> 3) % curAnim[dir.getDir()].length]; if (hurtTime > 0) { - screen.render(xo, yo, curSprite.getSprite(), true); + screen.render(null, xo, yo, curSprite.getSprite(), true); } else { - screen.render(xo, yo, curSprite); + screen.render(null, xo, yo, curSprite); } } diff --git a/src/client/java/minicraft/entity/particle/Particle.java b/src/client/java/minicraft/entity/particle/Particle.java index 04e0382ec..0375562d9 100644 --- a/src/client/java/minicraft/entity/particle/Particle.java +++ b/src/client/java/minicraft/entity/particle/Particle.java @@ -51,7 +51,7 @@ public void tick() { @Override public void render(Screen screen) { - screen.render(x, y, sprite); + screen.render(null, x, y, sprite); } @Override diff --git a/src/client/java/minicraft/gfx/Font.java b/src/client/java/minicraft/gfx/Font.java index dc8eb1766..118c36612 100644 --- a/src/client/java/minicraft/gfx/Font.java +++ b/src/client/java/minicraft/gfx/Font.java @@ -2,6 +2,8 @@ import minicraft.core.Renderer; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.screen.entry.ListEntry; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Arrays; @@ -22,24 +24,25 @@ public class Font { /* The order of the letters in the chars string is represented in the order that they appear in the sprite-sheet. */ public static void draw(String msg, Screen screen, int x, int y) { - draw(msg, screen, x, y, -1); + draw(null, msg, screen, x, y, -1); } + public static void draw(@Nullable Screen.RenderingLimitingModel bounds, String msg, Screen screen, int x, int y) { draw(bounds, msg, screen, x, y, -1); } /** * Draws the message to the x & y coordinates on the screen. */ - public static void - draw(String msg, Screen screen, int x, int y, int whiteTint) { + public static void draw(String msg, Screen screen, int x, int y, int whiteTint) { draw(null, msg, screen, x, y, whiteTint); } + public static void draw(@Nullable Screen.RenderingLimitingModel bounds, String msg, Screen screen, int x, int y, int whiteTint) { for (int i = 0; i < msg.length(); i++) { // Loops through all the characters that you typed int ix = chars.indexOf(msg.charAt(i)); // The current letter in the message loop if (ix >= 0) { // If that character's position is larger than or equal to 0, then render the character on the screen. - screen.render(x + i * textWidth(msg.substring(i, i + 1)), y, ix % 32, ix / 32, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "font"), whiteTint); + screen.render(bounds, x + i * textWidth(msg.substring(i, i + 1)), y, ix % 32, ix / 32, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "font"), whiteTint); } } } - public static void drawColor(String message, Screen screen, int x, int y) { + public static void drawColor(@Nullable Screen.RenderingLimitingModel bounds, String message, Screen screen, int x, int y) { // Set default color message if it doesn't have initially if (message.charAt(0) != Color.COLOR_CHAR) { message = Color.WHITE_CODE + message; @@ -63,22 +66,24 @@ public static void drawColor(String message, Screen screen, int x, int y) { color = Color.WHITE_CODE; } - Font.draw(text, screen, x + leading, y, Color.get(color)); + Font.draw(bounds, text, screen, x + leading, y, Color.get(color)); leading += Font.textWidth(text); } } public static void drawBackground(String msg, Screen screen, int x, int y) { - drawBackground(msg, screen, x, y, -1); + drawBackground(null, msg, screen, x, y, -1); } + public static void drawBackground(@Nullable Screen.RenderingLimitingModel bounds, String msg, Screen screen, int x, int y) { drawBackground(bounds, msg, screen, x, y, -1); } - public static void drawBackground(String msg, Screen screen, int x, int y, int whiteTint) { + public static void drawBackground(String msg, Screen screen, int x, int y, int whiteTint) { drawBackground(null, msg, screen, x, y, whiteTint); } + public static void drawBackground(@Nullable Screen.RenderingLimitingModel bounds, String msg, Screen screen, int x, int y, int whiteTint) { for (int i = 0; i < msg.length(); i++) { // Renders the black boxes under the text - screen.render(x + i * textWidth(msg.substring(i, i + 1)), y, 5, 2, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "hud")); + screen.render(null, x + i * textWidth(msg.substring(i, i + 1)), y, 5, 2, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "hud")); } // Renders the text - draw(msg, screen, x, y, whiteTint); + draw(bounds, msg, screen, x, y, whiteTint); } public static int textWidth(String text) { // Filtering out coloring codes. diff --git a/src/client/java/minicraft/gfx/Rectangle.java b/src/client/java/minicraft/gfx/Rectangle.java index 3aeeb0d4d..9c9467612 100644 --- a/src/client/java/minicraft/gfx/Rectangle.java +++ b/src/client/java/minicraft/gfx/Rectangle.java @@ -12,10 +12,8 @@ public class Rectangle { public Rectangle() { } // 0 all. - public Rectangle(int x, int y, int x1, int y1, int type) { if (type < 0 || type > 2) type = 0; - if (type != CENTER_DIMS) { // x and y are the coords of the top left corner. this.x = x; this.y = y; @@ -36,7 +34,6 @@ public Rectangle(int x, int y, int x1, int y1, int type) { public Rectangle(Point p, Dimension d) { this(false, p, d); } - public Rectangle(boolean isCenter, Point p, Dimension d) { this(p.x, p.y, d.width, d.height, isCenter ? CENTER_DIMS : CORNER_DIMS); } @@ -48,12 +45,8 @@ public Rectangle(Rectangle model) { h = model.h; } - public int getLeft() { - return x; - } - - public int getRight() { - return x + w; + public int getLeft() { return x; } + public int getRight() { return x + w; } public int getTop() { @@ -62,24 +55,18 @@ public int getTop() { public int getBottom() { return y + h; - } +} public int getWidth() { return w; - } - - public int getHeight() { - return h; - } + }public int getHeight() { return h; } - public Point getCenter() { - return new Point(x + w / 2, y + h / 2); + public Point getCenter() { return new Point(x + w/2, y + h/2); } public Dimension getSize() { return new Dimension(w, h); - } - +} public Point getPosition(RelPos relPos) { Point p = new Point(x, y); p.x += relPos.xIndex * w / 2; @@ -95,10 +82,12 @@ public boolean intersects(Rectangle other) { ); } - public void setPosition(Point p, RelPos relPos) { - setPosition(p.x, p.y, relPos); + public boolean contains(Point pt) { return contains(pt.x, pt.y); } + public boolean contains(int x, int y) { // inclusive + return getLeft() <= x && x <= getRight() && getTop() <= y && y <= getBottom(); } + public void setPosition(Point p, RelPos relPos) { setPosition(p.x, p.y, relPos); } public void setPosition(int x, int y, RelPos relPos) { this.x = x - relPos.xIndex * w / 2; this.y = y - relPos.yIndex * h / 2; @@ -112,7 +101,6 @@ public void translate(int xoff, int yoff) { public void setSize(Dimension d, RelPos anchor) { setSize(d.width, d.height, anchor); } - public void setSize(int width, int height, RelPos anchor) { Point p = getPosition(anchor); this.w = width; diff --git a/src/client/java/minicraft/gfx/Screen.java b/src/client/java/minicraft/gfx/Screen.java index dbc05cb22..f384e8209 100644 --- a/src/client/java/minicraft/gfx/Screen.java +++ b/src/client/java/minicraft/gfx/Screen.java @@ -2,10 +2,15 @@ import minicraft.core.Renderer; import minicraft.core.Updater; +import minicraft.core.io.InputHandler; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.screen.RelPos; +import minicraft.screen.entry.SelectableStringEntry; import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.awt.AlphaComposite; import java.awt.Graphics2D; @@ -93,9 +98,12 @@ private class SpriteRendering implements Rendering { private final int xp, yp, xt, yt, tw, th, mirrors, whiteTint, color; private final boolean fullBright; private final MinicraftImage sheet; + private final @Nullable RenderingLimitingModel limitingModel; - public SpriteRendering(int xp, int yp, int xt, int yt, int tw, int th, - int mirrors, int whiteTint, boolean fullBright, int color, MinicraftImage sheet) { + public SpriteRendering(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, + int tw, int th, int mirrors, int whiteTint, boolean fullBright, int color, + MinicraftImage sheet) { + this.limitingModel = limitingModel; this.xp = xp; this.yp = yp; this.xt = xt; @@ -121,6 +129,7 @@ public void render(Graphics2D graphics) { int sy = mirrorY ? th - 1 - y : y; // Source relative; reverse if necessary for (int x = 0; x < tw; ++x) { // Relative if (x + xp < 0) continue; // Skip rest if out of bounds. + if (limitingModel != null && !limitingModel.contains(x + xp, y + yp)) continue; if (x + xp >= w) break; int sx = mirrorX ? tw - 1 - x : x; // Source relative; reverse if necessary int col = sheet.pixels[toffs + sx + sy * sheet.width]; // Gets the color of the current pixel from the value stored in the sheet. @@ -284,103 +293,414 @@ public void flush() { } while ((rendering = renderings.poll()) != null); } - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet) { - render(xp, yp, xt, yt, bits, sheet, -1); + /** Inclusive bounds for rendering */ + public static abstract class RenderingLimitingModel { + public abstract int getLeftBound(); + public abstract int getRightBound(); + public abstract int getTopBound(); + public abstract int getBottomBound(); + + public boolean contains(int x, int y) { // inclusive + return getLeftBound() <= x && x <= getRightBound() && getTopBound() <= y && y <= getBottomBound(); + } + } + + /** The basic class of a GUI entry. */ + public interface ScreenEntry { + int getWidth(); + void tick(InputHandler input); + void tickScrollingTicker(SelectableStringEntry.EntryXAccessor accessor); + boolean isScrollingTickerSet(); + void render(Screen screen, @Nullable RenderingLimitingModel limitingModel, int x, int y, boolean selected); + void render(Screen screen, @Nullable RenderingLimitingModel limitingModel, int x, int y, boolean selected, + String contain, int containColor); + + /** All values here should be in the same relative coordinate system. */ + interface EntryXAccessor { + int getWidth(); + int getX(RelPos anchor); + void setX(RelPos anchor, int x); + void translateX(int displacement); + void setAnchors(RelPos anchor); // This is recommended to be invoked first. + int getLeftBound(RelPos anchor); + int getRightBound(RelPos anchor); + } + + abstract class EntryScrollingTicker { + protected static final int DEFAULT_CYCLING_PERIOD = 90; // in ticks + + protected int tick = 0; + + public abstract void tick(@NotNull EntryXAccessor accessor); + } + + class ExceedingHorizontallyAlternatingScrollingTicker extends EntryScrollingTicker { + @Range(from = -1, to = 1) + private int direction = 0; // Number line direction; text movement + + @Override + public void tick(@NotNull EntryXAccessor accessor) { + RelPos refAnchor = RelPos.getPos(1 - direction, 0); + accessor.setAnchors(refAnchor); + int x = accessor.getX(refAnchor); + // Proceeds when the entry is out of bounds. + if (x < accessor.getLeftBound(refAnchor) || x > accessor.getRightBound(refAnchor)) { + if (direction != 0) { + if (tick++ == 5) { + x += direction * MinicraftImage.boxWidth; + if ((direction == 1 ? x - accessor.getLeftBound(refAnchor) : + accessor.getRightBound(refAnchor) - x) >= 0) { + // Alignment correction + x = direction == 1 ? accessor.getLeftBound(refAnchor) : accessor.getRightBound(refAnchor); + direction = 0; // Stops when destination is reached. + } + + accessor.setX(refAnchor, x); + tick = 0; + } + } else if (tick++ == DEFAULT_CYCLING_PERIOD) { + if (x <= accessor.getRightBound(refAnchor)) + direction = 1; // Right + else + direction = -1; // Left + tick = 0; + } + } else tick = 0; + } + } + + class HorizontalScrollerScrollingTicker extends EntryScrollingTicker { + @MagicConstant(intValues = {-1, 1}) + private final int direction; + + public HorizontalScrollerScrollingTicker(@MagicConstant int direction) { + switch (direction) { + case -1: case 1: + this.direction = direction; break; + default: + throw new IllegalArgumentException("direction; input: " + direction); + } + } + + private boolean moving = false; + + @Override + public void tick(@NotNull EntryXAccessor accessor) { + RelPos refAnchor = direction == 1 ? RelPos.LEFT : RelPos.RIGHT; + accessor.setAnchors(refAnchor); + int x = accessor.getX(refAnchor); + int width = accessor.getWidth(); + int lw = direction == -1 ? -width : 0; + int rw = direction == 1 ? width : 0; + // Proceeds when the entry is out of bounds. + if (x < accessor.getLeftBound(refAnchor) || x > accessor.getRightBound(refAnchor)) { + if (moving) { + if (tick++ == 5) { + if (direction == 1 && x >= accessor.getRightBound(refAnchor) + rw) { // Left side reaches right bound + x += accessor.getLeftBound(refAnchor) - x - width; + } else if (direction == -1 && x <= accessor.getLeftBound(refAnchor) + lw) { + x += accessor.getRightBound(refAnchor) - x + width; + } else { + x += direction * MinicraftImage.boxWidth; + } + + int diff = direction == 1 ? accessor.getRightBound(refAnchor) - x : + x - accessor.getLeftBound(refAnchor); + if (diff >= 0 && diff < MinicraftImage.boxWidth) { // Moves back to the original point + moving = false; // Pauses the scrolling + // Alignment correction + x = direction == 1 ? accessor.getRightBound(refAnchor) : accessor.getLeftBound(refAnchor); + } + + accessor.setX(refAnchor, x); + tick = 0; + } + } else if (tick++ == DEFAULT_CYCLING_PERIOD) { + moving = true; + tick = 0; + } + } else tick = 0; + } + } + } + + public static abstract class EntryRenderingUnit { + protected abstract class EntryLimitingModel extends RenderingLimitingModel { + @Override + public int getLeftBound() { + return getEntryBounds().getLeft(); + } + + @Override + public int getRightBound() { + return getEntryBounds().getRight() - 1; // As this model is inclusive. + } + + @Override + public int getTopBound() { + return getEntryBounds().getTop(); + } + + @Override + public int getBottomBound() { + return getEntryBounds().getBottom() - 1; // As this model is inclusive. + } + } + + protected abstract class EntryXAccessor implements SelectableStringEntry.EntryXAccessor { + /* Most of the methods here can be obtained by algebra. */ + + @Override + public int getWidth() { + return getDelegate().getWidth(); + } + + @Override + public int getX(RelPos anchor) { + return xPos + (containerAnchor.xIndex - anchor.xIndex) * getEntryBounds().getWidth() / 2 + + (anchor.xIndex - entryAnchor.xIndex) * getDelegate().getWidth() / 2; + } + + @Override + public void setX(RelPos anchor, int x) { + xPos = x + (anchor.xIndex - containerAnchor.xIndex) * getEntryBounds().getWidth() / 2 + + (entryAnchor.xIndex - anchor.xIndex) * getDelegate().getWidth() / 2; + } + + @Override + public void translateX(int displacement) { + xPos += displacement; + } + + @Override + public void setAnchors(RelPos anchor) { + changeRelativeEntryAnchor(anchor); + changeRelativeContainerAnchor(anchor); + } + + @Override + public int getLeftBound(RelPos anchor) { + return anchor.xIndex * (getDelegate().getWidth() - getEntryBounds().getWidth()) / 2; + } + + @Override + public int getRightBound(RelPos anchor) { + return (2 - anchor.xIndex) * (getEntryBounds().getWidth() - getDelegate().getWidth()) / 2; + } + } + + protected abstract EntryLimitingModel getLimitingModel(); + protected abstract EntryXAccessor getXAccessor(); + + /** + * A reference anchor, which is the relative position of its container
+ * Also, it is the relative position of the entry.
+ * Acceptable values: {@code LEFT}, {@code CENTER}, {@code RIGHT} + */ + protected @NotNull RelPos containerAnchor; + /** + * A reference anchor of the entry
+ * This is usually the same as {@link #containerAnchor}. + * Acceptable values: {@code LEFT}, {@code CENTER}, {@code RIGHT} + */ + protected @NotNull RelPos entryAnchor; + /** The x-position of the entry at its anchor {@link #entryAnchor} relative to the container anchor {@link #containerAnchor} */ + protected int xPos = 0; + + /** This is used to prevent further exceptions to {@link RelPos}. + * Here, we only use the x indices for positioning, so we can just simply shrink the acceptable value range + * to an extent that we use the best. */ + private static RelPos getRelPos(@NotNull RelPos anchor) { + return RelPos.getPos(anchor.xIndex, 1); // Confirms that this meets the requirement. + } + + protected EntryRenderingUnit(@NotNull RelPos anchor) { + anchor = getRelPos(anchor); + this.containerAnchor = anchor; + this.entryAnchor = anchor; + } + protected EntryRenderingUnit(@NotNull RelPos containerAnchor, @NotNull RelPos entryAnchor) { + this.containerAnchor = getRelPos(containerAnchor); + this.entryAnchor = getRelPos(entryAnchor); + } + + protected abstract Rectangle getEntryBounds(); // Global coordinate system + protected abstract ScreenEntry getDelegate(); + + public void resetRelativeAnchorsSynced(RelPos newAnchor) { + entryAnchor = containerAnchor = newAnchor; + xPos = 0; + } + public void moveRelativeContainerAnchor(RelPos newAnchor) { + containerAnchor = newAnchor; + xPos = 0; + } + public void moveRelativeEntryAnchor(RelPos newAnchor) { + entryAnchor = newAnchor; + xPos = 0; + } + public void changeRelativeContainerAnchor(RelPos newAnchor) { + xPos += (containerAnchor.xIndex - newAnchor.xIndex) * getEntryBounds().getWidth() / 2; + containerAnchor = newAnchor; + } + public void changeRelativeEntryAnchor(RelPos newAnchor) { + xPos += (newAnchor.xIndex - entryAnchor.xIndex) * getDelegate().getWidth() / 2; + entryAnchor = newAnchor; + } + + public void tick(InputHandler input) { + getDelegate().tickScrollingTicker(getXAccessor()); + getDelegate().tick(input); + } + + protected void renderExtra(Screen screen, int x, int y, int entryWidth, boolean selected) {} + + protected boolean renderOutOfFrame() { + return false; + } + + public void render(Screen screen, int y, boolean selected) { + int w = getDelegate().getWidth(); // Reduce calculation + int x = getRenderX(w); // Reduce calculation + getDelegate().render(screen, renderOutOfFrame() ? null : getLimitingModel(), x, y, selected); + renderExtra(screen, x, y, w, selected); + } + + public void render(Screen screen, int y, boolean selected, String contain, int containColor) { + int w = getDelegate().getWidth(); // Reduce calculation + int x = getRenderX(w); // Reduce calculation + getDelegate().render(screen, renderOutOfFrame() ? null : getLimitingModel(), x, y, selected, contain, containColor); + renderExtra(screen, x, y, w, selected); + } + + protected int getRenderX(int entryWidth) { + return getEntryBounds().getLeft() + xPos - entryAnchor.xIndex * entryWidth / 2 + + containerAnchor.xIndex * getEntryBounds().getWidth() / 2; + } + } + + // Just use a menu for it. + public static final class ScreenLimitingModel extends RenderingLimitingModel { + public static final ScreenLimitingModel INSTANCE = new ScreenLimitingModel(); + + @Override + public int getLeftBound() { + return 0; + } + + @Override + public int getRightBound() { + return Screen.w - 1; + } + + @Override + public int getTopBound() { + return 0; + } + + @Override + public int getBottomBound() { + return Screen.h - 1; + } + } + + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet) { + render(limitingModel, xp, yp, xt, yt, bits, sheet, -1); } - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint) { - render(xp, yp, xt, yt, bits, sheet, whiteTint, false); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint) { + render(limitingModel, xp, yp, xt, yt, bits, sheet, whiteTint, false); } /** * This method takes care of assigning the correct spritesheet to assign to the sheet variable **/ - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright) { - render(xp, yp, xt, yt, bits, sheet, whiteTint, fullbright, 0); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright) { + render(limitingModel, xp, yp, xt, yt, bits, sheet, whiteTint, fullbright, 0); } - public void render(int xp, int yp, LinkedSprite sprite) { - render(xp, yp, sprite.getSprite()); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, LinkedSprite sprite) { + render(limitingModel, xp, yp, sprite.getSprite()); } - public void render(int xp, int yp, Sprite sprite) { - render(xp, yp, sprite, false); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite sprite) { + render(limitingModel, xp, yp, sprite, false); } - public void render(int xp, int yp, Sprite sprite, boolean fullbright) { - render(xp, yp, sprite, 0, fullbright, 0); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite sprite, boolean fullbright) { + render(limitingModel, xp, yp, sprite, 0, fullbright, 0); } - public void render(int xp, int yp, Sprite sprite, int mirror, boolean fullbright) { - render(xp, yp, sprite, mirror, fullbright, 0); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite sprite, int mirror, boolean fullbright) { + render(limitingModel, xp, yp, sprite, mirror, fullbright, 0); } - public void render(int xp, int yp, Sprite sprite, int mirror, boolean fullbright, int color) { + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite sprite, int mirror, boolean fullbright, int color) { boolean mirrorX = (mirror & BIT_MIRROR_X) > 0; // Horizontally. boolean mirrorY = (mirror & BIT_MIRROR_Y) > 0; // Vertically. for (int r = 0; r < sprite.spritePixels.length; r++) { int lr = mirrorY ? sprite.spritePixels.length - 1 - r : r; for (int c = 0; c < sprite.spritePixels[lr].length; c++) { Sprite.Px px = sprite.spritePixels[lr][mirrorX ? sprite.spritePixels[lr].length - 1 - c : c]; - render(xp + c * 8, yp + r * 8, px, mirror, sprite.color, fullbright, color); + render(limitingModel, xp + c * 8, yp + r * 8, px, mirror, sprite.color, fullbright, color); } } } - public void render(int xp, int yp, Sprite.Px pixel) { - render(xp, yp, pixel, -1); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite.Px pixel) { + render(limitingModel, xp, yp, pixel, -1); } - public void render(int xp, int yp, Sprite.Px pixel, int whiteTint) { - render(xp, yp, pixel, 0, whiteTint); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite.Px pixel, int whiteTint) { + render(limitingModel, xp, yp, pixel, 0, whiteTint); } - public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint) { - render(xp, yp, pixel, mirror, whiteTint, false); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint) { + render(limitingModel, xp, yp, pixel, mirror, whiteTint, false); } - public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint, boolean fullbright) { - render(xp, yp, pixel, mirror, whiteTint, fullbright, 0); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint, boolean fullbright) { + render(limitingModel, xp, yp, pixel, mirror, whiteTint, fullbright, 0); } - public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint, boolean fullbright, int color) { - render(xp, yp, pixel.x, pixel.y, pixel.mirror ^ mirror, pixel.sheet, whiteTint, fullbright, color); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint, boolean fullbright, int color) { + render(limitingModel, xp, yp, pixel.x, pixel.y, pixel.mirror ^ mirror, pixel.sheet, whiteTint, fullbright, color); } /** * Renders an object from the sprite sheet based on screen coordinates, tile (SpriteSheet location), colors, and bits (for mirroring). I believe that xp and yp refer to the desired position of the upper-left-most pixel. */ - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright, int color) { + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright, int color) { if (sheet == null) return; // Verifying that sheet is not null. // xp and yp are originally in level coordinates, but offset turns them to screen coordinates. // xOffset and yOffset account for screen offset - render(xp - xOffset, yp - yOffset, xt * 8, yt * 8, 8, 8, sheet, bits, whiteTint, fullbright, color); + render(limitingModel, xp - xOffset, yp - yOffset, xt * 8, yt * 8, 8, 8, sheet, bits, whiteTint, fullbright, color); } - public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet) { - render(xp, yp, xt, yt ,tw, th, sheet, 0); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet) { + render(limitingModel, xp, yp, xt, yt ,tw, th, sheet, 0); } - public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors) { - render(xp, yp, xt, yt ,tw, th, sheet, mirrors, -1); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors) { + render(limitingModel, xp, yp, xt, yt ,tw, th, sheet, mirrors, -1); } - public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint) { - render(xp, yp, xt, yt, tw, th, sheet, mirrors, whiteTint, false); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint) { + render(limitingModel, xp, yp, xt, yt, tw, th, sheet, mirrors, whiteTint, false); } - public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint, boolean fullbright) { - render(xp, yp, xt, yt, tw, th, sheet, mirrors, whiteTint, fullbright, 0); + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint, boolean fullbright) { + render(limitingModel, xp, yp, xt, yt, tw, th, sheet, mirrors, whiteTint, fullbright, 0); } // Any single pixel from the image can be rendered using this method. - public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint, boolean fullBright, int color) { + public void render(@Nullable RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint, boolean fullBright, int color) { if (sheet == null) return; // Verifying that sheet is not null. // Validation check if (xt + tw > sheet.width && yt + th > sheet.height) { - render(xp, yp, 0, 0, mirrors, Renderer.spriteLinker.missingSheet(SpriteType.Item)); + render(null, xp, yp, 0, 0, mirrors, Renderer.spriteLinker.missingSheet(SpriteType.Item)); return; } - queue(new SpriteRendering(xp, yp, xt, yt, tw, th, mirrors, whiteTint, fullBright, color, sheet)); + queue(new SpriteRendering(limitingModel, xp, yp, xt, yt, tw, th, mirrors, whiteTint, fullBright, color, sheet)); } public void fillRect(int xp, int yp, int w, int h, int color) { diff --git a/src/client/java/minicraft/gfx/SpriteAnimation.java b/src/client/java/minicraft/gfx/SpriteAnimation.java index 7df098a68..a8e7b837e 100644 --- a/src/client/java/minicraft/gfx/SpriteAnimation.java +++ b/src/client/java/minicraft/gfx/SpriteAnimation.java @@ -219,41 +219,41 @@ public void render(Screen screen, Level level, int x, int y) { if (u && l) { int connectiveColor = singletonWithConnective ? full.color : sparse.color; Sprite.Px connective = singletonWithConnective ? full.spritePixels[1][1] : sparse.spritePixels[1][1]; - if (ul) screen.render(x, y, connective, connectiveColor); - else if (sides == null) screen.render(x, y, full.spritePixels[1][1], full.color); - else screen.render(x, y, sides.spritePixels[0][0], 3, sides.color); + if (ul) screen.render(null, x, y, connective, connectiveColor); + else if (sides == null) screen.render(null, x, y, full.spritePixels[1][1], full.color); + else screen.render(null, x, y, sides.spritePixels[0][0], 3, sides.color); } else - screen.render(x, y, sparse.spritePixels[u ? 1 : 0][l ? 1 : 0], sparse.color); + screen.render(null, x, y, sparse.spritePixels[u ? 1 : 0][l ? 1 : 0], sparse.color); if (u && r) { int connectiveColor = singletonWithConnective ? full.color : sparse.color; Sprite.Px connective = singletonWithConnective ? full.spritePixels[1][0] : sparse.spritePixels[1][1]; - if (ur) screen.render(x + 8, y, connective, connectiveColor); - else if (sides == null) screen.render(x + 8, y, full.spritePixels[1][0], full.color); - else screen.render(x + 8, y, sides.spritePixels[0][1], 3, sides.color); + if (ur) screen.render(null, x + 8, y, connective, connectiveColor); + else if (sides == null) screen.render(null, x + 8, y, full.spritePixels[1][0], full.color); + else screen.render(null, x + 8, y, sides.spritePixels[0][1], 3, sides.color); } else - screen.render(x + 8, y, sparse.spritePixels[u ? 1 : 0][r ? 1 : 2], sparse.color); + screen.render(null, x + 8, y, sparse.spritePixels[u ? 1 : 0][r ? 1 : 2], sparse.color); if (d && l) { int connectiveColor = singletonWithConnective ? full.color : sparse.color; Sprite.Px connective = singletonWithConnective ? full.spritePixels[0][1] : sparse.spritePixels[1][1]; - if (dl) screen.render(x, y + 8, connective, connectiveColor); - else if (sides == null) screen.render(x, y + 8, full.spritePixels[0][1], full.color); - else screen.render(x, y + 8, sides.spritePixels[1][0], 3, sides.color); + if (dl) screen.render(null, x, y + 8, connective, connectiveColor); + else if (sides == null) screen.render(null, x, y + 8, full.spritePixels[0][1], full.color); + else screen.render(null, x, y + 8, sides.spritePixels[1][0], 3, sides.color); } else - screen.render(x, y + 8, sparse.spritePixels[d ? 1 : 2][l ? 1 : 0], sparse.color); + screen.render(null, x, y + 8, sparse.spritePixels[d ? 1 : 2][l ? 1 : 0], sparse.color); if (d && r) { int connectiveColor = singletonWithConnective ? full.color : sparse.color; Sprite.Px connective = singletonWithConnective ? full.spritePixels[0][0] : sparse.spritePixels[1][1]; - if (dr) screen.render(x + 8, y + 8, connective, connectiveColor); - else if (sides == null) screen.render(x + 8, y + 8, full.spritePixels[0][0], full.color); - else screen.render(x + 8, y + 8, sides.spritePixels[1][1], 3, sides.color); + if (dr) screen.render(null, x + 8, y + 8, connective, connectiveColor); + else if (sides == null) screen.render(null, x + 8, y + 8, full.spritePixels[0][0], full.color); + else screen.render(null, x + 8, y + 8, sides.spritePixels[1][1], 3, sides.color); } else - screen.render(x + 8, y + 8, sparse.spritePixels[d ? 1 : 2][r ? 1 : 2], sparse.color); + screen.render(null, x + 8, y + 8, sparse.spritePixels[d ? 1 : 2][r ? 1 : 2], sparse.color); } else - screen.render(x << 4, y << 4, animations[frame]); + screen.render(null, x << 4, y << 4, animations[frame]); // If there is animation. if (animations.length > 1) { diff --git a/src/client/java/minicraft/item/Item.java b/src/client/java/minicraft/item/Item.java index 2761d3b2c..79ec64b2e 100644 --- a/src/client/java/minicraft/item/Item.java +++ b/src/client/java/minicraft/item/Item.java @@ -36,8 +36,8 @@ protected Item(String name, LinkedSprite sprite) { */ public void renderHUD(Screen screen, int x, int y, int fontColor) { String dispName = getDisplayName(); - screen.render(x, y, sprite); - Font.drawBackground(dispName, screen, x + 8, y, fontColor); + screen.render(null, x, y, sprite); + Font.drawBackground(null, dispName, screen, x + 8, y, fontColor); } /** diff --git a/src/client/java/minicraft/level/tile/DecorTile.java b/src/client/java/minicraft/level/tile/DecorTile.java index a3ee6968c..45e5a53a4 100644 --- a/src/client/java/minicraft/level/tile/DecorTile.java +++ b/src/client/java/minicraft/level/tile/DecorTile.java @@ -52,7 +52,7 @@ protected DecorTile(decorType type) { @Override public void render(Screen screen, Level level, int x, int y) { super.render(screen, level, x, y); - screen.render(x * 16 + 0, y * 16, sprite.getCurrentFrame().getSprite().spritePixels[0][0]); + screen.render(null, x >> 4, y >> 4, sprite.getCurrentFrame().getSprite().spritePixels[0][0]); } public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { diff --git a/src/client/java/minicraft/level/tile/TreeTile.java b/src/client/java/minicraft/level/tile/TreeTile.java index 6b9a76160..8f5147df2 100644 --- a/src/client/java/minicraft/level/tile/TreeTile.java +++ b/src/client/java/minicraft/level/tile/TreeTile.java @@ -83,27 +83,27 @@ public void render(Screen screen, Level level, int x, int y) { Sprite spriteFull = level.treeTypes[x + y * level.w].treeSpriteFull.getSprite(); if (isUpTileSame && isUpLeftTileSame && isLeftTileSame) { - screen.render((x << 4) + 0, (y << 4) + 0, spriteFull.spritePixels[0][1]); + screen.render(null, (x << 4) + 0, (y << 4) + 0, spriteFull.spritePixels[0][1]); } else { - screen.render((x << 4) + 0, (y << 4) + 0, sprite.spritePixels[0][0]); + screen.render(null, (x << 4) + 0, (y << 4) + 0, sprite.spritePixels[0][0]); } if (isUpTileSame && isUpRightTileSame && isRightTileSame) { - screen.render((x << 4) + 8, (y << 4) + 0, spriteFull.spritePixels[0][0]); + screen.render(null, (x << 4) + 8, (y << 4) + 0, spriteFull.spritePixels[0][0]); } else { - screen.render((x << 4) + 8, (y << 4) + 0, sprite.spritePixels[0][1]); + screen.render(null, (x << 4) + 8, (y << 4) + 0, sprite.spritePixels[0][1]); } if (isDownTileSame && isDownLeftTileSame && isLeftTileSame) { - screen.render((x << 4) + 0, (y << 4) + 8, spriteFull.spritePixels[1][1]); + screen.render(null, (x << 4) + 0, (y << 4) + 8, spriteFull.spritePixels[1][1]); } else { - screen.render((x << 4) + 0, (y << 4) + 8, sprite.spritePixels[1][0]); + screen.render(null, (x << 4) + 0, (y << 4) + 8, sprite.spritePixels[1][0]); } if (isDownTileSame && isDownRightTileSame && isRightTileSame) { - screen.render((x << 4) + 8, (y << 4) + 8, spriteFull.spritePixels[1][0]); + screen.render(null, (x << 4) + 8, (y << 4) + 8, spriteFull.spritePixels[1][0]); } else { - screen.render((x << 4) + 8, (y << 4) + 8, sprite.spritePixels[1][1]); + screen.render(null, (x << 4) + 8, (y << 4) + 8, sprite.spritePixels[1][1]); } } diff --git a/src/client/java/minicraft/level/tile/farming/CarrotTile.java b/src/client/java/minicraft/level/tile/farming/CarrotTile.java index 542fee7d6..a45fd2c5e 100644 --- a/src/client/java/minicraft/level/tile/farming/CarrotTile.java +++ b/src/client/java/minicraft/level/tile/farming/CarrotTile.java @@ -23,6 +23,6 @@ public void render(Screen screen, Level level, int x, int y) { int age = (level.getData(x, y) >> 3) & maxAge; Tiles.get("Farmland").render(screen, level, x, y); int stage = (int) ((float) age / maxAge * 3); - screen.render(x * 16, y * 16, spritStages[stage]); + screen.render(null, x * 16, y * 16, spritStages[stage]); } } diff --git a/src/client/java/minicraft/level/tile/farming/HeavenlyBerriesTile.java b/src/client/java/minicraft/level/tile/farming/HeavenlyBerriesTile.java index c4fc57100..f0870a31e 100644 --- a/src/client/java/minicraft/level/tile/farming/HeavenlyBerriesTile.java +++ b/src/client/java/minicraft/level/tile/farming/HeavenlyBerriesTile.java @@ -22,6 +22,6 @@ public void render(Screen screen, Level level, int x, int y) { int age = (level.getData(x, y) >> 3) & maxAge; Tiles.get("Farmland").render(screen, level, x, y); int stage = (int) ((float) age / maxAge * 3); - screen.render(x * 16, y * 16, spritStages[stage]); + screen.render(null, x * 16, y * 16, spritStages[stage]); } } diff --git a/src/client/java/minicraft/level/tile/farming/HellishBerriesTile.java b/src/client/java/minicraft/level/tile/farming/HellishBerriesTile.java index 6d4f7bcb5..ad93f6f48 100644 --- a/src/client/java/minicraft/level/tile/farming/HellishBerriesTile.java +++ b/src/client/java/minicraft/level/tile/farming/HellishBerriesTile.java @@ -22,6 +22,6 @@ public void render(Screen screen, Level level, int x, int y) { int age = (level.getData(x, y) >> 3) & maxAge; Tiles.get("Farmland").render(screen, level, x, y); int stage = (int) ((float) age / maxAge * 3); - screen.render(x * 16, y * 16, spritStages[stage]); + screen.render(null, x * 16, y * 16, spritStages[stage]); } } diff --git a/src/client/java/minicraft/level/tile/farming/PotatoTile.java b/src/client/java/minicraft/level/tile/farming/PotatoTile.java index 619dbf2fc..7fe8bbe71 100644 --- a/src/client/java/minicraft/level/tile/farming/PotatoTile.java +++ b/src/client/java/minicraft/level/tile/farming/PotatoTile.java @@ -25,6 +25,6 @@ public void render(Screen screen, Level level, int x, int y) { int age = (level.getData(x, y) >> 3) & maxAge; Tiles.get("Farmland").render(screen, level, x, y); int stage = (int) ((float) age / maxAge * 5); - screen.render(x << 4, y << 4, spritStages[stage]); + screen.render(null, x << 4, y << 4, spritStages[stage]); } } diff --git a/src/client/java/minicraft/level/tile/farming/TomatoTile.java b/src/client/java/minicraft/level/tile/farming/TomatoTile.java index a8329ae63..bbaf444a8 100644 --- a/src/client/java/minicraft/level/tile/farming/TomatoTile.java +++ b/src/client/java/minicraft/level/tile/farming/TomatoTile.java @@ -23,6 +23,6 @@ public void render(Screen screen, Level level, int x, int y) { int age = (level.getData(x, y) >> 3) & maxAge; Tiles.get("Farmland").render(screen, level, x, y); int stage = (int) ((float) age / maxAge * 3); - screen.render(x * 16, y * 16, spritStages[stage]); + screen.render(null, x * 16, y * 16, spritStages[stage]); } } diff --git a/src/client/java/minicraft/level/tile/farming/WheatTile.java b/src/client/java/minicraft/level/tile/farming/WheatTile.java index 31fb0fe5a..40426d5aa 100644 --- a/src/client/java/minicraft/level/tile/farming/WheatTile.java +++ b/src/client/java/minicraft/level/tile/farming/WheatTile.java @@ -25,6 +25,6 @@ public void render(Screen screen, Level level, int x, int y) { int age = (level.getData(x, y) >> 3) & maxAge; Tiles.get("Farmland").render(screen, level, x, y); int stage = (int) ((float) age / maxAge * 5); - screen.render(x << 4, y << 4, spritStages[stage]); + screen.render(null, x << 4, y << 4, spritStages[stage]); } } diff --git a/src/client/java/minicraft/screen/AchievementsDisplay.java b/src/client/java/minicraft/screen/AchievementsDisplay.java index 6703280f3..a20ca223d 100644 --- a/src/client/java/minicraft/screen/AchievementsDisplay.java +++ b/src/client/java/minicraft/screen/AchievementsDisplay.java @@ -71,7 +71,7 @@ public class AchievementsDisplay extends Display { public AchievementsDisplay() { super(true, true, - new Menu.Builder(false, 2, RelPos.CENTER, getAchievemensAsEntries()).setSize(48, 48).createMenu(), + new Menu.Builder(false, 2, RelPos.CENTER, getAchievemensAsEntries()).setSize(Screen.w, 48).createMenu(), new Menu.Builder(false, 2, RelPos.BOTTOM, new StringEntry("")).setSize(200, 32).setPositioning(new Point(Screen.w / 2, Screen.h / 2 + 32), RelPos.BOTTOM).createMenu()); } diff --git a/src/client/java/minicraft/screen/ContainerDisplay.java b/src/client/java/minicraft/screen/ContainerDisplay.java index 05da5855e..77d7ea61e 100644 --- a/src/client/java/minicraft/screen/ContainerDisplay.java +++ b/src/client/java/minicraft/screen/ContainerDisplay.java @@ -85,10 +85,10 @@ public void render(Screen screen) { // Expanded counter if (sizeLeft < 10) { // At the moment at most just 2 digits and always 2 digits for capacity (no worry yet) // Background - screen.render(boundsLeft.getRight() + 2 - (23 - 5), boundsLeft.getTop() - 3, + screen.render(null, boundsLeft.getRight() + 2 - (23 - 5), boundsLeft.getTop() - 3, 12, 12, 3, 13, counterSheet); // Skips the middle part as that is for more digits - screen.render(boundsLeft.getRight() + 2 - 15, boundsLeft.getTop() - 3, + screen.render(null, boundsLeft.getRight() + 2 - 15, boundsLeft.getTop() - 3, 20, 12, 15, 13, counterSheet); // Digits @@ -98,7 +98,7 @@ public void render(Screen screen) { 0, 4, 5, capLeft, Color.GRAY); } else { // Background - screen.render(boundsLeft.getRight() + 2 - 23, boundsLeft.getTop() - 3, + screen.render(null, boundsLeft.getRight() + 2 - 23, boundsLeft.getTop() - 3, 12, 12, 23, 13, counterSheet); // Digits @@ -115,10 +115,10 @@ public void render(Screen screen) { // Minimized counter if (sizeRight < 10) { // no worry yet, really // Background - screen.render(boundsRight.getLeft() + 4, boundsRight.getTop() - 1, + screen.render(null, boundsRight.getLeft() + 4, boundsRight.getTop() - 1, 0, 12, 4, 9, counterSheet); // Skips the middle part as that is for more digits - screen.render(boundsRight.getLeft() + 8, boundsRight.getTop() - 1, + screen.render(null, boundsRight.getLeft() + 8, boundsRight.getTop() - 1, 8, 12, 4, 9, counterSheet); // Digits @@ -126,7 +126,7 @@ public void render(Screen screen) { 0, 4, 5, sizeRight, fadeColor(colorByHeaviness(calculateHeaviness(sizeRight, capRight), false))); } else { // Background - screen.render(boundsRight.getLeft() + 4, boundsRight.getTop() - 1, + screen.render(null, boundsRight.getLeft() + 4, boundsRight.getTop() - 1, 0, 12, 12, 9, counterSheet); // Digits @@ -141,10 +141,10 @@ public void render(Screen screen) { // Minimized counter if (sizeLeft < 10) { // Background - screen.render(boundsLeft.getRight() - 4 - 8, boundsLeft.getTop() - 1, + screen.render(null, boundsLeft.getRight() - 4 - 8, boundsLeft.getTop() - 1, 0, 12, 4, 9, counterSheet); // Skips the middle part as that is for more digits - screen.render(boundsLeft.getRight() - 4 - 4, boundsLeft.getTop() - 1, + screen.render(null, boundsLeft.getRight() - 4 - 4, boundsLeft.getTop() - 1, 8, 12, 4, 9, counterSheet); // Digits @@ -152,7 +152,7 @@ public void render(Screen screen) { 0, 4, 5, sizeLeft, fadeColor(colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), false))); } else { // Background - screen.render(boundsLeft.getRight() - 4 - 12, boundsLeft.getTop() - 1, + screen.render(null, boundsLeft.getRight() - 4 - 12, boundsLeft.getTop() - 1, 0, 12, 12, 9, counterSheet); // Digits @@ -167,10 +167,10 @@ public void render(Screen screen) { // Expanded counter (background horizontally mirrored) if (sizeRight < 10) { // Background - screen.render(boundsRight.getLeft() - 2 + (20 - 5), boundsRight.getTop() - 3, + screen.render(null, boundsRight.getLeft() - 2 + (20 - 5), boundsRight.getTop() - 3, 12, 12, 3, 13, counterSheet, 1); // Skips the middle part as that is for more digits - screen.render(boundsRight.getLeft() - 2, boundsRight.getTop() - 3, + screen.render(null, boundsRight.getLeft() - 2, boundsRight.getTop() - 3, 20, 12, 15, 13, counterSheet, 1); // Digits @@ -180,7 +180,7 @@ public void render(Screen screen) { 0, 4, 5, capRight, Color.GRAY); } else { // Background - screen.render(boundsRight.getLeft() - 2, boundsRight.getTop() - 3, + screen.render(null, boundsRight.getLeft() - 2, boundsRight.getTop() - 3, 12, 12, 23, 13, counterSheet, 1); // Digits @@ -196,7 +196,7 @@ public void render(Screen screen) { private void renderCounterNumber(Screen screen, int xp, int yp, int ys, int w, int h, int n, int color) { String display = String.valueOf(n); for (int i = 0; i < display.length(); ++i) { - screen.render(xp + i * w, yp, w * (display.charAt(i) - '0'), ys, w, h, counterSheet, 0, color); + screen.render(null, xp + i * w, yp, w * (display.charAt(i) - '0'), ys, w, h, counterSheet, 0, color); } } diff --git a/src/client/java/minicraft/screen/ControlsDisplay.java b/src/client/java/minicraft/screen/ControlsDisplay.java index 8e028156a..6704570e1 100644 --- a/src/client/java/minicraft/screen/ControlsDisplay.java +++ b/src/client/java/minicraft/screen/ControlsDisplay.java @@ -5,13 +5,13 @@ import minicraft.core.io.Localization; import minicraft.gfx.Color; import minicraft.gfx.Font; +import minicraft.gfx.MinicraftImage; import minicraft.gfx.Point; import minicraft.gfx.Screen; import minicraft.screen.entry.ListEntry; -import minicraft.screen.entry.StringEntry; +import minicraft.screen.entry.SelectableStringEntry; import java.util.ArrayList; -import java.util.Arrays; public class ControlsDisplay extends Display { private ListEntry[] keyControls; @@ -20,10 +20,11 @@ public class ControlsDisplay extends Display { private int displaying; // 0 for keyboard; 1 for controller. public ControlsDisplay() { - super(true, true, new Menu.Builder(false, 0, RelPos.CENTER) + super(true, true, new Menu.Builder(false, 0, RelPos.LEFT) .setSelectable(true) - .setPositioning(new Point(Screen.w / 2, 20), RelPos.BOTTOM) + .setPositioning(new Point(0, 20), RelPos.BOTTOM_RIGHT) .setDisplayLength(17) + .setSize(Screen.w, 17 * 8) .createMenu() ); @@ -36,17 +37,21 @@ public ControlsDisplay() { private void initKeyControls() { ArrayList entries = new ArrayList<>(23); - for (int i = 0; i < 23; i++) - entries.addAll(Arrays.asList(StringEntry.useLines(String.format("minicraft.displays.controls.display.keyboard.%02d", i)))); - entries.forEach(e -> e.setSelectable(true)); + for (int i = 0; i < 23; i++) { + SelectableStringEntry entry = new SelectableStringEntry(String.format("minicraft.displays.controls.display.keyboard.%02d", i)); + entry.setScrollerScrollingTicker(); + entries.add(entry); + } keyControls = entries.toArray(new ListEntry[0]); } private void initControllerControls() { ArrayList entries = new ArrayList<>(16); - for (int i = 0; i < 16; i++) - entries.addAll(Arrays.asList(StringEntry.useLines(String.format("minicraft.displays.controls.display.controller.%02d", i)))); - entries.forEach(e -> e.setSelectable(true)); + for (int i = 0; i < 16; i++) { + SelectableStringEntry entry = new SelectableStringEntry(String.format("minicraft.displays.controls.display.controller.%02d", i)); + entry.setScrollerScrollingTicker(); + entries.add(entry); + } controllerControls = entries.toArray(new ListEntry[0]); } diff --git a/src/client/java/minicraft/screen/LevelTransitionDisplay.java b/src/client/java/minicraft/screen/LevelTransitionDisplay.java index 6f8a3a970..91eb88300 100644 --- a/src/client/java/minicraft/screen/LevelTransitionDisplay.java +++ b/src/client/java/minicraft/screen/LevelTransitionDisplay.java @@ -34,9 +34,9 @@ public void render(Screen screen) { int dd = (y + x % 2 * 2 + x / 3) - time * 2; // Used as part of the positioning. if (dd < 0 && dd > -30) { if (dir > 0) - screen.render(x * 8, y * 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is upwards then render the squares going up + screen.render(null, x * 8, y * 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is upwards then render the squares going up else - screen.render(x * 8, Screen.h - y * 8 - 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is negative, then the squares will go down. + screen.render(null, x * 8, Screen.h - y * 8 - 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is negative, then the squares will go down. } } } diff --git a/src/client/java/minicraft/screen/Menu.java b/src/client/java/minicraft/screen/Menu.java index ca402bc4a..6eaf307d7 100644 --- a/src/client/java/minicraft/screen/Menu.java +++ b/src/client/java/minicraft/screen/Menu.java @@ -15,6 +15,7 @@ import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.screen.entry.BlankEntry; import minicraft.screen.entry.ListEntry; +import minicraft.screen.entry.SelectableStringEntry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,11 +30,12 @@ public class Menu { private static final int LIMIT_TYPING_SEARCHER = 22; @NotNull - private final ArrayList entries = new ArrayList<>(); + private final ArrayList entries = new ArrayList<>(); private int spacing = 0; private Rectangle bounds = null; private Rectangle entryBounds = null; + private Rectangle entryRenderingBounds = null; private RelPos entryPos = RelPos.CENTER; // the x part of this is re-applied per entry, while the y part is calculated once using the cumulative height of all entries and spacing. private String title = ""; @@ -42,6 +44,7 @@ public class Menu { private boolean drawVertically = false; private boolean hasFrame; + private boolean renderOutOfFrame = false; private boolean selectable = false; boolean shouldRender = true; @@ -74,11 +77,13 @@ private Menu() { } protected Menu(Menu m) { - entries.addAll(m.entries); spacing = m.spacing; bounds = m.bounds == null ? null : new Rectangle(m.bounds); entryBounds = m.entryBounds == null ? null : new Rectangle(m.entryBounds); + entryRenderingBounds = m.entryRenderingBounds == null ? null : new Rectangle(m.entryRenderingBounds); entryPos = m.entryPos; + // Requires parameters before this. + setEntries(m.entries.stream().map(e -> e.delegate).toArray(ListEntry[]::new)); title = m.title; titleColor = m.titleColor; titleLoc = m.titleLoc; @@ -92,6 +97,7 @@ protected Menu(Menu m) { selection = m.selection; dispSelection = m.dispSelection; offset = m.offset; + renderOutOfFrame = m.renderOutOfFrame; useSearcherBar = m.useSearcherBar; selectionSearcher = 0; @@ -112,13 +118,13 @@ public void init() { selection = Math.min(selection, entries.size() - 1); selection = Math.max(0, selection); - if (!entries.get(selection).isSelectable()) { + if (!entries.get(selection).delegate.isSelectable()) { int prevSel = selection; do { selection++; if (selection < 0) selection = entries.size() - 1; selection = selection % entries.size(); - } while (!entries.get(selection).isSelectable() && selection != prevSel); + } while (!entries.get(selection).delegate.isSelectable() && selection != prevSel); } dispSelection = selection; @@ -148,21 +154,21 @@ int getDispSelection() { } ListEntry[] getEntries() { - return entries.toArray(new ListEntry[0]); + return entries.stream().map(a -> a.delegate).toArray(ListEntry[]::new); } - protected void setEntries(ListEntry[] entries) { this.entries.clear(); - this.entries.addAll(0, Arrays.asList(entries)); + Arrays.stream(entries) + .forEach(entry -> this.entries.add(new MenuListEntry(entry, entryPos))); } protected void setEntries(List entries) { this.entries.clear(); - this.entries.addAll(entries); + entries.forEach(entry -> this.entries.add(new MenuListEntry(entry, entryPos))); } @Nullable ListEntry getCurEntry() { - return entries.size() == 0 ? null : entries.get(selection); + return entries.size() == 0 ? null : entries.get(selection).delegate; } int getNumOptions() { @@ -195,18 +201,31 @@ public boolean isSearcherBarActive() { void translate(int xoff, int yoff) { bounds.translate(xoff, yoff); entryBounds.translate(xoff, yoff); + entryRenderingBounds.translate(xoff, yoff); titleLoc.translate(xoff, yoff); } public void tick(InputHandler input) { - if (!selectable || entries.size() == 0) return; + if (!selectable) { + if (!entries.isEmpty()) entries.get(selection).tick(input); + return; + } else if (entries.size() == 0) { + return; + } int prevSel = selection; - if (input.inputPressed("cursor-up")) selection--; - if (input.inputPressed("cursor-down")) selection++; - if (input.getMappedKey("shift+cursor-up").isClicked() && selectionSearcher == 0) selectionSearcher -= 2; - if (input.getMappedKey("shift+cursor-down").isClicked() && selectionSearcher == 0) selectionSearcher += 2; - if (prevSel != selection && selectionSearcher != 0) selection = prevSel; + if (input.getMappedKey("ALT").isDown()) { + if (input.inputPressed("cursor-left")) + entries.get(selection).translateX(MinicraftImage.boxWidth, true); + if (input.inputPressed("cursor-right")) + entries.get(selection).translateX(-MinicraftImage.boxWidth, true); + } else { + if (input.inputPressed("cursor-up")) selection--; + if (input.inputPressed("cursor-down")) selection++; + if (input.getMappedKey("shift+cursor-up").isClicked() && selectionSearcher == 0) selectionSearcher -= 2; + if (input.getMappedKey("shift+cursor-down").isClicked() && selectionSearcher == 0) selectionSearcher += 2; + if (prevSel != selection && selectionSearcher != 0) selection = prevSel; + } if (useSearcherBar) { if (input.getMappedKey("searcher-bar").isClicked()) { @@ -239,10 +258,10 @@ public void tick(InputHandler input) { listSearcher.clear(); listPositionSearcher = 0; - Iterator entryIt = entries.iterator(); + Iterator entryIt = entries.iterator(); boolean shouldSelect = true; for (int i = 0; entryIt.hasNext(); i++) { - ListEntry entry = entryIt.next(); + ListEntry entry = entryIt.next().delegate; String stringEntry = entry.toString().toLowerCase(Locale.ENGLISH); String typingString = typingSearcher.toLowerCase(Locale.ENGLISH); @@ -280,7 +299,7 @@ public void tick(InputHandler input) { selection += delta; if (selection < 0) selection = entries.size() - 1; selection = selection % entries.size(); - } while (!entries.get(selection).isSelectable() && selection != prevSel); + } while (!entries.get(selection).delegate.isSelectable() && selection != prevSel); // update offset and selection displayed dispSelection += selection - prevSel; @@ -324,13 +343,13 @@ public void render(Screen screen) { if (drawVertically) { for (int i = 0; i < title.length(); i++) { if (hasFrame) - screen.render(titleLoc.x, titleLoc.y + i * Font.textHeight(), 3, 6, 0, hudSheet.getSheet()); + screen.render(null, titleLoc.x, titleLoc.y + i * Font.textHeight(), 3, 6, 0, hudSheet.getSheet()); Font.draw(title.substring(i, i + 1), screen, titleLoc.x, titleLoc.y + i * Font.textHeight(), titleColor); } } else { for (int i = 0; i < title.length(); i++) { if (hasFrame) - screen.render(titleLoc.x + i * Font.textWidth(" "), titleLoc.y, 3, 6, 0, hudSheet.getSheet()); + screen.render(null, titleLoc.x + i * Font.textWidth(" "), titleLoc.y, 3, 6, 0, hudSheet.getSheet()); Font.draw(title.substring(i, i + 1), screen, titleLoc.x + i * Font.textWidth(" "), titleLoc.y, titleColor); } } @@ -349,7 +368,7 @@ public void render(Screen screen) { for (int i = 0; i < typingSearcher.length() + 4; i++) { if (hasFrame) { - screen.render(xSearcherBar + spaceWidth * i - leading, titleLoc.y - 8, 3, 6, 0, hudSheet.getSheet()); + screen.render(null, xSearcherBar + spaceWidth * i - leading, titleLoc.y - 8, 3, 6, 0, hudSheet.getSheet()); } Font.draw("> " + typingSearcher + " <", screen, xSearcherBar - leading, titleLoc.y - 8, typingSearcher.length() < Menu.LIMIT_TYPING_SEARCHER ? Color.YELLOW : Color.RED); @@ -368,20 +387,12 @@ public void render(Screen screen) { if (special && i - offset >= entries.size()) break; int idx = i % entries.size(); - ListEntry entry = entries.get(idx); - - if (!(entry instanceof BlankEntry)) { - Point pos = entryPos.positionRect(new Dimension(entry.getWidth(), ListEntry.getHeight()), new Rectangle(entryBounds.getLeft(), y, entryBounds.getWidth(), ListEntry.getHeight(), Rectangle.CORNER_DIMS)); - boolean selected = idx == selection; + MenuListEntry entry = entries.get(idx); + if (!(entry.delegate instanceof BlankEntry) && entry.delegate.isVisible()) { if (searcherBarActive && useSearcherBar) { - entry.render(screen, pos.x, pos.y, selected, typingSearcher, Color.YELLOW); + entry.render(screen, y, idx == selection, typingSearcher, Color.YELLOW); } else { - entry.render(screen, pos.x, pos.y, selected); - } - if (selected && entry.isSelectable()) { - // draw the arrows - Font.draw("> ", screen, pos.x - Font.textWidth("> "), y, ListEntry.COL_SLCT); - Font.draw(" <", screen, pos.x + entry.getWidth(), y, ListEntry.COL_SLCT); + entry.render(screen, y, idx == selection); } } @@ -395,7 +406,7 @@ void updateSelectedEntry(ListEntry newEntry) { void updateEntry(int idx, ListEntry newEntry) { if (idx >= 0 && idx < entries.size()) - entries.set(idx, newEntry); + entries.set(idx, new MenuListEntry(newEntry, entryPos)); } public void removeSelectedEntry() { @@ -427,7 +438,7 @@ private void renderFrame(Screen screen) { int spriteoffset = (xend && yend ? 0 : (yend ? 1 : (xend ? 2 : 3))); // determines which sprite to use int mirrors = (x == right ? 1 : 0) + (y == bottom ? 2 : 0); // gets mirroring - screen.render(x, y, spriteoffset, 6, mirrors, hudSheet.getSheet()); + screen.render(null, x, y, spriteoffset, 6, mirrors, hudSheet.getSheet()); if (x < right && x + MinicraftImage.boxWidth > right) x = right - MinicraftImage.boxWidth; @@ -438,6 +449,86 @@ private void renderFrame(Screen screen) { } } + /** Acts as an internal wrapping decorator of a {@link ListEntry} for the {@link Menu} environment. */ + private class MenuListEntry extends Screen.EntryRenderingUnit { + private class MenuEntryLimitingModel extends EntryLimitingModel {} + + private class MenuEntryXAccessor extends EntryXAccessor {} + + public final MenuEntryLimitingModel limitingModel = new MenuEntryLimitingModel(); + public final MenuEntryXAccessor accessor = new MenuEntryXAccessor(); + public final ListEntry delegate; + + public MenuListEntry(ListEntry delegate, @NotNull RelPos anchor) { + super(anchor); + this.delegate = delegate; + } + + @Override + protected EntryLimitingModel getLimitingModel() { + return limitingModel; + } + + @Override + protected EntryXAccessor getXAccessor() { + return accessor; + } + + protected Rectangle getEntryBounds() { + return delegate.isSelectable() ? entryBounds : entryRenderingBounds; + } + + @Override + protected ListEntry getDelegate() { + return delegate; + } + + public void translateX(int displacement, boolean limit) { + xPos += displacement; + if (limit) { + int w = delegate.getWidth(); + int minX; + int maxX; + if (w <= getEntryBounds().getWidth()) { + minX = (entryAnchor.xIndex * w - containerAnchor.xIndex * getEntryBounds().getWidth()) / 2; + maxX = ((2 - containerAnchor.xIndex) * getEntryBounds().getWidth() - (2 - entryAnchor.xIndex) * w) / 2; + } else { + minX = ((2 - containerAnchor.xIndex) * getEntryBounds().getWidth() - (2 - entryAnchor.xIndex) * w) / 2; + maxX = (entryAnchor.xIndex * w - containerAnchor.xIndex * getEntryBounds().getWidth()) / 2; + } + if (xPos < minX) xPos = minX; + if (xPos > maxX) xPos = maxX; + } + } + + @Override + public void tick(InputHandler input) { + delegate.hook(() -> { // For input entry + xPos = 0; // Resets position + int diff = xPos + (containerAnchor.xIndex - 2) * getEntryBounds().getWidth() / 2 + + (2 - entryAnchor.xIndex) * delegate.getWidth() / 2; + if (diff > 0) translateX(-diff, false); // Shifts if and only if the entry exceeds the area. + }); + super.tick(input); + } + + @Override + protected boolean renderOutOfFrame() { + return renderOutOfFrame; + } + + protected void renderExtra(Screen screen, int x, int y, int entryWidth, boolean selected) { + if (selected && delegate.isSelectable()) { + if (delegate.isScrollingTickerSet()) { + entryWidth = Math.min(entryWidth, getEntryBounds().getWidth()); + x = getEntryBounds().getLeft(); + } + + Font.draw(null, "> ", screen, x - 2 * MinicraftImage.boxWidth, y, ListEntry.COL_SLCT); + Font.draw(null, " <", screen, x + entryWidth, y, ListEntry.COL_SLCT); + } + } + } // This needs to be in the Menu class, to have access to the private constructor and fields. public static class Builder { @@ -468,10 +559,10 @@ public Builder(boolean hasFrame, int entrySpacing, RelPos entryPos, ListEntry... public Builder(boolean hasFrame, int entrySpacing, RelPos entryPos, List entries) { menu = new Menu(); - setEntries(entries); menu.hasFrame = hasFrame; menu.spacing = entrySpacing; menu.entryPos = entryPos; + setEntries(entries); } public Builder setEntries(ListEntry... entries) { @@ -479,8 +570,7 @@ public Builder setEntries(ListEntry... entries) { } public Builder setEntries(List entries) { - menu.entries.clear(); - menu.entries.addAll(entries); + menu.setEntries(entries); return this; } @@ -592,8 +682,8 @@ private Menu createMenu(Builder b) { // set default selectability if (!setSelectable) { - for (ListEntry entry : menu.entries) { - menu.selectable = menu.selectable || entry.isSelectable(); + for (MenuListEntry entry : menu.entries) { + menu.selectable = menu.selectable || entry.delegate.isSelectable(); if (menu.selectable) break; } @@ -656,13 +746,14 @@ else if (c.xIndex == 2) // must be center right if (menuSize == null) { int width = titleDim.width; - for (ListEntry entry : menu.entries) { - int entryWidth = entry.getWidth(); - if (menu.isSelectable() && !entry.isSelectable()) + for (MenuListEntry entry : menu.entries) { + int entryWidth = entry.delegate.getWidth(); + if (menu.isSelectable() && !entry.delegate.isSelectable()) entryWidth = Math.max(0, entryWidth - MinicraftImage.boxWidth * 4); width = Math.max(width, entryWidth); } + if (!menu.hasFrame && menu.entryPos.xIndex == 1) width = Screen.w; // Reduces troubles simply :) if (menu.displayLength > 0) { // has been set; use to determine entry bounds int height = (ListEntry.getHeight() + menu.spacing) * menu.displayLength - menu.spacing; @@ -701,6 +792,14 @@ else if (menuPos.yIndex == 2) menu.entryBounds = border.subtractFrom(menu.bounds); + if (menu.isSelectable()) { + // remove spacing for selection cursors + border.left -= MinicraftImage.boxWidth * 2; + border.right -= MinicraftImage.boxWidth * 2; + } + + menu.entryRenderingBounds = border.subtractFrom(menu.bounds); + menu.titleLoc = titlePos.positionRect(titleDim, menu.bounds); if (titlePos.xIndex == 0 && titlePos.yIndex != 1) @@ -732,7 +831,7 @@ else if (menuPos.yIndex == 2) // returns a new Builder instance, that can be further modified to create another menu. public Builder copy() { - Builder b = new Builder(menu.hasFrame, menu.spacing, menu.entryPos, menu.entries); + Builder b = new Builder(menu.hasFrame, menu.spacing, menu.entryPos); b.menu = new Menu(menu); diff --git a/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java b/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java index 6d6f285dc..23fd080ea 100644 --- a/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java +++ b/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java @@ -287,11 +287,11 @@ public void render(Screen screen) { VirtualKey key = keys[r][c]; int color = keyPressed > 0 && r == this.y && c == this.x? 0x1EFEFF0: 0x1FDFDFD; if (key == backspace) { - screen.render(x, y, 0, 0, keyWidth , keyHeight , sheet, color); + screen.render(null, x, y, 0, 0, keyWidth , keyHeight , sheet, color); } else if (key == shiftKey) { - screen.render(x, y, keyWidth , 0, keyWidth , keyHeight , sheet, color); + screen.render(null, x, y, keyWidth , 0, keyWidth , keyHeight , sheet, color); } else if (key == spaceBar) { - screen.render(x, y, 0, keyHeight, keyWidth , keyHeight , sheet, color); + screen.render(null, x, y, 0, keyHeight, keyWidth , keyHeight , sheet, color); } else Font.draw(String.valueOf(key.output), screen, x + keyWidth / 2 - 3, y + keyHeight / 2 - 3, color); diff --git a/src/client/java/minicraft/screen/PlayerInvDisplay.java b/src/client/java/minicraft/screen/PlayerInvDisplay.java index 65373e58e..27f6df00f 100644 --- a/src/client/java/minicraft/screen/PlayerInvDisplay.java +++ b/src/client/java/minicraft/screen/PlayerInvDisplay.java @@ -206,10 +206,10 @@ public void render(Screen screen) { // Expanded counter if (sizeLeft < 10) { // At the moment at most just 2 digits and always 2 digits for capacity (no worry yet) // Background - screen.render(boundsLeft.getRight() + 2 - (23 - 5), boundsLeft.getTop() - 3, + screen.render(null, boundsLeft.getRight() + 2 - (23 - 5), boundsLeft.getTop() - 3, 12, 12, 3, 13, counterSheet); // Skips the middle part as that is for more digits - screen.render(boundsLeft.getRight() + 2 - 15, boundsLeft.getTop() - 3, + screen.render(null, boundsLeft.getRight() + 2 - 15, boundsLeft.getTop() - 3, 20, 12, 15, 13, counterSheet); // Digits @@ -219,7 +219,7 @@ public void render(Screen screen) { 0, 4, 5, capLeft, Color.GRAY); } else { // Background - screen.render(boundsLeft.getRight() + 2 - 23, boundsLeft.getTop() - 3, + screen.render(null, boundsLeft.getRight() + 2 - 23, boundsLeft.getTop() - 3, 12, 12, 23, 13, counterSheet); // Digits @@ -236,10 +236,10 @@ public void render(Screen screen) { // Minimized counter if (sizeLeft < 10) { // Background - screen.render(boundsLeft.getRight() - 4 - 8, boundsLeft.getTop() - 1, + screen.render(null, boundsLeft.getRight() - 4 - 8, boundsLeft.getTop() - 1, 0, 12, 4, 9, counterSheet); // Skips the middle part as that is for more digits - screen.render(boundsLeft.getRight() - 4 - 4, boundsLeft.getTop() - 1, + screen.render(null, boundsLeft.getRight() - 4 - 4, boundsLeft.getTop() - 1, 8, 12, 4, 9, counterSheet); // Digits @@ -247,7 +247,7 @@ public void render(Screen screen) { 0, 4, 5, sizeLeft, fadeColor(colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), false))); } else { // Background - screen.render(boundsLeft.getRight() - 4 - 12, boundsLeft.getTop() - 1, + screen.render(null, boundsLeft.getRight() - 4 - 12, boundsLeft.getTop() - 1, 0, 12, 12, 9, counterSheet); // Digits @@ -268,7 +268,7 @@ public void render(Screen screen) { private void renderCounterNumber(Screen screen, int xp, int yp, int ys, int w, int h, int n, int color) { String display = String.valueOf(n); for (int i = 0; i < display.length(); ++i) { - screen.render(xp + i * w, yp, w * (display.charAt(i) - '0'), ys, w, h, counterSheet, 0, color); + screen.render(null, xp + i * w, yp, w * (display.charAt(i) - '0'), ys, w, h, counterSheet, 0, color); } } diff --git a/src/client/java/minicraft/screen/PopupDisplay.java b/src/client/java/minicraft/screen/PopupDisplay.java index c156ca94f..ecf1f97b2 100644 --- a/src/client/java/minicraft/screen/PopupDisplay.java +++ b/src/client/java/minicraft/screen/PopupDisplay.java @@ -3,6 +3,8 @@ import com.studiohartman.jamepad.ControllerButton; import minicraft.core.Game; import minicraft.core.io.InputHandler; +import minicraft.gfx.MinicraftImage; +import minicraft.gfx.Rectangle; import minicraft.gfx.Screen; import minicraft.screen.entry.InputEntry; import minicraft.screen.entry.ListEntry; @@ -19,6 +21,7 @@ public class PopupDisplay extends Display { // Using Color codes for coloring in title and plain text messages. private final ArrayList callbacks; + private final Menu.Builder builder; public PopupDisplay(@Nullable PopupConfig config, String... messages) { this(config, false, messages); @@ -43,7 +46,7 @@ public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, ListEntry public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, boolean menuFrame, ListEntry... entries) { super(clearScreen, true); - Menu.Builder builder = new Menu.Builder(menuFrame, 0, RelPos.CENTER, entries); + builder = new Menu.Builder(menuFrame, 0, RelPos.CENTER, entries); if (config != null) { if (config.title != null) @@ -60,6 +63,17 @@ public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, boolean m menus = new Menu[] { builder.createMenu() }; else menus = new Menu[] { onScreenKeyboardMenu, builder.createMenu() }; + + Rectangle menuBounds = menus[onScreenKeyboardMenu == null ? 0 : 1].getBounds(); + for (ListEntry entry : entries) { + if (entry instanceof InputEntry) { + ((InputEntry) entry).setChangeListener(v -> update()); + } + } + } + + private void update() { + menus[onScreenKeyboardMenu == null ? 0 : 1] = builder.createMenu(); } OnScreenKeyboardMenu onScreenKeyboardMenu; diff --git a/src/client/java/minicraft/screen/QuestsDisplay.java b/src/client/java/minicraft/screen/QuestsDisplay.java index e185c58f7..37bfecc74 100644 --- a/src/client/java/minicraft/screen/QuestsDisplay.java +++ b/src/client/java/minicraft/screen/QuestsDisplay.java @@ -309,7 +309,7 @@ private static class SeriesQuestViewerDisplay extends Display { private final int[] rasterPixels; private final Screen simulatedRasterScreen = new Screen(new BufferedImage(Screen.w, Screen.h, BufferedImage.TYPE_INT_RGB)) { @Override - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright, int color) { + public void render(RenderingLimitingModel limitingModel, int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright, int color) { if (sheet == null) return; // Verifying that sheet is not null. // Ignoring mirror. // Validation check @@ -508,7 +508,7 @@ public void render(Screen screen) { renderRaster(); // Border screen.drawRect(rasterX - 1, rasterY - 1, rasterWidth + 2, rasterHeight + 2, Color.WHITE); - screen.render(rasterX, rasterY, 0, 0, rasterWidth, rasterHeight, image); + screen.render(null, rasterX, rasterY, 0, 0, rasterWidth, rasterHeight, image); } private void renderRaster() { diff --git a/src/client/java/minicraft/screen/ResourcePackDisplay.java b/src/client/java/minicraft/screen/ResourcePackDisplay.java index 6ca66a950..2157e3066 100644 --- a/src/client/java/minicraft/screen/ResourcePackDisplay.java +++ b/src/client/java/minicraft/screen/ResourcePackDisplay.java @@ -18,6 +18,7 @@ import minicraft.saveload.Save; import minicraft.screen.entry.ListEntry; import minicraft.screen.entry.SelectEntry; +import minicraft.screen.entry.StringEntry; import minicraft.util.BookData; import minicraft.util.Logging; import org.jetbrains.annotations.NotNull; @@ -196,6 +197,8 @@ public ResourcePackDisplay() { menus[1].translate(menus[0].getBounds().getRight() - menus[1].getBounds().getLeft() + padding, 0); fileWatcher = new WatcherThread(); + ((StringEntry) Objects.requireNonNull(helpPositionTextEntryMenu.getCurEntry())) + .setExceedingAlternatingScrollingTicker(); } @Override @@ -335,6 +338,8 @@ public void onExit() { @Override public void tick(InputHandler input) { + helpPositionTextEntryMenu.tick(input); // For rendering purpose + // Overrides the default tick handler. if (input.getMappedKey("shift+cursor-right").isClicked()) { // Move the selected pack to the second list. if (selection == 0 && resourcePacks.size() > 0) { @@ -393,6 +398,11 @@ public void tick(InputHandler input) { super.tick(input); } + private final Menu helpPositionTextEntryMenu = new Menu.Builder(false, 0, RelPos.CENTER, + new StringEntry("minicraft.displays.resource_packs.display.help.position", Color.DARK_GRAY)) + .setPositioning(new Point(Screen.w / 2, Screen.h), RelPos.TOP) + .createMenu(); + @Override public void render(Screen screen) { super.render(screen); @@ -405,7 +415,7 @@ public void render(Screen screen) { Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.keyboard_needed"), screen, Screen.h - 33, Color.DARK_GRAY); Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.move", Game.input.getMapping("cursor-down"), Game.input.getMapping("cursor-up")), screen, Screen.h - 25, Color.DARK_GRAY); Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.select", Game.input.getMapping("SELECT")), screen, Screen.h - 17, Color.DARK_GRAY); - Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.position"), screen, Screen.h - 9, Color.DARK_GRAY); + helpPositionTextEntryMenu.render(screen); ArrayList packs = selection == 0 ? resourcePacks : loadedPacks; if (packs.size() > 0) { // If there is any pack that can be selected. @@ -419,7 +429,7 @@ public void render(Screen screen) { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { // Resource pack logo - screen.render(xo + x * 8, yo + y * 8, x, y, 0, logo); + screen.render(null, xo + x * 8, yo + y * 8, x, y, 0, logo); } } } diff --git a/src/client/java/minicraft/screen/SkinDisplay.java b/src/client/java/minicraft/screen/SkinDisplay.java index e19a80616..64e2c5f6d 100644 --- a/src/client/java/minicraft/screen/SkinDisplay.java +++ b/src/client/java/minicraft/screen/SkinDisplay.java @@ -272,7 +272,7 @@ public void render(Screen screen) { // Render preview of skin. LinkedSprite sprite = new ArrayList<>(skins.values()).get(menus[0].getSelection())[spriteIndex / 2][spriteIndex % 2]; - screen.render(xOffset, yOffset, sprite); + screen.render(null, xOffset, yOffset, sprite); // Help text. Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.move", Game.input.getMapping("cursor-down"), Game.input.getMapping("cursor-up")), screen, Screen.h - 17, Color.DARK_GRAY); diff --git a/src/client/java/minicraft/screen/TitleDisplay.java b/src/client/java/minicraft/screen/TitleDisplay.java index de083b95f..c1e26f455 100644 --- a/src/client/java/minicraft/screen/TitleDisplay.java +++ b/src/client/java/minicraft/screen/TitleDisplay.java @@ -121,7 +121,7 @@ public void render(Screen screen) { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { - screen.render(xo + x * 8, yo + y * 8, x, y, 0, sheet); + screen.render(null, xo + x * 8, yo + y * 8, x, y, 0, sheet); } } diff --git a/src/client/java/minicraft/screen/WorldGenDisplay.java b/src/client/java/minicraft/screen/WorldGenDisplay.java index 63ca2735f..8fe34ec17 100644 --- a/src/client/java/minicraft/screen/WorldGenDisplay.java +++ b/src/client/java/minicraft/screen/WorldGenDisplay.java @@ -7,11 +7,16 @@ import minicraft.core.io.Localization; import minicraft.core.io.Settings; import minicraft.gfx.Color; +import minicraft.gfx.Dimension; import minicraft.gfx.Font; +import minicraft.gfx.MinicraftImage; +import minicraft.gfx.Rectangle; import minicraft.gfx.Screen; import minicraft.screen.entry.InputEntry; +import minicraft.screen.entry.ListEntry; import minicraft.screen.entry.SelectEntry; import minicraft.util.Logging; +import org.jetbrains.annotations.Nullable; import java.nio.file.InvalidPathException; import java.nio.file.Paths; @@ -128,12 +133,12 @@ public String getUserInput() { return super.getUserInput().toLowerCase(Localization.getSelectedLocale()); } - @Override - public void render(Screen screen, int x, int y, boolean isSelected) { - super.render(screen, isGen ? - (getUserInput().length() > 11 ? x - (getUserInput().length() - 11) * 8 : x) : - x, y, isSelected); - } +// @Override +// public void render(Screen screen, int x, int y, boolean isSelected, @Nullable IntRange bounds) { +// super.render(screen, isGen ? +// (getUserInput().length() > 11 ? x - (getUserInput().length() - 11) * 8 : x) : +// x, y, isSelected, bounds); +// } }; } @@ -181,8 +186,8 @@ public boolean isValid() { Game.setDisplay(new LoadingDisplay()); }) { @Override - public void render(Screen screen, int x, int y, boolean isSelected) { - Font.draw(toString(), screen, x, y, Color.CYAN); + public void render(Screen screen, @Nullable Screen.RenderingLimitingModel limitingModel, int x, int y, boolean isSelected) { + Font.draw(limitingModel, toString(), screen, x, y, Color.CYAN); } }, diff --git a/src/client/java/minicraft/screen/entry/BlankEntry.java b/src/client/java/minicraft/screen/entry/BlankEntry.java index fcad07afc..02baaa405 100644 --- a/src/client/java/minicraft/screen/entry/BlankEntry.java +++ b/src/client/java/minicraft/screen/entry/BlankEntry.java @@ -3,6 +3,7 @@ import minicraft.core.io.InputHandler; import minicraft.gfx.MinicraftImage; import minicraft.gfx.Screen; +import org.jetbrains.annotations.Nullable; public class BlankEntry extends ListEntry { @@ -15,7 +16,7 @@ public void tick(InputHandler input) { } @Override - public void render(Screen screen, int x, int y, boolean isSelected) { + public void render(Screen screen, @Nullable Screen.RenderingLimitingModel limitingModel, int x, int y, boolean isSelected) { } @Override diff --git a/src/client/java/minicraft/screen/entry/InputEntry.java b/src/client/java/minicraft/screen/entry/InputEntry.java index 5dceb61e4..3fb1d68ee 100644 --- a/src/client/java/minicraft/screen/entry/InputEntry.java +++ b/src/client/java/minicraft/screen/entry/InputEntry.java @@ -1,17 +1,24 @@ package minicraft.screen.entry; +import minicraft.core.Action; import minicraft.core.io.ClipboardHandler; import minicraft.core.io.InputHandler; import minicraft.core.io.Localization; import minicraft.gfx.Color; import minicraft.gfx.Font; import minicraft.gfx.Screen; +import minicraft.screen.RelPos; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; public class InputEntry extends ListEntry { private String prompt; private String regex; private int maxLength; + private RelPos entryPos; private String userInput; @@ -39,8 +46,13 @@ public InputEntry(String prompt, String regex, int maxLen, String initValue) { public void tick(InputHandler input) { String prev = userInput; userInput = input.addKeyTyped(userInput, regex); - if (!prev.equals(userInput) && listener != null) - listener.onChange(userInput); + if (!prev.equals(userInput)) { + if (hook != null) + hook.act(); + if (listener != null) + listener.onChange(userInput); + } + hook = null; // Once per tick if (maxLength > 0 && userInput.length() > maxLength) userInput = userInput.substring(0, maxLength); // truncates extra @@ -58,6 +70,13 @@ public void tick(InputHandler input) { } } + private @Nullable Action hook = null; + + @Override + public void hook(@NotNull Action callback) { + this.hook = callback; + } + public String getUserInput() { return userInput; } @@ -66,8 +85,9 @@ public String toString() { return Localization.getLocalized(prompt) + (prompt.length() == 0 ? "" : ": ") + userInput; } - public void render(Screen screen, int x, int y, boolean isSelected) { - Font.draw(toString(), screen, x, y, isValid() ? isSelected ? Color.GREEN : COL_UNSLCT : Color.RED); + @Override + public void render(Screen screen, @Nullable Screen.RenderingLimitingModel limitingModel, int x, int y, boolean isSelected) { + Font.draw(limitingModel, toString(), screen, x, y, isValid() ? isSelected ? Color.GREEN : COL_UNSLCT : Color.RED); } public boolean isValid() { diff --git a/src/client/java/minicraft/screen/entry/ItemEntry.java b/src/client/java/minicraft/screen/entry/ItemEntry.java index cfc17d1c3..ff35a64d6 100644 --- a/src/client/java/minicraft/screen/entry/ItemEntry.java +++ b/src/client/java/minicraft/screen/entry/ItemEntry.java @@ -3,6 +3,7 @@ import minicraft.core.io.InputHandler; import minicraft.gfx.Screen; import minicraft.item.Item; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -30,9 +31,9 @@ public void tick(InputHandler input) { } @Override - public void render(Screen screen, int x, int y, boolean isSelected) { - super.render(screen, x, y, true); - screen.render(x, y, item.sprite); + public void render(Screen screen, @Nullable Screen.RenderingLimitingModel limitingModel, int x, int y, boolean isSelected) { + super.render(screen, limitingModel, x, y, true); + screen.render(null, x, y, item.sprite); } // If you add to the length of the string, and therefore the width of the entry, then it will actually move the entry RIGHT in the inventory, instead of the intended left, because it is auto-positioned to the left side. diff --git a/src/client/java/minicraft/screen/entry/ListEntry.java b/src/client/java/minicraft/screen/entry/ListEntry.java index 6b00e17a8..17895a77e 100644 --- a/src/client/java/minicraft/screen/entry/ListEntry.java +++ b/src/client/java/minicraft/screen/entry/ListEntry.java @@ -1,11 +1,14 @@ package minicraft.screen.entry; +import minicraft.core.Action; import minicraft.core.io.InputHandler; import minicraft.gfx.Color; import minicraft.gfx.Font; import minicraft.gfx.Screen; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public abstract class ListEntry { +public abstract class ListEntry implements Screen.ScreenEntry { public static final int COL_UNSLCT = Color.GRAY; public static final int COL_SLCT = Color.WHITE; @@ -16,21 +19,31 @@ public abstract class ListEntry { * Ticks the entry. Used to handle input from the InputHandler * @param input InputHandler used to get player input. */ + @Override public abstract void tick(InputHandler input); - public void render(Screen screen, int x, int y, boolean isSelected, String contain, int containColor) { + @Override + public void tickScrollingTicker(@NotNull SelectableStringEntry.EntryXAccessor accessor) {} + + @Override + public boolean isScrollingTickerSet() { return false; } + + public void hook(@NotNull Action callback) {} + + @Override + public void render(Screen screen, @Nullable Screen.RenderingLimitingModel bounds, int x, int y, boolean isSelected, String contain, int containColor) { if (!visible) { return; } - render(screen, x, y, isSelected); + render(screen, bounds, x, y, isSelected); if (contain == null || contain.isEmpty()) { return; } String string = toString(); - Font.drawColor(string.replace(contain, Color.toStringCode(containColor) + contain + Color.WHITE_CODE), screen, x, y); + Font.drawColor(bounds, string.replace(contain, Color.toStringCode(containColor) + contain + Color.WHITE_CODE), screen, x, y); } /** @@ -40,14 +53,16 @@ public void render(Screen screen, int x, int y, boolean isSelected, String conta * @param x X coordinate * @param y Y coordinate * @param isSelected true if the entry is selected, false otherwise + * @param bounds X rendering bounds */ - public void render(Screen screen, int x, int y, boolean isSelected) { + @Override + public void render(Screen screen, @Nullable Screen.RenderingLimitingModel bounds, int x, int y, boolean isSelected) { if (visible) { String text = toString().replace(Color.WHITE_CODE + Color.GRAY_CODE, Color.toStringCode(getColor(isSelected))); if (text.contains(String.valueOf(Color.COLOR_CHAR))) - Font.drawColor(Color.toStringCode(getColor(isSelected)) + text, screen, x, y); + Font.drawColor(bounds, Color.toStringCode(getColor(isSelected)) + text, screen, x, y); else - Font.draw(text, screen, x, y, getColor(isSelected)); + Font.draw(bounds, text, screen, x, y, getColor(isSelected)); } } @@ -64,6 +79,7 @@ public int getColor(boolean isSelected) { * Calculates the width of the entry. * @return the entry's width */ + @Override public int getWidth() { return Font.textWidth(toString()); } diff --git a/src/client/java/minicraft/screen/entry/RecipeEntry.java b/src/client/java/minicraft/screen/entry/RecipeEntry.java index 41fe3fc75..651c357f6 100644 --- a/src/client/java/minicraft/screen/entry/RecipeEntry.java +++ b/src/client/java/minicraft/screen/entry/RecipeEntry.java @@ -4,6 +4,7 @@ import minicraft.gfx.Font; import minicraft.gfx.Screen; import minicraft.item.Recipe; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -28,10 +29,10 @@ public void tick(InputHandler input) { } @Override - public void render(Screen screen, int x, int y, boolean isSelected) { + public void render(Screen screen, @Nullable Screen.RenderingLimitingModel limitingModel, int x, int y, boolean isSelected) { if (isVisible()) { - Font.draw(toString(), screen, x, y, recipe.getCanCraft() ? COL_SLCT : COL_UNSLCT); - screen.render(x, y, getItem().sprite); + Font.draw(limitingModel, toString(), screen, x, y, recipe.getCanCraft() ? COL_SLCT : COL_UNSLCT); + screen.render(null, x, y, getItem().sprite); } } diff --git a/src/client/java/minicraft/screen/entry/SelectableStringEntry.java b/src/client/java/minicraft/screen/entry/SelectableStringEntry.java new file mode 100644 index 000000000..1ef4f35b4 --- /dev/null +++ b/src/client/java/minicraft/screen/entry/SelectableStringEntry.java @@ -0,0 +1,62 @@ +package minicraft.screen.entry; + +import minicraft.core.io.InputHandler; +import minicraft.core.io.Localization; +import minicraft.gfx.Color; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; + +public class SelectableStringEntry extends ListEntry { + + private static final int DEFAULT_COLOR = Color.WHITE; + + private String text; + private final int color; + private final boolean localize; + + private EntryScrollingTicker ticker; + + public SelectableStringEntry(String text) { + this(text, DEFAULT_COLOR); + } + public SelectableStringEntry(String text, boolean localize) { this(text, DEFAULT_COLOR, localize); } // This might be false as the text might have been localized already. + public SelectableStringEntry(String text, int color) { this(text, color, true); } // This should be always true with the new localization IDs. + public SelectableStringEntry(String text, int color, boolean localize) { + this.text = text; + this.localize = localize; + this.color = color; + } + + public void setExceedingAlternatingScrollingTicker() { + ticker = new ExceedingHorizontallyAlternatingScrollingTicker(); + } + + public void setScrollerScrollingTicker() { setScrollerScrollingTicker(-1); } + public void setScrollerScrollingTicker(@MagicConstant int direction) { + ticker = new HorizontalScrollerScrollingTicker(direction); + } + + public void setText(String text) { + this.text = text; + } + + @Override + public void tick(InputHandler input) {} + + @Override + public void tickScrollingTicker(@NotNull EntryXAccessor accessor) { + if (ticker != null) + ticker.tick(accessor); + } + + @Override + public boolean isScrollingTickerSet() { + return ticker != null; + } + + @Override + public int getColor(boolean isSelected) { return color; } + + @Override + public String toString() { return localize? Localization.getLocalized(text): text; } +} diff --git a/src/client/java/minicraft/screen/entry/StringEntry.java b/src/client/java/minicraft/screen/entry/StringEntry.java index ec866f594..b92e27ea0 100644 --- a/src/client/java/minicraft/screen/entry/StringEntry.java +++ b/src/client/java/minicraft/screen/entry/StringEntry.java @@ -10,14 +10,10 @@ import java.util.Arrays; // an unselectable line. -public class StringEntry extends ListEntry { +public class StringEntry extends SelectableStringEntry { private static final int DEFAULT_COLOR = Color.WHITE; - private String text; - private int color; - private boolean localize; - /** * */ @@ -54,27 +50,7 @@ public StringEntry(String text, int color) { } // This should be always true with the new localization IDs. public StringEntry(String text, int color, boolean localize) { + super(text, color, localize); setSelectable(false); - this.text = text; - this.localize = localize; - this.color = color; - } - - public void setText(String text) { - this.text = text; - } - - @Override - public void tick(InputHandler input) { - } - - @Override - public int getColor(boolean isSelected) { - return color; - } - - @Override - public String toString() { - return localize ? Localization.getLocalized(text) : text; } }