refactor: Improved chest logic

This commit is contained in:
2025-12-16 22:24:18 +01:00
parent 3f0ccc49a8
commit a26aaf69e1
2 changed files with 151 additions and 75 deletions

View File

@@ -31,11 +31,19 @@ import java.util.List;
@Slf4j @Slf4j
public final class Chest extends GameObject implements Interactable, UIClickHandler { 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<GameItem> items; private final List<GameItem> items;
private final DependencyManager dependencyManager; private final DependencyManager dependencyManager;
private int listenerHashCode; private int listenerHashCode;
private int actualDisplayStartX;
private int actualDisplayStartY;
private int chestUISizeX;
private int chestUISizeY;
@InjectDependency @InjectDependency
private StateManager sm; private StateManager sm;
@InjectDependency @InjectDependency
@@ -44,6 +52,7 @@ public final class Chest extends GameObject implements Interactable, UIClickHand
private EventManager eventManager; private EventManager eventManager;
@InjectDependency @InjectDependency
private UIClickHandlerRepository uiClickHandlerRepository; private UIClickHandlerRepository uiClickHandlerRepository;
@InjectState @InjectState
private GameState gameState; private GameState gameState;
@InjectState @InjectState
@@ -57,11 +66,6 @@ public final class Chest extends GameObject implements Interactable, UIClickHand
this.dependencyManager = dm; this.dependencyManager = dm;
} }
private int actualDisplayStartX;
private int actualDisplayStartY;
private int chestUISizeX;
private int chestUISizeY;
@Override @Override
public void interact(DependencyManager dm) { public void interact(DependencyManager dm) {
dm.inject(this); dm.inject(this);
@@ -72,112 +76,180 @@ public final class Chest extends GameObject implements Interactable, UIClickHand
private void render(boolean clear) { private void render(boolean clear) {
GameRoom currentRoom = gameState.getCurrentRoom(); GameRoom currentRoom = gameState.getCurrentRoom();
Player player = gameState.getPlayer(); Player player = gameState.getPlayer();
BufferedImage playerTexture = RerenderUtils.getPlayer(resourceManager, player);
BufferedImage room = resourceManager.getResource(currentRoom.getTexture()); BufferedImage roomTexture = resourceManager.getResource(currentRoom.getTexture());
BufferedImage chest = getTexture(); BufferedImage playerTexture = RerenderUtils.getPlayer(resourceManager, player);
BufferedImage chestTexture = getTexture();
var buffer = screenBuffer.getRenderedBuffer(); var buffer = screenBuffer.getRenderedBuffer();
var overrideBuffer = currentRoom.getOverrideBuffer(); var overrideBuffer = currentRoom.getOverrideBuffer();
RoomCords start = RerenderUtils.getStart(room, terminalState.getTerminalScreen().getTerminalSize()); RoomCords start = RerenderUtils.getStart(
roomTexture,
terminalState.getTerminalScreen().getTerminalSize()
);
int itemCount = items.size(); int itemCount = items.size();
calculateUISize(itemCount);
int chestUIStartX = getCords().getX(); int chestUIStartX = getCords().getX();
int chestUIStartY = getCords().getY(); int chestUIStartY = getCords().getY();
chestUISizeY = 16 + 4; int guiStartX = chestUIStartX + (chestTexture.getWidth() / 2) - (chestUISizeX / 2);
chestUISizeX = 4 + itemCount * 16 + (itemCount - 1) * 2; int guiStartY = chestUIStartY - chestUISizeY - 1;
int chestGUIStartY = chestUIStartY - chestUISizeY - 1; TerminalPosition guiStart = new TerminalPosition(guiStartX + start.getX(), guiStartY + start.getY());
int chestGUIStartX = chestUIStartX + (chest.getWidth() / 2) - (chestUISizeX / 2); TerminalPosition guiEnd = new TerminalPosition(
(guiStartX + chestUISizeX - 1) + start.getX(),
(guiStartY + chestUISizeY - 1) + start.getY()
);
TerminalPosition guiStart = new TerminalPosition(chestGUIStartX / 2, chestGUIStartY); actualDisplayStartX = guiStartX + start.getX() + 2;
TerminalPosition guiEnd = new TerminalPosition((chestGUIStartX + chestUISizeX - 1) / 2, ((chestGUIStartY + chestUISizeY - 1) / 2)); actualDisplayStartY = guiStartY + start.getY() + 2;
actualDisplayStartX = chestGUIStartX + start.getX() + 2;
actualDisplayStartY = chestGUIStartY + start.getY() + 2;
if (clear) { if (clear) {
int chestUISizeX = 4 + (itemCount + 1) * 16 + (itemCount) * 2; clearPreviousUI(
int chestGUIStartX2 = chestUIStartX + (chest.getWidth() / 2) - (chestUISizeX / 2); currentRoom,
roomTexture,
player,
playerTexture,
buffer,
overrideBuffer,
start,
guiStartY,
chestUIStartX,
chestTexture.getWidth(),
itemCount
);
for (int y = chestGUIStartY; y < chestGUIStartY + chestUISizeY; y++) { int clearWidth = 4 + (itemCount + 1) * 16 + itemCount * 2;
for (int x = chestGUIStartX2; x < chestGUIStartX2 + chestUISizeX; x++) { int clearStartX = chestUIStartX + (chestTexture.getWidth() / 2) - (clearWidth / 2);
log.debug("{} {}", x, y);
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 guiStart = new TerminalPosition(clearStartX + start.getX(), guiStartY + start.getY());
int red = (intPixel >> 16) & 0xff; guiEnd = new TerminalPosition(clearStartX + start.getX() + clearWidth, (guiStartY + chestUISizeY - 1) + start.getY());
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));
} }
if (!items.isEmpty()) { if (!items.isEmpty()) {
for (int y = chestGUIStartY; y < chestGUIStartY + chestUISizeY; y++) { drawUI(buffer, overrideBuffer, start, guiStartX, guiStartY);
for (int x = chestGUIStartX; x < chestGUIStartX + chestUISizeX; x++) { }
int objectX = x - chestGUIStartX;
int objectY = y - chestGUIStartY;
Pixel pixel = getPixel(objectX, objectY, chestUISizeX, chestUISizeY); 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
);
buffer[y + start.getY()][x + start.getX()] = pixel; RerenderScreen.ScreenPart sp = new RerenderScreen.ScreenPart(guiStart, guiEnd);
overrideBuffer[y][x] = pixel;
listenerHashCode = uiClickHandlerRepository.registerCurrentRoomHandler(sp, this);
//eventManager.emitEvent(RerenderScreen.full(terminalState.getTerminalScreen().getTerminalSize()));
eventManager.emitEvent(new RerenderScreen(sp));
}
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();
} }
} }
} }
RerenderUtils.rerenderPart(guiStart.getColumn(), guiEnd.getColumn(), guiStart.getRow(), guiEnd.getRow(), start.getX(), start.getY(), currentRoom, room, player, playerTexture, screenBuffer, resourceManager); private void drawUI(
Pixel[][] buffer,
this.listenerHashCode = uiClickHandlerRepository.registerCurrentRoomHandler(RerenderScreen.ScreenPart.full(terminalState.getTerminalScreen().getTerminalSize()), this); Pixel[][] overrideBuffer,
RoomCords start,
eventManager.emitEvent(RerenderScreen.full(terminalState.getTerminalScreen().getTerminalSize())); // TODO: Make this not rerender full screen 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;
}
}
} }
// TODO: Add some padding on the item private Pixel pixelToColored(int argb) {
private Pixel getPixel(int objectX, int objectY, int chestUISizeX, int chestUISizeY) { int r = (argb >> 16) & 0xff;
if (objectX >= 0 && objectX <= 1 || objectX >= chestUISizeX - 2 && objectX <= chestUISizeX - 1 || objectY >= 0 && objectY <= 1 || objectY >= chestUISizeY - 2 && objectY <= chestUISizeY - 1) { int g = (argb >> 8) & 0xff;
return new ColoredPixel(new TextColor.RGB(0, 0, 0)); 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 screenX = objectX - 2;
int screenY = objectY - 2; int screenY = objectY - 2;
int part = screenX / 18; int part = screenX / 18;
int rest = screenX % 18; int rest = screenX % 18;
if (rest == 16 || rest == 17) { if (rest >= 16) {
return new ColoredPixel(new TextColor.RGB(0, 0, 0)); return new ColoredPixel(BORDER_COLOR);
} }
GameItem item = items.get(part); GameItem item = items.get(part);
BufferedImage texture = item.getTexture(); 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; int alpha = (pixel >> 24) & 0xff;
if (alpha == 0) { if (alpha == 0) {
return new ColoredPixel( return new ColoredPixel(TRANSPARENT_COLOR);
new TextColor.RGB(255, 255, 255)
);
} }
int red = (pixel >> 16) & 0xff; return pixelToColored(pixel);
int green = (pixel >> 8) & 0xff; }
int blue = pixel & 0xff;
return new ColoredPixel( private boolean isBorder(int x, int y, int width, int height) {
new TextColor.RGB(red, green, blue) return x <= 1 || x >= width - 2 || y <= 1 || y >= height - 2;
);
} }
@Override @Override
@@ -192,22 +264,25 @@ public final class Chest extends GameObject implements Interactable, UIClickHand
log.debug("Screen: x: {}, y: {}", screenX, screenY); 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; return;
} }
int rest = screenX % 18; int rest = screenX % 18;
if (rest == 17 || rest == 16) { if (rest >= 16) {
return; return;
} }
GameItem item = items.get(part);
items.remove(part); items.remove(part);
// TODO: Add item to inventory if (items.isEmpty()) {
uiClickHandlerRepository.removeHandlerForCurrentRoom(listenerHashCode, this);
}
render(true); render(true);
} }
} }

View File

@@ -44,8 +44,9 @@ public class UIClickHandlerRepository {
for (var entry : handlers.entrySet()) { for (var entry : handlers.entrySet()) {
RerenderScreen.ScreenPart part = entry.getKey(); RerenderScreen.ScreenPart part = entry.getKey();
UIClickHandler uiClickHandler = entry.getValue(); 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); uiClickHandler.handleClick(mouseAction);
return; return;
} }