feat: Render stamina

This commit is contained in:
2026-01-02 22:37:54 +01:00
parent 27cdde97a0
commit 4136696c83
11 changed files with 150 additions and 33 deletions

View File

@@ -0,0 +1,6 @@
package cz.jzitnik.events;
import cz.jzitnik.utils.events.Event;
public class RenderStats implements Event {
}

View File

@@ -19,6 +19,7 @@ import cz.jzitnik.states.RenderState;
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.Inventory;
import cz.jzitnik.ui.Stats;
import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.DependencyManager;
import cz.jzitnik.utils.RerenderUtils; import cz.jzitnik.utils.RerenderUtils;
import cz.jzitnik.utils.UIClickHandlerRepository; import cz.jzitnik.utils.UIClickHandlerRepository;
@@ -58,6 +59,8 @@ public class FullRoomDrawHandler extends AbstractEventHandler<FullRoomDraw> {
private UIClickHandlerRepository uiClickHandlerRepository; private UIClickHandlerRepository uiClickHandlerRepository;
@InjectDependency @InjectDependency
private Inventory inventory; private Inventory inventory;
@InjectDependency
private Stats stats;
public FullRoomDrawHandler(DependencyManager dm) { public FullRoomDrawHandler(DependencyManager dm) {
super(dm); super(dm);
@@ -86,6 +89,7 @@ public class FullRoomDrawHandler extends AbstractEventHandler<FullRoomDraw> {
RerenderUtils.rerenderPart(0, width - 1, 0, height - 1, startX, startY, currentRoom, room, player, playerTexture, screenBuffer, resourceManager, debugging); RerenderUtils.rerenderPart(0, width - 1, 0, height - 1, startX, startY, currentRoom, room, player, playerTexture, screenBuffer, resourceManager, debugging);
if (event.isFullRerender()) { if (event.isFullRerender()) {
inventory.renderInventoryRerender(); inventory.renderInventoryRerender();
stats.rerender();
uiClickHandlerRepository.registerGlobalHandler(inventory); uiClickHandlerRepository.registerGlobalHandler(inventory);
} }

View File

@@ -21,6 +21,7 @@ import cz.jzitnik.states.RenderState;
import cz.jzitnik.states.ScreenBuffer; import cz.jzitnik.states.ScreenBuffer;
import cz.jzitnik.states.PlayerMovementState; import cz.jzitnik.states.PlayerMovementState;
import cz.jzitnik.states.TerminalState; import cz.jzitnik.states.TerminalState;
import cz.jzitnik.ui.Stats;
import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.DependencyManager;
import cz.jzitnik.utils.RerenderUtils; import cz.jzitnik.utils.RerenderUtils;
import cz.jzitnik.utils.events.AbstractEventHandler; import cz.jzitnik.utils.events.AbstractEventHandler;
@@ -52,6 +53,8 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
private Logging logging; private Logging logging;
@InjectState @InjectState
private PlayerMovementState playerMovementState; private PlayerMovementState playerMovementState;
@InjectDependency
private Stats stats;
public PlayerMoveEventHandler(DependencyManager dm) { public PlayerMoveEventHandler(DependencyManager dm) {
super(dm); super(dm);
@@ -126,7 +129,8 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
} }
playerMovementState.setLastMovement(System.currentTimeMillis()); playerMovementState.setLastMovement(System.currentTimeMillis());
if (isSprinting) { if (isSprinting) {
int newStamina = player.decreaseStamina(); player.decreaseStamina();
stats.rerender();
} }
int newPlayerX = playerCords.getX(); int newPlayerX = playerCords.getX();
@@ -148,10 +152,16 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
RerenderUtils.rerenderPart(forStartX, forEndX, forStartY, forEndY, startX, startY, currentRoom, room, player, playerTexture, screenBuffer, resourceManager, debugging); RerenderUtils.rerenderPart(forStartX, forEndX, forStartY, forEndY, startX, startY, currentRoom, room, player, playerTexture, screenBuffer, resourceManager, debugging);
eventManager.emitEvent(new RerenderScreen( eventManager.emitEvent(new RerenderScreen(
new RerenderScreen.ScreenPart[]{
new RerenderScreen.ScreenPart( new RerenderScreen.ScreenPart(
new TerminalPosition(forStartX + startX, forStartY + startY), new TerminalPosition(forStartX + startX, forStartY + startY),
new TerminalPosition(forEndX + 1 + startX, forEndY + startY) new TerminalPosition(forEndX + 1 + startX, forEndY + startY)
),
new RerenderScreen.ScreenPart(
new TerminalPosition(Stats.OFFSET_X, Stats.OFFSET_X),
new TerminalPosition(Stats.OFFSET_X + Stats.WIDTH, Stats.OFFSET_Y + Stats.HEIGHT)
) )
}
)); ));
} }

View File

@@ -0,0 +1,33 @@
package cz.jzitnik.events.handlers;
import com.googlecode.lanterna.TerminalPosition;
import cz.jzitnik.annotations.EventHandler;
import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.events.RenderStats;
import cz.jzitnik.events.RerenderScreen;
import cz.jzitnik.ui.Stats;
import cz.jzitnik.utils.DependencyManager;
import cz.jzitnik.utils.events.AbstractEventHandler;
import cz.jzitnik.utils.events.EventManager;
@EventHandler(RenderStats.class)
public class RenderStatsHandler extends AbstractEventHandler<RenderStats> {
@InjectDependency
private EventManager eventManager;
@InjectDependency
private Stats stats;
public RenderStatsHandler(DependencyManager dm) {
super(dm);
}
@Override
public void handle(RenderStats event) {
stats.rerender();
eventManager.emitEvent(new RerenderScreen(new RerenderScreen.ScreenPart(
new TerminalPosition(Stats.OFFSET_X, Stats.OFFSET_X),
new TerminalPosition(Stats.OFFSET_X + Stats.WIDTH, Stats.OFFSET_Y + Stats.HEIGHT)
)));
}
}

View File

@@ -49,10 +49,10 @@ public class RoomChangeEventHandler extends AbstractEventHandler<RoomChangeEvent
} }
switch (event.door()) { switch (event.door()) {
case LEFT -> playerCords.updateCords(155, 60); case LEFT -> playerCords.updateCords(155, playerCords.getY());
case RIGHT -> playerCords.updateCords(30, 50); case RIGHT -> playerCords.updateCords(30, playerCords.getY());
case TOP -> playerCords.updateCords(90, 110); case TOP -> playerCords.updateCords(playerCords.getX(), 110);
case BOTTOM -> playerCords.updateCords(90, 10); case BOTTOM -> playerCords.updateCords(playerCords.getX(), 10);
} }
gameState.setCurrentRoom(newRoom); gameState.setCurrentRoom(newRoom);

