diff --git a/src/main/java/cz/jzitnik/events/handlers/CliHandler.java b/src/main/java/cz/jzitnik/events/handlers/CliHandler.java index 40fb48f..49c8d83 100644 --- a/src/main/java/cz/jzitnik/events/handlers/CliHandler.java +++ b/src/main/java/cz/jzitnik/events/handlers/CliHandler.java @@ -44,20 +44,24 @@ public class CliHandler extends AbstractEventHandler { 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 + } } } } diff --git a/src/main/java/cz/jzitnik/game/Player.java b/src/main/java/cz/jzitnik/game/Player.java index 24b992f..264faca 100644 --- a/src/main/java/cz/jzitnik/game/Player.java +++ b/src/main/java/cz/jzitnik/game/Player.java @@ -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(); } diff --git a/src/main/java/cz/jzitnik/game/ResourceManager.java b/src/main/java/cz/jzitnik/game/ResourceManager.java index c437a45..caa6394 100644 --- a/src/main/java/cz/jzitnik/game/ResourceManager.java +++ b/src/main/java/cz/jzitnik/game/ResourceManager.java @@ -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; diff --git a/src/main/java/cz/jzitnik/game/items/strategy/Strategy.java b/src/main/java/cz/jzitnik/game/items/strategy/Strategy.java deleted file mode 100644 index dd58a40..0000000 --- a/src/main/java/cz/jzitnik/game/items/strategy/Strategy.java +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 4fde945..0000000 --- a/src/main/java/cz/jzitnik/game/items/strategy/SwordStrategy.java +++ /dev/null @@ -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; -} diff --git a/src/main/java/cz/jzitnik/game/items/types/InteractableItem.java b/src/main/java/cz/jzitnik/game/items/types/InteractableItem.java new file mode 100644 index 0000000..a7e4402 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/types/InteractableItem.java @@ -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, + } +} diff --git a/src/main/java/cz/jzitnik/game/items/types/ItemType.java b/src/main/java/cz/jzitnik/game/items/types/ItemType.java index a767dd0..a86e842 100644 --- a/src/main/java/cz/jzitnik/game/items/types/ItemType.java +++ b/src/main/java/cz/jzitnik/game/items/types/ItemType.java @@ -1,8 +1,5 @@ package cz.jzitnik.game.items.types; -import cz.jzitnik.game.items.strategy.Strategy; - public interface ItemType { 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 deleted file mode 100644 index daeb1e0..0000000 --- a/src/main/java/cz/jzitnik/game/items/types/Sword.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/java/cz/jzitnik/game/items/types/food/Food.java b/src/main/java/cz/jzitnik/game/items/types/food/Food.java new file mode 100644 index 0000000..e164ecd --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/types/food/Food.java @@ -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 { + 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 getItemType() { + return Food.class; + } +} diff --git a/src/main/java/cz/jzitnik/game/items/types/weapons/Sword.java b/src/main/java/cz/jzitnik/game/items/types/weapons/Sword.java new file mode 100644 index 0000000..a819b5a --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/types/weapons/Sword.java @@ -0,0 +1,7 @@ +package cz.jzitnik.game.items.types.weapons; + +public class Sword extends Weapon { + public Sword(int damageDeal) { + super(damageDeal); + } +} diff --git a/src/main/java/cz/jzitnik/game/items/types/Weapon.java b/src/main/java/cz/jzitnik/game/items/types/weapons/Weapon.java similarity index 73% rename from src/main/java/cz/jzitnik/game/items/types/Weapon.java rename to src/main/java/cz/jzitnik/game/items/types/weapons/Weapon.java index aab73ea..94268c1 100644 --- a/src/main/java/cz/jzitnik/game/items/types/Weapon.java +++ b/src/main/java/cz/jzitnik/game/items/types/weapons/Weapon.java @@ -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, WeaponInterface { return Weapon.class; } - public abstract Strategy getStrategy(); } diff --git a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java index a086790..889943e 100644 --- a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java +++ b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java @@ -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); diff --git a/src/main/java/cz/jzitnik/game/mobs/Mob.java b/src/main/java/cz/jzitnik/game/mobs/Mob.java index d31bf3d..8c301c0 100644 --- a/src/main/java/cz/jzitnik/game/mobs/Mob.java +++ b/src/main/java/cz/jzitnik/game/mobs/Mob.java @@ -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; } diff --git a/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java b/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java index 8c0294b..fdd81ad 100644 --- a/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java +++ b/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java @@ -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 diff --git a/src/main/java/cz/jzitnik/game/mobs/tasks/EnemyPlayerHittingTask.java b/src/main/java/cz/jzitnik/game/mobs/tasks/EnemyPlayerHittingTask.java new file mode 100644 index 0000000..13c3ba6 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/mobs/tasks/EnemyPlayerHittingTask.java @@ -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 damageSupplier) { + super(new Task(reach, damageSupplier, mob), updateRateMs, TimeUnit.MILLISECONDS); + } + + @RequiredArgsConstructor + private static class Task implements Runnable { + private final double reach; + private final Supplier 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 + } + } +} diff --git a/src/main/java/cz/jzitnik/game/mobs/tasks/MobFollowingPlayerTask.java b/src/main/java/cz/jzitnik/game/mobs/tasks/MobFollowingPlayerTask.java index 74205cc..9a85ad6 100644 --- a/src/main/java/cz/jzitnik/game/mobs/tasks/MobFollowingPlayerTask.java +++ b/src/main/java/cz/jzitnik/game/mobs/tasks/MobFollowingPlayerTask.java @@ -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 diff --git a/src/main/java/cz/jzitnik/game/mobs/tasks/AStarAlg.java b/src/main/java/cz/jzitnik/game/mobs/tasks/utils/AStarAlg.java similarity index 98% rename from src/main/java/cz/jzitnik/game/mobs/tasks/AStarAlg.java rename to src/main/java/cz/jzitnik/game/mobs/tasks/utils/AStarAlg.java index d03a13d..f3f9a4a 100644 --- a/src/main/java/cz/jzitnik/game/mobs/tasks/AStarAlg.java +++ b/src/main/java/cz/jzitnik/game/mobs/tasks/utils/AStarAlg.java @@ -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; diff --git a/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java b/src/main/java/cz/jzitnik/game/setup/enemies/Zombie.java similarity index 62% rename from src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java rename to src/main/java/cz/jzitnik/game/setup/enemies/Zombie.java index 79d32e8..be0a395 100644 --- a/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java +++ b/src/main/java/cz/jzitnik/game/setup/enemies/Zombie.java @@ -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 diff --git a/src/main/java/cz/jzitnik/game/setup/items/Apple.java b/src/main/java/cz/jzitnik/game/setup/items/Apple.java new file mode 100644 index 0000000..b543fcc --- /dev/null +++ b/src/main/java/cz/jzitnik/game/setup/items/Apple.java @@ -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) + ); + } +} diff --git a/src/main/java/cz/jzitnik/game/setup/items/WoodenSword.java b/src/main/java/cz/jzitnik/game/setup/items/WoodenSword.java index 243814f..3f18dbf 100644 --- a/src/main/java/cz/jzitnik/game/setup/items/WoodenSword.java +++ b/src/main/java/cz/jzitnik/game/setup/items/WoodenSword.java @@ -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) { diff --git a/src/main/java/cz/jzitnik/game/setup/rooms/MainRoom.java b/src/main/java/cz/jzitnik/game/setup/rooms/MainRoom.java index 1da5c57..d5a7613 100644 --- a/src/main/java/cz/jzitnik/game/setup/rooms/MainRoom.java +++ b/src/main/java/cz/jzitnik/game/setup/rooms/MainRoom.java @@ -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); } } diff --git a/src/main/java/cz/jzitnik/game/utils/RoomCords.java b/src/main/java/cz/jzitnik/game/utils/RoomCords.java index 90a3537..20d0fe4 100644 --- a/src/main/java/cz/jzitnik/game/utils/RoomCords.java +++ b/src/main/java/cz/jzitnik/game/utils/RoomCords.java @@ -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); + } } diff --git a/src/main/java/cz/jzitnik/ui/Inventory.java b/src/main/java/cz/jzitnik/ui/Inventory.java index 741015d..478b9c3 100644 --- a/src/main/java/cz/jzitnik/ui/Inventory.java +++ b/src/main/java/cz/jzitnik/ui/Inventory.java @@ -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 diff --git a/src/main/java/cz/jzitnik/utils/roomtasks/RoomTask.java b/src/main/java/cz/jzitnik/utils/roomtasks/RoomTask.java index 4af0f0f..97dfcb3 100644 --- a/src/main/java/cz/jzitnik/utils/roomtasks/RoomTask.java +++ b/src/main/java/cz/jzitnik/utils/roomtasks/RoomTask.java @@ -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; diff --git a/src/main/java/cz/jzitnik/utils/roomtasks/RoomTaskScheduler.java b/src/main/java/cz/jzitnik/utils/roomtasks/RoomTaskScheduler.java index 2fb9834..7f0466a 100644 --- a/src/main/java/cz/jzitnik/utils/roomtasks/RoomTaskScheduler.java +++ b/src/main/java/cz/jzitnik/utils/roomtasks/RoomTaskScheduler.java @@ -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); diff --git a/src/main/resources/textures/food/apple.png b/src/main/resources/textures/food/apple.png new file mode 100644 index 0000000..4f9ed62 Binary files /dev/null and b/src/main/resources/textures/food/apple.png differ