/* * Copyright (C) 2021 P. J. McDermott * * This file is part of Maze Fight * * Maze Fight is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Maze Fight is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Maze Fight. If not, see . */ #include #include #include #include #include #include #include #include "defs.h" #include "dirs.h" #include "game.h" #include "maze.h" #include "menu.h" #include "tk.h" #include "util.h" const int MF_MENU_SIZES_[] = {15, 20, 30}; const int MF_MENU_ENEMIES_[] = { 1, 2, 4}; struct _mf_menu { char *seed_buf; long seed; int size; char *enemies_buf; int enemies; int enemies_custom; int fow; int reveal; struct mftk_widget *seed_text; struct mftk_widget *enemies_text; SDL_Renderer *renderer; }; static int _mf_menu_seed(void *user_data, const char *seed) { struct _mf_menu *menu = (struct _mf_menu *) user_data; menu->seed = atol(seed); return 0; } static int _mf_menu_size(void *user_data, int state) { struct _mf_menu *menu = (struct _mf_menu *) user_data; menu->size = state; if (menu->enemies_custom == SDL_FALSE) { menu->enemies = MF_MENU_ENEMIES_[state]; if (sprintf(menu->enemies_buf, "%d", menu->enemies) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate string: %s", strerror(errno)); return -1; } mftk_text_set_value(menu->enemies_text, menu->enemies_buf); } return 0; } static int _mf_menu_enemies(void *user_data, const char *enemies) { struct _mf_menu *menu = (struct _mf_menu *) user_data; menu->enemies = atoi(enemies); menu->enemies_custom = SDL_TRUE; return 0; } static int _mf_menu_fow(void *user_data, int state) { struct _mf_menu *menu = (struct _mf_menu *) user_data; menu->fow = state; return 0; } static int _mf_menu_reveal(void *user_data, int state) { struct _mf_menu *menu = (struct _mf_menu *) user_data; menu->reveal = state; return 0; } static int _mf_menu_quit(void *user_data __attribute__((__unused__))) { return 1; } static int _mf_menu_play(void *user_data) { struct _mf_menu *menu = (struct _mf_menu *) user_data; int e; e = mf_game(menu->seed, MF_MENU_SIZES_[menu->size], menu->fow, menu->reveal, menu->enemies, menu->renderer); menu->seed = rand(); if (sprintf(menu->seed_buf, "%ld", menu->seed) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate string: %s", strerror(errno)); return -1; } mftk_text_set_value(menu->seed_text, menu->seed_buf); return e; } static struct mftk_widget * _mf_menu_form(SDL_Renderer *renderer, TTF_Font *text_font, struct _mf_menu *menu) { double rand_max_len; struct mftk_widget *grid; rand_max_len = ceil(log10(RAND_MAX)); menu->seed_buf = calloc(rand_max_len + 1, sizeof(*menu->seed_buf)); if (menu->seed_buf == NULL || sprintf(menu->seed_buf, "%ld", menu->seed) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate string: %s", strerror(errno)); return NULL; } menu->enemies_buf = calloc(rand_max_len + 1, sizeof(*menu->enemies_buf)); if (menu->enemies_buf == NULL || sprintf(menu->enemies_buf, "%d", menu->enemies) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate string: %s", strerror(errno)); return NULL; } menu->seed_text = mftk_text_new(MF_DIGITS, rand_max_len, menu->seed_buf, text_font, MF_TXT_P, MF_WGT_B, SDL_TRUE, &_mf_menu_seed, &_mf_menu_play, menu); menu->enemies_text = mftk_text_new(MF_DIGITS, 2, menu->enemies_buf, text_font, MF_TXT_P, MF_WGT_B, SDL_TRUE, &_mf_menu_enemies, &_mf_menu_play, menu); grid = mftk_grid_new(6, 2, MF_ROW_M, MF_COL_M, mftk_label_new(text_font, "Seed", renderer), MFTK_GRID_HALIGN_R|MFTK_GRID_VALIGN_T, menu->seed_text, MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T, mftk_label_new(text_font, "Size", renderer), MFTK_GRID_HALIGN_R|MFTK_GRID_VALIGN_T, mftk_radio_new(MF_CHK_BTN_W, MF_CHK_BTN_P, MF_WGT_B, MF_CHK_LBL_P, MF_CHK_ITM_P, text_font, &_mf_menu_size, &_mf_menu_play, menu, renderer, 0, 3, "15x15", "20x20", "30x30"), MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T, mftk_label_new(text_font, "Enemies", renderer), MFTK_GRID_HALIGN_R|MFTK_GRID_VALIGN_T, menu->enemies_text, MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T, mftk_label_new(text_font, "Fog of war", renderer), MFTK_GRID_HALIGN_R|MFTK_GRID_VALIGN_T, mftk_check_new(MF_CHK_BTN_W, MF_CHK_BTN_P, MF_WGT_B, SDL_TRUE, 0, NULL, NULL, &_mf_menu_fow, &_mf_menu_play, menu, renderer), MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T, mftk_label_new(text_font, "Reveal maze", renderer), MFTK_GRID_HALIGN_R|MFTK_GRID_VALIGN_T, mftk_check_new(MF_CHK_BTN_W, MF_CHK_BTN_P, MF_WGT_B, SDL_FALSE, 0, NULL, NULL, &_mf_menu_reveal, &_mf_menu_play, menu, renderer), MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T, mftk_blank_new(), MFTK_GRID_HALIGN_R|MFTK_GRID_VALIGN_T, mftk_grid_new(1, 2, 0, MF_BTN_M, mftk_button_new(text_font, "Quit", MF_BTN_P, MF_WGT_B, &_mf_menu_quit, NULL, renderer), MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T, mftk_button_new(text_font, "Play", MF_BTN_P, MF_WGT_B, &_mf_menu_play, menu, renderer), MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T ), MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T ); return grid; } int mf_menu(SDL_Renderer *renderer) { struct mf_maze *maze = NULL; SDL_Color maze_color; struct _mf_menu menu; char *font_path = NULL; TTF_Font *title_font = NULL; TTF_Font *text_font = NULL; struct mftk_window *win = NULL; int fr; Uint32 beg; SDL_Event event; Uint32 end; Uint32 delay; /* Create maze */ maze = mf_maze_new(time(NULL), MF_WINDOW_W / MF_MENU_MAZE_CELL_W, MF_WINDOW_H / MF_MENU_MAZE_CELL_W, SDL_TRUE); if (maze == NULL) { goto err; } maze_color.r = MF_COLOR_MAZE_R; maze_color.g = MF_COLOR_MAZE_G; maze_color.b = MF_COLOR_MAZE_B; maze_color.a = MF_COLOR_MAZE_A; menu.seed = 59906178L; menu.size = 0; menu.enemies = 8; menu.enemies_custom = SDL_TRUE; menu.fow = SDL_FALSE; menu.reveal = SDL_TRUE; menu.renderer = renderer; font_path = mf_strcat(mf_get_fonts_dir(), "/FifteenTwenty-Bold.ttf"); title_font = TTF_OpenFont(font_path, MF_TITLE_FONT_S); if (title_font == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open font: %s", TTF_GetError()); goto err; } text_font = TTF_OpenFont(font_path, MF_TEXT_FONT_S); if (text_font == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open font: %s", TTF_GetError()); goto err; } free(font_path); font_path = NULL; win = mftk_window_new(0, 0, mftk_box_new(MF_WINDOW_W, MF_WINDOW_H, 0, 0, MF_FORM_P, MF_FORM_B, mftk_grid_new(2, 1, MF_TITLE_M, 0, mftk_label_new(title_font, "Maze Fight", renderer), MFTK_GRID_HALIGN_C|MFTK_GRID_VALIGN_T, _mf_menu_form(renderer, text_font, &menu), MFTK_GRID_HALIGN_C|MFTK_GRID_VALIGN_T ) ) ); TTF_CloseFont(title_font); title_font = NULL; SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); fr = 10; while(1) { beg = SDL_GetTicks(); while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: goto quit; case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_ESCAPE: goto quit; default: break; } default: break; } switch (mftk_window_event(win, &event)) { case 0: break; case 1: goto quit; default: goto err; } } SDL_SetRenderDrawColor(renderer, MF_COLOR_BACK_R, MF_COLOR_BACK_G, MF_COLOR_BACK_B, MF_COLOR_BACK_A); SDL_RenderClear(renderer); mf_maze_render(maze, renderer, &maze_color, MF_MENU_MAZE_CELL_W); mftk_window_render(win, renderer); SDL_RenderPresent(renderer); end = SDL_GetTicks(); if ((Uint32) (1000 / fr) > (end - beg)) { delay = 1000 / fr - (end - beg); } else { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Frame took longer than frame period"); delay = 0; } SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Frame took %u ms, delaying %u ms", end - beg, delay); SDL_Delay(delay); } quit: mftk_window_destroy(&win); free(menu.seed_buf); TTF_CloseFont(text_font); text_font = NULL; mf_maze_destroy(&maze); return 0; err: if (font_path != NULL) { free(font_path); } if (title_font != NULL) { TTF_CloseFont(title_font); } if (text_font != NULL) { TTF_CloseFont(text_font); } mftk_window_destroy(&win); if (menu.seed_buf != NULL) { free(menu.seed_buf); } mf_maze_destroy(&maze); return -1; }