Fix crafting table crash and add HUD clock - v1.5.1

This commit is contained in:
Michael Howard 2026-04-23 14:52:15 -05:00
parent 920378fac6
commit 99e348abc5
3 changed files with 90 additions and 18 deletions

Binary file not shown.

Binary file not shown.

View File

@ -419,7 +419,7 @@ void DrawTexturedCube(Vector3 position, float width, float height, float length,
// Draws a grass block with correct per-face textures: // Draws a grass block with correct per-face textures:
// top=green grass, sides=dirt+grass stripe, bottom=pure dirt. // top=green grass, sides=dirt+grass stripe, bottom=pure dirt.
// Caller must NOT have an active rlSetTexture — this function manages its own binds. // Caller must NOT have an active rlSetTexture — this function manages its own binds.
void DrawGrassBlock(Vector3 position, unsigned int sideTexId, unsigned int topTexId, unsigned int botTexId) { void DrawGrassBlock(Vector3 position, unsigned int sideTexId, unsigned int topTexId, unsigned int botTexId, Color tint) {
float x = position.x; float x = position.x;
float y = position.y; float y = position.y;
float z = position.z; float z = position.z;
@ -427,7 +427,7 @@ void DrawGrassBlock(Vector3 position, unsigned int sideTexId, unsigned int topTe
// ---- SIDES (4 faces) ---- // ---- SIDES (4 faces) ----
rlSetTexture(sideTexId); rlSetTexture(sideTexId);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255); rlColor4ub(tint.r, tint.g, tint.b, 255);
// Front // Front
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z + 0.5f);
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f);
@ -453,7 +453,10 @@ void DrawGrassBlock(Vector3 position, unsigned int sideTexId, unsigned int topTe
// ---- TOP (pure green) ---- // ---- TOP (pure green) ----
rlSetTexture(topTexId); rlSetTexture(topTexId);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(124, 189, 107, 255); // Minecraft grass green tint // Combine grass green with ambient light
rlColor4ub((unsigned char)(124 * (tint.r/255.0f)),
(unsigned char)(189 * (tint.g/255.0f)),
(unsigned char)(107 * (tint.b/255.0f)), 255);
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y + 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y + 0.5f, z - 0.5f);
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z + 0.5f);
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z + 0.5f); rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z + 0.5f);
@ -461,7 +464,7 @@ void DrawGrassBlock(Vector3 position, unsigned int sideTexId, unsigned int topTe
// ---- BOTTOM (pure dirt) ---- // ---- BOTTOM (pure dirt) ----
rlSetTexture(botTexId); rlSetTexture(botTexId);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255); rlColor4ub(tint.r, tint.g, tint.b, 255);
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z - 0.5f); rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z - 0.5f);
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z - 0.5f);
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f);
@ -470,13 +473,13 @@ void DrawGrassBlock(Vector3 position, unsigned int sideTexId, unsigned int topTe
} }
// Draws a crafting table with custom top and sides // Draws a crafting table with custom top and sides
void DrawCraftingTable(Vector3 position, unsigned int sideTexId, unsigned int topTexId, unsigned int botTexId) { void DrawCraftingTable(Vector3 position, unsigned int sideTexId, unsigned int topTexId, unsigned int botTexId, Color tint) {
float x = position.x; float y = position.y; float z = position.z; float x = position.x; float y = position.y; float z = position.z;
// SIDES // SIDES
rlSetTexture(sideTexId); rlSetTexture(sideTexId);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255); rlColor4ub(tint.r, tint.g, tint.b, 255);
// Front, Back, Right, Left // Front, Back, Right, Left
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z + 0.5f);
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z - 0.5f); rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z - 0.5f); rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z - 0.5f); rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z - 0.5f);
@ -487,6 +490,7 @@ void DrawCraftingTable(Vector3 position, unsigned int sideTexId, unsigned int to
// TOP // TOP
rlSetTexture(topTexId); rlSetTexture(topTexId);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(tint.r, tint.g, tint.b, 255);
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y + 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - 0.5f, y + 0.5f, z - 0.5f);
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - 0.5f, y + 0.5f, z + 0.5f);
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z + 0.5f); rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + 0.5f, y + 0.5f, z + 0.5f);
@ -496,6 +500,7 @@ void DrawCraftingTable(Vector3 position, unsigned int sideTexId, unsigned int to
// BOTTOM (dirt) // BOTTOM (dirt)
rlSetTexture(botTexId); rlSetTexture(botTexId);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(tint.r, tint.g, tint.b, 255);
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z - 0.5f); rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - 0.5f, y - 0.5f, z - 0.5f);
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z - 0.5f); rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + 0.5f, y - 0.5f, z - 0.5f);
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f); rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + 0.5f, y - 0.5f, z + 0.5f);
@ -617,6 +622,7 @@ int main(void)
MenuState optionsReturnState = MAIN_MENU; MenuState optionsReturnState = MAIN_MENU;
InventorySlot mouseHeldItem(AIR, 0); InventorySlot mouseHeldItem(AIR, 0);
float gameTime = 0.0f; // Total game time for day/night cycle
float targetZoom = 1.1f; float targetZoom = 1.1f;
float currentZoom = 1.1f; float currentZoom = 1.1f;
@ -666,7 +672,10 @@ int main(void)
Texture2D grassTopTexture = LoadTexture("assets/grass_top.png"); Texture2D grassTopTexture = LoadTexture("assets/grass_top.png");
Texture2D craftingSideTexture = LoadTexture("assets/crafting_table_side.png"); Texture2D craftingSideTexture = LoadTexture("assets/crafting_table_side.png");
Texture2D craftingTopTexture = LoadTexture("assets/crafting_table_top.png"); Texture2D craftingTopTexture = LoadTexture("assets/crafting_table_top.png");
blockTextures[CRAFTING_TABLE] = craftingSideTexture; // Default preview
// 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];
// Inventory Crafting State // Inventory Crafting State
InventorySlot craftingSlots[4]; // Default to AIR/0 InventorySlot craftingSlots[4]; // Default to AIR/0
@ -740,6 +749,8 @@ int main(void)
// Gameplay Update // Gameplay Update
if (currentState == GAMEPLAY) { if (currentState == GAMEPLAY) {
gameTime += GetFrameTime();
// Hotbar slot selection (keys 1-9) // Hotbar slot selection (keys 1-9)
if (IsKeyPressed(KEY_ONE)) activeHotbarSlot = 0; if (IsKeyPressed(KEY_ONE)) activeHotbarSlot = 0;
if (IsKeyPressed(KEY_TWO)) activeHotbarSlot = 1; if (IsKeyPressed(KEY_TWO)) activeHotbarSlot = 1;
@ -975,8 +986,8 @@ int main(void)
DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE); DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE);
EndMode2D(); EndMode2D();
// Show Version Number (v1.4.2) in Red // Show Version Number (v1.5.1) in Red
DrawTextEx(customFont, "v1.4.2", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED); DrawTextEx(customFont, "v1.5.1", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED);
} }
Vector2 mousePos = GetMousePosition(); Vector2 mousePos = GetMousePosition();
@ -1407,10 +1418,33 @@ int main(void)
// Draw Gameplay overlay if we entered gameplay // Draw Gameplay overlay if we entered gameplay
if (currentState == GAMEPLAY || currentState == PAUSE_MENU) { if (currentState == GAMEPLAY || currentState == PAUSE_MENU) {
// Clear the background to a sky color // ---- Day / Night Cycle Calculations ----
ClearBackground((Color){ 135, 206, 235, 255 }); // Sky Blue float cycleLength = 300.0f; // 5 minutes
float timeOfDay = fmodf(gameTime, cycleLength) / cycleLength;
float sunAngle = timeOfDay * 2.0f * PI - PI/2.0f; // Offset so it starts at sunrise
float dayFactor = (sinf(sunAngle) + 1.0f) / 2.0f; // 0 (night) to 1 (day)
float lightLevel = 0.2f + 0.8f * dayFactor; // Ambient light multiplier
Color blockTint = { (unsigned char)(255 * lightLevel), (unsigned char)(255 * lightLevel), (unsigned char)(255 * lightLevel), 255 };
Color skyBlue = { 135, 206, 235, 255 };
Color nightBlue = { 10, 10, 25, 255 };
Color currentSky = {
(unsigned char)(nightBlue.r + dayFactor * (skyBlue.r - nightBlue.r)),
(unsigned char)(nightBlue.g + dayFactor * (skyBlue.g - nightBlue.g)),
(unsigned char)(nightBlue.b + dayFactor * (skyBlue.b - nightBlue.b)),
255
};
ClearBackground(currentSky);
BeginMode3D(camera3D); BeginMode3D(camera3D);
// Draw Sun and Moon (simple billboards or spheres far away)
Vector3 sunPos = { camera3D.position.x + cosf(sunAngle) * 100, camera3D.position.y + sinf(sunAngle) * 100, camera3D.position.z };
Vector3 moonPos = { camera3D.position.x + cosf(sunAngle + PI) * 100, camera3D.position.y + sinf(sunAngle + PI) * 100, camera3D.position.z };
DrawSphere(sunPos, 5.0f, YELLOW);
DrawSphere(moonPos, 4.0f, LIGHTGRAY);
int playerCX = (int)floorf(camera3D.position.x / CHUNK_SIZE); int playerCX = (int)floorf(camera3D.position.x / CHUNK_SIZE);
int playerCZ = (int)floorf(camera3D.position.z / CHUNK_SIZE); int playerCZ = (int)floorf(camera3D.position.z / CHUNK_SIZE);
@ -1439,9 +1473,11 @@ int main(void)
for (int ly = 0; ly <= chunk->maxY; ly++) { for (int ly = 0; ly <= chunk->maxY; ly++) {
for (int lz = 0; lz < CHUNK_SIZE; lz++) { for (int lz = 0; lz < CHUNK_SIZE; lz++) {
if (chunk->blocks[lx][ly][lz] != GRASS) continue; if (chunk->blocks[lx][ly][lz] != GRASS) continue;
if (!IsExposedOptimized(lx, ly, lz, chunk, nxM, nxP, nzM, nzP)) continue;
if (IsExposedOptimized(lx, ly, lz, chunk, nxM, nxP, nzM, nzP)) {
DrawGrassBlock((Vector3){(float)(worldX+lx), (float)ly, (float)(worldZ+lz)}, DrawGrassBlock((Vector3){(float)(worldX+lx), (float)ly, (float)(worldZ+lz)},
blockTextures[GRASS].id, grassTopTexture.id, blockTextures[DIRT].id); blockTextures[GRASS].id, grassTopTexture.id, blockTextures[DIRT].id, blockTint);
}
} }
} }
} }
@ -1471,7 +1507,7 @@ int main(void)
if (chunk->blocks[lx][ly][lz] != CRAFTING_TABLE) continue; if (chunk->blocks[lx][ly][lz] != CRAFTING_TABLE) continue;
if (!IsExposedOptimized(lx, ly, lz, chunk, nxM, nxP, nzM, nzP)) continue; if (!IsExposedOptimized(lx, ly, lz, chunk, nxM, nxP, nzM, nzP)) continue;
DrawCraftingTable((Vector3){(float)(worldX+lx), (float)ly, (float)(worldZ+lz)}, DrawCraftingTable((Vector3){(float)(worldX+lx), (float)ly, (float)(worldZ+lz)},
craftingSideTexture.id, craftingTopTexture.id, blockTextures[DIRT].id); craftingSideTexture.id, craftingTopTexture.id, blockTextures[DIRT].id, blockTint);
} }
} }
} }
@ -1481,8 +1517,11 @@ int main(void)
unsigned int currentTexId = blockTextures[renderType].id; unsigned int currentTexId = blockTextures[renderType].id;
rlSetTexture(currentTexId); rlSetTexture(currentTexId);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255); rlColor4ub(blockTint.r, blockTint.g, blockTint.b, 255);
if (renderType == LEAVES) rlColor4ub(40, 140, 40, 255); if (renderType == LEAVES) {
// Combined green and day/night tint
rlColor4ub((unsigned char)(blockTint.r * 0.2f), (unsigned char)(blockTint.g * 0.6f), (unsigned char)(blockTint.b * 0.2f), 255);
}
for (int cx = playerCX - RENDER_DISTANCE; cx <= playerCX + RENDER_DISTANCE; cx++) { for (int cx = playerCX - RENDER_DISTANCE; cx <= playerCX + RENDER_DISTANCE; cx++) {
for (int cz = playerCZ - RENDER_DISTANCE; cz <= playerCZ + RENDER_DISTANCE; cz++) { for (int cz = playerCZ - RENDER_DISTANCE; cz <= playerCZ + RENDER_DISTANCE; cz++) {
@ -1536,6 +1575,18 @@ int main(void)
camera3D.position.x, camera3D.position.y - 1.6f, camera3D.position.z), camera3D.position.x, camera3D.position.y - 1.6f, camera3D.position.z),
(Vector2){ 10, 80 }, 16, 1.0f, DARKGRAY); (Vector2){ 10, 80 }, 16, 1.0f, DARKGRAY);
// --- In-Game Clock ---
float clockTime = fmodf(timeOfDay + 0.25f, 1.0f); // Offset so 0.5 is noon
int totalMinutes = (int)(clockTime * 24 * 60);
int hours = (totalMinutes / 60) % 24;
int minutes = totalMinutes % 60;
const char* ampm = (hours >= 12) ? "PM" : "AM";
int displayHours = hours % 12;
if (displayHours == 0) displayHours = 12;
DrawTextEx(customFont, TextFormat("Time: %i:%02i %s", displayHours, minutes, ampm), (Vector2){ 10, 110 }, 18, 1.0f, (dayFactor > 0.5f) ? BLACK : WHITE);
DrawTextEx(customFont, (dayFactor > 0.5f) ? "Status: Day" : "Status: Night", (Vector2){ 10, 130 }, 16, 1.0f, (dayFactor > 0.5f) ? (Color){180, 150, 0, 255} : (Color){100, 100, 255, 255});
// ---- HOTBAR ---- // ---- HOTBAR ----
const int slotSize = 50; const int slotSize = 50;
const int slotGap = 4; const int slotGap = 4;
@ -1606,7 +1657,7 @@ int main(void)
if (slot.count > 0 && slot.blockType != AIR) { if (slot.count > 0 && slot.blockType != AIR) {
int bt = slot.blockType; int bt = slot.blockType;
Texture2D tex = (bt == GRASS) ? grassTopTexture : (bt == CRAFTING_TABLE ? craftingSideTexture : blockTextures[bt]); Texture2D tex = (bt == GRASS) ? grassTopTexture : (bt == CRAFTING_TABLE ? craftingSideTexture : blockTextures[bt]);
if (tex.id > 0) { if (tex.id > 0 && tex.width > 0 && tex.height > 0) {
Rectangle src = { 0,0,(float)tex.width,(float)tex.height }; Rectangle src = { 0,0,(float)tex.width,(float)tex.height };
Rectangle dst = { (float)(px+5),(float)(py+5), (float)(invSlotSize-10),(float)(invSlotSize-10) }; Rectangle dst = { (float)(px+5),(float)(py+5), (float)(invSlotSize-10),(float)(invSlotSize-10) };
Color tint = (bt == GRASS) ? (Color){124,189,107,255} : WHITE; Color tint = (bt == GRASS) ? (Color){124,189,107,255} : WHITE;
@ -1645,6 +1696,27 @@ int main(void)
UpdateTableCrafting(); UpdateTableCrafting();
} }
} }
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"
} else {
// Holding something, place one
if (slot.blockType == AIR) {
slot = InventorySlot(mouseHeldItem.blockType, 1);
mouseHeldItem.count--;
} else if (slot.blockType == mouseHeldItem.blockType && slot.count < 64) {
slot.count++;
mouseHeldItem.count--;
}
if (mouseHeldItem.count <= 0) mouseHeldItem = InventorySlot(AIR, 0);
UpdateCrafting();
UpdateTableCrafting();
}
}
}
}; };
auto drawInvGrid = [&](int startX, int startY) { auto drawInvGrid = [&](int startX, int startY) {