438 lines
15 KiB
Java
438 lines
15 KiB
Java
package cz.jzitnik.game.ui;
|
|
|
|
import cz.jzitnik.game.annotations.AutoTransient;
|
|
import cz.jzitnik.game.core.autotransient.AutoTransientSupport;
|
|
import cz.jzitnik.game.entities.items.InventoryItem;
|
|
import cz.jzitnik.game.entities.items.Item;
|
|
import cz.jzitnik.tui.utils.SpriteCombiner;
|
|
import cz.jzitnik.tui.SpriteList;
|
|
import cz.jzitnik.tui.utils.Numbers;
|
|
import lombok.Getter;
|
|
import lombok.Setter;
|
|
import org.jline.terminal.Terminal;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
|
|
@Getter
|
|
public class Inventory extends AutoTransientSupport {
|
|
public static final int INVENTORY_SIZE_PX = 470;
|
|
public static final int COLUMN_AMOUNT = 5;
|
|
public static final int ROW_AMOUNT = 4;
|
|
|
|
private final InventoryItem[] items = new InventoryItem[20];
|
|
private final InventoryItem[] hotbar = new InventoryItem[9];
|
|
|
|
@AutoTransient
|
|
private transient SmallCraftingTable smallCraftingTable = new SmallCraftingTable(this);
|
|
|
|
@Setter
|
|
private int itemInhHandIndex = 0;
|
|
@Setter
|
|
private int selectedItemInv = -1;
|
|
@Setter
|
|
private boolean rightClick = false;
|
|
|
|
public Optional<Item> getItemInHand() {
|
|
if (hotbar[itemInhHandIndex] == null) {
|
|
return Optional.empty();
|
|
}
|
|
return Optional.of(hotbar[itemInhHandIndex].getItem().getLast());
|
|
}
|
|
|
|
public void decreaseItemInHand() {
|
|
if (hotbar[itemInhHandIndex] == null) {
|
|
return;
|
|
}
|
|
|
|
if (hotbar[itemInhHandIndex].getAmount() == 1) {
|
|
hotbar[itemInhHandIndex] = null;
|
|
return;
|
|
}
|
|
|
|
hotbar[itemInhHandIndex].decrease();
|
|
}
|
|
|
|
private void placeItem(Item item) {
|
|
var inventoryItem = new InventoryItem(item);
|
|
|
|
// Try to place to hotbar
|
|
for (int i = 0; i < hotbar.length; i++) {
|
|
if (hotbar[i] == null) {
|
|
hotbar[i] = inventoryItem;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Try to place to inventory
|
|
for (int i = 0; i < items.length; i++) {
|
|
if (items[i] == null) {
|
|
items[i] = inventoryItem;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If inventory is full the item is lost
|
|
}
|
|
|
|
public void addItem(InventoryItem item) {
|
|
for (int i = 0; i < item.getAmount(); i++) {
|
|
addItem(item.getItem().get(i));
|
|
}
|
|
}
|
|
|
|
public void addItem(List<Item> item) {
|
|
for (Item i : item) {
|
|
addItem(i);
|
|
}
|
|
}
|
|
|
|
public void addItem(Item item) {
|
|
if (!item.isStackable()) {
|
|
placeItem(item);
|
|
return;
|
|
}
|
|
|
|
// Try to stack in hotbar
|
|
for (InventoryItem value : hotbar) {
|
|
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().getFirst().equals(item)
|
|
&& inventoryItem.getAmount() < item.getStackAmount()) {
|
|
inventoryItem.add(item);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// If stacking didn't work try to add it to inventory
|
|
placeItem(item);
|
|
}
|
|
|
|
private String getHotbarBackground() {
|
|
StringBuilder sprite = new StringBuilder();
|
|
for (int i = 0; i < 25; i++) {
|
|
sprite.append("\033[38;5;245;48;5;245m▓".repeat(50));
|
|
sprite.append("\n");
|
|
}
|
|
return sprite.toString();
|
|
}
|
|
|
|
public void renderHotbar(StringBuilder buffer, SpriteList spriteList, Terminal terminal, boolean isFull) {
|
|
int termWidth = terminal.getWidth();
|
|
int startLeft = (termWidth / 2) - (INVENTORY_SIZE_PX / 2);
|
|
|
|
List<String> sprites = getSprites(hotbar, spriteList, (isFull ? selectedItemInv - 20 : itemInhHandIndex));
|
|
|
|
for (int i = 0; i < 26; i++) {
|
|
// Empty left space
|
|
buffer.append("\033[0m ".repeat(Math.max(0, startLeft)));
|
|
|
|
if (i == 0 || i == 25) {
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(INVENTORY_SIZE_PX - 2));
|
|
} else {
|
|
for (int j = 0; j < 9; j++) {
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(2));
|
|
if (sprites.get(j) == null) {
|
|
buffer.append("\033[0m ".repeat(50));
|
|
continue;
|
|
}
|
|
|
|
String x = sprites.get(j).split("\n")[i];
|
|
buffer.append(x);
|
|
}
|
|
}
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(2));
|
|
buffer.append("\033[0m\n");
|
|
}
|
|
}
|
|
|
|
public void renderFull(StringBuilder buffer, Terminal terminal, SpriteList spriteList, boolean includeCrafting,
|
|
Optional<Integer> moveTopCustom) {
|
|
int widthPixels = COLUMN_AMOUNT * (50 + 4) + 2;
|
|
int heightPixels = ROW_AMOUNT * (25 + 1);
|
|
|
|
int moveLeft = Math.max(0, (terminal.getWidth() / 2) - (widthPixels / 2));
|
|
int moveTop = moveTopCustom.orElse((terminal.getHeight() / 2) - (heightPixels / 2));
|
|
|
|
List<String> sprites = getSprites(items, spriteList, selectedItemInv);
|
|
|
|
// Top center
|
|
buffer.append("\n".repeat(Math.max(0, moveTopCustom.isPresent() ? 0 : moveTop)));
|
|
|
|
buffer.append("\033[0m ".repeat(moveLeft));
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(widthPixels)).append("\033[0m\n");
|
|
|
|
String[] craftingTable = smallCraftingTable.render(spriteList).toString().split("\n");
|
|
int spacesFromTop = (ROW_AMOUNT - SmallCraftingTable.ROW_AMOUNT) / 2;
|
|
|
|
for (int i = 0; i < ROW_AMOUNT; i++) {
|
|
for (int j = 0; j < 26; j++) {
|
|
buffer.append("\033[0m ".repeat(moveLeft));
|
|
if (j < 25) {
|
|
buffer.append("\033[38;5;231;48;5;231m▓");
|
|
for (int k = 0; k < COLUMN_AMOUNT; k++) {
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(2));
|
|
var item = items[i * COLUMN_AMOUNT + k];
|
|
if (item == null) {
|
|
buffer.append("\033[0m ".repeat(50));
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(2));
|
|
continue;
|
|
}
|
|
var sprite = sprites.get(i * COLUMN_AMOUNT + k).split("\n");
|
|
buffer.append(sprite[j]);
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(2));
|
|
}
|
|
buffer.append("\033[38;5;231;48;5;231m▓");
|
|
} else {
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(widthPixels));
|
|
if (i == 0 && includeCrafting) {
|
|
buffer.append("\033[0m").append(" ".repeat(20));
|
|
buffer.append("\033[38;5;231;48;5;231m▓".repeat(106));
|
|
}
|
|
}
|
|
|
|
if (i + 1 > spacesFromTop && includeCrafting) {
|
|
int craftingIndex = ((i - spacesFromTop) * 26) + j;
|
|
|
|
if (craftingIndex < craftingTable.length) {
|
|
buffer.append("\033[0m").append(" ".repeat(20));
|
|
buffer.append(craftingTable[craftingIndex]);
|
|
}
|
|
}
|
|
|
|
buffer.append("\n");
|
|
}
|
|
}
|
|
|
|
buffer.append("\n".repeat(10));
|
|
|
|
renderHotbar(buffer, spriteList, terminal, true);
|
|
}
|
|
|
|
public List<String> getSprites(InventoryItem[] items, SpriteList spriteList, int selectedItem) {
|
|
List<String> sprites = new ArrayList<>();
|
|
|
|
for (int i = 0; i < items.length; i++) {
|
|
var item = items[i];
|
|
|
|
if (item == null) {
|
|
if (i == selectedItem) {
|
|
sprites.add(getHotbarBackground());
|
|
continue;
|
|
}
|
|
|
|
sprites.add(null);
|
|
continue;
|
|
}
|
|
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
if (item.getItem().getFirst().getDurability() != 0
|
|
|| item.getItem().getFirst().getDurability() == item.getItem().getFirst().getMaxDurability()) {
|
|
stringBuilder.append(("\033[0m ".repeat(50) + "\n").repeat(21));
|
|
|
|
stringBuilder.append("\033[0m ".repeat(4));
|
|
int width = (int) (((double) item.getItem().getFirst().getDurability()
|
|
/ item.getItem().getFirst().getMaxDurability()) * 42);
|
|
|
|
stringBuilder.append("\033[38;5;231;48;5;231m▓".repeat(width));
|
|
stringBuilder.append("\033[40m ".repeat(42 - width));
|
|
stringBuilder.append("\033[0m ".repeat(4));
|
|
stringBuilder.append("\n");
|
|
|
|
stringBuilder.append(("\033[0m ".repeat(50) + "\n").repeat(3));
|
|
}
|
|
|
|
String sprite;
|
|
|
|
if (i == selectedItem) {
|
|
sprite = SpriteCombiner
|
|
.combineTwoSprites(getHotbarBackground(),
|
|
SpriteCombiner.combineTwoSprites(
|
|
item.getItem().getFirst().getSpriteState().isPresent()
|
|
? spriteList.getSprite(item.getItem().getFirst().getSprite())
|
|
.getSprite(item.getItem().getFirst().getSpriteState()
|
|
.get())
|
|
: spriteList.getSprite(item.getItem().getFirst().getSprite())
|
|
.getSprite(),
|
|
Numbers.getNumberSprite(item.getAmount(), spriteList)));
|
|
} else {
|
|
sprite = SpriteCombiner.combineTwoSprites(
|
|
item.getItem().getFirst().getSpriteState().isPresent()
|
|
? spriteList.getSprite(item.getItem().getFirst().getSprite())
|
|
.getSprite(item.getItem().getFirst().getSpriteState().get())
|
|
: spriteList.getSprite(item.getItem().getFirst().getSprite()).getSprite(),
|
|
Numbers.getNumberSprite(item.getAmount(), spriteList));
|
|
}
|
|
|
|
if (item.getItem().getFirst().getDurability() == 0
|
|
|| item.getItem().getFirst().getDurability() == item.getItem().getFirst().getMaxDurability()) {
|
|
sprites.add(sprite);
|
|
} else {
|
|
sprites.add(SpriteCombiner.combineTwoSprites(sprite, stringBuilder.toString()));
|
|
}
|
|
}
|
|
|
|
return sprites;
|
|
}
|
|
|
|
public InventoryDTO getItem(int index, Optional<InventoryItem[]> i) {
|
|
if (index < 20) {
|
|
// Normal inventory
|
|
return new InventoryDTO(items, index);
|
|
} else if (index >= 50) {
|
|
return new InventoryDTO(i.get(), index - 50);
|
|
} else if (index >= 29) {
|
|
// Small crafting table
|
|
return new InventoryDTO(smallCraftingTable.getItems(), index - 29);
|
|
} else {
|
|
// Hotbar
|
|
return new InventoryDTO(hotbar, index - 20);
|
|
}
|
|
}
|
|
|
|
public InventoryItem getSelectedItemNo(Optional<InventoryItem[]> i) {
|
|
InventoryDTO data = getItem(selectedItemInv, i);
|
|
if (selectedItemInv == -1) {
|
|
return null;
|
|
}
|
|
return data.getObj()[data.getIndex()];
|
|
}
|
|
|
|
public InventoryItem getSelectedItem(Optional<InventoryItem[]> i) {
|
|
InventoryItem temp;
|
|
InventoryDTO data = getItem(selectedItemInv, i);
|
|
temp = data.getObj()[data.getIndex()];
|
|
data.getObj()[data.getIndex()] = null;
|
|
|
|
selectedItemInv = -1;
|
|
rightClick = false;
|
|
|
|
return temp;
|
|
}
|
|
|
|
public InventoryItem getOne(Optional<InventoryItem[]> i) {
|
|
InventoryDTO inventoryItem = getItem(selectedItemInv, i);
|
|
if (inventoryItem.getIndex() == -1) {
|
|
return null;
|
|
}
|
|
InventoryItem item = inventoryItem.getObj()[inventoryItem.getIndex()];
|
|
if (item.getAmount() == 1) {
|
|
return getSelectedItem(i);
|
|
}
|
|
|
|
rightClick = false;
|
|
|
|
var ij = new InventoryItem(1, item.getItem().getLast());
|
|
item.decrease();
|
|
|
|
return ij;
|
|
}
|
|
|
|
public InventoryItem getHalf(Optional<InventoryItem[]> i) {
|
|
InventoryDTO inventoryItem = getItem(selectedItemInv, i);
|
|
InventoryItem item = inventoryItem.getObj()[inventoryItem.getIndex()];
|
|
if (item.getAmount() == 1) {
|
|
return getSelectedItem(i);
|
|
}
|
|
|
|
int half = item.getAmount() / 2;
|
|
|
|
var inv = new InventoryItem();
|
|
|
|
for (int j = 0; j < half; j++) {
|
|
inv.add(item.getItem().getLast());
|
|
item.decrease();
|
|
}
|
|
|
|
selectedItemInv = -1;
|
|
rightClick = false;
|
|
|
|
return inv;
|
|
}
|
|
|
|
public boolean hasSelectedItem() {
|
|
return selectedItemInv != -1;
|
|
}
|
|
|
|
public boolean mergeItems(int indexFrom, int indexTo, Optional<InventoryItem[]> i) {
|
|
InventoryDTO fromData = getItem(indexFrom, i);
|
|
InventoryDTO toData = getItem(indexTo, i);
|
|
|
|
InventoryItem fromItem = fromData.getObj()[fromData.getIndex()];
|
|
InventoryItem toItem = toData.getObj()[toData.getIndex()];
|
|
|
|
if (fromItem == null || toItem == null) {
|
|
return false; // Nothing to merge
|
|
}
|
|
|
|
if (!fromItem.getItem().getFirst().isStackable() || !toItem.getItem().getFirst().isStackable()) {
|
|
return false;
|
|
}
|
|
|
|
if (!fromItem.getItem().getFirst().equals(toItem.getItem().getFirst())) {
|
|
return false; // Different items cannot be merged
|
|
}
|
|
|
|
while (true) {
|
|
if (toItem.getAmount() == 64) {
|
|
break;
|
|
}
|
|
|
|
if (fromItem.getAmount() == 0) {
|
|
fromData.getObj()[fromData.getIndex()] = null;
|
|
break;
|
|
}
|
|
|
|
toItem.add(fromItem.getItem().getLast());
|
|
fromItem.decrease();
|
|
}
|
|
|
|
selectedItemInv = -1;
|
|
|
|
return true;
|
|
}
|
|
|
|
public void mergeOne(int fromIndex, int toIndex, Optional<InventoryItem[]> i) {
|
|
InventoryDTO fromSlot = getItem(fromIndex, i);
|
|
InventoryDTO toSlot = getItem(toIndex, i);
|
|
|
|
InventoryItem fromItem = fromSlot.getObj()[fromSlot.getIndex()];
|
|
InventoryItem toItem = toSlot.getObj()[toSlot.getIndex()];
|
|
|
|
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.add(fromItem.getItem().getLast());
|
|
fromItem.decrease();
|
|
|
|
// Remove source item if empty
|
|
if (fromItem.getAmount() <= 0) {
|
|
fromSlot.getObj()[fromSlot.getIndex()] = null;
|
|
selectedItemInv = -1;
|
|
}
|
|
}
|
|
|
|
public void exit() {
|
|
// Put all items from crafting to inv
|
|
for (int i = 0; i < smallCraftingTable.getItems().length; i++) {
|
|
InventoryItem item = smallCraftingTable.getItems()[i];
|
|
if (item == null) {
|
|
continue;
|
|
}
|
|
|
|
addItem(item);
|
|
smallCraftingTable.getItems()[i] = null;
|
|
}
|
|
}
|
|
}
|