MorriCraft v2.2.29: Fixed texture format issue (JPEGs converted to PNGs), added texture loading fallbacks, and adjusted grass tinting
|
|
@ -106,7 +106,7 @@ A pre-built `MorriCraft-Windows.zip` is available in the repository root.
|
|||
|
||||
## 📜 Version History
|
||||
|
||||
### v2.2.28 - Hunger & World Gen Final (Current)
|
||||
### v2.2.29 - Hunger & World Gen Final (Current)
|
||||
- **Hunger System**: Added player hunger bar, starvation mechanics, and health regeneration when full.
|
||||
- **Apple Item**: Added edible Apple item to restore hunger.
|
||||
- **Grass Texture**: Improved `grass_top` texture with better pixel art.
|
||||
|
|
|
|||
BIN
assets/grass.png
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 771 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -1 +1 @@
|
|||
v2.2.28
|
||||
v2.2.29
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 771 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -1 +1 @@
|
|||
v2.2.28
|
||||
v2.2.29
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 771 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -1 +1 @@
|
|||
v2.2.28
|
||||
v2.2.29
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v2.2.28
|
||||
v2.2.29
|
||||
|
|
|
|||
46
src/main.cpp
|
|
@ -386,7 +386,7 @@ void RebuildChunkRenderList(Chunk* chunk, int cx, int cz) {
|
|||
|
||||
unsigned char faces = GetExposedFaces(lx, ly, lz, chunk, nxM, nxP, nzM, nzP);
|
||||
if (faces != 0) {
|
||||
// Simple Torch Lighting (v2.2.28)
|
||||
// Simple Torch Lighting (v2.2.29)
|
||||
float blockLight = 0.0f;
|
||||
Vector3 bPos = {(float)(worldX+lx), (float)ly, (float)(worldZ+lz)};
|
||||
for (const auto& tp : torchPositions) {
|
||||
|
|
@ -673,7 +673,7 @@ float FindSpawnY(int spawnX, int spawnZ) {
|
|||
// Feet land at top of block (y + 0.5).
|
||||
// We use +0.6f + 1.6f to ensure we start slightly ABOVE the block
|
||||
// to avoid getting stuck in collision on frame 1.
|
||||
// v2.2.28: Spawn higher (feet at y + 1.5, eyes at y + 3.1) to avoid ground-clipping
|
||||
// v2.2.29: Spawn higher (feet at y + 1.5, eyes at y + 3.1) to avoid ground-clipping
|
||||
return (float)y + 1.5f + 1.6f;
|
||||
}
|
||||
}
|
||||
|
|
@ -714,7 +714,7 @@ void GenerateChunk(int cx, int cz) {
|
|||
// Combine: broad hills (±12) + local detail (±4) = up to ±16 around Y=32
|
||||
int height = 32 + (int)(continentNoise * 12.0f) + (int)(detailNoise * 4.0f);
|
||||
|
||||
// Spawn Plateau (v2.2.28): Smoothly flatten area around (0,0)
|
||||
// Spawn Plateau (v2.2.29): Smoothly flatten area around (0,0)
|
||||
float distToSpawn = sqrtf(worldX * worldX + worldZ * worldZ);
|
||||
if (distToSpawn < 12.0f) {
|
||||
float plateauStrength = 1.0f - (distToSpawn / 12.0f);
|
||||
|
|
@ -726,7 +726,7 @@ void GenerateChunk(int cx, int cz) {
|
|||
if (height < 10) height = 10;
|
||||
if (height >= CHUNK_HEIGHT - 2) height = CHUNK_HEIGHT - 2;
|
||||
|
||||
// Biome noise: determines surface type (v2.2.28: 4x larger biomes)
|
||||
// Biome noise: determines surface type (v2.2.29: 4x larger biomes)
|
||||
float biomeNoise = fbm(worldX * 0.002f, worldZ * 0.002f, globalSeedHash + 77777);
|
||||
|
||||
for (int y = 0; y <= height; y++) {
|
||||
|
|
@ -933,7 +933,7 @@ void DrawGrassBlock(Vector3 position, unsigned int sideTexId, unsigned int topTe
|
|||
}
|
||||
if (mask & 4) { // Top
|
||||
rlSetTexture(topTexId); rlBegin(RL_QUADS);
|
||||
rlColor4ub((unsigned char)(124 * (tint.r/255.0f)), (unsigned char)(189 * (tint.g/255.0f)), (unsigned char)(107 * (tint.b/255.0f)), 255);
|
||||
rlColor4ub((unsigned char)(160 * (tint.r/255.0f)), (unsigned char)(230 * (tint.g/255.0f)), (unsigned char)(140 * (tint.b/255.0f)), 255);
|
||||
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(1.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); rlEnd();
|
||||
}
|
||||
if (mask & 8) { // Bottom
|
||||
|
|
@ -1011,7 +1011,7 @@ int main(void)
|
|||
// By default, windows have minimize, maximize, and close buttons on the top bar.
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_VSYNC_HINT);
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "MorriCraft v2.2.28");
|
||||
InitWindow(screenWidth, screenHeight, "MorriCraft v2.2.29");
|
||||
LoadConfig();
|
||||
SetExitKey(KEY_NULL); // Prevent ESC from closing the window
|
||||
|
||||
|
|
@ -1081,7 +1081,7 @@ int main(void)
|
|||
float updateTimer = 0.0f;
|
||||
float downloadProgress = 0.0f;
|
||||
std::string latestVersion = "";
|
||||
std::string localVersion = "v2.2.28"; // Default fallback
|
||||
std::string localVersion = "v2.2.29"; // Default fallback
|
||||
|
||||
// Read local version
|
||||
std::ifstream vfile("assets/version.txt");
|
||||
|
|
@ -1159,6 +1159,10 @@ int main(void)
|
|||
Texture2D logSideTexture = LoadTexture("assets/oak_log_side.png");
|
||||
Texture2D logTopTexture = LoadTexture("assets/oak_log_top.png");
|
||||
|
||||
// Safety Fallbacks
|
||||
if (blockTextures[GRASS].id == 0) blockTextures[GRASS] = blockTextures[DIRT];
|
||||
if (grassTopTexture.id == 0) grassTopTexture = blockTextures[DIRT];
|
||||
|
||||
// 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];
|
||||
|
|
@ -1689,7 +1693,7 @@ int main(void)
|
|||
|
||||
|
||||
// --- GLOBAL TIME & AUDIO MANAGEMENT ---
|
||||
float cycleLength = 600.0f; // Slower day cycle (v2.2.28: cut speed in half)
|
||||
float cycleLength = 600.0f; // Slower day cycle (v2.2.29: cut speed in half)
|
||||
if (currentState == GAMEPLAY) {
|
||||
gameTime += GetFrameTime();
|
||||
|
||||
|
|
@ -2075,7 +2079,7 @@ int main(void)
|
|||
AddToInventory(targetBlock);
|
||||
NetSetBlock(hitX, hitY, hitZ, AIR);
|
||||
|
||||
// Tool Durability Logic (v2.2.28)
|
||||
// Tool Durability Logic (v2.2.29)
|
||||
InventorySlot* slot = &hotbar[activeHotbarSlot];
|
||||
if (slot->maxDurability > 0) {
|
||||
slot->durability--;
|
||||
|
|
@ -2598,8 +2602,8 @@ int main(void)
|
|||
DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE);
|
||||
EndMode2D();
|
||||
|
||||
// Show Version Number (v2.2.28) in Red
|
||||
DrawTextEx(customFont, "v2.2.28", (Vector2){ 20, (float)currentHeight - 30 }, 22, 1.0f, RED);
|
||||
// Show Version Number (v2.2.29) in Red
|
||||
DrawTextEx(customFont, "v2.2.29", (Vector2){ 20, (float)currentHeight - 30 }, 22, 1.0f, RED);
|
||||
|
||||
// --- PLAYER NAME POPUP (IF MISSING) ---
|
||||
if (playerName == "") {
|
||||
|
|
@ -2777,7 +2781,7 @@ int main(void)
|
|||
spawnSavedX = 0; spawnSavedY = -1; spawnSavedZ = 0;
|
||||
}
|
||||
|
||||
// Load Chests (v2.2.28)
|
||||
// Load Chests (v2.2.29)
|
||||
chestInventories.clear();
|
||||
std::ifstream cf("saves/" + currentWorldName + "/chests.dat", std::ios::binary);
|
||||
if (cf.is_open()) {
|
||||
|
|
@ -2795,7 +2799,7 @@ int main(void)
|
|||
cf.close();
|
||||
}
|
||||
|
||||
// Load Torches (v2.2.28)
|
||||
// Load Torches (v2.2.29)
|
||||
torchPositions.clear();
|
||||
std::ifstream tf("saves/" + currentWorldName + "/torches.dat", std::ios::binary);
|
||||
if (tf.is_open()) {
|
||||
|
|
@ -3079,7 +3083,7 @@ int main(void)
|
|||
snprintf(worldName, sizeof(worldName), "%s", currentWorldName.c_str());
|
||||
worldNameLen = strlen(worldName);
|
||||
|
||||
gameTime = 150.0f; // Start new world at 7:00 AM (v2.2.28 adjusted for slower cycle)
|
||||
gameTime = 150.0f; // Start new world at 7:00 AM (v2.2.29 adjusted for slower cycle)
|
||||
|
||||
if (serverMode) {
|
||||
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
|
@ -3233,7 +3237,7 @@ int main(void)
|
|||
} else if (renderType == TORCH) {
|
||||
for (Chunk* chunk : visibleChunks) {
|
||||
for (auto& data : chunk->renderLists[TORCH]) {
|
||||
// 3D Flickering Torch (v2.2.28)
|
||||
// 3D Flickering Torch (v2.2.29)
|
||||
float flicker = sinf(GetTime() * 12.0f) * 0.03f;
|
||||
float h = 0.6f + flicker;
|
||||
float w = 0.12f;
|
||||
|
|
@ -3502,7 +3506,7 @@ int main(void)
|
|||
(Vector2){ (float)(sx + (slotSize/2) - (countSize.x/2)), (float)(hotbarY + slotSize - 14) },
|
||||
12, 1.0f, WHITE);
|
||||
|
||||
// Draw Hotbar Durability Bar (v2.2.28)
|
||||
// Draw Hotbar Durability Bar (v2.2.29)
|
||||
if (hotbar[s].maxDurability > 0 && hotbar[s].durability < hotbar[s].maxDurability) {
|
||||
float durP = (float)hotbar[s].durability / hotbar[s].maxDurability;
|
||||
int barW = slotSize - 10;
|
||||
|
|
@ -3533,7 +3537,7 @@ int main(void)
|
|||
DrawRectangleRec(slotRect, hov ? (Color){90,90,90,255} : (Color){60,60,60,255});
|
||||
DrawRectangleLinesEx(slotRect, 2.0f, hov ? WHITE : (Color){100,100,100,200});
|
||||
|
||||
// Draw Durability Bar (v2.2.28)
|
||||
// Draw Durability Bar (v2.2.29)
|
||||
if (slot.maxDurability > 0 && slot.durability < slot.maxDurability) {
|
||||
float durPercent = (float)slot.durability / slot.maxDurability;
|
||||
int barW = slotRect.width - 10;
|
||||
|
|
@ -3810,7 +3814,7 @@ int main(void)
|
|||
}
|
||||
}
|
||||
if (hov && IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
||||
// Right click: pick up/place one (v2.2.28)
|
||||
// Right click: pick up/place one (v2.2.29)
|
||||
if (mouseHeldItem.blockType == AIR) {
|
||||
if (chestInv[i].blockType != AIR && chestInv[i].count > 0) {
|
||||
mouseHeldItem = InventorySlot(chestInv[i].blockType, 1);
|
||||
|
|
@ -3857,7 +3861,7 @@ int main(void)
|
|||
}
|
||||
}
|
||||
if (hov && IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
||||
// Right click logic for player inv in chest GUI (v2.2.28)
|
||||
// Right click logic for player inv in chest GUI (v2.2.29)
|
||||
if (mouseHeldItem.blockType == AIR) {
|
||||
if (inventory[i].blockType != AIR && inventory[i].count > 0) {
|
||||
mouseHeldItem = InventorySlot(inventory[i].blockType, 1);
|
||||
|
|
@ -4036,7 +4040,7 @@ int main(void)
|
|||
invf.close();
|
||||
}
|
||||
|
||||
// Save Chests (v2.2.28)
|
||||
// Save Chests (v2.2.29)
|
||||
std::ofstream cf("saves/" + currentWorldName + "/chests.dat", std::ios::binary);
|
||||
if (cf.is_open()) {
|
||||
uint32_t count = (uint32_t)chestInventories.size();
|
||||
|
|
@ -4052,7 +4056,7 @@ int main(void)
|
|||
cf.close();
|
||||
}
|
||||
|
||||
// Save Torches (v2.2.28)
|
||||
// Save Torches (v2.2.29)
|
||||
std::ofstream tf("saves/" + currentWorldName + "/torches.dat", std::ios::binary);
|
||||
if (tf.is_open()) {
|
||||
uint32_t count = (uint32_t)torchPositions.size();
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v2.2.28
|
||||
v2.2.29
|
||||
|
|
|
|||