Compare commits
5 Commits
13db7972eb
...
main
Author | SHA1 | Date | |
---|---|---|---|
5c1ec41ac7
|
|||
75393f2bea
|
|||
579bc05538
|
|||
c6cc5faba2
|
|||
bfafe8577a
|
@ -1,6 +1,7 @@
|
|||||||
package cz.jzitnik;
|
package cz.jzitnik;
|
||||||
|
|
||||||
import cz.jzitnik.game.GameSaver;
|
import cz.jzitnik.game.GameSaver;
|
||||||
|
import cz.jzitnik.game.context.list.GameLoopContext;
|
||||||
import cz.jzitnik.game.logic.CustomLogicProvider;
|
import cz.jzitnik.game.logic.CustomLogicProvider;
|
||||||
import cz.jzitnik.game.mobs.EntityLogicProvider;
|
import cz.jzitnik.game.mobs.EntityLogicProvider;
|
||||||
import cz.jzitnik.game.threads.ThreadProvider;
|
import cz.jzitnik.game.threads.ThreadProvider;
|
||||||
@ -38,15 +39,21 @@ public class Main {
|
|||||||
var gameSaver = new GameSaver();
|
var gameSaver = new GameSaver();
|
||||||
var game = gameSaver.load();
|
var game = gameSaver.load();
|
||||||
|
|
||||||
final boolean[] isRunning = { true };
|
game.registerContext(Terminal.class, terminal);
|
||||||
|
|
||||||
|
GameLoopContext gameLoopContext = game.getContext(GameLoopContext.class);
|
||||||
EntityLogicProvider entityLogicProvider = new EntityLogicProvider();
|
EntityLogicProvider entityLogicProvider = new EntityLogicProvider();
|
||||||
CustomLogicProvider customLogicProvider = new CustomLogicProvider();
|
CustomLogicProvider customLogicProvider = new CustomLogicProvider();
|
||||||
|
|
||||||
ThreadProvider threadProvider = new ThreadProvider(game, screenRenderer, terminal, isRunning);
|
ThreadProvider threadProvider = new ThreadProvider(game, screenRenderer, terminal);
|
||||||
threadProvider.start();
|
threadProvider.start();
|
||||||
|
|
||||||
while (isRunning[0]) {
|
while (true) {
|
||||||
|
if (!gameLoopContext.isRunning()) {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
entityLogicProvider.update(game);
|
entityLogicProvider.update(game);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
@ -64,10 +71,6 @@ public class Main {
|
|||||||
|
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Closing terminal");
|
|
||||||
terminal.trackMouse(Terminal.MouseTracking.Off);
|
|
||||||
terminal.close();
|
|
||||||
} catch (IOException | InterruptedException ignored) {
|
} catch (IOException | InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import lombok.Setter;
|
|||||||
|
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
@ -50,7 +51,6 @@ public class Game {
|
|||||||
private final List<Block>[][] world = (List<Block>[][]) new CopyOnWriteArrayList[256][512];
|
private final List<Block>[][] world = (List<Block>[][]) new CopyOnWriteArrayList[256][512];
|
||||||
private final Player player = new Player();
|
private final Player player = new Player();
|
||||||
private transient boolean mining = false;
|
private transient boolean mining = false;
|
||||||
@Setter
|
|
||||||
private transient Window window = Window.WORLD;
|
private transient Window window = Window.WORLD;
|
||||||
private final Inventory inventory = new Inventory();
|
private final Inventory inventory = new Inventory();
|
||||||
private transient EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
|
private transient EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
|
||||||
@ -72,6 +72,15 @@ public class Game {
|
|||||||
Generation.generateWorld(this);
|
Generation.generateWorld(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNight() {
|
||||||
|
return daytime > 200 && daytime < 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWindow(Window window) {
|
||||||
|
this.window = window;
|
||||||
|
gameStates.dependencies.windowSwitchHandlerProvider.handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current coordinates of the player (bottom half).
|
* Returns the current coordinates of the player (bottom half).
|
||||||
*
|
*
|
||||||
@ -96,13 +105,19 @@ public class Game {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Point getPlayerCordsPoint() {
|
||||||
|
int[] cords = getPlayerCords();
|
||||||
|
|
||||||
|
return new Point(cords[0], cords[1]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the player one block to the right if possible.
|
* Moves the player one block to the right if possible.
|
||||||
*
|
*
|
||||||
* @param screenRenderer the renderer used to refresh the screen.
|
* @param screenRenderer the renderer used to refresh the screen.
|
||||||
* @param terminal the terminal instance used for layout.
|
* @param terminal the terminal instance used for layout.
|
||||||
*/
|
*/
|
||||||
public void movePlayerRight(ScreenRenderer screenRenderer, Terminal terminal) {
|
public synchronized void movePlayerRight(ScreenRenderer screenRenderer, Terminal terminal) {
|
||||||
if (window != Window.WORLD) {
|
if (window != Window.WORLD) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -122,9 +137,9 @@ public class Game {
|
|||||||
|
|
||||||
new Thread(() -> entitySpawnProvider.update(this, terminal)).start();
|
new Thread(() -> entitySpawnProvider.update(this, terminal)).start();
|
||||||
|
|
||||||
playMovePlayerSound(cords[0] + 1, cords[1]);
|
new Thread(() -> playMovePlayerSound(cords[0] + 1, cords[1])).start();
|
||||||
|
|
||||||
update(screenRenderer);
|
new Thread(() -> update(screenRenderer)).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,7 +148,7 @@ public class Game {
|
|||||||
* @param screenRenderer the renderer used to refresh the screen.
|
* @param screenRenderer the renderer used to refresh the screen.
|
||||||
* @param terminal the terminal instance used for layout.
|
* @param terminal the terminal instance used for layout.
|
||||||
*/
|
*/
|
||||||
public void movePlayerLeft(ScreenRenderer screenRenderer, Terminal terminal) {
|
public synchronized void movePlayerLeft(ScreenRenderer screenRenderer, Terminal terminal) {
|
||||||
if (window != Window.WORLD) {
|
if (window != Window.WORLD) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -153,23 +168,31 @@ public class Game {
|
|||||||
|
|
||||||
new Thread(() -> entitySpawnProvider.update(this, terminal)).start();
|
new Thread(() -> entitySpawnProvider.update(this, terminal)).start();
|
||||||
|
|
||||||
playMovePlayerSound(cords[0] - 1, cords[1]);
|
new Thread(() -> playMovePlayerSound(cords[0] - 1, cords[1])).start();
|
||||||
|
|
||||||
update(screenRenderer);
|
new Thread(() -> update(screenRenderer)).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private transient boolean playerMovingUp = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the player upward by one block, if jumping is valid.
|
* Moves the player upward by one block, if jumping is valid.
|
||||||
*
|
*
|
||||||
* @param screenRenderer the renderer used to refresh the screen.
|
* @param screenRenderer the renderer used to refresh the screen.
|
||||||
*/
|
*/
|
||||||
public void movePlayerUp(ScreenRenderer screenRenderer) {
|
public synchronized void movePlayerUp(ScreenRenderer screenRenderer) {
|
||||||
|
if (playerMovingUp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerMovingUp = true;
|
||||||
if (window != Window.WORLD) {
|
if (window != Window.WORLD) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int[] cords = getPlayerCords();
|
int[] cords = getPlayerCords();
|
||||||
|
|
||||||
if (isSolid(world[cords[1] - 2][cords[0]]) || !isSolid(world[cords[1] + 1][cords[0]])) {
|
if (isSolid(world[cords[1] - 2][cords[0]]) || !isSolid(world[cords[1] + 1][cords[0]])) {
|
||||||
|
playerMovingUp = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +203,8 @@ public class Game {
|
|||||||
|
|
||||||
stats.setBlocksTraveled(stats.getBlocksTraveled() + 1);
|
stats.setBlocksTraveled(stats.getBlocksTraveled() + 1);
|
||||||
|
|
||||||
|
screenRenderer.render(this);
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(400);
|
Thread.sleep(400);
|
||||||
@ -187,6 +212,8 @@ public class Game {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playerMovingUp = false;
|
||||||
|
|
||||||
update(screenRenderer);
|
update(screenRenderer);
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
@ -210,7 +237,9 @@ public class Game {
|
|||||||
int dealDamage = inventory.getItemInHand().map(Item::getDealDamage).orElse(1);
|
int dealDamage = inventory.getItemInHand().map(Item::getDealDamage).orElse(1);
|
||||||
if (mob.getHp() - dealDamage <= 0) {
|
if (mob.getHp() - dealDamage <= 0) {
|
||||||
// Mob is killed
|
// Mob is killed
|
||||||
gameStates.dependencies.entityKill.get(mob.getBlockId()).killed(this, mob, x, y);
|
try {
|
||||||
|
gameStates.dependencies.entityKill.get(mob.getBlockId()).killed(this, mob, x, y);
|
||||||
|
} catch (Exception _) {}
|
||||||
world[y][x].remove(mob);
|
world[y][x].remove(mob);
|
||||||
} else {
|
} else {
|
||||||
mob.decreaseHp(dealDamage);
|
mob.decreaseHp(dealDamage);
|
||||||
@ -610,7 +639,7 @@ public class Game {
|
|||||||
* @return true if any block is not a ghost block.
|
* @return true if any block is not a ghost block.
|
||||||
*/
|
*/
|
||||||
public boolean isSolid(List<Block> blocks) {
|
public boolean isSolid(List<Block> blocks) {
|
||||||
return !blocks.stream().allMatch(Block::isGhost);
|
return !blocks.stream().allMatch(block -> block.isGhost() || block.isMob());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -646,7 +675,11 @@ public class Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getContext(Class clazz) {
|
public <T> T getContext(Class<T> clazz) {
|
||||||
return gameStates.globalContextProvider.getMap(clazz);
|
return gameStates.globalContextProvider.getMap(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerContext(Class clazz, Object instance) {
|
||||||
|
gameStates.globalContextProvider.registerContext(clazz, instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
12
src/main/java/cz/jzitnik/game/annotations/FireImmune.java
Normal file
12
src/main/java/cz/jzitnik/game/annotations/FireImmune.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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)
|
||||||
|
@RequireAnnotation(BlockRegistry.class)
|
||||||
|
public @interface FireImmune {
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
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)
|
||||||
|
@RequireAnnotation(BlockRegistry.class)
|
||||||
|
public @interface LightBurningMob {
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public @interface WindowSwitchHandler {
|
||||||
|
}
|
@ -17,7 +17,7 @@ public class Bed implements RightClickHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void onBlockRightClick(int x, int y, Game game, ScreenRenderer screenRenderer) {
|
public void onBlockRightClick(int x, int y, Game game, ScreenRenderer screenRenderer) {
|
||||||
BedSleepGlobalContext bedSleepGlobalContext =
|
BedSleepGlobalContext bedSleepGlobalContext =
|
||||||
(BedSleepGlobalContext) game.getContext(BedSleepGlobalContext.class);
|
game.getContext(BedSleepGlobalContext.class);
|
||||||
|
|
||||||
if (bedSleepGlobalContext.isSleeping() || game.getDaytime() < 200 || game.getDaytime() > 500) {
|
if (bedSleepGlobalContext.isSleeping() || game.getDaytime() < 200 || game.getDaytime() > 500) {
|
||||||
return; // already in progress
|
return; // already in progress
|
||||||
|
@ -11,7 +11,8 @@ public class GlobalContextProvider {
|
|||||||
private final Map<Class, Object> data = new HashMap<>();
|
private final Map<Class, Object> data = new HashMap<>();
|
||||||
private boolean loaded = false;
|
private boolean loaded = false;
|
||||||
|
|
||||||
public Object getMap(Class<?> clazz) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T getMap(Class<T> clazz) {
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
Reflections reflections = new Reflections("cz.jzitnik.game.context");
|
Reflections reflections = new Reflections("cz.jzitnik.game.context");
|
||||||
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(GlobalContext.class);
|
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(GlobalContext.class);
|
||||||
@ -28,6 +29,10 @@ public class GlobalContextProvider {
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.get(clazz);
|
return clazz.cast(data.get(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerContext(Class clazz, Object instance) {
|
||||||
|
data.put(clazz, instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package cz.jzitnik.game.context.list;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.annotations.GlobalContext;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@GlobalContext
|
||||||
|
public class GameLoopContext {
|
||||||
|
private boolean isRunning = true;
|
||||||
|
}
|
@ -7,6 +7,7 @@ import cz.jzitnik.game.handlers.events.EventHandlerProvider;
|
|||||||
import cz.jzitnik.game.handlers.pickup.PickupHandlerProvider;
|
import cz.jzitnik.game.handlers.pickup.PickupHandlerProvider;
|
||||||
import cz.jzitnik.game.handlers.place.PlaceHandler;
|
import cz.jzitnik.game.handlers.place.PlaceHandler;
|
||||||
import cz.jzitnik.game.handlers.tooluse.ToolUseProvider;
|
import cz.jzitnik.game.handlers.tooluse.ToolUseProvider;
|
||||||
|
import cz.jzitnik.game.handlers.windowswitch.WindowSwitchHandlerProvider;
|
||||||
import cz.jzitnik.game.mobs.EntityHurtAnimation;
|
import cz.jzitnik.game.mobs.EntityHurtAnimation;
|
||||||
import cz.jzitnik.game.mobs.EntityKill;
|
import cz.jzitnik.game.mobs.EntityKill;
|
||||||
import cz.jzitnik.game.smelting.Smelting;
|
import cz.jzitnik.game.smelting.Smelting;
|
||||||
@ -20,6 +21,7 @@ public class Dependencies {
|
|||||||
public EntityHurtAnimation entityHurtAnimation = new EntityHurtAnimation();
|
public EntityHurtAnimation entityHurtAnimation = new EntityHurtAnimation();
|
||||||
public EntityKill entityKill = new EntityKill();
|
public EntityKill entityKill = new EntityKill();
|
||||||
public PickupHandlerProvider pickupHandlerProvider = new PickupHandlerProvider();
|
public PickupHandlerProvider pickupHandlerProvider = new PickupHandlerProvider();
|
||||||
|
public WindowSwitchHandlerProvider windowSwitchHandlerProvider = new WindowSwitchHandlerProvider();
|
||||||
public GameSaver gameSaver = new GameSaver();
|
public GameSaver gameSaver = new GameSaver();
|
||||||
public EventHandlerProvider eventHandlerProvider = new EventHandlerProvider();
|
public EventHandlerProvider eventHandlerProvider = new EventHandlerProvider();
|
||||||
public Smelting smelting = new Smelting();
|
public Smelting smelting = new Smelting();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cz.jzitnik.game.entities;
|
package cz.jzitnik.game.entities;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.context.list.GameLoopContext;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@ -3,10 +3,12 @@ package cz.jzitnik.game.entities.items.registry.mobs;
|
|||||||
import cz.jzitnik.game.SpriteLoader;
|
import cz.jzitnik.game.SpriteLoader;
|
||||||
import cz.jzitnik.game.annotations.CustomMobFallingAfterMineLogic;
|
import cz.jzitnik.game.annotations.CustomMobFallingAfterMineLogic;
|
||||||
import cz.jzitnik.game.annotations.EntityRegistry;
|
import cz.jzitnik.game.annotations.EntityRegistry;
|
||||||
|
import cz.jzitnik.game.annotations.LightBurningMob;
|
||||||
import cz.jzitnik.game.entities.Block;
|
import cz.jzitnik.game.entities.Block;
|
||||||
import cz.jzitnik.game.mobs.services.zombie.ZombieData;
|
import cz.jzitnik.game.mobs.services.zombie.ZombieData;
|
||||||
import cz.jzitnik.game.mobs.services.zombie.ZombieFallingAfterMineLogic;
|
import cz.jzitnik.game.mobs.services.zombie.ZombieFallingAfterMineLogic;
|
||||||
|
|
||||||
|
@LightBurningMob
|
||||||
@CustomMobFallingAfterMineLogic(ZombieFallingAfterMineLogic.class)
|
@CustomMobFallingAfterMineLogic(ZombieFallingAfterMineLogic.class)
|
||||||
@EntityRegistry("zombie")
|
@EntityRegistry("zombie")
|
||||||
public class Zombie extends Block {
|
public class Zombie extends Block {
|
||||||
|
@ -27,11 +27,11 @@ public class Generation {
|
|||||||
|
|
||||||
int[] terrainHeight = PopulateWorld.generateTerrain();
|
int[] terrainHeight = PopulateWorld.generateTerrain();
|
||||||
|
|
||||||
|
game.getInventory().addItem(ItemBlockSupplier.getItem("coal"));
|
||||||
|
|
||||||
game.getPlayer().setPlayerBlock1(steveBlock);
|
game.getPlayer().setPlayerBlock1(steveBlock);
|
||||||
game.getPlayer().setPlayerBlock2(steveBlock2);
|
game.getPlayer().setPlayerBlock2(steveBlock2);
|
||||||
|
|
||||||
game.getInventory().addItem(ItemBlockSupplier.getItem("sand"));
|
|
||||||
|
|
||||||
PopulateWorld.populateWorld(world, terrainHeight);
|
PopulateWorld.populateWorld(world, terrainHeight);
|
||||||
Trees.plantTrees(world, terrainHeight);
|
Trees.plantTrees(world, terrainHeight);
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package cz.jzitnik.game.handlers.windowswitch;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
|
||||||
|
public interface WindowSwitchHandlerInterface {
|
||||||
|
void handle(Game game);
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package cz.jzitnik.game.handlers.windowswitch;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.annotations.WindowSwitchHandler;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
|
public class WindowSwitchHandlerProvider {
|
||||||
|
public final List<WindowSwitchHandlerInterface> handler = new ArrayList<>();
|
||||||
|
|
||||||
|
public WindowSwitchHandlerProvider() {
|
||||||
|
registerHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(Game game) {
|
||||||
|
handler.forEach(handler -> handler.handle(game));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerHandlers() {
|
||||||
|
Reflections reflections = new Reflections("cz.jzitnik.game.handlers.windowswitch.handlers");
|
||||||
|
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(WindowSwitchHandler.class);
|
||||||
|
|
||||||
|
for (Class<?> clazz : handlerClasses) {
|
||||||
|
if (WindowSwitchHandlerInterface.class.isAssignableFrom(clazz)) {
|
||||||
|
try {
|
||||||
|
WindowSwitchHandlerInterface handlerInstance = (WindowSwitchHandlerInterface) clazz.getDeclaredConstructor()
|
||||||
|
.newInstance();
|
||||||
|
handler.add(handlerInstance);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package cz.jzitnik.game.handlers.windowswitch.handlers;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
import cz.jzitnik.game.annotations.WindowSwitchHandler;
|
||||||
|
import cz.jzitnik.game.context.list.GameLoopContext;
|
||||||
|
import cz.jzitnik.game.handlers.windowswitch.WindowSwitchHandlerInterface;
|
||||||
|
import cz.jzitnik.game.ui.Window;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@WindowSwitchHandler
|
||||||
|
public class GamePauseHandler implements WindowSwitchHandlerInterface {
|
||||||
|
private final Window[] pausedWindows = {Window.ESC, Window.DEATH_SCREEN, Window.OPTIONS, Window.SAVE_EXIT, Window.SAVED};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Game game) {
|
||||||
|
GameLoopContext gameLoopContext = game.getContext(GameLoopContext.class);
|
||||||
|
gameLoopContext.setRunning(!Arrays.asList(pausedWindows).contains(game.getWindow()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package cz.jzitnik.game.logic.services.burning;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
import cz.jzitnik.game.annotations.CustomLogic;
|
||||||
|
import cz.jzitnik.game.annotations.LightBurningMob;
|
||||||
|
import cz.jzitnik.game.entities.Block;
|
||||||
|
import cz.jzitnik.game.entities.items.Item;
|
||||||
|
import cz.jzitnik.game.logic.CustomLogicInterface;
|
||||||
|
import cz.jzitnik.tui.ScreenRenderer;
|
||||||
|
|
||||||
|
@CustomLogic
|
||||||
|
public class LightBurningMobLogic implements CustomLogicInterface {
|
||||||
|
private static final int RADIUS = 30;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nextIteration(Game game, ScreenRenderer screenRenderer) {
|
||||||
|
if (!game.isNight()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] data = game.getPlayerCords();
|
||||||
|
var world = game.getWorld();
|
||||||
|
int playerX = data[0];
|
||||||
|
int playerY = data[1];
|
||||||
|
|
||||||
|
int startX = Math.max(0, playerX - RADIUS);
|
||||||
|
int startY = Math.max(0, playerY - RADIUS);
|
||||||
|
int endX = Math.min(world[0].length - 1, playerX + RADIUS);
|
||||||
|
int endY = Math.min(world.length - 1, playerY + RADIUS);
|
||||||
|
|
||||||
|
for (int y = startY; y <= endY; y++) {
|
||||||
|
for (int x = startX; x <= endX; x++) {
|
||||||
|
var blocks = world[y][x];
|
||||||
|
|
||||||
|
for (Block block : blocks) {
|
||||||
|
if (block.getClass().isAnnotationPresent(LightBurningMob.class)) {
|
||||||
|
int dealDamage = game.getInventory().getItemInHand().map(Item::getDealDamage).orElse(1);
|
||||||
|
if (block.getHp() - dealDamage <= 0) {
|
||||||
|
// Mob is killed
|
||||||
|
world[y][x].remove(block);
|
||||||
|
} else {
|
||||||
|
block.decreaseHp(dealDamage);
|
||||||
|
block.setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(true, block.getSpriteState().get()));
|
||||||
|
if (block.getLinkedMobTexture() != null) {
|
||||||
|
block.getLinkedMobTexture().setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(true, block.getLinkedMobTexture().getSpriteState().get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
block.setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(false, block.getSpriteState().get()));
|
||||||
|
|
||||||
|
if (block.getLinkedMobTexture() != null) {
|
||||||
|
block.getLinkedMobTexture().setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(false, block.getLinkedMobTexture().getSpriteState().get()));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,7 +32,7 @@ public class FireSpreadingLogic implements CustomLogicInterface {
|
|||||||
var blocks = world[y][x];
|
var blocks = world[y][x];
|
||||||
|
|
||||||
for (Block block : blocks) {
|
for (Block block : blocks) {
|
||||||
if (block.isOnFire() && block.getClass().getAnnotation(Flamable.class).value()) {
|
if ((block.isOnFire() && !block.isMob()) && block.getClass().getAnnotation(Flamable.class).value()) {
|
||||||
int maxTime = random.nextInt(30) + 15;
|
int maxTime = random.nextInt(30) + 15;
|
||||||
block.setBurningTime2(block.getBurningTime2() + 1);
|
block.setBurningTime2(block.getBurningTime2() + 1);
|
||||||
if (block.getBurningTime2() >= maxTime) {
|
if (block.getBurningTime2() >= maxTime) {
|
||||||
|
@ -4,9 +4,12 @@ import java.util.Random;
|
|||||||
|
|
||||||
import cz.jzitnik.game.Game;
|
import cz.jzitnik.game.Game;
|
||||||
import cz.jzitnik.game.annotations.CustomLogic;
|
import cz.jzitnik.game.annotations.CustomLogic;
|
||||||
|
import cz.jzitnik.game.annotations.FireImmune;
|
||||||
import cz.jzitnik.game.annotations.Flamable;
|
import cz.jzitnik.game.annotations.Flamable;
|
||||||
import cz.jzitnik.game.entities.Block;
|
import cz.jzitnik.game.entities.Block;
|
||||||
|
import cz.jzitnik.game.entities.items.Item;
|
||||||
import cz.jzitnik.game.logic.CustomLogicInterface;
|
import cz.jzitnik.game.logic.CustomLogicInterface;
|
||||||
|
import cz.jzitnik.game.sprites.Steve;
|
||||||
import cz.jzitnik.tui.ScreenRenderer;
|
import cz.jzitnik.tui.ScreenRenderer;
|
||||||
|
|
||||||
@CustomLogic
|
@CustomLogic
|
||||||
@ -48,12 +51,45 @@ public class LavaFireLogic implements CustomLogicInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Block block : world[y][x]) {
|
for (Block block : world[y][x]) {
|
||||||
if (block.getClass().isAnnotationPresent(Flamable.class) && !block.isOnFire()) {
|
if ((block.getClass().isAnnotationPresent(Flamable.class) || block.isMob()) && !block.isOnFire()) {
|
||||||
int maxTime = random.nextInt(8) + 5;
|
int maxTime = random.nextInt(8) + 5;
|
||||||
block.setBurningTime(block.getBurningTime() + 1);
|
|
||||||
if (block.getBurningTime() >= maxTime) {
|
if (!block.isMob()) {
|
||||||
block.setOnFire(true);
|
block.setBurningTime(block.getBurningTime() + 1);
|
||||||
block.setBurningTime(0);
|
if (block.getBurningTime() >= maxTime) {
|
||||||
|
block.setOnFire(true);
|
||||||
|
block.setBurningTime(0);
|
||||||
|
}
|
||||||
|
} else if (!block.getClass().isAnnotationPresent(FireImmune.class) && !block.getBlockId().equals("steve")) {
|
||||||
|
int dealDamage = game.getInventory().getItemInHand().map(Item::getDealDamage).orElse(1);
|
||||||
|
if (block.getHp() - dealDamage <= 0) {
|
||||||
|
// Mob is killed
|
||||||
|
world[y][x].remove(block);
|
||||||
|
} else {
|
||||||
|
block.decreaseHp(dealDamage);
|
||||||
|
block.setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(true, block.getSpriteState().get()));
|
||||||
|
if (block.getLinkedMobTexture() != null) {
|
||||||
|
block.getLinkedMobTexture().setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(true, block.getLinkedMobTexture().getSpriteState().get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
block.setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(false, block.getSpriteState().get()));
|
||||||
|
|
||||||
|
if (block.getLinkedMobTexture() != null) {
|
||||||
|
block.getLinkedMobTexture().setSpriteState(game.getGameStates().dependencies.entityHurtAnimation.get(block.getBlockId())
|
||||||
|
.setHurtAnimation(false, block.getLinkedMobTexture().getSpriteState().get()));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package cz.jzitnik.game.logic.services.mobs;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
import cz.jzitnik.game.annotations.CustomLogic;
|
||||||
|
import cz.jzitnik.game.entities.items.registry.mobs.Zombie;
|
||||||
|
import cz.jzitnik.game.logic.CustomLogicInterface;
|
||||||
|
import cz.jzitnik.tui.ScreenRenderer;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@CustomLogic
|
||||||
|
public class ZombieHurtLogic implements CustomLogicInterface {
|
||||||
|
@Override
|
||||||
|
public void nextIteration(Game game, ScreenRenderer screenRenderer) {
|
||||||
|
var world = game.getWorld();
|
||||||
|
var playerCords = game.getPlayerCordsPoint();
|
||||||
|
|
||||||
|
if (world[playerCords.y][playerCords.x].stream().anyMatch(block -> block.getClass().equals(Zombie.class))) {
|
||||||
|
game.getPlayer().dealDamage(game, screenRenderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,5 @@ import lombok.Setter;
|
|||||||
@Setter
|
@Setter
|
||||||
public class ZombieData {
|
public class ZombieData {
|
||||||
private int lastDirection = 1; // 1 = right, -1 = left
|
private int lastDirection = 1; // 1 = right, -1 = left
|
||||||
private int movementCooldown = 0;
|
|
||||||
private int jumpAttempts = 0;
|
private int jumpAttempts = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,140 @@
|
|||||||
package cz.jzitnik.game.mobs.services.zombie;
|
package cz.jzitnik.game.mobs.services.zombie;
|
||||||
|
|
||||||
import cz.jzitnik.game.annotations.EntityLogic;
|
import cz.jzitnik.game.annotations.EntityLogic;
|
||||||
|
import cz.jzitnik.game.entities.Block;
|
||||||
import cz.jzitnik.game.mobs.EntityLogicInterface;
|
import cz.jzitnik.game.mobs.EntityLogicInterface;
|
||||||
import cz.jzitnik.game.mobs.EntityLogicProvider;
|
import cz.jzitnik.game.mobs.EntityLogicProvider;
|
||||||
|
import cz.jzitnik.game.sprites.Zombie;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@EntityLogic("zombie")
|
@EntityLogic("zombie")
|
||||||
public class ZombieMoveLogic implements EntityLogicInterface {
|
public class ZombieMoveLogic implements EntityLogicInterface {
|
||||||
@Override
|
@Override
|
||||||
public void nextIteration(EntityLogicProvider.EntityLogicMobDTO entityLogicMobDTO) {
|
public void nextIteration(EntityLogicProvider.EntityLogicMobDTO entityLogicMobDTO) {
|
||||||
|
int zombieX = entityLogicMobDTO.getX();
|
||||||
|
int zombieY = entityLogicMobDTO.getY();
|
||||||
|
var game = entityLogicMobDTO.getGame();
|
||||||
|
var zombie = entityLogicMobDTO.getMob();
|
||||||
|
|
||||||
|
// Skip updates for top half
|
||||||
|
if (zombie.getSpriteState().get() == Zombie.ZombieState.TOP ||
|
||||||
|
zombie.getSpriteState().get() == Zombie.ZombieState.TOP_HURT) {
|
||||||
|
log.debug("Skipping top half of zombie at ({},{})", zombieX, zombieY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Zombie tick @ ({},{})", zombieX, zombieY);
|
||||||
|
|
||||||
|
var world = game.getWorld();
|
||||||
|
var zombieData = (ZombieData) zombie.getData();
|
||||||
|
|
||||||
|
// Player coordinates
|
||||||
|
Point playerCords = game.getPlayerCordsPoint();
|
||||||
|
int playerX = playerCords.x;
|
||||||
|
int playerY = playerCords.y;
|
||||||
|
log.debug("Player at ({},{})", playerX, playerY);
|
||||||
|
|
||||||
|
// Decide direction
|
||||||
|
int direction = Integer.compare(playerX, zombieX);
|
||||||
|
zombieData.setLastDirection(direction);
|
||||||
|
log.debug("Zombie direction: {}", direction);
|
||||||
|
|
||||||
|
if (direction == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean updated = false;
|
||||||
|
int newZombieX = zombieX;
|
||||||
|
int newZombieY = zombieY;
|
||||||
|
|
||||||
|
// Check bounds
|
||||||
|
if (zombieX + direction < 0 || zombieX + direction >= world[0].length) {
|
||||||
|
log.debug("Zombie cannot move, out of bounds at X: {}", zombieX + direction);
|
||||||
|
} else {
|
||||||
|
// Blocks ahead
|
||||||
|
List<Block> blocksAhead = world[zombieY][zombieX + direction];
|
||||||
|
log.debug("Blocks ahead solid? {}", game.isSolid(blocksAhead));
|
||||||
|
|
||||||
|
if (!game.isSolid(blocksAhead)) {
|
||||||
|
log.debug("Path clear, moving to ({},{})", zombieX + direction, zombieY);
|
||||||
|
moveZombie(zombie, zombieX, zombieY, zombieX + direction, zombieY, world);
|
||||||
|
newZombieX = zombieX + direction;
|
||||||
|
updated = true;
|
||||||
|
zombieData.setJumpAttempts(0);
|
||||||
|
} else {
|
||||||
|
log.debug("Path blocked, checking jump options");
|
||||||
|
List<Block> blocksAboveAhead = world[zombieY - 1][zombieX + direction];
|
||||||
|
List<Block> blocksTwoAboveAhead = world[zombieY - 2][zombieX + direction];
|
||||||
|
|
||||||
|
log.debug("Blocks above ahead solid? {}", game.isSolid(blocksAboveAhead));
|
||||||
|
log.debug("Blocks two above ahead solid? {}", game.isSolid(blocksTwoAboveAhead));
|
||||||
|
|
||||||
|
if (!game.isSolid(blocksAboveAhead) && game.isSolid(blocksAhead) && !game.isSolid(blocksTwoAboveAhead)) {
|
||||||
|
if (zombieData.getJumpAttempts() < 2) {
|
||||||
|
log.debug("Jumping to ({},{})", zombieX + direction, zombieY - 1);
|
||||||
|
moveZombie(zombie, zombieX, zombieY, zombieX + direction, zombieY - 1, world);
|
||||||
|
newZombieX = zombieX + direction;
|
||||||
|
newZombieY = zombieY - 1;
|
||||||
|
updated = true;
|
||||||
|
zombieData.setJumpAttempts(zombieData.getJumpAttempts() + 1);
|
||||||
|
} else {
|
||||||
|
log.debug("Max jump attempts reached: {}", zombieData.getJumpAttempts());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("Cannot jump over obstacle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply gravity
|
||||||
|
while (updated) {
|
||||||
|
if (newZombieY + 1 >= world.length) {
|
||||||
|
log.debug("Gravity blocked, bottom of world reached");
|
||||||
|
updated = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!game.isSolid(world[newZombieY + 1][newZombieX])) {
|
||||||
|
if (newZombieY - zombieY < 3) {
|
||||||
|
log.debug("Gravity moving zombie down from ({},{}) to ({},{})", newZombieX, newZombieY, newZombieX, newZombieY + 1);
|
||||||
|
moveZombie(zombie, newZombieX, newZombieY, newZombieX, newZombieY + 1, world);
|
||||||
|
newZombieY++;
|
||||||
|
} else {
|
||||||
|
log.debug("Gravity limit reached, stopping");
|
||||||
|
updated = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("Block below solid, stopping gravity");
|
||||||
|
updated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveZombie(Block zombie, int oldX, int oldY, int newX, int newY, List<Block>[][] world) {
|
||||||
|
Block linked = zombie.getLinkedMobTexture();
|
||||||
|
|
||||||
|
boolean isTop = zombie.getSpriteState().isPresent() &&
|
||||||
|
(zombie.getSpriteState().get().equals(Zombie.ZombieState.TOP) ||
|
||||||
|
zombie.getSpriteState().get().equals(Zombie.ZombieState.TOP_HURT));
|
||||||
|
|
||||||
|
if (isTop) {
|
||||||
|
log.debug("Moving TOP block from ({},{}) to ({},{})", oldX, oldY, newX, newY);
|
||||||
|
world[oldY][oldX].remove(zombie);
|
||||||
|
world[oldY + 1][oldX].remove(linked);
|
||||||
|
|
||||||
|
world[newY][newX].add(zombie);
|
||||||
|
world[newY + 1][newX].add(linked);
|
||||||
|
} else {
|
||||||
|
log.debug("Moving BOTTOM block from ({},{}) to ({},{})", oldX, oldY, newX, newY);
|
||||||
|
world[oldY][oldX].remove(zombie);
|
||||||
|
world[oldY - 1][oldX].remove(linked);
|
||||||
|
|
||||||
|
world[newY][newX].add(zombie);
|
||||||
|
world[newY - 1][newX].add(linked);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,10 @@ public class ZombieSpawnLogic implements EntitySpawnInterface {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawn(int playerX, int playerY, Game game, Terminal terminal) {
|
public void spawn(int playerX, int playerY, Game game, Terminal terminal) {
|
||||||
|
if (!game.isNight()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int[] view = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);
|
int[] view = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);
|
||||||
int startX = view[0];
|
int startX = view[0];
|
||||||
int endX = view[1];
|
int endX = view[1];
|
||||||
|
@ -22,7 +22,6 @@ public class ThreadProvider {
|
|||||||
private final Game game;
|
private final Game game;
|
||||||
private final ScreenRenderer screenRenderer;
|
private final ScreenRenderer screenRenderer;
|
||||||
private final Terminal terminal;
|
private final Terminal terminal;
|
||||||
private final boolean[] isRunning;
|
|
||||||
private final List<Thread> list = new ArrayList<>();
|
private final List<Thread> list = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,11 +42,10 @@ public class ThreadProvider {
|
|||||||
* @param terminal The terminal.
|
* @param terminal The terminal.
|
||||||
* @param isRunning A shared boolean array for controlling thread execution.
|
* @param isRunning A shared boolean array for controlling thread execution.
|
||||||
*/
|
*/
|
||||||
public ThreadProvider(Game game, ScreenRenderer screenRenderer, Terminal terminal, boolean[] isRunning) {
|
public ThreadProvider(Game game, ScreenRenderer screenRenderer, Terminal terminal) {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
this.screenRenderer = screenRenderer;
|
this.screenRenderer = screenRenderer;
|
||||||
this.terminal = terminal;
|
this.terminal = terminal;
|
||||||
this.isRunning = isRunning;
|
|
||||||
registerHandlers();
|
registerHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +75,6 @@ public class ThreadProvider {
|
|||||||
params[i] = screenRenderer;
|
params[i] = screenRenderer;
|
||||||
else if (type == Terminal.class)
|
else if (type == Terminal.class)
|
||||||
params[i] = terminal;
|
params[i] = terminal;
|
||||||
else if (type == boolean[].class)
|
|
||||||
params[i] = isRunning;
|
|
||||||
else if (type == Player.class)
|
else if (type == Player.class)
|
||||||
params[i] = game.getPlayer();
|
params[i] = game.getPlayer();
|
||||||
else {
|
else {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package cz.jzitnik.game.threads.list;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
import cz.jzitnik.game.annotations.ThreadRegistry;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ThreadRegistry
|
||||||
|
public class BackgroundSaveTask extends Thread {
|
||||||
|
private final Game game;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10000);
|
||||||
|
game.getGameStates().dependencies.gameSaver.save(game);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -84,15 +84,10 @@ public class InputHandlerThread extends Thread {
|
|||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case '1', '2', '3', '4', '5', '6', '7', '8', '9' -> game.changeSlot(key - 49, screenRenderer);
|
case '1', '2', '3', '4', '5', '6', '7', '8', '9' -> game.changeSlot(key - 49, screenRenderer);
|
||||||
case 'a' -> {
|
case 'a' -> new Thread(() -> game.movePlayerLeft(screenRenderer, terminal)).start();
|
||||||
game.movePlayerLeft(screenRenderer, terminal);
|
case 'd' -> new Thread(() -> game.movePlayerRight(screenRenderer, terminal)).start();
|
||||||
}
|
case ' ' ->{
|
||||||
case 'd' -> {
|
|
||||||
game.movePlayerRight(screenRenderer, terminal);
|
|
||||||
}
|
|
||||||
case ' ' -> {
|
|
||||||
game.movePlayerUp(screenRenderer);
|
game.movePlayerUp(screenRenderer);
|
||||||
screenRenderer.render(game);
|
|
||||||
}
|
}
|
||||||
case 'e' -> {
|
case 'e' -> {
|
||||||
if (game.getWindow() != Window.WORLD) {
|
if (game.getWindow() != Window.WORLD) {
|
||||||
@ -107,11 +102,12 @@ public class InputHandlerThread extends Thread {
|
|||||||
case 'q' -> {
|
case 'q' -> {
|
||||||
if (game.getWindow() != Window.WORLD) {
|
if (game.getWindow() != Window.WORLD) {
|
||||||
game.setWindow(Window.WORLD);
|
game.setWindow(Window.WORLD);
|
||||||
|
screenRenderer.render(game);
|
||||||
} else {
|
} else {
|
||||||
game.setWindow(Window.ESC);
|
game.setWindow(Window.ESC);
|
||||||
game.getGameStates().dependencies.escape.reset();
|
game.getGameStates().dependencies.escape.reset();
|
||||||
|
screenRenderer.render(game);
|
||||||
}
|
}
|
||||||
screenRenderer.render(game);
|
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import cz.jzitnik.game.sprites.ui.Font.*;
|
|||||||
import cz.jzitnik.tui.ScreenRenderer;
|
import cz.jzitnik.tui.ScreenRenderer;
|
||||||
import cz.jzitnik.tui.utils.Menu;
|
import cz.jzitnik.tui.utils.Menu;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the in-game escape menu functionality, including rendering options,
|
* Handles the in-game escape menu functionality, including rendering options,
|
||||||
* handling mouse input, and managing save and exit logic.
|
* handling mouse input, and managing save and exit logic.
|
||||||
@ -22,7 +24,7 @@ public class Escape {
|
|||||||
*/
|
*/
|
||||||
public Escape(Game game) {
|
public Escape(Game game) {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
this.menu = new Menu(game, "2DCraft", new String[] { "Continue", "Options", "Save and exit" },
|
this.menu = new Menu(game, "2DCraft", new String[]{"Continue", "Options", "Save and exit"},
|
||||||
this::onButtonClick);
|
this::onButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +76,15 @@ public class Escape {
|
|||||||
game.getGameStates().dependencies.gameSaver.save(game);
|
game.getGameStates().dependencies.gameSaver.save(game);
|
||||||
game.setWindow(Window.SAVED);
|
game.setWindow(Window.SAVED);
|
||||||
screenRenderer.render(game);
|
screenRenderer.render(game);
|
||||||
|
|
||||||
|
Terminal terminal = game.getContext(Terminal.class);
|
||||||
|
terminal.trackMouse(Terminal.MouseTracking.Off);
|
||||||
|
try {
|
||||||
|
terminal.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -99,8 +110,8 @@ public class Escape {
|
|||||||
/**
|
/**
|
||||||
* Callback for when a button in the escape menu is clicked.
|
* Callback for when a button in the escape menu is clicked.
|
||||||
*
|
*
|
||||||
* @param index The index of the clicked button (0 = Continue, 1 = Options, 2 = Save and exit).
|
* @param index The index of the clicked button (0 = Continue, 1 = Options, 2 = Save and exit).
|
||||||
* @param screenRenderer The screen renderer used to refresh the display.
|
* @param screenRenderer The screen renderer used to refresh the display.
|
||||||
*/
|
*/
|
||||||
public void renderSaved(StringBuilder buffer, Terminal terminal) {
|
public void renderSaved(StringBuilder buffer, Terminal terminal) {
|
||||||
var font = game.getGameStates().dependencies.font;
|
var font = game.getGameStates().dependencies.font;
|
||||||
|
@ -6,6 +6,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import org.jline.terminal.MouseEvent;
|
import org.jline.terminal.MouseEvent;
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -171,17 +172,14 @@ public class MouseHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (game.isMineable(blockX, blockY, terminal)) {
|
if (game.isMineable(blockX, blockY, terminal)) {
|
||||||
List<Integer> list = new ArrayList<>();
|
|
||||||
list.add(blockX);
|
|
||||||
list.add(blockY);
|
|
||||||
|
|
||||||
if (screenRenderer.getSelectedBlock().isPresent()
|
if (screenRenderer.getSelectedBlock().isPresent()
|
||||||
&& screenRenderer.getSelectedBlock().get().get(0).equals(blockX)
|
&& screenRenderer.getSelectedBlock().get().x == blockX
|
||||||
&& screenRenderer.getSelectedBlock().get().get(1).equals(blockY)) {
|
&& screenRenderer.getSelectedBlock().get().y == blockY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
screenRenderer.setSelectedBlock(Optional.of(list));
|
screenRenderer.setSelectedBlock(Optional.of(new Point(blockX, blockY)));
|
||||||
} else {
|
} else {
|
||||||
if (screenRenderer.getSelectedBlock().isEmpty()) {
|
if (screenRenderer.getSelectedBlock().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -8,6 +8,7 @@ import cz.jzitnik.game.sprites.SimpleSprite;
|
|||||||
import cz.jzitnik.game.blocks.Chest;
|
import cz.jzitnik.game.blocks.Chest;
|
||||||
import cz.jzitnik.game.blocks.Furnace;
|
import cz.jzitnik.game.blocks.Furnace;
|
||||||
import cz.jzitnik.game.ui.Healthbar;
|
import cz.jzitnik.game.ui.Healthbar;
|
||||||
|
import cz.jzitnik.game.ui.Window;
|
||||||
import cz.jzitnik.tui.utils.SpriteCombiner;
|
import cz.jzitnik.tui.utils.SpriteCombiner;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -15,6 +16,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -28,6 +30,7 @@ public class ScreenRenderer {
|
|||||||
private final SpriteList spriteList;
|
private final SpriteList spriteList;
|
||||||
private final Terminal terminal;
|
private final Terminal terminal;
|
||||||
private boolean rendering = false;
|
private boolean rendering = false;
|
||||||
|
private Window currentlyRenderingWindow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@code ScreenRenderer} with the given sprite list and terminal.
|
* Constructs a {@code ScreenRenderer} with the given sprite list and terminal.
|
||||||
@ -45,7 +48,7 @@ public class ScreenRenderer {
|
|||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private Optional<List<Integer>> selectedBlock = Optional.empty();
|
private Optional<Point> selectedBlock = Optional.empty();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the coordinates of the player's lower or upper body in the world array.
|
* Finds the coordinates of the player's lower or upper body in the world array.
|
||||||
@ -53,7 +56,7 @@ public class ScreenRenderer {
|
|||||||
* @param world The 2D world array of blocks.
|
* @param world The 2D world array of blocks.
|
||||||
* @return Integer array of coordinates [x, y], or null if player not found.
|
* @return Integer array of coordinates [x, y], or null if player not found.
|
||||||
*/
|
*/
|
||||||
private int[] getPlayerCords(List<Block>[][] world) {
|
private Point getPlayerCords(List<Block>[][] world) {
|
||||||
for (int i = 0; i < world.length; i++) {
|
for (int i = 0; i < world.length; i++) {
|
||||||
for (int j = 0; j < world[i].length; j++) {
|
for (int j = 0; j < world[i].length; j++) {
|
||||||
var steve = world[i][j].stream().filter(x -> x.getBlockId().equals("steve")).findFirst();
|
var steve = world[i][j].stream().filter(x -> x.getBlockId().equals("steve")).findFirst();
|
||||||
@ -61,9 +64,9 @@ public class ScreenRenderer {
|
|||||||
var steveData = (SteveData) steve.get().getData();
|
var steveData = (SteveData) steve.get().getData();
|
||||||
|
|
||||||
if (steveData.isTop()) {
|
if (steveData.isTop()) {
|
||||||
return new int[] { j, i + 1 };
|
return new Point(j, i + 1);
|
||||||
} else {
|
} else {
|
||||||
return new int[] { j, i };
|
return new Point(j, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,11 +101,12 @@ public class ScreenRenderer {
|
|||||||
*
|
*
|
||||||
* @param game Current game state to render.
|
* @param game Current game state to render.
|
||||||
*/
|
*/
|
||||||
public synchronized void render(Game game) {
|
public void render(Game game) {
|
||||||
if (rendering) {
|
if (rendering && game.getWindow() == currentlyRenderingWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rendering = true;
|
rendering = true;
|
||||||
|
currentlyRenderingWindow = game.getWindow();
|
||||||
log.debug("Rendering frame");
|
log.debug("Rendering frame");
|
||||||
var world = game.getWorld();
|
var world = game.getWorld();
|
||||||
StringBuilder main = new StringBuilder();
|
StringBuilder main = new StringBuilder();
|
||||||
@ -126,12 +130,12 @@ public class ScreenRenderer {
|
|||||||
case WORLD -> {
|
case WORLD -> {
|
||||||
// World
|
// World
|
||||||
|
|
||||||
int[] cords = getPlayerCords(world);
|
Point cords = getPlayerCords(world);
|
||||||
if (cords == null)
|
if (cords == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int playerX = cords[0];
|
int playerX = cords.x;
|
||||||
int playerY = cords[1];
|
int playerY = cords.y;
|
||||||
|
|
||||||
int terminalWidth = terminal.getWidth();
|
int terminalWidth = terminal.getWidth();
|
||||||
int terminalHeight = terminal.getHeight();
|
int terminalHeight = terminal.getHeight();
|
||||||
@ -168,8 +172,8 @@ public class ScreenRenderer {
|
|||||||
.map(block -> getTexture(block, spriteList, game))
|
.map(block -> getTexture(block, spriteList, game))
|
||||||
.toList());
|
.toList());
|
||||||
|
|
||||||
if (selectedBlock.isPresent() && selectedBlock.get().get(0) == x
|
if (selectedBlock.isPresent() && selectedBlock.get().x == x
|
||||||
&& selectedBlock.get().get(1) == y) {
|
&& selectedBlock.get().y == y) {
|
||||||
StringBuilder stringBuilder = getStringBuilder();
|
StringBuilder stringBuilder = getStringBuilder();
|
||||||
|
|
||||||
sprites.add(stringBuilder.toString());
|
sprites.add(stringBuilder.toString());
|
||||||
|
Reference in New Issue
Block a user