diff --git a/pom.xml b/pom.xml
index e9111aa..58aeff5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,12 @@
guava
31.1-jre
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.18.2
+
diff --git a/src/main/java/cz/jzitnik/Main.java b/src/main/java/cz/jzitnik/Main.java
index b0e4f23..e933c7c 100644
--- a/src/main/java/cz/jzitnik/Main.java
+++ b/src/main/java/cz/jzitnik/Main.java
@@ -1,6 +1,7 @@
package cz.jzitnik;
import cz.jzitnik.game.Game;
+import cz.jzitnik.game.mobs.EntityLogicProvider;
import cz.jzitnik.game.threads.HealthRegenerationThread;
import cz.jzitnik.game.threads.HungerDrainThread;
import cz.jzitnik.game.threads.InputHandlerThread;
@@ -33,16 +34,18 @@ public class Main {
Thread inputHandlerThread = new InputHandlerThread(game, terminal, screenRenderer, isRunning);
Thread healingThread = new HealthRegenerationThread(game.getPlayer());
Thread hungerDrainThread = new HungerDrainThread(game.getPlayer());
+ EntityLogicProvider entityLogicProvider = new EntityLogicProvider();
+ // Start all threads
healingThread.start();
hungerDrainThread.start();
inputHandlerThread.start();
-
while (isRunning[0]) {
if (game.getWindow() == Window.WORLD) {
screenRenderer.render(game);
}
+ entityLogicProvider.update(game);
Thread.sleep(1000);
}
diff --git a/src/main/java/cz/jzitnik/game/Game.java b/src/main/java/cz/jzitnik/game/Game.java
index aa028d3..adc380a 100644
--- a/src/main/java/cz/jzitnik/game/Game.java
+++ b/src/main/java/cz/jzitnik/game/Game.java
@@ -1,16 +1,21 @@
package cz.jzitnik.game;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import cz.jzitnik.game.entities.Block;
+import cz.jzitnik.game.entities.GameStates;
+import cz.jzitnik.game.entities.Player;
import cz.jzitnik.game.generation.Generation;
-import cz.jzitnik.game.items.Item;
-import cz.jzitnik.game.items.ItemType;
+import cz.jzitnik.game.entities.items.Item;
+import cz.jzitnik.game.entities.items.ItemType;
import cz.jzitnik.game.handlers.place.CustomPlaceHandler;
+import cz.jzitnik.game.mobs.EntitySpawnProvider;
import cz.jzitnik.game.sprites.Breaking;
import cz.jzitnik.game.sprites.Steve;
-import cz.jzitnik.game.ui.Chest;
-import cz.jzitnik.game.ui.Furnace;
+import cz.jzitnik.game.blocks.Chest;
+import cz.jzitnik.game.blocks.Furnace;
import cz.jzitnik.game.ui.Window;
import cz.jzitnik.game.ui.Inventory;
-import cz.jzitnik.game.handlers.rightclick.RightClickHandler;
+import cz.jzitnik.game.handlers.rightclick.RightClickHandlerProvider;
import cz.jzitnik.tui.ScreenMovingCalculationProvider;
import cz.jzitnik.tui.ScreenRenderer;
import lombok.Getter;
@@ -28,12 +33,14 @@ public class Game {
private boolean mining = false;
@Setter
private Window window = Window.WORLD;
-
- //jsonignore
- private final GameStates gameStates = new GameStates(this);
-
private final Inventory inventory = new Inventory();
+ @JsonIgnore
+ private final EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
+
+ @JsonIgnore
+ private final GameStates gameStates = new GameStates(this);
+
public Game() {
Generation.generateWorld(this);
}
@@ -51,13 +58,13 @@ public class Game {
return null;
}
- public void movePlayerRight(ScreenRenderer screenRenderer) {
+ public void movePlayerRight(ScreenRenderer screenRenderer, Terminal terminal) {
if (window != Window.WORLD) {
return;
}
int[] cords = getPlayerCords();
- if (world[cords[1]][cords[0] + 1].stream().anyMatch(block -> !block.isGhost()) || world[cords[1] - 1][cords[0] + 1].stream().anyMatch(block -> !block.isGhost())) {
+ if (isSolid(world[cords[1]][cords[0] + 1]) || isSolid(world[cords[1] - 1][cords[0] + 1])) {
return;
}
@@ -67,16 +74,18 @@ public class Game {
world[cords[1]-1][cords[0]].remove(player.getPlayerBlock1());
screenRenderer.render(this);
+ entitySpawnProvider.update(this, terminal);
+
update(screenRenderer);
}
- public void movePlayerLeft(ScreenRenderer screenRenderer) {
+ public void movePlayerLeft(ScreenRenderer screenRenderer, Terminal terminal) {
if (window != Window.WORLD) {
return;
}
int[] cords = getPlayerCords();
- if (world[cords[1]][cords[0] - 1].stream().anyMatch(block -> !block.isGhost()) || world[cords[1] - 1][cords[0] - 1].stream().anyMatch(block -> !block.isGhost())) {
+ if (isSolid(world[cords[1]][cords[0] - 1]) || isSolid(world[cords[1] - 1][cords[0] - 1])) {
return;
}
@@ -86,6 +95,8 @@ public class Game {
world[cords[1]-1][cords[0]].remove(player.getPlayerBlock1());
screenRenderer.render(this);
+ entitySpawnProvider.update(this, terminal);
+
update(screenRenderer);
}
@@ -95,7 +106,7 @@ public class Game {
}
int[] cords = getPlayerCords();
- if (world[cords[1] - 2][cords[0]].stream().anyMatch(block -> !block.isGhost()) || world[cords[1] + 1][cords[0]].stream().allMatch(Block::isGhost)) {
+ if (isSolid(world[cords[1] - 2][cords[0]]) || !isSolid(world[cords[1] + 1][cords[0]])) {
return;
}
@@ -106,20 +117,12 @@ public class Game {
new Thread(() -> {
try {
- Thread.sleep(500);
+ Thread.sleep(400);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
- int[] cords2 = getPlayerCords();
- if (world[cords2[1] + 1][cords2[0]].stream().allMatch(Block::isGhost)) {
- world[cords2[1] - 1][cords2[0]].remove(player.getPlayerBlock1());
- world[cords2[1]][cords2[0]].add(player.getPlayerBlock1());
- world[cords2[1] + 1][cords2[0]].add(player.getPlayerBlock2());
- world[cords2[1]][cords2[0]].remove(player.getPlayerBlock2());
-
- screenRenderer.render(this);
- }
+ update(screenRenderer);
}).start();
}
@@ -233,7 +236,7 @@ public class Game {
}
int[] cords2 = getPlayerCords();
- if (world[cords2[1] + 1][cords2[0]].stream().allMatch(Block::isGhost)) {
+ if (!isSolid(world[cords2[1] + 1][cords2[0]])) {
world[cords2[1] - 1][cords2[0]].remove(player.getPlayerBlock1());
world[cords2[1]][cords2[0]].add(player.getPlayerBlock1());
world[cords2[1] + 1][cords2[0]].add(player.getPlayerBlock2());
@@ -268,7 +271,7 @@ public class Game {
}
if (!blocks.stream().allMatch(block -> block.getBlockId().equals("air"))) {
- RightClickHandler.handle(x, y, this, screenRenderer);
+ RightClickHandlerProvider.handle(x, y, this, screenRenderer);
screenRenderer.render(this);
return;
}
@@ -293,4 +296,8 @@ public class Game {
inventory.setItemInhHandIndex(slot);
screenRenderer.render(this);
}
+
+ public boolean isSolid(List blocks) {
+ return !blocks.stream().allMatch(Block::isGhost);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/cz/jzitnik/game/annotations/RegisterPlaceHandler.java b/src/main/java/cz/jzitnik/game/annotations/EntityLogic.java
similarity index 87%
rename from src/main/java/cz/jzitnik/game/annotations/RegisterPlaceHandler.java
rename to src/main/java/cz/jzitnik/game/annotations/EntityLogic.java
index d9cc272..3775c60 100644
--- a/src/main/java/cz/jzitnik/game/annotations/RegisterPlaceHandler.java
+++ b/src/main/java/cz/jzitnik/game/annotations/EntityLogic.java
@@ -5,8 +5,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
-@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
-public @interface RegisterPlaceHandler {
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EntityLogic {
String value();
}
diff --git a/src/main/java/cz/jzitnik/game/annotations/EntitySpawn.java b/src/main/java/cz/jzitnik/game/annotations/EntitySpawn.java
new file mode 100644
index 0000000..1d9c4d6
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/annotations/EntitySpawn.java
@@ -0,0 +1,11 @@
+package cz.jzitnik.game.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EntitySpawn {
+}
diff --git a/src/main/java/cz/jzitnik/game/annotations/PlaceHandler.java b/src/main/java/cz/jzitnik/game/annotations/PlaceHandler.java
new file mode 100644
index 0000000..2c61b9f
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/annotations/PlaceHandler.java
@@ -0,0 +1,13 @@
+package cz.jzitnik.game.annotations;
+
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface PlaceHandler {
+ String value();
+}
diff --git a/src/main/java/cz/jzitnik/game/annotations/RightClickLogic.java b/src/main/java/cz/jzitnik/game/annotations/RightClickLogic.java
new file mode 100644
index 0000000..22cbaac
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/annotations/RightClickLogic.java
@@ -0,0 +1,11 @@
+package cz.jzitnik.game.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RightClickLogic {
+}
diff --git a/src/main/java/cz/jzitnik/game/ui/Chest.java b/src/main/java/cz/jzitnik/game/blocks/Chest.java
similarity index 87%
rename from src/main/java/cz/jzitnik/game/ui/Chest.java
rename to src/main/java/cz/jzitnik/game/blocks/Chest.java
index c21e01d..dfb2d7c 100644
--- a/src/main/java/cz/jzitnik/game/ui/Chest.java
+++ b/src/main/java/cz/jzitnik/game/blocks/Chest.java
@@ -1,7 +1,11 @@
-package cz.jzitnik.game.ui;
+package cz.jzitnik.game.blocks;
import cz.jzitnik.game.Game;
-import cz.jzitnik.game.items.InventoryItem;
+import cz.jzitnik.game.annotations.RightClickLogic;
+import cz.jzitnik.game.entities.items.InventoryItem;
+import cz.jzitnik.game.handlers.rightclick.RightClickHandler;
+import cz.jzitnik.game.ui.InventoryClickHandler;
+import cz.jzitnik.game.ui.Window;
import cz.jzitnik.tui.ScreenRenderer;
import cz.jzitnik.tui.SpriteList;
import org.jline.terminal.MouseEvent;
@@ -10,7 +14,8 @@ import org.jline.terminal.Terminal;
import java.util.List;
import java.util.Optional;
-public class Chest {
+@RightClickLogic
+public class Chest implements RightClickHandler {
private static final int ROW_AMOUNT = 4;
private static final int COLUMN_AMOUNT = 6;
private static final int CELL_WIDTH = 50;
@@ -91,4 +96,9 @@ public class Chest {
items[i] = null;
}
}
+
+ @Override
+ public void onBlockRightClick(int ignored, int ignored2, Game game, ScreenRenderer ignored4) {
+ game.setWindow(Window.CHEST);
+ }
}
diff --git a/src/main/java/cz/jzitnik/game/ui/Furnace.java b/src/main/java/cz/jzitnik/game/blocks/Furnace.java
similarity index 94%
rename from src/main/java/cz/jzitnik/game/ui/Furnace.java
rename to src/main/java/cz/jzitnik/game/blocks/Furnace.java
index b218fe5..8d941be 100644
--- a/src/main/java/cz/jzitnik/game/ui/Furnace.java
+++ b/src/main/java/cz/jzitnik/game/blocks/Furnace.java
@@ -1,10 +1,14 @@
-package cz.jzitnik.game.ui;
+package cz.jzitnik.game.blocks;
-import cz.jzitnik.game.Block;
+import cz.jzitnik.game.annotations.RightClickLogic;
+import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.Game;
-import cz.jzitnik.game.items.InventoryItem;
-import cz.jzitnik.game.items.Item;
+import cz.jzitnik.game.entities.items.InventoryItem;
+import cz.jzitnik.game.entities.items.Item;
+import cz.jzitnik.game.handlers.rightclick.RightClickHandler;
import cz.jzitnik.game.smelting.Smelting;
+import cz.jzitnik.game.ui.InventoryClickHandler;
+import cz.jzitnik.game.ui.Window;
import cz.jzitnik.tui.ScreenRenderer;
import cz.jzitnik.tui.SpriteList;
import cz.jzitnik.tui.utils.Numbers;
@@ -15,7 +19,8 @@ import org.jline.terminal.Terminal;
import java.util.List;
import java.util.Optional;
-public class Furnace {
+@RightClickLogic
+public class Furnace implements RightClickHandler {
private final Block block;
private final InventoryItem[] items = new InventoryItem[2];
private InventoryItem outputItem;
@@ -254,4 +259,9 @@ public class Furnace {
setSmelting(false);
}
+
+ @Override
+ public void onBlockRightClick(int ignored, int ignored2, Game game, ScreenRenderer ignored3) {
+ game.setWindow(Window.FURNACE);
+ }
}
diff --git a/src/main/java/cz/jzitnik/game/blocks/OakDoorData.java b/src/main/java/cz/jzitnik/game/blocks/OakDoorData.java
new file mode 100644
index 0000000..d9683d5
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/blocks/OakDoorData.java
@@ -0,0 +1,51 @@
+package cz.jzitnik.game.blocks;
+
+import cz.jzitnik.game.Game;
+import cz.jzitnik.game.annotations.RightClickLogic;
+import cz.jzitnik.game.entities.Block;
+import cz.jzitnik.game.handlers.rightclick.RightClickHandler;
+import cz.jzitnik.game.sprites.OakDoor;
+
+import cz.jzitnik.tui.ScreenRenderer;
+
+@RightClickLogic
+public class OakDoorData implements RightClickHandler {
+ private void change(Block door) {
+ door.setSpriteState(switch (door.getSpriteState().get()) {
+ case OakDoor.OakDoorState.TOP -> OakDoor.OakDoorState.TOPCLOSED;
+ case OakDoor.OakDoorState.BOTTOM -> OakDoor.OakDoorState.BOTTOMCLOSED;
+ case OakDoor.OakDoorState.TOPCLOSED -> OakDoor.OakDoorState.TOP;
+ case OakDoor.OakDoorState.BOTTOMCLOSED -> OakDoor.OakDoorState.BOTTOM;
+ default -> throw new IllegalStateException("Unexpected value: " + door.getSpriteState().get());
+ });
+
+ door.setGhost(switch (door.getSpriteState().get()) {
+ case OakDoor.OakDoorState.TOP, OakDoor.OakDoorState.BOTTOM -> true;
+ case OakDoor.OakDoorState.TOPCLOSED, OakDoor.OakDoorState.BOTTOMCLOSED -> false;
+ default -> throw new IllegalStateException("Unexpected value: " + door.getSpriteState().get());
+ });
+ }
+
+ public void onBlockRightClick(int x, int y, Game game, ScreenRenderer screenRenderer) {
+ var blocks = game.getWorld()[y][x];
+ var door = blocks.stream().filter(block -> block.getBlockId().equals("oak_door")).toList().getFirst();
+
+
+ switch (door.getSpriteState().get()) {
+ case OakDoor.OakDoorState.TOP, OakDoor.OakDoorState.TOPCLOSED -> {
+ var blocks2 = game.getWorld()[y+1][x];
+ var door2 = blocks2.stream().filter(block -> block.getBlockId().equals("oak_door")).toList().getFirst();
+ change(door2);
+ }
+ case OakDoor.OakDoorState.BOTTOM, OakDoor.OakDoorState.BOTTOMCLOSED -> {
+ var blocks2 = game.getWorld()[y-1][x];
+ var door2 = blocks2.stream().filter(block -> block.getBlockId().equals("oak_door")).toList().getFirst();
+ change(door2);
+ }
+ default -> throw new IllegalStateException("Unexpected value: " + door.getSpriteState().get());
+ }
+
+ change(door);
+ game.update(screenRenderer);
+ }
+}
diff --git a/src/main/java/cz/jzitnik/game/crafting/CraftingRecipe.java b/src/main/java/cz/jzitnik/game/crafting/CraftingRecipe.java
index f74c4ad..39d138f 100644
--- a/src/main/java/cz/jzitnik/game/crafting/CraftingRecipe.java
+++ b/src/main/java/cz/jzitnik/game/crafting/CraftingRecipe.java
@@ -1,6 +1,6 @@
package cz.jzitnik.game.crafting;
-import cz.jzitnik.game.items.InventoryItem;
+import cz.jzitnik.game.entities.items.InventoryItem;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/src/main/java/cz/jzitnik/game/crafting/CraftingRecipeList.java b/src/main/java/cz/jzitnik/game/crafting/CraftingRecipeList.java
index f03a109..6c3c280 100644
--- a/src/main/java/cz/jzitnik/game/crafting/CraftingRecipeList.java
+++ b/src/main/java/cz/jzitnik/game/crafting/CraftingRecipeList.java
@@ -1,7 +1,7 @@
package cz.jzitnik.game.crafting;
-import cz.jzitnik.game.items.InventoryItem;
-import cz.jzitnik.game.items.ItemBlockSupplier;
+import cz.jzitnik.game.entities.items.InventoryItem;
+import cz.jzitnik.game.entities.items.ItemBlockSupplier;
import java.util.*;
diff --git a/src/main/java/cz/jzitnik/game/Block.java b/src/main/java/cz/jzitnik/game/entities/Block.java
similarity index 90%
rename from src/main/java/cz/jzitnik/game/Block.java
rename to src/main/java/cz/jzitnik/game/entities/Block.java
index 713f5ba..e655840 100644
--- a/src/main/java/cz/jzitnik/game/Block.java
+++ b/src/main/java/cz/jzitnik/game/entities/Block.java
@@ -1,8 +1,9 @@
-package cz.jzitnik.game;
+package cz.jzitnik.game.entities;
-import cz.jzitnik.game.items.Item;
-import cz.jzitnik.game.items.ItemType;
-import cz.jzitnik.game.items.ToolVariant;
+import cz.jzitnik.game.SpriteLoader;
+import cz.jzitnik.game.entities.items.Item;
+import cz.jzitnik.game.entities.items.ItemType;
+import cz.jzitnik.game.entities.items.ToolVariant;
import cz.jzitnik.game.ui.Inventory;
import lombok.Getter;
import lombok.Setter;
@@ -24,6 +25,7 @@ public class Block {
private List toolVariants = new ArrayList<>();
private List- drops = new ArrayList<>();
private Object data = null;
+ private boolean isMob = false;
public Block(String blockId, SpriteLoader.SPRITES sprite) {
this.blockId = blockId;
diff --git a/src/main/java/cz/jzitnik/game/Dependencies.java b/src/main/java/cz/jzitnik/game/entities/Dependencies.java
similarity index 80%
rename from src/main/java/cz/jzitnik/game/Dependencies.java
rename to src/main/java/cz/jzitnik/game/entities/Dependencies.java
index 62e6837..c0a34ad 100644
--- a/src/main/java/cz/jzitnik/game/Dependencies.java
+++ b/src/main/java/cz/jzitnik/game/entities/Dependencies.java
@@ -1,4 +1,4 @@
-package cz.jzitnik.game;
+package cz.jzitnik.game.entities;
import cz.jzitnik.game.handlers.place.PlaceHandler;
diff --git a/src/main/java/cz/jzitnik/game/GameStates.java b/src/main/java/cz/jzitnik/game/entities/GameStates.java
similarity index 84%
rename from src/main/java/cz/jzitnik/game/GameStates.java
rename to src/main/java/cz/jzitnik/game/entities/GameStates.java
index b10d2b1..c3367da 100644
--- a/src/main/java/cz/jzitnik/game/GameStates.java
+++ b/src/main/java/cz/jzitnik/game/entities/GameStates.java
@@ -1,5 +1,6 @@
-package cz.jzitnik.game;
+package cz.jzitnik.game.entities;
+import cz.jzitnik.game.Game;
import cz.jzitnik.game.ui.CraftingTable;
public class GameStates {
diff --git a/src/main/java/cz/jzitnik/game/Player.java b/src/main/java/cz/jzitnik/game/entities/Player.java
similarity index 95%
rename from src/main/java/cz/jzitnik/game/Player.java
rename to src/main/java/cz/jzitnik/game/entities/Player.java
index 7958b95..5a61710 100644
--- a/src/main/java/cz/jzitnik/game/Player.java
+++ b/src/main/java/cz/jzitnik/game/entities/Player.java
@@ -1,4 +1,4 @@
-package cz.jzitnik.game;
+package cz.jzitnik.game.entities;
import lombok.Getter;
import lombok.Setter;
diff --git a/src/main/java/cz/jzitnik/game/items/InventoryItem.java b/src/main/java/cz/jzitnik/game/entities/items/InventoryItem.java
similarity index 95%
rename from src/main/java/cz/jzitnik/game/items/InventoryItem.java
rename to src/main/java/cz/jzitnik/game/entities/items/InventoryItem.java
index 80fe605..44d59fa 100644
--- a/src/main/java/cz/jzitnik/game/items/InventoryItem.java
+++ b/src/main/java/cz/jzitnik/game/entities/items/InventoryItem.java
@@ -1,4 +1,4 @@
-package cz.jzitnik.game.items;
+package cz.jzitnik.game.entities.items;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/src/main/java/cz/jzitnik/game/items/Item.java b/src/main/java/cz/jzitnik/game/entities/items/Item.java
similarity index 95%
rename from src/main/java/cz/jzitnik/game/items/Item.java
rename to src/main/java/cz/jzitnik/game/entities/items/Item.java
index 8cb9834..9fe1f50 100644
--- a/src/main/java/cz/jzitnik/game/items/Item.java
+++ b/src/main/java/cz/jzitnik/game/entities/items/Item.java
@@ -1,6 +1,6 @@
-package cz.jzitnik.game.items;
+package cz.jzitnik.game.entities.items;
-import cz.jzitnik.game.Block;
+import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.SpriteLoader;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/src/main/java/cz/jzitnik/game/items/ItemBlockSupplier.java b/src/main/java/cz/jzitnik/game/entities/items/ItemBlockSupplier.java
similarity index 91%
rename from src/main/java/cz/jzitnik/game/items/ItemBlockSupplier.java
rename to src/main/java/cz/jzitnik/game/entities/items/ItemBlockSupplier.java
index b03aa33..6f82d46 100644
--- a/src/main/java/cz/jzitnik/game/items/ItemBlockSupplier.java
+++ b/src/main/java/cz/jzitnik/game/entities/items/ItemBlockSupplier.java
@@ -1,9 +1,11 @@
-package cz.jzitnik.game.items;
+package cz.jzitnik.game.entities.items;
import cz.jzitnik.game.SpriteLoader;
-import cz.jzitnik.game.Block;
-import cz.jzitnik.game.ui.Chest;
-import cz.jzitnik.game.ui.Furnace;
+import cz.jzitnik.game.blocks.OakDoorData;
+import cz.jzitnik.game.entities.Block;
+import cz.jzitnik.game.blocks.Chest;
+import cz.jzitnik.game.blocks.Furnace;
+import cz.jzitnik.game.mobs.services.pig.PigData;
import java.util.ArrayList;
import java.util.Arrays;
@@ -93,6 +95,7 @@ public class ItemBlockSupplier {
}
public static Block oakDoor() {
var block = new Block("oak_door", SpriteLoader.SPRITES.OAK_DOOR, 3, ItemType.AXE, new ArrayList<>());
+ block.setData(new OakDoorData());
block.setDrops(List.of(Helper.oakDoor(block)));
return block;
}
@@ -146,4 +149,16 @@ public class ItemBlockSupplier {
return Helper.oakDoor(Blocks.oakDoor());
}
}
+
+ public static class Mobs {
+ public static Block pig() {
+ // Yes, pig is a block. Cry about it.
+ var block = new Block("pig", SpriteLoader.SPRITES.PIG);
+ block.setMob(true);
+ block.setGhost(true);
+ block.setMineable(false);
+ block.setData(new PigData());
+ return block;
+ }
+ }
}
diff --git a/src/main/java/cz/jzitnik/game/items/ItemType.java b/src/main/java/cz/jzitnik/game/entities/items/ItemType.java
similarity index 71%
rename from src/main/java/cz/jzitnik/game/items/ItemType.java
rename to src/main/java/cz/jzitnik/game/entities/items/ItemType.java
index 007de75..d8cde61 100644
--- a/src/main/java/cz/jzitnik/game/items/ItemType.java
+++ b/src/main/java/cz/jzitnik/game/entities/items/ItemType.java
@@ -1,4 +1,4 @@
-package cz.jzitnik.game.items;
+package cz.jzitnik.game.entities.items;
public enum ItemType {
PICKAXE,
diff --git a/src/main/java/cz/jzitnik/game/items/ToolVariant.java b/src/main/java/cz/jzitnik/game/entities/items/ToolVariant.java
similarity index 60%
rename from src/main/java/cz/jzitnik/game/items/ToolVariant.java
rename to src/main/java/cz/jzitnik/game/entities/items/ToolVariant.java
index 8ee5c8b..6a9edf7 100644
--- a/src/main/java/cz/jzitnik/game/items/ToolVariant.java
+++ b/src/main/java/cz/jzitnik/game/entities/items/ToolVariant.java
@@ -1,4 +1,4 @@
-package cz.jzitnik.game.items;
+package cz.jzitnik.game.entities.items;
public enum ToolVariant {
WOODEN,
diff --git a/src/main/java/cz/jzitnik/game/generation/CaveGenerator.java b/src/main/java/cz/jzitnik/game/generation/CaveGenerator.java
deleted file mode 100644
index a27c98f..0000000
--- a/src/main/java/cz/jzitnik/game/generation/CaveGenerator.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package cz.jzitnik.game.generation;
-
-import cz.jzitnik.game.Block;
-import java.util.List;
-
-public class CaveGenerator {
- private static final int WIDTH = 512;
- private static final int HEIGHT = 256;
-
- public static void generateCaves(List[][] world, int[] terrainHeight) {
- }
-}
diff --git a/src/main/java/cz/jzitnik/game/generation/Generation.java b/src/main/java/cz/jzitnik/game/generation/Generation.java
index 7798e79..965b77a 100644
--- a/src/main/java/cz/jzitnik/game/generation/Generation.java
+++ b/src/main/java/cz/jzitnik/game/generation/Generation.java
@@ -1,10 +1,10 @@
package cz.jzitnik.game.generation;
-import cz.jzitnik.game.Block;
+import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.SpriteLoader;
-import cz.jzitnik.game.items.ItemBlockSupplier;
-import cz.jzitnik.game.items.ItemType;
+import cz.jzitnik.game.entities.items.ItemBlockSupplier;
+import cz.jzitnik.game.entities.items.ItemType;
import cz.jzitnik.game.sprites.Steve;
import java.util.ArrayList;
@@ -18,13 +18,16 @@ public class Generation {
Block steveBlock = new Block("steve", SpriteLoader.SPRITES.STEVE);
steveBlock.setSpriteState(Steve.SteveState.FIRST);
+ steveBlock.setGhost(true);
Block steveBlock2 = new Block("steve", SpriteLoader.SPRITES.STEVE);
steveBlock2.setSpriteState(Steve.SteveState.SECOND);
+ steveBlock2.setGhost(true);
+
+ int[] terrainHeight = generateTerrain();
game.getPlayer().setPlayerBlock1(steveBlock);
game.getPlayer().setPlayerBlock2(steveBlock2);
- int[] terrainHeight = generateTerrain();
populateWorld(world, terrainHeight);
plantTrees(world, terrainHeight);
diff --git a/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java b/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java
index 6c5d650..88db7d9 100644
--- a/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java
+++ b/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java
@@ -3,7 +3,6 @@ package cz.jzitnik.game.handlers.place;
import java.util.HashMap;
import java.util.Set;
-import cz.jzitnik.game.annotations.RegisterPlaceHandler;
import org.reflections.Reflections;
public class PlaceHandler {
@@ -28,13 +27,13 @@ public class PlaceHandler {
private void registerHandlers() {
Reflections reflections = new Reflections("cz.jzitnik.game.handlers.place.handlers");
- Set> handlerClasses = reflections.getTypesAnnotatedWith(RegisterPlaceHandler.class);
+ Set> handlerClasses = reflections.getTypesAnnotatedWith(cz.jzitnik.game.annotations.PlaceHandler.class);
for (Class> clazz : handlerClasses) {
if (CustomPlaceHandler.class.isAssignableFrom(clazz)) {
try {
CustomPlaceHandler handlerInstance = (CustomPlaceHandler) clazz.getDeclaredConstructor().newInstance();
- RegisterPlaceHandler annotation = clazz.getAnnotation(RegisterPlaceHandler.class);
+ cz.jzitnik.game.annotations.PlaceHandler annotation = clazz.getAnnotation(cz.jzitnik.game.annotations.PlaceHandler.class);
placeHandlerList.put(annotation.value(), handlerInstance);
} catch (Exception e) {
e.printStackTrace();
diff --git a/src/main/java/cz/jzitnik/game/handlers/place/handlers/DoorPlaceHandler.java b/src/main/java/cz/jzitnik/game/handlers/place/handlers/DoorPlaceHandler.java
index cd1672a..298ac8c 100644
--- a/src/main/java/cz/jzitnik/game/handlers/place/handlers/DoorPlaceHandler.java
+++ b/src/main/java/cz/jzitnik/game/handlers/place/handlers/DoorPlaceHandler.java
@@ -1,54 +1,14 @@
package cz.jzitnik.game.handlers.place.handlers;
-import cz.jzitnik.game.Block;
+import cz.jzitnik.game.annotations.PlaceHandler;
+import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.Game;
-import cz.jzitnik.game.annotations.RegisterPlaceHandler;
import cz.jzitnik.game.handlers.place.CustomPlaceHandler;
-import cz.jzitnik.game.items.ItemBlockSupplier;
+import cz.jzitnik.game.entities.items.ItemBlockSupplier;
import cz.jzitnik.game.sprites.OakDoor;
-import cz.jzitnik.tui.ScreenRenderer;
-@RegisterPlaceHandler("oak_door")
+@PlaceHandler("oak_door")
public class DoorPlaceHandler implements CustomPlaceHandler {
- public static void rightClick(Game game, int x, int y, ScreenRenderer screenRenderer) {
- var blocks = game.getWorld()[y][x];
- var door = blocks.stream().filter(block -> block.getBlockId().equals("oak_door")).toList().getFirst();
-
-
- switch (door.getSpriteState().get()) {
- case OakDoor.OakDoorState.TOP, OakDoor.OakDoorState.TOPCLOSED -> {
- var blocks2 = game.getWorld()[y+1][x];
- var door2 = blocks2.stream().filter(block -> block.getBlockId().equals("oak_door")).toList().getFirst();
- change(door2);
- }
- case OakDoor.OakDoorState.BOTTOM, OakDoor.OakDoorState.BOTTOMCLOSED -> {
- var blocks2 = game.getWorld()[y-1][x];
- var door2 = blocks2.stream().filter(block -> block.getBlockId().equals("oak_door")).toList().getFirst();
- change(door2);
- }
- default -> throw new IllegalStateException("Unexpected value: " + door.getSpriteState().get());
- }
-
- change(door);
- game.update(screenRenderer);
- }
-
- private static void change(Block door) {
- door.setSpriteState(switch (door.getSpriteState().get()) {
- case OakDoor.OakDoorState.TOP -> OakDoor.OakDoorState.TOPCLOSED;
- case OakDoor.OakDoorState.BOTTOM -> OakDoor.OakDoorState.BOTTOMCLOSED;
- case OakDoor.OakDoorState.TOPCLOSED -> OakDoor.OakDoorState.TOP;
- case OakDoor.OakDoorState.BOTTOMCLOSED -> OakDoor.OakDoorState.BOTTOM;
- default -> throw new IllegalStateException("Unexpected value: " + door.getSpriteState().get());
- });
-
- door.setGhost(switch (door.getSpriteState().get()) {
- case OakDoor.OakDoorState.TOP, OakDoor.OakDoorState.BOTTOM -> true;
- case OakDoor.OakDoorState.TOPCLOSED, OakDoor.OakDoorState.BOTTOMCLOSED -> false;
- default -> throw new IllegalStateException("Unexpected value: " + door.getSpriteState().get());
- });
- }
-
@Override
public boolean place(Game game, int x, int y) {
var blocks = game.getWorld()[y][x];
diff --git a/src/main/java/cz/jzitnik/game/handlers/rightclick/RightClickHandler.java b/src/main/java/cz/jzitnik/game/handlers/rightclick/RightClickHandler.java
index 557f722..8769690 100644
--- a/src/main/java/cz/jzitnik/game/handlers/rightclick/RightClickHandler.java
+++ b/src/main/java/cz/jzitnik/game/handlers/rightclick/RightClickHandler.java
@@ -1,40 +1,8 @@
package cz.jzitnik.game.handlers.rightclick;
-import cz.jzitnik.game.Block;
import cz.jzitnik.game.Game;
-import cz.jzitnik.game.handlers.place.handlers.DoorPlaceHandler;
-import cz.jzitnik.game.ui.Window;
import cz.jzitnik.tui.ScreenRenderer;
-import java.util.HashMap;
-
-public class RightClickHandler {
- @FunctionalInterface
- public interface Function3 {
- void apply(T t, U u);
- }
-
- public static void handle(int x, int y, Game game, ScreenRenderer screenRenderer) {
- if (game.isMining()) {
- return;
- }
-
- HashMap> functionMap = new HashMap<>();
- functionMap.put("crafting_table", game.getGameStates().craftingTable::render);
- functionMap.put("chest", (Integer ignored, Integer ignored2) -> game.setWindow(Window.CHEST));
- functionMap.put("furnace", (Integer ignored, Integer ignored2) -> game.setWindow(Window.FURNACE));
- functionMap.put("oak_door", (Integer xx, Integer xy) -> DoorPlaceHandler.rightClick(game, xx, xy, screenRenderer));
-
- game.getGameStates().clickX = x;
- game.getGameStates().clickY = y;
-
- var blocks = game.getWorld()[y][x];
- for (Block block : blocks) {
- if (functionMap.containsKey(block.getBlockId())) {
- functionMap.get(block.getBlockId()).apply(x, y);
-
- return;
- }
- }
- }
+public interface RightClickHandler {
+ void onBlockRightClick(int x, int y, Game game, ScreenRenderer screenRenderer);
}
diff --git a/src/main/java/cz/jzitnik/game/handlers/rightclick/RightClickHandlerProvider.java b/src/main/java/cz/jzitnik/game/handlers/rightclick/RightClickHandlerProvider.java
new file mode 100644
index 0000000..2fe0f55
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/handlers/rightclick/RightClickHandlerProvider.java
@@ -0,0 +1,29 @@
+package cz.jzitnik.game.handlers.rightclick;
+
+import cz.jzitnik.game.annotations.RightClickLogic;
+import cz.jzitnik.game.entities.Block;
+import cz.jzitnik.game.Game;
+import cz.jzitnik.tui.ScreenRenderer;
+
+public class RightClickHandlerProvider {
+ public static void handle(int x, int y, Game game, ScreenRenderer screenRenderer) {
+ if (game.isMining()) {
+ return;
+ }
+
+ game.getGameStates().clickX = x;
+ game.getGameStates().clickY = y;
+
+ var blocks = game.getWorld()[y][x];
+ for (Block block : blocks) {
+ if (block.getBlockId().equalsIgnoreCase("crafting_table")) {
+ game.getGameStates().craftingTable.render(x, y);
+ continue;
+ }
+
+ if (block.getData() != null && block.getData().getClass().isAnnotationPresent(RightClickLogic.class) && block.getData() instanceof RightClickHandler handlerClass) {
+ handlerClass.onBlockRightClick(x, y, game, screenRenderer);
+ }
+ }
+ }
+}
diff --git a/src/main/java/cz/jzitnik/game/mobs/EntityLogicInterface.java b/src/main/java/cz/jzitnik/game/mobs/EntityLogicInterface.java
new file mode 100644
index 0000000..2ee5597
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/mobs/EntityLogicInterface.java
@@ -0,0 +1,5 @@
+package cz.jzitnik.game.mobs;
+
+public interface EntityLogicInterface {
+ void nextIteration(EntityLogicProvider.EntityLogicMobDTO entityLogicMobDTO);
+}
diff --git a/src/main/java/cz/jzitnik/game/mobs/EntityLogicProvider.java b/src/main/java/cz/jzitnik/game/mobs/EntityLogicProvider.java
new file mode 100644
index 0000000..3c334cc
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/mobs/EntityLogicProvider.java
@@ -0,0 +1,82 @@
+package cz.jzitnik.game.mobs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+import cz.jzitnik.game.Game;
+import cz.jzitnik.game.annotations.EntityLogic;
+import cz.jzitnik.game.entities.Block;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.reflections.Reflections;
+
+public class EntityLogicProvider {
+ private static final int CHUNK_SIZE = 20;
+ private final HashMap logicList = new HashMap<>();
+
+ @AllArgsConstructor
+ @Getter
+ public static class EntityLogicMobDTO {
+ private Game game;
+ private Block mob;
+ private int x;
+ private int y;
+ }
+
+ public void update(Game game) {
+ int[] playerLocation = game.getPlayerCords();
+ int playerX = playerLocation[0];
+ int playerY = playerLocation[1];
+
+ int startX = Math.max(0, playerX - CHUNK_SIZE);
+ int startY = Math.max(0, playerY - CHUNK_SIZE);
+ int endX = Math.min(game.getWorld()[0].length, playerX + CHUNK_SIZE);
+ int endY = Math.min(game.getWorld().length, playerY + CHUNK_SIZE);
+
+ List mobs = new ArrayList<>();
+
+ for (int y = startY; y <= endY; y++) {
+ for (int x = startX; x <= endX; x++) {
+ int finalX = x;
+ int finalY = y;
+ List blockMobs = game.getWorld()[y][x].stream().filter(Block::isMob).map(mob -> new EntityLogicMobDTO(game, mob, finalX, finalY)).toList();
+ mobs.addAll(blockMobs);
+ }
+ }
+
+ for (EntityLogicMobDTO entityLogicMobDTO : mobs) {
+ run(entityLogicMobDTO);
+ }
+ }
+
+ private void run(EntityLogicMobDTO entityLogicMobDTO) {
+ if (!logicList.containsKey(entityLogicMobDTO.getMob().getBlockId())) {
+ return;
+ }
+
+ logicList.get(entityLogicMobDTO.getMob().getBlockId()).nextIteration(entityLogicMobDTO);
+ }
+
+ public EntityLogicProvider() {
+ registerHandlers();
+ }
+
+ private void registerHandlers() {
+ Reflections reflections = new Reflections("cz.jzitnik.game.mobs.services");
+ Set> handlerClasses = reflections.getTypesAnnotatedWith(EntityLogic.class);
+
+ for (Class> clazz : handlerClasses) {
+ if (EntityLogicInterface.class.isAssignableFrom(clazz)) {
+ try {
+ EntityLogicInterface instance = (EntityLogicInterface) clazz.getDeclaredConstructor().newInstance();
+ EntityLogic annotation = clazz.getAnnotation(EntityLogic.class);
+ logicList.put(annotation.value(), instance);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/cz/jzitnik/game/mobs/EntitySpawnInterface.java b/src/main/java/cz/jzitnik/game/mobs/EntitySpawnInterface.java
new file mode 100644
index 0000000..0b6b003
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/mobs/EntitySpawnInterface.java
@@ -0,0 +1,8 @@
+package cz.jzitnik.game.mobs;
+
+import cz.jzitnik.game.Game;
+import org.jline.terminal.Terminal;
+
+public interface EntitySpawnInterface {
+ void spawn(int playerX, int playerY, Game game, Terminal terminal);
+}
diff --git a/src/main/java/cz/jzitnik/game/mobs/EntitySpawnProvider.java b/src/main/java/cz/jzitnik/game/mobs/EntitySpawnProvider.java
new file mode 100644
index 0000000..9b00369
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/mobs/EntitySpawnProvider.java
@@ -0,0 +1,57 @@
+package cz.jzitnik.game.mobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import cz.jzitnik.game.Game;
+import cz.jzitnik.game.annotations.EntitySpawn;
+import cz.jzitnik.game.entities.Block;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.jline.terminal.Terminal;
+import org.reflections.Reflections;
+
+public class EntitySpawnProvider {
+ private final List spawnList = new ArrayList<>();
+
+ @AllArgsConstructor
+ @Getter
+ public static class EntityLogicMobDTO {
+ private Game game;
+ private Block mob;
+ private int x;
+ private int y;
+ }
+
+ public void update(Game game, Terminal terminal) {
+ int[] playerLocation = game.getPlayerCords();
+ int playerX = playerLocation[0];
+ int playerY = playerLocation[1];
+
+ for (EntitySpawnInterface entitySpawnInterface: spawnList) {
+
+ entitySpawnInterface.spawn(playerX, playerY, game, terminal);
+ }
+ }
+
+ public EntitySpawnProvider() {
+ registerHandlers();
+ }
+
+ private void registerHandlers() {
+ Reflections reflections = new Reflections("cz.jzitnik.game.mobs.services");
+ Set> handlerClasses = reflections.getTypesAnnotatedWith(EntitySpawn.class);
+
+ for (Class> clazz : handlerClasses) {
+ if (EntitySpawnInterface.class.isAssignableFrom(clazz)) {
+ try {
+ EntitySpawnInterface instance = (EntitySpawnInterface) clazz.getDeclaredConstructor().newInstance();
+ spawnList.add(instance);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/cz/jzitnik/game/mobs/services/pig/PigData.java b/src/main/java/cz/jzitnik/game/mobs/services/pig/PigData.java
new file mode 100644
index 0000000..8f95ab7
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/mobs/services/pig/PigData.java
@@ -0,0 +1,12 @@
+package cz.jzitnik.game.mobs.services.pig;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class PigData {
+ private int lastDirection = 1; // 1 = right, -1 = left
+ private int movementCooldown = 0;
+ private int jumpAttempts = 0;
+}
diff --git a/src/main/java/cz/jzitnik/game/mobs/services/pig/PigLogic.java b/src/main/java/cz/jzitnik/game/mobs/services/pig/PigLogic.java
new file mode 100644
index 0000000..4eaf70e
--- /dev/null
+++ b/src/main/java/cz/jzitnik/game/mobs/services/pig/PigLogic.java
@@ -0,0 +1,177 @@
+package cz.jzitnik.game.mobs.services.pig;
+
+import cz.jzitnik.game.Game;
+import cz.jzitnik.game.annotations.EntityLogic;
+import cz.jzitnik.game.annotations.EntitySpawn;
+import cz.jzitnik.game.entities.Block;
+import cz.jzitnik.game.entities.items.ItemBlockSupplier;
+import cz.jzitnik.game.mobs.EntityLogicInterface;
+import cz.jzitnik.game.mobs.EntityLogicProvider;
+import cz.jzitnik.game.mobs.EntitySpawnInterface;
+import cz.jzitnik.game.sprites.Pig;
+import cz.jzitnik.tui.ScreenMovingCalculationProvider;
+import org.jline.terminal.Terminal;
+
+import java.util.*;
+
+@EntitySpawn
+@EntityLogic("pig")
+public class PigLogic implements EntityLogicInterface, EntitySpawnInterface {
+ private final Random random = new Random();
+
+ @Override
+ public void nextIteration(EntityLogicProvider.EntityLogicMobDTO entityLogicMobDTO) {
+ int pigX = entityLogicMobDTO.getX();
+ int pigY = entityLogicMobDTO.getY();
+ var game = entityLogicMobDTO.getGame();
+ var pig = entityLogicMobDTO.getMob();
+ var world = game.getWorld();
+ var pigData = (PigData) pig.getData();
+
+ boolean updated = false;
+ int newPigX = pigX;
+ int newPigY = pigY;
+
+ // Reduce movement cooldown
+ if (pigData.getMovementCooldown() > 0) {
+ pigData.setMovementCooldown(pigData.getMovementCooldown() - 1);
+ return; // Skip movement this iteration
+ }
+
+ // Determine movement direction
+ int direction = pigData.getLastDirection();
+ if (random.nextInt(10) < 3) { // 30% chance to change direction
+ direction = -direction;
+ }
+ pigData.setLastDirection(direction);
+
+ // Update sprite direction
+ if (direction == 1) {
+ pig.setSpriteState(Pig.PigState.RIGHT);
+ } else {
+ pig.setSpriteState(Pig.PigState.LEFT);
+ }
+
+ List blocksAhead = world[pigY][pigX + direction];
+ if (!game.isSolid(blocksAhead)) {
+ world[pigY][pigX].remove(pig);
+ world[pigY][pigX + direction].add(pig);
+ newPigX = pigX + direction;
+ updated = true;
+ pigData.setJumpAttempts(0); // Reset jump attempts when moving forward
+ } else {
+ List blocksAboveAhead = world[pigY - 1][pigX + direction];
+ List blocksTwoAboveAhead = world[pigY - 2][pigX + direction];
+
+ // Jump if there is only one block height obstacle and limit jump attempts
+ if (!game.isSolid(blocksAboveAhead) && game.isSolid(blocksAhead) && !game.isSolid(blocksTwoAboveAhead)) {
+ if (pigData.getJumpAttempts() < 2) { // Limit jumping attempts to prevent infinite jumping
+ world[pigY][pigX].remove(pig);
+ world[pigY - 1][pigX + direction].add(pig);
+ newPigX = pigX + direction;
+ newPigY = pigY - 1;
+ updated = true;
+ pigData.setJumpAttempts(pigData.getJumpAttempts() + 1);
+ }
+ }
+ }
+
+ // Falling logic (avoid long falls)
+ while (updated) {
+ if (!game.isSolid(world[newPigY + 1][newPigX])) {
+ if (newPigY - pigY < 3) { // Only fall if it's at most 2 blocks drop
+ world[newPigY][newPigX].remove(pig);
+ world[newPigY + 1][newPigX].add(pig);
+ newPigY++;
+ } else {
+ updated = false;
+ }
+ } else {
+ updated = false;
+ }
+ }
+
+ // Apply movement cooldown to slow down movement
+ pigData.setMovementCooldown(random.nextInt(3) + 1); // 1-3 iterations cooldown
+ }
+
+ @Override
+ public void spawn(int playerX, int playerY, Game game, Terminal terminal) {
+ // Cordinates where player can see
+ int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);
+ var world = game.getWorld();
+ int startX = data[0];
+ int endX = data[1];
+
+ // Left side
+ int lstartX = startX - 20;
+ int lendX = startX - 5;
+ int lstartY = playerY - 15;
+ int lendY = playerY + 15;
+
+ if (countPrasata(lstartX, lendX, lstartY, lendY, game) < 3 && random.nextInt(100) < 2) {
+ var spawnLocations = pigCanSpawn(lstartX, lendX, playerY, game);
+ if (!spawnLocations.isEmpty()) {
+ System.out.println(spawnLocations.size());
+ for (int i = 0; i < Math.min(4, spawnLocations.size()); i++) {
+ var randomLocation = getRandomEntry(spawnLocations);
+ int x = randomLocation.getKey();
+ int y = randomLocation.getValue();
+
+ world[y][x].add(ItemBlockSupplier.Mobs.pig());
+ }
+ }
+ }
+
+ // Right side
+ int rstartX = endX + 5;
+ int rendX = endX + 20;
+ int rstartY = playerY - 15;
+ int rendY = playerY + 15;
+
+ if (countPrasata(rstartX, rendX, rstartY, rendY, game) < 3 && random.nextInt(100) < 2) {
+ var spawnLocations = pigCanSpawn(rstartX, rendX, playerY, game);
+ if (!spawnLocations.isEmpty()) {
+ System.out.println(spawnLocations.size());
+ for (int i = 0; i < Math.min(4, spawnLocations.size()); i++) {
+ var randomLocation = getRandomEntry(spawnLocations);
+ int x = randomLocation.getKey();
+ int y = randomLocation.getValue();
+
+ world[y][x].add(ItemBlockSupplier.Mobs.pig());
+ }
+ }
+ }
+ }
+
+ public static Map.Entry getRandomEntry(HashMap map) {
+ List> entryList = new ArrayList<>(map.entrySet());
+ Random random = new Random();
+ return entryList.get(random.nextInt(entryList.size()));
+ }
+
+ private HashMap pigCanSpawn(int startX, int endX, int playerY, Game game) {
+ var map = new HashMap();
+ var world = game.getWorld();
+ for (int x = startX; x <= endX; x++) {
+ for (int y = Math.max(0, playerY - 30); y < Math.min(world.length, playerY + 30); y++) {
+ if (world[y][x].stream().anyMatch(i -> i.getBlockId().equals("grass"))) {
+ map.put(x, y - 1);
+ }
+ }
+ }
+
+ return map;
+ }
+
+ private long countPrasata(int startX, int endX, int startY, int endY, Game game) {
+ long pigAmount = 0;
+ for (int y = startY; y <= endY; y++) {
+ for (int x = startX; x <= endX; x++) {
+ pigAmount += game.getWorld()[y][x].stream().filter(i -> i.getBlockId().equals("pig")).count();
+ }
+ }
+
+ return pigAmount;
+ }
+}
diff --git a/src/main/java/cz/jzitnik/game/smelting/Smelting.java b/src/main/java/cz/jzitnik/game/smelting/Smelting.java
index 8aac464..2f06f63 100644
--- a/src/main/java/cz/jzitnik/game/smelting/Smelting.java
+++ b/src/main/java/cz/jzitnik/game/smelting/Smelting.java
@@ -1,7 +1,7 @@
package cz.jzitnik.game.smelting;
-import cz.jzitnik.game.items.Item;
-import cz.jzitnik.game.items.ItemBlockSupplier;
+import cz.jzitnik.game.entities.items.Item;
+import cz.jzitnik.game.entities.items.ItemBlockSupplier;
import java.util.HashMap;
import java.util.function.Supplier;
diff --git a/src/main/java/cz/jzitnik/game/threads/HealthRegenerationThread.java b/src/main/java/cz/jzitnik/game/threads/HealthRegenerationThread.java
index 0a9bded..451b523 100644
--- a/src/main/java/cz/jzitnik/game/threads/HealthRegenerationThread.java
+++ b/src/main/java/cz/jzitnik/game/threads/HealthRegenerationThread.java
@@ -1,6 +1,6 @@
package cz.jzitnik.game.threads;
-import cz.jzitnik.game.Player;
+import cz.jzitnik.game.entities.Player;
import lombok.AllArgsConstructor;
@AllArgsConstructor
diff --git a/src/main/java/cz/jzitnik/game/threads/HungerDrainThread.java b/src/main/java/cz/jzitnik/game/threads/HungerDrainThread.java
index dc0bc11..397f44a 100644
--- a/src/main/java/cz/jzitnik/game/threads/HungerDrainThread.java
+++ b/src/main/java/cz/jzitnik/game/threads/HungerDrainThread.java
@@ -1,6 +1,6 @@
package cz.jzitnik.game.threads;
-import cz.jzitnik.game.Player;
+import cz.jzitnik.game.entities.Player;
import lombok.AllArgsConstructor;
@AllArgsConstructor
diff --git a/src/main/java/cz/jzitnik/game/threads/InputHandlerThread.java b/src/main/java/cz/jzitnik/game/threads/InputHandlerThread.java
index d5f1e96..e077c83 100644
--- a/src/main/java/cz/jzitnik/game/threads/InputHandlerThread.java
+++ b/src/main/java/cz/jzitnik/game/threads/InputHandlerThread.java
@@ -1,6 +1,8 @@
package cz.jzitnik.game.threads;
import cz.jzitnik.game.Game;
+import cz.jzitnik.game.blocks.Chest;
+import cz.jzitnik.game.blocks.Furnace;
import cz.jzitnik.game.ui.*;
import cz.jzitnik.tui.MouseHandler;
import cz.jzitnik.tui.ScreenRenderer;
@@ -54,11 +56,11 @@ public class InputHandlerThread extends Thread {
switch (key) {
case '1', '2', '3', '4', '5', '6', '7', '8', '9' -> game.changeSlot(key - 49, screenRenderer);
case 'a' -> {
- game.movePlayerLeft(screenRenderer);
+ game.movePlayerLeft(screenRenderer, terminal);
screenRenderer.render(game);
}
case 'd' -> {
- game.movePlayerRight(screenRenderer);
+ game.movePlayerRight(screenRenderer, terminal);
screenRenderer.render(game);
}
case ' ' -> {
diff --git a/src/main/java/cz/jzitnik/game/ui/CraftingTable.java b/src/main/java/cz/jzitnik/game/ui/CraftingTable.java
index 09e0179..ce9e6d6 100644
--- a/src/main/java/cz/jzitnik/game/ui/CraftingTable.java
+++ b/src/main/java/cz/jzitnik/game/ui/CraftingTable.java
@@ -3,7 +3,7 @@ package cz.jzitnik.game.ui;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.crafting.CraftingRecipe;
import cz.jzitnik.game.crafting.CraftingRecipeList;
-import cz.jzitnik.game.items.InventoryItem;
+import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.tui.ScreenRenderer;
import cz.jzitnik.tui.utils.SpriteCombiner;
import cz.jzitnik.tui.SpriteList;
diff --git a/src/main/java/cz/jzitnik/game/ui/Inventory.java b/src/main/java/cz/jzitnik/game/ui/Inventory.java
index 76f7477..d33cc45 100644
--- a/src/main/java/cz/jzitnik/game/ui/Inventory.java
+++ b/src/main/java/cz/jzitnik/game/ui/Inventory.java
@@ -1,7 +1,7 @@
package cz.jzitnik.game.ui;
-import cz.jzitnik.game.items.InventoryItem;
-import cz.jzitnik.game.items.Item;
+import cz.jzitnik.game.entities.items.InventoryItem;
+import cz.jzitnik.game.entities.items.Item;
import cz.jzitnik.tui.utils.SpriteCombiner;
import cz.jzitnik.tui.SpriteList;
import cz.jzitnik.tui.utils.Numbers;
diff --git a/src/main/java/cz/jzitnik/game/ui/InventoryClickHandler.java b/src/main/java/cz/jzitnik/game/ui/InventoryClickHandler.java
index 65144a8..2bca08b 100644
--- a/src/main/java/cz/jzitnik/game/ui/InventoryClickHandler.java
+++ b/src/main/java/cz/jzitnik/game/ui/InventoryClickHandler.java
@@ -1,7 +1,7 @@
package cz.jzitnik.game.ui;
import cz.jzitnik.game.Game;
-import cz.jzitnik.game.items.InventoryItem;
+import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.tui.ScreenRenderer;
import org.jline.terminal.MouseEvent;
import org.jline.terminal.Terminal;
diff --git a/src/main/java/cz/jzitnik/game/ui/InventoryDTO.java b/src/main/java/cz/jzitnik/game/ui/InventoryDTO.java
index ca0a335..4f82ce0 100644
--- a/src/main/java/cz/jzitnik/game/ui/InventoryDTO.java
+++ b/src/main/java/cz/jzitnik/game/ui/InventoryDTO.java
@@ -1,6 +1,6 @@
package cz.jzitnik.game.ui;
-import cz.jzitnik.game.items.InventoryItem;
+import cz.jzitnik.game.entities.items.InventoryItem;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/src/main/java/cz/jzitnik/game/ui/SmallCraftingTable.java b/src/main/java/cz/jzitnik/game/ui/SmallCraftingTable.java
index d9d76a1..da321c6 100644
--- a/src/main/java/cz/jzitnik/game/ui/SmallCraftingTable.java
+++ b/src/main/java/cz/jzitnik/game/ui/SmallCraftingTable.java
@@ -2,7 +2,7 @@ package cz.jzitnik.game.ui;
import cz.jzitnik.game.crafting.CraftingRecipe;
import cz.jzitnik.game.crafting.CraftingRecipeList;
-import cz.jzitnik.game.items.InventoryItem;
+import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.tui.utils.SpriteCombiner;
import cz.jzitnik.tui.SpriteList;
import cz.jzitnik.tui.utils.Numbers;
diff --git a/src/main/java/cz/jzitnik/tui/ScreenRenderer.java b/src/main/java/cz/jzitnik/tui/ScreenRenderer.java
index 65942ee..733d2ef 100644
--- a/src/main/java/cz/jzitnik/tui/ScreenRenderer.java
+++ b/src/main/java/cz/jzitnik/tui/ScreenRenderer.java
@@ -1,14 +1,13 @@
package cz.jzitnik.tui;
-import cz.jzitnik.game.Block;
+import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.sprites.Steve;
-import cz.jzitnik.game.ui.Chest;
-import cz.jzitnik.game.ui.Furnace;
+import cz.jzitnik.game.blocks.Chest;
+import cz.jzitnik.game.blocks.Furnace;
import cz.jzitnik.game.ui.Healthbar;
import cz.jzitnik.tui.utils.SpriteCombiner;
import lombok.Getter;
-import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.jline.terminal.Terminal;
@@ -16,10 +15,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-@RequiredArgsConstructor
public class ScreenRenderer {
- private SpriteList spriteList;
- private Terminal terminal;
+ private final SpriteList spriteList;
+ private final Terminal terminal;
public ScreenRenderer(SpriteList spriteList, Terminal terminal) {
this.spriteList = spriteList;
@@ -41,7 +39,7 @@ public class ScreenRenderer {
return null;
}
- public void render(Game game) {
+ public synchronized void render(Game game) {
var world = game.getWorld();
StringBuilder main = new StringBuilder();
main.append("\033[H\033[2J");