diff --git a/src/main/java/cz/jzitnik/game/entities/Dependencies.java b/src/main/java/cz/jzitnik/game/entities/Dependencies.java index 0f15ec3..8632fc2 100644 --- a/src/main/java/cz/jzitnik/game/entities/Dependencies.java +++ b/src/main/java/cz/jzitnik/game/entities/Dependencies.java @@ -9,6 +9,8 @@ import cz.jzitnik.game.handlers.tooluse.ToolUseProvider; import cz.jzitnik.game.mobs.EntityHurtAnimation; import cz.jzitnik.game.mobs.EntityKill; import cz.jzitnik.game.smelting.Smelting; +import cz.jzitnik.game.sprites.ui.Font; +import cz.jzitnik.game.ui.Escape; public class Dependencies { public PlaceHandler placeHandler = new PlaceHandler(); @@ -20,4 +22,6 @@ public class Dependencies { public Smelting smelting = new Smelting(); public ToolUseProvider toolUseProvider = new ToolUseProvider(); public Sound sound = new Sound(); + public Font font = new Font(); + public Escape escape = new Escape(); } diff --git a/src/main/java/cz/jzitnik/game/sprites/ui/Font.java b/src/main/java/cz/jzitnik/game/sprites/ui/Font.java index f7a93ac..b4c2188 100644 --- a/src/main/java/cz/jzitnik/game/sprites/ui/Font.java +++ b/src/main/java/cz/jzitnik/game/sprites/ui/Font.java @@ -1,11 +1,34 @@ package cz.jzitnik.game.sprites.ui; -import cz.jzitnik.tui.ResourceLoader; +import java.util.function.Function; +import org.jline.terminal.Terminal; + +import cz.jzitnik.tui.ResourceLoader; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class Font { private final String[] lines = ResourceLoader.loadResource("ui/font.ans").split("\n"); private final int HEIGHT = 7; + @AllArgsConstructor + @Getter + public class FontDTO { + private String data; + private int width; + private int height; + } + + @Getter + @AllArgsConstructor + private class CharDTO { + private String character; + private int width; + } + private String get(int startY, int startX, int height, int width, String color) { StringBuilder stringBuilder = new StringBuilder(); @@ -18,11 +41,10 @@ public class Font { stringBuilder.append("\033[0m\n"); } - return stringBuilder.toString(); } - private String getDigit(char digit, String color) { + private CharDTO getDigit(char digit, String color) { int num = Integer.valueOf(digit); int width = 12; int startY = HEIGHT; @@ -33,12 +55,12 @@ public class Font { startX = (26 + 9) * width; } - return get(startY, startX, HEIGHT, width, color); + return new CharDTO(get(startY, startX, HEIGHT, width, color), width); } - public String getChar(char character, String color) { + public CharDTO getChar(char character, String color) { if (character == ' ') { - return ("\033[49m ".repeat(12) + "\n").repeat(HEIGHT); + return new CharDTO(("\033[49m ".repeat(12) + "\n").repeat(HEIGHT), 12); } if (Character.isDigit(character)) { @@ -50,16 +72,19 @@ public class Font { int startY = (upper ? 0 : 1) * HEIGHT; int startX = (upper ? character - 'A' : character - 'a') * width; - return get(startY, startX, HEIGHT, width, color); + return new CharDTO(get(startY, startX, HEIGHT, width, color), width); } - public String getLine(String text) { + public FontDTO getLine(String text) { char[] chars = text.toCharArray(); String[][] letters = new String[chars.length][]; + int width = 0; for (int i = 0; i < chars.length; i++) { - letters[i] = getChar(chars[i], "[47m").split("\n"); + var charDto = getChar(chars[i], "[47m"); + letters[i] = charDto.getCharacter().split("\n"); + width += charDto.getWidth(); } StringBuilder stringBuilder = new StringBuilder(); @@ -72,6 +97,137 @@ public class Font { stringBuilder.append("\n"); } - return stringBuilder.toString(); + return new FontDTO(stringBuilder.toString(), width, HEIGHT); + } + + public FontDTO scale(FontDTO font, int times) { + StringBuilder stringBuilder = new StringBuilder(); + var line = font.getData(); + var lines = line.split("\n"); + + for (int lineNum = 0; lineNum < lines.length; lineNum++) { + for (int i = 0; i < times; i++) { + stringBuilder.append(scaleLine(lines[lineNum], times)); + stringBuilder.append("\n"); + } + } + + return new FontDTO(stringBuilder.toString(), font.getWidth() * times, font.getHeight() * times); + } + + private StringBuilder scaleLine(String line, int times) { + StringBuilder result = new StringBuilder(); + + for (char c : line.toCharArray()) { + if (c == ' ') { + result.append(" ".repeat(times)); + } else { + result.append(c); + } + } + + return result; + } + + public FontDTO getScaledLine(String text, Size size, int termWidth) { + return scale(getLine(text), size.getFunc().apply(termWidth)); + } + + // This will probably need little more work + public enum Size { + SMALL((x) -> { + if (x < 800) { + return 1; + } + + return 2; + }), + MEDIUM((x) -> { + if (x < 800) { + return 2; + } + + return 3; + }), + LARGE((x) -> { + if (x < 800) { + return 3; + } + + return 4; + }); + + @Getter + private Function func; + + Size(Function func) { + this.func = func; + } + } + + public enum Align { + LEFT, + RIGHT, + CENTER + } + + private FontDTO applyAlignment(FontDTO data, Align alignment, int termWidth) { + return switch (alignment) { + case LEFT -> data; + case CENTER -> { + var lines = data.getData().split("\n"); + int nowWidth = data.getWidth(); + + StringBuilder buffer = new StringBuilder(); + + var leftPad = (termWidth - nowWidth) / 2; + + for (int i = 0; i < lines.length; i++) { + buffer.append(" ".repeat(leftPad)).append(lines[i]); + buffer.append("\n"); + } + + yield new FontDTO(buffer.toString(), termWidth, data.getHeight()); + } + case RIGHT -> { + var lines = data.getData().split("\n"); + int nowWidth = data.getWidth(); + + StringBuilder buffer = new StringBuilder(); + + var leftPad = termWidth - nowWidth; + + for (int i = 0; i < lines.length; i++) { + buffer.append(" ".repeat(leftPad)).append(lines[i]); + buffer.append("\n"); + } + + yield new FontDTO(buffer.toString(), termWidth, data.getHeight()); + } + }; + } + + public FontDTO line(Terminal terminal, String text, Object... attributes) { + int termWidth = terminal.getWidth(); + //int termHeight = terminal.getHeight(); + + Size fontSize = Size.MEDIUM; + Align alignment = Align.LEFT; + + for (Object attribute : attributes) { + if (Size.class.isAssignableFrom(attribute.getClass())) { + fontSize = (Size) attribute; + continue; + } + + if (Align.class.isAssignableFrom(attribute.getClass())) { + alignment = (Align) attribute; + continue; + } + + log.error("Invalid attribute class {}. Skipping", attribute.getClass().getSimpleName()); + } + + return applyAlignment(getScaledLine(text, fontSize, termWidth), alignment, termWidth); } } diff --git a/src/main/java/cz/jzitnik/game/ui/Escape.java b/src/main/java/cz/jzitnik/game/ui/Escape.java index aed55c6..b026931 100644 --- a/src/main/java/cz/jzitnik/game/ui/Escape.java +++ b/src/main/java/cz/jzitnik/game/ui/Escape.java @@ -2,13 +2,21 @@ package cz.jzitnik.game.ui; import org.jline.terminal.Terminal; -import cz.jzitnik.game.sprites.ui.Font; +import cz.jzitnik.game.Game; +import cz.jzitnik.game.sprites.ui.Font.*; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class Escape { - public static void render(StringBuilder buffer, Terminal terminal) { - Font font = new Font(); - String character = font.getLine("Never gonna give you up never gonna let you down"); + public void render(StringBuilder buffer, Terminal terminal, Game game) { + var font = game.getGameStates().dependencies.font; + var width = terminal.getWidth(); + var height = terminal.getHeight(); - buffer.append(character); + log.debug("Terminal width: {}", width); + log.debug("Terminal height: {}", height); + + var twodcraft = font.line(terminal, "2DCraft", Size.LARGE, Align.LEFT); + buffer.append(twodcraft.getData()); } } diff --git a/src/main/java/cz/jzitnik/tui/ScreenRenderer.java b/src/main/java/cz/jzitnik/tui/ScreenRenderer.java index 7574419..e607c43 100644 --- a/src/main/java/cz/jzitnik/tui/ScreenRenderer.java +++ b/src/main/java/cz/jzitnik/tui/ScreenRenderer.java @@ -72,6 +72,7 @@ public class ScreenRenderer { main.append("\033[H\033[2J"); switch (game.getWindow()) { + // Different screens: Probably will need a rewrite case INVENTORY -> game.getInventory().renderFull(main, terminal, spriteList, true, Optional.empty()); case CRAFTING_TABLE -> game.getGameStates().craftingTable.render(main, terminal, spriteList); case CHEST -> ((Chest) game.getWorld()[game.getGameStates().clickY][game.getGameStates().clickX].stream() @@ -80,7 +81,7 @@ public class ScreenRenderer { case FURNACE -> ((Furnace) game.getWorld()[game.getGameStates().clickY][game.getGameStates().clickX] .stream().filter(i -> i.getBlockId().equals("furnace")).toList().getFirst().getData()).render(game, main, terminal, spriteList); - case ESC -> Escape.render(main, terminal); + case ESC -> game.getGameStates().dependencies.escape.render(main, terminal, game); case WORLD -> { // World