diff --git a/src/compat.h b/src/compat.h index 26ee231..ee14f51 100644 --- a/src/compat.h +++ b/src/compat.h @@ -1,6 +1,3 @@ #pragma once -#ifdef _WIN32 - #define PATH_MAX 260 - #define NAME_MAX 260 -#endif +#define NAME_MAX 260 diff --git a/src/data.c b/src/data.c index b9f4a67..dde483e 100644 --- a/src/data.c +++ b/src/data.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -10,316 +11,523 @@ #include "data.h" #include "textures.h" +#ifdef _KOLIBRI + #include +#endif + + data_WorldListItem *data_worldList = NULL; int data_worldListLength = 0; -char directoryName [PATH_MAX] = { 0 }; -char optionsFileName [PATH_MAX] = { 0 }; -char worldsDirectoryName [PATH_MAX] = { 0 }; -char screenshotsDirectoryName [PATH_MAX] = { 0 }; +char directoryName[PATH_MAX] = {0}; +char optionsFileName[PATH_MAX] = {0}; +char worldsDirectoryName[PATH_MAX] = {0}; +char screenshotsDirectoryName[PATH_MAX] = {0}; + +static uint32_t getSurfacePixel(SDL_Surface *, int, int); +static int findDirectoryName(char *, const char *); -static uint32_t getSurfacePixel (SDL_Surface *, int, int); -static int findDirectoryName (char *, const char *); /* data_init * Initializes the data module. Returns zero on success, nonzero on failure. */ -int data_init (void) { - int err = 0; +int data_init(void) +{ + int err = 0; - err = findDirectoryName(directoryName, "/.m4kc"); - if (err) { return err; } - - err = findDirectoryName(optionsFileName, "/.m4kc/m4kc.conf"); - if (err) { return err; } - - err = findDirectoryName(worldsDirectoryName, "/.m4kc/worlds"); - if (err) { return err; } - - err = findDirectoryName ( - screenshotsDirectoryName, "/.m4kc/screenshots"); - if (err) { return err; } - - return 0; + err = findDirectoryName( + directoryName, + "/m4kc"); + if (err) + { + return err; + } + + err = findDirectoryName( + optionsFileName, + "/m4kc/m4kc.conf"); + if (err) + { + return err; + } + + err = findDirectoryName( + worldsDirectoryName, + "/m4kc/worlds"); + if (err) + { + return err; + } + + err = findDirectoryName( + screenshotsDirectoryName, + "/m4kc/screenshots"); + if (err) + { + return err; + } + + return 0; } + /* data_directoryExists * Test if a directory exists at the specified path. This function does not * create or delete anything. */ -int data_directoryExists (const char *path) { +int data_directoryExists(const char *path) +{ + #ifdef _KOLIBRI + ksys_file_info_t *bdfe_info; + return _ksys_file_info(path, bdfe_info) == 0; + #else struct stat directoryInfo; return (stat(path, &directoryInfo) == 0 && S_ISDIR(directoryInfo.st_mode)); - + #endif } + /* data_fileExists * Test if a file exists at the specified path. */ -int data_fileExists (const char *path) { - return access(path, F_OK) == 0; +int data_fileExists(const char *path) +{ + return access(path, F_OK) == 0; } + /* data_ensureDirectoryExists * Equivalent to mkdir -p. Creates a directory and all of its parent directories * if they don't exist. */ -int data_ensureDirectoryExists (const char *path) { - char currentDirectory[PATH_MAX] = ""; - int index = 0; - - while (path[index] != 0) { - while (path[index] != 0) { - currentDirectory[index] = path[index]; - currentDirectory[index + 1] = 0; - index ++; - char ch = currentDirectory[index - 1]; - if (ch == '/' || ch == '\\') { - break; - } - } - - if (!data_directoryExists(currentDirectory)) { - int status; - #ifdef _WIN32 - status = mkdir(currentDirectory); - #else - status = mkdir(currentDirectory, 0755); - #endif - if (status != 0) { - return 1; - } - } +int data_ensureDirectoryExists(const char *path) +{ + char currentDirectory[PATH_MAX] = ""; + int index = 0; + // printf("Directory path: %s\n", path); + while (path[index] != 0) + { + while (path[index] != 0) + { + currentDirectory[index] = path[index]; + currentDirectory[index + 1] = 0; + index++; + char ch = currentDirectory[index - 1]; + if (ch == '/' || ch == '\\') + { + break; + } } - return 0; + // printf("Requested directory %s!\n", currentDirectory); + + if (!data_directoryExists(currentDirectory)) + { + // printf("Need to create directory %s!\n", currentDirectory); + int status; + + #ifdef _WIN32 + status = mkdir(currentDirectory); + #elif __linux__ + status = mkdir(currentDirectory, 0755); + #elif _KOLIBRI + // Check and temporarily remove trailing '/' if present + int hadTrailingSlash = 0; + size_t len = strlen(currentDirectory); + if (len > 0 && currentDirectory[len - 1] == '/') + { + hadTrailingSlash = 1; + currentDirectory[len - 1] = '\0'; + } + + status = _ksys_mkdir(currentDirectory); + + // Restore the trailing '/' if it was removed + if (hadTrailingSlash) + { + currentDirectory[len - 1] = '/'; + } + #endif + + if (status != 0) + { + // printf("Failed creating directory \"%s\" - error code %d!\n", currentDirectory, status); + return 1; + } + else + { + // printf("Success creating directory \"%s\" - error code %d!\n", currentDirectory, status); + } + } + else + { + // printf("No need to create directory %s!\n", currentDirectory); + } + } + + return 0; } + /* data_removeDirectory * Equivalent of rm -r. Removes a directory and its contents recursively. */ -int data_removeDirectory (const char *path) { - DIR *directory = opendir(path); - size_t pathLength = strlen(path); +int data_removeDirectory(const char *path) +{ + DIR *directory = opendir(path); + size_t pathLength = strlen(path); - if (!directory) { return 1; } - - struct dirent *directoryEntry; + if (!directory) + { + return 1; + } - int err = 0; - while (!err) { - directoryEntry = readdir(directory); - if (directoryEntry == NULL) { - err = 2; - break; - } - - if ( - !strcmp(directoryEntry->d_name, ".") || - !strcmp(directoryEntry->d_name, "..") - ) { - continue; + struct dirent *directoryEntry; + + int err = 0; + while (!err) + { + directoryEntry = readdir(directory); + if (directoryEntry == NULL) + { + err = 2; + break; + } + + if ( + !strcmp(directoryEntry->d_name, ".") || + !strcmp(directoryEntry->d_name, "..")) + { + continue; + } + + size_t newLength = + pathLength + + strlen(directoryEntry->d_name) + 2; + + char *newPath = malloc(newLength); + if (newPath == NULL) + { + return 3; + } + + snprintf( + newPath, newLength, "%s/%s", + path, directoryEntry->d_name); + + struct stat fileInfo; + if (!stat(newPath, &fileInfo)) + { + if (S_ISDIR(fileInfo.st_mode)) + { + err = data_removeDirectory(newPath); + } + else + { + err = unlink(newPath); + } + } + free(newPath); + } + + closedir(directory); + + int status = 0; + + #ifdef _WIN32 + status = rmdir(path); + #elif __linux__ + status = rmdir(path); + #elif _KOLIBRI + // ksys_file_info_t* dir_info; + // _ksys_dir_info(path, dir_info); + // printf("Dir offset: %d!\n", dir_info->offset64); + // printf("Dir size: %d!\n", dir_info->size); + // _ksys_file_read_dir(path, 0, 0, ); + // TODO Make proper (recursive) determination of files in folder + char full_path[PATH_MAX]; + + const char *blocks[] = {"00000000", "00000001", "FFFFFFFF"}; + const char *fixedSuffixes[] = {"guest.player", "metadata"}; + + for (size_t i = 0; i < 3; i++) + { + for (size_t j = 0; j < 3; j++) + { + for (size_t k = 0; k < 3; k++) { + snprintf(full_path, sizeof(full_path), "%s/%s%s%s", path, blocks[i], blocks[j], blocks[k]); + _ksys_rmdir(full_path); } + } + } - size_t newLength = - pathLength + - strlen(directoryEntry->d_name) + 2; - - char *newPath = malloc(newLength); - if (newPath == NULL) { return 3; } - - snprintf ( - newPath, newLength, "%s/%s", - path, directoryEntry->d_name); - - struct stat fileInfo; - if (!stat(newPath, &fileInfo)) { - if (S_ISDIR(fileInfo.st_mode)) { - err = data_removeDirectory(newPath); - } else { - err = unlink(newPath); - } - } - free(newPath); + for (size_t i = 0; i < sizeof(fixedSuffixes) / sizeof(fixedSuffixes[0]); i++) + { + snprintf(full_path, sizeof(full_path), "%s/%s", path, fixedSuffixes[i]); + _ksys_rmdir(full_path); } - closedir(directory); - if (rmdir(path)) { return 4; } - return 0; + status = _ksys_rmdir(path); + + #endif + + if (status) + { + printf("Failed remove directory \"%s\" - %d!\n", path, status); + return 4; + } + return 0; } + /* data_getOptionsFileName * Returns the file path of the configuration file. */ -char *data_getOptionsFileName (void) { - return optionsFileName; +char *data_getOptionsFileName(void) +{ + return optionsFileName; } + /* data_getWorldPath * Returns the path to a world, regardless if it exists or not. This function * ensures that the worlds directory exists. If it cannot do this, it returns 1. */ -int data_getWorldPath (char *path, const char *worldName) { - if (data_ensureDirectoryExists(worldsDirectoryName)) { return 1; } +int data_getWorldPath(char *path, const char *worldName) +{ + if (data_ensureDirectoryExists(worldsDirectoryName)) + { + return 1; + } - snprintf(path, PATH_MAX, "%s/%s", worldsDirectoryName, worldName); - return 0; + snprintf(path, PATH_MAX, "%s/%s", worldsDirectoryName, worldName); + return 0; } + /* data_getWorldMetaPath * Returns the path to the metadata file of a world, given a world path. */ -void data_getWorldMetaPath (char *path, const char *worldPath) { - snprintf(path, PATH_MAX, "%s/metadata", worldPath); +void data_getWorldMetaPath(char *path, const char *worldPath) +{ + snprintf(path, PATH_MAX, "%s/metadata", worldPath); } + /* data_getWorldPlayerPath * Returns the path to a player file, given a world path and a player name. */ -void data_getWorldPlayerPath ( - char *path, - const char *worldPath, - const char *name -) { - snprintf(path, PATH_MAX, "%s/%s.player", worldPath, name); +void data_getWorldPlayerPath( + char *path, + const char *worldPath, + const char *name) +{ + snprintf(path, PATH_MAX, "%s/%s.player", worldPath, name); } + /* data_getScreenshotPath * Writes into path the path for a new screenshot. The name will take the form * of: snip_YYYY-MM-DD_HH:MM:SS.bmp * ... and will be located in the path stored in screenshotsDirectoryName. If * the screenshots directory doesn't exist, this function will create it. */ -int data_getScreenshotPath (char *path) { - if (data_ensureDirectoryExists(screenshotsDirectoryName)) { return 1; } +int data_getScreenshotPath(char *path) +{ + if (data_ensureDirectoryExists(screenshotsDirectoryName)) + { + return 1; + } - time_t unixTime = time(0); - struct tm *timeInfo = localtime(&unixTime); - - snprintf ( - path, PATH_MAX, - "%s/snip_%04i-%02i-%02i_%02i-%02i-%02i.bmp", - screenshotsDirectoryName, - timeInfo->tm_year + 1900, - timeInfo->tm_mon + 1, - timeInfo->tm_mday, - timeInfo->tm_hour, - timeInfo->tm_min, - timeInfo->tm_sec); - return 0; + time_t unixTime = time(0); + struct tm *timeInfo = localtime(&unixTime); + + snprintf( + path, PATH_MAX, + "%s/snip_%04i-%02i-%02i_%02i-%02i-%02i.bmp", + screenshotsDirectoryName, + timeInfo->tm_year + 1900, + timeInfo->tm_mon + 1, + timeInfo->tm_mday, + timeInfo->tm_hour, + timeInfo->tm_min, + timeInfo->tm_sec); + return 0; } + /* data_refreshWorldList * Regreshes the world list, clearing the previous one. Reads world names and * thumbnails from ~/.m4kc/worlds */ -int data_refreshWorldList (void) { - // Free previous list - data_WorldListItem *item = data_worldList; - while (item != NULL) { - data_WorldListItem *next = item->next; - free(item); - item = next; +int data_refreshWorldList(void) +{ + // Free previous list + data_WorldListItem *item = data_worldList; + while (item != NULL) + { + data_WorldListItem *next = item->next; + free(item); + item = next; + } + + if (data_ensureDirectoryExists(worldsDirectoryName)) + { + return 1; + } + + // Iterate through worlds directory + struct dirent *directoryEntry; + + // printf("Opening directory %s", worldsDirectoryName); + + DIR *directory = opendir(worldsDirectoryName); + if (!directory) + { + return 2; + } + + data_worldListLength = 0; + data_WorldListItem *last = NULL; + while ((directoryEntry = readdir(directory)) != NULL) + { + if (directoryEntry->d_name[0] == '.') + { + continue; } - if (data_ensureDirectoryExists(worldsDirectoryName)) { return 1; } - - // Iterate through worlds directory - struct dirent *directoryEntry; - DIR *directory = opendir(worldsDirectoryName); - if (!directory) { return 2; } - - data_worldListLength = 0; - data_WorldListItem *last = NULL; - while ((directoryEntry = readdir(directory)) != NULL) { - if (directoryEntry->d_name[0] == '.') { continue; } - - // Allocate new list item - data_WorldListItem *item = calloc ( - sizeof(data_WorldListItem), 1); - if (item == NULL) { return 3; } - - strncpy(item->name, directoryEntry->d_name, NAME_MAX); - if (last == NULL) { - data_worldList = item; - last = data_worldList; - } else { - last->next = item; - last = item; - } - - // Get thumbnail - char path[PATH_MAX]; - snprintf ( - path, PATH_MAX, - "%s/%s/thumbnail.bmp", - worldsDirectoryName, - item->name); - - SDL_Surface *image = SDL_LoadBMP(path); - int *pixel = item->thumbnail.buffer; - - // Do not accept vertical images - if (image != NULL && image->h <= image->w) { - int scale = image->h / 16; - for (int y = 0; y < 16; y ++) - for (int x = 0; x < 16; x ++) { - *pixel = getSurfacePixel (image, - x * scale, - y * scale); - pixel ++; - } - } else { - for (int y = 0; y < 16; y ++) - for (int x = 0; x < 16; x ++) { - *pixel = textures [ - x + - y * BLOCK_TEXTURE_W + - (BLOCK_GRASS * 3 + 1) * - BLOCK_TEXTURE_W * BLOCK_TEXTURE_H]; - pixel ++; - } - } - - SDL_FreeSurface(image); - - data_worldListLength ++; + // Allocate new list item + data_WorldListItem *item = calloc( + sizeof(data_WorldListItem), 1); + if (item == NULL) + { + return 3; } - - closedir(directory); - return 0; + strncpy(item->name, directoryEntry->d_name, NAME_MAX); + if (last == NULL) + { + data_worldList = item; + last = data_worldList; + } + else + { + last->next = item; + last = item; + } + + // Get thumbnail + char path[PATH_MAX]; + snprintf( + path, PATH_MAX, + "%s/%s/thumbnail.bmp", + worldsDirectoryName, + item->name); + + SDL_Surface *image = SDL_LoadBMP(path); + int *pixel = item->thumbnail.buffer; + + // Do not accept vertical images + if (image != NULL && image->h <= image->w) + { + int scale = image->h / 16; + for (int y = 0; y < 16; y++) + for (int x = 0; x < 16; x++) + { + *pixel = getSurfacePixel(image, + x * scale, + y * scale); + pixel++; + } + } + else + { + for (int y = 0; y < 16; y++) + for (int x = 0; x < 16; x++) + { + *pixel = textures[x + + y * BLOCK_TEXTURE_W + + (BLOCK_GRASS * 3 + 1) * + BLOCK_TEXTURE_W * BLOCK_TEXTURE_H]; + pixel++; + } + } + + SDL_FreeSurface(image); + + data_worldListLength++; + } + + closedir(directory); + + return 0; } + /* getSurfacePixel * Gets a pixel value from an SDL surface at the specified coordinates. */ -static uint32_t getSurfacePixel (SDL_Surface *surface, int x, int y) { - return *((uint32_t *) ((uint8_t *) surface->pixels - + y * surface->pitch - + x * surface->format->BytesPerPixel)); +static uint32_t getSurfacePixel(SDL_Surface *surface, int x, int y) +{ + return *((uint32_t *)((uint8_t *)surface->pixels + y * surface->pitch + x * surface->format->BytesPerPixel)); } + +char* ksys_get_process_cwd() { + char *process_cwd = (char *)*((uint32_t *)0x20); + char *trimmed_cwd = strdup(process_cwd + 2); + char *last_slash = strrchr(trimmed_cwd, '/'); + if (last_slash) + *last_slash = '\0'; + return trimmed_cwd; +} + + /* findDirectoryName * Concatenates the user's home directory with the specified path. subDirectory * must begin with a '/'. Uses %APPDATA% instead of home on windows. */ -static int findDirectoryName (char *path, const char *subDirectory) { - if (subDirectory[0] != '/') { return 2; } - - #ifdef _WIN32 +static int findDirectoryName(char *path, const char *subDirectory) +{ + if (subDirectory[0] != '/') + { + return 2; + } + + #ifdef _WIN32 char *homeDirectory = getenv("APPDATA"); - #else + #elif __linux__ char *homeDirectory = getenv("HOME"); - #endif - if (homeDirectory == NULL) { return 3; } - - snprintf(path, PATH_MAX, "%s%s", homeDirectory, subDirectory); - - // Normalize path - for (char *ch = path; *ch; ch ++) { - if (*ch == '\\') { *ch = '/'; } + #elif _KOLIBRI + char *homeDirectory; + int buf_size = 24; + if (!_ksys_mkdir("m4kc")) + { + homeDirectory = ksys_get_process_cwd(); + printf("Success to use local directory!\n"); + // homeDirectory = getenv("HOME"); } - return 0; + else { + printf("Failed to use local directory!\n"); + homeDirectory = getenv("HOME"); // Assign value + } + #endif + + if (homeDirectory == NULL) + { + return 3; + } + + snprintf(path, PATH_MAX, "%s%s", homeDirectory, subDirectory); + + // Normalize path + for (char *ch = path; *ch; ch++) + { + if (*ch == '\\') + { + *ch = '/'; + } + } + return 0; } diff --git a/src/gameloop.c b/src/gameloop.c index 2f9921e..ba07db2 100644 --- a/src/gameloop.c +++ b/src/gameloop.c @@ -8,6 +8,7 @@ #include "data.h" #include "gui.h" + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * WARNING!!! * * * @@ -19,7 +20,8 @@ * psychological effects. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -World world = { 0 }; + +World world = {0}; Player *player = &world.player; int gameState = STATE_TITLE; @@ -32,106 +34,119 @@ static SDL_Rect backgroundRect; static char *errorMessage = NULL; static long l; -static void gameLoop_gameplay (SDL_Renderer *, Inputs *); -static void gameLoop_drawPopup (SDL_Renderer *, Inputs *); -static void gameLoop_processMovement (Inputs *, int); +static void gameLoop_gameplay(SDL_Renderer *, Inputs *); +static void gameLoop_drawPopup(SDL_Renderer *, Inputs *); +static void gameLoop_processMovement(Inputs *, int); static uint32_t - fps_lastmil = 0, - fps_count = 0, - fps_now = 0; + fps_lastmil = 0, + fps_count = 0, + fps_now = 0; + /* gameLoop_resetGame * Resets elements of the game such as time and the player position. This will * also reset the world. */ -void gameLoop_resetGame () { - l = SDL_GetTicks(); +void gameLoop_resetGame() +{ + l = SDL_GetTicks(); - gamePopup = 0; - - guiOn = 1; - debugOn = 0; + gamePopup = 0; - backgroundRect.x = 0; - backgroundRect.y = 0; - backgroundRect.w = BUFFER_W; - backgroundRect.h = BUFFER_H; - - chatAdd("Game started"); + guiOn = 1; + debugOn = 0; + + backgroundRect.x = 0; + backgroundRect.y = 0; + backgroundRect.w = BUFFER_W; + backgroundRect.h = BUFFER_H; + + chatAdd("Game started"); } + /* gameLoop * Does all the raycasting stuff, moves the player around, etc. * If by chance the game ends, it returns false - which should * terminate the main while loop and end the program. */ -int gameLoop ( - Inputs *inputs, - SDL_Renderer *renderer -) { - // If there is an error, show it and stop - if (errorMessage) { - if (state_err(renderer, inputs, errorMessage)) { - errorMessage = NULL; - // TODO: add capability to recover from error: - return 0; - } else { - return 1; - } +int gameLoop( + Inputs *inputs, + SDL_Renderer *renderer) +{ + // If there is an error, show it and stop + if (errorMessage) + { + if (state_err(renderer, inputs, errorMessage)) + { + errorMessage = NULL; + // TODO: add capability to recover from error: + return 0; } - - switch (gameState) { - case STATE_TITLE: - // A main menu - if (state_title(renderer, inputs, &gameState)) return 0; - break; - - case STATE_SELECT_WORLD: - // World creation menu - state_selectWorld(renderer, inputs, &gameState, &world); - break; - - case STATE_NEW_WORLD: - // World creation menu - state_newWorld(renderer, inputs, &gameState, &world); - break; - - case STATE_LOADING: - // Generate a world and present a loading screen - if (state_loading(renderer, &world, world.seed, player->pos)) { - gameLoop_resetGame(); - gameState = 5; - }; - break; - - case STATE_GAMEPLAY: - // The actual gameplay - gameLoop_gameplay(renderer, inputs); - break; - - case STATE_OPTIONS: - state_options(renderer, inputs, &gameState); - break; - - default: - state_egg(renderer, inputs, &gameState); - break; + else + { + return 1; } + } - if (gameState != STATE_GAMEPLAY || gamePopup != POPUP_HUD) { - inputs->mouse.left = 0; - inputs->mouse.right = 0; - } + switch (gameState) + { + case STATE_TITLE: + // A main menu + if (state_title(renderer, inputs, &gameState)) + return 0; + break; - return 1; + case STATE_SELECT_WORLD: + // World creation menu + state_selectWorld(renderer, inputs, &gameState, &world); + break; + + case STATE_NEW_WORLD: + // World creation menu + state_newWorld(renderer, inputs, &gameState, &world); + break; + + case STATE_LOADING: + // Generate a world and present a loading screen + if (state_loading(renderer, &world, world.seed, player->pos)) + { + gameLoop_resetGame(); + gameState = 5; + }; + break; + + case STATE_GAMEPLAY: + // The actual gameplay + gameLoop_gameplay(renderer, inputs); + break; + + case STATE_OPTIONS: + state_options(renderer, inputs, &gameState); + break; + + default: + state_egg(renderer, inputs, &gameState); + break; + } + + if (gameState != STATE_GAMEPLAY || gamePopup != POPUP_HUD) + { + inputs->mouse.left = 0; + inputs->mouse.right = 0; + } + + return 1; } + /* gameLoop_gameplay * Runs game logic and rendering. This is where most of the obfuscated code is. */ -static void gameLoop_gameplay (SDL_Renderer *renderer, Inputs *inputs) { - static double +static void gameLoop_gameplay(SDL_Renderer *renderer, Inputs *inputs) +{ + static double f21, f22, f23, @@ -149,755 +164,851 @@ static void gameLoop_gameplay (SDL_Renderer *renderer, Inputs *inputs) { f35, f36; - static int + static int blockSelected = 0, selectedPass; - - static IntCoords blockSelect = { 0 }; - static IntCoords blockSelectOffset = { 0 }; - static IntCoords coordPass = { 0 }; - static IntCoords blockRayPosition = { 0 }; - - static Chunk *chunk; - - /* Look to see if there are chunks that need to be - loaded in*/ - - // static int chunkLoadNum = 0; - // if(chunkLoadNum < CHUNKARR_SIZE) { + + static IntCoords blockSelect = {0}; + static IntCoords blockSelectOffset = {0}; + static IntCoords coordPass = {0}; + static IntCoords blockRayPosition = {0}; + + static Chunk *chunk; + + /* Look to see if there are chunks that need to be + loaded in*/ + + // static int chunkLoadNum = 0; + // if(chunkLoadNum < CHUNKARR_SIZE) { // static IntCoords chunkLoadCoords = { 0 }; // chunkLoadCoords.x = - // ((chunkLoadNum % CHUNKARR_DIAM) - - // CHUNKARR_RAD) * 64 + player.pos.x; + // ((chunkLoadNum % CHUNKARR_DIAM) - + // CHUNKARR_RAD) * 64 + player.pos.x; // chunkLoadCoords.y = - // (((chunkLoadNum / CHUNKARR_DIAM) % CHUNKARR_DIAM) - - // CHUNKARR_RAD) * 64 + player.pos.y; + // (((chunkLoadNum / CHUNKARR_DIAM) % CHUNKARR_DIAM) - + // CHUNKARR_RAD) * 64 + player.pos.y; // chunkLoadCoords.z = - // ((chunkLoadNum / (CHUNKARR_DIAM * CHUNKARR_DIAM)) - - // CHUNKARR_RAD) * 64 + player.pos.z; + // ((chunkLoadNum / (CHUNKARR_DIAM * CHUNKARR_DIAM)) - + // CHUNKARR_RAD) * 64 + player.pos.z; // chunkLoadNum++; - // + // // genChunk ( - // &world, world.seed, - // chunkLoadCoords.x, - // chunkLoadCoords.y, - // chunkLoadCoords.z, world->type, 0, - // player.pos + // &world, world.seed, + // chunkLoadCoords.x, + // chunkLoadCoords.y, + // chunkLoadCoords.z, world->type, 0, + // player.pos // ); - // } else { + // } else { // chunkLoadNum = 0; - // } + // } - ;int headInWater = World_getBlock (&world, - player->pos.x, - player->pos.y, - player->pos.z) == BLOCK_WATER; + ; + int headInWater = World_getBlock(&world, + player->pos.x, + player->pos.y, + player->pos.z) == BLOCK_WATER; - int feetInWater = World_getBlock (&world, - player->pos.x, - player->pos.y + 1, - player->pos.z) == BLOCK_WATER; + int feetInWater = World_getBlock(&world, + player->pos.x, + player->pos.y + 1, + player->pos.z) == BLOCK_WATER; - int effectDrawDistance = options.drawDistance; - // Restrict view distance while in water - if (headInWater) { effectDrawDistance = 10; } + int effectDrawDistance = options.drawDistance; + // Restrict view distance while in water + if (headInWater) + { + effectDrawDistance = 10; + } - // Update directional vectors - player->vectorH.x = sin(player->hRot); - player->vectorH.y = cos(player->hRot); - player->vectorV.x = sin(player->vRot); - player->vectorV.y = cos(player->vRot); + // Update directional vectors + player->vectorH.x = sin(player->hRot); + player->vectorH.y = cos(player->hRot); + player->vectorV.x = sin(player->vRot); + player->vectorV.y = cos(player->vRot); - // Skybox, basically - double timeCoef; - switch (world.dayNightMode) { + // Skybox, basically + double timeCoef; + switch (world.dayNightMode) + { case 0: - timeCoef = (double)(world.time % 102944) / 16384; - timeCoef = sin(timeCoef); - timeCoef /= sqrt(timeCoef * timeCoef + (1.0 / 128.0)); - timeCoef = (timeCoef + 1) / 2; - break; + timeCoef = (double)(world.time % 102944) / 16384; + timeCoef = sin(timeCoef); + timeCoef /= sqrt(timeCoef * timeCoef + (1.0 / 128.0)); + timeCoef = (timeCoef + 1) / 2; + break; case 1: - timeCoef = 1; - break; + timeCoef = 1; + break; case 2: - timeCoef = 0; - break; - } - - // Change ambient color depending on if we are in the water or the air - if (headInWater) { - SDL_SetRenderDrawColor ( - renderer, - 48 * timeCoef, - 96 * timeCoef, - 200 * timeCoef, - 255 - ); - } else { - SDL_SetRenderDrawColor ( - renderer, - 153 * timeCoef, - 204 * timeCoef, - 255 * timeCoef, - 255 - ); - } - - SDL_RenderClear(renderer); - - if (inputs->keyboard.esc) { - gamePopup = gamePopup ? 0 : 1; - inputs->keyboard.esc = 0; - } - - fps_count++; - if (fps_lastmil < SDL_GetTicks() - 1000) { - fps_lastmil = SDL_GetTicks(); - fps_now = fps_count; - fps_count = 0; - } - - /* Things that should run at a constant speed, regardless - of CPU power. If the rendering takes a long time, this - will fire more times to compensate. */ - while (SDL_GetTicks() - l > 10L) { - world.time++; - l += 10L; - gameLoop_processMovement(inputs, feetInWater); - } - - if (gamePopup == POPUP_HUD) { - if (blockSelected) { - InvSlot *activeSlot = &player->inventory.hotbar [ - player->inventory.hotbarSelect - ]; - - // Breaking blocks - if (inputs->mouse.left > 0) { - Block blockid = World_getBlock ( - &world, - blockSelect.x, - blockSelect.y, - blockSelect.z - ); - - // Can't break other players - if (blockid != BLOCK_PLAYER_BODY && blockid != BLOCK_PLAYER_HEAD) { - InvSlot pickedUp = { - .blockid = blockid, - .amount = 1, - .durability = 1 - }; - - Inventory_transferIn(&player->inventory, &pickedUp); - - World_setBlock ( - &world, - blockSelect.x, - blockSelect.y, - blockSelect.z, 0, 1 - ); - } - } - - blockSelectOffset.x += blockSelect.x; - blockSelectOffset.y += blockSelect.y; - blockSelectOffset.z += blockSelect.z; - - // Placing blocks - if (inputs->mouse.right > 0) { - if ( - // Player cannot be obstructing the block - ( - fabs(player->pos.x - 0.5 - blockSelectOffset.x) >= 0.8 || - fabs(player->pos.y - blockSelectOffset.y) >= 1.45 || - fabs(player->pos.z - 0.5 - blockSelectOffset.z) >= 0.8 - ) && - // Player must have enough of that block - activeSlot->amount > 0 - ) { - int blockSet = World_setBlock ( - &world, - blockSelectOffset.x, - blockSelectOffset.y, - blockSelectOffset.z, - activeSlot->blockid, 1 - ); - - if (blockSet) { - activeSlot->amount --; - if (activeSlot->amount == 0) activeSlot->blockid = 0; - } - } - } + timeCoef = 0; + break; } - inputs->mouse.left = 0; - inputs->mouse.right = 0; - - // Toggle GUI - if (inputs->keyboard.f1) { - inputs->keyboard.f1 = 0; - guiOn ^= 1; - } - - // Toggle debug mode - if (inputs->keyboard.f3) { - inputs->keyboard.f3 = 0; - debugOn = !debugOn; - } - - // Toggle advanced debug menu - #ifndef small - if (inputs->keyboard.f4) { - inputs->keyboard.f4 = 0; - gamePopup = (gamePopup == POPUP_ADVANCED_DEBUG) ? 0 : 4; - } - #endif - - // Enter chat - if (inputs->keyboard.t) { - // reset text input - inputs->keyboard.t = 0; - inputs->keyTyped = 0; - gamePopup = POPUP_CHAT; - } - - // Enter inventory - if (inputs->keyboard.e) { - inputs->keyboard.e = 0; - gamePopup = POPUP_INVENTORY; - } - - // Swap hotbar selection with offhand - if (inputs->keyboard.f) { - inputs->keyboard.f = 0; - InvSlot_swap ( - &player->inventory.hotbar[player->inventory.hotbarSelect], - &player->inventory.offhand - ); - } - - // Select hotbar slots with scroll wheel - if (inputs->mouse.wheel != 0) { - player->inventory.hotbarSelect -= inputs->mouse.wheel; - player->inventory.hotbarSelect = nmod ( - player->inventory.hotbarSelect, 9); - inputs->mouse.wheel = 0; - } - - // Select hotbar slots with number keys - if (inputs->keyboard.num1) { player->inventory.hotbarSelect = 0; } - if (inputs->keyboard.num2) { player->inventory.hotbarSelect = 1; } - if (inputs->keyboard.num3) { player->inventory.hotbarSelect = 2; } - if (inputs->keyboard.num4) { player->inventory.hotbarSelect = 3; } - if (inputs->keyboard.num5) { player->inventory.hotbarSelect = 4; } - if (inputs->keyboard.num6) { player->inventory.hotbarSelect = 5; } - if (inputs->keyboard.num7) { player->inventory.hotbarSelect = 6; } - if (inputs->keyboard.num8) { player->inventory.hotbarSelect = 7; } - if (inputs->keyboard.num9) { player->inventory.hotbarSelect = 8; } - } - - /* Cast rays. selectedPass passes wether or not a block is - selected to the blockSelected variable */ - - // Decrease fov when in water - double effectFov = options.fov; - if (headInWater) { effectFov += 20; } - - selectedPass = 0; - for (int pixelX = 0; pixelX < BUFFER_W; pixelX++) { - double rayOffsetX = (pixelX - BUFFER_HALF_W) / effectFov; - for (int pixelY = 0; pixelY < BUFFER_H; pixelY++) { - int finalPixelColor = 0; - int pixelMist = 255; - int pixelShade; - - double rayOffsetY = (pixelY - BUFFER_HALF_H) / effectFov; - - // Ray offset Z? - f21 = 1.0; - - f22 = f21 * player->vectorV.y + rayOffsetY * player->vectorV.x; - f23 = rayOffsetY * player->vectorV.y - f21 * player->vectorV.x; - f24 = rayOffsetX * player->vectorH.y + f22 * player->vectorH.x; - f25 = f22 * player->vectorH.y - rayOffsetX * player->vectorH.x; - - double rayDistanceLimit = effectDrawDistance; - - f26 = 5.0; - for (int blockFace = 0; blockFace < 3; blockFace++) { - f27 = f24; - if (blockFace == 1) f27 = f23; - if (blockFace == 2) f27 = f25; - f28 = 1.0 / ((f27 < 0.0) ? (-1 * f27) : f27); - f29 = f24 * f28; - f30 = f23 * f28; - f31 = f25 * f28; - f32 = player->pos.x - floor(player->pos.x); - if (blockFace == 1) f32 = player->pos.y - floor(player->pos.y); - if (blockFace == 2) f32 = player->pos.z - floor(player->pos.z); - if (f27 > 0.0) f32 = 1.0 - f32; - f33 = f28 * f32; - f34 = player->pos.x + f29 * f32; - f35 = player->pos.y + f30 * f32; - f36 = player->pos.z + f31 * f32; - if (f27 < 0.0) { - if (blockFace == 0) f34--; - if (blockFace == 1) f35--; - if (blockFace == 2) f36--; - } - - /* Whatever's in this loop needs to run *extremely* - fast */ - while (f33 < rayDistanceLimit) { - blockRayPosition.x = floor(f34); - blockRayPosition.y = floor(f35); - blockRayPosition.z = floor(f36); - - /* Imitate getBlock so we don't have to launch - into a function then another function a zillion - times per second. This MUST BE STATIC because - this information needs to carry over between - iterations of gameLoop. */ - // TODO: make this an inline function - static IntCoords lookup_ago = { - 100000000, - 100000000, - 100000000 - }, lookup_now; - - lookup_now.x = blockRayPosition.x >> 6; - lookup_now.y = blockRayPosition.y >> 6; - lookup_now.z = blockRayPosition.z >> 6; - - if ( - lookup_now.x != lookup_ago.x || - lookup_now.y != lookup_ago.y || - lookup_now.z != lookup_ago.z - ) { - lookup_ago = lookup_now; - - // hash coordinates - lookup_now.x &= 0x3FF; - lookup_now.y &= 0x3FF; - lookup_now.z &= 0x3FF; - - lookup_now.y <<= 10; - lookup_now.z <<= 20; - - uint32_t lookup_hash = lookup_now.x | lookup_now.y | lookup_now.z; - lookup_hash++; - - int lookup_first = 0, - lookup_last = CHUNKARR_SIZE - 1, - lookup_middle = (CHUNKARR_SIZE - 1) / 2; - - // Perform binary search - while (lookup_first <= lookup_last) { - if (world.chunk[lookup_middle].coordHash > lookup_hash) { - lookup_first = lookup_middle + 1; - - } else if (world.chunk[lookup_middle].coordHash == lookup_hash) { - chunk = &world.chunk[lookup_middle]; - goto foundChunk; - - } else { - lookup_last = lookup_middle - 1; - } - - lookup_middle = (lookup_first + lookup_last) / 2; - } - chunk = NULL; - } - - Block intersectedBlock; - foundChunk: if (chunk) { - intersectedBlock = chunk->blocks [ - nmod(blockRayPosition.x, 64) + - (nmod(blockRayPosition.y, 64) << 6 ) + - (nmod(blockRayPosition.z, 64) << 12) - ]; - } else { - intersectedBlock = 0; - goto chunkNull; - } - - if ( - intersectedBlock != BLOCK_AIR && - !(headInWater && intersectedBlock == BLOCK_WATER) - ) { - // Determine what texel the ray hit - int textureX = (int)floor((f34 + f36) * 16.0) & 0xF; - int textureY = ((int)floor(f35 * 16.0) & 0xF) + 16; - if (blockFace == 1) { - textureX = (int)floor(f34 * 16.0) & 0xF; - textureY = (int)floor(f36 * 16.0) & 0xF; - if (f30 < 0.0) - textureY += 32; - } - - // Block outline color - int pixelColor = 0xFFFFFF; - if ( - ( - !blockSelected || - blockRayPosition.x != blockSelect.x || - blockRayPosition.y != blockSelect.y || - blockRayPosition.z != blockSelect.z - ) || ( - textureX > 0 - && textureY % 16 > 0 - && textureX < 15 - && textureY % 16 < 15 - ) || !guiOn || gamePopup - ) { - if (intersectedBlock >= NUMBER_OF_BLOCKS) { - pixelColor = 0xFF0000; - } else { - pixelColor = textures [ - textureX + (textureY * 16) + intersectedBlock * 256 * 3]; - } - } - - /* See if the block is selected. There must be a - better way to do this check... */ - if ( - f33 < f26 && ( - ( - ! options.trapMouse - && pixelX == inputs->mouse.x / BUFFER_SCALE - && pixelY == inputs->mouse.y / BUFFER_SCALE - ) || ( - options.trapMouse - && pixelX == BUFFER_HALF_W - && pixelY == BUFFER_HALF_H - ) - ) - ) { - selectedPass = 1; - coordPass = blockRayPosition; - - blockSelectOffset = (const IntCoords) { 0 }; - switch (blockFace) { - case 0: blockSelectOffset.x = 1 - 2 * (f27 > 0.0); break; - case 1: blockSelectOffset.y = 1 - 2 * (f27 > 0.0); break; - case 2: blockSelectOffset.z = 1 - 2 * (f27 > 0.0); break; - } - - f26 = f33; - } - - if (pixelColor > 0) { - finalPixelColor = pixelColor; - pixelMist = 255 - (int)( - f33 / (double)effectDrawDistance * 255.0F); - pixelShade = 255 - (blockFace + 2) % 3 * 50; - rayDistanceLimit = f33; - } - } - chunkNull: - f34 += f29; - f35 += f30; - f36 += f31; - f33 += f28; - } // This concludes our warpspeed rampage - } - - // Draw inverted color crosshair - if (options.trapMouse && ( - (pixelX == BUFFER_HALF_W - && abs(BUFFER_HALF_H - pixelY) < 4) || - (pixelY == BUFFER_HALF_H - && abs(BUFFER_HALF_W - pixelX) < 4) - )) { - finalPixelColor = 0x1000000 - finalPixelColor; - } - - if (finalPixelColor > 0) { + // Change ambient color depending on if we are in the water or the air + if (headInWater) + { SDL_SetRenderDrawColor( - renderer, - ((finalPixelColor >> 16 & 0xFF) * pixelShade) >> 8, - ((finalPixelColor >> 8 & 0xFF) * pixelShade) >> 8, - ((finalPixelColor & 0xFF) * pixelShade) >> 8, - options.fogType ? sqrt(pixelMist) * 16 : pixelMist - ); - - SDL_RenderDrawPoint(renderer, pixelX, pixelY); - } + renderer, + 48 * timeCoef, + 96 * timeCoef, + 200 * timeCoef, + 255); + } + else + { + SDL_SetRenderDrawColor( + renderer, + 153 * timeCoef, + 204 * timeCoef, + 255 * timeCoef, + 255); } - } - // Make camera blue if in water - if (headInWater) { - SDL_SetRenderDrawColor(renderer, 16, 32, 255, 128); - SDL_RenderFillRect(renderer, &backgroundRect); - } - - // Pass info about selected block on - blockSelected = selectedPass; - blockSelect = coordPass; - - inputs->mouse.x /= BUFFER_SCALE; - inputs->mouse.y /= BUFFER_SCALE; + SDL_RenderClear(renderer); - // Draw current popup - gameLoop_drawPopup(renderer, inputs); - - // If we need to take a screenshot, do so - if (inputs->keyboard.f2) { - inputs->keyboard.f2 = 0; - char path [PATH_MAX]; - int err = data_getScreenshotPath(path); - gameLoop_screenshot(renderer, err ? NULL : path); - } -} + if (inputs->keyboard.esc) + { + gamePopup = gamePopup ? 0 : 1; + inputs->keyboard.esc = 0; + } -void gameLoop_drawPopup (SDL_Renderer *renderer, Inputs *inputs) { - // In-game menus - if (gamePopup != 0) { - SDL_SetRelativeMouseMode(0); + fps_count++; + if (fps_lastmil < SDL_GetTicks() - 1000) + { + fps_lastmil = SDL_GetTicks(); + fps_now = fps_count; + fps_count = 0; + } + + /* Things that should run at a constant speed, regardless + of CPU power. If the rendering takes a long time, this + will fire more times to compensate. */ + while (SDL_GetTicks() - l > 10L) + { + world.time++; + l += 10L; + gameLoop_processMovement(inputs, feetInWater); + } + + if (gamePopup == POPUP_HUD) + { + if (blockSelected) + { + InvSlot *activeSlot = &player->inventory.hotbar[player->inventory.hotbarSelect]; + + // Breaking blocks + if (inputs->mouse.left > 0) + { + Block blockid = World_getBlock( + &world, + blockSelect.x, + blockSelect.y, + blockSelect.z); + + // Can't break other players + if (blockid != BLOCK_PLAYER_BODY && blockid != BLOCK_PLAYER_HEAD) + { + InvSlot pickedUp = { + .blockid = blockid, + .amount = 1, + .durability = 1}; + + Inventory_transferIn(&player->inventory, &pickedUp); + + World_setBlock( + &world, + blockSelect.x, + blockSelect.y, + blockSelect.z, 0, 1); + } + } + + blockSelectOffset.x += blockSelect.x; + blockSelectOffset.y += blockSelect.y; + blockSelectOffset.z += blockSelect.z; + + // Placing blocks + if (inputs->mouse.right > 0) + { + if ( + // Player cannot be obstructing the block + ( + fabs(player->pos.x - 0.5 - blockSelectOffset.x) >= 0.8 || + fabs(player->pos.y - blockSelectOffset.y) >= 1.45 || + fabs(player->pos.z - 0.5 - blockSelectOffset.z) >= 0.8) && + // Player must have enough of that block + activeSlot->amount > 0) + { + int blockSet = World_setBlock( + &world, + blockSelectOffset.x, + blockSelectOffset.y, + blockSelectOffset.z, + activeSlot->blockid, 1); + + if (blockSet) + { + activeSlot->amount--; + if (activeSlot->amount == 0) + activeSlot->blockid = 0; + } + } + } } - switch (gamePopup) { - case POPUP_HUD: - // HUD - if (options.trapMouse) SDL_SetRelativeMouseMode(1); - if (guiOn) popup_hud ( - renderer, inputs, &world, - &debugOn, &fps_now, player - ); - break; + inputs->mouse.left = 0; + inputs->mouse.right = 0; - case POPUP_PAUSE: - // Pause menu - tblack(renderer); - SDL_RenderFillRect(renderer, &backgroundRect); - popup_pause(renderer, inputs, &gamePopup, &gameState, &world); - break; + // Toggle GUI + if (inputs->keyboard.f1) + { + inputs->keyboard.f1 = 0; + guiOn ^= 1; + } - case POPUP_OPTIONS: - // Options - tblack(renderer); - SDL_RenderFillRect(renderer, &backgroundRect); - popup_options (renderer, inputs, &gamePopup); - break; - - case POPUP_INVENTORY: - // Inventory - popup_inventory(renderer, inputs, player, &gamePopup); - break; + // Toggle debug mode + if (inputs->keyboard.f3) + { + inputs->keyboard.f3 = 0; + debugOn = !debugOn; + } + // Toggle advanced debug menu #ifndef small - case POPUP_ADVANCED_DEBUG: - // Advanced debug menu - tblack(renderer); - SDL_RenderFillRect(renderer, &backgroundRect); - popup_debugTools(renderer, inputs, &gamePopup); - break; - - case POPUP_CHUNK_PEEK: - // Chunk peek - tblack(renderer); - SDL_RenderFillRect(renderer, &backgroundRect); - popup_chunkPeek(renderer, inputs, &world, &gamePopup, player); - break; - - case POPUP_ROLL_CALL: - // Chunk info viewer - tblack(renderer); - SDL_RenderFillRect(renderer, &backgroundRect); - popup_rollCall(renderer, inputs, &world, &gamePopup); - break; - - case POPUP_OVERVIEW: - // View all chunks - tblack(renderer); - SDL_RenderFillRect(renderer, &backgroundRect); - popup_overview(renderer, inputs, &world, &gamePopup); - break; + if (inputs->keyboard.f4) + { + inputs->keyboard.f4 = 0; + gamePopup = (gamePopup == POPUP_ADVANCED_DEBUG) ? 0 : 4; + } #endif - case POPUP_CHAT: - // Chat - popup_chat(renderer, inputs, world.time); - break; + // Enter chat + if (inputs->keyboard.t) + { + // reset text input + inputs->keyboard.t = 0; + inputs->keyTyped = 0; + gamePopup = POPUP_CHAT; } + + // Enter inventory + if (inputs->keyboard.e) + { + inputs->keyboard.e = 0; + gamePopup = POPUP_INVENTORY; + } + + // Swap hotbar selection with offhand + if (inputs->keyboard.f) + { + inputs->keyboard.f = 0; + InvSlot_swap( + &player->inventory.hotbar[player->inventory.hotbarSelect], + &player->inventory.offhand); + } + + // Select hotbar slots with scroll wheel + if (inputs->mouse.wheel != 0) + { + player->inventory.hotbarSelect -= inputs->mouse.wheel; + player->inventory.hotbarSelect = nmod( + player->inventory.hotbarSelect, 9); + inputs->mouse.wheel = 0; + } + + // Select hotbar slots with number keys + if (inputs->keyboard.num1) + { + player->inventory.hotbarSelect = 0; + } + if (inputs->keyboard.num2) + { + player->inventory.hotbarSelect = 1; + } + if (inputs->keyboard.num3) + { + player->inventory.hotbarSelect = 2; + } + if (inputs->keyboard.num4) + { + player->inventory.hotbarSelect = 3; + } + if (inputs->keyboard.num5) + { + player->inventory.hotbarSelect = 4; + } + if (inputs->keyboard.num6) + { + player->inventory.hotbarSelect = 5; + } + if (inputs->keyboard.num7) + { + player->inventory.hotbarSelect = 6; + } + if (inputs->keyboard.num8) + { + player->inventory.hotbarSelect = 7; + } + if (inputs->keyboard.num9) + { + player->inventory.hotbarSelect = 8; + } + } + + /* Cast rays. selectedPass passes wether or not a block is + selected to the blockSelected variable */ + + // Decrease fov when in water + double effectFov = options.fov; + if (headInWater) + { + effectFov += 20; + } + + selectedPass = 0; + for (int pixelX = 0; pixelX < BUFFER_W; pixelX++) + { + double rayOffsetX = (pixelX - BUFFER_HALF_W) / effectFov; + for (int pixelY = 0; pixelY < BUFFER_H; pixelY++) + { + int finalPixelColor = 0; + int pixelMist = 255; + int pixelShade; + + double rayOffsetY = (pixelY - BUFFER_HALF_H) / effectFov; + + // Ray offset Z? + f21 = 1.0; + + f22 = f21 * player->vectorV.y + rayOffsetY * player->vectorV.x; + f23 = rayOffsetY * player->vectorV.y - f21 * player->vectorV.x; + f24 = rayOffsetX * player->vectorH.y + f22 * player->vectorH.x; + f25 = f22 * player->vectorH.y - rayOffsetX * player->vectorH.x; + + double rayDistanceLimit = effectDrawDistance; + + f26 = 5.0; + for (int blockFace = 0; blockFace < 3; blockFace++) + { + f27 = f24; + if (blockFace == 1) + f27 = f23; + if (blockFace == 2) + f27 = f25; + f28 = 1.0 / ((f27 < 0.0) ? (-1 * f27) : f27); + f29 = f24 * f28; + f30 = f23 * f28; + f31 = f25 * f28; + f32 = player->pos.x - floor(player->pos.x); + if (blockFace == 1) + f32 = player->pos.y - floor(player->pos.y); + if (blockFace == 2) + f32 = player->pos.z - floor(player->pos.z); + if (f27 > 0.0) + f32 = 1.0 - f32; + f33 = f28 * f32; + f34 = player->pos.x + f29 * f32; + f35 = player->pos.y + f30 * f32; + f36 = player->pos.z + f31 * f32; + if (f27 < 0.0) + { + if (blockFace == 0) + f34--; + if (blockFace == 1) + f35--; + if (blockFace == 2) + f36--; + } + + /* Whatever's in this loop needs to run *extremely* + fast */ + while (f33 < rayDistanceLimit) + { + blockRayPosition.x = floor(f34); + blockRayPosition.y = floor(f35); + blockRayPosition.z = floor(f36); + + /* Imitate getBlock so we don't have to launch + into a function then another function a zillion + times per second. This MUST BE STATIC because + this information needs to carry over between + iterations of gameLoop. */ + // TODO: make this an inline function + static IntCoords lookup_ago = { + 100000000, + 100000000, + 100000000}, + lookup_now; + + lookup_now.x = blockRayPosition.x >> 6; + lookup_now.y = blockRayPosition.y >> 6; + lookup_now.z = blockRayPosition.z >> 6; + + if ( + lookup_now.x != lookup_ago.x || + lookup_now.y != lookup_ago.y || + lookup_now.z != lookup_ago.z) + { + lookup_ago = lookup_now; + + // hash coordinates + lookup_now.x &= 0x3FF; + lookup_now.y &= 0x3FF; + lookup_now.z &= 0x3FF; + + lookup_now.y <<= 10; + lookup_now.z <<= 20; + + uint32_t lookup_hash = lookup_now.x | lookup_now.y | lookup_now.z; + lookup_hash++; + + int lookup_first = 0, + lookup_last = CHUNKARR_SIZE - 1, + lookup_middle = (CHUNKARR_SIZE - 1) / 2; + + // Perform binary search + while (lookup_first <= lookup_last) + { + if (world.chunk[lookup_middle].coordHash > lookup_hash) + { + lookup_first = lookup_middle + 1; + } + else if (world.chunk[lookup_middle].coordHash == lookup_hash) + { + chunk = &world.chunk[lookup_middle]; + goto foundChunk; + } + else + { + lookup_last = lookup_middle - 1; + } + + lookup_middle = (lookup_first + lookup_last) / 2; + } + chunk = NULL; + } + + Block intersectedBlock; + foundChunk: + if (chunk) + { + intersectedBlock = chunk->blocks[nmod(blockRayPosition.x, 64) + + (nmod(blockRayPosition.y, 64) << 6) + + (nmod(blockRayPosition.z, 64) << 12)]; + } + else + { + intersectedBlock = 0; + goto chunkNull; + } + + if ( + intersectedBlock != BLOCK_AIR && + !(headInWater && intersectedBlock == BLOCK_WATER)) + { + // Determine what texel the ray hit + int textureX = (int)floor((f34 + f36) * 16.0) & 0xF; + int textureY = ((int)floor(f35 * 16.0) & 0xF) + 16; + if (blockFace == 1) + { + textureX = (int)floor(f34 * 16.0) & 0xF; + textureY = (int)floor(f36 * 16.0) & 0xF; + if (f30 < 0.0) + textureY += 32; + } + + // Block outline color + int pixelColor = 0xFFFFFF; + if ( + ( + !blockSelected || + blockRayPosition.x != blockSelect.x || + blockRayPosition.y != blockSelect.y || + blockRayPosition.z != blockSelect.z) || + (textureX > 0 && textureY % 16 > 0 && textureX < 15 && textureY % 16 < 15) || !guiOn || gamePopup) + { + if (intersectedBlock >= NUMBER_OF_BLOCKS) + { + pixelColor = 0xFF0000; + } + else + { + pixelColor = textures[textureX + (textureY * 16) + intersectedBlock * 256 * 3]; + } + } + + /* See if the block is selected. There must be a + better way to do this check... */ + if ( + f33 < f26 && + ( + (!options.trapMouse && pixelX == inputs->mouse.x / BUFFER_SCALE && pixelY == inputs->mouse.y / BUFFER_SCALE) || + (options.trapMouse && pixelX == BUFFER_HALF_W && pixelY == BUFFER_HALF_H) + ) + ) + { + selectedPass = 1; + coordPass = blockRayPosition; + + blockSelectOffset = (const IntCoords){0}; + switch (blockFace) + { + case 0: + blockSelectOffset.x = 1 - 2 * (f27 > 0.0); + break; + case 1: + blockSelectOffset.y = 1 - 2 * (f27 > 0.0); + break; + case 2: + blockSelectOffset.z = 1 - 2 * (f27 > 0.0); + break; + } + + f26 = f33; + } + + if (pixelColor > 0) + { + finalPixelColor = pixelColor; + pixelMist = 255 - (int)(f33 / (double)effectDrawDistance * 255.0F); + pixelShade = 255 - (blockFace + 2) % 3 * 50; + rayDistanceLimit = f33; + } + } + chunkNull: + f34 += f29; + f35 += f30; + f36 += f31; + f33 += f28; + } // This concludes our warpspeed rampage + } + + // Draw inverted color crosshair + if (options.trapMouse && ((pixelX == BUFFER_HALF_W && abs(BUFFER_HALF_H - pixelY) < 4) || + (pixelY == BUFFER_HALF_H && abs(BUFFER_HALF_W - pixelX) < 4))) + { + finalPixelColor = 0x1000000 - finalPixelColor; + } + + if (finalPixelColor > 0) + { + SDL_SetRenderDrawColor( + renderer, + ((finalPixelColor >> 16 & 0xFF) * pixelShade) >> 8, + ((finalPixelColor >> 8 & 0xFF) * pixelShade) >> 8, + ((finalPixelColor & 0xFF) * pixelShade) >> 8, + options.fogType ? sqrt(pixelMist) * 16 : pixelMist); + + SDL_RenderDrawPoint(renderer, pixelX, pixelY); + } + } + } + + // Make camera blue if in water + if (headInWater) + { + SDL_SetRenderDrawColor(renderer, 16, 32, 255, 128); + SDL_RenderFillRect(renderer, &backgroundRect); + } + + // Pass info about selected block on + blockSelected = selectedPass; + blockSelect = coordPass; + + inputs->mouse.x /= BUFFER_SCALE; + inputs->mouse.y /= BUFFER_SCALE; + + // Draw current popup + gameLoop_drawPopup(renderer, inputs); + + // If we need to take a screenshot, do so + if (inputs->keyboard.f2) + { + inputs->keyboard.f2 = 0; + char path[PATH_MAX]; + int err = data_getScreenshotPath(path); + gameLoop_screenshot(renderer, err ? NULL : path); + } } -static void gameLoop_processMovement (Inputs *inputs, int inWater) { - // Run at half speed if in water - static int flipFlop = 0; - flipFlop = !flipFlop; - int doPhysics = !inWater || flipFlop; - // Only process movement controls if there are no active popup - if (gamePopup == 0) { - // Looking around - if (options.trapMouse) { - player->hRot += (double)inputs->mouse.x / 64; - player->vRot -= (double)inputs->mouse.y / 64; - } else { - double cameraMoveX = - (inputs->mouse.x - BUFFER_W * 2) / - (double)BUFFER_W * 2.0; - double cameraMoveY = - (inputs->mouse.y - BUFFER_H * 2) / - (double)BUFFER_H * 2.0; +void gameLoop_drawPopup(SDL_Renderer *renderer, Inputs *inputs) +{ + // In-game menus + if (gamePopup != 0) + { + SDL_SetRelativeMouseMode(0); + } - double cameraMoveDistance = sqrt ( - cameraMoveX * cameraMoveX + - cameraMoveY * cameraMoveY) - 1.2; + switch (gamePopup) + { + case POPUP_HUD: + // HUD + if (options.trapMouse) + SDL_SetRelativeMouseMode(1); + if (guiOn) + popup_hud( + renderer, inputs, &world, + &debugOn, &fps_now, player); + break; - if (cameraMoveDistance < 0.0) { - cameraMoveDistance = 0.0; - } - if (cameraMoveDistance > 0.0) { - player->hRot += cameraMoveX * - cameraMoveDistance / 400.0; - player->vRot -= cameraMoveY * - cameraMoveDistance / 400.0; - } - } + case POPUP_PAUSE: + // Pause menu + tblack(renderer); + SDL_RenderFillRect(renderer, &backgroundRect); + popup_pause(renderer, inputs, &gamePopup, &gameState, &world); + break; - // Restrict camera vertical position - if (player->vRot < -1.57) player->vRot = -1.57; - if (player->vRot > 1.57) player->vRot = 1.57; + case POPUP_OPTIONS: + // Options + tblack(renderer); + SDL_RenderFillRect(renderer, &backgroundRect); + popup_options(renderer, inputs, &gamePopup); + break; - double speed = 0.02; + case POPUP_INVENTORY: + // Inventory + popup_inventory(renderer, inputs, player, &gamePopup); + break; - if (doPhysics) { - player->FBVelocity = - (inputs->keyboard.w - inputs->keyboard.s) * - speed; - player->LRVelocity = - (inputs->keyboard.d - inputs->keyboard.a) * - speed; - } + #ifndef small + case POPUP_ADVANCED_DEBUG: + // Advanced debug menu + tblack(renderer); + SDL_RenderFillRect(renderer, &backgroundRect); + popup_debugTools(renderer, inputs, &gamePopup); + break; + + case POPUP_CHUNK_PEEK: + // Chunk peek + tblack(renderer); + SDL_RenderFillRect(renderer, &backgroundRect); + popup_chunkPeek(renderer, inputs, &world, &gamePopup, player); + break; + + case POPUP_ROLL_CALL: + // Chunk info viewer + tblack(renderer); + SDL_RenderFillRect(renderer, &backgroundRect); + popup_rollCall(renderer, inputs, &world, &gamePopup); + break; + + case POPUP_OVERVIEW: + // View all chunks + tblack(renderer); + SDL_RenderFillRect(renderer, &backgroundRect); + popup_overview(renderer, inputs, &world, &gamePopup); + break; + #endif + + case POPUP_CHAT: + // Chat + popup_chat(renderer, inputs, world.time); + break; + } +} + + +static void gameLoop_processMovement(Inputs *inputs, int inWater) +{ + // Run at half speed if in water + static int flipFlop = 0; + flipFlop = !flipFlop; + int doPhysics = !inWater || flipFlop; + + // Only process movement controls if there are no active popup + if (gamePopup == 0) + { + // Looking around + if (options.trapMouse) + { + player->hRot += (double)inputs->mouse.x / 64; + player->vRot -= (double)inputs->mouse.y / 64; } - - static Coords playerMovement = { 0.0, 0.0, 0.0 }; + else + { + double cameraMoveX = + (inputs->mouse.x - BUFFER_W * 2) / + (double)BUFFER_W * 2.0; + double cameraMoveY = + (inputs->mouse.y - BUFFER_H * 2) / + (double)BUFFER_H * 2.0; - // Moving around - if (doPhysics) { - playerMovement.x *= 0.5; - playerMovement.y *= 0.99; - playerMovement.z *= 0.5; + double cameraMoveDistance = sqrt( + cameraMoveX * cameraMoveX + + cameraMoveY * cameraMoveY) - + 1.2; - playerMovement.x += - player->vectorH.x * player->FBVelocity + - player->vectorH.y * player->LRVelocity; - playerMovement.z += - player->vectorH.y * player->FBVelocity - - player->vectorH.x * player->LRVelocity; - playerMovement.y += 0.003; + if (cameraMoveDistance < 0.0) + { + cameraMoveDistance = 0.0; + } + if (cameraMoveDistance > 0.0) + { + player->hRot += cameraMoveX * + cameraMoveDistance / 400.0; + player->vRot -= cameraMoveY * + cameraMoveDistance / 400.0; + } } + // Restrict camera vertical position + if (player->vRot < -1.57) + player->vRot = -1.57; + if (player->vRot > 1.57) + player->vRot = 1.57; - // Detect collisions and jump - for (int axis = 0; axis < 3; axis++) { - if (!doPhysics) { break; } + double speed = 0.02; - Coords playerPosTry = { - player->pos.x + playerMovement.x * (double)((axis + 2) % 3 / 2), - player->pos.y + playerMovement.y * (double)((axis + 1) % 3 / 2), - player->pos.z + playerMovement.z * (double)((axis + 3) % 3 / 2), - }; - - for (int step = 0; step < 12; step++) { - int blockX = floor(playerPosTry.x + - ((step >> 0) & 1) * 0.6 - 0.3); - int blockY = floor(playerPosTry.y + - ((step >> 2) - 1) * 0.8 + 0.65); - int blockZ = floor(playerPosTry.z + - ((step >> 1) & 1) * 0.6 - 0.3); + if (doPhysics) + { + player->FBVelocity = + (inputs->keyboard.w - inputs->keyboard.s) * + speed; + player->LRVelocity = + (inputs->keyboard.d - inputs->keyboard.a) * + speed; + } + } - // Very ad-hoc. TODO: look into a deeper fix than this. - // blockX -= (blockX < 0); - // blockY -= (blockY < 0); - // blockZ -= (blockZ < 0); - // --- + static Coords playerMovement = {0.0, 0.0, 0.0}; - Block block = World_getBlock (&world, - blockX, - blockY, - blockZ); + // Moving around + if (doPhysics) + { + playerMovement.x *= 0.5; + playerMovement.y *= 0.99; + playerMovement.z *= 0.5; - int shouldCollide = 1; - // Blocks that have collision disabled - shouldCollide &= block != BLOCK_AIR; - shouldCollide &= block != BLOCK_WATER; - shouldCollide &= block != BLOCK_TALL_GRASS; - // Uncomment this line to be able to enter chunks that - // don't exist in memory - // shouldCollide &= block != BLOCK_NIL; - - if (shouldCollide) { - if (axis != 1) { goto stopCheck; } - - if ( - inputs->keyboard.space > 0 && - (playerMovement.y > 0.0) && - !gamePopup - ) { - inputs->keyboard.space = 0; - playerMovement.y = -0.1; - goto stopCheck; - } - playerMovement.y = 0.0; - goto stopCheck; - } - } + playerMovement.x += + player->vectorH.x * player->FBVelocity + + player->vectorH.y * player->LRVelocity; + playerMovement.z += + player->vectorH.y * player->FBVelocity - + player->vectorH.x * player->LRVelocity; + playerMovement.y += 0.003; + } - player->pos.x = playerPosTry.x; - player->pos.y = playerPosTry.y; - player->pos.z = playerPosTry.z; - - stopCheck:; + // Detect collisions and jump + for (int axis = 0; axis < 3; axis++) + { + if (!doPhysics) + { + break; } - // Swim in water - if (inWater && doPhysics) { + Coords playerPosTry = { + player->pos.x + playerMovement.x * (double)((axis + 2) % 3 / 2), + player->pos.y + playerMovement.y * (double)((axis + 1) % 3 / 2), + player->pos.z + playerMovement.z * (double)((axis + 3) % 3 / 2), + }; + + for (int step = 0; step < 12; step++) + { + int blockX = floor(playerPosTry.x + + ((step >> 0) & 1) * 0.6 - 0.3); + int blockY = floor(playerPosTry.y + + ((step >> 2) - 1) * 0.8 + 0.65); + int blockZ = floor(playerPosTry.z + + ((step >> 1) & 1) * 0.6 - 0.3); + + // Very ad-hoc. TODO: look into a deeper fix than this. + // blockX -= (blockX < 0); + // blockY -= (blockY < 0); + // blockZ -= (blockZ < 0); + // --- + + Block block = World_getBlock(&world, + blockX, + blockY, + blockZ); + + int shouldCollide = 1; + // Blocks that have collision disabled + shouldCollide &= block != BLOCK_AIR; + shouldCollide &= block != BLOCK_WATER; + shouldCollide &= block != BLOCK_TALL_GRASS; + // Uncomment this line to be able to enter chunks that + // don't exist in memory + // shouldCollide &= block != BLOCK_NIL; + + if (shouldCollide) + { + if (axis != 1) + { + goto stopCheck; + } + if ( - inputs->keyboard.space > 0 && - (playerMovement.y > -0.05) && - !gamePopup - ) { - inputs->keyboard.space = 0; - playerMovement.y = -0.1; + inputs->keyboard.space > 0 && + (playerMovement.y > 0.0) && + !gamePopup) + { + inputs->keyboard.space = 0; + playerMovement.y = -0.1; + goto stopCheck; } + playerMovement.y = 0.0; + goto stopCheck; + } } + + player->pos.x = playerPosTry.x; + player->pos.y = playerPosTry.y; + player->pos.z = playerPosTry.z; + + stopCheck:; + } + + // Swim in water + if (inWater && doPhysics) + { + if ( + inputs->keyboard.space > 0 && + (playerMovement.y > -0.05) && + !gamePopup) + { + inputs->keyboard.space = 0; + playerMovement.y = -0.1; + } + } } -int gameLoop_screenshot (SDL_Renderer *renderer, const char *path) { - SDL_Surface *grab = SDL_CreateRGBSurfaceWithFormat ( - 0, BUFFER_W * BUFFER_SCALE, BUFFER_H * BUFFER_SCALE, - 32, SDL_PIXELFORMAT_ARGB8888 - ); - SDL_RenderReadPixels ( - renderer, NULL, SDL_PIXELFORMAT_ARGB8888, - grab->pixels, grab->pitch - ); +int gameLoop_screenshot(SDL_Renderer *renderer, const char *path) +{ + SDL_Surface *grab = SDL_CreateRGBSurfaceWithFormat( + 0, BUFFER_W * BUFFER_SCALE, BUFFER_H * BUFFER_SCALE, + 32, SDL_PIXELFORMAT_ARGB8888); - if (path == NULL) { - chatAdd("Couldn't save screenshot"); - return 1; - } - - int saved = SDL_SaveBMP(grab, path); - SDL_FreeSurface(grab); + SDL_RenderReadPixels( + renderer, NULL, SDL_PIXELFORMAT_ARGB8888, + grab->pixels, grab->pitch); - if (saved == 0) { - chatAdd("Saved screenshot"); - return 0; - } else { - chatAdd("Couldn't save screenshot"); - return 1; - } + if (path == NULL) + { + chatAdd("Couldn't save screenshot"); + return 1; + } + + int saved = SDL_SaveBMP(grab, path); + SDL_FreeSurface(grab); + + if (saved == 0) + { + chatAdd("Saved screenshot"); + return 0; + } + else + { + chatAdd("Couldn't save screenshot"); + return 1; + } } -void gameLoop_error (char *message) { - errorMessage = message; + +void gameLoop_error(char *message) +{ + errorMessage = message; } diff --git a/src/gui.c b/src/gui.c index e1d1126..8b4daf3 100644 --- a/src/gui.c +++ b/src/gui.c @@ -1,506 +1,562 @@ #include "gui.h" #include "blocks.h" -const int BUFFER_W = 214; -const int BUFFER_H = 120; -const int BUFFER_SCALE = 4; -const int BUFFER_HALF_W = BUFFER_W / 2; -const int BUFFER_HALF_H = BUFFER_H / 2; -const int WINDOW_W = BUFFER_W * BUFFER_SCALE; -const int WINDOW_H = BUFFER_H * BUFFER_SCALE; -char chatHistory [11][64] = {0}; -int chatHistoryFade [11] = {0}; -int chatHistoryIndex = 0; +int BUFFER_HALF_W = BUFFER_W / 2; +int BUFFER_HALF_H = BUFFER_H / 2; +int WINDOW_W = BUFFER_W * BUFFER_SCALE; +int WINDOW_H = BUFFER_H * BUFFER_SCALE; + +char chatHistory[11][64] = {0}; +int chatHistoryFade[11] = {0}; +int chatHistoryIndex = 0; + /* strnum * Takes in a char array and an offset and puts the specified * number into it. Make sure there is sufficient space in the * string. */ -void strnum (char *ptr, int offset, int num) { - sprintf(ptr + offset, "%d", num); +void strnum(char *ptr, int offset, int num) +{ + sprintf(ptr + offset, "%d", num); } + /* drawChar * Takes in a pointer to a renderer, a character (as an int), * draws it at the specified x and y coordinates, and then returns * the character's width. */ -int drawChar (SDL_Renderer *renderer,int c, int x, int y) { - for (int yy = 0; yy < 8; yy++) { - for (int xx = 0; xx < 8; xx++) { - if ((font[c][yy] >> (7 - xx)) & 0x1) { - SDL_RenderDrawPoint(renderer, x + xx, y + yy); - } - } +int drawChar(SDL_Renderer *renderer, int c, int x, int y) +{ + for (int yy = 0; yy < 8; yy++) + { + for (int xx = 0; xx < 8; xx++) + { + if ((font[c][yy] >> (7 - xx)) & 0x1) + { + SDL_RenderDrawPoint(renderer, x + xx, y + yy); + } } + } - return font[c][8]; + return font[c][8]; } + /* drawStr * Takes in a pointer to a renderer, a string, draws it at the * specified x and y coordinates, and then returns the x position * it left off on. */ -int drawStr (SDL_Renderer *renderer, const char *str, int x, int y) { - while (*str > 0) { - x += drawChar(renderer, *(str++), x, y); - } - return x; +int drawStr(SDL_Renderer *renderer, const char *str, int x, int y) +{ + while (*str > 0) + { + x += drawChar(renderer, *(str++), x, y); + } + return x; } + /* shadowStr * Identical to drawStr, but draws white text with a grey shadow. */ -int shadowStr (SDL_Renderer *renderer, const char *str, int x, int y) { - SDL_SetRenderDrawColor(renderer, 77, 77, 77, 255); - drawStr(renderer, str, x + 1, y + 1); - white(renderer); - return drawStr(renderer, str, x, y); +int shadowStr(SDL_Renderer *renderer, const char *str, int x, int y) +{ + SDL_SetRenderDrawColor(renderer, 77, 77, 77, 255); + drawStr(renderer, str, x + 1, y + 1); + white(renderer); + return drawStr(renderer, str, x, y); } + /* centerStr * Identical to drawStr, but centers the text */ -int centerStr (SDL_Renderer *renderer, const char *str, int x, int y) { - x *= 2; - int i = 0; - while (str[i] > 0) { - x -= font[(int)str[i++]][8]; - } +int centerStr(SDL_Renderer *renderer, const char *str, int x, int y) +{ + x *= 2; + int i = 0; + while (str[i] > 0) + { + x -= font[(int)str[i++]][8]; + } - x /= 2; - i = 0; - while(str[i] > 0) { - x += drawChar(renderer, str[i++], x, y); - } + x /= 2; + i = 0; + while (str[i] > 0) + { + x += drawChar(renderer, str[i++], x, y); + } - return x; + return x; } + /* shadowStr * Identical to centerStr, but draws white text with a grey shadow. */ -int shadowCenterStr (SDL_Renderer *renderer, const char *str, int x, int y) { - SDL_SetRenderDrawColor(renderer, 77, 77, 77, 255); - centerStr(renderer, str, x + 1, y + 1); - white(renderer); - return centerStr(renderer, str, x, y); +int shadowCenterStr(SDL_Renderer *renderer, const char *str, int x, int y) +{ + SDL_SetRenderDrawColor(renderer, 77, 77, 77, 255); + centerStr(renderer, str, x + 1, y + 1); + white(renderer); + return centerStr(renderer, str, x, y); } + /* drawBig * Draws centered text at a large scale */ -int drawBig (SDL_Renderer *renderer, const char *str, int x, int y) { - int i = 0; - while (str[i] > 0) - x -= font[(int)str[i++]][8]; +int drawBig(SDL_Renderer *renderer, const char *str, int x, int y) +{ + int i = 0; + while (str[i] > 0) + x -= font[(int)str[i++]][8]; - i = 0; - while (str[i] > 0) { - int c = str[i++]; - for (int yy = 0; yy < 16; yy++) { - for (int xx = 0; xx < 16; xx++) { - if ((font[c][yy / 2] >> (7 - xx / 2)) & 0x1) { - SDL_RenderDrawPoint ( - renderer, - x + xx, - y + yy - ); - } - } + i = 0; + while (str[i] > 0) + { + int c = str[i++]; + for (int yy = 0; yy < 16; yy++) + { + for (int xx = 0; xx < 16; xx++) + { + if ((font[c][yy / 2] >> (7 - xx / 2)) & 0x1) + { + SDL_RenderDrawPoint( + renderer, + x + xx, + y + yy); } - - x += font[c][8] * 2; + } } - return x; + x += font[c][8] * 2; + } + + return x; } + /* drawBGStr * Like drawStr, but also draws a semitransparent background * behind the text. */ -int drawBGStr ( - SDL_Renderer *renderer, - const char *str, int x, int y -) { - static int len; - static SDL_Rect bg = {0, 0, 0, 9}; +int drawBGStr(SDL_Renderer *renderer, const char *str, int x, int y) +{ + static int len; + static SDL_Rect bg = {0, 0, 0, 9}; - int i = 0; - len = 0; - while(str[i] > 0) { - len += font[(int)str[i++]][8]; - } - - bg.x = x; - bg.y = y; - bg.w = len + 1; + int i = 0; + len = 0; + while (str[i] > 0) + { + len += font[(int)str[i++]][8]; + } - tblack(renderer); - SDL_RenderFillRect(renderer, &bg); + bg.x = x; + bg.y = y; + bg.w = len + 1; - white(renderer); - return drawStr(renderer, str, ++x, ++y); + tblack(renderer); + SDL_RenderFillRect(renderer, &bg); + + white(renderer); + return drawStr(renderer, str, ++x, ++y); } + /* button * Takes in a pointer to a renderer, a string, draws a button with * the specified x and y coordinates and width, and then returns * wether or not the specified mouse coordinates are within it. */ -int button ( - SDL_Renderer *renderer, - const char *str, - int x, int y, int w, - int mouseX, int mouseY -) { - int hover = mouseX >= x && - mouseY >= y && - mouseX < x + w && - mouseY < y + 16 ; +int button( + SDL_Renderer *renderer, + const char *str, + int x, int y, int w, + int mouseX, int mouseY) +{ + int hover = mouseX >= x && + mouseY >= y && + mouseX < x + w && + mouseY < y + 16; - SDL_Rect rect; - rect.x = x; - rect.y = y; - rect.w = w; - rect.h = 16; + SDL_Rect rect; + rect.x = x; + rect.y = y; + rect.w = w; + rect.h = 16; - if (hover) { - SDL_SetRenderDrawColor(renderer, 116, 134, 230, 255); - } else { - SDL_SetRenderDrawColor(renderer, 139, 139, 139, 255); - } - SDL_RenderFillRect(renderer, &rect); + if (hover) + { + SDL_SetRenderDrawColor(renderer, 116, 134, 230, 255); + } + else + { + SDL_SetRenderDrawColor(renderer, 139, 139, 139, 255); + } + SDL_RenderFillRect(renderer, &rect); - x += w / 2 + 1; - y += 5; + x += w / 2 + 1; + y += 5; - if (hover) { - SDL_SetRenderDrawColor(renderer, 63, 63, 40, 255); - } else { - SDL_SetRenderDrawColor(renderer, 56, 56, 56, 255); - } - centerStr(renderer, str, x, y); + if (hover) + { + SDL_SetRenderDrawColor(renderer, 63, 63, 40, 255); + } + else + { + SDL_SetRenderDrawColor(renderer, 56, 56, 56, 255); + } + centerStr(renderer, str, x, y); - x--; - y--; + x--; + y--; - if (hover) { - SDL_SetRenderDrawColor(renderer, 255, 255, 160, 255); - } else { - white(renderer); - } - centerStr(renderer, str, x, y); + if (hover) + { + SDL_SetRenderDrawColor(renderer, 255, 255, 160, 255); + } + else + { + white(renderer); + } + centerStr(renderer, str, x, y); - if (hover) { - white(renderer); - } else { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - } - SDL_RenderDrawRect(renderer, &rect); + if (hover) + { + white(renderer); + } + else + { + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + } + SDL_RenderDrawRect(renderer, &rect); - return hover; + return hover; } + /* input * Draws a simple text input. Draws the string in buffer. If buffer is empty, * the placeholder text is drawn instead (but in a darker color). Returns * whether or not the mouse is inside of the input. */ -int input ( - SDL_Renderer *renderer, - const char *placeholder, - const char *buffer, - int x, int y, int w, - int mouseX, int mouseY, - int active -) { - static int flash = 0; +int input( + SDL_Renderer *renderer, + const char *placeholder, + const char *buffer, + int x, int y, int w, + int mouseX, int mouseY, + int active) +{ + static int flash = 0; - int hover = mouseX >= x && - mouseY >= y && - mouseX < x + w && - mouseY < y + 16 ; + int hover = mouseX >= x && + mouseY >= y && + mouseX < x + w && + mouseY < y + 16; - SDL_Rect rect; - rect.x = x; - rect.y = y; - rect.w = w; - rect.h = 16; + SDL_Rect rect; + rect.x = x; + rect.y = y; + rect.w = w; + rect.h = 16; - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderFillRect(renderer, &rect); - - if (hover || active) { - white(renderer); - } else { - SDL_SetRenderDrawColor(renderer, 139, 139, 139, 255); - } - SDL_RenderDrawRect(renderer, &rect); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderFillRect(renderer, &rect); - int textX = x + 4; - if (buffer[0] != 0) { - white(renderer); - textX = drawStr(renderer, buffer, x + 4, y + 4); - } else { - SDL_SetRenderDrawColor(renderer, 63, 63, 63, 255); - drawStr(renderer, placeholder, x + 4, y + 4); - } + if (hover || active) + { + white(renderer); + } + else + { + SDL_SetRenderDrawColor(renderer, 139, 139, 139, 255); + } + SDL_RenderDrawRect(renderer, &rect); - if (flash < 32 && active) { - white(renderer); - drawChar(renderer, '_', textX, y + 4); - } + int textX = x + 4; + if (buffer[0] != 0) + { + white(renderer); + textX = drawStr(renderer, buffer, x + 4, y + 4); + } + else + { + SDL_SetRenderDrawColor(renderer, 63, 63, 63, 255); + drawStr(renderer, placeholder, x + 4, y + 4); + } - flash ++; - flash %= 64; + if (flash < 32 && active) + { + white(renderer); + drawChar(renderer, '_', textX, y + 4); + } - return hover; + flash++; + flash %= 64; + + return hover; } + /* scrollbar * Draws a scrollbar of the specified length at the specified coordinates. * Able to modify the level value when the user interacts with it. */ -void scrollbar ( - SDL_Renderer *renderer, - int x, int y, int length, - int mouseX, int mouseY, - int mouseLeft, - int *level, int max -) { - float sectionLength = (float)length / (float)max; +void scrollbar( + SDL_Renderer *renderer, + int x, int y, int length, + int mouseX, int mouseY, + int mouseLeft, + int *level, int max) +{ + float sectionLength = (float)length / (float)max; - SDL_Rect background = { - .x = x, - .y = y, - .w = 4, - .h = length - }; + SDL_Rect background = { + .x = x, + .y = y, + .w = 4, + .h = length}; - SDL_Rect foreground = { - .x = x, - .y = (float)*level * sectionLength, - .w = 4, - .h = ceil(sectionLength) - }; + SDL_Rect foreground = { + .x = x, + .y = (float)*level * sectionLength, + .w = 4, + .h = ceil(sectionLength)}; - int hover = mouseX >= background.x && - mouseY >= background.y && - mouseX < background.x + background.w && - mouseY < background.y + background.h; + int hover = mouseX >= background.x && + mouseY >= background.y && + mouseX < background.x + background.w && + mouseY < background.y + background.h; - if (hover && mouseLeft) { - *level = (mouseY - background.y) / sectionLength; - } + if (hover && mouseLeft) + { + *level = (mouseY - background.y) / sectionLength; + } - tblack(renderer); - SDL_RenderFillRect(renderer, &background); - SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255); - SDL_RenderFillRect(renderer, &foreground); - SDL_SetRenderDrawColor(renderer, 139, 139, 139, 255); - SDL_RenderDrawLine ( - renderer, - foreground.x + foreground.w - 1, - foreground.y, - foreground.x + foreground.w - 1, - foreground.y + foreground.h - 1); + tblack(renderer); + SDL_RenderFillRect(renderer, &background); + SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255); + SDL_RenderFillRect(renderer, &foreground); + SDL_SetRenderDrawColor(renderer, 139, 139, 139, 255); + SDL_RenderDrawLine( + renderer, + foreground.x + foreground.w - 1, + foreground.y, + foreground.x + foreground.w - 1, + foreground.y + foreground.h - 1); } + /* drawSlot * Takes in a pointer to a renderer, an InvSlot, draws the item - * with the specified x and y coordinates and width, and then + * with the specified x and y coordinates and width, and then * returns wether or not the specified mouse coordinates are * within it. */ -int drawSlot ( - SDL_Renderer *renderer, - InvSlot *slot, int x, int y, int mouseX, int mouseY -) { - int hover, - i, - xx, - yy, - color; +int drawSlot(SDL_Renderer *renderer, InvSlot *slot, int x, int y, int mouseX, int mouseY) +{ + int hover, + i, + xx, + yy, + color; - char count[4]; + char count[4]; - hover = mouseX >= x && - mouseY >= y && - mouseX < x + 16 && - mouseY < y + 16 ; - - if (slot->amount == 0) { return hover; } - - i = slot->blockid * 256 * 3; - for (yy = 0; yy < 16; yy++) { - for (xx = 0; xx < 16; xx++) { - color = textures[i + BLOCK_TEXTURE_H * BLOCK_TEXTURE_W]; - SDL_SetRenderDrawColor( - renderer, - (color >> 16 & 0xFF), - (color >> 8 & 0xFF), - (color & 0xFF), - 255 - ); - if (color > 0) { - SDL_RenderDrawPoint(renderer, x + xx, y + yy); - } - i++; - } - } - - strnum(count, 0, slot->amount); - shadowStr(renderer, count, x + (slot->amount >= 10 ? 4 : 10), y + 8); + hover = mouseX >= x && + mouseY >= y && + mouseX < x + 16 && + mouseY < y + 16; + if (slot->amount == 0) + { return hover; + } + + i = slot->blockid * 256 * 3; + for (yy = 0; yy < 16; yy++) + { + for (xx = 0; xx < 16; xx++) + { + color = textures[i + BLOCK_TEXTURE_H * BLOCK_TEXTURE_W]; + SDL_SetRenderDrawColor( + renderer, + (color >> 16 & 0xFF), + (color >> 8 & 0xFF), + (color & 0xFF), + 255); + if (color > 0) + { + SDL_RenderDrawPoint(renderer, x + xx, y + yy); + } + i++; + } + } + + strnum(count, 0, slot->amount); + shadowStr(renderer, count, x + (slot->amount >= 10 ? 4 : 10), y + 8); + + return hover; } + /* drawWorldListItem * Draws a world list item and reurns whether the mouse is inside of it or one * of its buttons. */ -int drawWorldListItem ( - SDL_Renderer *renderer, data_WorldListItem *item, - int x, int y, int mouseX, int mouseY -) { - int hover; - - hover = mouseX >= x && - mouseY >= y && - mouseX < x + 128 && - mouseY < y + 16 ; +int drawWorldListItem(SDL_Renderer *renderer, data_WorldListItem *item, int x, int y, int mouseX, int mouseY) +{ + int hover; - SDL_Rect rect; - rect.x = x - 1; - rect.y = y - 1; - rect.w = 130; - rect.h = 18; + hover = mouseX >= x && + mouseY >= y && + mouseX < x + 128 && + mouseY < y + 16; - SDL_Rect thumbnailShadow; - thumbnailShadow.x = x + 1; - thumbnailShadow.y = y + 1; - thumbnailShadow.w = 16; - thumbnailShadow.h = 16; + SDL_Rect rect; + rect.x = x - 1; + rect.y = y - 1; + rect.w = 130; + rect.h = 18; - tblack(renderer); - SDL_RenderFillRect(renderer, &thumbnailShadow); - - int *pixel = item->thumbnail.buffer; - for (int yy = 0; yy < 16; yy++) { - for (int xx = 0; xx < 16; xx++) { - SDL_SetRenderDrawColor ( - renderer, - (*pixel >> 16 & 0xFF), - (*pixel >> 8 & 0xFF), - (*pixel & 0xFF), - 255 - ); - SDL_RenderDrawPoint(renderer, x + xx, y + yy); - pixel ++; - } + SDL_Rect thumbnailShadow; + thumbnailShadow.x = x + 1; + thumbnailShadow.y = y + 1; + thumbnailShadow.w = 16; + thumbnailShadow.h = 16; + + tblack(renderer); + SDL_RenderFillRect(renderer, &thumbnailShadow); + + int *pixel = item->thumbnail.buffer; + for (int yy = 0; yy < 16; yy++) + { + for (int xx = 0; xx < 16; xx++) + { + SDL_SetRenderDrawColor( + renderer, + (*pixel >> 16 & 0xFF), + (*pixel >> 8 & 0xFF), + (*pixel & 0xFF), + 255); + SDL_RenderDrawPoint(renderer, x + xx, y + yy); + pixel++; } + } - shadowStr(renderer, item->name, x + 20, y + 4); + shadowStr(renderer, item->name, x + 20, y + 4); - if (button(renderer, "x", - x + 128 - 16, y, 16, - mouseX, mouseY) - ) { - hover = 2; - } + if (button(renderer, "x", + x + 128 - 16, y, 16, + mouseX, mouseY)) + { + hover = 2; + } - if (hover == 1) { - white(renderer); - SDL_RenderDrawRect(renderer, &rect); - } + if (hover == 1) + { + white(renderer); + SDL_RenderDrawRect(renderer, &rect); + } - return hover; + return hover; } + /* dirtBg * Draws a dirt textured background */ -void dirtBg (SDL_Renderer *renderer) { - int color; - for (int y = 0; y < BUFFER_H; y++) { - for (int x = 0; x < BUFFER_W; x++) { - color = textures [ - (x & 0xF) + - (y & 0xF) * 16 + - BLOCK_DIRT * 256 * 3 - ]; - - SDL_SetRenderDrawColor( - renderer, - (color >> 16 & 0xFF) >> 1, - (color >> 8 & 0xFF) >> 1, - (color & 0xFF) >> 1, - 255 - ); - - SDL_RenderDrawPoint(renderer, x, y); - } +void dirtBg(SDL_Renderer *renderer) +{ + int color; + for (int y = 0; y < BUFFER_H; y++) + { + for (int x = 0; x < BUFFER_W; x++) + { + color = textures[(x & 0xF) + + (y & 0xF) * 16 + + BLOCK_DIRT * 256 * 3]; + + SDL_SetRenderDrawColor( + renderer, + (color >> 16 & 0xFF) >> 1, + (color >> 8 & 0xFF) >> 1, + (color & 0xFF) >> 1, + 255); + + SDL_RenderDrawPoint(renderer, x, y); } + } } + /* loadScreen * Draws a loading screen */ -void loadScreen ( - SDL_Renderer *renderer, - const char *str, - float prog, float max -) { - dirtBg(renderer); +void loadScreen( + SDL_Renderer *renderer, + const char *str, + float prog, float max) +{ + dirtBg(renderer); - shadowCenterStr(renderer, str, BUFFER_HALF_W, BUFFER_HALF_H - 8); + shadowCenterStr(renderer, str, BUFFER_HALF_W, BUFFER_HALF_H - 8); - SDL_SetRenderDrawColor(renderer, 77, 77, 77, 255); - SDL_RenderDrawLine ( - renderer, - BUFFER_HALF_W - 32, - BUFFER_HALF_H + 6, - BUFFER_HALF_W + 32, - BUFFER_HALF_H + 6 - ); + SDL_SetRenderDrawColor(renderer, 77, 77, 77, 255); + SDL_RenderDrawLine( + renderer, + BUFFER_HALF_W - 32, + BUFFER_HALF_H + 6, + BUFFER_HALF_W + 32, + BUFFER_HALF_H + 6); - SDL_SetRenderDrawColor(renderer, 132, 255, 132, 255); - SDL_RenderDrawLine ( - renderer, - BUFFER_HALF_W - 32, - BUFFER_HALF_H + 6, - BUFFER_HALF_W - 32 + (prog / max) * 64, - BUFFER_HALF_H + 6 - ); + SDL_SetRenderDrawColor(renderer, 132, 255, 132, 255); + SDL_RenderDrawLine( + renderer, + BUFFER_HALF_W - 32, + BUFFER_HALF_H + 6, + BUFFER_HALF_W - 32 + (prog / max) * 64, + BUFFER_HALF_H + 6); } + /* chatAdd * Adds a message to chat */ -void chatAdd (const char *str) { - chatHistoryFade[chatHistoryIndex] = 480; - memcpy ( - chatHistory[(chatHistoryIndex)++], - str, sizeof(char) * 64 - ); - chatHistoryIndex = nmod(chatHistoryIndex, 11); +void chatAdd(const char *str) +{ + chatHistoryFade[chatHistoryIndex] = 480; + memcpy( + chatHistory[(chatHistoryIndex)++], + str, sizeof(char) * 64); + chatHistoryIndex = nmod(chatHistoryIndex, 11); } + /* white * Sets the render color to white */ -void white (SDL_Renderer *renderer) { - SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); +void white(SDL_Renderer *renderer) +{ + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); } + /* tblack * Sets the render color to transparent black */ -void tblack (SDL_Renderer *renderer) { +void tblack(SDL_Renderer *renderer) +{ + #ifdef _KOLIBRI + SDL_SetRenderDrawColor(renderer, 15, 15, 15, 255); + #else SDL_SetRenderDrawColor(renderer, 0, 0, 0, 128); + #endif } diff --git a/src/gui.h b/src/gui.h index 1c8d860..7495bc4 100644 --- a/src/gui.h +++ b/src/gui.h @@ -10,6 +10,10 @@ #include "main.h" #include "data.h" +#define BUFFER_W 200 +#define BUFFER_H 150 +#define BUFFER_SCALE 4 + void strnum (char *, int, int); int drawChar (SDL_Renderer *, int, int, int); int drawStr (SDL_Renderer *, const char *, int, int); @@ -32,13 +36,10 @@ void chatAdd (const char*); void white (SDL_Renderer *); void tblack (SDL_Renderer *); -extern const int BUFFER_W; -extern const int BUFFER_H; -extern const int BUFFER_SCALE; -extern const int BUFFER_HALF_W; -extern const int BUFFER_HALF_H; -extern const int WINDOW_W; -extern const int WINDOW_H; +extern int BUFFER_HALF_W; +extern int BUFFER_HALF_H; +extern int WINDOW_W; +extern int WINDOW_H; extern char chatHistory [11][64]; extern int chatHistoryFade [11]; diff --git a/src/inputbuffer.c b/src/inputbuffer.c index 4dc5b03..860bcf1 100644 --- a/src/inputbuffer.c +++ b/src/inputbuffer.c @@ -1,25 +1,37 @@ #include "inputbuffer.h" + /* manageInputBuffer * Applies keyboard input to a text input buffer. Returns 1 if the enter key was * pressed (there must be content in buffer) */ -int manageInputBuffer (InputBuffer *inputBuffer, Inputs *inputs) { - if (!inputs->keyTyped && !inputs->keySym) { return 0; } - - if (inputs->keySym == SDLK_BACKSPACE) { +int manageInputBuffer(InputBuffer *inputBuffer, Inputs *inputs) +{ + if (!inputs->keyTyped && !inputs->keySym) + { + return 0; + } + + // printf("Typed key: %d\n", inputs->keyTyped); + + if (inputs->keySym == SDLK_BACKSPACE) + { // Delete last char and decrement cursor // position - if (inputBuffer->cursor > 0) { - inputBuffer->buffer[-- inputBuffer->cursor] = 0; + if (inputBuffer->cursor > 0) + { + inputBuffer->buffer[--inputBuffer->cursor] = 0; } - } else if (inputs->keySym == SDLK_RETURN && inputBuffer->cursor > 0) { + } + else if (inputs->keySym == SDLK_RETURN && inputBuffer->cursor > 0) + { return 1; - } else if ( - inputs->keyTyped > 31 && - inputs->keyTyped < 127 && - inputBuffer->cursor < inputBuffer->len - 1 - ) { + } + else if ( + inputs->keyTyped > 31 && + inputs->keyTyped < 127 && + inputBuffer->cursor < inputBuffer->len - 1) + { inputBuffer->buffer[inputBuffer->cursor] = inputs->keyTyped; inputBuffer->cursor += 1; inputBuffer->buffer[inputBuffer->cursor] = 0; diff --git a/src/main.c b/src/main.c index c018b44..dc5f9c0 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "textures.h" #include "gameloop.h" #include "options.h" @@ -10,208 +11,340 @@ #include "main.h" #include "gui.h" -/* Minecraft 4k, C edition. Version 0.7 - * + +/* Minecraft 4k, C edition. Version 0.8.0 KolibriOS + * * Credits: * notch - creating the original game * sashakoshka - C port, modifications * samsebe - deciphering the meaning of some of the code * gracie bell - daylight function * https://gist.github.com/nowl/828013 - perlin noise - * + * * ... & contributors on github! * https://github.com/sashakoshka/m4kc/graphs/contributors - * + * * If you distribute a modified copy of this, just include this * notice. */ - + + #define MAX_FPS 60 #define MIN_FRAME_MILLISECONDS 1000 / MAX_FPS + static int controlLoop(Inputs *, const uint8_t *); static int handleEvent(Inputs *, const uint8_t *, SDL_Event); -int main (int argc, char *argv[]) { - (void)(argc); - (void)(argv); - //---- initializing SDL ----// +int main(int argc, char *argv[]) +{ + (void)(argc); + (void)(argv); - SDL_Window *window = NULL; - SDL_Renderer *renderer = NULL; - const uint8_t *keyboard = SDL_GetKeyboardState(NULL); + //---- initializing SDL ----// - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - printf("cant make window\n"); - goto exit; - } + SDL_Window *window = NULL; + SDL_Renderer *renderer = NULL; + const uint8_t *keyboard = SDL_GetKeyboardState(NULL); - window = SDL_CreateWindow ("M4KC", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - WINDOW_W, WINDOW_H, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - printf("%s\n", SDL_GetError()); - goto exit; - } + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + printf("cant make window\n"); + goto exit; + } - renderer = SDL_CreateRenderer ( - window, - -1, SDL_RENDERER_ACCELERATED - ); - if (renderer == NULL) { - printf("%s\n", SDL_GetError()); - goto exit; - } - SDL_RenderSetScale(renderer, BUFFER_SCALE, BUFFER_SCALE); + window = SDL_CreateWindow( + "M4KC 0.8.0 KOLIBRI", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + WINDOW_W, WINDOW_H, + SDL_WINDOW_SHOWN); + if (window == NULL) + { + printf("%s\n", SDL_GetError()); + goto exit; + } + + #ifdef _KOLIBRI + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE | SDL_RENDERER_PRESENTVSYNC); + #else + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + #endif + + if (renderer == NULL) + { + printf("%s\n", SDL_GetError()); + goto exit; + } + + SDL_RenderSetScale(renderer, BUFFER_SCALE, BUFFER_SCALE); + + #ifndef _KOLIBRI SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + #endif - //--- initializing modules ---// - - int err = 0; - - err = data_init(); - if (err) { - gameLoop_error("Cannot initialize data module."); + //--- initializing modules ---// + + int err = 0; + + err = data_init(); + if (err) + { + gameLoop_error("Cannot initialize data module."); + } + + err = options_init(); + if (err) + { + gameLoop_error("Cannot initialize options module."); + } + + //---- generating assets ----// + + genTextures(45390874); + + //---- main game loop ----// + + Inputs inputs = {0}; + int running = 1; + while (running) + { + uint32_t frameStartTime = SDL_GetTicks(); + + running &= controlLoop(&inputs, keyboard); + running &= gameLoop(&inputs, renderer); + SDL_RenderPresent(renderer); + // SDL_UpdateWindowSurface(window); + + // Clean up input struct + inputs.keyTyped = 0; + inputs.keySym = 0; + + // Limit FPS + uint32_t frameDuration = SDL_GetTicks() - frameStartTime; + if (frameDuration < MIN_FRAME_MILLISECONDS) + { + SDL_Delay(MIN_FRAME_MILLISECONDS - frameDuration); } - - err = options_init(); - if (err) { - gameLoop_error("Cannot initialize options module."); + } + +exit: + SDL_Quit(); + return 0; +} + + +static int controlLoop(Inputs *inputs, const Uint8 *keyboard) +{ + SDL_PumpEvents(); + int mouseX = 0, mouseY = 0; + SDL_GetMouseState(&mouseX, &mouseY); + + // Detect movement controls + inputs->keyboard.space = keyboard[SDL_SCANCODE_SPACE]; + inputs->keyboard.w = keyboard[SDL_SCANCODE_W]; + inputs->keyboard.s = keyboard[SDL_SCANCODE_S]; + inputs->keyboard.a = keyboard[SDL_SCANCODE_A]; + inputs->keyboard.d = keyboard[SDL_SCANCODE_D]; + + if (!SDL_GetRelativeMouseMode()) + { + inputs->mouse.x = mouseX; + inputs->mouse.y = mouseY; + } + + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if (!handleEvent(inputs, keyboard, event)) + { + return 0; } + } - //---- generating assets ----// + return 1; +} - genTextures(45390874); - //---- main game loop ----// +static char scancodeToChar(SDL_Scancode scancode, int shiftPressed) +{ + // Basic mapping from scancodes to characters + switch (scancode) + { + case SDL_SCANCODE_A: + return shiftPressed ? 'A' : 'a'; + case SDL_SCANCODE_B: + return shiftPressed ? 'B' : 'b'; + case SDL_SCANCODE_C: + return shiftPressed ? 'C' : 'c'; + case SDL_SCANCODE_D: + return shiftPressed ? 'D' : 'd'; + case SDL_SCANCODE_E: + return shiftPressed ? 'E' : 'e'; + case SDL_SCANCODE_F: + return shiftPressed ? 'F' : 'f'; + case SDL_SCANCODE_G: + return shiftPressed ? 'G' : 'g'; + case SDL_SCANCODE_H: + return shiftPressed ? 'H' : 'h'; + case SDL_SCANCODE_I: + return shiftPressed ? 'I' : 'i'; + case SDL_SCANCODE_J: + return shiftPressed ? 'J' : 'j'; + case SDL_SCANCODE_K: + return shiftPressed ? 'K' : 'k'; + case SDL_SCANCODE_L: + return shiftPressed ? 'L' : 'l'; + case SDL_SCANCODE_M: + return shiftPressed ? 'M' : 'm'; + case SDL_SCANCODE_N: + return shiftPressed ? 'N' : 'n'; + case SDL_SCANCODE_O: + return shiftPressed ? 'O' : 'o'; + case SDL_SCANCODE_P: + return shiftPressed ? 'P' : 'p'; + case SDL_SCANCODE_Q: + return shiftPressed ? 'Q' : 'q'; + case SDL_SCANCODE_R: + return shiftPressed ? 'R' : 'r'; + case SDL_SCANCODE_S: + return shiftPressed ? 'S' : 's'; + case SDL_SCANCODE_T: + return shiftPressed ? 'T' : 't'; + case SDL_SCANCODE_U: + return shiftPressed ? 'U' : 'u'; + case SDL_SCANCODE_V: + return shiftPressed ? 'V' : 'v'; + case SDL_SCANCODE_W: + return shiftPressed ? 'W' : 'w'; + case SDL_SCANCODE_X: + return shiftPressed ? 'X' : 'x'; + case SDL_SCANCODE_Y: + return shiftPressed ? 'Y' : 'y'; + case SDL_SCANCODE_Z: + return shiftPressed ? 'Z' : 'z'; - Inputs inputs = {0}; - int running = 1; - while (running) { - uint32_t frameStartTime = SDL_GetTicks(); - - running &= controlLoop(&inputs, keyboard); - running &= gameLoop(&inputs, renderer); - - SDL_RenderPresent(renderer); - SDL_UpdateWindowSurface(window); + case SDL_SCANCODE_1: + return shiftPressed ? '!' : '1'; + case SDL_SCANCODE_2: + return shiftPressed ? '@' : '2'; + case SDL_SCANCODE_3: + return shiftPressed ? '#' : '3'; + case SDL_SCANCODE_4: + return shiftPressed ? '$' : '4'; + case SDL_SCANCODE_5: + return shiftPressed ? '%' : '5'; + case SDL_SCANCODE_6: + return shiftPressed ? '^' : '6'; + case SDL_SCANCODE_7: + return shiftPressed ? '&' : '7'; + case SDL_SCANCODE_8: + return shiftPressed ? '\0' : '8'; // KolibriOS file can't contain * in name + case SDL_SCANCODE_9: + return shiftPressed ? '(' : '9'; + case SDL_SCANCODE_0: + return shiftPressed ? ')' : '0'; - // Clean up input struct - inputs.keyTyped = 0; - inputs.keySym = 0; + case SDL_SCANCODE_MINUS: + return shiftPressed ? '_' : '-'; + case SDL_SCANCODE_EQUALS: + return shiftPressed ? '+' : '='; - // Limit FPS - uint32_t frameDuration = SDL_GetTicks() - frameStartTime; - if (frameDuration < MIN_FRAME_MILLISECONDS) { - SDL_Delay(MIN_FRAME_MILLISECONDS - frameDuration); - } - } + case SDL_SCANCODE_SPACE: + return ' '; + case SDL_SCANCODE_RETURN: + return '\n'; + case SDL_SCANCODE_BACKSPACE: + return '\b'; + default: + return '\0'; // Unsupported scancodes + } +} - exit: - SDL_Quit(); + +static int handleEvent(Inputs *inputs, const uint8_t *keyboard, SDL_Event event) +{ + switch (event.type) + { + case SDL_QUIT: return 0; -} -static int controlLoop (Inputs *inputs, const Uint8 *keyboard) { - SDL_PumpEvents(); - int mouseX = 0, mouseY = 0; - SDL_GetMouseState(&mouseX, &mouseY); - - // Detect movement controls - inputs->keyboard.space = keyboard[SDL_SCANCODE_SPACE]; - inputs->keyboard.w = keyboard[SDL_SCANCODE_W]; - inputs->keyboard.s = keyboard[SDL_SCANCODE_S]; - inputs->keyboard.a = keyboard[SDL_SCANCODE_A]; - inputs->keyboard.d = keyboard[SDL_SCANCODE_D]; - - if (!SDL_GetRelativeMouseMode()) { - inputs->mouse.x = mouseX; - inputs->mouse.y = mouseY; + case SDL_MOUSEBUTTONDOWN: + switch (event.button.button) + { + case SDL_BUTTON_LEFT: + inputs->mouse.left = 1; + break; + case SDL_BUTTON_RIGHT: + inputs->mouse.right = 1; + break; } + break; - SDL_Event event; - while (SDL_PollEvent(&event)) { - if (!handleEvent(inputs, keyboard, event)) { - return 0; - } + case SDL_MOUSEBUTTONUP: + switch (event.button.button) + { + case SDL_BUTTON_LEFT: + inputs->mouse.left = 0; + break; + case SDL_BUTTON_RIGHT: + inputs->mouse.right = 0; + break; } + break; - return 1; -} + case SDL_KEYDOWN: + inputs->keySym = event.key.keysym.sym; -static int handleEvent (Inputs *inputs, const uint8_t *keyboard, SDL_Event event) { - switch (event.type) { - case SDL_QUIT: - return 0; - - case SDL_MOUSEBUTTONDOWN: - switch (event.button.button) { - case SDL_BUTTON_LEFT: - inputs->mouse.left = 1; - break; - case SDL_BUTTON_RIGHT: - inputs->mouse.right = 1; - break; - } - break; - - case SDL_MOUSEBUTTONUP: - switch (event.button.button) { - case SDL_BUTTON_LEFT: - inputs->mouse.left = 0; - break; - case SDL_BUTTON_RIGHT: - inputs->mouse.right = 0; - break; - } - break; + if (event.key.repeat == 0) + { + // Detect UI hotkeys using scancodes + SDL_Scancode scancode = event.key.keysym.scancode; - case SDL_KEYDOWN: - inputs->keySym = event.key.keysym.sym; - case SDL_KEYUP: - if (event.key.repeat == 0) { - // Detect UI hotkeys - inputs->keyboard.esc = keyboard[SDL_SCANCODE_ESCAPE]; - inputs->keyboard.f1 = keyboard[SDL_SCANCODE_F1]; - inputs->keyboard.f2 = keyboard[SDL_SCANCODE_F2]; - inputs->keyboard.f3 = keyboard[SDL_SCANCODE_F3]; - inputs->keyboard.f4 = keyboard[SDL_SCANCODE_F4]; - inputs->keyboard.e = keyboard[SDL_SCANCODE_E]; - inputs->keyboard.t = keyboard[SDL_SCANCODE_T]; - inputs->keyboard.f = keyboard[SDL_SCANCODE_F]; + int shiftPressed = keyboard[SDL_SCANCODE_LSHIFT] || keyboard[SDL_SCANCODE_RSHIFT]; + char typedChar = scancodeToChar(scancode, shiftPressed); - inputs->keyboard.num0 = keyboard[SDL_SCANCODE_0]; - inputs->keyboard.num1 = keyboard[SDL_SCANCODE_1]; - inputs->keyboard.num2 = keyboard[SDL_SCANCODE_2]; - inputs->keyboard.num3 = keyboard[SDL_SCANCODE_3]; - inputs->keyboard.num4 = keyboard[SDL_SCANCODE_4]; - inputs->keyboard.num5 = keyboard[SDL_SCANCODE_5]; - inputs->keyboard.num6 = keyboard[SDL_SCANCODE_6]; - inputs->keyboard.num7 = keyboard[SDL_SCANCODE_7]; - inputs->keyboard.num8 = keyboard[SDL_SCANCODE_8]; - inputs->keyboard.num9 = keyboard[SDL_SCANCODE_9]; - } - - break; + if (typedChar != '\0') + { + inputs->keyTyped = (int)typedChar; // Store the character as int + // printf("Typed char: %c", typedChar); + } - case SDL_MOUSEWHEEL: - inputs->mouse.wheel = event.wheel.y; - break; + // Update hotkey states + inputs->keyboard.esc = keyboard[SDL_SCANCODE_ESCAPE]; + inputs->keyboard.f1 = keyboard[SDL_SCANCODE_F1]; + inputs->keyboard.f2 = keyboard[SDL_SCANCODE_F2]; + inputs->keyboard.f3 = keyboard[SDL_SCANCODE_F3]; + inputs->keyboard.f4 = keyboard[SDL_SCANCODE_F4]; + inputs->keyboard.e = keyboard[SDL_SCANCODE_E]; + inputs->keyboard.t = keyboard[SDL_SCANCODE_T]; + inputs->keyboard.f = keyboard[SDL_SCANCODE_F]; - case SDL_MOUSEMOTION: - if (SDL_GetRelativeMouseMode()) { - inputs->mouse.x = event.motion.xrel; - inputs->mouse.y = event.motion.yrel; - } - break; - - case SDL_TEXTINPUT: - inputs->keyTyped = event.text.text[0]; - break; + inputs->keyboard.num0 = keyboard[SDL_SCANCODE_0]; + inputs->keyboard.num1 = keyboard[SDL_SCANCODE_1]; + inputs->keyboard.num2 = keyboard[SDL_SCANCODE_2]; + inputs->keyboard.num3 = keyboard[SDL_SCANCODE_3]; + inputs->keyboard.num4 = keyboard[SDL_SCANCODE_4]; + inputs->keyboard.num5 = keyboard[SDL_SCANCODE_5]; + inputs->keyboard.num6 = keyboard[SDL_SCANCODE_6]; + inputs->keyboard.num7 = keyboard[SDL_SCANCODE_7]; + inputs->keyboard.num8 = keyboard[SDL_SCANCODE_8]; + inputs->keyboard.num9 = keyboard[SDL_SCANCODE_9]; } + break; - return 1; + case SDL_MOUSEWHEEL: + inputs->mouse.wheel = event.wheel.y; + break; + + case SDL_MOUSEMOTION: + if (SDL_GetRelativeMouseMode()) + { + inputs->mouse.x = event.motion.xrel; + inputs->mouse.y = event.motion.yrel; + } + break; + } + + return 1; } diff --git a/src/menus.c b/src/menus.c index 9cf5a8f..c2e5932 100644 --- a/src/menus.c +++ b/src/menus.c @@ -5,448 +5,496 @@ #include "options.h" #include "gameloop.h" -static int menu_optionsMain (SDL_Renderer *, Inputs *); + +static int menu_optionsMain(SDL_Renderer *, Inputs *); + /* === GAME STATES === */ + /* state_title * Presents a title screen with basic options. Is capable of changing the game * state. */ -int state_title (SDL_Renderer *renderer, Inputs *inputs, int *gameState) { - inputs->mouse.x /= BUFFER_SCALE; - inputs->mouse.y /= BUFFER_SCALE; +int state_title(SDL_Renderer *renderer, Inputs *inputs, int *gameState) +{ + inputs->mouse.x /= BUFFER_SCALE; + inputs->mouse.y /= BUFFER_SCALE; - dirtBg(renderer); - white(renderer); - drawBig ( - renderer, - "M4KC", - BUFFER_HALF_W, - 16 - ); + dirtBg(renderer); + white(renderer); + drawBig( + renderer, + "M4KC", + BUFFER_HALF_W, + 16); - #ifdef small - shadowStr(renderer, "version 0.7", 1, BUFFER_H - 9); - #else - shadowStr(renderer, "version 0.7 (dev build)", 1, BUFFER_H - 9); - #endif + #ifdef small + shadowStr(renderer, "version 0.8.0 kolibri", 1, BUFFER_H - 9); + #else + shadowStr(renderer, "version 0.8.0 kolibri (dev build)", 1, BUFFER_H - 9); + #endif - if (button(renderer, "Singleplayer", - BUFFER_HALF_W - 64, 42, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - if (data_refreshWorldList()) { - gameLoop_error("Cannot refresh world list"); - } else { - *gameState = STATE_SELECT_WORLD; - } + if (button(renderer, "Singleplayer", + BUFFER_HALF_W - 64, 42, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + if (data_refreshWorldList()) + { + gameLoop_error("Cannot refresh world list"); } - - if (button(renderer, "Options", - BUFFER_HALF_W - 64, 64, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gameState = STATE_OPTIONS; + else + { + *gameState = STATE_SELECT_WORLD; } + } - if (button(renderer, "Quit Game", - BUFFER_HALF_W - 64, 86, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - return 1; - } + if (button(renderer, "Options", + BUFFER_HALF_W - 64, 64, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gameState = STATE_OPTIONS; + } - return 0; + if (button(renderer, "Quit Game", + BUFFER_HALF_W - 64, 86, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + return 1; + } + + return 0; } -void state_selectWorld ( - SDL_Renderer *renderer, - Inputs *inputs, - int *gameState, - World *world -) { - static int scroll = 0; - int needRefresh = 0; - if (inputs->mouse.wheel != 0) { - scroll -= inputs->mouse.wheel; - inputs->mouse.wheel = 0; +void state_selectWorld( + SDL_Renderer *renderer, + Inputs *inputs, + int *gameState, + World *world) +{ + static int scroll = 0; + int needRefresh = 0; + + if (inputs->mouse.wheel != 0) + { + scroll -= inputs->mouse.wheel; + inputs->mouse.wheel = 0; + } + + if (scroll < 0) + { + scroll = 0; + } + if (scroll > data_worldListLength - 1) + { + scroll = data_worldListLength - 1; + } + + SDL_Rect listBackground; + listBackground.x = 0; + listBackground.y = 0; + listBackground.w = BUFFER_W; + listBackground.h = BUFFER_H - 28; + + inputs->mouse.x /= BUFFER_SCALE; + inputs->mouse.y /= BUFFER_SCALE; + + dirtBg(renderer); + tblack(renderer); + SDL_RenderFillRect(renderer, &listBackground); + SDL_RenderDrawLine(renderer, + 0, BUFFER_H - 29, + BUFFER_W, BUFFER_H - 29); + + int index = 0; + int y = 6; + int yLimit = BUFFER_H - 44; + data_WorldListItem *item = data_worldList; + while (item != NULL) + { + if (y > yLimit) + { + break; + } + if (index < scroll) + { + goto nextItem; } - if (scroll < 0) { scroll = 0; } - if (scroll > data_worldListLength - 1) { - scroll = data_worldListLength - 1; + int hover = drawWorldListItem(renderer, item, + BUFFER_HALF_W - 64, y, + inputs->mouse.x, + inputs->mouse.y); + y += 21; + if (!inputs->mouse.left) + { + goto nextItem; } - SDL_Rect listBackground; - listBackground.x = 0; - listBackground.y = 0; - listBackground.w = BUFFER_W; - listBackground.h = BUFFER_H - 28; - - inputs->mouse.x /= BUFFER_SCALE; - inputs->mouse.y /= BUFFER_SCALE; + switch (hover) + { + case 1: + if (World_load(world, item->name)) + { + gameLoop_error("Could not load world"); + } + else + { + *gameState = STATE_LOADING; + } + return; + case 2:; + char deletePath[PATH_MAX]; + if (data_getWorldPath(deletePath, item->name)) + { + gameLoop_error("Could not delete world"); + return; + } - dirtBg(renderer); - tblack(renderer); - SDL_RenderFillRect (renderer, &listBackground); - SDL_RenderDrawLine (renderer, - 0, BUFFER_H - 29, - BUFFER_W, BUFFER_H - 29); - - int index = 0; - int y = 6; - int yLimit = BUFFER_H - 44; - data_WorldListItem *item = data_worldList; - while (item != NULL) { - if (y > yLimit) { break;} - if (index < scroll) { goto nextItem; } - - int hover = drawWorldListItem(renderer, item, - BUFFER_HALF_W - 64, y, - inputs->mouse.x, - inputs->mouse.y); - y += 21; - if (!inputs->mouse.left) { goto nextItem; } - - switch (hover) { - case 1: - if (World_load(world, item->name)) { - gameLoop_error("Could not load world"); - } else { - *gameState = STATE_LOADING; - } - return; - case 2: - ;char deletePath[PATH_MAX]; - if (data_getWorldPath(deletePath, item->name)) { - gameLoop_error("Could not delete world"); - return; - } - - data_removeDirectory(deletePath); - needRefresh = 1; - - break; - } - - nextItem: - index ++; - item = item->next; + data_removeDirectory(deletePath); + needRefresh = 1; + // TODO Fix call and recursion here + // data_refreshWorldList(); + // state_selectWorld(renderer, inputs, gameState, world); + break; } - if (6 + index * 22 > yLimit) { - scrollbar ( - renderer, - BUFFER_HALF_W + 70, 0, BUFFER_H - 29, - inputs->mouse.x, inputs->mouse.y, inputs->mouse.left, - &scroll, data_worldListLength); - } + nextItem: + index++; + item = item->next; + } - if (index == 0) { - shadowCenterStr (renderer, "No worlds", + if (6 + index * 22 > yLimit) + { + scrollbar( + renderer, + BUFFER_HALF_W + 70, 0, BUFFER_H - 29, + inputs->mouse.x, inputs->mouse.y, inputs->mouse.left, + &scroll, data_worldListLength); + } + + if (index == 0) + { + shadowCenterStr(renderer, "No worlds", BUFFER_HALF_W, BUFFER_HALF_H - 15); - } + } - if (button(renderer, "Cancel", - BUFFER_HALF_W - 64, BUFFER_H - 22, 61, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gameState = STATE_TITLE; - scroll = 0; - } + if (button(renderer, "Cancel", + BUFFER_HALF_W - 64, BUFFER_H - 22, 61, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gameState = STATE_TITLE; + scroll = 0; + } - if (button(renderer, "New", - BUFFER_HALF_W + 3, BUFFER_H - 22, 61, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gameState = STATE_NEW_WORLD; - scroll = 0; - } + if (button(renderer, "New", + BUFFER_HALF_W + 3, BUFFER_H - 22, 61, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gameState = STATE_NEW_WORLD; + scroll = 0; + } - if (needRefresh) { - data_refreshWorldList(); - } + if (needRefresh) + { + data_refreshWorldList(); + } } const char *terrainNames[16] = { - "Classic Terrain", - "Natural Terrain", - "Flat Stone", - "Flat Grass", - "Water World" -}; + "Classic Terrain", + "Natural Terrain", + "Flat Stone", + "Flat Grass", + "Water World"}; const char *dayNightModes[16] = { - "Day and Night", - "Always Day", - "Always Night", + "Day and Night", + "Always Day", + "Always Night", }; /* state_newWorld * Shows a menu with editable parameters for creating a new world. Capable of * editing world prarameters and changing the game state. */ -void state_newWorld ( - SDL_Renderer *renderer, - Inputs *inputs, - int *gameState, - World *world -) { - static int badName = 0; - static int whichInput = 0; +void state_newWorld( + SDL_Renderer *renderer, + Inputs *inputs, + int *gameState, + World *world) +{ + static int badName = 0; + static int whichInput = 0; - static int typeSelect = 1; - static int dayNightSelect = 0; - - static char seedBuffer[16]; - static InputBuffer seedInput = { - .buffer = seedBuffer, - .len = 16, - .cursor = 0 - }; - - static char nameBuffer[16]; - static InputBuffer nameInput = { - .buffer = nameBuffer, - .len = 16, - .cursor = 0 - }; - - inputs->mouse.x /= BUFFER_SCALE; - inputs->mouse.y /= BUFFER_SCALE; + static int typeSelect = 1; + static int dayNightSelect = 0; - dirtBg(renderer); - - if (whichInput == 0) {manageInputBuffer(&nameInput, inputs); } - if (input(renderer, "Name", nameInput.buffer, - BUFFER_HALF_W - 64, 8, 128, - inputs->mouse.x, inputs->mouse.y, whichInput == 0) && - inputs->mouse.left - ) { - whichInput = 0; + static char seedBuffer[16]; + static InputBuffer seedInput = { + .buffer = seedBuffer, + .len = 16, + .cursor = 0}; + + static char nameBuffer[16]; + static InputBuffer nameInput = { + .buffer = nameBuffer, + .len = 16, + .cursor = 0}; + + inputs->mouse.x /= BUFFER_SCALE; + inputs->mouse.y /= BUFFER_SCALE; + + dirtBg(renderer); + + if (whichInput == 0) + { + manageInputBuffer(&nameInput, inputs); + } + if (input(renderer, "Name", nameInput.buffer, + BUFFER_HALF_W - 64, 8, 128, + inputs->mouse.x, inputs->mouse.y, whichInput == 0) && + inputs->mouse.left) + { + whichInput = 0; + } + + if (badName) + { + SDL_SetRenderDrawColor(renderer, 255, 128, 128, 255); + drawChar(renderer, '!', BUFFER_HALF_W + 70, 12); + } + + if (whichInput == 1) + { + manageInputBuffer(&seedInput, inputs); + } + if (input(renderer, "Seed", seedInput.buffer, + BUFFER_HALF_W - 64, 30, 128, + inputs->mouse.x, inputs->mouse.y, whichInput == 1) && + inputs->mouse.left) + { + whichInput = 1; + } + + if (button(renderer, terrainNames[typeSelect], + BUFFER_HALF_W - 64, 52, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + typeSelect = (typeSelect + 1) % 5; + } + + if (button(renderer, dayNightModes[dayNightSelect], + BUFFER_HALF_W - 64, 74, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + dayNightSelect = (dayNightSelect + 1) % 3; + } + + if (button(renderer, "Cancel", + BUFFER_HALF_W - 64, 96, 61, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gameState = STATE_SELECT_WORLD; + } + + if (button(renderer, "Generate", + BUFFER_HALF_W + 3, 96, 61, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + // Reject empty names and names with slashes + if (nameInput.buffer[0] == 0) + { + goto cantMakeWorld; + } + for (int index = 0; nameInput.buffer[index]; index++) + { + if (nameInput.buffer[index] == '/') + { + goto cantMakeWorld; + } } - if (badName) { - SDL_SetRenderDrawColor(renderer, 255, 128, 128, 255); - drawChar(renderer, '!', BUFFER_HALF_W + 70, 12); - } - - if (whichInput == 1) {manageInputBuffer(&seedInput, inputs); } - if (input(renderer, "Seed", seedInput.buffer, - BUFFER_HALF_W - 64, 30, 128, - inputs->mouse.x, inputs->mouse.y, whichInput == 1) && - inputs->mouse.left - ) { - whichInput = 1; - } - - if (button(renderer, terrainNames[typeSelect], - BUFFER_HALF_W - 64, 52, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - typeSelect = (typeSelect + 1) % 5; + if (data_getWorldPath(world->path, nameInput.buffer)) + { + goto cantMakeWorld; } - - if (button(renderer, dayNightModes[dayNightSelect], - BUFFER_HALF_W - 64, 74, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - dayNightSelect = (dayNightSelect + 1) % 3; + if (data_directoryExists(world->path)) + { + goto cantMakeWorld; } - if (button(renderer, "Cancel", - BUFFER_HALF_W - 64, 96, 61, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gameState = STATE_SELECT_WORLD; + world->time = 2048; + world->type = typeSelect; + world->dayNightMode = dayNightSelect; + + // Get numeric seed + world->seed = 0; + for (int index = 0; seedInput.buffer[index]; index++) + { + world->seed *= 10; + world->seed += seedInput.buffer[index] - '0'; } - if (button(renderer, "Generate", - BUFFER_HALF_W + 3, 96, 61, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - // Reject empty names and names with slashes - if (nameInput.buffer[0] == 0) { - goto cantMakeWorld; - } - for (int index = 0; nameInput.buffer[index]; index ++) { - if (nameInput.buffer[index] == '/') { - goto cantMakeWorld; - } - } - - if (data_getWorldPath(world->path, nameInput.buffer)) { - goto cantMakeWorld; - } - - if (data_directoryExists(world->path)) { - goto cantMakeWorld; - } - - world->time = 2048; - world->type = typeSelect; - world->dayNightMode = dayNightSelect; - - // Get numeric seed - world->seed = 0; - for (int index = 0; seedInput.buffer[index]; index ++) { - world->seed *= 10; - world->seed += seedInput.buffer[index] - '0'; - } - - // "Randomize" seed if it was not set - if (world->seed == 0) { - world->seed = time(0) % 999999999999999; - } - - // Secret world for testing nonsense. Type "dev" - if (world->seed == 5800) { - world->type = -1; - } - - whichInput = 0; - - seedInput.buffer[0] = 0; - seedInput.cursor = 0; - - nameInput.buffer[0] = 0; - nameInput.cursor = 0; - badName = 0; - - *gameState = STATE_LOADING; + // "Randomize" seed if it was not set + if (world->seed == 0) + { + world->seed = time(0) % 999999999999999; } - return; + // Secret world for testing nonsense. Type "dev" + if (world->seed == 5800) + { + world->type = -1; + } + + whichInput = 0; + + seedInput.buffer[0] = 0; + seedInput.cursor = 0; - cantMakeWorld: nameInput.buffer[0] = 0; - nameInput.cursor = 0; - badName = 1; + nameInput.cursor = 0; + badName = 0; + + *gameState = STATE_LOADING; + } + + return; + +cantMakeWorld: + nameInput.buffer[0] = 0; + nameInput.cursor = 0; + badName = 1; } /* state_loading * Shows a loading screen and progressively loads in chunks. Returns 1 when * finished. */ -int state_loading ( - SDL_Renderer *renderer, - World *world, - unsigned int seed, - Coords center -) { - IntCoords chunkLoadCoords; - static int chunkLoadNum = 0; - - if (chunkLoadNum < CHUNKARR_SIZE) { - chunkLoadCoords.x = - ((chunkLoadNum % CHUNKARR_DIAM) - - CHUNKARR_RAD) * 64; - chunkLoadCoords.y = - (((chunkLoadNum / CHUNKARR_DIAM) % CHUNKARR_DIAM) - - CHUNKARR_RAD) * 64; - chunkLoadCoords.z = - ((chunkLoadNum / (CHUNKARR_DIAM * CHUNKARR_DIAM)) - - CHUNKARR_RAD) * 64; - genChunk ( - world, seed, - chunkLoadCoords.x, - chunkLoadCoords.y, - chunkLoadCoords.z, world->type, 1, - center - ); - loadScreen ( - renderer, - "Generating world...", - chunkLoadNum, CHUNKARR_SIZE - ); - chunkLoadNum++; - return 0; - } else { - chunkLoadNum = 0; - return 1; - } +int state_loading( + SDL_Renderer *renderer, + World *world, + unsigned int seed, + Coords center) +{ + IntCoords chunkLoadCoords; + static int chunkLoadNum = 0; + + if (chunkLoadNum < CHUNKARR_SIZE) + { + chunkLoadCoords.x = + ((chunkLoadNum % CHUNKARR_DIAM) - + CHUNKARR_RAD) * + 64; + chunkLoadCoords.y = + (((chunkLoadNum / CHUNKARR_DIAM) % CHUNKARR_DIAM) - + CHUNKARR_RAD) * + 64; + chunkLoadCoords.z = + ((chunkLoadNum / (CHUNKARR_DIAM * CHUNKARR_DIAM)) - + CHUNKARR_RAD) * + 64; + genChunk( + world, seed, + chunkLoadCoords.x, + chunkLoadCoords.y, + chunkLoadCoords.z, world->type, 1, + center); + loadScreen( + renderer, + "Generating world...", + chunkLoadNum, CHUNKARR_SIZE); + chunkLoadNum++; + return 0; + } + else + { + chunkLoadNum = 0; + return 1; + } } /* state_options * Shows an options screen. Capable of changing settings and the game state. */ -void state_options (SDL_Renderer *renderer, Inputs *inputs, int *gameState) { - inputs->mouse.x /= BUFFER_SCALE; - inputs->mouse.y /= BUFFER_SCALE; +void state_options(SDL_Renderer *renderer, Inputs *inputs, int *gameState) +{ + inputs->mouse.x /= BUFFER_SCALE; + inputs->mouse.y /= BUFFER_SCALE; - dirtBg(renderer); + dirtBg(renderer); - if (menu_optionsMain (renderer, inputs)) { - *gameState = 0; - } + if (menu_optionsMain(renderer, inputs)) + { + *gameState = 0; + } } /* state_egg * This lacks description. Capable of changing the game state. */ -void state_egg (SDL_Renderer *renderer, Inputs *inputs, int *gameState) { - inputs->mouse.x /= BUFFER_SCALE; - inputs->mouse.y /= BUFFER_SCALE; +void state_egg(SDL_Renderer *renderer, Inputs *inputs, int *gameState) +{ + inputs->mouse.x /= BUFFER_SCALE; + inputs->mouse.y /= BUFFER_SCALE; - dirtBg(renderer); - white(renderer); - centerStr ( - renderer, - "Go away, this is my house.", - BUFFER_HALF_W, - BUFFER_HALF_H - 16 - ); - if (button(renderer, "Ok", - BUFFER_HALF_W - 64, BUFFER_HALF_H, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gameState = STATE_TITLE; - } + dirtBg(renderer); + white(renderer); + centerStr( + renderer, + "Go away, this is my house.", + BUFFER_HALF_W, + BUFFER_HALF_H - 16); + if (button(renderer, "Ok", + BUFFER_HALF_W - 64, BUFFER_HALF_H, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gameState = STATE_TITLE; + } } /* state_err * Shows an error message on screen. Returns 1 when the "Ok" button is pressed. */ -int state_err (SDL_Renderer *renderer, Inputs *inputs, char *message) { - inputs->mouse.x /= BUFFER_SCALE; - inputs->mouse.y /= BUFFER_SCALE; +int state_err(SDL_Renderer *renderer, Inputs *inputs, char *message) +{ + inputs->mouse.x /= BUFFER_SCALE; + inputs->mouse.y /= BUFFER_SCALE; - dirtBg(renderer); - SDL_SetRenderDrawColor(renderer, 255, 128, 128, 255); - centerStr ( - renderer, - "Error:", - BUFFER_HALF_W, - BUFFER_HALF_H - 20 - ); - white(renderer); - centerStr ( - renderer, - message, - BUFFER_HALF_W, - BUFFER_HALF_H - 4 - ); - if (button(renderer, "Ok", - BUFFER_HALF_W - 64, BUFFER_HALF_H + 16, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - return 1; - } - return 0; + dirtBg(renderer); + SDL_SetRenderDrawColor(renderer, 255, 128, 128, 255); + centerStr( + renderer, + "Error:", + BUFFER_HALF_W, + BUFFER_HALF_H - 20); + white(renderer); + centerStr( + renderer, + message, + BUFFER_HALF_W, + BUFFER_HALF_H - 4); + if (button(renderer, "Ok", + BUFFER_HALF_W - 64, BUFFER_HALF_H + 16, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + return 1; + } + return 0; } /* === INGAME POPUPS === */ @@ -455,394 +503,414 @@ int state_err (SDL_Renderer *renderer, Inputs *inputs, char *message) { * Draws the heads up display, including the hotbar, offhand, crosshair, health, * hunger, chat history, and the debug menu if activated. */ -void popup_hud ( - SDL_Renderer *renderer, Inputs *inputs, World *world, - int *debugOn, uint32_t *fps_now, - Player *player -) { - int i; +void popup_hud( + SDL_Renderer *renderer, Inputs *inputs, World *world, + int *debugOn, uint32_t *fps_now, + Player *player) +{ + int i; - static SDL_Rect hotbarRect; - hotbarRect.x = BUFFER_HALF_W - 77; - hotbarRect.y = BUFFER_H - 18; - hotbarRect.w = 154; - hotbarRect.h = 18; + static SDL_Rect hotbarRect; + hotbarRect.x = BUFFER_HALF_W - 77; + hotbarRect.y = BUFFER_H - 18; + hotbarRect.w = 154; + hotbarRect.h = 18; - static SDL_Rect hotbarSelectRect; - hotbarSelectRect.x = 0; - hotbarSelectRect.y = hotbarRect.y; - hotbarSelectRect.w = 18; - hotbarSelectRect.h = 18; + static SDL_Rect hotbarSelectRect; + hotbarSelectRect.x = 0; + hotbarSelectRect.y = hotbarRect.y; + hotbarSelectRect.w = 18; + hotbarSelectRect.h = 18; - static SDL_Rect offhandRect; - offhandRect.x = 0; - offhandRect.y = BUFFER_H - 18; - offhandRect.w = 18; - offhandRect.h = 18; + static SDL_Rect offhandRect; + offhandRect.x = 0; + offhandRect.y = BUFFER_H - 18; + offhandRect.w = 18; + offhandRect.h = 18; - // Debug screen - if (*debugOn) { - static char debugText [][32] = { - "M4KC 0.7", - "Seed: ", - "X: ", - "Y: ", - "Z: ", - "FPS: ", - "ChunkX: ", - "ChunkY: ", - "ChunkZ: " - }; + // Debug screen + if (*debugOn) + { + static char debugText[][32] = { + "M4KC 0.7", + "Seed: ", + "X: ", + "Y: ", + "Z: ", + "FPS: ", + "ChunkX: ", + "ChunkY: ", + "ChunkZ: "}; - // Seed - strnum(debugText[1], 6, world->seed); + // Seed + strnum(debugText[1], 6, world->seed); - // Coordinates - strnum(debugText[2], 3, (int)player->pos.x); - strnum(debugText[3], 3, (int)player->pos.y); - strnum(debugText[4], 3, (int)player->pos.z); + // Coordinates + strnum(debugText[2], 3, (int)player->pos.x); + strnum(debugText[3], 3, (int)player->pos.y); + strnum(debugText[4], 3, (int)player->pos.z); - // FPS - strnum(debugText[5], 5, *fps_now); + // FPS + strnum(debugText[5], 5, *fps_now); - // Chunk coordinates - strnum(debugText[6], 8, ((int)player->pos.x) >> 6); - strnum(debugText[7], 8, ((int)player->pos.y) >> 6); - strnum(debugText[8], 8, ((int)player->pos.z) >> 6); + // Chunk coordinates + strnum(debugText[6], 8, ((int)player->pos.x) >> 6); + strnum(debugText[7], 8, ((int)player->pos.y) >> 6); + strnum(debugText[8], 8, ((int)player->pos.z) >> 6); - // Text - for (i = 0; i < 9; i++) { - drawBGStr(renderer, debugText[i], 0, i * 9); - } - - // Chunk monitor - #ifndef small - #define CHUNKMONW 10 - #define CHUNKMONCOL 9 - - SDL_Rect chunkMonitorRect = { - .x = 0, - .y = 1 - CHUNKMONW, - .w = CHUNKMONW, - .h = CHUNKMONW - }; - for (i = 0; i < CHUNKARR_SIZE; i++) { - if (i % CHUNKMONCOL == 0) { - chunkMonitorRect.x = BUFFER_W - ( - (CHUNKMONW * (CHUNKMONCOL - 1)) + 2); - chunkMonitorRect.y += CHUNKMONW - 1; - } else { - chunkMonitorRect.x += CHUNKMONW - 1; - } - - int stamp = world->chunk[i].loaded; - SDL_SetRenderDrawColor ( - renderer, - (stamp & 0x03) * 64, - (stamp & 0x0C) * 16, - (stamp & 0x30) * 4, - 0xFF - ); - SDL_RenderFillRect(renderer, &chunkMonitorRect); - white(renderer); - SDL_RenderDrawRect(renderer, &chunkMonitorRect); - } - - #undef CHUNKMONW - #undef CHUNKMONCOL - #endif + // Text + for (i = 0; i < 9; i++) + { + drawBGStr(renderer, debugText[i], 0, i * 9); } - - // Hotbar - tblack(renderer); - SDL_RenderFillRect(renderer, &hotbarRect); - hotbarSelectRect.x = +// Chunk monitor +#ifndef small +#define CHUNKMONW 10 +#define CHUNKMONCOL 9 + + SDL_Rect chunkMonitorRect = { + .x = 0, + .y = 1 - CHUNKMONW, + .w = CHUNKMONW, + .h = CHUNKMONW}; + for (i = 0; i < CHUNKARR_SIZE; i++) + { + if (i % CHUNKMONCOL == 0) + { + chunkMonitorRect.x = BUFFER_W - ((CHUNKMONW * (CHUNKMONCOL - 1)) + 2); + chunkMonitorRect.y += CHUNKMONW - 1; + } + else + { + chunkMonitorRect.x += CHUNKMONW - 1; + } + + int stamp = world->chunk[i].loaded; + SDL_SetRenderDrawColor( + renderer, + (stamp & 0x03) * 64, + (stamp & 0x0C) * 16, + (stamp & 0x30) * 4, + 0xFF); + SDL_RenderFillRect(renderer, &chunkMonitorRect); + white(renderer); + SDL_RenderDrawRect(renderer, &chunkMonitorRect); + } + +#undef CHUNKMONW +#undef CHUNKMONCOL +#endif + } + + // Hotbar + tblack(renderer); + SDL_RenderFillRect(renderer, &hotbarRect); + + hotbarSelectRect.x = BUFFER_HALF_W - 77 + player->inventory.hotbarSelect * 17; - white(renderer); - SDL_RenderDrawRect(renderer, &hotbarSelectRect); + white(renderer); + SDL_RenderDrawRect(renderer, &hotbarSelectRect); - for (i = 0; i < 9; i++) { - drawSlot ( - renderer, - &player->inventory.hotbar[i], - BUFFER_HALF_W - 76 + i * 17, - BUFFER_H - 17, - inputs->mouse.x, - inputs->mouse.y - ); - } + for (i = 0; i < 9; i++) + { + drawSlot( + renderer, + &player->inventory.hotbar[i], + BUFFER_HALF_W - 76 + i * 17, + BUFFER_H - 17, + inputs->mouse.x, + inputs->mouse.y); + } - // Offhand - if (player->inventory.offhand.blockid != 0) { - tblack(renderer); - SDL_RenderDrawRect(renderer, &offhandRect); - drawSlot ( - renderer, - &player->inventory.offhand, - 1, - BUFFER_H - 17, - inputs->mouse.x, - inputs->mouse.y - ); - } + // Offhand + if (player->inventory.offhand.blockid != 0) + { + tblack(renderer); + SDL_RenderDrawRect(renderer, &offhandRect); + drawSlot( + renderer, + &player->inventory.offhand, + 1, + BUFFER_H - 17, + inputs->mouse.x, + inputs->mouse.y); + } - // Chat - int chatDrawIndex = chatHistoryIndex; - for (i = 0; i < 11; i++) { - chatDrawIndex = nmod(chatDrawIndex - 1, 11); - if (chatHistoryFade[chatDrawIndex] > 0) { - chatHistoryFade[chatDrawIndex]--; - drawBGStr( - renderer, chatHistory[chatDrawIndex], - 0, BUFFER_H - 32 - i * 9 - ); - } + // Chat + int chatDrawIndex = chatHistoryIndex; + for (i = 0; i < 11; i++) + { + chatDrawIndex = nmod(chatDrawIndex - 1, 11); + if (chatHistoryFade[chatDrawIndex] > 0) + { + chatHistoryFade[chatDrawIndex]--; + drawBGStr( + renderer, chatHistory[chatDrawIndex], + 0, BUFFER_H - 32 - i * 9); } + } } /* manageInvSlot * Draws and performs the input logic of a single inventory slot. Capable of * changing which slot is currently being dragged. */ -void manageInvSlot ( - SDL_Renderer *renderer, - Inputs *inputs, - int x, - int y, - InvSlot *current, - InvSlot *selected, - int *dragging -) { - if (drawSlot ( - renderer, - current, - x, y, - inputs->mouse.x, - inputs->mouse.y - ) && inputs->mouse.left) { - inputs->mouse.left = 0; - if (*dragging) { - // Place down item - if (current->blockid == 0) { - *current = *selected; - *selected = (const InvSlot) { 0 }; - *dragging = 0; - } else if (current->blockid == selected->blockid) { - InvSlot_transfer(current, selected); - } else { - InvSlot_swap(current, selected); - } - - } else if (current->blockid != 0) { - // Pick up item - *selected = *current; - *current = (const InvSlot) { 0 }; - *dragging = 1; - } +void manageInvSlot( + SDL_Renderer *renderer, + Inputs *inputs, + int x, + int y, + InvSlot *current, + InvSlot *selected, + int *dragging) +{ + if (drawSlot( + renderer, + current, + x, y, + inputs->mouse.x, + inputs->mouse.y) && + inputs->mouse.left) + { + inputs->mouse.left = 0; + if (*dragging) + { + // Place down item + if (current->blockid == 0) + { + *current = *selected; + *selected = (const InvSlot){0}; + *dragging = 0; + } + else if (current->blockid == selected->blockid) + { + InvSlot_transfer(current, selected); + } + else + { + InvSlot_swap(current, selected); + } } + else if (current->blockid != 0) + { + // Pick up item + *selected = *current; + *current = (const InvSlot){0}; + *dragging = 1; + } + } } + /* popup_inventory * Allows the user to manage their inventory, rearranging the items inside of * it. Capable of closing itself. */ -void popup_inventory ( - SDL_Renderer *renderer, - Inputs *inputs, - Player *player, - int *gamePopup -) { - SDL_Rect inventoryRect; - inventoryRect.x = BUFFER_HALF_W - 77; - inventoryRect.y = (BUFFER_H - 18) / 2 - 26; - inventoryRect.w = 154; - inventoryRect.h = 52; +void popup_inventory( + SDL_Renderer *renderer, + Inputs *inputs, + Player *player, + int *gamePopup) +{ + SDL_Rect inventoryRect; + inventoryRect.x = BUFFER_HALF_W - 77; + inventoryRect.y = (BUFFER_H - 18) / 2 - 26; + inventoryRect.w = 154; + inventoryRect.h = 52; - SDL_Rect hotbarRect; - hotbarRect.x = BUFFER_HALF_W - 77; - hotbarRect.y = BUFFER_H - 18; - hotbarRect.w = 154; - hotbarRect.h = 18; + SDL_Rect hotbarRect; + hotbarRect.x = BUFFER_HALF_W - 77; + hotbarRect.y = BUFFER_H - 18; + hotbarRect.w = 154; + hotbarRect.h = 18; - SDL_Rect offhandRect; - offhandRect.x = 0; - offhandRect.y = BUFFER_H - 18; - offhandRect.w = 18; - offhandRect.h = 18; + SDL_Rect offhandRect; + offhandRect.x = 0; + offhandRect.y = BUFFER_H - 18; + offhandRect.w = 18; + offhandRect.h = 18; - static InvSlot selected = { 0 }; - static int dragging = 0; + static InvSlot selected = {0}; + static int dragging = 0; - // Inventory background - tblack(renderer); - SDL_RenderFillRect(renderer, &inventoryRect); - SDL_RenderFillRect(renderer, &hotbarRect); - SDL_RenderFillRect(renderer, &offhandRect); + // Inventory background + tblack(renderer); + SDL_RenderFillRect(renderer, &inventoryRect); + SDL_RenderFillRect(renderer, &hotbarRect); + SDL_RenderFillRect(renderer, &offhandRect); - // Hotbar items - for (int i = 0; i < HOTBAR_SIZE; i++) { - manageInvSlot ( - renderer, inputs, - BUFFER_HALF_W - 76 + i * 17, - BUFFER_H - 17, - &player->inventory.hotbar[i], - &selected, - &dragging - ); - } + // Hotbar items + for (int i = 0; i < HOTBAR_SIZE; i++) + { + manageInvSlot( + renderer, inputs, + BUFFER_HALF_W - 76 + i * 17, + BUFFER_H - 17, + &player->inventory.hotbar[i], + &selected, + &dragging); + } - // Inventory items - for (int i = 0; i < INVENTORY_SIZE; i++) { - manageInvSlot ( - renderer, inputs, - BUFFER_HALF_W - 76 + (i % HOTBAR_SIZE) * 17, - inventoryRect.y + 1 + (i / HOTBAR_SIZE) * 17, - &player->inventory.slots[i], - &selected, - &dragging - ); - } + // Inventory items + for (int i = 0; i < INVENTORY_SIZE; i++) + { + manageInvSlot( + renderer, inputs, + BUFFER_HALF_W - 76 + (i % HOTBAR_SIZE) * 17, + inventoryRect.y + 1 + (i / HOTBAR_SIZE) * 17, + &player->inventory.slots[i], + &selected, + &dragging); + } - // Offhand - manageInvSlot ( - renderer, inputs, - 1, - BUFFER_H - 17, - &player->inventory.offhand, - &selected, - &dragging - ); + // Offhand + manageInvSlot( + renderer, inputs, + 1, + BUFFER_H - 17, + &player->inventory.offhand, + &selected, + &dragging); - if (dragging) { - drawSlot ( - renderer, - &selected, - inputs->mouse.x - 8, - inputs->mouse.y - 8, - 0, 0 - ); - } - - // Exit inventory - if (inputs->keyboard.e) { - inputs->keyboard.e = 0; - *gamePopup = POPUP_HUD; - } + if (dragging) + { + drawSlot( + renderer, + &selected, + inputs->mouse.x - 8, + inputs->mouse.y - 8, + 0, 0); + } + + // Exit inventory + if (inputs->keyboard.e) + { + inputs->keyboard.e = 0; + *gamePopup = POPUP_HUD; + } } + /* popup_chat * Allows the user to type in chat, and view farther back in the message * history. Capable of closing itself. */ -void popup_chat (SDL_Renderer *renderer, Inputs *inputs, uint64_t gameTime) { - static char buffer[64] = { 0 }; - static InputBuffer chatBox = { - .buffer = buffer, - .len = 64, - .cursor = 0 - }; - - static SDL_Rect chatBoxRect = {0, 0, 0, 9}; - chatBoxRect.y = BUFFER_H - 9; - chatBoxRect.w = BUFFER_W; +void popup_chat(SDL_Renderer *renderer, Inputs *inputs, uint64_t gameTime) +{ + static char buffer[64] = {0}; + static InputBuffer chatBox = { + .buffer = buffer, + .len = 64, + .cursor = 0}; - int chatDrawIndex = chatHistoryIndex; - for (int i = 0; i < 11; i++) { - chatDrawIndex = nmod(chatDrawIndex - 1, 11); - drawBGStr( - renderer, chatHistory[chatDrawIndex], - 0, BUFFER_H - 32 - i * 9 - ); - } + static SDL_Rect chatBoxRect = {0, 0, 0, 9}; + chatBoxRect.y = BUFFER_H - 9; + chatBoxRect.w = BUFFER_W; - // Get keyboard input - if (manageInputBuffer(&chatBox, inputs)) { - // 63: max chat box length - // 7: max username length - // 2: ": " chars - // 1: null - static char chatNameConcat[63 + 7 + 2 + 1]; - snprintf (chatNameConcat, 63 + 7 + 2, "%s: %s", - options.username.buffer, chatBox.buffer); - - // Add input to chat - chatAdd(chatNameConcat); - // Clear input box - chatBox.cursor = 0; - chatBox.buffer[0] = 0; - } + int chatDrawIndex = chatHistoryIndex; + for (int i = 0; i < 11; i++) + { + chatDrawIndex = nmod(chatDrawIndex - 1, 11); + drawBGStr( + renderer, chatHistory[chatDrawIndex], + 0, BUFFER_H - 32 - i * 9); + } - // Chat input box - // If char limit is reached, give some visual - // feedback. - if (chatBox.cursor == 63) { - SDL_SetRenderDrawColor(renderer, 128, 0, 0, 128); - } else { - tblack(renderer); - } - - SDL_RenderFillRect(renderer, &chatBoxRect); + // Get keyboard input + if (manageInputBuffer(&chatBox, inputs)) + { + // 63: max chat box length + // 7: max username length + // 2: ": " chars + // 1: null + static char chatNameConcat[63 + 7 + 2 + 1]; + snprintf(chatNameConcat, 63 + 7 + 2, "%s: %s", + options.username.buffer, chatBox.buffer); - white(renderer); - drawChar ( - renderer, - 95 + 32 * ((gameTime >> 6) % 2), - drawStr ( - renderer, chatBox.buffer, - 0, BUFFER_H - 8 - ), - BUFFER_H - 8 - ); + // Add input to chat + chatAdd(chatNameConcat); + // Clear input box + chatBox.cursor = 0; + chatBox.buffer[0] = 0; + } + + // Chat input box + // If char limit is reached, give some visual + // feedback. + if (chatBox.cursor == 63) + { + SDL_SetRenderDrawColor(renderer, 128, 0, 0, 128); + } + else + { + tblack(renderer); + } + + SDL_RenderFillRect(renderer, &chatBoxRect); + + white(renderer); + drawChar( + renderer, + 95 + 32 * ((gameTime >> 6) % 2), + drawStr( + renderer, chatBox.buffer, + 0, BUFFER_H - 8), + BUFFER_H - 8); } + /* popup_pause * Displays a pause menu. Capable of activating submenus or changing the game * state. */ -void popup_pause ( - SDL_Renderer *renderer, Inputs *inputs, - int *gamePopup, int *gameState, World *world -) { - if (button(renderer, "Back to Game", - BUFFER_HALF_W - 64, 20, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gamePopup = POPUP_HUD; +void popup_pause( + SDL_Renderer *renderer, Inputs *inputs, + int *gamePopup, int *gameState, World *world) +{ + if (button(renderer, "Back to Game", + BUFFER_HALF_W - 64, 20, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_HUD; + } + + if (button(renderer, "Options...", + BUFFER_HALF_W - 64, 42, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_OPTIONS; + } + + if (button(renderer, "Save and Quit", + BUFFER_HALF_W - 64, 64, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + int err = World_save(world); + if (err) + { + gameLoop_error("Could not save world"); + return; } - if (button(renderer, "Options...", - BUFFER_HALF_W - 64, 42, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gamePopup = POPUP_OPTIONS; - } - - if (button(renderer, "Save and Quit", - BUFFER_HALF_W - 64, 64, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - int err = World_save(world); - if (err) { - gameLoop_error("Could not save world"); - return; - } - - World_wipe(world); - *gameState = STATE_TITLE; - } + World_wipe(world); + *gameState = STATE_TITLE; + } } + /* popup_options * Shows an options screen. Capable of changing settings and closing itself. */ -void popup_options (SDL_Renderer *renderer, Inputs *inputs, int *gamePopup) { - if (menu_optionsMain(renderer, inputs)) { - *gamePopup = 1; - } +void popup_options(SDL_Renderer *renderer, Inputs *inputs, int *gamePopup) +{ + if (menu_optionsMain(renderer, inputs)) + { + *gamePopup = 1; + } } #ifndef small @@ -850,421 +918,458 @@ void popup_options (SDL_Renderer *renderer, Inputs *inputs, int *gamePopup) { * Shows a menu listing advanced debug tools. These are only included in debug * builds and are not included in compressed executables. */ -void popup_debugTools (SDL_Renderer *renderer, Inputs *inputs, int *gamePopup) { - if (button(renderer, "Chunk Peek", - BUFFER_HALF_W - 64, 20, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gamePopup = POPUP_CHUNK_PEEK; - } - - if (button(renderer, "All Chunks", - BUFFER_HALF_W - 64, 42, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gamePopup = POPUP_ROLL_CALL; - } - - if (button(renderer, "World overview", - BUFFER_HALF_W - 64, 64, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gamePopup = POPUP_OVERVIEW; - } +void popup_debugTools(SDL_Renderer *renderer, Inputs *inputs, int *gamePopup) +{ + if (button(renderer, "Chunk Peek", + BUFFER_HALF_W - 64, 20, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_CHUNK_PEEK; + } - if (button(renderer, "Done", - BUFFER_HALF_W - 64, 86, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - *gamePopup = POPUP_HUD; - } + if (button(renderer, "All Chunks", + BUFFER_HALF_W - 64, 42, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_ROLL_CALL; + } + + if (button(renderer, "World overview", + BUFFER_HALF_W - 64, 64, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_OVERVIEW; + } + + if (button(renderer, "Done", + BUFFER_HALF_W - 64, 86, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_HUD; + } } /* popup_chunkPeek * Shows a 3D map of the current chunk, with the ability to view a cross-section * of it. This feature is only included in debug builds. */ -void popup_chunkPeek ( - SDL_Renderer *renderer, Inputs *inputs, World *world, - int *gamePopup, - Player *player -) { - static int chunkPeekRYMax = 0; +void popup_chunkPeek( + SDL_Renderer *renderer, Inputs *inputs, World *world, + int *gamePopup, + Player *player) +{ + static int chunkPeekRYMax = 0; - int chunkPeekRX, - chunkPeekRY, - chunkPeekRZ, - chunkPeekColor; - - Chunk *debugChunk; - char chunkPeekText[][32] = { - "coordHash: ", - "loaded: " - }; + int chunkPeekRX, + chunkPeekRY, + chunkPeekRZ, + chunkPeekColor; - debugChunk = chunkLookup ( - world, - (int)player->pos.x, - (int)player->pos.y, - (int)player->pos.z - ); + Chunk *debugChunk; + char chunkPeekText[][32] = { + "coordHash: ", + "loaded: "}; + debugChunk = chunkLookup( + world, + (int)player->pos.x, + (int)player->pos.y, + (int)player->pos.z); + + white(renderer); + if (debugChunk != NULL) + { + // There is a chunk to display info about. Process + // strings. + strnum(chunkPeekText[0], 11, debugChunk->coordHash); + strnum(chunkPeekText[1], 8, debugChunk->loaded); + // Draw the strings + for (int i = 0; i < 2; i++) + { + drawStr(renderer, chunkPeekText[i], 0, i << 3); + } + + // Scroll wheel for changing chunk map xray + if (inputs->mouse.wheel != 0) + { + chunkPeekRYMax -= inputs->mouse.wheel; + chunkPeekRYMax = nmod(chunkPeekRYMax, 64); + inputs->mouse.wheel = 0; + } + + // Mouse for changing chunk map xray + if ( + inputs->mouse.x > 128 && + inputs->mouse.y < 64 && + inputs->mouse.left) + chunkPeekRYMax = inputs->mouse.y; + + // Up/Down buttons for changing chunk map xray + if (button(renderer, "UP", + 4, 56, 64, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + chunkPeekRYMax = nmod(chunkPeekRYMax - 1, 64); + } + + if (button(renderer, "DOWN", + 4, 78, 64, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + chunkPeekRYMax = nmod(chunkPeekRYMax + 1, 64); + } + + // Draw chunk map white(renderer); - if (debugChunk != NULL) { - // There is a chunk to display info about. Process - // strings. - strnum(chunkPeekText[0], 11, debugChunk -> coordHash); - strnum(chunkPeekText[1], 8, debugChunk -> loaded); - // Draw the strings - for (int i = 0; i < 2; i++) { - drawStr(renderer, chunkPeekText[i], 0, i << 3); - } + SDL_RenderDrawLine( + renderer, + 128, chunkPeekRYMax, + 191, chunkPeekRYMax); - // Scroll wheel for changing chunk map xray - if (inputs->mouse.wheel != 0) { - chunkPeekRYMax -= inputs->mouse.wheel; - chunkPeekRYMax = nmod(chunkPeekRYMax, 64); - inputs->mouse.wheel = 0; - } - - // Mouse for changing chunk map xray - if ( - inputs->mouse.x > 128 && - inputs->mouse.y < 64 && - inputs->mouse.left - ) chunkPeekRYMax = inputs->mouse.y; - - // Up/Down buttons for changing chunk map xray - if (button(renderer, "UP", - 4, 56, 64, - inputs->mouse.x, inputs->mouse.y) - && inputs->mouse.left - ) { - chunkPeekRYMax = nmod(chunkPeekRYMax - 1, 64); - } - - if (button(renderer, "DOWN", - 4, 78, 64, - inputs->mouse.x, inputs->mouse.y) - && inputs->mouse.left - ) { - chunkPeekRYMax = nmod(chunkPeekRYMax + 1, 64); - } - - // Draw chunk map - white(renderer); - SDL_RenderDrawLine ( - renderer, - 128, chunkPeekRYMax, - 191, chunkPeekRYMax - ); - + for ( + chunkPeekRY = 64; + chunkPeekRY >= chunkPeekRYMax; + chunkPeekRY--) + for ( + chunkPeekRX = 0; + chunkPeekRX < 64; + chunkPeekRX++) for ( - chunkPeekRY = 64; - chunkPeekRY >= chunkPeekRYMax; - chunkPeekRY-- - ) for ( - chunkPeekRX = 0; - chunkPeekRX < 64; - chunkPeekRX++ - ) for ( - chunkPeekRZ = 0; - chunkPeekRZ < 63; - chunkPeekRZ++ - ) { - Block currentBlock = debugChunk->blocks [ - chunkPeekRX + - (chunkPeekRY << 6) + - (chunkPeekRZ << 12)]; - - chunkPeekColor = textures [ - currentBlock * 256 * 3 + 6 * 16]; + chunkPeekRZ = 0; + chunkPeekRZ < 63; + chunkPeekRZ++) + { + Block currentBlock = debugChunk->blocks[chunkPeekRX + + (chunkPeekRY << 6) + + (chunkPeekRZ << 12)]; - if (chunkPeekColor) { - int alpha = 255; - - if (currentBlock == BLOCK_WATER) { - alpha = 64; - } - - SDL_SetRenderDrawColor ( - renderer, - (chunkPeekColor >> 16 & 0xFF), - (chunkPeekColor >> 8 & 0xFF), - (chunkPeekColor & 0xFF), - alpha); - - SDL_RenderDrawPoint ( - renderer, - chunkPeekRX + 128, - chunkPeekRY + chunkPeekRZ); - - // A little shadow for depth - SDL_SetRenderDrawColor ( - renderer, - 0, 0, 0, 64); - - SDL_RenderDrawPoint ( - renderer, - chunkPeekRX + 128, - chunkPeekRY + chunkPeekRZ + 1); + chunkPeekColor = textures[currentBlock * 256 * 3 + 6 * 16]; + + if (chunkPeekColor) + { + int alpha = 255; + + if (currentBlock == BLOCK_WATER) + { + alpha = 64; } + + SDL_SetRenderDrawColor( + renderer, + (chunkPeekColor >> 16 & 0xFF), + (chunkPeekColor >> 8 & 0xFF), + (chunkPeekColor & 0xFF), + alpha); + + SDL_RenderDrawPoint( + renderer, + chunkPeekRX + 128, + chunkPeekRY + chunkPeekRZ); + + // A little shadow for depth + SDL_SetRenderDrawColor( + renderer, + 0, 0, 0, 64); + + SDL_RenderDrawPoint( + renderer, + chunkPeekRX + 128, + chunkPeekRY + chunkPeekRZ + 1); + } } - } else { - drawStr(renderer, "Chunk not found", 0, 0); - } + } + else + { + drawStr(renderer, "Chunk not found", 0, 0); + } - if (button(renderer, "Done", - 4, 100, 64, - inputs->mouse.x, inputs->mouse.y) - && inputs->mouse.left - ) { - *gamePopup = POPUP_ADVANCED_DEBUG; - } + if (button(renderer, "Done", + 4, 100, 64, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_ADVANCED_DEBUG; + } } -void popup_rollCall ( - SDL_Renderer *renderer, Inputs *inputs, World *world, - int *gamePopup -) { - static int scroll = 0; +void popup_rollCall( + SDL_Renderer *renderer, Inputs *inputs, World *world, + int *gamePopup) +{ + static int scroll = 0; - if (inputs->mouse.wheel != 0) { - scroll += inputs->mouse.wheel; - inputs->mouse.wheel = 0; - } + if (inputs->mouse.wheel != 0) + { + scroll += inputs->mouse.wheel; + inputs->mouse.wheel = 0; + } - if (scroll > 0) { scroll = 0; } - if (scroll < 1 - CHUNKARR_SIZE) { scroll = 1 - CHUNKARR_SIZE; } + if (scroll > 0) + { + scroll = 0; + } + if (scroll < 1 - CHUNKARR_SIZE) + { + scroll = 1 - CHUNKARR_SIZE; + } + white(renderer); + drawStr(renderer, "x y z stmp hash", 8, 10); + + for (int index = 0; index < CHUNKARR_SIZE; index++) + { + Chunk *chunk = &world->chunk[index]; + char chunkDescription[32]; white(renderer); - drawStr(renderer, "x y z stmp hash", 8, 10); - for (int index = 0; index < CHUNKARR_SIZE; index ++) { - Chunk *chunk = &world->chunk[index]; - char chunkDescription[32]; - white(renderer); - - int topMargin = 28; - int y = (index + scroll) * 8 + topMargin; - if (y < topMargin || y >= BUFFER_H) { continue; } - - snprintf(chunkDescription, 32, "%i", chunk->center.x - 32); - drawStr(renderer, chunkDescription, 0, y); - snprintf(chunkDescription, 32, "%i", chunk->center.y - 32); - drawStr(renderer, chunkDescription, 24, y); - snprintf(chunkDescription, 32, "%i", chunk->center.z - 32); - drawStr(renderer, chunkDescription, 48, y); - - snprintf(chunkDescription, 32, "#%i", chunk->loaded); - drawStr(renderer, chunkDescription, 72, y); - snprintf(chunkDescription, 32, "%016x", chunk->coordHash); - drawStr(renderer, chunkDescription, 96, y); + int topMargin = 28; + int y = (index + scroll) * 8 + topMargin; + if (y < topMargin || y >= BUFFER_H) + { + continue; } - if (button(renderer, "Done", - BUFFER_W - 6 - 32, 6, 32, - inputs->mouse.x, inputs->mouse.y) - && inputs->mouse.left - ) { - *gamePopup = POPUP_ADVANCED_DEBUG; - } + snprintf(chunkDescription, 32, "%i", chunk->center.x - 32); + drawStr(renderer, chunkDescription, 0, y); + snprintf(chunkDescription, 32, "%i", chunk->center.y - 32); + drawStr(renderer, chunkDescription, 24, y); + snprintf(chunkDescription, 32, "%i", chunk->center.z - 32); + drawStr(renderer, chunkDescription, 48, y); + + snprintf(chunkDescription, 32, "#%i", chunk->loaded); + drawStr(renderer, chunkDescription, 72, y); + snprintf(chunkDescription, 32, "%016x", chunk->coordHash); + drawStr(renderer, chunkDescription, 96, y); + } + + if (button(renderer, "Done", + BUFFER_W - 6 - 32, 6, 32, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_ADVANCED_DEBUG; + } } -void popup_overview ( - SDL_Renderer *renderer, Inputs *inputs, World *world, - int *gamePopup -) { - (void)(world); +void popup_overview( + SDL_Renderer *renderer, Inputs *inputs, World *world, + int *gamePopup) +{ + (void)(world); - int worldEndingBound = CHUNK_SIZE * (CHUNKARR_RAD + 1); - int worldStartingBound = CHUNK_SIZE * CHUNKARR_RAD * -1; - for (int y = worldEndingBound; y > worldStartingBound; y -= 4) + int worldEndingBound = CHUNK_SIZE * (CHUNKARR_RAD + 1); + int worldStartingBound = CHUNK_SIZE * CHUNKARR_RAD * -1; + for (int y = worldEndingBound; y > worldStartingBound; y -= 4) for (int x = worldStartingBound; x < worldEndingBound; x += 4) - for (int z = worldStartingBound; z < worldEndingBound; z += 4) { + for (int z = worldStartingBound; z < worldEndingBound; z += 4) + { int projectX = (x - z) / 4; int projectY = ((x + z) / 2 + y) / 4; - + Block currentBlock = World_getBlock(world, x, y, z); int color; int alpha = 255; - if (currentBlock < NUMBER_OF_BLOCKS) { - color = textures[currentBlock * 256 * 3 + 6 * 16]; - } else { - color = 0xFF0000; - alpha = 0; + if (currentBlock < NUMBER_OF_BLOCKS) + { + color = textures[currentBlock * 256 * 3 + 6 * 16]; + } + else + { + color = 0xFF0000; + alpha = 0; } - if (color != 0) { - if (currentBlock == BLOCK_WATER) { - alpha = 64; - } - - SDL_SetRenderDrawColor ( - renderer, - (color >> 16 & 0xFF), - (color >> 8 & 0xFF), - (color & 0xFF), - alpha); - - SDL_RenderDrawPoint ( - renderer, - projectX + BUFFER_HALF_W, - projectY + 32); - } - } - + if (color != 0) + { + if (currentBlock == BLOCK_WATER) + { + alpha = 64; + } - if (button(renderer, "Done", - BUFFER_W - 6 - 32, 6, 32, - inputs->mouse.x, inputs->mouse.y) - && inputs->mouse.left - ) { - *gamePopup = POPUP_ADVANCED_DEBUG; - } + SDL_SetRenderDrawColor( + renderer, + (color >> 16 & 0xFF), + (color >> 8 & 0xFF), + (color & 0xFF), + alpha); + + SDL_RenderDrawPoint( + renderer, + projectX + BUFFER_HALF_W, + projectY + 32); + } + } + + if (button(renderer, "Done", + BUFFER_W - 6 - 32, 6, 32, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + *gamePopup = POPUP_ADVANCED_DEBUG; + } } #endif + /* menu_optionsMain * This function presents the options menu. It's purpose is to be included in * other functions that draw a suitable background and then call this one. * Returns 1 when the user pressed the "Done" button. Capable of changing * settings. */ -static int menu_optionsMain (SDL_Renderer *renderer, Inputs *inputs) { - static int page = 0; +static int menu_optionsMain(SDL_Renderer *renderer, Inputs *inputs) +{ + static int page = 0; - switch (page) { - case 0: - manageInputBuffer(&options.username, inputs); - input (renderer, "Username", options.username.buffer, - BUFFER_HALF_W - 64, 20, 128, - inputs->mouse.x, inputs->mouse.y, 1); + switch (page) + { + case 0: + manageInputBuffer(&options.username, inputs); + input(renderer, "Username", options.username.buffer, + BUFFER_HALF_W - 64, 20, 128, + inputs->mouse.x, inputs->mouse.y, 1); - static char *trapMouseTexts[] = { - "Capture Mouse: OFF", - "Capture Mouse: ON" - }; - if (button(renderer, trapMouseTexts[options.trapMouse], - BUFFER_HALF_W - 64, 42, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - options.trapMouse = !options.trapMouse; - } + static char *trapMouseTexts[] = { + "Capture Mouse: OFF", + "Capture Mouse: ON"}; + if (button(renderer, trapMouseTexts[options.trapMouse], + BUFFER_HALF_W - 64, 42, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + options.trapMouse = !options.trapMouse; + } + break; + case 1: + ;static char drawDistanceText[20] = {0}; + if (!drawDistanceText[0]) + { + snprintf( + drawDistanceText, 20, + "Draw distance: %i", + options.drawDistance); + } + + if (button(renderer, drawDistanceText, + BUFFER_HALF_W - 64, 20, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + switch (options.drawDistance) + { + case 20: + options.drawDistance = 32; break; - case 1: - ;static char drawDistanceText[20] = { 0 }; - if (!drawDistanceText[0]) { - snprintf ( - drawDistanceText, 20, - "Draw distance: %i", - options.drawDistance); - } - - if (button(renderer, drawDistanceText, - BUFFER_HALF_W - 64, 20, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - switch (options.drawDistance) { - case 20: - options.drawDistance = 32; - break; - case 32: - options.drawDistance = 64; - break; - case 64: - options.drawDistance = 96; - break; - case 96: - options.drawDistance = 128; - break; - default: - options.drawDistance = 20; - break; - } - strnum(drawDistanceText, 15, options.drawDistance); - } - - static char *fovTexts[] = { - "FOV: Low", - "FOV: Medium", - "FOV: High", - "FOV: ?" - }; - char *fovText = NULL; - switch ((int)options.fov) { - default: fovText = fovTexts[3]; break; - case 60: fovText = fovTexts[2]; break; - case 90: fovText = fovTexts[1]; break; - case 140: fovText = fovTexts[0]; break; - } - - if (button(renderer, fovText, - BUFFER_HALF_W - 64, 42, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - switch ((int)options.fov) { - case 60: options.fov = 140; break; - case 90: options.fov = 60; break; - default: options.fov = 90; break; - } - - } - - static char *fogTexts[] = { - "Fog: Gradual", - "Fog: Sharp" - }; - if (button(renderer, fogTexts[options.fogType], - BUFFER_HALF_W - 64, 64, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - options.fogType = !options.fogType; - } - + case 32: + options.drawDistance = 64; break; + case 64: + options.drawDistance = 96; + break; + case 96: + options.drawDistance = 128; + break; + default: + options.drawDistance = 20; + break; + } + strnum(drawDistanceText, 15, options.drawDistance); } - if (button(renderer, "<", - BUFFER_HALF_W - 86, 20, 16, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - page --; - page = nmod(page, 2); + static char *fovTexts[] = { + "FOV: Low", + "FOV: Medium", + "FOV: High", + "FOV: ?"}; + char *fovText = NULL; + switch ((int)options.fov) + { + default: + fovText = fovTexts[3]; + break; + case 60: + fovText = fovTexts[2]; + break; + case 90: + fovText = fovTexts[1]; + break; + case 140: + fovText = fovTexts[0]; + break; } - if (button(renderer, ">", - BUFFER_HALF_W + 70, 20, 16, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - page ++; - page = nmod(page, 2); + if (button(renderer, fovText, + BUFFER_HALF_W - 64, 42, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + switch ((int)options.fov) + { + case 60: + options.fov = 140; + break; + case 90: + options.fov = 60; + break; + default: + options.fov = 90; + break; + } } - if (button(renderer, "Done", - BUFFER_HALF_W - 64, 86, 128, - inputs->mouse.x, inputs->mouse.y) && - inputs->mouse.left - ) { - int err = options_save(); - if (err) { - gameLoop_error("Could not save options"); - } - - page = 0; - return 1; + static char *fogTexts[] = { + "Fog: Gradual", + "Fog: Sharp"}; + if (button(renderer, fogTexts[options.fogType], + BUFFER_HALF_W - 64, 64, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + options.fogType = !options.fogType; } - return 0; + break; + } + + if (button(renderer, "<", + BUFFER_HALF_W - 86, 20, 16, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + page--; + page = nmod(page, 2); + } + + if (button(renderer, ">", + BUFFER_HALF_W + 70, 20, 16, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + page++; + page = nmod(page, 2); + } + + if (button(renderer, "Done", + BUFFER_HALF_W - 64, 86, 128, + inputs->mouse.x, inputs->mouse.y) && + inputs->mouse.left) + { + int err = options_save(); + if (err) + { + gameLoop_error("Could not save options"); + } + + page = 0; + return 1; + } + + return 0; } diff --git a/src/options.c b/src/options.c index ed88b13..5d08caf 100644 --- a/src/options.c +++ b/src/options.c @@ -31,8 +31,10 @@ int options_init (void) { * on success, non-zero on failure. */ int options_load (void) { + const char *path = data_getOptionsFileName(); - + printf("Options path: %s\n", path); + // If the file doesn't exist, calmly exit the function and just use // default values FILE *file = fopen(path, "r"); @@ -70,7 +72,9 @@ int options_load (void) { * success, non-zero on failure. */ int options_save (void) { + const char *path = data_getOptionsFileName(); + printf("%s\n", path); FILE *file = fopen(path, "w"); if (file == NULL) { return 1; } diff --git a/xmake.lua b/xmake.lua new file mode 100644 index 0000000..107ee86 --- /dev/null +++ b/xmake.lua @@ -0,0 +1,84 @@ +set_project("m4kc") + + +KOS_SDK = "/projects/kos/contrib/sdk" +KOS_GCC = "/home/autobuild/tools/win32" + + +toolchain("kos-gcc") + + set_toolset("cc", KOS_GCC .. "/bin/kos32-gcc") + set_toolset("ld", KOS_GCC .. "/bin/kos32-ld") + set_toolset("objcopy", KOS_GCC .. "/bin/kos32-objcopy") + + add_cflags("-fno-ident -O3 -fomit-frame-pointer -fno-ident -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -D_KOLIBRI -DNO_ZIP -DPERFORMANCE -DMINIZ_NO_TIME") + add_ldflags("-static -S -nostdlib -T " .. KOS_SDK .. "/sources/newlib/app.lds --image-base 0 --subsystem native") + +toolchain_end() + + +target("m4kc-kolibri") + + set_arch("i386") + set_plat("cross") + set_kind("binary") + set_toolchains("kos-gcc") + + add_defines("_KOLIBRI") + + add_includedirs(KOS_SDK .. "/sources/SDL2-2.30.6/include") + add_includedirs(KOS_SDK .. "/sources/newlib/libc/include") + add_includedirs(KOS_SDK .. "/sources/newlib/libc/include/sys") + add_includedirs("src", {public = true}) + + add_files("src/*.c") + + add_linkdirs(KOS_SDK .. "/lib") + add_linkdirs(KOS_GCC .. "/mingw32/lib") + + add_links("SDL2", "gcc", "c.dll", "c", "sound") + + after_link(function (target) + os.vrunv("objcopy", {target:targetfile(), "-O", "binary"}) + end) + +target_end() + + +target("m4kc-linux") + + set_arch("x86_64") + set_plat("linux") + set_kind("binary") + + add_includedirs("src", {public = true}) + + add_files("src/*.c") + + add_links("SDL2") + + set_optimize("fastest") + +target_end() + + +target("m4kc-windows") + + set_kind("binary") + set_toolchains("@tinycc") + + add_includedirs("../TCC/include/") + add_includedirs("src", {public = true}) + + add_files("src/*.c") + + add_linkdirs("./") + + add_links("SDL2") + + set_optimize("fastest") + +target_end() + + +add_rules("mode.debug", "mode.release")