MorriCraft v2.2.26: Hunger System, Apple item, improved Grass Top texture, and World Spawn offset fix
|
After Width: | Height: | Size: 427 KiB |
|
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 870 KiB |
|
After Width: | Height: | Size: 427 KiB |
|
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 870 KiB |
|
After Width: | Height: | Size: 427 KiB |
|
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 870 KiB |
97
src/main.cpp
|
|
@ -31,7 +31,8 @@ enum BlockType {
|
|||
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,
|
||||
IRON_AXE = 32, IRON_PICKAXE = 33, IRON_SWORD = 34, IRON_SHOVEL = 35, IRON_HOE = 36,
|
||||
DIAMOND_AXE = 37, DIAMOND_PICKAXE = 38, DIAMOND_SWORD = 39, DIAMOND_SHOVEL = 40, DIAMOND_HOE = 41
|
||||
DIAMOND_AXE = 37, DIAMOND_PICKAXE = 38, DIAMOND_SWORD = 39, DIAMOND_SHOVEL = 40, DIAMOND_HOE = 41,
|
||||
APPLE = 42
|
||||
};
|
||||
|
||||
std::string GetBlockName(int type) {
|
||||
|
|
@ -78,6 +79,7 @@ std::string GetBlockName(int type) {
|
|||
case DIAMOND_SWORD: return "Diamond Sword";
|
||||
case DIAMOND_SHOVEL: return "Diamond Shovel";
|
||||
case DIAMOND_HOE: return "Diamond Hoe";
|
||||
case APPLE: return "Apple";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
|
@ -170,6 +172,10 @@ static float masterSoundVolume = 1.0f;
|
|||
static Color myShirtColor = BLUE;
|
||||
static Color myPantsColor = DARKBLUE;
|
||||
static float playerHealth = 16.0f;
|
||||
static float playerHunger = 20.0f;
|
||||
static float hungerTimer = 0.0f;
|
||||
static float healthRegenTimer = 0.0f;
|
||||
static float healthStarveTimer = 0.0f;
|
||||
static uint32_t localPlayerID = 0;
|
||||
static Sound hitSound;
|
||||
|
||||
|
|
@ -1075,7 +1081,7 @@ int main(void)
|
|||
float updateTimer = 0.0f;
|
||||
float downloadProgress = 0.0f;
|
||||
std::string latestVersion = "";
|
||||
std::string localVersion = "v2.2.25"; // Default fallback
|
||||
std::string localVersion = "v2.2.26"; // Default fallback
|
||||
|
||||
// Read local version
|
||||
std::ifstream vfile("assets/version.txt");
|
||||
|
|
@ -1163,6 +1169,7 @@ int main(void)
|
|||
blockTextures[CRAFTING_TABLE] = craftingSideTexture; // Preview for inventory
|
||||
|
||||
blockTextures[STICK] = LoadTexture("assets/stick.png");
|
||||
blockTextures[APPLE] = LoadTexture("assets/apple.png");
|
||||
blockTextures[WOOD_AXE] = LoadTexture("assets/wooden_axe.png");
|
||||
blockTextures[WOOD_PICKAXE] = LoadTexture("assets/wooden_pickaxe.png");
|
||||
blockTextures[WOOD_SWORD] = LoadTexture("assets/wooden_sword.png");
|
||||
|
|
@ -1683,7 +1690,37 @@ int main(void)
|
|||
|
||||
// --- GLOBAL TIME & AUDIO MANAGEMENT ---
|
||||
float cycleLength = 600.0f; // Slower day cycle (v2.2.23: cut speed in half)
|
||||
if (currentState == GAMEPLAY) gameTime += GetFrameTime();
|
||||
if (currentState == GAMEPLAY) {
|
||||
gameTime += GetFrameTime();
|
||||
|
||||
// Hunger Depletion
|
||||
hungerTimer += GetFrameTime();
|
||||
if (hungerTimer >= 10.0f) { // Deplete every 10 seconds
|
||||
hungerTimer = 0;
|
||||
if (playerHunger > 0) playerHunger -= 0.5f;
|
||||
}
|
||||
|
||||
// Hunger Effects (Health Regen/Starve)
|
||||
if (playerHunger >= 20.0f) {
|
||||
healthRegenTimer += GetFrameTime();
|
||||
if (healthRegenTimer >= 3.0f) {
|
||||
healthRegenTimer = 0;
|
||||
if (playerHealth < 16.0f) playerHealth += 1.0f; // Half heart
|
||||
}
|
||||
} else {
|
||||
healthRegenTimer = 0;
|
||||
}
|
||||
|
||||
if (playerHunger <= 0) {
|
||||
healthStarveTimer += GetFrameTime();
|
||||
if (healthStarveTimer >= 3.0f) {
|
||||
healthStarveTimer = 0;
|
||||
if (playerHealth > 2.0f) playerHealth -= 1.0f; // Half heart until 1 heart left
|
||||
}
|
||||
} else {
|
||||
healthStarveTimer = 0;
|
||||
}
|
||||
}
|
||||
float timeOfDay = fmodf(gameTime, cycleLength) / cycleLength;
|
||||
float sunAngle = timeOfDay * 2.0f * 3.14159f - 3.14159f/2.0f;
|
||||
dayFactor = (sinf(sunAngle) + 1.0f) / 2.0f;
|
||||
|
|
@ -2060,6 +2097,14 @@ int main(void)
|
|||
}
|
||||
|
||||
if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
||||
// NEW: Eating Logic
|
||||
if (hotbar[activeHotbarSlot].blockType == APPLE && playerHunger < 20.0f) {
|
||||
playerHunger += 4.0f;
|
||||
if (playerHunger > 20.0f) playerHunger = 20.0f;
|
||||
hotbar[activeHotbarSlot].count--;
|
||||
if (hotbar[activeHotbarSlot].count <= 0) hotbar[activeHotbarSlot].blockType = AIR;
|
||||
PlaySound(digGrass);
|
||||
} else if (hitBlock) {
|
||||
int targetBlock = GetBlock(hitX, hitY, hitZ);
|
||||
if (targetBlock == CRAFTING_TABLE) {
|
||||
currentState = CRAFTING_GUI;
|
||||
|
|
@ -2074,11 +2119,10 @@ int main(void)
|
|||
PlaySound(chestOpenSound);
|
||||
EnableCursor();
|
||||
} else if (hotbar[activeHotbarSlot].count > 0) {
|
||||
int placeX = hitX + (int)roundf(closestNormal.x);
|
||||
int placeY = hitY + (int)roundf(closestNormal.y);
|
||||
int placeZ = hitZ + (int)roundf(closestNormal.z);
|
||||
int placeX = hitX + (int)closestNormal.x;
|
||||
int placeY = hitY + (int)closestNormal.y;
|
||||
int placeZ = hitZ + (int)closestNormal.z;
|
||||
|
||||
// Check if space is occupied by player
|
||||
BoundingBox playerBB = {
|
||||
(Vector3){camera3D.position.x - 0.3f, camera3D.position.y - 1.5f, camera3D.position.z - 0.3f},
|
||||
(Vector3){camera3D.position.x + 0.3f, camera3D.position.y + 0.3f, camera3D.position.z + 0.3f}
|
||||
|
|
@ -2088,13 +2132,13 @@ int main(void)
|
|||
(Vector3){(float)placeX + 0.5f, (float)placeY + 0.5f, (float)placeZ + 0.5f}
|
||||
};
|
||||
|
||||
// Torches and some other blocks don't collide, but for now we just check occupancy
|
||||
if (!CheckCollisionBoxes(playerBB, blockBB) || hotbar[activeHotbarSlot].blockType == TORCH) {
|
||||
NetSetBlock(placeX, placeY, placeZ, hotbar[activeHotbarSlot].blockType);
|
||||
hotbar[activeHotbarSlot].count--;
|
||||
if (hotbar[activeHotbarSlot].count <= 0) hotbar[activeHotbarSlot].blockType = AIR;
|
||||
}
|
||||
isSwinging = true; // Swing when placing
|
||||
isSwinging = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2493,10 +2537,9 @@ int main(void)
|
|||
if (chunksGeneratedCount >= totalChunksToPreGen) {
|
||||
// FINALIZE: Place player and save world data
|
||||
if (isNewWorldGeneration) {
|
||||
Vector2 idealSpawn = FindIdealSpawn();
|
||||
float spawnY = FindSpawnY((int)idealSpawn.x, (int)idealSpawn.y);
|
||||
camera3D.position = (Vector3){ idealSpawn.x, spawnY, idealSpawn.y };
|
||||
camera3D.target = (Vector3){ idealSpawn.x, spawnY, idealSpawn.y + 1.0f };
|
||||
float spawnY = FindSpawnY((int)camera3D.position.x, (int)camera3D.position.z);
|
||||
camera3D.position.y = spawnY;
|
||||
camera3D.target = (Vector3){ camera3D.position.x, spawnY, camera3D.position.z + 1.0f };
|
||||
|
||||
std::ofstream worldFile2("saves/" + currentWorldName + "/world.dat");
|
||||
if (worldFile2.is_open()) {
|
||||
|
|
@ -2519,8 +2562,7 @@ int main(void)
|
|||
invf.close();
|
||||
}
|
||||
}
|
||||
playerVelocityY = 0.0f;
|
||||
camYaw = 0.0f; camPitch = 0.0f;
|
||||
|
||||
currentState = GAMEPLAY;
|
||||
DisableCursor();
|
||||
}
|
||||
|
|
@ -3071,7 +3113,14 @@ int main(void)
|
|||
isNewWorldGeneration = true;
|
||||
chunksGeneratedCount = 0;
|
||||
worldGenProgress = 0.0f;
|
||||
spawnSavedX = 0; spawnSavedY = -1; spawnSavedZ = 0; // Fresh world start at origin
|
||||
|
||||
// NEW: Find the ideal spawn BEFORE generating chunks to fix "missing terrain" bug
|
||||
Vector2 idealSpawn = FindIdealSpawn();
|
||||
spawnSavedX = idealSpawn.x;
|
||||
spawnSavedZ = idealSpawn.y;
|
||||
spawnSavedY = -1;
|
||||
camera3D.position = (Vector3){ idealSpawn.x, 60.0f, idealSpawn.y };
|
||||
|
||||
currentState = WORLD_CREATION_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -3399,6 +3448,22 @@ int main(void)
|
|||
}
|
||||
}
|
||||
|
||||
// --- Hunger Bar ---
|
||||
int hungerX = currentWidth / 2 + 5;
|
||||
int hungerY = hotbarY - 35;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Rectangle hungerRect = { (float)hungerX + i * 22, (float)hungerY, 18, 18 };
|
||||
float h = playerHunger - (i * 2);
|
||||
Color hungerColor = { 180, 100, 40, 255 }; // Brownish orange
|
||||
if (h >= 2.0f) DrawRectangleRec(hungerRect, hungerColor);
|
||||
else if (h >= 1.0f) {
|
||||
DrawRectangle((int)hungerRect.x, (int)hungerRect.y, 9, 18, hungerColor);
|
||||
DrawRectangleLinesEx(hungerRect, 2.0f, DARKGRAY);
|
||||
} else {
|
||||
DrawRectangleLinesEx(hungerRect, 2.0f, (Color){ 60, 60, 60, 255 });
|
||||
}
|
||||
}
|
||||
|
||||
// Hotbar background panel
|
||||
DrawRectangle(hotbarX - 6, hotbarY - 6, hotbarW + 12, slotSize + 12,
|
||||
(Color){ 30, 30, 30, 180 });
|
||||
|
|
|
|||