feat: Food, Health system
This commit is contained in:
@@ -44,20 +44,24 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
|
||||
|
||||
for (int y = startYNormalized; y <= endYNormalized; y += 2) {
|
||||
for (int x = start.getColumn(); x <= end.getColumn(); x++) {
|
||||
Pixel topPixel = buffer[y][x];
|
||||
Pixel bottomPixel = (y + 1 <= end.getRow())
|
||||
? buffer[y + 1][x]
|
||||
: new Empty();
|
||||
try {
|
||||
Pixel topPixel = buffer[y][x];
|
||||
Pixel bottomPixel = (y + 1 <= end.getRow())
|
||||
? buffer[y + 1][x]
|
||||
: new Empty();
|
||||
|
||||
TextColor topColor = topPixel instanceof Empty
|
||||
? Constants.BACKGROUND_COLOR
|
||||
: topPixel.getColor();
|
||||
TextColor topColor = topPixel instanceof Empty
|
||||
? Constants.BACKGROUND_COLOR
|
||||
: topPixel.getColor();
|
||||
|
||||
TextColor bottomColor = bottomPixel instanceof Empty
|
||||
? Constants.BACKGROUND_COLOR
|
||||
: bottomPixel.getColor();
|
||||
TextColor bottomColor = bottomPixel instanceof Empty
|
||||
? Constants.BACKGROUND_COLOR
|
||||
: bottomPixel.getColor();
|
||||
|
||||
drawHalfPixel(tg, x, y / 2, topColor, bottomColor);
|
||||
drawHalfPixel(tg, x, y / 2, topColor, bottomColor);
|
||||
} catch (ArrayIndexOutOfBoundsException ignored) {
|
||||
// Random error, ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,27 @@ public class Player {
|
||||
stamina--;
|
||||
}
|
||||
|
||||
public void addHealth(int amount) {
|
||||
health = Math.min(MAX_HEALTH, health + amount);
|
||||
}
|
||||
|
||||
public boolean dealDamage(int amount) {
|
||||
if (health - amount <= 0) {
|
||||
health = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
health -= amount;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (selectedItem != null && selectedItem.getType() instanceof WeaponInterface item) {
|
||||
damage = item.getDamageDeal();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ public class ResourceManager {
|
||||
|
||||
WOODEN_SWORD("tools/wooden_sword.png"),
|
||||
|
||||
APPLE("food/apple.png"),
|
||||
|
||||
DOORS("rooms/doors.png");
|
||||
|
||||
private final String path;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package cz.jzitnik.game.items.strategy;
|
||||
|
||||
public interface Strategy {
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cz.jzitnik.game.items.types;
|
||||
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.StateManager;
|
||||
|
||||
public interface InteractableItem {
|
||||
InteractableItemResponse interact(DependencyManager dependencyManager, StateManager stateManager);
|
||||
|
||||
enum InteractableItemResponse {
|
||||
CLEAR_ITEM,
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package cz.jzitnik.game.items.types;
|
||||
|
||||
import cz.jzitnik.game.items.strategy.Strategy;
|
||||
|
||||
public interface ItemType<T> {
|
||||
Class<T> getItemType();
|
||||
Strategy getStrategy();
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package cz.jzitnik.game.items.types;
|
||||
|
||||
import cz.jzitnik.game.items.strategy.Strategy;
|
||||
import cz.jzitnik.game.items.strategy.SwordStrategy;
|
||||
|
||||
public class Sword extends Weapon {
|
||||
public Sword(int damageDeal) {
|
||||
super(damageDeal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Strategy getStrategy() {
|
||||
return new SwordStrategy(this);
|
||||
}
|
||||
}
|
||||
31
src/main/java/cz/jzitnik/game/items/types/food/Food.java
Normal file
31
src/main/java/cz/jzitnik/game/items/types/food/Food.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package cz.jzitnik.game.items.types.food;
|
||||
|
||||
import cz.jzitnik.events.RenderStats;
|
||||
import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.items.types.InteractableItem;
|
||||
import cz.jzitnik.game.items.types.ItemType;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.StateManager;
|
||||
import cz.jzitnik.utils.events.EventManager;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class Food implements InteractableItem, ItemType<Food> {
|
||||
private final int addHealth;
|
||||
|
||||
@Override
|
||||
public InteractableItemResponse interact(DependencyManager dependencyManager, StateManager stateManager) {
|
||||
GameState gameState = stateManager.getOrThrow(GameState.class);
|
||||
EventManager eventManager = dependencyManager.getDependencyOrThrow(EventManager.class);
|
||||
|
||||
gameState.getPlayer().addHealth(addHealth);
|
||||
eventManager.emitEvent(new RenderStats());
|
||||
|
||||
return InteractableItemResponse.CLEAR_ITEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Food> getItemType() {
|
||||
return Food.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package cz.jzitnik.game.items.types.weapons;
|
||||
|
||||
public class Sword extends Weapon {
|
||||
public Sword(int damageDeal) {
|
||||
super(damageDeal);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package cz.jzitnik.game.items.types;
|
||||
package cz.jzitnik.game.items.types.weapons;
|
||||
|
||||
import cz.jzitnik.game.items.strategy.Strategy;
|
||||
import cz.jzitnik.game.items.types.ItemType;
|
||||
import cz.jzitnik.game.items.types.interfaces.WeaponInterface;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@@ -15,5 +15,4 @@ public abstract class Weapon implements ItemType<Weapon>, WeaponInterface {
|
||||
return Weapon.class;
|
||||
}
|
||||
|
||||
public abstract Strategy getStrategy();
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public abstract class HittableMob extends Mob {
|
||||
|
||||
if (health <= 0) {
|
||||
onKilled();
|
||||
if (task != null) {
|
||||
for (RoomTask task : tasks) {
|
||||
roomTaskScheduler.stopTask(task);
|
||||
}
|
||||
gameState.getCurrentRoom().getMobs().remove(this);
|
||||
|
||||
@@ -14,12 +14,18 @@ public abstract class Mob implements Renderable, Selectable {
|
||||
protected final BufferedImage texture;
|
||||
|
||||
@Setter
|
||||
protected RoomTask task;
|
||||
protected RoomTask[] tasks;
|
||||
protected final RoomCords cords;
|
||||
|
||||
public Mob(BufferedImage texture, RoomTask task, RoomCords cords) {
|
||||
this.texture = texture;
|
||||
this.task = task;
|
||||
this.tasks = new RoomTask[] {task};
|
||||
this.cords = cords;
|
||||
}
|
||||
|
||||
public Mob(BufferedImage texture, RoomTask[] tasks, RoomCords cords) {
|
||||
this.texture = texture;
|
||||
this.tasks = tasks;
|
||||
this.cords = cords;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BlindMobFollowingPlayerTask extends RoomTask {
|
||||
public BlindMobFollowingPlayerTask(Mob mob, int speed, int updateRate) {
|
||||
super(new Task(mob, speed), updateRate, TimeUnit.MILLISECONDS);
|
||||
public BlindMobFollowingPlayerTask(Mob mob, int speed, int updateRateMs) {
|
||||
super(new Task(mob, speed), updateRateMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package cz.jzitnik.game.mobs.tasks;
|
||||
|
||||
import cz.jzitnik.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.events.RenderStats;
|
||||
import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.mobs.Mob;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.utils.events.EventManager;
|
||||
import cz.jzitnik.utils.roomtasks.RoomTask;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Slf4j
|
||||
public class EnemyPlayerHittingTask extends RoomTask {
|
||||
public EnemyPlayerHittingTask(Mob mob, long updateRateMs, double reach, Supplier<Integer> damageSupplier) {
|
||||
super(new Task(reach, damageSupplier, mob), updateRateMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class Task implements Runnable {
|
||||
private final double reach;
|
||||
private final Supplier<Integer> damageSupplier;
|
||||
private final Mob mob;
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
RoomCords playerCords = gameState.getPlayer().getPlayerCords();
|
||||
RoomCords mobCords = mob.getCords();
|
||||
double distance = playerCords.calculateDistance(mobCords);
|
||||
|
||||
if (distance > reach) {
|
||||
return;
|
||||
}
|
||||
|
||||
int damage = damageSupplier.get();
|
||||
|
||||
boolean isDead = gameState.getPlayer().dealDamage(damage);
|
||||
eventManager.emitEvent(new RenderStats());
|
||||
|
||||
log.debug("Is dead: {}", isDead);
|
||||
// TODO: Death screen
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.Player;
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.mobs.Mob;
|
||||
import cz.jzitnik.game.mobs.tasks.utils.AStarAlg;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.states.ScreenBuffer;
|
||||
import cz.jzitnik.states.TerminalState;
|
||||
@@ -26,8 +27,8 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
public class MobFollowingPlayerTask extends RoomTask {
|
||||
public MobFollowingPlayerTask(Mob mob, int speed, int updateRate) {
|
||||
super(new Task(mob, speed), updateRate, TimeUnit.MILLISECONDS);
|
||||
public MobFollowingPlayerTask(Mob mob, int speed, int updateRateMs) {
|
||||
super(new Task(mob, speed), updateRateMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cz.jzitnik.game.mobs.tasks;
|
||||
package cz.jzitnik.game.mobs.tasks.utils;
|
||||
|
||||
import cz.jzitnik.game.GameRoomPart;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
@@ -1,10 +1,11 @@
|
||||
package cz.jzitnik.game.setup.mobs;
|
||||
package cz.jzitnik.game.setup.enemies;
|
||||
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.mobs.HittableMob;
|
||||
import cz.jzitnik.game.mobs.tasks.BlindMobFollowingPlayerTask;
|
||||
import cz.jzitnik.game.mobs.tasks.EnemyPlayerHittingTask;
|
||||
import cz.jzitnik.game.mobs.tasks.MobFollowingPlayerTask;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.utils.roomtasks.RoomTask;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@@ -12,8 +13,10 @@ public class Zombie extends HittableMob {
|
||||
|
||||
public Zombie(ResourceManager resourceManager, RoomCords cords) {
|
||||
super(resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), null, cords, 10);
|
||||
setTask(new BlindMobFollowingPlayerTask(this, 1, 100));
|
||||
//setTask(new MobFollowingPlayerTask(this, 1, 100));
|
||||
setTasks(new RoomTask[]{
|
||||
new MobFollowingPlayerTask(this, 1, 100),
|
||||
new EnemyPlayerHittingTask(this, 500, 15, () -> 5)
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
15
src/main/java/cz/jzitnik/game/setup/items/Apple.java
Normal file
15
src/main/java/cz/jzitnik/game/setup/items/Apple.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package cz.jzitnik.game.setup.items;
|
||||
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.items.GameItem;
|
||||
import cz.jzitnik.game.items.types.food.Food;
|
||||
|
||||
public class Apple extends GameItem {
|
||||
public Apple(ResourceManager resourceManager) {
|
||||
super(
|
||||
"Apple",
|
||||
new Food(1),
|
||||
resourceManager.getResource(ResourceManager.Resource.APPLE)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package cz.jzitnik.game.setup.items;
|
||||
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.items.GameItem;
|
||||
import cz.jzitnik.game.items.types.Sword;
|
||||
import cz.jzitnik.game.items.types.weapons.Sword;
|
||||
|
||||
public class WoodenSword extends GameItem {
|
||||
public WoodenSword(ResourceManager resourceManager) {
|
||||
|
||||
@@ -4,9 +4,10 @@ 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.setup.items.Apple;
|
||||
import cz.jzitnik.game.setup.items.WoodenSword;
|
||||
import cz.jzitnik.game.objects.Chest;
|
||||
import cz.jzitnik.game.setup.mobs.Zombie;
|
||||
import cz.jzitnik.game.setup.enemies.Zombie;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -18,8 +19,7 @@ public class MainRoom extends GameRoom {
|
||||
|
||||
Chest chest = new Chest(dependencyManager, resourceManager, new RoomCords(100, 45), new GameItem[]{
|
||||
new WoodenSword(resourceManager),
|
||||
new WoodenSword(resourceManager),
|
||||
new WoodenSword(resourceManager),
|
||||
new Apple(resourceManager)
|
||||
});
|
||||
addCollider(new GameRoomPart(
|
||||
new RoomCords(60, 10),
|
||||
@@ -28,6 +28,6 @@ public class MainRoom extends GameRoom {
|
||||
addObject(chest);
|
||||
|
||||
Zombie zombie = new Zombie(resourceManager, new RoomCords(100, 100));
|
||||
//addMob(zombie);
|
||||
addMob(zombie);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,4 +38,16 @@ public class RoomCords implements Cloneable {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the Euclidean distance between this coordinate and another.
|
||||
* @param other The other RoomCords instance
|
||||
* @return The distance as a double
|
||||
*/
|
||||
public double calculateDistance(RoomCords other) {
|
||||
if (other == null) {
|
||||
throw new IllegalArgumentException("Cannot calculate distance to null");
|
||||
}
|
||||
return Math.hypot(this.x - other.x, this.y - other.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,16 @@ import cz.jzitnik.events.MouseAction;
|
||||
import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.items.GameItem;
|
||||
import cz.jzitnik.game.items.types.InteractableItem;
|
||||
import cz.jzitnik.game.objects.GlobalUIClickHandler;
|
||||
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.ui.utils.Grid;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.RerenderUtils;
|
||||
import cz.jzitnik.utils.StateManager;
|
||||
import cz.jzitnik.utils.events.EventManager;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -82,6 +85,10 @@ public class Inventory implements GlobalUIClickHandler {
|
||||
private ScreenBuffer screenBuffer;
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
@InjectDependency
|
||||
private DependencyManager dependencyManager;
|
||||
@InjectDependency
|
||||
private StateManager stateManager;
|
||||
@Getter
|
||||
private int offsetX;
|
||||
@Getter
|
||||
@@ -137,6 +144,17 @@ public class Inventory implements GlobalUIClickHandler {
|
||||
if (inventoryState.isGonnaDoubleClick) {
|
||||
inventoryState.isGonnaDoubleClick = false;
|
||||
inventoryState.selectedItem = -1;
|
||||
|
||||
if (inventory[itemClickedOnIndex].getType() instanceof InteractableItem item) {
|
||||
switch (item.interact(dependencyManager, stateManager)) {
|
||||
case CLEAR_ITEM -> {
|
||||
inventory[itemClickedOnIndex] = null;
|
||||
eventManager.emitEvent(new InventoryRerender());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gameState.getPlayer().setSelectedItem(
|
||||
gameState.getPlayer().getSelectedItem() == inventory[itemClickedOnIndex]
|
||||
? null
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public class RoomTask {
|
||||
public abstract class RoomTask {
|
||||
private final Runnable task;
|
||||
private final long rate;
|
||||
private final TimeUnit rateUnit;
|
||||
|
||||
@@ -77,9 +77,9 @@ public class RoomTaskScheduler {
|
||||
}
|
||||
|
||||
for (Mob mob : currentRoom.getMobs()) {
|
||||
RoomTask task = mob.getTask();
|
||||
RoomTask[] mobTasks = mob.getTasks();
|
||||
|
||||
if (task != null) {
|
||||
for (RoomTask task : mobTasks) {
|
||||
dependencyManager.inject(task.getTask());
|
||||
ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(task.getTask(), 0, task.getRate(), task.getRateUnit());
|
||||
tasks.put(task, future);
|
||||
|
||||
BIN
src/main/resources/textures/food/apple.png
Normal file
BIN
src/main/resources/textures/food/apple.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 504 B |
Reference in New Issue
Block a user