feat: Implemented farmland
This commit is contained in:
@ -375,7 +375,15 @@ public class Game extends AutoTransientSupport {
|
||||
|
||||
if (!blocks.stream().allMatch(block -> block.getBlockId().equals("air") || block.isFlowing()
|
||||
|| block.getClass().isAnnotationPresent(BreaksByPlace.class))) {
|
||||
RightClickHandlerProvider.handle(x, y, this, screenRenderer);
|
||||
boolean toolUsed = false;
|
||||
if (inventory.getItemInHand().isPresent()) {
|
||||
var item = inventory.getItemInHand().get();
|
||||
toolUsed = gameStates.dependencies.toolUseProvider.handle(item.getType(), this, x, y);
|
||||
}
|
||||
|
||||
if (!toolUsed) {
|
||||
RightClickHandlerProvider.handle(x, y, this, screenRenderer);
|
||||
}
|
||||
screenRenderer.render(this);
|
||||
return;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ public class SpriteLoader {
|
||||
WATER,
|
||||
LAVA,
|
||||
DIRT,
|
||||
FARMLAND,
|
||||
GRASS,
|
||||
STONE,
|
||||
BEDROCK,
|
||||
@ -180,6 +181,7 @@ public class SpriteLoader {
|
||||
SPRITES_MAP.put(SPRITES.WATER, new Water());
|
||||
SPRITES_MAP.put(SPRITES.LAVA, new Lava());
|
||||
SPRITES_MAP.put(SPRITES.DIRT, new SimpleSprite("dirt.ans"));
|
||||
SPRITES_MAP.put(SPRITES.FARMLAND, new Farmland());
|
||||
SPRITES_MAP.put(SPRITES.GRASS, new SimpleSprite("grass.ans"));
|
||||
SPRITES_MAP.put(SPRITES.STONE, new SimpleSprite("stone.ans"));
|
||||
SPRITES_MAP.put(SPRITES.BEDROCK, new SimpleSprite("bedrock.ans"));
|
||||
|
11
src/main/java/cz/jzitnik/game/annotations/Farmable.java
Normal file
11
src/main/java/cz/jzitnik/game/annotations/Farmable.java
Normal file
@ -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 Farmable {
|
||||
}
|
15
src/main/java/cz/jzitnik/game/annotations/ToolUse.java
Normal file
15
src/main/java/cz/jzitnik/game/annotations/ToolUse.java
Normal file
@ -0,0 +1,15 @@
|
||||
package cz.jzitnik.game.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import cz.jzitnik.game.entities.items.ItemType;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ToolUse {
|
||||
ItemType value();
|
||||
}
|
@ -4,6 +4,7 @@ import cz.jzitnik.game.GameSaver;
|
||||
import cz.jzitnik.game.handlers.events.EventHandlerProvider;
|
||||
import cz.jzitnik.game.handlers.pickup.PickupHandlerProvider;
|
||||
import cz.jzitnik.game.handlers.place.PlaceHandler;
|
||||
import cz.jzitnik.game.handlers.tooluse.ToolUseProvider;
|
||||
import cz.jzitnik.game.mobs.EntityHurtAnimation;
|
||||
import cz.jzitnik.game.mobs.EntityKill;
|
||||
import cz.jzitnik.game.smelting.Smelting;
|
||||
@ -16,4 +17,5 @@ public class Dependencies {
|
||||
public GameSaver gameSaver = new GameSaver();
|
||||
public EventHandlerProvider eventHandlerProvider = new EventHandlerProvider();
|
||||
public Smelting smelting = new Smelting();
|
||||
public ToolUseProvider toolUseProvider = new ToolUseProvider();
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package cz.jzitnik.game.entities.items.registry.blocks.blocks;
|
||||
|
||||
import cz.jzitnik.game.SpriteLoader;
|
||||
import cz.jzitnik.game.annotations.BlockRegistry;
|
||||
import cz.jzitnik.game.annotations.ResetDataOnMine;
|
||||
import cz.jzitnik.game.entities.Block;
|
||||
import cz.jzitnik.game.entities.items.ItemType;
|
||||
import cz.jzitnik.game.logic.services.farmland.FarmlandData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ResetDataOnMine
|
||||
@BlockRegistry(value = "farmland", drops = "dirt")
|
||||
public class FarmlandBlock extends Block {
|
||||
public FarmlandBlock() {
|
||||
super("farmland", SpriteLoader.SPRITES.FARMLAND, 1, ItemType.SHOVEL, new ArrayList<>());
|
||||
setData(new FarmlandData());
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package cz.jzitnik.game.entities.items.registry.blocks.grassy;
|
||||
|
||||
import cz.jzitnik.game.SpriteLoader;
|
||||
import cz.jzitnik.game.annotations.BlockRegistry;
|
||||
import cz.jzitnik.game.annotations.Farmable;
|
||||
import cz.jzitnik.game.annotations.ResetDataOnMine;
|
||||
import cz.jzitnik.game.entities.Block;
|
||||
import cz.jzitnik.game.logic.services.farmable.FarmableData;
|
||||
|
||||
@ResetDataOnMine
|
||||
@Farmable
|
||||
@BlockRegistry("wheat")
|
||||
public class WheatBlock extends Block {
|
||||
public WheatBlock() {
|
||||
super("weat", SpriteLoader.SPRITES.OAK_SAPLING, 0);
|
||||
setData(new FarmableData());
|
||||
setGhost(true);
|
||||
}
|
||||
}
|
@ -34,10 +34,8 @@ public class Generation {
|
||||
world[terrainHeight[256] - 1][256].add(steveBlock2);
|
||||
world[terrainHeight[256] - 2][256].add(steveBlock);
|
||||
|
||||
game.getInventory().addItem(ItemBlockSupplier.getItem("furnace"));
|
||||
game.getInventory().addItem(ItemBlockSupplier.getItem("coal"));
|
||||
game.getInventory().addItem(ItemBlockSupplier.getItem("oak_log"));
|
||||
game.getInventory().addItem(ItemBlockSupplier.getItem("diamond_pickaxe"));
|
||||
game.getInventory().addItem(ItemBlockSupplier.getItem("wooden_hoe"));
|
||||
game.getInventory().addItem(ItemBlockSupplier.getItem("water_bucket"));
|
||||
}
|
||||
|
||||
private static void initializeWorld(List<Block>[][] world) {
|
||||
|
@ -1,49 +0,0 @@
|
||||
package cz.jzitnik.game.handlers;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.Scanners;
|
||||
import org.reflections.util.ConfigurationBuilder;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
import cz.jzitnik.game.annotations.MineEventHandler;
|
||||
|
||||
public class BreakBlockActionProvider {
|
||||
private HashMap<String, Function<Game, Void>> actions = new HashMap<>();
|
||||
|
||||
public BreakBlockActionProvider() {
|
||||
register();
|
||||
}
|
||||
|
||||
private void register() {
|
||||
Reflections reflections = new Reflections(
|
||||
new ConfigurationBuilder()
|
||||
.forPackage("cz.jzitnik.game.handlers.events.handlers.mine")
|
||||
.addScanners(Scanners.MethodsAnnotated)
|
||||
);
|
||||
Set<Method> mineHandlers = reflections.getMethodsAnnotatedWith(MineEventHandler.class);
|
||||
|
||||
for (Method method : mineHandlers) {
|
||||
if (method.getParameterCount() == 1 &&
|
||||
method.getParameterTypes()[0] == Game.class)
|
||||
try {
|
||||
Object instance = method.getDeclaringClass().getDeclaredConstructor().newInstance();
|
||||
Function<ScreenRenderer, Game, Integer, Integer> handler = (screenRenderer, game, x, y) -> {
|
||||
try {
|
||||
method.invoke(instance, screenRenderer, game, x, y);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
this.mineHandlers.add(handler);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ public class EventHandlerProvider {
|
||||
private void registerHandlers() {
|
||||
Reflections reflections = new Reflections(
|
||||
new ConfigurationBuilder()
|
||||
.forPackage("cz.jzitnik.game.handlers.events.handlers.mine")
|
||||
.forPackage("cz.jzitnik.game.handlers.events.handlers")
|
||||
.addScanners(Scanners.MethodsAnnotated)
|
||||
);
|
||||
Set<Method> mineHandlers = reflections.getMethodsAnnotatedWith(MineEventHandler.class);
|
||||
|
@ -0,0 +1,23 @@
|
||||
package cz.jzitnik.game.handlers.events.handlers.place;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
import cz.jzitnik.game.annotations.PlaceEventHandler;
|
||||
import cz.jzitnik.game.entities.items.ItemBlockSupplier;
|
||||
import cz.jzitnik.game.handlers.tooluse.handlers.HoeUse;
|
||||
import cz.jzitnik.tui.ScreenRenderer;
|
||||
|
||||
public class FarmlandPlaceHandler {
|
||||
@PlaceEventHandler
|
||||
public void handle(ScreenRenderer screenRenderer, Game game, int x, int y) {
|
||||
var world = game.getWorld();
|
||||
|
||||
if (world[y][x].stream().noneMatch(HoeUse::isBlock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (world[y + 1][x].stream().anyMatch(block -> block.getBlockId().equals("farmland"))) {
|
||||
world[y + 1][x].add(ItemBlockSupplier.getBlock("dirt"));
|
||||
world[y + 1][x].removeIf(block -> block.getBlockId().equals("farmland"));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cz.jzitnik.game.handlers.tooluse;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
|
||||
public interface ToolUseHandler {
|
||||
void handle(Game game, int x, int y);
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package cz.jzitnik.game.handlers.tooluse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
import cz.jzitnik.game.annotations.ToolUse;
|
||||
import cz.jzitnik.game.entities.items.ItemType;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
|
||||
public class ToolUseProvider {
|
||||
public final HashMap<ItemType, ToolUseHandler> handler = new HashMap<>();
|
||||
|
||||
public ToolUseProvider() {
|
||||
registerHandlers();
|
||||
}
|
||||
|
||||
public boolean handle(ItemType itemType, Game game, int x, int y) {
|
||||
if (!handler.containsKey(itemType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.get(itemType).handle(game, x, y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void registerHandlers() {
|
||||
Reflections reflections = new Reflections("cz.jzitnik.game.handlers.tooluse.handlers");
|
||||
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(ToolUse.class);
|
||||
|
||||
for (Class<?> clazz : handlerClasses) {
|
||||
if (ToolUseHandler.class.isAssignableFrom(clazz)) {
|
||||
try {
|
||||
ToolUseHandler handlerInstance = (ToolUseHandler) clazz.getDeclaredConstructor()
|
||||
.newInstance();
|
||||
ToolUse annotation = clazz.getAnnotation(ToolUse.class);
|
||||
ItemType key = annotation.value();
|
||||
handler.put(key, handlerInstance);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package cz.jzitnik.game.handlers.tooluse.handlers;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
import cz.jzitnik.game.annotations.Farmable;
|
||||
import cz.jzitnik.game.annotations.ToolUse;
|
||||
import cz.jzitnik.game.entities.Block;
|
||||
import cz.jzitnik.game.entities.items.ItemBlockSupplier;
|
||||
import cz.jzitnik.game.entities.items.ItemType;
|
||||
import cz.jzitnik.game.handlers.tooluse.ToolUseHandler;
|
||||
|
||||
@ToolUse(ItemType.HOE)
|
||||
public class HoeUse implements ToolUseHandler{
|
||||
|
||||
@Override
|
||||
public void handle(Game game, int x, int y) {
|
||||
var blocks = game.getWorld()[y][x];
|
||||
|
||||
if (!blocks.stream().anyMatch(block -> block.getBlockId().equals("dirt") || block.getBlockId().equals("grass"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (game.getWorld()[y-1][x].stream().anyMatch(block -> isBlock(block))) {
|
||||
return;
|
||||
}
|
||||
|
||||
blocks.removeIf(block -> block.getBlockId().equals("dirt") || block.getBlockId().equals("grass"));
|
||||
blocks.add(ItemBlockSupplier.getBlock("farmland"));
|
||||
}
|
||||
|
||||
public static boolean isBlock(Block block) {
|
||||
return !block.getBlockId().equals("air") && !block.isMob() && !block.getClass().isAnnotationPresent(Farmable.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package cz.jzitnik.game.logic.services.farmable;
|
||||
|
||||
public class FarmableData {
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cz.jzitnik.game.logic.services.farmland;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FarmlandData implements Serializable {
|
||||
private int age = 0;
|
||||
private int dryAge = 0;
|
||||
private boolean watered = false;
|
||||
|
||||
public void increaseAge() {
|
||||
age++;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package cz.jzitnik.game.logic.services.farmland;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
import cz.jzitnik.game.annotations.CustomLogic;
|
||||
import cz.jzitnik.game.entities.items.ItemBlockSupplier;
|
||||
import cz.jzitnik.game.logic.CustomLogicInterface;
|
||||
import cz.jzitnik.game.sprites.Farmland.FarmlandState;
|
||||
|
||||
@CustomLogic
|
||||
public class FarmlandLogic implements CustomLogicInterface {
|
||||
private static final int RADIUS = 50;
|
||||
private static final int WATER_DISTANCE = 4;
|
||||
private static final int DRY_TO_DIRT_THRESHOLD = 11;
|
||||
private static final int AGE_THRESHOLD = 5;
|
||||
|
||||
@Override
|
||||
public void nextIteration(Game game) {
|
||||
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 x = startX; x <= endX; x++) {
|
||||
for (int y = startY; y <= endY; y++) {
|
||||
var blocks = world[y][x];
|
||||
var farmlandOptional = blocks.stream()
|
||||
.filter(block -> block.getBlockId().equals("farmland"))
|
||||
.findFirst();
|
||||
|
||||
if (farmlandOptional.isEmpty()) continue;
|
||||
|
||||
var farmland = farmlandOptional.get();
|
||||
var farmlandData = (FarmlandData) farmland.getData();
|
||||
|
||||
boolean waterNearby = false;
|
||||
|
||||
for (int dx = -WATER_DISTANCE; dx <= WATER_DISTANCE && !waterNearby; dx++) {
|
||||
for (int dy = -WATER_DISTANCE; dy <= WATER_DISTANCE && !waterNearby; dy++) {
|
||||
int checkX = x + dx;
|
||||
int checkY = y + dy;
|
||||
|
||||
if (checkX < 0 || checkX >= world[0].length || checkY < 0 || checkY >= world.length) continue;
|
||||
|
||||
var nearbyBlocks = world[checkY][checkX];
|
||||
if (nearbyBlocks.stream().anyMatch(b -> b.getBlockId().equals("water"))) {
|
||||
waterNearby = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (farmlandData.isWatered() != waterNearby) {
|
||||
farmlandData.setAge(farmlandData.getAge() + 1);
|
||||
if (farmlandData.getAge() >= AGE_THRESHOLD) {
|
||||
farmlandData.setWatered(waterNearby);
|
||||
farmland.setSpriteState(waterNearby ? FarmlandState.WET : FarmlandState.NORMAL);
|
||||
farmlandData.setAge(0);
|
||||
}
|
||||
} else {
|
||||
farmlandData.setAge(0);
|
||||
}
|
||||
|
||||
if (!farmlandData.isWatered()) {
|
||||
farmlandData.setDryAge(farmlandData.getDryAge() + 1);
|
||||
if (farmlandData.getDryAge() >= DRY_TO_DIRT_THRESHOLD) {
|
||||
blocks.remove(farmland);
|
||||
blocks.add(ItemBlockSupplier.getBlock("dirt"));
|
||||
farmlandData.setDryAge(0);
|
||||
}
|
||||
} else {
|
||||
farmlandData.setDryAge(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@ import java.util.*;
|
||||
@CustomLogic
|
||||
public class GrassGrowingLogic implements CustomLogicInterface {
|
||||
private static final int RADIUS = 35;
|
||||
private final Random random = new Random();
|
||||
|
||||
@Override
|
||||
public void nextIteration(Game game) {
|
||||
|
30
src/main/java/cz/jzitnik/game/sprites/Farmland.java
Normal file
30
src/main/java/cz/jzitnik/game/sprites/Farmland.java
Normal file
@ -0,0 +1,30 @@
|
||||
package cz.jzitnik.game.sprites;
|
||||
|
||||
import cz.jzitnik.tui.ResourceLoader;
|
||||
import cz.jzitnik.tui.Sprite;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class Farmland extends Sprite {
|
||||
public enum FarmlandState {
|
||||
NORMAL,
|
||||
WET
|
||||
}
|
||||
|
||||
public String getSprite() {
|
||||
return getSprite(FarmlandState.NORMAL);
|
||||
}
|
||||
|
||||
public String getSprite(Enum e) {
|
||||
return ResourceLoader.loadResource(switch (e) {
|
||||
case FarmlandState.NORMAL -> "farmland.ans";
|
||||
case FarmlandState.WET -> "farmland_wet.ans";
|
||||
default -> throw new IllegalStateException("Unexpected value: " + e);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Class<FarmlandState>> getStates() {
|
||||
return Optional.of(FarmlandState.class);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user