feat: Implemented growing

This commit is contained in:
Jakub Žitník 2025-03-21 10:18:13 +01:00
parent 9fc72a67ec
commit bffee19583
Signed by: jzitnik
GPG Key ID: C577A802A6AF4EF3
14 changed files with 191 additions and 29 deletions

View File

@ -394,7 +394,7 @@ public class Game extends AutoTransientSupport {
Item item = inventory.getItemInHand().get();
CustomPlaceHandler placeHandler = gameStates.dependencies.placeHandler.get(item.getId());
CustomPlaceHandler placeHandler = gameStates.dependencies.placeHandler.get(item.getBlock().get().getBlockId());
var blocksRemove = blocks.stream().filter(block -> block.getClass().isAnnotationPresent(BreaksByPlace.class))
.toList();

View File

@ -158,6 +158,9 @@ public class SpriteLoader {
LAVA_BUCKET,
MILK_BUCKET,
// Seeds
WHEAT,
// Food
ITEM_PORKCHOP,
ITEM_COOKED_PORKCHOP,
@ -248,6 +251,9 @@ public class SpriteLoader {
SPRITES_MAP.put(SPRITES.HEART, new Heart());
SPRITES_MAP.put(SPRITES.HUNGER, new Hunger());
// SEEDS
SPRITES_MAP.put(SPRITES.WHEAT, new Farmable("dirt.ans", "grass.ans", "sand.ans"));
// ITEMS
// Items
@ -339,8 +345,6 @@ public class SpriteLoader {
SPRITES_MAP.put(SPRITES.ITEM_BEEF, new SimpleSprite("items/beef.ans"));
SPRITES_MAP.put(SPRITES.ITEM_STEAK, new SimpleSprite("items/steak.ans"));
SPRITES_MAP.put(SPRITES.ITEM_APPLE, new SimpleSprite("items/apple.ans"));
}
public static SpriteList<SPRITES> load() {

View 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;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RequireAnnotation(BlockRegistry.class)
public @interface ResetSpriteStateOnMine {
}

View File

@ -70,6 +70,10 @@ public class Block implements Serializable {
this.spriteState = MyOptional.of(spriteState);
}
public void setSpriteState() {
this.spriteState = MyOptional.empty();
}
public double calculateHardness(Inventory inventory) {
double holdingDecrease = 0;
if (inventory.getItemInHand().isPresent() && tool.isPresent()

View File

@ -3,16 +3,20 @@ 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.PlaceOnSolidNoHandler;
import cz.jzitnik.game.annotations.ResetDataOnMine;
import cz.jzitnik.game.annotations.ResetSpriteStateOnMine;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.logic.services.farmable.FarmableData;
@ResetDataOnMine
@Farmable
@BlockRegistry("wheat")
@PlaceOnSolidNoHandler
@ResetDataOnMine
@ResetSpriteStateOnMine
@BlockRegistry(value = "wheat", drops = "wheat_seeds")
public class WheatBlock extends Block {
public WheatBlock() {
super("weat", SpriteLoader.SPRITES.OAK_SAPLING, 0);
super("wheat", SpriteLoader.SPRITES.WHEAT, 0);
setData(new FarmableData());
setGhost(true);
}

View File

@ -5,9 +5,9 @@ import cz.jzitnik.game.annotations.ItemRegistry;
import cz.jzitnik.game.entities.items.Item;
import cz.jzitnik.game.entities.items.ItemType;
@ItemRegistry(value = "wheat_seeds", block = "grass_bush")
@ItemRegistry(value = "wheat_seeds", block = "wheat")
public class WheatSeedsItem extends Item {
public WheatSeedsItem() {
super("wheat_seeds", "Wheat seeds", ItemType.USELESS_ITEM, SpriteLoader.SPRITES.ITEM_WHEAT_SEEDS);
super("wheat_seeds", "Wheat seeds", ItemType.BLOCK, SpriteLoader.SPRITES.ITEM_WHEAT_SEEDS);
}
}

View File

@ -36,6 +36,7 @@ public class Generation {
game.getInventory().addItem(ItemBlockSupplier.getItem("wooden_hoe"));
game.getInventory().addItem(ItemBlockSupplier.getItem("water_bucket"));
game.getInventory().addItem(ItemBlockSupplier.getItem("wheat_seeds"));
}
private static void initializeWorld(List<Block>[][] world) {

View File

@ -15,7 +15,8 @@ public class CustomAnnotationHandler implements CustomPlaceHandler {
private final Class<?> clazz;
private final DefaultPlaceHandler defaultPlaceHandler = new DefaultPlaceHandler();
private record BlockDrop(String drops, int percentage) {}
private record BlockDrop(String drops, int percentage) {
}
public CustomAnnotationHandler(Class<?> clazz) {
this.clazz = clazz;
@ -28,7 +29,11 @@ public class CustomAnnotationHandler implements CustomPlaceHandler {
if (clazz.isAnnotationPresent(PlaceOnSolid.class)) {
place = placeOnSolid(game, x, y);
}
if (place && clazz.isAnnotationPresent(Farmable.class)) {
place = placeFarmable(game, x, y);
}
if (place && clazz.isAnnotationPresent(TwoblockBlock.class)) {
var blocksTop = game.getWorld()[y - 1][x];
if (!blocksTop.stream().allMatch(block -> block.getBlockId().equals("air"))) {
@ -53,12 +58,10 @@ public class CustomAnnotationHandler implements CustomPlaceHandler {
inventory.decreaseItemInHand();
customPlace = true;
return true;
}
if (!customPlace && place) {
return defaultPlaceHandler.place(game, x, y);
}
@ -72,19 +75,27 @@ public class CustomAnnotationHandler implements CustomPlaceHandler {
resetDataOnMine(game, x, y);
}
if (clazz.isAnnotationPresent(ResetSpriteStateOnMine.class)) {
var blocks = game.getWorld()[y][x];
var blockx = blocks.stream().filter(block -> !block.getBlockId().equals("air")).findFirst().get();
blockx.setSpriteState();
}
boolean dropDefault = true;
if (clazz.isAnnotationPresent(CustomDrops.class) || clazz.isAnnotationPresent(CustomDrop.class)) {
var annotations = clazz.isAnnotationPresent(CustomDrops.class) ?
clazz.getAnnotation(CustomDrops.class).value() :
new CustomDrop[] { clazz.getAnnotation(CustomDrop.class) };
var annotations = clazz.isAnnotationPresent(CustomDrops.class)
? clazz.getAnnotation(CustomDrops.class).value()
: new CustomDrop[] { clazz.getAnnotation(CustomDrop.class) };
var hashmap = new HashMap<String, BlockDrop>();
for (CustomDrop customDrop : annotations) {
hashmap.put(customDrop.tool(), new BlockDrop(customDrop.drops(), customDrop.percentage()));
}
if (game.getInventory().getItemInHand().isPresent() && hashmap.containsKey(game.getInventory().getItemInHand().get().getId())) {
if (game.getInventory().getItemInHand().isPresent()
&& hashmap.containsKey(game.getInventory().getItemInHand().get().getId())) {
BlockDrop blockDrop = hashmap.get(game.getInventory().getItemInHand().get().getId());
Random random = new Random();
int num = random.nextInt(100);
@ -103,10 +114,12 @@ public class CustomAnnotationHandler implements CustomPlaceHandler {
if (clazz.isAnnotationPresent(TwoblockBlock.class)) {
var blocksTop = game.getWorld()[y - 1][x];
if (blocksTop.stream().anyMatch(i -> !i.getBlockId().equals("air") && !i.isMob())) {
blocksTop.removeAll(blocksTop.stream().filter(i -> !i.getBlockId().equals("air") && !i.isMob()).toList());
blocksTop.removeAll(
blocksTop.stream().filter(i -> !i.getBlockId().equals("air") && !i.isMob()).toList());
} else {
var blocksBottom = game.getWorld()[y + 1][x];
blocksBottom.removeAll(blocksBottom.stream().filter(i -> !i.getBlockId().equals("air") && !i.isMob()).toList());
blocksBottom.removeAll(
blocksBottom.stream().filter(i -> !i.getBlockId().equals("air") && !i.isMob()).toList());
}
}
@ -133,6 +146,17 @@ public class CustomAnnotationHandler implements CustomPlaceHandler {
return true;
}
private boolean placeFarmable(Game game, int x, int y) {
var blocksBottom = game.getWorld()[y + 1][x];
System.out.println("lol");
if (blocksBottom.stream().noneMatch(block -> block.getBlockId().equals("farmland"))) {
return false;
}
return true;
}
private void resetDataOnMine(Game game, int x, int y) {
var blocks = game.getWorld()[y][x].stream().filter(i -> !i.getBlockId().equals("air")).toList();
@ -145,8 +169,9 @@ public class CustomAnnotationHandler implements CustomPlaceHandler {
Constructor<?> constructor = block.getData().getClass().getDeclaredConstructor();
Object object = constructor.newInstance();
block.setData(object);
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
InvocationTargetException _) {
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException
| InvocationTargetException e) {
e.printStackTrace();
}
}
}

View File

@ -59,15 +59,15 @@ public class PlaceHandler {
for (Class<?> clazz : blocks) {
var annotation = clazz.getAnnotation(BlockRegistry.class);
var id = annotation.value();
if (clazz.isAnnotationPresent(PlaceOnSolid.class) || clazz.isAnnotationPresent(ResetDataOnMine.class) || clazz.isAnnotationPresent(BlockDropPercentage.class) || clazz.isAnnotationPresent(CustomDrops.class) || clazz.isAnnotationPresent(CustomDrop.class)) {
try {
placeHandlerList.put(id, new CustomAnnotationHandler(clazz));
} catch (Exception e) {
e.printStackTrace();
}
if (clazz.isAnnotationPresent(PlaceOnSolid.class) || clazz.isAnnotationPresent(ResetDataOnMine.class)
|| clazz.isAnnotationPresent(BlockDropPercentage.class)
|| clazz.isAnnotationPresent(CustomDrops.class) || clazz.isAnnotationPresent(CustomDrop.class)
|| clazz.isAnnotationPresent(TwoblockBlock.class) || clazz.isAnnotationPresent(ResetSpriteStateOnMine.class)) {
placeHandlerList.put(id, new CustomAnnotationHandler(clazz));
}
if (clazz.isAnnotationPresent(PlaceOnSolid.class) || clazz.isAnnotationPresent(PlaceOnSolidNoHandler.class)) {
if (clazz.isAnnotationPresent(PlaceOnSolid.class)
|| clazz.isAnnotationPresent(PlaceOnSolidNoHandler.class)) {
placeOnSolid.add(id);
}
}

View File

@ -1,5 +1,11 @@
package cz.jzitnik.game.logic.services.farmable;
public class FarmableData {
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FarmableData {
private int age = 0;
private int state = 0;
}

View File

@ -0,0 +1,54 @@
package cz.jzitnik.game.logic.services.farmable;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.CustomLogic;
import cz.jzitnik.game.annotations.Farmable;
import cz.jzitnik.game.logic.CustomLogicInterface;
@CustomLogic
public class FarmableLogic implements CustomLogicInterface {
private static int RADIUS = 50;
private static int GROW_LENGTH = 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 y = startY; y <= endY; y++) {
for (int x = startX; x <= endX; x++) {
var blocks = world[y][x];
var farmable = blocks.stream().filter(block -> block.getClass().isAnnotationPresent(Farmable.class)).findFirst();
if (farmable.isEmpty()) {
continue;
}
var farmableBlock = farmable.get();
var farmableData = (FarmableData) farmableBlock.getData();
if (farmableData.getAge() >= GROW_LENGTH) {
if (farmableData.getState() >= 2) {
// Fully grown
continue;
}
farmableData.setState(farmableData.getState() + 1);
farmableData.setAge(0);
farmableBlock.setSpriteState(cz.jzitnik.game.sprites.Farmable.getState(farmableData.getState()));
} else {
farmableData.setAge(farmableData.getAge() + 1);
}
}
}
}
}

View File

@ -2,6 +2,7 @@ package cz.jzitnik.game.logic.services.farmland;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.CustomLogic;
import cz.jzitnik.game.annotations.Farmable;
import cz.jzitnik.game.entities.items.ItemBlockSupplier;
import cz.jzitnik.game.logic.CustomLogicInterface;
import cz.jzitnik.game.sprites.Farmland.FarmlandState;
@ -69,6 +70,8 @@ public class FarmlandLogic implements CustomLogicInterface {
if (farmlandData.getDryAge() >= DRY_TO_DIRT_THRESHOLD) {
blocks.remove(farmland);
blocks.add(ItemBlockSupplier.getBlock("dirt"));
world[y-1][x].removeIf(block -> block.getClass().isAnnotationPresent(Farmable.class));
farmlandData.setDryAge(0);
}
} else {

View File

@ -0,0 +1,49 @@
package cz.jzitnik.game.sprites;
import cz.jzitnik.tui.ResourceLoader;
import cz.jzitnik.tui.Sprite;
import java.util.Optional;
public class Farmable extends Sprite {
private String[] textures;
public Farmable(String first, String second, String third) {
textures = new String[] {first, second, third};
}
public enum FarmableState {
FIRST,
SECOND,
THIRD
}
public String getSprite() {
return getSprite(getState(0));
}
public String getSprite(Enum e) {
return ResourceLoader.loadResource(textures[switch (e) {
case FarmableState.FIRST -> 0;
case FarmableState.SECOND -> 1;
case FarmableState.THIRD -> 2;
default -> throw new IllegalStateException("Unexpected value: " + e);
}]);
}
public static FarmableState getState(int num) {
return switch (num) {
case 0 -> FarmableState.FIRST;
case 1 -> FarmableState.SECOND;
case 2 -> FarmableState.THIRD;
default -> throw new IllegalStateException("Unexpected value: " + num);
};
}
@Override
public Optional<Class<FarmableState>> getStates() {
return Optional.of(FarmableState.class);
}
}

View File

@ -7,5 +7,5 @@ public abstract class Sprite<E extends Enum<E>> {
public abstract String getSprite(E key);
public abstract Optional<Class<Enum>> getStates();
public abstract Optional<Class<E>> getStates();
}