View File

@@ -27,13 +27,11 @@ public class Player {
private GameItem selectedItem; private GameItem selectedItem;
private boolean swinging = false; private boolean swinging = false;
public int increaseStamina() { public void increaseStamina() {
log.debug("Stamina: {}", stamina + 1); stamina++;
return ++stamina;
} }
public int decreaseStamina() { public void decreaseStamina() {
log.debug("Stamina: {}", stamina - 1); stamina--;
return --stamina;
} }
public int getDamageDeal() { public int getDamageDeal() {

View File

@@ -250,7 +250,7 @@ public final class Chest extends GameObject implements UIClickHandler {
} }
@Override @Override
public void handleClick(MouseAction mouseAction) { public boolean handleClick(MouseAction mouseAction) {
int mouseX = mouseAction.getPosition().getColumn(); int mouseX = mouseAction.getPosition().getColumn();
int mouseY = mouseAction.getPosition().getRow(); int mouseY = mouseAction.getPosition().getRow();
@@ -262,21 +262,23 @@ public final class Chest extends GameObject implements UIClickHandler {
int itemIndex = grid.getItemIndexAt(localX, localY); int itemIndex = grid.getItemIndexAt(localX, localY);
if (itemIndex == -1 || itemIndex >= items.size()) { if (itemIndex == -1 || itemIndex >= items.size()) {
return; return false;
} }
GameItem item = items.get(itemIndex); GameItem item = items.get(itemIndex);
boolean added = gameState.getPlayer().addItem(item); boolean added = gameState.getPlayer().addItem(item);
if (!added) { if (!added) {
return; return true;
} }
eventManager.emitEvent(new InventoryRerender()); eventManager.emitEvent(new InventoryRerender());
items.remove(item); items.remove(item);
if (items.isEmpty()) { if (items.isEmpty()) {
uiClickHandlerRepository.removeHandlerForCurrentRoom(listenerHashCode, this); uiClickHandlerRepository.removeHandlerForCurrentRoom(listenerHashCode);
} }
render(true); render(true);
return true;
} }
} }

View File

@@ -3,8 +3,12 @@ package cz.jzitnik.game.objects;
import cz.jzitnik.events.MouseAction; import cz.jzitnik.events.MouseAction;
public interface UIClickHandler { public interface UIClickHandler {
void handleClick(MouseAction mouseAction); boolean handleClick(MouseAction mouseAction);
default void handleMove(MouseAction ignoredMouseAction) {} default boolean handleMove(MouseAction ignoredMouseAction) {
default void handleElse(MouseAction ignoredMouseAction) {} return false;
}
default boolean handleElse(MouseAction ignoredMouseAction) {
return false;
}
} }

View File

@@ -5,11 +5,13 @@ import cz.jzitnik.annotations.injectors.InjectConfig;
import cz.jzitnik.annotations.injectors.InjectDependency; import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.annotations.injectors.InjectState; import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.config.PlayerConfig; import cz.jzitnik.config.PlayerConfig;
import cz.jzitnik.events.RenderStats;
import cz.jzitnik.game.GameState; import cz.jzitnik.game.GameState;
import cz.jzitnik.game.Player; import cz.jzitnik.game.Player;
import cz.jzitnik.states.PlayerMovementState; import cz.jzitnik.states.PlayerMovementState;
import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.DependencyManager;
import cz.jzitnik.utils.ScheduledTaskManager; import cz.jzitnik.utils.ScheduledTaskManager;
import cz.jzitnik.utils.events.EventManager;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -55,6 +57,9 @@ public class StaminaIncreaseTask implements Runnable {
@InjectConfig @InjectConfig
private PlayerConfig playerConfig; private PlayerConfig playerConfig;
@InjectDependency
private EventManager eventManager;
@Override @Override
public void run() { public void run() {
long nowTime = System.currentTimeMillis(); long nowTime = System.currentTimeMillis();
@@ -68,6 +73,7 @@ public class StaminaIncreaseTask implements Runnable {
} }
player.increaseStamina(); player.increaseStamina();
eventManager.emitEvent(new RenderStats());
} }
} }
} }

