/*
* 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, SDL_TRUE, &_mf_menu_seed, &_mf_menu_play,
menu);
menu->enemies_text = mftk_text_new(MF_DIGITS, 2, menu->enemies_buf,
text_font, 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_BTN_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_BTN_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_BTN_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_BTN_B,
&_mf_menu_quit, NULL, renderer),
MFTK_GRID_HALIGN_L|MFTK_GRID_VALIGN_T,
mftk_button_new(text_font, "Play",
MF_BTN_P, MF_BTN_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;
}