feat: Added cow

This commit is contained in:
Jakub Žitník 2025-03-02 11:54:46 +01:00
parent 632e65c491
commit 6f8e35a9f1
Signed by: jzitnik
GPG Key ID: C577A802A6AF4EF3
12 changed files with 409 additions and 7 deletions

View File

@ -41,6 +41,7 @@ public class SpriteLoader {
STEVE, STEVE,
PIG, PIG,
SHEEP, SHEEP,
COW,
// UI // UI
BREAKING, BREAKING,
@ -147,6 +148,7 @@ public class SpriteLoader {
SPRITES_MAP.put(SPRITES.STEVE, new Steve()); SPRITES_MAP.put(SPRITES.STEVE, new Steve());
SPRITES_MAP.put(SPRITES.PIG, new Pig()); SPRITES_MAP.put(SPRITES.PIG, new Pig());
SPRITES_MAP.put(SPRITES.SHEEP, new Sheep()); SPRITES_MAP.put(SPRITES.SHEEP, new Sheep());
SPRITES_MAP.put(SPRITES.COW, new Cow());
// UI // UI
SPRITES_MAP.put(SPRITES.BREAKING, new Breaking()); SPRITES_MAP.put(SPRITES.BREAKING, new Breaking());
@ -215,13 +217,6 @@ public class SpriteLoader {
SPRITES_MAP.put(SPRITES.ITEM_COOKED_PORKCHOP, new SimpleSprite("items/cooked_porkchop.ans")); SPRITES_MAP.put(SPRITES.ITEM_COOKED_PORKCHOP, new SimpleSprite("items/cooked_porkchop.ans"));
SPRITES_MAP.put(SPRITES.ITEM_MUTTON, new SimpleSprite("items/mutton.ans")); SPRITES_MAP.put(SPRITES.ITEM_MUTTON, new SimpleSprite("items/mutton.ans"));
SPRITES_MAP.put(SPRITES.ITEM_COOKED_MUTTON, new SimpleSprite("items/cooked_mutton.ans")); SPRITES_MAP.put(SPRITES.ITEM_COOKED_MUTTON, new SimpleSprite("items/cooked_mutton.ans"));
} }
public static SpriteList<SPRITES> load() { public static SpriteList<SPRITES> load() {

View File

@ -0,0 +1,16 @@
package cz.jzitnik.game.entities.items.registry.blocks;
import cz.jzitnik.game.SpriteLoader;
import cz.jzitnik.game.annotations.BlockRegistry;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.entities.items.ItemType;
import cz.jzitnik.game.entities.items.ToolVariant;
import java.util.Arrays;
@BlockRegistry("iron_ore")
public class IronOreBlock extends Block {
public IronOreBlock() {
super("iron_ore", SpriteLoader.SPRITES.IRON_ORE, 15, ItemType.PICKAXE, Arrays.stream(ToolVariant.values()).toList());
}
}

View File

@ -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("coal")
public class CoalItem extends Item {
public CoalItem() {
super("coal", "Coal", ItemType.USELESS_ITEM, SpriteLoader.SPRITES.ITEM_COAL_ORE);
}
}

View File

@ -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("iron_ore")
public class IronOreItem extends Item {
public IronOreItem() {
super("iron_ore", "Iron ore", ItemType.BLOCK, SpriteLoader.SPRITES.ITEM_IRON_ORE);
}
}

View File

@ -0,0 +1,19 @@
package cz.jzitnik.game.entities.items.registry.mobs;
import cz.jzitnik.game.SpriteLoader;
import cz.jzitnik.game.annotations.EntityRegistry;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.mobs.services.cow.CowData;
@EntityRegistry("cow")
public class Cow extends Block {
public Cow() {
super("cow", SpriteLoader.SPRITES.COW);
setMob(true);
setGhost(true);
setSpriteState(cz.jzitnik.game.sprites.Cow.CowState.RIGHT);
setMineable(false);
setData(new CowData());
setHp(10);
}
}

View File

@ -0,0 +1,12 @@
package cz.jzitnik.game.mobs.services.cow;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CowData {
private int lastDirection = 1; // 1 = right, -1 = left
private int movementCooldown = 0;
private int jumpAttempts = 0;
}

View File

@ -0,0 +1,205 @@
package cz.jzitnik.game.mobs.services.cow;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.EntityHurtAnimationHandler;
import cz.jzitnik.game.annotations.EntityKillHandler;
import cz.jzitnik.game.annotations.EntityLogic;
import cz.jzitnik.game.annotations.EntitySpawn;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.game.entities.items.ItemBlockSupplier;
import cz.jzitnik.game.mobs.*;
import cz.jzitnik.game.sprites.Cow;
import cz.jzitnik.tui.ScreenMovingCalculationProvider;
import org.jline.terminal.Terminal;
import java.util.*;
import static cz.jzitnik.game.sprites.Cow.CowState.*;
@EntitySpawn
@EntityLogic("cow")
@EntityHurtAnimationHandler("cow")
@EntityKillHandler("cow")
public class CowLogic implements EntityLogicInterface, EntitySpawnInterface, EntityHurtAnimationChanger, EntityKillInterface {
private final Random random = new Random();
@Override
public void nextIteration(EntityLogicProvider.EntityLogicMobDTO entityLogicMobDTO) {
int cowX = entityLogicMobDTO.getX();
int cowY = entityLogicMobDTO.getY();
var game = entityLogicMobDTO.getGame();
var cow = entityLogicMobDTO.getMob();
var world = game.getWorld();
var cowData = (CowData) cow.getData();
boolean updated = false;
int newCowX = cowX;
int newCowY = cowY;
if (cowData.getMovementCooldown() > 0) {
cowData.setMovementCooldown(cowData.getMovementCooldown() - 1);
return;
}
int direction = cowData.getLastDirection();
if (random.nextInt(10) < 1) { // 10% chance to change direction
direction = -direction;
}
cowData.setLastDirection(direction);
if (direction == 1) {
if (cow.getSpriteState().get() == RIGHT_HURT || cow.getSpriteState().get() == LEFT_HURT) {
cow.setSpriteState(RIGHT_HURT);
} else {
cow.setSpriteState(RIGHT);
}
} else {
if (cow.getSpriteState().get() == RIGHT_HURT || cow.getSpriteState().get() == LEFT_HURT) {
cow.setSpriteState(LEFT_HURT);
} else {
cow.setSpriteState(LEFT);
}
}
List<Block> blocksAhead = world[cowY][cowX + direction];
if (!game.isSolid(blocksAhead)) {
world[cowY][cowX].remove(cow);
world[cowY][cowX + direction].add(cow);
newCowX = cowX + direction;
updated = true;
cowData.setJumpAttempts(0);
} else {
List<Block> blocksAboveAhead = world[cowY - 1][cowX + direction];
List<Block> blocksTwoAboveAhead = world[cowY - 2][cowX + direction];
if (!game.isSolid(blocksAboveAhead) && game.isSolid(blocksAhead) && !game.isSolid(blocksTwoAboveAhead)) {
if (cowData.getJumpAttempts() < 2) {
world[cowY][cowX].remove(cow);
world[cowY - 1][cowX + direction].add(cow);
newCowX = cowX + direction;
newCowY = cowY - 1;
updated = true;
cowData.setJumpAttempts(cowData.getJumpAttempts() + 1);
}
}
}
while (updated) {
if (!game.isSolid(world[newCowY + 1][newCowX])) {
if (newCowY - cowY < 3) {
world[newCowY][newCowX].remove(cow);
world[newCowY + 1][newCowX].add(cow);
newCowY++;
} else {
updated = false;
}
} else {
updated = false;
}
}
cowData.setMovementCooldown(random.nextInt(3) + 1); // 1-3 iterations cooldown
}
@Override
public void spawn(int playerX, int playerY, Game game, Terminal terminal) {
// Cordinates where player can see
int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);
var world = game.getWorld();
int startX = data[0];
int endX = data[1];
// Left side
int lstartX = startX - 20;
int lendX = startX - 5;
int lstartY = playerY - 15;
int lendY = playerY + 15;
if (countCows(lstartX, lendX, lstartY, lendY, game) < 3 && random.nextInt(100) < 100) {
var spawnLocations = cowCanSpawn(lstartX, lendX, playerY, game);
if (!spawnLocations.isEmpty()) {
for (int i = 0; i < Math.min(4, spawnLocations.size()); i++) {
var randomLocation = getRandomEntry(spawnLocations);
int x = randomLocation.getKey();
int y = randomLocation.getValue();
world[y][x].add(ItemBlockSupplier.getEntity("cow"));
}
}
}
// Right side
int rstartX = endX + 5;
int rendX = endX + 20;
int rstartY = playerY - 15;
int rendY = playerY + 15;
if (countCows(rstartX, rendX, rstartY, rendY, game) < 3 && random.nextInt(100) < 2) {
var spawnLocations = cowCanSpawn(rstartX, rendX, playerY, game);
if (!spawnLocations.isEmpty()) {
for (int i = 0; i < Math.min(random.nextInt(3) + 2, spawnLocations.size()); i++) {
var randomLocation = getRandomEntry(spawnLocations);
int x = randomLocation.getKey();
int y = randomLocation.getValue();
world[y][x].add(ItemBlockSupplier.getEntity("cow"));
}
}
}
}
public static <K, V> Map.Entry<K, V> getRandomEntry(HashMap<K, V> map) {
List<Map.Entry<K, V>> entryList = new ArrayList<>(map.entrySet());
Random random = new Random();
return entryList.get(random.nextInt(entryList.size()));
}
private HashMap<Integer, Integer> cowCanSpawn(int startX, int endX, int playerY, Game game) {
var map = new HashMap<Integer, Integer>();
var world = game.getWorld();
for (int x = startX; x <= endX; x++) {
for (int y = Math.max(0, playerY - 30); y < Math.min(world.length, playerY + 30); y++) {
if (world[y][x].stream().anyMatch(i -> i.getBlockId().equals("grass"))) {
map.put(x, y - 1);
}
}
}
return map;
}
private long countCows(int startX, int endX, int startY, int endY, Game game) {
long cowAmount = 0;
for (int y = startY; y <= endY; y++) {
for (int x = startX; x <= endX; x++) {
cowAmount += game.getWorld()[y][x].stream().filter(i -> i.getBlockId().equals("cow")).count();
}
}
return cowAmount;
}
public Cow.CowState setHurtAnimation(boolean hurt, Enum current) {
if (hurt) {
return switch (current) {
case LEFT_HURT,LEFT -> LEFT_HURT;
case RIGHT_HURT,RIGHT -> RIGHT_HURT;
default -> throw new IllegalStateException("Unexpected value: " + current);
};
}
return switch (current) {
case LEFT_HURT,LEFT -> LEFT;
case RIGHT_HURT,RIGHT -> RIGHT;
default -> throw new IllegalStateException("Unexpected value: " + current);
};
}
@Override
public void killed(Game game, Block mob) {
/*int amount = random.nextInt(2) + 1;
InventoryItem inventoryItem = new InventoryItem(amount, ItemBlockSupplier.getItem("mutton"));
game.getInventory().addItem(inventoryItem);*/
}
}

View File

@ -0,0 +1,29 @@
package cz.jzitnik.game.sprites;
import cz.jzitnik.tui.ResourceLoader;
import cz.jzitnik.tui.Sprite;
public class Cow extends Sprite {
public enum CowState{
LEFT,
RIGHT,
LEFT_HURT,
RIGHT_HURT
}
public String getSprite() {
return getSprite(CowState.RIGHT);
}
public String getSprite(Enum e) {
return ResourceLoader.loadResource(
switch (e) {
case CowState.LEFT -> "mobs/cow/left.ans";
case CowState.RIGHT -> "mobs/cow/right.ans";
case CowState.LEFT_HURT -> "mobs/cow/lefthurt.ans";
case CowState.RIGHT_HURT -> "mobs/cow/righthurt.ans";
default -> throw new IllegalStateException("Unexpected value: " + e);
}
);
}
}

View File

@ -0,0 +1,25 @@
                                                
                                             
                                             
                 
                   
                   
                      
                     
                        
                              
                        
                             
                           
                                         
                                          
                                      
                                          
                                        
                                          
                                        
                                          
                                          
                                         
                                      
                                    

View File

@ -0,0 +1,25 @@
                                                
                                            
                                             
                     
                    
                     
               
                 
                        
                            
                        
                            
                         
                                        
                                          
                                       
                                         
                                       
                                          
                                          
                                        
                                        
                                         
                                      
                                    

View File

@ -0,0 +1,25 @@
                                                
                                             
                                             
              
                   
                    
           
               
                      
                               
                        
                          
                         
                                        
                                          
                                       
                                         
                                        
                                          
                                       
                                        
                                       
                                        
                                      
                                    

View File

@ -0,0 +1,25 @@