View File

@@ -0,0 +1,51 @@
package cz.jzitnik.ui;
import com.googlecode.lanterna.TextColor;
import cz.jzitnik.annotations.Dependency;
import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.game.GameState;
import cz.jzitnik.game.Player;
import cz.jzitnik.states.ScreenBuffer;
import cz.jzitnik.ui.pixels.ColoredPixel;
import cz.jzitnik.ui.pixels.Empty;
import cz.jzitnik.ui.pixels.Pixel;
import lombok.Getter;
@Getter
@Dependency
public class Stats {
public static final int BARS_COUNT = 1;
public static final int BAR_WIDTH = 72;
public static final int BAR_HEIGHT = 8;
public static final int BAR_PADDING = 2;
public static final int HEIGHT = BAR_HEIGHT * BARS_COUNT + (BAR_PADDING * (BARS_COUNT - 1));
public static final int WIDTH = BAR_WIDTH;
public static final int OFFSET_X = 5;
public static final int OFFSET_Y = 5;
private static final Pixel STAMINA_COLOR = new ColoredPixel(new TextColor.RGB(207, 175, 89));
@InjectState
private GameState gameState;
@InjectState
private ScreenBuffer screenBuffer;
public void rerender() {
var buffer = screenBuffer.getRenderedBuffer();
float staminaDelta = (float) gameState.getPlayer().getStamina() / Player.MAX_STAMINA;
float staminaAmount = (BAR_WIDTH - 2) * staminaDelta;
for (int x = 0; x < BAR_WIDTH; x++) {
for (int y = 0; y < BAR_HEIGHT; y++) {
if (x == 0 || y == 0 || x == BAR_WIDTH - 1 || y == BAR_HEIGHT - 1 || x - 1 < staminaAmount) {
buffer[y + OFFSET_Y][x + OFFSET_X] = STAMINA_COLOR;
} else {
buffer[y + OFFSET_Y][x + OFFSET_X] = new Empty();
}
}
}
}
}

