From 59f0a70ea9258f0350b43683ca48dc12316901f5 Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Sat, 8 Mar 2025 18:14:28 +0100 Subject: [PATCH] feat: Implemented grass bush --- .../java/cz/jzitnik/game/SpriteLoader.java | 12 +++++++++ .../game/annotations/BlockDropPercentage.java | 12 +++++++++ .../items/registry/blocks/GrassBushBlock.java | 15 +++++++++++ .../items/registry/items/WheatSeedsItem.java | 13 ++++++++++ .../jzitnik/game/generation/Generation.java | 26 +++++++++++++++++++ .../place/CustomAnnotationHandler.java | 18 ++++++++++++- .../game/handlers/place/PlaceHandler.java | 3 ++- src/main/resources/textures/grass_bush.ans | 25 ++++++++++++++++++ .../resources/textures/items/wheat_seeds.ans | 25 ++++++++++++++++++ .../game/handlers/place/PlaceHandlerTest.java | 14 ++++++++++ 10 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 src/main/java/cz/jzitnik/game/annotations/BlockDropPercentage.java create mode 100644 src/main/java/cz/jzitnik/game/entities/items/registry/blocks/GrassBushBlock.java create mode 100644 src/main/java/cz/jzitnik/game/entities/items/registry/items/WheatSeedsItem.java create mode 100644 src/main/resources/textures/grass_bush.ans create mode 100644 src/main/resources/textures/items/wheat_seeds.ans diff --git a/src/main/java/cz/jzitnik/game/SpriteLoader.java b/src/main/java/cz/jzitnik/game/SpriteLoader.java index 12d331e..187072e 100644 --- a/src/main/java/cz/jzitnik/game/SpriteLoader.java +++ b/src/main/java/cz/jzitnik/game/SpriteLoader.java @@ -14,6 +14,9 @@ public class SpriteLoader { // Blocks AIR, WATER, LAVA, DIRT, GRASS, STONE, BEDROCK, COBBLESTONE, WOOL, OAK_LOG, OAK_LEAF, OAK_PLANKS, OAK_DOOR, OBSIDIAN, + // Flowers etc + GRASS_BUSH, + // Ores COAL_ORE, IRON_ORE, GOLD_ORE, DIAMOND_ORE, @@ -63,6 +66,9 @@ public class SpriteLoader { BUCKET, WATER_BUCKET, LAVA_BUCKET, MILK_BUCKET, // Food ITEM_PORKCHOP, ITEM_COOKED_PORKCHOP, ITEM_MUTTON, ITEM_COOKED_MUTTON, ITEM_BEEF, ITEM_STEAK, ITEM_APPLE, + + // Seeds + ITEM_WHEAT_SEEDS, } public static final HashMap SPRITES_MAP = new HashMap<>(); @@ -86,6 +92,9 @@ public class SpriteLoader { SPRITES_MAP.put(SPRITES.COBBLESTONE, new SimpleSprite("cobblestone.ans")); SPRITES_MAP.put(SPRITES.OBSIDIAN, new SimpleSprite("obsidian.ans")); + // Flowers etc. + SPRITES_MAP.put(SPRITES.GRASS_BUSH, new SimpleSprite("grass_bush.ans")); + // Ores SPRITES_MAP.put(SPRITES.COAL_ORE, new SimpleSprite("coal_ore.ans")); SPRITES_MAP.put(SPRITES.IRON_ORE, new SimpleSprite("iron_ore.ans")); @@ -200,6 +209,9 @@ 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")); + + // Seeds + SPRITES_MAP.put(SPRITES.ITEM_WHEAT_SEEDS, new SimpleSprite("items/wheat_seeds.ans")); } public static SpriteList load() { diff --git a/src/main/java/cz/jzitnik/game/annotations/BlockDropPercentage.java b/src/main/java/cz/jzitnik/game/annotations/BlockDropPercentage.java new file mode 100644 index 0000000..71a4a18 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/annotations/BlockDropPercentage.java @@ -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) +public @interface BlockDropPercentage { + int value(); +} diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/GrassBushBlock.java b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/GrassBushBlock.java new file mode 100644 index 0000000..f827303 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/GrassBushBlock.java @@ -0,0 +1,15 @@ +package cz.jzitnik.game.entities.items.registry.blocks; + +import cz.jzitnik.game.SpriteLoader; +import cz.jzitnik.game.annotations.BlockDropPercentage; +import cz.jzitnik.game.annotations.BlockRegistry; +import cz.jzitnik.game.entities.Block; + +@BlockDropPercentage(100) +@BlockRegistry(value = "grass_bush", drops = "wheat_seeds") +public class GrassBushBlock extends Block { + public GrassBushBlock() { + super("grass_bush", SpriteLoader.SPRITES.GRASS_BUSH, 0); + setGhost(true); + } +} diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/items/WheatSeedsItem.java b/src/main/java/cz/jzitnik/game/entities/items/registry/items/WheatSeedsItem.java new file mode 100644 index 0000000..c349160 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/items/WheatSeedsItem.java @@ -0,0 +1,13 @@ +package cz.jzitnik.game.entities.items.registry.items; + +import cz.jzitnik.game.SpriteLoader; +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") +public class WheatSeedsItem extends Item { + public WheatSeedsItem() { + super("wheat_seeds", "Wheat seeds", ItemType.USELESS_ITEM, SpriteLoader.SPRITES.ITEM_WHEAT_SEEDS); + } +} diff --git a/src/main/java/cz/jzitnik/game/generation/Generation.java b/src/main/java/cz/jzitnik/game/generation/Generation.java index d8d4f0d..d79d4f0 100644 --- a/src/main/java/cz/jzitnik/game/generation/Generation.java +++ b/src/main/java/cz/jzitnik/game/generation/Generation.java @@ -63,11 +63,17 @@ public class Generation { } private static void populateWorld(List[][] world, int[] terrainHeight) { + Random random = new Random(); + for (int i = 0; i < 512; i++) { int hillHeight = terrainHeight[i]; world[hillHeight][i].add(ItemBlockSupplier.getBlock("grass")); + if (random.nextDouble() < 0.1 && !isTreeNearby(world, i, hillHeight)) { + world[hillHeight - 1][i].add(ItemBlockSupplier.getBlock("grass_bush")); + } + for (int j = 1; j <= 4; j++) { if (hillHeight + j < 256) { world[hillHeight + j][i].add(ItemBlockSupplier.getBlock("dirt")); @@ -81,6 +87,7 @@ public class Generation { world[255][i].add(new Block("bedrock", SpriteLoader.SPRITES.BEDROCK)); } + // Fill air blocks for (List[] lists : world) { for (List list : lists) { list.addFirst(new Block("air", SpriteLoader.SPRITES.AIR, true, false)); @@ -88,6 +95,25 @@ public class Generation { } } + private static boolean isTreeNearby(List[][] world, int x, int y) { + int radius = 3; // Check within a 3-block radius for trees + for (int dx = -radius; dx <= radius; dx++) { + for (int dy = -radius; dy <= radius; dy++) { + int nx = x + dx; + int ny = y + dy; + if (nx >= 0 && nx < 512 && ny >= 0 && ny < 256) { + for (Block block : world[ny][nx]) { + if (block.getBlockId().equals("oak_log") || block.getBlockId().equals("oak_leaves")) { + return true; + } + } + } + } + } + return false; + } + + private static void plantTrees(List[][] world, int[] terrainHeight) { Random random = new Random(); for (int i = 10; i < 502; i += random.nextInt(20) + 20) { diff --git a/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java b/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java index b6a5c97..01d5f28 100644 --- a/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java +++ b/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java @@ -1,12 +1,14 @@ package cz.jzitnik.game.handlers.place; import cz.jzitnik.game.Game; +import cz.jzitnik.game.annotations.BlockDropPercentage; import cz.jzitnik.game.annotations.PlaceOnSolid; import cz.jzitnik.game.annotations.ResetDataOnMine; import cz.jzitnik.game.entities.Block; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.Random; public class CustomAnnotationHandler implements CustomPlaceHandler { private final Class clazz; @@ -31,10 +33,24 @@ public class CustomAnnotationHandler implements CustomPlaceHandler { resetDataOnMine(game, x, y); } - return defaultPlaceHandler.mine(game, x, y); + boolean drop = true; + + if (clazz.isAnnotationPresent(BlockDropPercentage.class)) { + drop = blockDropPercentage(game, x, y); + } + + defaultPlaceHandler.mine(game, x, y); + + return drop; } + private boolean blockDropPercentage(Game game, int x, int y) { + var annotation = clazz.getAnnotation(BlockDropPercentage.class); + int percentage = annotation.value(); + Random random = new Random(); + return random.nextInt(100) < percentage; + } private boolean placeOnSolid(Game game, int x, int y) { var blocksBottom = game.getWorld()[y + 1][x]; 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 9292e8e..cd3c6f0 100644 --- a/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java +++ b/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java @@ -3,6 +3,7 @@ package cz.jzitnik.game.handlers.place; import java.util.HashMap; import java.util.Set; +import cz.jzitnik.game.annotations.BlockDropPercentage; import cz.jzitnik.game.annotations.BlockRegistry; import cz.jzitnik.game.annotations.PlaceOnSolid; import cz.jzitnik.game.annotations.ResetDataOnMine; @@ -52,7 +53,7 @@ public class PlaceHandler { .getTypesAnnotatedWith(BlockRegistry.class); for (Class clazz : blocks) { - if (clazz.isAnnotationPresent(PlaceOnSolid.class) || clazz.isAnnotationPresent(ResetDataOnMine.class)) { + if (clazz.isAnnotationPresent(PlaceOnSolid.class) || clazz.isAnnotationPresent(ResetDataOnMine.class) || clazz.isAnnotationPresent(BlockDropPercentage.class)) { try { var annotation = clazz.getAnnotation(BlockRegistry.class); var id = annotation.value(); diff --git a/src/main/resources/textures/grass_bush.ans b/src/main/resources/textures/grass_bush.ans new file mode 100644 index 0000000..f79c9c0 --- /dev/null +++ b/src/main/resources/textures/grass_bush.ans @@ -0,0 +1,25 @@ +                                                   +                                                   +                                                   +                                            +                                            +                                             +                                          +                                           +                                      +                                     +                                     +                                     +                                   +                                   +                                   +                                    +                                  +                                +                                +                        +                         +                       +                        +                          +                         diff --git a/src/main/resources/textures/items/wheat_seeds.ans b/src/main/resources/textures/items/wheat_seeds.ans new file mode 100644 index 0000000..ba55ce2 --- /dev/null +++ b/src/main/resources/textures/items/wheat_seeds.ans @@ -0,0 +1,25 @@ +                                                   +                                                   +                                                   +                                                   +                                                   +                                                   +                                               +                                               +                                                 +                                             +                                             +                                      +                                    +                                       +                                            +                                            +                                       +                                           +                                           +                                              +                                                   +                                                   +                                                   +                                                   +                                                   diff --git a/src/test/java/cz/jzitnik/game/handlers/place/PlaceHandlerTest.java b/src/test/java/cz/jzitnik/game/handlers/place/PlaceHandlerTest.java index b7b2b25..ad3c863 100644 --- a/src/test/java/cz/jzitnik/game/handlers/place/PlaceHandlerTest.java +++ b/src/test/java/cz/jzitnik/game/handlers/place/PlaceHandlerTest.java @@ -1,5 +1,6 @@ package cz.jzitnik.game.handlers.place; +import cz.jzitnik.game.annotations.BlockDropPercentage; import cz.jzitnik.game.annotations.BlockRegistry; import cz.jzitnik.game.annotations.PlaceOnSolid; import cz.jzitnik.game.annotations.ResetDataOnMine; @@ -68,6 +69,19 @@ class PlaceHandlerTest { } } + @Test + @DisplayName("All blocks annotated with @BlockDropPercentage must be also annotated with @BlockRegistry") + void blockDropPercentageTest() { + Reflections reflections = new Reflections("cz.jzitnik.game.entities.items.registry.blocks"); + Set> handlerClasses = reflections + .getTypesAnnotatedWith(BlockDropPercentage.class); + + for (Class clazz : handlerClasses) { + boolean hasAnnotation = clazz.isAnnotationPresent(BlockRegistry.class); + assertTrue(hasAnnotation, "Class " + clazz.getName() + " is annotated with @BlockDropPercentage but does not have annotation @BlockRegistry"); + } + } + @Test @DisplayName("All blocks annotated with @ResetDataOnMine must have data class with default constructor") void dataOnMineHasDataTest() {