diff --git a/assets/stick.png b/assets/stick.png new file mode 100644 index 0000000..484b512 Binary files /dev/null and b/assets/stick.png differ diff --git a/assets/wooden_axe.png b/assets/wooden_axe.png new file mode 100644 index 0000000..495e2e4 Binary files /dev/null and b/assets/wooden_axe.png differ diff --git a/build-linux/MorriCraft b/build-linux/MorriCraft index 89ddc76..16514ba 100755 Binary files a/build-linux/MorriCraft and b/build-linux/MorriCraft differ diff --git a/build-linux/assets/stick.png b/build-linux/assets/stick.png new file mode 100644 index 0000000..484b512 Binary files /dev/null and b/build-linux/assets/stick.png differ diff --git a/build-linux/assets/wooden_axe.png b/build-linux/assets/wooden_axe.png new file mode 100644 index 0000000..495e2e4 Binary files /dev/null and b/build-linux/assets/wooden_axe.png differ diff --git a/build-windows/MorriCraft.exe b/build-windows/MorriCraft.exe index 1c9365f..7000cec 100755 Binary files a/build-windows/MorriCraft.exe and b/build-windows/MorriCraft.exe differ diff --git a/build-windows/assets/stick.png b/build-windows/assets/stick.png new file mode 100644 index 0000000..484b512 Binary files /dev/null and b/build-windows/assets/stick.png differ diff --git a/build-windows/assets/wooden_axe.png b/build-windows/assets/wooden_axe.png new file mode 100644 index 0000000..495e2e4 Binary files /dev/null and b/build-windows/assets/wooden_axe.png differ diff --git a/src/main.cpp b/src/main.cpp index 05439cf..21a1db3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,8 @@ 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 + STONE = 7, BEDROCK = 8, DIAMOND_ORE = 9, IRON_ORE = 10, GRAVEL = 11, CRAFTING_TABLE = 12, SAND = 13, + STICK = 14, WOOD_AXE = 15 }; // Simple 2D Perlin Noise implementation @@ -622,7 +623,11 @@ int main(void) MenuState optionsReturnState = MAIN_MENU; InventorySlot mouseHeldItem(AIR, 0); - float gameTime = 0.0f; // Total game time for day/night cycle + float gameTime = 75.0f; // Start at 6:00 AM + float breakProgress = 0.0f; + int lastHitX = -1, lastHitY = -1, lastHitZ = -1; + float swingTime = 0.0f; + bool isSwinging = false; float targetZoom = 1.1f; float currentZoom = 1.1f; @@ -676,6 +681,10 @@ int main(void) // Safety Fallback: Use Planks if custom textures failed to load (prevents crash) if (craftingSideTexture.id == 0) craftingSideTexture = blockTextures[PLANK]; if (craftingTopTexture.id == 0) craftingTopTexture = blockTextures[PLANK]; + blockTextures[CRAFTING_TABLE] = craftingSideTexture; // Preview for inventory + + blockTextures[STICK] = LoadTexture("assets/stick.png"); + blockTextures[WOOD_AXE] = LoadTexture("assets/wooden_axe.png"); // Inventory Crafting State InventorySlot craftingSlots[4]; // Default to AIR/0 @@ -690,14 +699,44 @@ int main(void) if (craftingSlots[0].blockType == PLANK && craftingSlots[1].blockType == PLANK && craftingSlots[2].blockType == PLANK && craftingSlots[3].blockType == PLANK) { craftingResult = InventorySlot(CRAFTING_TABLE, 1); - } else { + } + // Recipe: 2 Planks (vertical) -> 4 Sticks + else if ((craftingSlots[0].blockType == PLANK && craftingSlots[2].blockType == PLANK) || + (craftingSlots[1].blockType == PLANK && craftingSlots[3].blockType == PLANK)) { + craftingResult = InventorySlot(STICK, 4); + } + else { craftingResult = InventorySlot(AIR, 0); } }; auto UpdateTableCrafting = [&]() { - // Example: 1 plank -> 4 buttons? No, let's just keep it empty for now or add one. - tableResult = InventorySlot(AIR, 0); + // 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); + } + // 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); + } + // 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); + } + else { + tableResult = InventorySlot(AIR, 0); + } }; // Block Selection State (for wireframe) bool hitBlock = false; @@ -903,13 +942,41 @@ int main(void) } if (hitBlock) { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { - int targetBlock = GetBlock(hitX, hitY, hitZ); - if (targetBlock != BEDROCK) { - AddToInventory(targetBlock); - SetBlock(hitX, hitY, hitZ, AIR); + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { + if (hitX != lastHitX || hitY != lastHitY || hitZ != lastHitZ) { + breakProgress = 0.0f; + lastHitX = hitX; lastHitY = hitY; lastHitZ = hitZ; } - } else if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) { + + int targetBlock = GetBlock(hitX, hitY, hitZ); + if (targetBlock != AIR && targetBlock != BEDROCK) { + float breakSpeed = 2.0f; // Seconds to break + + // Axe logic: Wood/Plank/Logs are faster + if (targetBlock == LOG || targetBlock == PLANK || targetBlock == CRAFTING_TABLE) { + if (hotbar[activeHotbarSlot].blockType == WOOD_AXE) breakSpeed = 0.5f; // Fast + else breakSpeed = 1.5f; // Normal + } else if (targetBlock == LEAVES) { + breakSpeed = 0.2f; // Very fast + } + + breakProgress += GetFrameTime(); + + if (breakProgress >= breakSpeed) { + AddToInventory(targetBlock); + SetBlock(hitX, hitY, hitZ, AIR); + breakProgress = 0.0f; + isSwinging = true; // Swing when finishing + } + + // Visual swing while mining + if (fmodf(breakProgress, 0.4f) < 0.1f) isSwinging = true; + } + } else { + breakProgress = 0.0f; + } + + if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) { int targetBlock = GetBlock(hitX, hitY, hitZ); if (targetBlock == CRAFTING_TABLE) { currentState = CRAFTING_GUI; @@ -922,6 +989,7 @@ int main(void) hotbar[activeHotbarSlot].count--; if (hotbar[activeHotbarSlot].count == 0) hotbar[activeHotbarSlot].blockType = AIR; + isSwinging = true; // Swing when placing } } } @@ -986,8 +1054,8 @@ int main(void) DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE); EndMode2D(); - // Show Version Number (v1.5.2) in Red - DrawTextEx(customFont, "v1.5.2", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED); + // Show Version Number (v1.6.1) in Red + DrawTextEx(customFont, "v1.6.1", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED); } Vector2 mousePos = GetMousePosition(); @@ -1417,7 +1485,7 @@ int main(void) } // Draw Gameplay overlay if we entered gameplay - if (currentState == GAMEPLAY || currentState == PAUSE_MENU) { + if (currentState == GAMEPLAY || currentState == PAUSE_MENU || currentState == CRAFTING_GUI) { // ---- Day / Night Cycle Calculations ---- float cycleLength = 300.0f; // 5 minutes float timeOfDay = fmodf(gameTime, cycleLength) / cycleLength; @@ -1556,8 +1624,66 @@ int main(void) } } // Draw Block Selection Wireframe - if (hitBlock && !inventoryOpen) { - DrawCubeWires((Vector3){(float)hitX, (float)hitY, (float)hitZ}, 1.02f, 1.02f, 1.02f, BLACK); + if (hitBlock && !inventoryOpen && currentState != CRAFTING_GUI) { + float size = 1.02f; + DrawCubeWires((Vector3){(float)hitX, (float)hitY, (float)hitZ}, size, size, size, BLACK); + + // Draw breaking progress indicator + // Draw breaking progress indicator + if (breakProgress > 0.0f) { + float pSize = (breakProgress / 1.5f) * 1.05f; // Scale visual based on progress + if (pSize > 1.05f) pSize = 1.05f; + DrawCubeWires((Vector3){(float)hitX, (float)hitY, (float)hitZ}, pSize, pSize, pSize, RED); + } + } + + // --- DRAW VIEWMODEL (ARM/HELD ITEM) --- + if (!inventoryOpen && currentState != CRAFTING_GUI) { + if (isSwinging) { + swingTime += GetFrameTime() * 8.0f; + if (swingTime >= 1.0f) { + swingTime = 0.0f; + isSwinging = false; + } + } + + float swingVal = sinf(swingTime * PI); + + rlDisableDepthTest(); // Draw on top + rlPushMatrix(); + // Transform to camera space manually for the viewmodel + Vector3 forwardVM = Vector3Subtract(camera3D.target, camera3D.position); + forwardVM = Vector3Normalize(forwardVM); + Vector3 rightVM = Vector3CrossProduct(forwardVM, camera3D.up); + rightVM = Vector3Normalize(rightVM); + Vector3 upVM = Vector3CrossProduct(rightVM, forwardVM); + upVM = Vector3Normalize(upVM); + + Vector3 handPos = Vector3Add(camera3D.position, Vector3Scale(forwardVM, 0.4f)); + handPos = Vector3Add(handPos, Vector3Scale(rightVM, 0.25f)); + handPos = Vector3Add(handPos, Vector3Scale(upVM, -0.2f - swingVal * 0.1f)); + + // Draw Arm + DrawCube(handPos, 0.08f, 0.2f, 0.08f, (Color){220, 180, 150, 255}); + + // Draw Held Item + int heldBT = hotbar[activeHotbarSlot].blockType; + if (heldBT != AIR) { + Vector3 itemPos = Vector3Add(handPos, Vector3Scale(upVM, 0.1f)); + itemPos = Vector3Add(itemPos, Vector3Scale(forwardVM, 0.1f)); + + if (heldBT < STICK) { + // Block + DrawCube(itemPos, 0.15f, 0.15f, 0.15f, blockTint); + DrawCubeWires(itemPos, 0.151f, 0.151f, 0.151f, BLACK); + } else { + // Item (Stick/Axe) - use small thin cube for now + Color itemColor = (heldBT == STICK) ? BROWN : DARKGRAY; + DrawCube(itemPos, 0.03f, 0.25f, 0.03f, itemColor); + } + } + rlPopMatrix(); + rlEnableDepthTest(); } EndMode3D(); @@ -1662,6 +1788,10 @@ int main(void) Rectangle dst = { (float)(px+5),(float)(py+5), (float)(invSlotSize-10),(float)(invSlotSize-10) }; Color tint = (bt == GRASS) ? (Color){124,189,107,255} : WHITE; DrawTexturePro(tex, src, dst, (Vector2){0,0}, 0.0f, tint); + } else if (bt >= STICK) { + // Fallback rendering for items if texture failed + Color itemCol = (bt == STICK) ? BROWN : DARKGRAY; + DrawRectangle(px + 10, py + 10, invSlotSize - 20, invSlotSize - 20, itemCol); } Vector2 cSize = MeasureTextEx(customFont, TextFormat("%i", slot.count), 12, 1.0f); DrawTextEx(customFont, TextFormat("%i", slot.count),