feat: Better colors for inventory

This commit is contained in:
2026-01-02 17:34:44 +01:00
parent b355ae1dd2
commit f8bc960af2
5 changed files with 80 additions and 23 deletions

View File

@@ -8,8 +8,6 @@ import cz.jzitnik.config.PlayerConfig;
import cz.jzitnik.events.MouseAction; import cz.jzitnik.events.MouseAction;
import cz.jzitnik.events.MouseMoveEvent; import cz.jzitnik.events.MouseMoveEvent;
import cz.jzitnik.game.GameState; import cz.jzitnik.game.GameState;
import cz.jzitnik.game.objects.GameObject;
import cz.jzitnik.game.objects.Interactable;
import cz.jzitnik.game.utils.Selectable; import cz.jzitnik.game.utils.Selectable;
import cz.jzitnik.states.RenderState; import cz.jzitnik.states.RenderState;
import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.DependencyManager;

View File

@@ -19,6 +19,8 @@ public class Player {
private final RoomCords playerCords; private final RoomCords playerCords;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final GameItem[] inventory = new GameItem[Inventory.ITEMS_X * Inventory.ITEMS_Y]; private final GameItem[] inventory = new GameItem[Inventory.ITEMS_X * Inventory.ITEMS_Y];
@Setter
private GameItem selectedItem;
private boolean swinging = false; private boolean swinging = false;
public boolean addItem(GameItem item) { public boolean addItem(GameItem item) {

View File

@@ -18,6 +18,7 @@ import cz.jzitnik.game.items.GameItem;
import cz.jzitnik.game.utils.RoomCords; import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.states.ScreenBuffer; import cz.jzitnik.states.ScreenBuffer;
import cz.jzitnik.states.TerminalState; import cz.jzitnik.states.TerminalState;
import cz.jzitnik.ui.Inventory;
import cz.jzitnik.ui.utils.Grid; import cz.jzitnik.ui.utils.Grid;
import cz.jzitnik.ui.pixels.ColoredPixel; import cz.jzitnik.ui.pixels.ColoredPixel;
import cz.jzitnik.ui.pixels.Empty; import cz.jzitnik.ui.pixels.Empty;
@@ -35,9 +36,6 @@ import java.util.List;
@Slf4j @Slf4j
public final class Chest extends GameObject implements UIClickHandler { public final class Chest extends GameObject implements UIClickHandler {
private static final TextColor BORDER_COLOR = new TextColor.RGB(255, 255, 255);
private static final TextColor TRANSPARENT_COLOR = new TextColor.RGB(166, 166, 166);
private static final int RENDER_PADDING = 1; private static final int RENDER_PADDING = 1;
private final List<GameItem> items; private final List<GameItem> items;
@@ -91,8 +89,8 @@ public final class Chest extends GameObject implements UIClickHandler {
2, // Inner Border 2, // Inner Border
16, // Item Size 16, // Item Size
1, // Item Padding (Changed to 1 as per your request example) 1, // Item Padding (Changed to 1 as per your request example)
new ColoredPixel(BORDER_COLOR), Inventory.BORDER_COLOR,
new ColoredPixel(TRANSPARENT_COLOR) Inventory.BACKGROUND_COLOR
); );
} }

View File

@@ -20,26 +20,37 @@ import cz.jzitnik.ui.utils.Grid;
import cz.jzitnik.utils.RerenderUtils; import cz.jzitnik.utils.RerenderUtils;
import cz.jzitnik.utils.events.EventManager; import cz.jzitnik.utils.events.EventManager;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
@Slf4j
@Dependency @Dependency
public class Inventory implements GlobalUIClickHandler { public class Inventory implements GlobalUIClickHandler {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public static final int ITEMS_X = 3; public static final int ITEMS_X = 3;
public static final int ITEMS_Y = 5; public static final int ITEMS_Y = 5;
private static final int OUTER_BORDER_WIDTH = 2; private static final int OUTER_BORDER_WIDTH = 2;
private static final int INNER_BORDER_WIDTH = 1; private static final int INNER_BORDER_WIDTH = 1;
private static final int ITEM_SIZE = 16; // Characters private static final int ITEM_SIZE = 16; // Characters
private static final int ITEM_PADDING = 2; // padding on each side private static final int ITEM_PADDING = 2; // padding on each side
private static final Pixel BORDER_COLOR = public static final Pixel BORDER_COLOR =
new ColoredPixel(new TextColor.RGB(255, 255, 255)); new ColoredPixel(new TextColor.RGB(41, 29, 19));
private static final Pixel BACKGROUND_COLOR = public static final Pixel BACKGROUND_COLOR =
new ColoredPixel(new TextColor.RGB(166, 166, 166)); new ColoredPixel(new TextColor.RGB(61, 45, 29));
private static final Pixel BACKGROUND_COLOR_HOVERED = private static final Pixel BACKGROUND_COLOR_HOVERED =
new ColoredPixel(new TextColor.RGB(186, 186, 186)); new ColoredPixel(new TextColor.RGB(77, 56, 36));
private static final Pixel BACKGROUND_COLOR_SELECTED = private static final Pixel BACKGROUND_COLOR_SELECTED =
new ColoredPixel(new TextColor.RGB(216, 216, 216)); new ColoredPixel(new TextColor.RGB(95, 62, 32));
private static final Pixel BACKGROUND_COLOR_EQUIPPED =
new ColoredPixel(new TextColor.RGB(50, 145, 150));
private static final Pixel BACKGROUND_COLOR_EQUIPPED_SELECTED =
new ColoredPixel(new TextColor.RGB(58, 170, 176));
private static final int ITEM_SLOT_SIZE = ITEM_SIZE + ITEM_PADDING * 2; private static final int ITEM_SLOT_SIZE = ITEM_SIZE + ITEM_PADDING * 2;
public static final int INVENTORY_WIDTH = public static final int INVENTORY_WIDTH =
OUTER_BORDER_WIDTH * 2 + OUTER_BORDER_WIDTH * 2 +
@@ -49,6 +60,7 @@ public class Inventory implements GlobalUIClickHandler {
(ITEMS_Y * (ITEM_SLOT_SIZE + INNER_BORDER_WIDTH) - INNER_BORDER_WIDTH); (ITEMS_Y * (ITEM_SLOT_SIZE + INNER_BORDER_WIDTH) - INNER_BORDER_WIDTH);
private static final int REAL_INVENTORY_HEIGHT = private static final int REAL_INVENTORY_HEIGHT =
Math.ceilDiv(INVENTORY_HEIGHT, 2); // 2 pixels per terminal row Math.ceilDiv(INVENTORY_HEIGHT, 2); // 2 pixels per terminal row
private static final Grid grid = new Grid( private static final Grid grid = new Grid(
ITEMS_X, ITEMS_X,
ITEMS_Y, ITEMS_Y,
@@ -99,13 +111,15 @@ public class Inventory implements GlobalUIClickHandler {
inventoryState.draggingItemPosition = null; inventoryState.draggingItemPosition = null;
inventoryState.selectedItem = -1; inventoryState.selectedItem = -1;
if (itemClickedOnIndex != -1) { if (itemClickedOnIndex != -1 && inventory[itemClickedOnIndex] == null) {
inventory[itemClickedOnIndex] = gameItem; inventory[itemClickedOnIndex] = gameItem;
inventoryState.hoveredItem = itemClickedOnIndex;
} else { } else {
gameState.getPlayer().addItem(gameItem); inventory[inventoryState.draggingItemOriginalIndex] = gameItem;
} }
inventoryState.draggingItemOriginalIndex = -1;
inventoryState.hoveredItem = itemClickedOnIndex;
eventManager.emitEvent(new InventoryRerender()); eventManager.emitEvent(new InventoryRerender());
return true; return true;
} }
@@ -120,10 +134,31 @@ public class Inventory implements GlobalUIClickHandler {
return true; return true;
} }
if (inventoryState.isGonnaDoubleclick) {
inventoryState.isGonnaDoubleclick = false;
inventoryState.selectedItem = -1;
gameState.getPlayer().setSelectedItem(inventory[itemClickedOnIndex]);
eventManager.emitEvent(new InventoryRerender());
return true;
}
inventoryState.isGonnaDoubleclick = true;
log.debug("Gonna doubleclick: {}", true);
scheduler.schedule(() -> {
inventoryState.isGonnaDoubleclick = false;
log.debug("Gonna doubleclick: {}", false);
}, 200, TimeUnit.MILLISECONDS);
if (inventoryState.selectedItem == itemClickedOnIndex) { if (inventoryState.selectedItem == itemClickedOnIndex) {
inventoryState.selectedItem = -1; inventoryState.selectedItem = -1;
} else if (inventoryState.selectedItem == -1) { } else if (inventoryState.selectedItem == -1) {
inventoryState.selectedItem = itemClickedOnIndex; if (inventory[itemClickedOnIndex] != null) {
inventoryState.selectedItem = itemClickedOnIndex;
} else {
return true;
}
} else { } else {
// Already have selected item and now clicked on different item so swap items // Already have selected item and now clicked on different item so swap items
GameItem temp = inventory[inventoryState.selectedItem]; GameItem temp = inventory[inventoryState.selectedItem];
@@ -174,6 +209,7 @@ public class Inventory implements GlobalUIClickHandler {
boolean render = false; boolean render = false;
if (inventoryState.onNextDragTakeItemOnIndex != -1) { if (inventoryState.onNextDragTakeItemOnIndex != -1) {
inventoryState.draggingItem = gameState.getPlayer().getInventory()[inventoryState.onNextDragTakeItemOnIndex]; inventoryState.draggingItem = gameState.getPlayer().getInventory()[inventoryState.onNextDragTakeItemOnIndex];
inventoryState.draggingItemOriginalIndex = inventoryState.onNextDragTakeItemOnIndex;
gameState.getPlayer().getInventory()[inventoryState.onNextDragTakeItemOnIndex] = null; gameState.getPlayer().getInventory()[inventoryState.onNextDragTakeItemOnIndex] = null;
inventoryState.onNextDragTakeItemOnIndex = -1; inventoryState.onNextDragTakeItemOnIndex = -1;
render = true; render = true;
@@ -201,6 +237,11 @@ public class Inventory implements GlobalUIClickHandler {
var inventory = gameState.getPlayer().getInventory(); var inventory = gameState.getPlayer().getInventory();
var buffer = screenBuffer.getRenderedBuffer(); var buffer = screenBuffer.getRenderedBuffer();
int indexEquippedItem = IntStream.range(0, inventory.length)
.filter(i -> inventory[i] == gameState.getPlayer().getSelectedItem())
.findFirst()
.orElse(-1);
BufferedImage[] textures = Arrays.stream(inventory) BufferedImage[] textures = Arrays.stream(inventory)
.map(item -> item == null ? null : item.getTexture()) .map(item -> item == null ? null : item.getTexture())
.toArray(BufferedImage[]::new); .toArray(BufferedImage[]::new);
@@ -212,6 +253,11 @@ public class Inventory implements GlobalUIClickHandler {
if (inventoryState.selectedItem != -1) { if (inventoryState.selectedItem != -1) {
backgrounds[inventoryState.selectedItem] = BACKGROUND_COLOR_SELECTED; backgrounds[inventoryState.selectedItem] = BACKGROUND_COLOR_SELECTED;
} }
if (indexEquippedItem != -1 && indexEquippedItem != inventoryState.selectedItem) {
backgrounds[indexEquippedItem] = BACKGROUND_COLOR_EQUIPPED;
} else if (indexEquippedItem != -1) {
backgrounds[indexEquippedItem] = BACKGROUND_COLOR_EQUIPPED_SELECTED;
}
Pixel[][] internalBuffer = grid.render(textures, backgrounds); Pixel[][] internalBuffer = grid.render(textures, backgrounds);
if (inventoryState.draggingItem != null) { if (inventoryState.draggingItem != null) {
@@ -229,13 +275,24 @@ public class Inventory implements GlobalUIClickHandler {
for (int x = 0; x < texture.getWidth(); x++) { for (int x = 0; x < texture.getWidth(); x++) {
int pixel = texture.getRGB(x, y); int pixel = texture.getRGB(x, y);
int alpha = (pixel >> 24) & 0xff; int alpha = (pixel >> 24) & 0xff;
int r = (pixel >> 16) & 0xff;
int g = (pixel >> 8) & 0xff;
int b = pixel & 0xff;
if (alpha == 0) { if (alpha == 0) {
continue; continue;
} }
internalBuffer[y + offsetY][x + offsetX] = new ColoredPixel(new TextColor.RGB(r, g, b)); Pixel bottomPixel = internalBuffer[y + offsetY][x + offsetX];
int topR = (pixel >> 16) & 0xff;
int topG = (pixel >> 8) & 0xff;
int topB = pixel & 0xff;
float topOpacity = 0.80f;
int bottomR = bottomPixel.getColor().getRed();
int bottomG = bottomPixel.getColor().getGreen();
int bottomB = bottomPixel.getColor().getBlue();
int finalR = (int)(topR * topOpacity + bottomR * (1 - topOpacity));
int finalG = (int)(topG * topOpacity + bottomG * (1 - topOpacity));
int finalB = (int)(topB * topOpacity + bottomB * (1 - topOpacity));
internalBuffer[y + offsetY][x + offsetX] = new ColoredPixel(new TextColor.RGB(finalR, finalG, finalB));
} }
} }
} }
@@ -251,5 +308,7 @@ public class Inventory implements GlobalUIClickHandler {
protected GameItem draggingItem; protected GameItem draggingItem;
protected TerminalPosition draggingItemPosition; protected TerminalPosition draggingItemPosition;
protected int onNextDragTakeItemOnIndex = -1; protected int onNextDragTakeItemOnIndex = -1;
protected int draggingItemOriginalIndex = -1;
protected boolean isGonnaDoubleclick = false;
} }
} }

View File

@@ -19,13 +19,13 @@ import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Dependency @Dependency
public class RoomTaskScheduler { public class RoomTaskScheduler {
ScheduledExecutorService scheduler; private ScheduledExecutorService scheduler;
@InjectConfig @InjectConfig
private ThreadPoolConfig threadPoolConfig; private ThreadPoolConfig threadPoolConfig;
@InjectDependency @InjectDependency
private DependencyManager dependencyManager; private DependencyManager dependencyManager;
private HashMap<RoomTask, ScheduledFuture<?>> tasks = new HashMap<>(); private final HashMap<RoomTask, ScheduledFuture<?>> tasks = new HashMap<>();
private boolean firstRun = true; private boolean firstRun = true;