From e1404ea9283042310a998304424b875a4c451f27 Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Tue, 16 Dec 2025 14:50:44 +0100 Subject: [PATCH] feat: Started items and chest ui --- .../java/cz/jzitnik/events/FullRoomDraw.java | 5 +- .../events/handlers/FullRoomDrawHandler.java | 14 +++- .../handlers/MouseActionEventHandler.java | 2 +- .../handlers/PlayerMoveEventHandler.java | 1 - src/main/java/cz/jzitnik/game/GameRoom.java | 23 ++++++- src/main/java/cz/jzitnik/game/GameSetup.java | 7 +- .../java/cz/jzitnik/game/ResourceManager.java | 10 ++- .../java/cz/jzitnik/game/items/GameItem.java | 16 +++++ src/main/java/cz/jzitnik/game/items/Item.java | 4 -- .../cz/jzitnik/game/items/WoodenSword.java | 14 ++++ .../jzitnik/game/items/strategy/Strategy.java | 4 ++ .../game/items/strategy/SwordStrategy.java | 9 +++ .../cz/jzitnik/game/items/types/ItemType.java | 8 +++ .../cz/jzitnik/game/items/types/Sword.java | 19 ++++++ .../java/cz/jzitnik/game/objects/Chest.java | 66 +++++++++++++++++-- .../java/cz/jzitnik/screens/ChestScreen.java | 63 ------------------ src/main/java/cz/jzitnik/screens/Screen.java | 2 +- .../cz/jzitnik/utils/DependencyManager.java | 12 ++-- .../java/cz/jzitnik/utils/RerenderUtils.java | 26 +++++--- 19 files changed, 206 insertions(+), 99 deletions(-) create mode 100644 src/main/java/cz/jzitnik/game/items/GameItem.java delete mode 100644 src/main/java/cz/jzitnik/game/items/Item.java create mode 100644 src/main/java/cz/jzitnik/game/items/WoodenSword.java create mode 100644 src/main/java/cz/jzitnik/game/items/strategy/Strategy.java create mode 100644 src/main/java/cz/jzitnik/game/items/strategy/SwordStrategy.java create mode 100644 src/main/java/cz/jzitnik/game/items/types/ItemType.java create mode 100644 src/main/java/cz/jzitnik/game/items/types/Sword.java delete mode 100644 src/main/java/cz/jzitnik/screens/ChestScreen.java diff --git a/src/main/java/cz/jzitnik/events/FullRoomDraw.java b/src/main/java/cz/jzitnik/events/FullRoomDraw.java index cd2e707..1268625 100644 --- a/src/main/java/cz/jzitnik/events/FullRoomDraw.java +++ b/src/main/java/cz/jzitnik/events/FullRoomDraw.java @@ -5,9 +5,12 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -@AllArgsConstructor @NoArgsConstructor @Getter public class FullRoomDraw implements Event { private boolean fullRerender = false; + + public FullRoomDraw(boolean fullRerender) { + this.fullRerender = fullRerender; + } } diff --git a/src/main/java/cz/jzitnik/events/handlers/FullRoomDrawHandler.java b/src/main/java/cz/jzitnik/events/handlers/FullRoomDrawHandler.java index 42c31ae..1a02572 100644 --- a/src/main/java/cz/jzitnik/events/handlers/FullRoomDrawHandler.java +++ b/src/main/java/cz/jzitnik/events/handlers/FullRoomDrawHandler.java @@ -17,6 +17,7 @@ import cz.jzitnik.states.RenderState; import cz.jzitnik.states.ScreenBuffer; import cz.jzitnik.states.TerminalState; import cz.jzitnik.ui.pixels.ColoredPixel; +import cz.jzitnik.ui.pixels.Empty; import cz.jzitnik.ui.pixels.Pixel; import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.RerenderUtils; @@ -69,6 +70,7 @@ public class FullRoomDrawHandler extends AbstractEventHandler { Set doorPositions = RerenderUtils.getDoorPositions(currentRoom); var buffer = screenBuffer.getRenderedBuffer(); + var overrideBuffer = currentRoom.getOverrideBuffer(); BufferedImage room = resourceManager.getResource(currentRoom.getTexture()); BufferedImage doors = resourceManager.getResource(ResourceManager.Resource.DOORS); @@ -85,15 +87,21 @@ public class FullRoomDrawHandler extends AbstractEventHandler { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int pixel = RerenderUtils.getPixel(currentRoom, room, doors, doorPositions, player, playerTexture, x, y); + RerenderUtils.PixelResult pixelResult = RerenderUtils.getPixel(currentRoom, room, doors, doorPositions, player, playerTexture, x, y); + int pixel = pixelResult.pixel(); int red = (pixel >> 16) & 0xff; int green = (pixel >> 8) & 0xff; int blue = pixel & 0xff; + Pixel overridePixelLeft = overrideBuffer[y][x * 2]; + Pixel overridePixelRight = overrideBuffer[y][x * 2 + 1]; Pixel pixel1 = new ColoredPixel(new TextColor.RGB(red, green, blue)); - buffer[y + startY][x * 2 + startX] = pixel1; - buffer[y + startY][x * 2 + 1 + startX] = pixel1; + Pixel finalPixelLeft = overridePixelLeft.getClass() == Empty.class || pixelResult.isPlayer() ? pixel1 : overridePixelLeft; + Pixel finalPixelRight = overridePixelRight.getClass() == Empty.class || pixelResult.isPlayer() ? pixel1 : overridePixelRight; + + buffer[y + startY][x * 2 + startX] = finalPixelLeft; + buffer[y + startY][x * 2 + 1 + startX] = finalPixelRight; } } diff --git a/src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java b/src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java index d580c46..369bf91 100644 --- a/src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java +++ b/src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java @@ -40,8 +40,8 @@ public class MouseActionEventHandler extends AbstractEventHandler { if (object.isEmpty()) return; - ((Interactable) object.get()).interact(dm); object.get().setSelected(false); + ((Interactable) object.get()).interact(dm); } } } diff --git a/src/main/java/cz/jzitnik/events/handlers/PlayerMoveEventHandler.java b/src/main/java/cz/jzitnik/events/handlers/PlayerMoveEventHandler.java index cceedcf..60aeebc 100644 --- a/src/main/java/cz/jzitnik/events/handlers/PlayerMoveEventHandler.java +++ b/src/main/java/cz/jzitnik/events/handlers/PlayerMoveEventHandler.java @@ -22,7 +22,6 @@ import cz.jzitnik.utils.events.EventManager; import lombok.extern.slf4j.Slf4j; import java.awt.image.BufferedImage; -import java.util.Set; @Slf4j @EventHandler(PlayerMoveEvent.class) diff --git a/src/main/java/cz/jzitnik/game/GameRoom.java b/src/main/java/cz/jzitnik/game/GameRoom.java index f1cfe2a..d848f28 100644 --- a/src/main/java/cz/jzitnik/game/GameRoom.java +++ b/src/main/java/cz/jzitnik/game/GameRoom.java @@ -1,21 +1,40 @@ package cz.jzitnik.game; import cz.jzitnik.game.objects.GameObject; +import cz.jzitnik.ui.pixels.Empty; +import cz.jzitnik.ui.pixels.Pixel; import lombok.Getter; -import lombok.RequiredArgsConstructor; import java.util.ArrayList; import java.util.List; -@RequiredArgsConstructor @Getter public class GameRoom { private GameRoom left; private GameRoom right; private GameRoom up; private GameRoom down; + private final Pixel[][] overrideBuffer; private final ResourceManager.Resource texture; + public GameRoom(ResourceManager.Resource texture) { + this.texture = texture; + + // Size of a room + int height = 225; + int width = 225 * 2; + + Pixel[][] overrideBuffer = new Pixel[height][width]; + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + overrideBuffer[y][x] = new Empty(); + overrideBuffer[y][x] = new Empty(); + } + } + + this.overrideBuffer = overrideBuffer; + } + private final List objects = new ArrayList<>(); public void addObject(GameObject gameObject) { diff --git a/src/main/java/cz/jzitnik/game/GameSetup.java b/src/main/java/cz/jzitnik/game/GameSetup.java index 7d50699..27e823c 100644 --- a/src/main/java/cz/jzitnik/game/GameSetup.java +++ b/src/main/java/cz/jzitnik/game/GameSetup.java @@ -3,6 +3,8 @@ package cz.jzitnik.game; import cz.jzitnik.annotations.Dependency; import cz.jzitnik.annotations.injectors.InjectDependency; import cz.jzitnik.annotations.injectors.InjectState; +import cz.jzitnik.game.items.GameItem; +import cz.jzitnik.game.items.WoodenSword; import cz.jzitnik.game.objects.Chest; import cz.jzitnik.game.utils.RoomCords; @@ -22,7 +24,10 @@ public class GameSetup { mainRoom.setRight(rightRoom); rightRoom.setUp(topRightRoom); - Chest chest = new Chest(resourceManager, new RoomCords(100, 45)); + Chest chest = new Chest(resourceManager, new RoomCords(100, 45), new GameItem[]{ + new WoodenSword(resourceManager), + new WoodenSword(resourceManager), + }); mainRoom.addObject(chest); gameState.setCurrentRoom(mainRoom); diff --git a/src/main/java/cz/jzitnik/game/ResourceManager.java b/src/main/java/cz/jzitnik/game/ResourceManager.java index 1caae57..7a1192c 100644 --- a/src/main/java/cz/jzitnik/game/ResourceManager.java +++ b/src/main/java/cz/jzitnik/game/ResourceManager.java @@ -37,16 +37,22 @@ public class ResourceManager { private final String path; } - private HashMap resourceCache = new HashMap<>(); + private final HashMap resourceCache = new HashMap<>(); public BufferedImage getResource(Resource resource) { + if (resourceCache.containsKey(resource)) { + return resourceCache.get(resource); + } + InputStream is = classLoader.getResourceAsStream("textures/" + resource.getPath()); if (is == null) { throw new RuntimeException("Image not found in resources!"); } try { - return ImageIO.read(is); + BufferedImage image = ImageIO.read(is); + resourceCache.put(resource, image); + return image; } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/cz/jzitnik/game/items/GameItem.java b/src/main/java/cz/jzitnik/game/items/GameItem.java new file mode 100644 index 0000000..d02d5f3 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/GameItem.java @@ -0,0 +1,16 @@ +package cz.jzitnik.game.items; + +import cz.jzitnik.game.items.types.ItemType; +import cz.jzitnik.game.utils.Renderable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.awt.image.BufferedImage; + +@Getter +@AllArgsConstructor +public abstract class GameItem implements Renderable { + private String name; + private final ItemType type; + private final BufferedImage texture; +} diff --git a/src/main/java/cz/jzitnik/game/items/Item.java b/src/main/java/cz/jzitnik/game/items/Item.java deleted file mode 100644 index 2a6e462..0000000 --- a/src/main/java/cz/jzitnik/game/items/Item.java +++ /dev/null @@ -1,4 +0,0 @@ -package cz.jzitnik.game.items; - -public abstract class Item { -} diff --git a/src/main/java/cz/jzitnik/game/items/WoodenSword.java b/src/main/java/cz/jzitnik/game/items/WoodenSword.java new file mode 100644 index 0000000..6bb0316 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/WoodenSword.java @@ -0,0 +1,14 @@ +package cz.jzitnik.game.items; + +import cz.jzitnik.game.ResourceManager; +import cz.jzitnik.game.items.types.Sword; + +public class WoodenSword extends GameItem { + public WoodenSword(ResourceManager resourceManager) { + super( + "Wooden sword", + new Sword(5), + resourceManager.getResource(ResourceManager.Resource.PLAYER_RIGHT) // TODO: Change to actual resource + ); + } +} diff --git a/src/main/java/cz/jzitnik/game/items/strategy/Strategy.java b/src/main/java/cz/jzitnik/game/items/strategy/Strategy.java new file mode 100644 index 0000000..dd58a40 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/strategy/Strategy.java @@ -0,0 +1,4 @@ +package cz.jzitnik.game.items.strategy; + +public interface Strategy { +} diff --git a/src/main/java/cz/jzitnik/game/items/strategy/SwordStrategy.java b/src/main/java/cz/jzitnik/game/items/strategy/SwordStrategy.java new file mode 100644 index 0000000..4fde945 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/strategy/SwordStrategy.java @@ -0,0 +1,9 @@ +package cz.jzitnik.game.items.strategy; + +import cz.jzitnik.game.items.types.Sword; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class SwordStrategy implements Strategy { + private final Sword sword; +} diff --git a/src/main/java/cz/jzitnik/game/items/types/ItemType.java b/src/main/java/cz/jzitnik/game/items/types/ItemType.java new file mode 100644 index 0000000..1fb524c --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/types/ItemType.java @@ -0,0 +1,8 @@ +package cz.jzitnik.game.items.types; + +import cz.jzitnik.game.items.strategy.Strategy; + +public sealed interface ItemType permits Sword { + Class getItemType(); + Strategy getStrategy(); +} diff --git a/src/main/java/cz/jzitnik/game/items/types/Sword.java b/src/main/java/cz/jzitnik/game/items/types/Sword.java new file mode 100644 index 0000000..71e53e1 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/types/Sword.java @@ -0,0 +1,19 @@ +package cz.jzitnik.game.items.types; + +import cz.jzitnik.game.items.strategy.SwordStrategy; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public non-sealed class Sword implements ItemType { + protected int damageDeal; + + public final Class getItemType() { + return Sword.class; + } + + public SwordStrategy getStrategy() { + return new SwordStrategy(this); + } +} diff --git a/src/main/java/cz/jzitnik/game/objects/Chest.java b/src/main/java/cz/jzitnik/game/objects/Chest.java index 01e42f4..6701734 100644 --- a/src/main/java/cz/jzitnik/game/objects/Chest.java +++ b/src/main/java/cz/jzitnik/game/objects/Chest.java @@ -1,28 +1,82 @@ package cz.jzitnik.game.objects; +import com.google.common.collect.Lists; +import com.googlecode.lanterna.TerminalPosition; +import com.googlecode.lanterna.TextColor; +import cz.jzitnik.events.RerenderScreen; +import cz.jzitnik.game.GameRoom; import cz.jzitnik.game.GameState; +import cz.jzitnik.game.Player; import cz.jzitnik.game.ResourceManager; +import cz.jzitnik.game.items.GameItem; import cz.jzitnik.game.utils.RoomCords; -import cz.jzitnik.screens.ChestScreen; +import cz.jzitnik.states.ScreenBuffer; +import cz.jzitnik.states.TerminalState; +import cz.jzitnik.ui.pixels.ColoredPixel; +import cz.jzitnik.ui.pixels.Pixel; import cz.jzitnik.utils.DependencyManager; +import cz.jzitnik.utils.RerenderUtils; import cz.jzitnik.utils.StateManager; +import cz.jzitnik.utils.events.EventManager; import lombok.extern.slf4j.Slf4j; +import java.awt.image.BufferedImage; +import java.util.List; + @Slf4j public final class Chest extends GameObject implements Interactable { - public Chest(ResourceManager resourceManager, RoomCords cords) { + private final List items; + + public Chest(ResourceManager resourceManager, RoomCords cords, GameItem[] items) { super(resourceManager.getResource(ResourceManager.Resource.CHEST), cords, true); + this.items = Lists.newArrayList(items); } @Override public void interact(DependencyManager dm) { + setSelected(true); + log.debug("Interacted with chest"); StateManager sm = dm.getDependencyOrThrow(StateManager.class); + EventManager eventManager = dm.getDependencyOrThrow(EventManager.class); GameState gameState = sm.getOrThrow(GameState.class); + ScreenBuffer screenBuffer = sm.getOrThrow(ScreenBuffer.class); + TerminalState terminalState = sm.getOrThrow(TerminalState.class); + ResourceManager resourceManager = dm.getDependencyOrThrow(ResourceManager.class); + GameRoom currentRoom = gameState.getCurrentRoom(); + Player player = gameState.getPlayer(); + BufferedImage playerTexture = RerenderUtils.getPlayer(resourceManager, player); - gameState.setInteracting(this); - ChestScreen chestScreen = dm.getDependencyOrThrow(ChestScreen.class); - gameState.setScreen(chestScreen); - chestScreen.fullRender(); + BufferedImage room = resourceManager.getResource(currentRoom.getTexture()); + BufferedImage chest = getTexture(); + var buffer = screenBuffer.getRenderedBuffer(); + var overrideBuffer = currentRoom.getOverrideBuffer(); + + RoomCords start = RerenderUtils.getStart(room, terminalState.getTerminalScreen().getTerminalSize()); + + int itemCount = items.size(); + + int chestUIStartX = getCords().getX() * 2; + int chestUIStartY = getCords().getY(); + int chestUISizeY = 16 + 4; + int chestUISizeX = 8 + itemCount * 32 + (itemCount - 1) * 2; + int chestGUIStartY = chestUIStartY - chestUISizeY - 1; + int chestGUIStartX = chestUIStartX + chest.getWidth() - (chestUISizeX / 2); + + TerminalPosition guiStart = new TerminalPosition(chestGUIStartX / 2, chestGUIStartY); + TerminalPosition guiEnd = new TerminalPosition((chestGUIStartX + chestUISizeX - 1) / 2, ((chestGUIStartY + chestUISizeY - 1) / 2)); + + for (int y = chestGUIStartY; y < chestGUIStartY + chestUISizeY; y++) { + for (int x = chestGUIStartX ; x < chestGUIStartX + chestUISizeX; x++) { + Pixel pixel = new ColoredPixel(TextColor.ANSI.RED); + + buffer[y + start.getY()][x + start.getX()] = pixel; + overrideBuffer[y][x] = pixel; + } + } + + RerenderUtils.rerenderPart(guiStart.getColumn(), guiEnd.getColumn(), guiStart.getRow(), guiEnd.getRow(), start.getX(), start.getY(), currentRoom, room, player, playerTexture, screenBuffer, resourceManager); + + eventManager.emitEvent(RerenderScreen.full(terminalState.getTerminalScreen().getTerminalSize())); // TODO: Make this not rerender full screen } } diff --git a/src/main/java/cz/jzitnik/screens/ChestScreen.java b/src/main/java/cz/jzitnik/screens/ChestScreen.java deleted file mode 100644 index ec4154f..0000000 --- a/src/main/java/cz/jzitnik/screens/ChestScreen.java +++ /dev/null @@ -1,63 +0,0 @@ -package cz.jzitnik.screens; - -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.input.KeyStroke; -import com.googlecode.lanterna.input.KeyType; -import cz.jzitnik.annotations.Dependency; -import cz.jzitnik.annotations.injectors.InjectDependency; -import cz.jzitnik.annotations.injectors.InjectState; -import cz.jzitnik.events.FullRoomDraw; -import cz.jzitnik.events.KeyboardPressEvent; -import cz.jzitnik.events.MouseAction; -import cz.jzitnik.events.RerenderScreen; -import cz.jzitnik.game.GameState; -import cz.jzitnik.states.ScreenBuffer; -import cz.jzitnik.states.TerminalState; -import cz.jzitnik.ui.pixels.Empty; -import cz.jzitnik.utils.events.EventManager; - -@Dependency -public final class ChestScreen extends Screen { - @InjectDependency - private EventManager eventManager; - - @InjectState - private ScreenBuffer screenBuffer; - - @InjectState - private TerminalState terminalState; - - @InjectState - private GameState gameState; - - @Override - public void fullRender() { - var buffer = screenBuffer.getRenderedBuffer(); - TerminalSize terminalSize = terminalState.getTerminalScreen().getTerminalSize(); - - for (int x = 0; x < terminalSize.getColumns(); x++) { - for (int y = 0; y < terminalSize.getRows(); y++) { - buffer[y][x] = new Empty(); - } - } - - eventManager.emitEvent(RerenderScreen.full(terminalSize)); - } - - @Override - public void handleMouseAction(MouseAction event) { - - } - - @Override - public void handleKeyboardAction(KeyboardPressEvent event) { - KeyStroke keyStroke = event.getKeyStroke(); - - if (keyStroke.getKeyType() == KeyType.Escape || keyStroke.getCharacter() == 'e') { - gameState.setScreen(null); - gameState.setInteracting(null); - - eventManager.emitEvent(new FullRoomDraw(true)); - } - } -} diff --git a/src/main/java/cz/jzitnik/screens/Screen.java b/src/main/java/cz/jzitnik/screens/Screen.java index e022c70..c821afe 100644 --- a/src/main/java/cz/jzitnik/screens/Screen.java +++ b/src/main/java/cz/jzitnik/screens/Screen.java @@ -3,7 +3,7 @@ package cz.jzitnik.screens; import cz.jzitnik.events.KeyboardPressEvent; import cz.jzitnik.events.MouseAction; -public sealed abstract class Screen permits ChestScreen { +public abstract class Screen { public abstract void fullRender(); public abstract void handleMouseAction(MouseAction event); public abstract void handleKeyboardAction(KeyboardPressEvent event); diff --git a/src/main/java/cz/jzitnik/utils/DependencyManager.java b/src/main/java/cz/jzitnik/utils/DependencyManager.java index c9f5cf0..f52d206 100644 --- a/src/main/java/cz/jzitnik/utils/DependencyManager.java +++ b/src/main/java/cz/jzitnik/utils/DependencyManager.java @@ -1,28 +1,28 @@ package cz.jzitnik.utils; -// Don't blame me im using field injection instead of construction injection. I just like it more leave me alone. -// Yes I know I'll suffer in the unit tests. +// Don't blame me that I'm using field injection instead of construction injection. I just like it more leave me alone. +// Yes I know I'll suffer in the unit tests. (who said there will be any? hmmm) +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.MutableClassToInstanceMap; import cz.jzitnik.annotations.Config; import cz.jzitnik.annotations.Dependency; import cz.jzitnik.annotations.injectors.InjectConfig; import cz.jzitnik.annotations.injectors.InjectDependency; import cz.jzitnik.annotations.injectors.InjectState; -import cz.jzitnik.events.handlers.CliHandler; import lombok.extern.slf4j.Slf4j; import org.reflections.Reflections; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; import java.util.Optional; import java.util.Set; @Slf4j public class DependencyManager { - private final HashMap, Object> configs = new HashMap<>(); - private final HashMap, Object> data = new HashMap<>(); + private final ClassToInstanceMap configs = MutableClassToInstanceMap.create(); + private final ClassToInstanceMap data = MutableClassToInstanceMap.create(); public T getDependencyOrThrow(Class clazz) { T instance = get(clazz); diff --git a/src/main/java/cz/jzitnik/utils/RerenderUtils.java b/src/main/java/cz/jzitnik/utils/RerenderUtils.java index 9917523..14ed62e 100644 --- a/src/main/java/cz/jzitnik/utils/RerenderUtils.java +++ b/src/main/java/cz/jzitnik/utils/RerenderUtils.java @@ -10,6 +10,7 @@ import cz.jzitnik.game.objects.GameObject; import cz.jzitnik.game.utils.RoomCords; import cz.jzitnik.states.ScreenBuffer; import cz.jzitnik.ui.pixels.ColoredPixel; +import cz.jzitnik.ui.pixels.Empty; import cz.jzitnik.ui.pixels.Pixel; import java.awt.image.BufferedImage; @@ -32,31 +33,40 @@ public class RerenderUtils { public static void rerenderPart(int startX, int endX, int startY, int endY, int screenStartX, int screenStartY, GameRoom currentRoom, BufferedImage room, Player player, BufferedImage playerTexture, ScreenBuffer screenBuffer, ResourceManager resourceManager) { var buffer = screenBuffer.getRenderedBuffer(); + var overrideBuffer = currentRoom.getOverrideBuffer(); BufferedImage doors = resourceManager.getResource(ResourceManager.Resource.DOORS); Set doorPositions = RerenderUtils.getDoorPositions(currentRoom); for (int x = startX; x <= endX; x++) { for (int y = startY; y <= endY; y++) { - int pixel = getPixel(currentRoom, room, doors, doorPositions, player, playerTexture, x, y); + PixelResult pixelResult = getPixel(currentRoom, room, doors, doorPositions, player, playerTexture, x, y); + int pixel = pixelResult.pixel(); int red = (pixel >> 16) & 0xff; int green = (pixel >> 8) & 0xff; int blue = pixel & 0xff; + Pixel overridePixelLeft = overrideBuffer[y][x * 2]; + Pixel overridePixelRight = overrideBuffer[y][x * 2 + 1]; Pixel pixel1 = new ColoredPixel(new TextColor.RGB(red, green, blue)); - buffer[y + screenStartY][x * 2 + screenStartX] = pixel1; - buffer[y + screenStartY][x * 2 + 1 + screenStartX] = pixel1; + Pixel finalPixelLeft = overridePixelLeft.getClass() == Empty.class || pixelResult.isPlayer() ? pixel1 : overridePixelLeft; + Pixel finalPixelRight = overridePixelRight.getClass() == Empty.class || pixelResult.isPlayer() ? pixel1 : overridePixelRight; + + buffer[y + screenStartY][x * 2 + screenStartX] = finalPixelLeft; + buffer[y + screenStartY][x * 2 + 1 + screenStartX] = finalPixelRight; } } } - public static int getPixel(GameRoom currentRoom, BufferedImage room, BufferedImage doors, Set doorPositions, Player player, BufferedImage playerTexture, int x, int y) { + public record PixelResult(int pixel, boolean isPlayer) {} + + public static PixelResult getPixel(GameRoom currentRoom, BufferedImage room, BufferedImage doors, Set doorPositions, Player player, BufferedImage playerTexture, int x, int y) { if (x >= player.getPlayerCords().getX() && x < player.getPlayerCords().getX() + playerTexture.getWidth() - 1 && y >= player.getPlayerCords().getY() && y <= player.getPlayerCords().getY() + playerTexture.getHeight() - 1) { int pixel = playerTexture.getRGB(x - player.getPlayerCords().getX(), y - player.getPlayerCords().getY()); int alpha = (pixel >> 24) & 0xff; if (alpha != 0) { - return pixel; + return new PixelResult(pixel, true); } } @@ -81,7 +91,7 @@ public class RerenderUtils { pixel = (alpha << 24) | (r << 16) | (g << 8) | b; } - return pixel; + return new PixelResult(pixel, false); } } } @@ -102,11 +112,11 @@ public class RerenderUtils { for (FullRoomDrawHandler.DoorPosition pos : doorPositions) { DoorBounds bounds = doorBounds.get(pos); if (bounds != null && bounds.contains(x, y)) { - return doors.getRGB(x, y); + return new PixelResult(doors.getRGB(x, y), false); } } - return room.getRGB(x, y); + return new PixelResult(room.getRGB(x, y), false); } public static BufferedImage getPlayer(ResourceManager resourceManager, Player player) {