feat: Stamina and sprint
This commit is contained in:
@@ -2,6 +2,7 @@ package cz.jzitnik;
|
||||
|
||||
import cz.jzitnik.game.setup.GameSetup;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.ScheduledTaskManager;
|
||||
import cz.jzitnik.utils.ThreadManager;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
@@ -13,9 +14,11 @@ public class Game {
|
||||
|
||||
GameSetup gameSetup = dependencyManager.getDependencyOrThrow(GameSetup.class);
|
||||
ThreadManager threadManager = dependencyManager.getDependencyOrThrow(ThreadManager.class);
|
||||
ScheduledTaskManager scheduledTaskManager = dependencyManager.getDependencyOrThrow(ScheduledTaskManager.class);
|
||||
|
||||
gameSetup.setup();
|
||||
threadManager.startAll();
|
||||
scheduledTaskManager.startAll();
|
||||
|
||||
cli.run();
|
||||
}
|
||||
|
||||
14
src/main/java/cz/jzitnik/annotations/ScheduledTask.java
Normal file
14
src/main/java/cz/jzitnik/annotations/ScheduledTask.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package cz.jzitnik.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ScheduledTask {
|
||||
long rate();
|
||||
TimeUnit rateUnit();
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package cz.jzitnik.config;
|
||||
|
||||
import cz.jzitnik.annotations.Config;
|
||||
import cz.jzitnik.events.handlers.PlayerMoveEventHandler;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@@ -8,5 +9,10 @@ import lombok.Getter;
|
||||
public class PlayerConfig {
|
||||
private final double playerReach = 20;
|
||||
private final int playerMoveDistance = 3;
|
||||
private final int playerMoveDistanceSprinting = 6;
|
||||
private final PlayerMoveEventHandler.SprintKey sprintKey = PlayerMoveEventHandler.SprintKey.CTRL;
|
||||
private final int swingTimeMs = 500;
|
||||
|
||||
private final int staminaIncreaseRateMs = 500;
|
||||
private final int staminaDelayMs = 1000;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import cz.jzitnik.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.events.ExitEvent;
|
||||
import cz.jzitnik.states.RunningState;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.ScheduledTaskManager;
|
||||
import cz.jzitnik.utils.StateManager;
|
||||
import cz.jzitnik.utils.ThreadManager;
|
||||
import cz.jzitnik.utils.events.AbstractEventHandler;
|
||||
@@ -22,6 +23,9 @@ public class ExitEventHandler extends AbstractEventHandler<ExitEvent> {
|
||||
@InjectDependency
|
||||
private RoomTaskScheduler roomTaskScheduler;
|
||||
|
||||
@InjectDependency
|
||||
private ScheduledTaskManager scheduledTaskManager;
|
||||
|
||||
public ExitEventHandler(DependencyManager dm) {
|
||||
super(dm);
|
||||
}
|
||||
@@ -29,6 +33,7 @@ public class ExitEventHandler extends AbstractEventHandler<ExitEvent> {
|
||||
@Override
|
||||
public void handle(ExitEvent event) {
|
||||
threadManager.shutdownAll();
|
||||
scheduledTaskManager.shutdown();
|
||||
roomTaskScheduler.finalShutdown();
|
||||
runningState.setRunning(false);
|
||||
System.exit(0); // Pls don't blame me
|
||||
|
||||
@@ -19,6 +19,7 @@ import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.states.RenderState;
|
||||
import cz.jzitnik.states.ScreenBuffer;
|
||||
import cz.jzitnik.states.PlayerMovementState;
|
||||
import cz.jzitnik.states.TerminalState;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.RerenderUtils;
|
||||
@@ -31,37 +32,31 @@ import java.awt.image.BufferedImage;
|
||||
@Slf4j
|
||||
@EventHandler(PlayerMoveEvent.class)
|
||||
public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent> {
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
@InjectState
|
||||
private TerminalState terminalState;
|
||||
@InjectState
|
||||
private ScreenBuffer screenBuffer;
|
||||
@InjectDependency
|
||||
private ResourceManager resourceManager;
|
||||
@InjectConfig
|
||||
private Debugging debugging;
|
||||
@InjectConfig
|
||||
private PlayerConfig playerConfig;
|
||||
@InjectState
|
||||
private RenderState renderState;
|
||||
@InjectConfig
|
||||
private Logging logging;
|
||||
@InjectState
|
||||
private PlayerMovementState playerMovementState;
|
||||
|
||||
public PlayerMoveEventHandler(DependencyManager dm) {
|
||||
super(dm);
|
||||
}
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
|
||||
@InjectState
|
||||
private TerminalState terminalState;
|
||||
|
||||
@InjectState
|
||||
private ScreenBuffer screenBuffer;
|
||||
|
||||
@InjectDependency
|
||||
private ResourceManager resourceManager;
|
||||
|
||||
@InjectConfig
|
||||
private Debugging debugging;
|
||||
|
||||
@InjectConfig
|
||||
private PlayerConfig playerConfig;
|
||||
|
||||
@InjectState
|
||||
private RenderState renderState;
|
||||
|
||||
@InjectConfig
|
||||
private Logging logging;
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMoveEvent event) {
|
||||
if (renderState.isTerminalTooSmall()) {
|
||||
@@ -73,7 +68,13 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
|
||||
RoomCords playerCords = player.getPlayerCords();
|
||||
GameRoom currentRoom = gameState.getCurrentRoom();
|
||||
|
||||
int moveStep = playerConfig.getPlayerMoveDistance();
|
||||
boolean isSprinting = player.getStamina() > 0 && switch (playerConfig.getSprintKey()) {
|
||||
case CTRL -> event.getKeyStroke().isCtrlDown();
|
||||
case SHIFT -> event.getKeyStroke().isShiftDown();
|
||||
case ALT -> event.getKeyStroke().isAltDown();
|
||||
};
|
||||
|
||||
int moveStep = isSprinting ? playerConfig.getPlayerMoveDistanceSprinting() : playerConfig.getPlayerMoveDistance();
|
||||
|
||||
int originalPlayerX = playerCords.getX();
|
||||
int originalPlayerY = playerCords.getY();
|
||||
@@ -123,6 +124,11 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
|
||||
player.setPlayerRotation(Player.PlayerRotation.RIGHT);
|
||||
}
|
||||
}
|
||||
playerMovementState.setLastMovement(System.currentTimeMillis());
|
||||
if (isSprinting) {
|
||||
int newStamina = player.decreaseStamina();
|
||||
}
|
||||
|
||||
int newPlayerX = playerCords.getX();
|
||||
int newPlayerY = playerCords.getY();
|
||||
if (logging.isShowPlayerCordsLogs()) {
|
||||
@@ -148,4 +154,10 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
public static enum SprintKey {
|
||||
CTRL,
|
||||
SHIFT,
|
||||
ALT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cz.jzitnik.game;
|
||||
|
||||
import cz.jzitnik.game.items.GameItem;
|
||||
import cz.jzitnik.game.items.types.interfaces.WeaponInterface;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.ui.Inventory;
|
||||
import lombok.Getter;
|
||||
@@ -16,13 +17,37 @@ import java.util.concurrent.TimeUnit;
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class Player {
|
||||
public static final int MAX_STAMINA = 20;
|
||||
|
||||
private final RoomCords playerCords;
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private final GameItem[] inventory = new GameItem[Inventory.ITEMS_X * Inventory.ITEMS_Y];
|
||||
private int stamina = MAX_STAMINA;
|
||||
@Setter
|
||||
private GameItem selectedItem;
|
||||
private boolean swinging = false;
|
||||
|
||||
public int increaseStamina() {
|
||||
log.debug("Stamina: {}", stamina + 1);
|
||||
return ++stamina;
|
||||
}
|
||||
public int decreaseStamina() {
|
||||
log.debug("Stamina: {}", stamina - 1);
|
||||
return --stamina;
|
||||
}
|
||||
|
||||
public int getDamageDeal() {
|
||||
int damage = 1;
|
||||
|
||||
// Probably in the future, there will be more logic like potions, etc.
|
||||
log.debug("Selected item: {}", selectedItem);
|
||||
if (selectedItem.getType() instanceof WeaponInterface item) {
|
||||
damage = item.getDamageDeal();
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
public boolean addItem(GameItem item) {
|
||||
boolean added = false;
|
||||
for (int i = 0; i < inventory.length; i++) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package cz.jzitnik.game.items.types;
|
||||
|
||||
import cz.jzitnik.game.items.strategy.Strategy;
|
||||
|
||||
public sealed interface ItemType<T> permits Sword {
|
||||
public interface ItemType<T> {
|
||||
Class<T> getItemType();
|
||||
Strategy getStrategy();
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
package cz.jzitnik.game.items.types;
|
||||
|
||||
import cz.jzitnik.game.items.strategy.Strategy;
|
||||
import cz.jzitnik.game.items.strategy.SwordStrategy;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public non-sealed class Sword implements ItemType<Sword> {
|
||||
protected int damageDeal;
|
||||
|
||||
public final Class<Sword> getItemType() {
|
||||
return Sword.class;
|
||||
public class Sword extends Weapon {
|
||||
public Sword(int damageDeal) {
|
||||
super(damageDeal);
|
||||
}
|
||||
|
||||
public SwordStrategy getStrategy() {
|
||||
@Override
|
||||
public Strategy getStrategy() {
|
||||
return new SwordStrategy(this);
|
||||
}
|
||||
}
|
||||
|
||||
19
src/main/java/cz/jzitnik/game/items/types/Weapon.java
Normal file
19
src/main/java/cz/jzitnik/game/items/types/Weapon.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package cz.jzitnik.game.items.types;
|
||||
|
||||
import cz.jzitnik.game.items.strategy.Strategy;
|
||||
import cz.jzitnik.game.items.types.interfaces.WeaponInterface;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public abstract class Weapon implements ItemType<Weapon>, WeaponInterface {
|
||||
protected int damageDeal;
|
||||
|
||||
@Override
|
||||
public final Class<Weapon> getItemType() {
|
||||
return Weapon.class;
|
||||
}
|
||||
|
||||
public abstract Strategy getStrategy();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package cz.jzitnik.game.items.types.interfaces;
|
||||
|
||||
public interface WeaponInterface {
|
||||
int getDamageDeal();
|
||||
}
|
||||
@@ -61,8 +61,7 @@ public abstract class HittableMob extends Mob {
|
||||
public void interact(DependencyManager dm) {
|
||||
dm.inject(this);
|
||||
|
||||
// TODO: Swords in hand will deal more damage, for now deal always one
|
||||
health--;
|
||||
health -= gameState.getPlayer().getDamageDeal();
|
||||
|
||||
log.debug("Health: {}", health);
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package cz.jzitnik.game.items;
|
||||
package cz.jzitnik.game.setup.items;
|
||||
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.items.GameItem;
|
||||
import cz.jzitnik.game.items.types.Sword;
|
||||
|
||||
public class WoodenSword extends GameItem {
|
||||
public WoodenSword(ResourceManager resourceManager) {
|
||||
super(
|
||||
"Wooden sword",
|
||||
new Sword(5),
|
||||
new Sword(2),
|
||||
resourceManager.getResource(ResourceManager.Resource.WOODEN_SWORD)
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import cz.jzitnik.game.GameRoom;
|
||||
import cz.jzitnik.game.GameRoomPart;
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.items.GameItem;
|
||||
import cz.jzitnik.game.items.WoodenSword;
|
||||
import cz.jzitnik.game.setup.items.WoodenSword;
|
||||
import cz.jzitnik.game.objects.Chest;
|
||||
import cz.jzitnik.game.setup.mobs.Zombie;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
|
||||
13
src/main/java/cz/jzitnik/states/PlayerMovementState.java
Normal file
13
src/main/java/cz/jzitnik/states/PlayerMovementState.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package cz.jzitnik.states;
|
||||
|
||||
import cz.jzitnik.annotations.State;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
@Data
|
||||
@State
|
||||
public class PlayerMovementState {
|
||||
long lastMovement;
|
||||
ScheduledFuture<?> staminaIncreaseSchedule;
|
||||
}
|
||||
73
src/main/java/cz/jzitnik/tasks/StaminaIncreaseTask.java
Normal file
73
src/main/java/cz/jzitnik/tasks/StaminaIncreaseTask.java
Normal file
@@ -0,0 +1,73 @@
|
||||
package cz.jzitnik.tasks;
|
||||
|
||||
import cz.jzitnik.annotations.ScheduledTask;
|
||||
import cz.jzitnik.annotations.injectors.InjectConfig;
|
||||
import cz.jzitnik.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.config.PlayerConfig;
|
||||
import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.Player;
|
||||
import cz.jzitnik.states.PlayerMovementState;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.ScheduledTaskManager;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ScheduledTask(rate = 1, rateUnit = TimeUnit.SECONDS)
|
||||
public class StaminaIncreaseTask implements Runnable {
|
||||
@InjectState
|
||||
private PlayerMovementState playerMovementState;
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private ScheduledTaskManager scheduledTaskManager;
|
||||
|
||||
@InjectDependency
|
||||
private DependencyManager dependencyManager;
|
||||
|
||||
@InjectConfig
|
||||
private PlayerConfig playerConfig;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (playerMovementState.getStaminaIncreaseSchedule() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long nowTime = System.currentTimeMillis();
|
||||
if (nowTime - playerMovementState.getLastMovement() >= playerConfig.getStaminaDelayMs() && gameState.getPlayer().getStamina() < Player.MAX_STAMINA) {
|
||||
IncreaseStamina instance = new IncreaseStamina();
|
||||
dependencyManager.inject(instance);
|
||||
playerMovementState.setStaminaIncreaseSchedule(scheduledTaskManager.tempScheduleFixedRate(instance, playerConfig.getStaminaIncreaseRateMs(), TimeUnit.MILLISECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
public static class IncreaseStamina implements Runnable {
|
||||
@InjectState
|
||||
private PlayerMovementState playerMovementState;
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectConfig
|
||||
private PlayerConfig playerConfig;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long nowTime = System.currentTimeMillis();
|
||||
|
||||
Player player = gameState.getPlayer();
|
||||
if (player.getStamina() >= Player.MAX_STAMINA || nowTime - playerMovementState.getLastMovement() < playerConfig.getStaminaDelayMs()) {
|
||||
ScheduledFuture<?> future = playerMovementState.getStaminaIncreaseSchedule();
|
||||
playerMovementState.setStaminaIncreaseSchedule(null);
|
||||
future.cancel(false);
|
||||
return;
|
||||
}
|
||||
|
||||
player.increaseStamina();
|
||||
}
|
||||
}
|
||||
}
|
||||
73
src/main/java/cz/jzitnik/utils/ScheduledTaskManager.java
Normal file
73
src/main/java/cz/jzitnik/utils/ScheduledTaskManager.java
Normal file
@@ -0,0 +1,73 @@
|
||||
package cz.jzitnik.utils;
|
||||
|
||||
import cz.jzitnik.annotations.Dependency;
|
||||
import cz.jzitnik.annotations.ScheduledTask;
|
||||
import cz.jzitnik.config.ThreadPoolConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Dependency
|
||||
public class ScheduledTaskManager {
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(new ThreadPoolConfig().getTaskThreadCount());
|
||||
private final HashSet<Registry> instances = new HashSet<>();
|
||||
private final DependencyManager dependencyManager;
|
||||
|
||||
public ScheduledTaskManager(Reflections reflections, DependencyManager dependencyManager) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
var classes = reflections.getTypesAnnotatedWith(ScheduledTask.class);
|
||||
for (Class<?> clazz : classes) {
|
||||
if (!Runnable.class.isAssignableFrom(clazz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
var instance = (Runnable) clazz.getDeclaredConstructor().newInstance();
|
||||
var annotation = clazz.getAnnotation(ScheduledTask.class);
|
||||
|
||||
assert annotation != null;
|
||||
|
||||
instances.add(new Registry(instance, annotation));
|
||||
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startAll() {
|
||||
for (Registry instance : instances) {
|
||||
dependencyManager.inject(instance.runnable);
|
||||
scheduler.scheduleAtFixedRate(instance.runnable, 0, instance.scheduledTask.rate(), instance.scheduledTask.rateUnit());
|
||||
}
|
||||
}
|
||||
|
||||
public ScheduledFuture<?> tempScheduleFixedRate(Runnable runnable, int rate, TimeUnit rateUnit) {
|
||||
return scheduler.scheduleAtFixedRate(runnable, 0, rate, rateUnit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
try {
|
||||
scheduler.shutdown();
|
||||
if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||
scheduler.shutdownNow();
|
||||
if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||
log.error("Pool did not terminate");
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
scheduler.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private record Registry(Runnable runnable, ScheduledTask scheduledTask) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user