Crafting Overhaul: 20+ recipes, Log->Planks, proper stack/split mechanics - v2.1.9
This commit is contained in:
parent
b200e9e07f
commit
910e2d6a6e
Binary file not shown.
|
|
@ -1 +1 @@
|
|||
v2.1.8
|
||||
v2.1.9
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1 +1 @@
|
|||
v2.1.8
|
||||
v2.1.9
|
||||
|
|
|
|||
243
src/main.cpp
243
src/main.cpp
|
|
@ -25,7 +25,10 @@
|
|||
enum BlockType {
|
||||
AIR = 0, GRASS = 1, DIRT = 2, COBBLESTONE = 3, LOG = 4, LEAVES = 5, PLANK = 6,
|
||||
STONE = 7, BEDROCK = 8, DIAMOND_ORE = 9, IRON_ORE = 10, GRAVEL = 11, CRAFTING_TABLE = 12, SAND = 13,
|
||||
STICK = 14, WOOD_AXE = 15
|
||||
STICK = 14, WOOD_AXE = 15,
|
||||
WOOD_PICKAXE = 16, WOOD_SWORD = 17, WOOD_SHOVEL = 18, WOOD_HOE = 19,
|
||||
STONE_AXE = 20, STONE_PICKAXE = 21, STONE_SWORD = 22, STONE_SHOVEL = 23, STONE_HOE = 24,
|
||||
FURNACE = 25, CHEST = 26, LADDER = 27, FENCE = 28, TORCH = 29, DOOR = 30, STONE_SLAB = 31
|
||||
};
|
||||
|
||||
std::string GetBlockName(int type) {
|
||||
|
|
@ -46,6 +49,22 @@ std::string GetBlockName(int type) {
|
|||
case SAND: return "Sand";
|
||||
case STICK: return "Stick";
|
||||
case WOOD_AXE: return "Wooden Axe";
|
||||
case WOOD_PICKAXE: return "Wooden Pickaxe";
|
||||
case WOOD_SWORD: return "Wooden Sword";
|
||||
case WOOD_SHOVEL: return "Wooden Shovel";
|
||||
case WOOD_HOE: return "Wooden Hoe";
|
||||
case STONE_AXE: return "Stone Axe";
|
||||
case STONE_PICKAXE: return "Stone Pickaxe";
|
||||
case STONE_SWORD: return "Stone Sword";
|
||||
case STONE_SHOVEL: return "Stone Shovel";
|
||||
case STONE_HOE: return "Stone Hoe";
|
||||
case FURNACE: return "Furnace";
|
||||
case CHEST: return "Chest";
|
||||
case LADDER: return "Ladder";
|
||||
case FENCE: return "Fence";
|
||||
case TORCH: return "Torch";
|
||||
case DOOR: return "Wooden Door";
|
||||
case STONE_SLAB: return "Stone Slab";
|
||||
default: return "Unknown Item";
|
||||
}
|
||||
}
|
||||
|
|
@ -99,7 +118,7 @@ struct Chunk {
|
|||
bool generated = false;
|
||||
bool modified = false;
|
||||
bool dirty = true;
|
||||
std::vector<Vector3> renderLists[16];
|
||||
std::vector<Vector3> renderLists[32];
|
||||
Chunk() : generated(false), modified(false), maxY(0), dirty(true) {}
|
||||
};
|
||||
|
||||
|
|
@ -245,7 +264,7 @@ int GetBlock(int x, int y, int z) {
|
|||
}
|
||||
|
||||
void RebuildChunkRenderList(Chunk* chunk, int cx, int cz) {
|
||||
for (int i = 0; i < 16; i++) chunk->renderLists[i].clear();
|
||||
for (int i = 0; i < 32; i++) chunk->renderLists[i].clear();
|
||||
|
||||
// Neighbors for exposure check
|
||||
auto itNM = worldChunks.find({cx-1, cz});
|
||||
|
|
@ -940,7 +959,7 @@ int main(void)
|
|||
camera3D.projection = CAMERA_PERSPECTIVE;
|
||||
|
||||
// 3D Block Textures Setup
|
||||
Texture2D blockTextures[32] = {0};
|
||||
Texture2D blockTextures[64] = {0};
|
||||
blockTextures[DIRT] = LoadTexture("assets/dirt.png");
|
||||
blockTextures[GRASS] = LoadTexture("assets/grass.png");
|
||||
blockTextures[COBBLESTONE] = LoadTexture("assets/cobblestone.png");
|
||||
|
|
@ -986,48 +1005,179 @@ int main(void)
|
|||
InventorySlot tableResult(AIR, 0);
|
||||
|
||||
auto UpdateCrafting = [&]() {
|
||||
// Count non-empty slots
|
||||
int filledSlots = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (craftingSlots[i].blockType != AIR) filledSlots++;
|
||||
}
|
||||
|
||||
// Recipe: 1 Log -> 4 Planks (single slot, any position)
|
||||
if (filledSlots == 1) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (craftingSlots[i].blockType == LOG) {
|
||||
craftingResult = InventorySlot(PLANK, 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recipe: 4 Planks -> 1 Crafting Table
|
||||
if (craftingSlots[0].blockType == PLANK && craftingSlots[1].blockType == PLANK &&
|
||||
craftingSlots[2].blockType == PLANK && craftingSlots[3].blockType == PLANK) {
|
||||
craftingResult = InventorySlot(CRAFTING_TABLE, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Recipe: 2 Planks (vertical) -> 4 Sticks
|
||||
else if ((craftingSlots[0].blockType == PLANK && craftingSlots[2].blockType == PLANK) ||
|
||||
(craftingSlots[1].blockType == PLANK && craftingSlots[3].blockType == PLANK)) {
|
||||
if ((craftingSlots[0].blockType == PLANK && craftingSlots[2].blockType == PLANK &&
|
||||
craftingSlots[1].blockType == AIR && craftingSlots[3].blockType == AIR) ||
|
||||
(craftingSlots[1].blockType == PLANK && craftingSlots[3].blockType == PLANK &&
|
||||
craftingSlots[0].blockType == AIR && craftingSlots[2].blockType == AIR)) {
|
||||
craftingResult = InventorySlot(STICK, 4);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
craftingResult = InventorySlot(AIR, 0);
|
||||
}
|
||||
|
||||
craftingResult = InventorySlot(AIR, 0);
|
||||
};
|
||||
|
||||
auto UpdateTableCrafting = [&]() {
|
||||
// Wooden Axe Recipe
|
||||
// [P P .]
|
||||
// [P S .]
|
||||
// [. S .]
|
||||
if (tableSlots[0].blockType == PLANK && tableSlots[1].blockType == PLANK &&
|
||||
tableSlots[3].blockType == PLANK && tableSlots[4].blockType == STICK &&
|
||||
tableSlots[7].blockType == STICK) {
|
||||
tableResult = InventorySlot(WOOD_AXE, 1);
|
||||
// Helper: get block type at grid position, -1 if out of bounds
|
||||
auto T = [&](int i) -> int { return (i >= 0 && i < 9) ? tableSlots[i].blockType : AIR; };
|
||||
|
||||
// Count filled slots and find bounding box
|
||||
int filledSlots = 0;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (T(i) != AIR) filledSlots++;
|
||||
}
|
||||
// Sticks (vertical anywhere)
|
||||
else if ((tableSlots[0].blockType == PLANK && tableSlots[3].blockType == PLANK) ||
|
||||
(tableSlots[1].blockType == PLANK && tableSlots[4].blockType == PLANK) ||
|
||||
(tableSlots[2].blockType == PLANK && tableSlots[5].blockType == PLANK) ||
|
||||
(tableSlots[3].blockType == PLANK && tableSlots[6].blockType == PLANK) ||
|
||||
(tableSlots[4].blockType == PLANK && tableSlots[7].blockType == PLANK) ||
|
||||
(tableSlots[5].blockType == PLANK && tableSlots[8].blockType == PLANK)) {
|
||||
tableResult = InventorySlot(STICK, 4);
|
||||
|
||||
// === SINGLE SLOT RECIPES ===
|
||||
if (filledSlots == 1) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (T(i) == LOG) { tableResult = InventorySlot(PLANK, 4); return; }
|
||||
}
|
||||
}
|
||||
// 4 Planks -> 1 Table (3x3 grid)
|
||||
else if (tableSlots[0].blockType == PLANK && tableSlots[1].blockType == PLANK &&
|
||||
tableSlots[3].blockType == PLANK && tableSlots[4].blockType == PLANK) {
|
||||
tableResult = InventorySlot(CRAFTING_TABLE, 1);
|
||||
|
||||
// === Helper: Check a 3x3 pattern against grid ===
|
||||
// Pattern: array of 9 ints, -1 means "must be empty", type means "must match"
|
||||
auto checkPattern = [&](int p[9]) -> bool {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (p[i] == -1) { if (T(i) != AIR) return false; }
|
||||
else { if (T(i) != p[i]) return false; }
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// === TOOLS (check all valid column offsets) ===
|
||||
// Wooden Pickaxe: PPP / .S. / .S.
|
||||
for (int c = 0; c <= 0; c++) {
|
||||
int p[9] = {PLANK, PLANK, PLANK, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(WOOD_PICKAXE, 1); return; }
|
||||
}
|
||||
else {
|
||||
tableResult = InventorySlot(AIR, 0);
|
||||
|
||||
// Wooden Axe: PP. / PS. / .S. (and mirrored PP. -> .PP)
|
||||
{ int p[9] = {PLANK, PLANK, -1, PLANK, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(WOOD_AXE, 1); return; } }
|
||||
{ int p[9] = {-1, PLANK, PLANK, -1, STICK, PLANK, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(WOOD_AXE, 1); return; } }
|
||||
|
||||
// Wooden Sword: .P. / .P. / .S.
|
||||
{ int p[9] = {-1, PLANK, -1, -1, PLANK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(WOOD_SWORD, 1); return; } }
|
||||
|
||||
// Wooden Shovel: .P. / .S. / .S.
|
||||
{ int p[9] = {-1, PLANK, -1, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(WOOD_SHOVEL, 1); return; } }
|
||||
|
||||
// Wooden Hoe: PP. / .S. / .S. (and mirrored)
|
||||
{ int p[9] = {PLANK, PLANK, -1, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(WOOD_HOE, 1); return; } }
|
||||
{ int p[9] = {-1, PLANK, PLANK, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(WOOD_HOE, 1); return; } }
|
||||
|
||||
// Stone Pickaxe: CCC / .S. / .S.
|
||||
{ int p[9] = {COBBLESTONE, COBBLESTONE, COBBLESTONE, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_PICKAXE, 1); return; } }
|
||||
|
||||
// Stone Axe: CC. / CS. / .S. (and mirrored)
|
||||
{ int p[9] = {COBBLESTONE, COBBLESTONE, -1, COBBLESTONE, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_AXE, 1); return; } }
|
||||
{ int p[9] = {-1, COBBLESTONE, COBBLESTONE, -1, STICK, COBBLESTONE, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_AXE, 1); return; } }
|
||||
|
||||
// Stone Sword: .C. / .C. / .S.
|
||||
{ int p[9] = {-1, COBBLESTONE, -1, -1, COBBLESTONE, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_SWORD, 1); return; } }
|
||||
|
||||
// Stone Shovel: .C. / .S. / .S.
|
||||
{ int p[9] = {-1, COBBLESTONE, -1, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_SHOVEL, 1); return; } }
|
||||
|
||||
// Stone Hoe: CC. / .S. / .S. (and mirrored)
|
||||
{ int p[9] = {COBBLESTONE, COBBLESTONE, -1, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_HOE, 1); return; } }
|
||||
{ int p[9] = {-1, COBBLESTONE, COBBLESTONE, -1, STICK, -1, -1, STICK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_HOE, 1); return; } }
|
||||
|
||||
// === BLOCKS ===
|
||||
// Furnace: CCC / C.C / CCC
|
||||
{ int p[9] = {COBBLESTONE, COBBLESTONE, COBBLESTONE, COBBLESTONE, -1, COBBLESTONE, COBBLESTONE, COBBLESTONE, COBBLESTONE};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(FURNACE, 1); return; } }
|
||||
|
||||
// Chest: PPP / P.P / PPP
|
||||
{ int p[9] = {PLANK, PLANK, PLANK, PLANK, -1, PLANK, PLANK, PLANK, PLANK};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(CHEST, 1); return; } }
|
||||
|
||||
// Door: PP. / PP. / PP.
|
||||
{ int p[9] = {PLANK, PLANK, -1, PLANK, PLANK, -1, PLANK, PLANK, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(DOOR, 3); return; } }
|
||||
{ int p[9] = {-1, PLANK, PLANK, -1, PLANK, PLANK, -1, PLANK, PLANK};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(DOOR, 3); return; } }
|
||||
|
||||
// Fence: PSP / PSP / ... (bottom row empty)
|
||||
{ int p[9] = {PLANK, STICK, PLANK, PLANK, STICK, PLANK, -1, -1, -1};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(FENCE, 3); return; } }
|
||||
{ int p[9] = {-1, -1, -1, PLANK, STICK, PLANK, PLANK, STICK, PLANK};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(FENCE, 3); return; } }
|
||||
|
||||
// Ladder: S.S / SSS / S.S
|
||||
{ int p[9] = {STICK, -1, STICK, STICK, STICK, STICK, STICK, -1, STICK};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(LADDER, 3); return; } }
|
||||
|
||||
// Stone Slab: ... / ... / CCC (bottom row)
|
||||
{ int p[9] = {-1, -1, -1, -1, -1, -1, COBBLESTONE, COBBLESTONE, COBBLESTONE};
|
||||
if (checkPattern(p)) { tableResult = InventorySlot(STONE_SLAB, 6); return; } }
|
||||
|
||||
// === SIMPLE 2x2 RECIPES (in any 2x2 sub-grid of the 3x3) ===
|
||||
// Crafting Table: 2x2 planks (check all four 2x2 positions)
|
||||
for (int r = 0; r <= 1; r++) {
|
||||
for (int c = 0; c <= 1; c++) {
|
||||
int i0 = r*3+c, i1 = r*3+c+1, i2 = (r+1)*3+c, i3 = (r+1)*3+c+1;
|
||||
if (T(i0) == PLANK && T(i1) == PLANK && T(i2) == PLANK && T(i3) == PLANK) {
|
||||
// Make sure other slots are empty
|
||||
bool othersEmpty = true;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (i != i0 && i != i1 && i != i2 && i != i3 && T(i) != AIR) othersEmpty = false;
|
||||
}
|
||||
if (othersEmpty) { tableResult = InventorySlot(CRAFTING_TABLE, 1); return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sticks: 2 planks vertical (in any column, any two adjacent rows)
|
||||
for (int c = 0; c < 3; c++) {
|
||||
for (int r = 0; r <= 1; r++) {
|
||||
int top = r*3+c, bot = (r+1)*3+c;
|
||||
if (T(top) == PLANK && T(bot) == PLANK) {
|
||||
bool othersEmpty = true;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (i != top && i != bot && T(i) != AIR) othersEmpty = false;
|
||||
}
|
||||
if (othersEmpty) { tableResult = InventorySlot(STICK, 4); return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tableResult = InventorySlot(AIR, 0);
|
||||
};
|
||||
// Block Selection State (for wireframe)
|
||||
bool hitBlock = false;
|
||||
|
|
@ -2886,9 +3036,20 @@ int main(void)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
InventorySlot tmp = slot;
|
||||
slot = mouseHeldItem;
|
||||
mouseHeldItem = tmp;
|
||||
// Left click: stack if same type, swap if different
|
||||
if (mouseHeldItem.blockType != AIR && slot.blockType == mouseHeldItem.blockType) {
|
||||
// Same type: merge stacks
|
||||
int space = 64 - slot.count;
|
||||
int toAdd = (mouseHeldItem.count < space) ? mouseHeldItem.count : space;
|
||||
slot.count += toAdd;
|
||||
mouseHeldItem.count -= toAdd;
|
||||
if (mouseHeldItem.count <= 0) mouseHeldItem = InventorySlot(AIR, 0);
|
||||
} else {
|
||||
// Different type or one is empty: swap
|
||||
InventorySlot tmp = slot;
|
||||
slot = mouseHeldItem;
|
||||
mouseHeldItem = tmp;
|
||||
}
|
||||
UpdateCrafting();
|
||||
UpdateTableCrafting();
|
||||
}
|
||||
|
|
@ -2897,10 +3058,16 @@ int main(void)
|
|||
if (hov && IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
||||
if (!isResultSlot) {
|
||||
if (mouseHeldItem.blockType == AIR) {
|
||||
// Pick up half? Not requested, but common.
|
||||
// For now just following user request: "holding a stack... right click into a box, place one"
|
||||
// Empty hand: pick up one item from the slot
|
||||
if (slot.blockType != AIR && slot.count > 0) {
|
||||
mouseHeldItem = InventorySlot(slot.blockType, 1);
|
||||
slot.count--;
|
||||
if (slot.count <= 0) slot = InventorySlot(AIR, 0);
|
||||
UpdateCrafting();
|
||||
UpdateTableCrafting();
|
||||
}
|
||||
} else {
|
||||
// Holding something, place one
|
||||
// Holding something: place one into the slot
|
||||
if (slot.blockType == AIR) {
|
||||
slot = InventorySlot(mouseHeldItem.blockType, 1);
|
||||
mouseHeldItem.count--;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v2.1.8
|
||||
v2.1.9
|
||||
|
|
|
|||
Loading…
Reference in New Issue