View File

@@ -48,18 +48,19 @@ public class UIClickHandlerRepository {
public boolean handleClick(MouseAction mouseAction) { public boolean handleClick(MouseAction mouseAction) {
if (roomSpecificHandlers.containsKey(gameState.getCurrentRoom())) { if (roomSpecificHandlers.containsKey(gameState.getCurrentRoom())) {
Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(gameState.getCurrentRoom()); Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(gameState.getCurrentRoom());
TerminalPosition position = new TerminalPosition(mouseAction.getPosition().getColumn(), mouseAction.getPosition().getRow() * 2);
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(position)) { if (part.isWithin(position)) {
uiClickHandler.handleClick(mouseAction); if (uiClickHandler.handleClick(mouseAction)) {
return true; return true;
} }
} }
} }
}
for (var handler : globalHandlers) { for (var handler : globalHandlers) {
if (handler.handleClick(mouseAction)) { if (handler.handleClick(mouseAction)) {
@@ -73,18 +74,19 @@ public class UIClickHandlerRepository {
public boolean handleElse(MouseAction mouseAction) { public boolean handleElse(MouseAction mouseAction) {
if (roomSpecificHandlers.containsKey(gameState.getCurrentRoom())) { if (roomSpecificHandlers.containsKey(gameState.getCurrentRoom())) {
Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(gameState.getCurrentRoom()); Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(gameState.getCurrentRoom());
TerminalPosition position = new TerminalPosition(mouseAction.getPosition().getColumn(), mouseAction.getPosition().getRow() * 2);
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(position)) { if (part.isWithin(position)) {
uiClickHandler.handleElse(mouseAction); if (uiClickHandler.handleElse(mouseAction)) {
return true; return true;
} }
} }
} }
}
for (var handler : globalHandlers) { for (var handler : globalHandlers) {
if (handler.handleElse(mouseAction)) { if (handler.handleElse(mouseAction)) {
@@ -98,17 +100,18 @@ public class UIClickHandlerRepository {
public boolean handleMove(MouseAction mouseAction) { public boolean handleMove(MouseAction mouseAction) {
if (roomSpecificHandlers.containsKey(gameState.getCurrentRoom())) { if (roomSpecificHandlers.containsKey(gameState.getCurrentRoom())) {
Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(gameState.getCurrentRoom()); Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(gameState.getCurrentRoom());
TerminalPosition position = new TerminalPosition(mouseAction.getPosition().getColumn(), mouseAction.getPosition().getRow() * 2);
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(position)) { if (part.isWithin(position)) {
uiClickHandler.handleMove(mouseAction); if (uiClickHandler.handleMove(mouseAction)) {
return true; return true;
} }
} }
} }
}
for (var handler : globalHandlers) { for (var handler : globalHandlers) {
if (handler.handleMove(mouseAction)) { if (handler.handleMove(mouseAction)) {
@@ -119,14 +122,14 @@ public class UIClickHandlerRepository {
return false; return false;
} }
public void removeHandlerForCurrentRoom(int screenPartHashCode, UIClickHandler uiClickHandler) { public void removeHandlerForCurrentRoom(int screenPartHashCode) {
GameRoom currentRoom = gameState.getCurrentRoom(); GameRoom currentRoom = gameState.getCurrentRoom();
if (!roomSpecificHandlers.containsKey(currentRoom)) return; if (!roomSpecificHandlers.containsKey(currentRoom)) return;
Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(currentRoom); Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(currentRoom);
for (var key : handlers.keySet()) { for (var key : handlers.keySet()) {
if (key.hashCode() == screenPartHashCode) { if (key.hashCode() == screenPartHashCode) {
handlers.remove(key, uiClickHandler); handlers.remove(key);
} }
} }
} }