#include "game.h" #include "utils.h" void resetScreenScale(Game* game) { Texture texture = game->screen.render.texture; // Get screen size on window. float renderWidth = GetRenderWidth(); float renderHeight = GetRenderHeight(); float scale; if (renderWidth > renderHeight) { scale = (float)renderHeight / texture.height; } else { scale = (float)renderWidth / texture.width; } game->screen.scale = scale; float width = texture.width * scale; float height = texture.height * scale; game->screen.destination = (Rectangle){ renderWidth / 2.0 - width / 2.0, renderHeight / 2.0 - height / 2.0, width, height }; // Fuck ultra-wide. game->screen.ultraWideMode = renderWidth / renderHeight >= MAX_ASPECT; if (game->screen.ultraWideMode) { game->screen.destination = (Rectangle){ renderWidth / 2.0, renderHeight / 2.0, renderWidth, renderHeight }; } } void initMainMenu(Game* game) { game->mainMenu.renderTexture = LoadRenderTexture(GetRenderWidth(), GetRenderHeight()); game->mainMenu.camera = (Camera){ .position = Vector3Zero(), .target = (Vector3){0.0, 0.0, 1.0}, .up = (Vector3){0.0, 1.0, 0.0}, .fovy = 90.0, .projection = CAMERA_PERSPECTIVE }; game->mainMenu.sphere = LoadModelFromMesh(GenMeshSphere(1.0, 7, 14)); } void initGame(Game* game) { game->sceneId = MAIN_MENU_SCENE; // Settings. game->settings = defaultSettings(); game->isCrossHairEnabled = game->settings.isCrossHairEnabledDefault; game->showFPS = game->settings.showFPSDefault; // Window. InitWindow(game->settings.windowWidth, game->settings.windowHeight, "Find Things"); SetWindowState(FLAG_WINDOW_RESIZABLE); if (game->settings.maxFPS != 0) { SetTargetFPS(game->settings.maxFPS); } // Screen. game->screen.render = LoadRenderTexture(game->settings.screenWidth, game->settings.screenHeight); resetScreenScale(game); game->screen.postprocesserShader = POSTPROCESSING_SHADER; // Assets. initAssets(&game->assets, &game->settings); // Skybox. game->skybox = LoadModelFromMesh(GenMeshCube(1.0, 1.0, 1.0)); game->skybox.materials[0].shader = game->assets.shaders[SKYBOX_SHADER]; game->skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(game->assets.images[SKYBOX_IMAGE], CUBEMAP_LAYOUT_AUTO_DETECT); // World. Seed seed = 345893; game->world = createWorld(seed, &game->assets); game->strangeTalkSeed = 7373; // Player. game->player = createPlayer(); game->player.camera.fovy = game->settings.fov; game->player.position = Vector3Scale(game->world.size, 0.5); // Map. initMap(&game->map, &game->world, &game->settings); // Interaction chat and menu. initInteractionChat(&game->interactionChat, &game->settings); initInteractionMenu(&game->interactionMenu, &game->settings); // Inventory. initInventory(&game->inventory, &game->settings); // Main menu. initMainMenu(game); // disableGameCursor(game); } void mainMenuHandleWidgets(Game* game, Vector2 position) { float buttonWidth = 150.0; float buttonHeight = 50.0; // Start button. position.x = GetRenderWidth() / 2.0 - buttonWidth / 2.0; position.y = GetRenderHeight() / 2.0; if (GuiButton( (Rectangle){position.x, position.y, buttonWidth, buttonHeight}, "Start")) { game->sceneId = GAME_SCENE; disableGameCursor(game); } // Exit button. position.y += buttonHeight + 1.0; if (GuiButton( (Rectangle){position.x, position.y, buttonWidth, buttonHeight}, "Exit")) { CloseWindow(); } } void updateMainMenuBouncy(Game* game) { BeginMode3D(game->mainMenu.camera); game->mainMenu.sphere.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = game->mainMenu.renderTexture.texture; DrawModel(game->mainMenu.sphere, (Vector3){Wrap(GetTime(), -10.0, 10.0), 0.0, 5.0}, 1.0, WHITE); EndMode3D(); } // TODO: Use render texture instead of screenshot. void updateMainMenuScene(Game* game) { Texture texture = game->mainMenu.renderTexture.texture; BeginTextureMode(game->mainMenu.renderTexture); DrawTexturePro(texture, (Rectangle){0.0, 0.0, texture.width, -texture.height}, (Rectangle){0.0, 0.0, texture.width, texture.height}, (Vector2){0.0, 0.0}, 0.0, WHITE); float renderWidth = GetRenderWidth(); float renderHeight = GetRenderHeight(); int lineCount = 15; SetRandomSeed(GetTime() * 2.0); for (int count = 0; count < lineCount; ++count) { DrawRectangle(GetRandomValue(0, renderWidth), GetRandomValue(0, renderHeight), 10, 10, PURPLE); DrawLineEx( (Vector2){GetRandomValue(0, renderWidth), GetRandomValue(0, renderHeight)}, (Vector2){GetRandomValue(0, renderWidth), GetRandomValue(0, renderHeight)}, 2.0, GREEN); } // Draw logo. float currentTime = GetTime(); Texture logoTexture = game->assets.textures[LOGO_TEXTURE]; float logoScale = 2.0 + ((int)currentTime % 2) * 0.1; float logoHeight = logoTexture.height * logoScale; Vector2 position = (Vector2){ renderWidth / 2.0 - logoTexture.width * logoScale / 2.0, renderHeight / 2.0 - logoHeight / 2.0 }; position.y -= logoHeight; DrawTextureEx(logoTexture, position, Wrap(currentTime * 0.5, -0.5, 0.5), logoScale, WHITE); mainMenuHandleWidgets(game, position); updateMainMenuBouncy(game); EndTextureMode(); DrawTexturePro(texture, (Rectangle){0.0, 0.0, texture.width, -texture.height}, (Rectangle){0.0, 0.0, texture.width, texture.height}, (Vector2){0.0, 0.0}, 0.0, WHITE); } void drawGameTexturedBackground(Texture texture) { int screenWidth = GetRenderWidth(); int screenHeight = GetRenderHeight(); for (int y = 0; y < screenHeight; y += texture.height) { for (int x = 0; x < screenWidth; x += texture.width) { DrawTexture(texture, x, y, WHITE); } } } void drawGameScreen(Game* game) { Texture texture = game->screen.render.texture; if (game->screen.ultraWideMode) { BeginShaderMode(game->assets.shaders[FUCK_SHADER]); DrawTexturePro( texture, (Rectangle){0.0, 0.0, texture.width, -texture.height}, game->screen.destination, (Vector2){GetRenderWidth() / 2.0, GetRenderHeight() / 2.0}, (int)(GetTime() * ULTRA_WIDE_SPIN_SPEED) % 360, WHITE); EndShaderMode(); DrawText("FUCK ULTRA WIDE FUCK ULTRA WIDE FUCK ULTRA WIDE FUCK ULTRA WIDE FUCK ULTRA WIDE FUCK ULTRA WIDE FUCK ULTRA WIDE FUCK ULTRA WIDE", 0.0, 0.0, 50, RED); } else { BeginShaderMode(game->assets.shaders[game->screen.postprocesserShader]); DrawTexturePro( texture, (Rectangle){0.0, 0.0, texture.width, -texture.height}, game->screen.destination, (Vector2){0.0, 0.0}, 0.0, WHITE); EndShaderMode(); } } void drawCrosshair(float crossHairSize, float crossHairThickness, Color color) { float screenHalfWidth = GetRenderWidth() / 2.0; float screenHalfHeight = GetRenderHeight() / 2.0; float halfThickness = crossHairThickness / 2.0; // Vertical. DrawLineEx( (Vector2){screenHalfWidth - crossHairSize, screenHalfHeight}, (Vector2){screenHalfWidth + crossHairSize, screenHalfHeight}, crossHairThickness, color); // Horizontal. DrawLineEx( (Vector2){screenHalfWidth, screenHalfHeight - crossHairSize}, (Vector2){screenHalfWidth, screenHalfHeight + crossHairSize}, crossHairThickness, color); } void updateGameEntityInfo(Game* game) { // Get size. float screenWidth = GetRenderWidth(); float screenHeight = GetRenderWidth(); float x = game->map.rect.x + (game->map.rect.width * 0.25); float y = game->map.rect.y + game->map.rect.height; int lines = 1; int fontSize = game->settings.entityInfoFontSize; if (!game->map.isEnabled) { y = 0.0; } WorldUID selected = game->player.selectedEntity; if (selected == ENTITY_NONE) { return; } Color backgroundColor = PINK; backgroundColor.a = game->settings.statusAndInfoAlpha; DrawRectangle(x, y, screenWidth - x, lines * fontSize, backgroundColor); // Draw name. Entity* selectedEntity = &game->world.entities[selected]; DrawText(getEntityName(selectedEntity->id), x, y, fontSize, BLACK); } void updateGameStatus(Game* game) { float x; float y; float width; float height; int fontSize = 20; int lineCount = 3; int maxColumns = 24; float maxWidth = maxColumns * fontSize / 2.0; bool topBarStyle = game->screen.destination.x < maxWidth / 2.0; const char* spacer = topBarStyle ? ", " : "\n"; // Format text. char placeAt[ENTITY_NAME_MAX] = "Back woods"; WorldUID place = game->player.place; if (place != ENTITY_NONE) { strncpy(placeAt, getEntityName(game->world.entities[place].id), ENTITY_NAME_MAX - 1); } const char* text = TextFormat( "At: %s%sSpeed %d%sPee level: 7", placeAt, spacer, (int)roundf(game->player.speed), spacer); // Handle bar style. if (topBarStyle) // Top bar style. { x = 110.0; y = 1.0; width = (getStringLength(text, 255) + 1) * fontSize / 2.0; height = fontSize; } else // Side bar style. { x = 1.0; y = game->showFPS ? 20.0 : 0.0; width = maxWidth; height = fontSize * lineCount; } // Draw text and background. Color backgroundColor = PINK; backgroundColor.a = game->settings.statusAndInfoAlpha; DrawRectangle(x, y, width, height, backgroundColor); DrawText(text, x, y, fontSize, BLACK); } void updateGameScene(Game* game) { // Handle toggle cursor. if (IsKeyPressed(game->settings.toggleCursorKey)) { if (game->isCursorEnabled) { disableGameCursor(game); } else { enableGameCursor(game); } } BeginTextureMode(game->screen.render); ClearBackground(PINK); BeginMode3D(game->player.camera); // Render skybox. rlDisableBackfaceCulling(); rlDisableDepthMask(); DrawModel(game->skybox, Vector3Zero(), 1.0, WHITE); rlEnableBackfaceCulling(); rlEnableDepthMask(); updatePlayer(&game->player, game); updateWorld(&game->world, game); EndMode3D(); EndTextureMode(); // Draw background texture or color. if (game->settings.useBackgroundTexture && !FloatEquals(game->screen.destination.x, 0.0)) { AssetId backgroundTextureId = BACKGROUND1_TEXTURE + game->settings.backgroundTextureNumber; drawGameTexturedBackground(game->assets.textures[backgroundTextureId]); } else { ClearBackground(game->settings.backgroundColor); } drawGameScreen(game); // Cross hair. if (IsKeyPressed(game->settings.toggleCrossHairKey)) { game->isCrossHairEnabled = !game->isCrossHairEnabled; } if (game->isCrossHairEnabled) { drawCrosshair(game->settings.crossHairSize, game->settings.crossHairThickness, game->settings.crossHairColor); } updateMap(&game->map, game); updateGameEntityInfo(game); updateGameStatus(game); updateInteractionChat(&game->interactionChat, game); updateInteractionMenu(&game->interactionMenu, game); updateInventory(&game->inventory, game); } void handleGameResize(Game* game) { resetScreenScale(game); } void updateGame(Game* game) { BeginDrawing(); if (IsWindowResized()) { handleGameResize(game); } switch (game->sceneId) { case MAIN_MENU_SCENE: updateMainMenuScene(game); break; case GAME_SCENE: updateGameScene(game); break; default: break; } // FPS stuff. if (IsKeyPressed(game->settings.toggleFPSKey)) { game->showFPS = !game->showFPS; } if (game->showFPS) { DrawFPS(0, 0); } EndDrawing(); } void closeMainMenu(Game* game) { UnloadRenderTexture(game->mainMenu.renderTexture); UnloadModel(game->mainMenu.sphere); } void closeGame(Game* game) { closeAssets(&game->assets); UnloadRenderTexture(game->screen.render); UnloadTexture(game->skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture); UnloadModel(game->skybox); freeWorld(game->world); closeMap(&game->map); closeMainMenu(game); CloseWindow(); } void enableGameCursor(Game* game) { game->isCursorEnabled = true; EnableCursor(); } void disableGameCursor(Game* game) { game->isCursorEnabled = false; DisableCursor(); }