feat: Chest and other changes

This commit is contained in:
Jakub Žitník 2025-02-26 14:25:09 +01:00
parent 2f48cdd04a
commit 91724dbeb2
Signed by: jzitnik
GPG Key ID: C577A802A6AF4EF3
29 changed files with 590 additions and 145 deletions

View File

@ -3,7 +3,9 @@ package cz.jzitnik;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.MouseHandler;
import cz.jzitnik.game.SpriteLoader;
import cz.jzitnik.game.sprites.Window;
import cz.jzitnik.game.ui.Chest;
import cz.jzitnik.game.ui.CloseHandler;
import cz.jzitnik.game.ui.Window;
import cz.jzitnik.game.ui.InventoryClickHandler;
import cz.jzitnik.tui.ScreenRenderer;
import org.jline.terminal.MouseEvent;
@ -50,6 +52,7 @@ public class Main {
case WORLD -> mouseHandler.handle(mouseEvent);
case INVENTORY -> InventoryClickHandler.click(mouseEvent, terminal, screenRenderer, game, Optional.empty(), Optional.empty());
case CRAFTING_TABLE -> game.getGameStates().craftingTable.click(mouseEvent, terminal, screenRenderer);
case CHEST -> ((Chest) game.getWorld()[game.getGameStates().clickY][game.getGameStates().clickX].stream().filter(i -> i.getBlockId().equals("chest")).toList().getFirst().getData()).click(game, mouseEvent, terminal, screenRenderer);
}
}
}
@ -81,8 +84,9 @@ public class Main {
break;
case 'e':
if (game.getWindow() != Window.WORLD) {
game.setWindow(Window.WORLD);
game.getInventory().setSelectedItemInv(-1);
CloseHandler.handle(game.getWindow(), game);
game.setWindow(Window.WORLD);
} else {
game.setWindow(Window.INVENTORY);
}

View File

@ -23,6 +23,7 @@ public class Block {
private Optional<ItemType> tool = Optional.empty();
private List<ToolVariant> toolVariants = new ArrayList<>();
private List<Item> drops = new ArrayList<>();
private Object data = null;
public Block(String blockId, SpriteLoader.SPRITES sprite) {
this.blockId = blockId;
@ -44,6 +45,15 @@ public class Block {
this.toolVariants = toolVariants;
}
public Block(String blockId, SpriteLoader.SPRITES sprite, int hardness, ItemType tool, List<ToolVariant> toolVariants, Object data) {
this.blockId = blockId;
this.sprite = sprite;
this.hardness = hardness;
this.tool = Optional.of(tool);
this.toolVariants = toolVariants;
this.data = data;
}
public void setSpriteState(Enum spriteState) {
this.spriteState = Optional.of(spriteState);
}

View File

@ -3,7 +3,9 @@ package cz.jzitnik.game;
import cz.jzitnik.game.items.Item;
import cz.jzitnik.game.items.ItemType;
import cz.jzitnik.game.sprites.Breaking;
import cz.jzitnik.game.sprites.Window;
import cz.jzitnik.game.sprites.Steve;
import cz.jzitnik.game.ui.Chest;
import cz.jzitnik.game.ui.Window;
import cz.jzitnik.game.ui.Inventory;
import cz.jzitnik.tui.ScreenMovingCalculationProvider;
import cz.jzitnik.tui.ScreenRenderer;
@ -19,6 +21,8 @@ public class Game {
private List<Block>[][] world = new ArrayList[256][512];
@Setter
private Block player;
@Setter
private Block player2;
private boolean mining = false;
@Setter
private Window window = Window.WORLD;
@ -36,7 +40,7 @@ public class Game {
for (int i = 0; i < world.length; i++) {
for (int j = 0; j < world[i].length; j++) {
for (Block block : world[i][j]) {
if (block.getBlockId().equals("steve")) {
if (block.getBlockId().equals("steve") && block.getSpriteState().isPresent() && block.getSpriteState().get() == Steve.SteveState.SECOND) {
return new int[]{j, i};
}
}
@ -51,12 +55,14 @@ public class Game {
}
int[] cords = getPlayerCords();
if (world[cords[1]][cords[0] + 1].stream().anyMatch(block -> !block.isGhost())) {
if (world[cords[1]][cords[0] + 1].stream().anyMatch(block -> !block.isGhost()) || world[cords[1] - 1][cords[0] + 1].stream().anyMatch(block -> !block.isGhost())) {
return;
}
world[cords[1]][cords[0] + 1].add(player);
world[cords[1]][cords[0]].remove(player);
world[cords[1]][cords[0] + 1].add(player2);
world[cords[1]][cords[0]].remove(player2);
world[cords[1]-1][cords[0] + 1].add(player);
world[cords[1]-1][cords[0]].remove(player);
screenRenderer.render(this);
update(screenRenderer);
@ -68,12 +74,14 @@ public class Game {
}
int[] cords = getPlayerCords();
if (world[cords[1]][cords[0] - 1].stream().anyMatch(block -> !block.isGhost())) {
if (world[cords[1]][cords[0] - 1].stream().anyMatch(block -> !block.isGhost()) || world[cords[1] - 1][cords[0] - 1].stream().anyMatch(block -> !block.isGhost())) {
return;
}
world[cords[1]][cords[0] - 1].add(player);
world[cords[1]][cords[0]].remove(player);
world[cords[1]][cords[0] - 1].add(player2);
world[cords[1]][cords[0]].remove(player2);
world[cords[1]-1][cords[0] - 1].add(player);
world[cords[1]-1][cords[0]].remove(player);
screenRenderer.render(this);
update(screenRenderer);
@ -85,12 +93,14 @@ public class Game {
}
int[] cords = getPlayerCords();
if (world[cords[1] - 1][cords[0]].stream().anyMatch(block -> !block.isGhost()) || world[cords[1] + 1][cords[0]].stream().anyMatch(Block::isGhost)) {
if (world[cords[1] - 2][cords[0]].stream().anyMatch(block -> !block.isGhost()) || world[cords[1] + 1][cords[0]].stream().anyMatch(Block::isGhost)) {
return;
}
world[cords[1] - 1][cords[0]].add(player);
world[cords[1]][cords[0]].remove(player);
world[cords[1] - 1][cords[0]].remove(player);
world[cords[1] - 1][cords[0]].add(player2);
world[cords[1] - 2][cords[0]].add(player);
world[cords[1]][cords[0]].remove(player2);
new Thread(() -> {
try {
@ -101,8 +111,10 @@ public class Game {
int[] cords2 = getPlayerCords();
if (world[cords2[1] + 1][cords2[0]].stream().allMatch(Block::isGhost)) {
world[cords2[1] + 1][cords2[0]].add(player);
world[cords2[1]][cords2[0]].remove(player);
world[cords2[1] - 1][cords2[0]].remove(player);
world[cords2[1]][cords2[0]].add(player);
world[cords2[1] + 1][cords2[0]].add(player2);
world[cords2[1]][cords2[0]].remove(player2);
screenRenderer.render(this);
}
@ -155,13 +167,19 @@ public class Game {
if (block.getToolVariants().isEmpty()) {
// Add to inv
block.getDrops().forEach(item -> inventory.addItem(item));
block.getDrops().forEach(inventory::addItem);
continue;
}
var toolVariants = block.getToolVariants();
if (inventory.getItemInHand().isPresent() && inventory.getItemInHand().get().getToolVariant().isPresent() && block.getTool().isPresent() && block.getTool().get().equals(inventory.getItemInHand().get().getType()) && toolVariants.contains(inventory.getItemInHand().get().getToolVariant().get())) {
block.getDrops().forEach(item -> inventory.addItem(item));
block.getDrops().forEach(inventory::addItem);
}
}
for (Block block : blocks) {
if (block.getBlockId().equals("chest")) {
((Chest) block.getData()).breakChest(this);
}
}
@ -197,6 +215,7 @@ public class Game {
!blocks.stream().allMatch(block -> block.getBlockId().equals("air"))
&& distanceX <= 5 && distanceY <= 5
&& !(playerX == x && playerY == y)
&& !(playerX == x && playerY - 1 == y)
&& blocks.stream().anyMatch(Block::isMineable);
}
@ -210,8 +229,10 @@ public class Game {
int[] cords2 = getPlayerCords();
if (world[cords2[1] + 1][cords2[0]].stream().allMatch(Block::isGhost)) {
world[cords2[1] + 1][cords2[0]].add(player);
world[cords2[1]][cords2[0]].remove(player);
world[cords2[1] - 1][cords2[0]].remove(player);
world[cords2[1]][cords2[0]].add(player);
world[cords2[1] + 1][cords2[0]].add(player2);
world[cords2[1]][cords2[0]].remove(player2);
screenRenderer.render(this);
} else {

View File

@ -4,6 +4,8 @@ import cz.jzitnik.game.ui.CraftingTable;
public class GameStates {
public CraftingTable craftingTable;
public int clickX = -1;
public int clickY = -1;
public GameStates(Game game) {
craftingTable = new CraftingTable(game);

View File

@ -2,6 +2,7 @@ package cz.jzitnik.game;
import cz.jzitnik.game.items.ItemBlockSupplier;
import cz.jzitnik.game.items.ItemType;
import cz.jzitnik.game.sprites.Steve;
import java.util.ArrayList;
import java.util.List;
@ -13,14 +14,20 @@ public class Generation {
initializeWorld(world);
Block steveBlock = new Block("steve", SpriteLoader.SPRITES.STEVE);
steveBlock.setSpriteState(Steve.SteveState.FIRST);
Block steveBlock2 = new Block("steve", SpriteLoader.SPRITES.STEVE);
steveBlock2.setSpriteState(Steve.SteveState.SECOND);
game.setPlayer(steveBlock);
game.setPlayer2(steveBlock2);
int[] terrainHeight = generateTerrain();
populateWorld(world, terrainHeight);
plantTrees(world, terrainHeight);
// Spawn player at a valid starting point
world[terrainHeight[256] - 1][256].add(steveBlock);
world[terrainHeight[256] - 1][256].add(steveBlock2);
world[terrainHeight[256] - 2][256].add(steveBlock);
}
private static void initializeWorld(List<Block>[][] world) {

View File

@ -1,6 +1,6 @@
package cz.jzitnik.game;
import cz.jzitnik.game.sprites.Window;
import cz.jzitnik.game.ui.Window;
import cz.jzitnik.tui.ScreenMovingCalculationProvider;
import cz.jzitnik.tui.ScreenRenderer;
import lombok.AllArgsConstructor;

View File

@ -1,5 +1,7 @@
package cz.jzitnik.game;
import cz.jzitnik.game.ui.Window;
import java.util.HashMap;
public class RightClickHandler {
@ -9,8 +11,16 @@ public class RightClickHandler {
}
public static void handle(int x, int y, Game game) {
if (game.isMining()) {
return;
}
HashMap<String, Function3<Integer, Integer>> functionMap = new HashMap<>();
functionMap.put("crafting_table", game.getGameStates().craftingTable::render);
functionMap.put("chest", (Integer ignored, Integer ignored2) -> game.setWindow(Window.CHEST));
game.getGameStates().clickX = x;
game.getGameStates().clickY = y;
var blocks = game.getWorld()[y][x];
for (Block block : blocks) {

View File

@ -16,9 +16,11 @@ public class SpriteLoader {
STONE,
BEDROCK,
BREAKING,
CRAFTING_TABLE,
COBBLESTONE,
CHEST,
CRAFTING_TABLE,
OAK_LOG,
OAK_LEAF,
OAK_PLANKS,
@ -27,14 +29,18 @@ public class SpriteLoader {
STONE_PICKAXE,
WOODEN_AXE,
STONE_AXE,
WOODEN_SHOVEL,
STONE_SHOVEL,
// Items
ITEM_DIRT,
ITEM_OAK_LOG,
ITEM_OAK_PLANKS,
ITEM_STICK,
ITEM_COBBLESTONE,
ITEM_CRAFTING_TABLE,
ITEM_COBBLESTONE
ITEM_CHEST
}
public static final HashMap<SPRITES, Sprite> SPRITES_MAP = new HashMap<>();
@ -51,18 +57,22 @@ public class SpriteLoader {
SPRITES_MAP.put(SPRITES.OAK_LEAF, new SimpleSprite("oak_leaf.ans"));
SPRITES_MAP.put(SPRITES.OAK_PLANKS, new SimpleSprite("oak_planks.ans"));
SPRITES_MAP.put(SPRITES.CRAFTING_TABLE, new SimpleSprite("crafting_table.ans"));
SPRITES_MAP.put(SPRITES.CHEST, new SimpleSprite("chest.ans"));
SPRITES_MAP.put(SPRITES.COBBLESTONE, new SimpleSprite("cobblestone.ans"));
SPRITES_MAP.put(SPRITES.WOODEN_PICKAXE, new SimpleSprite("items/wooden_pickaxe.ans"));
SPRITES_MAP.put(SPRITES.STONE_PICKAXE, new SimpleSprite("items/stone_pickaxe.ans"));
SPRITES_MAP.put(SPRITES.WOODEN_AXE, new SimpleSprite("items/wooden_axe.ans"));
SPRITES_MAP.put(SPRITES.STONE_AXE, new SimpleSprite("items/stone_axe.ans"));
SPRITES_MAP.put(SPRITES.WOODEN_SHOVEL, new SimpleSprite("items/wooden_shovel.ans"));
SPRITES_MAP.put(SPRITES.STONE_SHOVEL, new SimpleSprite("items/stone_shovel.ans"));
SPRITES_MAP.put(SPRITES.ITEM_DIRT, new SimpleSprite("items/dirt.ans"));
SPRITES_MAP.put(SPRITES.ITEM_OAK_LOG, new SimpleSprite("items/oak_log.ans"));
SPRITES_MAP.put(SPRITES.ITEM_OAK_PLANKS, new SimpleSprite("items/oak_planks.ans"));
SPRITES_MAP.put(SPRITES.ITEM_STICK, new SimpleSprite("items/stick.ans"));
SPRITES_MAP.put(SPRITES.ITEM_CRAFTING_TABLE, new SimpleSprite("items/crafting_table.ans"));
SPRITES_MAP.put(SPRITES.ITEM_COBBLESTONE, new SimpleSprite("items/cobblestone.ans"));
SPRITES_MAP.put(SPRITES.ITEM_CHEST, new SimpleSprite("items/chest.ans"));
}
public static SpriteList<SPRITES> load() {

View File

@ -67,20 +67,36 @@ public class CraftingRecipeList {
{null, "stick", "cobblestone"},
{null, "stick", null}
}, () -> new InventoryItem(1, ItemBlockSupplier.Items.stoneAxe())));
// Chest
recipes.add(new CraftingRecipe(new String[][]{
{"oak_planks", "oak_planks", "oak_planks"},
{"oak_planks", null, "oak_planks"},
{"oak_planks", "oak_planks", "oak_planks"}
}, () -> new InventoryItem(1, ItemBlockSupplier.Items.chest())));
// Wooden shovel
recipes.add(new CraftingRecipe(new String[][]{
{null, "oak_planks", null},
{null, "stick", null},
{null, "stick", null}
}, () -> new InventoryItem(1, ItemBlockSupplier.Items.woodenShovel())));
// Stone shovel
recipes.add(new CraftingRecipe(new String[][]{
{null, "cobblestone", null},
{null, "stick", null},
{null, "stick", null}
}, () -> new InventoryItem(1, ItemBlockSupplier.Items.stoneShovel())));
recipes.add(new CraftingRecipe(new String[][]{
{"dirt", null, null},
{null, null, null},
{null, null, null}
}, () -> new InventoryItem(1, ItemBlockSupplier.Items.chest())));
}
// 2x2 crafting
public static Optional<CraftingRecipe> getRecipeSmall(String[] r) {
for (CraftingRecipe recipe : recipes) {
if (matchesByItemSet(recipe.getRecipe(), r)) {
return Optional.of(recipe);
}
}
return Optional.empty();
}
// 3x3 crafting
public static Optional<CraftingRecipe> getRecipeFull(String[] r) {
public static Optional<CraftingRecipe> getRecipe(String[] r) {
for (CraftingRecipe recipe : recipes) {
if (matchesByItemSet(recipe.getRecipe(), r)) {
return Optional.of(recipe);

View File

@ -2,17 +2,44 @@ package cz.jzitnik.game.items;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
public class InventoryItem {
private int amount;
private Item item;
private final List<Item> item;
public InventoryItem(int amount, Item item) {
this.amount = amount;
this.item = new ArrayList<>();
this.item.add(item);
}
public InventoryItem() {
this.item = new ArrayList<>();
this.amount = 0;
}
public void decrease() {
amount--;
item.removeLast();
}
public void add(Item i) {
amount++;
item.add(i);
}
public void setAmount(int amount) {
this.amount = amount;
}
public InventoryItem(Item item) {
this.amount = 1;
this.item = item;
this.item = new ArrayList<>();
this.item.add(item);
}
}

View File

@ -2,6 +2,7 @@ package cz.jzitnik.game.items;
import cz.jzitnik.game.SpriteLoader;
import cz.jzitnik.game.Block;
import cz.jzitnik.game.ui.Chest;
import java.util.ArrayList;
import java.util.Arrays;
@ -25,6 +26,9 @@ public class ItemBlockSupplier {
public static Item craftingTable(Block ref) {
return new Item("crafting_table", "Crafting table", ItemType.BLOCK, SpriteLoader.SPRITES.ITEM_CRAFTING_TABLE, ref);
}
public static Item chest(Block ref) {
return new Item("chest", "Chest", ItemType.BLOCK, SpriteLoader.SPRITES.ITEM_CHEST, ref);
}
}
public static class Blocks {
@ -63,6 +67,11 @@ public class ItemBlockSupplier {
block.setDrops(List.of(Helper.craftingTable(block)));
return block;
}
public static Block chest() {
var block = new Block("chest", SpriteLoader.SPRITES.CHEST, 3, ItemType.AXE, new ArrayList<>(), new Chest());
block.setDrops(List.of(Helper.chest(block)));
return block;
}
}
// I hate this but whatever
@ -94,5 +103,14 @@ public class ItemBlockSupplier {
public static Item stoneAxe() {
return new Item("stone_axe", "Stone axe", ItemType.AXE, SpriteLoader.SPRITES.STONE_AXE, ToolVariant.STONE, 3, 132, false);
}
public static Item woodenShovel() {
return new Item("wooden_shovel", "Wooden shovel", ItemType.SHOVEL, SpriteLoader.SPRITES.WOODEN_SHOVEL, ToolVariant.WOODEN, 0.3, 59, false);
}
public static Item chest() {
return Helper.chest(Blocks.chest());
}
public static Item stoneShovel() {
return new Item("stone_shovel", "Stone shovel", ItemType.SHOVEL, SpriteLoader.SPRITES.STONE_SHOVEL, ToolVariant.STONE, 0.5, 132, false);
}
}
}

View File

@ -3,21 +3,23 @@ package cz.jzitnik.game.sprites;
import cz.jzitnik.tui.ResourceLoader;
import cz.jzitnik.tui.Sprite;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Steve extends Sprite {
private String fix(String x) {
var arr = x.replaceAll("\033\\[38;5;1;48;5;16m", "\033[49m").split("\n");
arr = Arrays.copyOf(arr, arr.length - 1); // Remove the last line
return ("\033[0m ".repeat(50) + "\n").repeat(3) + Arrays.stream(arr).map(y -> "\033[0m ".repeat(12) + y + " " + "\033[0m ".repeat(12) + "\n").collect(Collectors.joining());
public enum SteveState{
FIRST,
SECOND,
}
public String getSprite() {
return fix(ResourceLoader.loadResource("steve.ans"));
throw new RuntimeException("Error");
}
public String getSprite(Enum e) {
throw new RuntimeException("Imposible state");
return ResourceLoader.loadResource(
switch (e) {
case SteveState.FIRST -> "steve1.ans";
case SteveState.SECOND -> "steve2.ans";
default -> throw new IllegalStateException("Unexpected value: " + e);
}
);
}
}

View File

@ -1,7 +0,0 @@
package cz.jzitnik.game.sprites;
public enum Window {
WORLD,
INVENTORY,
CRAFTING_TABLE
}

View File

@ -0,0 +1,101 @@
package cz.jzitnik.game.ui;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.crafting.CraftingRecipe;
import cz.jzitnik.game.crafting.CraftingRecipeList;
import cz.jzitnik.game.items.InventoryItem;
import cz.jzitnik.tui.ScreenRenderer;
import cz.jzitnik.tui.SpriteList;
import org.jline.terminal.MouseEvent;
import org.jline.terminal.Terminal;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class Chest {
private static final int ROW_AMOUNT = 4;
private static final int COLUMN_AMOUNT = 6;
private static final int CELL_WIDTH = 50;
private static final int CELL_HEIGHT = 25;
private static final int BORDER_SIZE = 2;
private final InventoryItem[] items = new InventoryItem[ROW_AMOUNT * COLUMN_AMOUNT];
private int size;
public void render(Game game, StringBuilder buffer, Terminal terminal, SpriteList spriteList) {
int widthPixels = COLUMN_AMOUNT * (CELL_WIDTH + BORDER_SIZE) + BORDER_SIZE;
var inventory = game.getInventory();
int moveLeft = (terminal.getWidth() / 2) - (widthPixels / 2);
List<String> sprites = game.getInventory().getSprites(items, spriteList, inventory.getSelectedItemInv() - 50);
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipe(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getFirst().getId()).toArray(String[]::new));
Optional<InventoryItem> craftedItem = recipe.map(craftingRecipe -> craftingRecipe.getItemSupplier().get());
for (int i = 0; i < ROW_AMOUNT; i++) {
for (int j = 0; j < CELL_HEIGHT; j++) {
buffer.append("\033[0m").append(" ".repeat(moveLeft));
for (int k = 0; k < COLUMN_AMOUNT; k++) {
buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));
if (j == 0 || j == CELL_HEIGHT - 1) {
buffer.append("\033[38;5;231;48;5;231m▓".repeat(CELL_WIDTH));
} else {
String sprite = sprites.get(i * COLUMN_AMOUNT + k);
if (sprite == null || sprite.isEmpty()) {
buffer.append("\033[0m ".repeat(CELL_WIDTH));
} else {
String[] spriteLines = sprite.split("\n");
buffer.append(spriteLines[j + 1]);
}
}
buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));
}
buffer.append("\n");
}
}
buffer.append("\n".repeat(20));
size = buffer.toString().split("\n").length;
game.getInventory().renderFull(buffer, terminal, spriteList, false, Optional.of(size));
}
public void click(Game game, MouseEvent mouseEvent, Terminal terminal, ScreenRenderer screenRenderer) {
int x = mouseEvent.getX();
int y = mouseEvent.getY();
int widthPixels = COLUMN_AMOUNT * (CELL_WIDTH + BORDER_SIZE) + BORDER_SIZE;
int heightPixels = ROW_AMOUNT * (CELL_HEIGHT + 1);
int moveLeft = (terminal.getWidth() / 2) - (widthPixels / 2);
if (x > moveLeft && x <= moveLeft + widthPixels && y > 0 && y <= heightPixels && mouseEvent.getType() == MouseEvent.Type.Pressed) {
if (mouseEvent.getType() != MouseEvent.Type.Pressed) return;
int blockX = (x - moveLeft) / 52;
int blockY = y / 26;
InventoryClickHandler.handleItemClick(mouseEvent, game.getInventory(), items, blockY * COLUMN_AMOUNT + blockX, 50, Optional.of(items));
screenRenderer.render(game);
return;
}
// TODO: Why I need to add 20 here. Like wtf
InventoryClickHandler.click(mouseEvent, terminal, screenRenderer, game, Optional.of(size + 20), Optional.of(items));
}
public void breakChest(Game game) {
for (var i = 0; i < items.length; i++) {
if (items[i] == null) {
continue;
}
game.getInventory().addItem(items[i]);
items[i] = null;
}
}
}

View File

@ -0,0 +1,26 @@
package cz.jzitnik.game.ui;
import cz.jzitnik.game.Game;
import java.util.HashMap;
public class CloseHandler {
@FunctionalInterface
public interface Function<T> {
void call(T t);
}
public static HashMap<Window, Function<Game>> handles = new HashMap<>();
static {
handles.put(Window.CRAFTING_TABLE, game -> game.getGameStates().craftingTable.exit());
}
public static void handle(Window window, Game game) {
if (handles.containsKey(window)) {
var func = handles.get(window);
func.call(game);
}
}
}

View File

@ -4,7 +4,6 @@ import cz.jzitnik.game.Game;
import cz.jzitnik.game.crafting.CraftingRecipe;
import cz.jzitnik.game.crafting.CraftingRecipeList;
import cz.jzitnik.game.items.InventoryItem;
import cz.jzitnik.game.sprites.Window;
import cz.jzitnik.tui.ScreenRenderer;
import cz.jzitnik.tui.utils.SpriteCombiner;
import cz.jzitnik.tui.SpriteList;
@ -24,7 +23,7 @@ public class CraftingTable {
private static final int CELL_HEIGHT = 25;
private static final int BORDER_SIZE = 2;
private final InventoryItem[] items = new InventoryItem[9];
private final InventoryItem[] items = new InventoryItem[ROW_AMOUNT * COLUMN_AMOUNT];
private int size;
public void render(int ignored, int ignored2) {
@ -32,7 +31,7 @@ public class CraftingTable {
}
public void pickup() {
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipeSmall(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getId()).toArray(String[]::new));
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipe(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getFirst().getId()).toArray(String[]::new));
if (recipe.isPresent()) {
InventoryItem item = recipe.get().getItemSupplier().get();
@ -47,7 +46,7 @@ public class CraftingTable {
if (it.getAmount() == 1) {
items[i] = null;
} else {
it.setAmount(it.getAmount() - 1);
it.decrease();
}
}
}
@ -61,12 +60,12 @@ public class CraftingTable {
List<String> sprites = game.getInventory().getSprites(items, spriteList, inventory.getSelectedItemInv() - 50);
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipeSmall(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getId()).toArray(String[]::new));
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipe(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getFirst().getId()).toArray(String[]::new));
Optional<InventoryItem> craftedItem = recipe.map(craftingRecipe -> craftingRecipe.getItemSupplier().get());
String[] craftedSprite = craftedItem.map(inventoryItem -> SpriteCombiner.combineTwoSprites(
spriteList.getSprite(inventoryItem.getItem().getSprite()).getSprite(),
spriteList.getSprite(inventoryItem.getItem().getFirst().getSprite()).getSprite(),
Numbers.getNumberSprite(inventoryItem.getAmount())
).split("\n")).orElse(null);
@ -146,6 +145,19 @@ public class CraftingTable {
InventoryClickHandler.click(mouseEvent, terminal, screenRenderer, game, Optional.of(size + 20), Optional.of(items));
}
public void exit() {
// Put all items from crafting to inv
for (int i = 0; i < items.length; i++) {
InventoryItem item = items[i];
if (item == null) {
continue;
}
game.getInventory().addItem(item);
items[i] = null;
}
}
public CraftingTable(Game game) {
this.game = game;
}

View File

@ -34,7 +34,7 @@ public class Inventory {
if (hotbar[itemInhHandIndex] == null) {
return Optional.empty();
}
return Optional.of(hotbar[itemInhHandIndex].getItem());
return Optional.of(hotbar[itemInhHandIndex].getItem().getLast());
}
public void decreaseItemInHand() {
@ -47,7 +47,7 @@ public class Inventory {
return;
}
hotbar[itemInhHandIndex].setAmount(hotbar[itemInhHandIndex].getAmount() - 1);
hotbar[itemInhHandIndex].decrease();
}
private void placeItem(Item item) {
@ -74,7 +74,7 @@ public class Inventory {
public void addItem(InventoryItem item) {
for (int i = 0; i < item.getAmount(); i++) {
addItem(item.getItem());
addItem(item.getItem().get(i));
}
}
@ -86,16 +86,16 @@ public class Inventory {
// Try to stack in hotbar
for (InventoryItem value : hotbar) {
if (value != null && value.getItem().equals(item) && value.getAmount() < item.getStackAmount()) {
value.setAmount(value.getAmount() + 1);
if (value != null && value.getItem().getFirst().equals(item) && value.getAmount() < item.getStackAmount()) {
value.add(item);
return;
}
}
// Try to stack in inventory
for (InventoryItem inventoryItem : items) {
if (inventoryItem != null && inventoryItem.getItem().equals(item) && inventoryItem.getAmount() < item.getStackAmount()) {
inventoryItem.setAmount(inventoryItem.getAmount() + 1);
if (inventoryItem != null && inventoryItem.getItem().getFirst().equals(item) && inventoryItem.getAmount() < item.getStackAmount()) {
inventoryItem.add(item);
return;
}
}
@ -223,14 +223,14 @@ public class Inventory {
if (i == selectedItem) {
sprites.add(SpriteCombiner.combineTwoSprites(getHotbarBackground(), SpriteCombiner.combineTwoSprites(
spriteList.getSprite(item.getItem().getSprite()).getSprite(),
spriteList.getSprite(item.getItem().getFirst().getSprite()).getSprite(),
Numbers.getNumberSprite(item.getAmount())
)));
continue;
}
sprites.add(SpriteCombiner.combineTwoSprites(
spriteList.getSprite(item.getItem().getSprite()).getSprite(),
spriteList.getSprite(item.getItem().getFirst().getSprite()).getSprite(),
Numbers.getNumberSprite(item.getAmount())
));
}
@ -272,11 +272,12 @@ public class Inventory {
return getSelectedItem(i);
}
item.setAmount(item.getAmount() - 1);
rightClick = false;
return new InventoryItem(1, item.getItem());
var ij = new InventoryItem(1, item.getItem().getLast());
item.decrease();
return ij;
}
public InventoryItem getHalf(Optional<InventoryItem[]> i) {
@ -287,12 +288,18 @@ public class Inventory {
}
int half = item.getAmount() / 2;
item.setAmount(item.getAmount() - half);
var inv = new InventoryItem();
for (int j = 0; j < half; j++) {
inv.add(item.getItem().getLast());
item.decrease();
}
selectedItemInv = -1;
rightClick = false;
return new InventoryItem(half, item.getItem());
return inv;
}
public boolean hasSelectedItem() {
@ -310,22 +317,26 @@ public class Inventory {
return; // Nothing to merge
}
if (!fromItem.getItem().isStackable() || !toItem.getItem().isStackable()) {
if (!fromItem.getItem().getFirst().isStackable() || !toItem.getItem().getFirst().isStackable()) {
return;
}
if (!fromItem.getItem().equals(toItem.getItem())) {
if (!fromItem.getItem().getFirst().equals(toItem.getItem().getFirst())) {
return; // Different items cannot be merged
}
int totalAmount = fromItem.getAmount() + toItem.getAmount();
while (true) {
if (toItem.getAmount() == 64) {
break;
}
if (totalAmount > 64) {
toItem.setAmount(64);
fromItem.setAmount(totalAmount - 64);
} else {
toItem.setAmount(totalAmount);
fromData.getObj()[fromData.getIndex()] = null; // Remove the source item after merging
if (fromItem.getAmount() == 0) {
fromData.getObj()[fromData.getIndex()] = null;
break;
}
toItem.add(fromItem.getItem().getLast());
fromItem.decrease();
}
selectedItemInv = -1;
@ -338,13 +349,13 @@ public class Inventory {
InventoryItem fromItem = fromSlot.getObj()[fromSlot.getIndex()];
InventoryItem toItem = toSlot.getObj()[toSlot.getIndex()];
if (fromItem == null || !fromItem.getItem().equals(toItem.getItem()) || toItem.getAmount() >= fromItem.getItem().getStackAmount()) {
if (fromItem == null || !fromItem.getItem().getFirst().equals(toItem.getItem().getFirst()) || toItem.getAmount() >= fromItem.getItem().getFirst().getStackAmount()) {
return; // Can't merge
}
// Move only one item
toItem.setAmount(toItem.getAmount() + 1);
fromItem.setAmount(fromItem.getAmount() - 1);
toItem.add(fromItem.getItem().getLast());
fromItem.decrease();
// Remove source item if empty
if (fromItem.getAmount() <= 0) {

View File

@ -21,7 +21,7 @@ public class SmallCraftingTable {
private InventoryItem[] items = new InventoryItem[4];
public void pickup() {
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipeSmall(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getId()).toArray(String[]::new));
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipe(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getFirst().getId()).toArray(String[]::new));
if (recipe.isPresent()) {
InventoryItem item = recipe.get().getItemSupplier().get();
@ -36,7 +36,7 @@ public class SmallCraftingTable {
if (it.getAmount() == 1) {
items[i] = null;
} else {
it.setAmount(it.getAmount() - 1);
it.decrease();
}
}
}
@ -47,12 +47,12 @@ public class SmallCraftingTable {
List<String> sprites = inventory.getSprites(items, spriteList, inventory.getSelectedItemInv() - 29);
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipeSmall(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getId()).toArray(String[]::new));
Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipe(Arrays.stream(items).map(item -> item == null ? null: item.getItem().getFirst().getId()).toArray(String[]::new));
Optional<InventoryItem> craftedItem = recipe.map(craftingRecipe -> craftingRecipe.getItemSupplier().get());
String[] craftedSprite = craftedItem.map(inventoryItem -> SpriteCombiner.combineTwoSprites(
spriteList.getSprite(inventoryItem.getItem().getSprite()).getSprite(),
spriteList.getSprite(inventoryItem.getItem().getFirst().getSprite()).getSprite(),
Numbers.getNumberSprite(inventoryItem.getAmount())
).split("\n")).orElse(null);

View File

@ -0,0 +1,8 @@
package cz.jzitnik.game.ui;
public enum Window {
WORLD,
INVENTORY,
CRAFTING_TABLE,
CHEST
}

View File

@ -2,6 +2,8 @@ package cz.jzitnik.tui;
import cz.jzitnik.game.Block;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.sprites.Steve;
import cz.jzitnik.game.ui.Chest;
import cz.jzitnik.tui.utils.SpriteCombiner;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@ -29,7 +31,7 @@ public class ScreenRenderer {
private int[] getPlayerCords(List<Block>[][] world) {
for (int i = 0; i < world.length; i++) {
for (int j = 0; j < world[i].length; j++) {
if (world[i][j].stream().anyMatch(x -> x.getBlockId().equals("steve"))) {
if (world[i][j].stream().anyMatch(x -> x.getBlockId().equals("steve") && x.getSpriteState().isPresent() && x.getSpriteState().get() == Steve.SteveState.SECOND)) {
return new int[]{j, i};
}
}
@ -45,6 +47,7 @@ public class ScreenRenderer {
switch (game.getWindow()) {
case INVENTORY -> game.getInventory().renderFull(main, terminal, spriteList, true, Optional.empty());
case CRAFTING_TABLE -> game.getGameStates().craftingTable.render(main, terminal, spriteList);
case CHEST -> ((Chest) game.getWorld()[game.getGameStates().clickY][game.getGameStates().clickX].stream().filter(i -> i.getBlockId().equals("chest")).toList().getFirst().getData()).render(game, main, terminal, spriteList);
case WORLD -> {
// World

View File

@ -33,6 +33,7 @@ public class SpriteCombiner {
int cursor2 = 0;
// Ensure we stay within the bounds of both rows.
int prev = -1;
while (cursor1 < row1.length() && cursor2 < row2.length()) {
String color1 = extractColorCode(row1, cursor1);
int pixelIndex1 = cursor1 + color1.length();
@ -45,8 +46,15 @@ public class SpriteCombiner {
char pixel2 = row2.charAt(pixelIndex2);
if (color2.equals("\033[0m") && pixel2 == ' ' || color2.equals("\033[49m") && pixel2 == ' ') {
if (prev != 1 && color1.isEmpty()) {
combinedRow.append(getColorCode(row1, cursor1));
prev = 1;
}
combinedRow.append(color1).append(pixel1);
} else {
if (prev != 2) {
prev = 2;
}
combinedRow.append(color2).append(pixel2);
}
@ -60,6 +68,14 @@ public class SpriteCombiner {
return combinedSprite.toString();
}
private static String getColorCode(String row, int index) {
if (row.charAt(index) != '\033') {
return getColorCode(row, index - 1);
}
return extractColorCode(row, index);
}
private static String extractColorCode(String row, int index) {
StringBuilder colorCode = new StringBuilder();

View File

@ -0,0 +1,25 @@
              
              
                   
                
                 
                    
                
                  
                  
                 
                    
                
                  
               
                   
                    
                  
                     
                 
                    
                   
                   
                  
              
 

View File

@ -0,0 +1,25 @@
                                                 
                                             
                                         
                                    
                                
                            
                          
                        
                           
                           
                         
                         
                       
                        
                          
                        
                         
                        
                      
                           
                                
                                    
                                         
                                             
                                                 

View File

@ -1,26 +1,25 @@
                                                  
                      ▒▒▒▒▒▒▒                     
                  ▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒                 
              ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒             
          ▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒         
      ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒     
   ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒  
   ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░▒░░░  
   ▒▒▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░▒▒▒▒░░  
   ▒▓▓▒░░▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒░▒▒▒░░░▒▒░░  
   ▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒▒▒▒▒▒▒▒▒▒▒▒░░▒▒▓░░▒░░░▒░░▒░░▒  
   ▒░░▒▒▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░▒░░░▒▒▒░░▓░░░░▒▒  
   ▒▒▒▒▒▒▒▒░▒▒▒▒▒▒▒▒░░▒░░▒░▒░░░▒░░░▒░▒░░░░░░▒░▒▒  
   ▒▒▒▒▒▒▓▒▒░░░░░▒▓▒▒▒░▒▒▒▒░▒▒░▒▒▒░░░░░▒▒▒░░░▒░░  
   ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░▒▒▒▒▒▒▒▓▒▒▒░▒▒░▒▒▒░▒▒▒░░░░▒▒  
   ▒▒▒░▒▒▒▒▒▒▒▒▒░▒▒▒▒▒▒▒▒▒▒░▒▒▒▓░░░░░▒▒▒▒░▒▒▒▓░░  
   ▒▒▒▒▒▒▒░░░▒▒▒▒▒▒▒▒▒▒▒▒░░░░░▒▒▒▒░░░░░░▒░▒▒▒░░▒  
   ▒░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░▒▒▒░▒░░░▒░▒▒▒░░░░▒▒▒  
   ▒▒▒▒▒▒▒▒▒▒▒▓░▒▒▒▒▒▒▒░▒░▒░░░░░░░▒▒▒▓▒░░░░░▒▒▒▒  
   ▒▒▒░▒▒▒▒▒▒▒▒▓▒▒▒░▒▒▒▒▒░░▒░░▒▒▒▒░░░░░▒▒░░░░▒░░  
      ▒▒▒▒░▒▒▒▒▒▒▒▒▒░▒▒▓▒░░▒░░▒▒▒▒▒▒▒░▒░░▒▒▒▒     
          ▒▓▓░▒▒▒▒░░▒▒▒▒░▒▒░▒▒░▒░░░░░▒▒░░         
              ▒▒▒▒▒▒▒▒▒▒▒░░▒░░▒░░░▓░░             
                  ▒▒▒▒▒▒▒░▒░░░▒▒░                 
                      ▒▒░▒▒░▒                     

                                                 
                                             
                                         
                                 
                              
                           
                         
                        
                          
                          
                           
                         
                        
                          
                          
                       
                        
                          
                          
                             
                                 
                                    
                                         
                                             
                                                 

View File

@ -0,0 +1,25 @@
                                                  
                                                  
                                                  
                                             
                                           
                                         
                                       
                                       
                                    
                                          
                                         
                                          
                                         
                                         
                                             
                                             
                                             
                                             
                                             
                                           
                                             
                                             
                                              
                                              
                                                  

View File

@ -0,0 +1,25 @@
                                                  
                                                  
                                                  
                                            
                                             
                                          
                                       
                                       
                                   
                                       
                                        
                                          
                                        
                                         
                                            
                                             
                                             
                                           
                                             
                                          
                                            
                                           
                                               
                                             
                                                  

View File

@ -1,26 +1,25 @@
                         ░                        
                         ░                        
                         ▒                        
                         ▒                        
                      ░                           
                      ░  ▒                        
                      ░  ▒                        
                      ░  ▒                        
                      ░  ▒                        
                      ░  ▒                        
   ▒                     ▒                        
    ░░░                  ░  ▒         ░░░         
                         ░  ▒                     
                         ░                     ░  
                         ░░░░                  ░  
                      ░  ▒                     ░  
                         ░                        
                      ░  ░                        
                            ▒                     
                      ░  ▓                        
                      ░  ▓                        
                      ░  ▓                     ░  
                            ▒                     
                            ▒                     
                                                  

                       
                     
                        
                     
                   
                      
                           
                          
                    
                         
                          
                            
                        
                         
                           
                           
                             
                       
                         
                      
                              
                              
                    
                      
                      

View File

@ -0,0 +1,25 @@
                                      
                                       
                                       
                                         
                                         
                                         
                                         
                                         
                                         
                                         
                                         
                                         
                           
                           
                         
                         
                         
                        
                           
                           
                          
                           
                           
                           
                          

View File

@ -0,0 +1,25 @@