From a26aaf69e11b4e17108fc5b757de255398124268 Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Tue, 16 Dec 2025 22:24:18 +0100 Subject: [PATCH] refactor: Improved chest logic --- .../java/cz/jzitnik/game/objects/Chest.java | 223 ++++++++++++------ .../utils/UIClickHandlerRepository.java | 3 +- 2 files changed, 151 insertions(+), 75 deletions(-) diff --git a/src/main/java/cz/jzitnik/game/objects/Chest.java b/src/main/java/cz/jzitnik/game/objects/Chest.java index 2b9778a..4852748 100644 --- a/src/main/java/cz/jzitnik/game/objects/Chest.java +++ b/src/main/java/cz/jzitnik/game/objects/Chest.java @@ -31,11 +31,19 @@ import java.util.List; @Slf4j public final class Chest extends GameObject implements Interactable, UIClickHandler { + private static final TextColor BORDER_COLOR = new TextColor.RGB(0, 0, 0); + private static final TextColor TRANSPARENT_COLOR = new TextColor.RGB(255, 255, 255); + private final List items; private final DependencyManager dependencyManager; private int listenerHashCode; + private int actualDisplayStartX; + private int actualDisplayStartY; + private int chestUISizeX; + private int chestUISizeY; + @InjectDependency private StateManager sm; @InjectDependency @@ -44,6 +52,7 @@ public final class Chest extends GameObject implements Interactable, UIClickHand private EventManager eventManager; @InjectDependency private UIClickHandlerRepository uiClickHandlerRepository; + @InjectState private GameState gameState; @InjectState @@ -57,11 +66,6 @@ public final class Chest extends GameObject implements Interactable, UIClickHand this.dependencyManager = dm; } - private int actualDisplayStartX; - private int actualDisplayStartY; - private int chestUISizeX; - private int chestUISizeY; - @Override public void interact(DependencyManager dm) { dm.inject(this); @@ -72,112 +76,180 @@ public final class Chest extends GameObject implements Interactable, UIClickHand private void render(boolean clear) { GameRoom currentRoom = gameState.getCurrentRoom(); Player player = gameState.getPlayer(); - BufferedImage playerTexture = RerenderUtils.getPlayer(resourceManager, player); - BufferedImage room = resourceManager.getResource(currentRoom.getTexture()); - BufferedImage chest = getTexture(); + BufferedImage roomTexture = resourceManager.getResource(currentRoom.getTexture()); + BufferedImage playerTexture = RerenderUtils.getPlayer(resourceManager, player); + BufferedImage chestTexture = getTexture(); + var buffer = screenBuffer.getRenderedBuffer(); var overrideBuffer = currentRoom.getOverrideBuffer(); - RoomCords start = RerenderUtils.getStart(room, terminalState.getTerminalScreen().getTerminalSize()); + RoomCords start = RerenderUtils.getStart( + roomTexture, + terminalState.getTerminalScreen().getTerminalSize() + ); int itemCount = items.size(); + calculateUISize(itemCount); int chestUIStartX = getCords().getX(); int chestUIStartY = getCords().getY(); - chestUISizeY = 16 + 4; - chestUISizeX = 4 + itemCount * 16 + (itemCount - 1) * 2; + int guiStartX = chestUIStartX + (chestTexture.getWidth() / 2) - (chestUISizeX / 2); + int guiStartY = chestUIStartY - chestUISizeY - 1; - int chestGUIStartY = chestUIStartY - chestUISizeY - 1; - int chestGUIStartX = chestUIStartX + (chest.getWidth() / 2) - (chestUISizeX / 2); + TerminalPosition guiStart = new TerminalPosition(guiStartX + start.getX(), guiStartY + start.getY()); + TerminalPosition guiEnd = new TerminalPosition( + (guiStartX + chestUISizeX - 1) + start.getX(), + (guiStartY + chestUISizeY - 1) + start.getY() + ); - TerminalPosition guiStart = new TerminalPosition(chestGUIStartX / 2, chestGUIStartY); - TerminalPosition guiEnd = new TerminalPosition((chestGUIStartX + chestUISizeX - 1) / 2, ((chestGUIStartY + chestUISizeY - 1) / 2)); - - actualDisplayStartX = chestGUIStartX + start.getX() + 2; - actualDisplayStartY = chestGUIStartY + start.getY() + 2; + actualDisplayStartX = guiStartX + start.getX() + 2; + actualDisplayStartY = guiStartY + start.getY() + 2; if (clear) { - int chestUISizeX = 4 + (itemCount + 1) * 16 + (itemCount) * 2; - int chestGUIStartX2 = chestUIStartX + (chest.getWidth() / 2) - (chestUISizeX / 2); + clearPreviousUI( + currentRoom, + roomTexture, + player, + playerTexture, + buffer, + overrideBuffer, + start, + guiStartY, + chestUIStartX, + chestTexture.getWidth(), + itemCount + ); - for (int y = chestGUIStartY; y < chestGUIStartY + chestUISizeY; y++) { - for (int x = chestGUIStartX2; x < chestGUIStartX2 + chestUISizeX; x++) { - log.debug("{} {}", x, y); + int clearWidth = 4 + (itemCount + 1) * 16 + itemCount * 2; + int clearStartX = chestUIStartX + (chestTexture.getWidth() / 2) - (clearWidth / 2); - int intPixel = RerenderUtils.getPixel(currentRoom, room, null, new HashSet<>(), player, playerTexture, x, y).pixel(); // This will never reach doors so no need to load texture - int red = (intPixel >> 16) & 0xff; - int green = (intPixel >> 8) & 0xff; - int blue = intPixel & 0xff; - - Pixel pixel = new ColoredPixel(new TextColor.RGB(red, green, blue)); - - buffer[y + start.getY()][x + start.getX()] = pixel; - overrideBuffer[y][x] = new Empty(); - } - } - - guiStart = new TerminalPosition(chestGUIStartX2 / 2, chestGUIStartY); - guiEnd = new TerminalPosition((chestGUIStartX2 + chestUISizeX - 1) / 2, ((chestGUIStartY + chestUISizeY - 1) / 2)); + guiStart = new TerminalPosition(clearStartX + start.getX(), guiStartY + start.getY()); + guiEnd = new TerminalPosition(clearStartX + start.getX() + clearWidth, (guiStartY + chestUISizeY - 1) + start.getY()); } if (!items.isEmpty()) { - for (int y = chestGUIStartY; y < chestGUIStartY + chestUISizeY; y++) { - for (int x = chestGUIStartX; x < chestGUIStartX + chestUISizeX; x++) { - int objectX = x - chestGUIStartX; - int objectY = y - chestGUIStartY; - - Pixel pixel = getPixel(objectX, objectY, chestUISizeX, chestUISizeY); - - buffer[y + start.getY()][x + start.getX()] = pixel; - overrideBuffer[y][x] = pixel; - } - } + drawUI(buffer, overrideBuffer, start, guiStartX, guiStartY); } - RerenderUtils.rerenderPart(guiStart.getColumn(), guiEnd.getColumn(), guiStart.getRow(), guiEnd.getRow(), start.getX(), start.getY(), currentRoom, room, player, playerTexture, screenBuffer, resourceManager); + RerenderUtils.rerenderPart( + guiStart.getColumn() - start.getX(), + guiEnd.getColumn() - start.getX(), + guiStart.getRow() - start.getY(), + guiEnd.getRow() - start.getY(), + start.getX(), + start.getY(), + currentRoom, + roomTexture, + player, + playerTexture, + screenBuffer, + resourceManager + ); - this.listenerHashCode = uiClickHandlerRepository.registerCurrentRoomHandler(RerenderScreen.ScreenPart.full(terminalState.getTerminalScreen().getTerminalSize()), this); + RerenderScreen.ScreenPart sp = new RerenderScreen.ScreenPart(guiStart, guiEnd); - eventManager.emitEvent(RerenderScreen.full(terminalState.getTerminalScreen().getTerminalSize())); // TODO: Make this not rerender full screen + listenerHashCode = uiClickHandlerRepository.registerCurrentRoomHandler(sp, this); + + //eventManager.emitEvent(RerenderScreen.full(terminalState.getTerminalScreen().getTerminalSize())); + + eventManager.emitEvent(new RerenderScreen(sp)); } - // TODO: Add some padding on the item - private Pixel getPixel(int objectX, int objectY, int chestUISizeX, int chestUISizeY) { - if (objectX >= 0 && objectX <= 1 || objectX >= chestUISizeX - 2 && objectX <= chestUISizeX - 1 || objectY >= 0 && objectY <= 1 || objectY >= chestUISizeY - 2 && objectY <= chestUISizeY - 1) { - return new ColoredPixel(new TextColor.RGB(0, 0, 0)); + private void calculateUISize(int itemCount) { + chestUISizeY = 20; + chestUISizeX = 4 + itemCount * 16 + (itemCount - 1) * 2; + } + + private void clearPreviousUI( + GameRoom room, + BufferedImage roomTexture, + Player player, + BufferedImage playerTexture, + Pixel[][] buffer, + Pixel[][] overrideBuffer, + RoomCords start, + int guiStartY, + int chestUIStartX, + int chestTextureWidth, + int itemCount + ) { + int clearWidth = 4 + (itemCount + 1) * 16 + itemCount * 2; + int clearStartX = chestUIStartX + (chestTextureWidth / 2) - (clearWidth / 2); + + for (int y = guiStartY; y < guiStartY + chestUISizeY; y++) { + for (int x = clearStartX; x < clearStartX + clearWidth; x++) { + int pixel = RerenderUtils.getPixel( + room, + roomTexture, + null, + new HashSet<>(), + player, + playerTexture, + x, + y + ).pixel(); + + buffer[y + start.getY()][x + start.getX()] = pixelToColored(pixel); + overrideBuffer[y][x] = new Empty(); + } + } + } + + private void drawUI( + Pixel[][] buffer, + Pixel[][] overrideBuffer, + RoomCords start, + int guiStartX, + int guiStartY + ) { + for (int y = 0; y < chestUISizeY; y++) { + for (int x = 0; x < chestUISizeX; x++) { + Pixel pixel = getPixel(x, y, chestUISizeX, chestUISizeY); + buffer[guiStartY + y + start.getY()][guiStartX + x + start.getX()] = pixel; + overrideBuffer[guiStartY + y][guiStartX + x] = pixel; + } + } + } + + private Pixel pixelToColored(int argb) { + int r = (argb >> 16) & 0xff; + int g = (argb >> 8) & 0xff; + int b = argb & 0xff; + return new ColoredPixel(new TextColor.RGB(r, g, b)); + } + + private Pixel getPixel(int objectX, int objectY, int width, int height) { + if (isBorder(objectX, objectY, width, height)) { + return new ColoredPixel(BORDER_COLOR); } int screenX = objectX - 2; int screenY = objectY - 2; + int part = screenX / 18; int rest = screenX % 18; - if (rest == 16 || rest == 17) { - return new ColoredPixel(new TextColor.RGB(0, 0, 0)); + if (rest >= 16) { + return new ColoredPixel(BORDER_COLOR); } GameItem item = items.get(part); BufferedImage texture = item.getTexture(); - log.debug("{} {}", rest, screenY); - int pixel = texture.getRGB(rest, screenY); + int pixel = texture.getRGB(rest, screenY); int alpha = (pixel >> 24) & 0xff; if (alpha == 0) { - return new ColoredPixel( - new TextColor.RGB(255, 255, 255) - ); + return new ColoredPixel(TRANSPARENT_COLOR); } - int red = (pixel >> 16) & 0xff; - int green = (pixel >> 8) & 0xff; - int blue = pixel & 0xff; + return pixelToColored(pixel); + } - return new ColoredPixel( - new TextColor.RGB(red, green, blue) - ); + private boolean isBorder(int x, int y, int width, int height) { + return x <= 1 || x >= width - 2 || y <= 1 || y >= height - 2; } @Override @@ -192,22 +264,25 @@ public final class Chest extends GameObject implements Interactable, UIClickHand log.debug("Screen: x: {}, y: {}", screenX, screenY); - int part = screenX / 18; + if (screenX < 0 || screenY < 0 || screenX > chestUISizeX || screenY > chestUISizeY) { + return; + } - if (screenX < 0 || screenY < 0 || screenX > chestUISizeX || screenY > chestUISizeY || part >= items.size()) { + int part = screenX / 18; + if (part >= items.size()) { return; } int rest = screenX % 18; - if (rest == 17 || rest == 16) { + if (rest >= 16) { return; } - GameItem item = items.get(part); items.remove(part); - // TODO: Add item to inventory - + if (items.isEmpty()) { + uiClickHandlerRepository.removeHandlerForCurrentRoom(listenerHashCode, this); + } render(true); } } diff --git a/src/main/java/cz/jzitnik/utils/UIClickHandlerRepository.java b/src/main/java/cz/jzitnik/utils/UIClickHandlerRepository.java index a39f552..47c8f76 100644 --- a/src/main/java/cz/jzitnik/utils/UIClickHandlerRepository.java +++ b/src/main/java/cz/jzitnik/utils/UIClickHandlerRepository.java @@ -44,8 +44,9 @@ public class UIClickHandlerRepository { for (var entry : handlers.entrySet()) { RerenderScreen.ScreenPart part = entry.getKey(); UIClickHandler uiClickHandler = entry.getValue(); + TerminalPosition position = new TerminalPosition(mouseAction.getPosition().getColumn(), mouseAction.getPosition().getRow() * 2); - if (part.isWithin(mouseAction.getPosition())) { + if (part.isWithin(position)) { uiClickHandler.handleClick(mouseAction); return; }