1655 lines
50 KiB
C
1655 lines
50 KiB
C
/* gameplaySP
|
|
*
|
|
* Copyright (C) 2006 Exophase <exophase@gmail.com>
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public Licens e as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "font.h"
|
|
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
|
|
#define MAX_PATH 1024
|
|
|
|
// Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
|
|
|
|
#define FILE_LIST_ROWS 25
|
|
#define FILE_LIST_POSITION 5
|
|
#define DIR_LIST_POSITION (resolution_width * 3 / 4)
|
|
|
|
#ifdef PSP_BUILD
|
|
|
|
#define COLOR_BG color16(2, 8, 10)
|
|
|
|
#define color16(red, green, blue) \
|
|
(blue << 11) | (green << 5) | red \
|
|
|
|
#else
|
|
|
|
#define COLOR_BG color16(0, 0, 0)
|
|
|
|
#define color16(red, green, blue) \
|
|
(red << 11) | (green << 5) | blue \
|
|
|
|
#endif
|
|
|
|
#define COLOR_ROM_INFO color16(22, 36, 26)
|
|
#define COLOR_ACTIVE_ITEM color16(31, 63, 31)
|
|
#define COLOR_INACTIVE_ITEM color16(13, 40, 18)
|
|
#define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
|
|
#define COLOR_HELP_TEXT color16(16, 40, 24)
|
|
|
|
#ifdef PSP_BUILD
|
|
static const char *clock_speed_options[] =
|
|
{
|
|
"33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
|
|
"266MHz", "300MHz", "333MHz"
|
|
};
|
|
#define menu_get_clock_speed() \
|
|
clock_speed = (clock_speed_number + 1) * 33
|
|
#define get_clock_speed_number() \
|
|
clock_speed_number = (clock_speed / 33) - 1
|
|
#else
|
|
static const char *clock_speed_options[] =
|
|
{
|
|
"0"
|
|
};
|
|
#define menu_get_clock_speed()
|
|
#define get_clock_speed_number()
|
|
#endif
|
|
|
|
|
|
int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
|
|
{
|
|
char *dest_str = *((char **)dest_str_ptr);
|
|
char *src_str = *((char **)src_str_ptr);
|
|
|
|
if(src_str[0] == '.')
|
|
return 1;
|
|
|
|
if(dest_str[0] == '.')
|
|
return -1;
|
|
|
|
return strcasecmp(dest_str, src_str);
|
|
}
|
|
|
|
s32 load_file(const char **wildcards, char *result)
|
|
{
|
|
DIR *current_dir;
|
|
struct dirent *current_file;
|
|
struct stat file_info;
|
|
char current_dir_name[MAX_PATH];
|
|
char current_dir_short[81];
|
|
u32 current_dir_length;
|
|
u32 total_filenames_allocated;
|
|
u32 total_dirnames_allocated;
|
|
char **file_list;
|
|
char **dir_list;
|
|
u32 num_files;
|
|
u32 num_dirs;
|
|
char *file_name;
|
|
u32 file_name_length;
|
|
u32 ext_pos = -1;
|
|
u32 chosen_file, chosen_dir;
|
|
s32 return_value = 1;
|
|
s32 current_file_selection;
|
|
s32 current_file_scroll_value;
|
|
u32 current_dir_selection;
|
|
u32 current_dir_scroll_value;
|
|
s32 current_file_in_scroll;
|
|
u32 current_dir_in_scroll;
|
|
u32 current_file_number, current_dir_number;
|
|
u32 current_column = 0;
|
|
u32 repeat;
|
|
u32 i;
|
|
gui_action_type gui_action;
|
|
|
|
while(return_value == 1)
|
|
{
|
|
current_file_selection = 0;
|
|
current_file_scroll_value = 0;
|
|
current_dir_selection = 0;
|
|
current_dir_scroll_value = 0;
|
|
current_file_in_scroll = 0;
|
|
current_dir_in_scroll = 0;
|
|
|
|
total_filenames_allocated = 32;
|
|
total_dirnames_allocated = 32;
|
|
file_list = (char **)malloc(sizeof(char *) * 32);
|
|
dir_list = (char **)malloc(sizeof(char *) * 32);
|
|
memset(file_list, 0, sizeof(char *) * 32);
|
|
memset(dir_list, 0, sizeof(char *) * 32);
|
|
|
|
num_files = 0;
|
|
num_dirs = 0;
|
|
chosen_file = 0;
|
|
chosen_dir = 0;
|
|
|
|
getcwd(current_dir_name, MAX_PATH);
|
|
|
|
current_dir = opendir(current_dir_name);
|
|
|
|
do
|
|
{
|
|
if(current_dir)
|
|
current_file = readdir(current_dir);
|
|
else
|
|
current_file = NULL;
|
|
|
|
if(current_file)
|
|
{
|
|
file_name = current_file->d_name;
|
|
file_name_length = strlen(file_name);
|
|
|
|
if((stat(file_name, &file_info) >= 0) &&
|
|
((file_name[0] != '.') || (file_name[1] == '.')))
|
|
{
|
|
if(S_ISDIR(file_info.st_mode))
|
|
{
|
|
dir_list[num_dirs] = malloc(file_name_length + 1);
|
|
|
|
sprintf(dir_list[num_dirs], "%s", file_name);
|
|
|
|
num_dirs++;
|
|
}
|
|
else
|
|
{
|
|
// Must match one of the wildcards, also ignore the .
|
|
if(file_name_length >= 4)
|
|
{
|
|
if(file_name[file_name_length - 4] == '.')
|
|
ext_pos = file_name_length - 4;
|
|
else
|
|
|
|
if(file_name[file_name_length - 3] == '.')
|
|
ext_pos = file_name_length - 3;
|
|
|
|
else
|
|
ext_pos = 0;
|
|
|
|
for(i = 0; wildcards[i] != NULL; i++)
|
|
{
|
|
if(!strcasecmp((file_name + ext_pos),
|
|
wildcards[i]))
|
|
{
|
|
file_list[num_files] =
|
|
malloc(file_name_length + 1);
|
|
|
|
sprintf(file_list[num_files], "%s", file_name);
|
|
|
|
num_files++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(num_files == total_filenames_allocated)
|
|
{
|
|
file_list = (char **)realloc(file_list, sizeof(char *) *
|
|
total_filenames_allocated * 2);
|
|
memset(file_list + total_filenames_allocated, 0,
|
|
sizeof(char *) * total_filenames_allocated);
|
|
total_filenames_allocated *= 2;
|
|
}
|
|
|
|
if(num_dirs == total_dirnames_allocated)
|
|
{
|
|
dir_list = (char **)realloc(dir_list, sizeof(char *) *
|
|
total_dirnames_allocated * 2);
|
|
memset(dir_list + total_dirnames_allocated, 0,
|
|
sizeof(char *) * total_dirnames_allocated);
|
|
total_dirnames_allocated *= 2;
|
|
}
|
|
}
|
|
} while(current_file);
|
|
|
|
qsort((void *)file_list, num_files, sizeof(char *), sort_function);
|
|
qsort((void *)dir_list, num_dirs, sizeof(char *), sort_function);
|
|
|
|
closedir(current_dir);
|
|
|
|
current_dir_length = strlen(current_dir_name);
|
|
|
|
if(current_dir_length > 80)
|
|
{
|
|
|
|
memcpy(current_dir_short, "...", 3);
|
|
memcpy(current_dir_short + 3,
|
|
current_dir_name + current_dir_length - 77, 77);
|
|
current_dir_short[80] = 0;
|
|
}
|
|
else
|
|
{
|
|
memcpy(current_dir_short, current_dir_name,
|
|
current_dir_length + 1);
|
|
}
|
|
|
|
repeat = 1;
|
|
|
|
if(num_files == 0)
|
|
current_column = 1;
|
|
|
|
clear_screen(COLOR_BG);
|
|
{
|
|
while(repeat)
|
|
{
|
|
flip_screen();
|
|
|
|
print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
|
|
print_string("Press X to return to the main menu.",
|
|
COLOR_HELP_TEXT, COLOR_BG, 20, 260);
|
|
|
|
for(i = 0, current_file_number = i + current_file_scroll_value;
|
|
i < FILE_LIST_ROWS; i++, current_file_number++)
|
|
{
|
|
if(current_file_number < num_files)
|
|
{
|
|
if((current_file_number == current_file_selection) &&
|
|
(current_column == 0))
|
|
{
|
|
print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
|
|
COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
|
|
}
|
|
else
|
|
{
|
|
print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
|
|
COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i = 0, current_dir_number = i + current_dir_scroll_value;
|
|
i < FILE_LIST_ROWS; i++, current_dir_number++)
|
|
{
|
|
if(current_dir_number < num_dirs)
|
|
{
|
|
if((current_dir_number == current_dir_selection) &&
|
|
(current_column == 1))
|
|
{
|
|
print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
|
|
COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
|
|
}
|
|
else
|
|
{
|
|
print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
|
|
COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
|
|
}
|
|
}
|
|
}
|
|
|
|
gui_action = get_gui_input();
|
|
|
|
switch(gui_action)
|
|
{
|
|
case CURSOR_DOWN:
|
|
if(current_column == 0)
|
|
{
|
|
if(current_file_selection < (num_files - 1))
|
|
{
|
|
current_file_selection++;
|
|
if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
|
|
{
|
|
clear_screen(COLOR_BG);
|
|
current_file_scroll_value++;
|
|
}
|
|
else
|
|
{
|
|
current_file_in_scroll++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clear_screen(COLOR_BG);
|
|
current_file_selection = 0;
|
|
current_file_scroll_value = 0;
|
|
current_file_in_scroll = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(current_dir_selection < (num_dirs - 1))
|
|
{
|
|
current_dir_selection++;
|
|
if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
|
|
{
|
|
clear_screen(COLOR_BG);
|
|
current_dir_scroll_value++;
|
|
}
|
|
else
|
|
{
|
|
current_dir_in_scroll++;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case CURSOR_R:
|
|
if (current_column != 0)
|
|
break;
|
|
clear_screen(COLOR_BG);
|
|
current_file_selection += FILE_LIST_ROWS;
|
|
if (current_file_selection > num_files - 1)
|
|
current_file_selection = num_files - 1;
|
|
current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
|
|
if (current_file_scroll_value < 0)
|
|
{
|
|
current_file_scroll_value = 0;
|
|
current_file_in_scroll = current_file_selection;
|
|
}
|
|
else
|
|
{
|
|
current_file_in_scroll = FILE_LIST_ROWS / 2;
|
|
}
|
|
break;
|
|
|
|
case CURSOR_UP:
|
|
if(current_column == 0)
|
|
{
|
|
if(current_file_selection)
|
|
{
|
|
current_file_selection--;
|
|
if(current_file_in_scroll == 0)
|
|
{
|
|
clear_screen(COLOR_BG);
|
|
current_file_scroll_value--;
|
|
}
|
|
else
|
|
{
|
|
current_file_in_scroll--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clear_screen(COLOR_BG);
|
|
current_file_selection = num_files - 1;
|
|
current_file_in_scroll = FILE_LIST_ROWS - 1;
|
|
if (current_file_in_scroll > num_files - 1)
|
|
current_file_in_scroll = num_files - 1;
|
|
current_file_scroll_value = num_files - FILE_LIST_ROWS;
|
|
if (current_file_scroll_value < 0)
|
|
current_file_scroll_value = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(current_dir_selection)
|
|
{
|
|
current_dir_selection--;
|
|
if(current_dir_in_scroll == 0)
|
|
{
|
|
clear_screen(COLOR_BG);
|
|
current_dir_scroll_value--;
|
|
}
|
|
else
|
|
{
|
|
current_dir_in_scroll--;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CURSOR_L:
|
|
if (current_column != 0)
|
|
break;
|
|
clear_screen(COLOR_BG);
|
|
current_file_selection -= FILE_LIST_ROWS;
|
|
if (current_file_selection < 0)
|
|
current_file_selection = 0;
|
|
current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
|
|
if (current_file_scroll_value < 0)
|
|
{
|
|
current_file_scroll_value = 0;
|
|
current_file_in_scroll = current_file_selection;
|
|
}
|
|
else
|
|
{
|
|
current_file_in_scroll = FILE_LIST_ROWS / 2;
|
|
}
|
|
break;
|
|
|
|
case CURSOR_RIGHT:
|
|
if(current_column == 0)
|
|
{
|
|
if(num_dirs != 0)
|
|
current_column = 1;
|
|
}
|
|
break;
|
|
|
|
case CURSOR_LEFT:
|
|
if(current_column == 1)
|
|
{
|
|
if(num_files != 0)
|
|
current_column = 0;
|
|
}
|
|
break;
|
|
|
|
case CURSOR_SELECT:
|
|
if(current_column == 1)
|
|
{
|
|
repeat = 0;
|
|
chdir(dir_list[current_dir_selection]);
|
|
}
|
|
else
|
|
{
|
|
if(num_files != 0)
|
|
{
|
|
repeat = 0;
|
|
return_value = 0;
|
|
strcpy(result, file_list[current_file_selection]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CURSOR_BACK:
|
|
#ifdef PSP_BUILD
|
|
if(!strcmp(current_dir_name, "ms0:/PSP"))
|
|
break;
|
|
#endif
|
|
repeat = 0;
|
|
chdir("..");
|
|
break;
|
|
|
|
case CURSOR_EXIT:
|
|
return_value = -1;
|
|
repeat = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i = 0; i < num_files; i++)
|
|
{
|
|
free(file_list[i]);
|
|
}
|
|
free(file_list);
|
|
|
|
for(i = 0; i < num_dirs; i++)
|
|
{
|
|
free(dir_list[i]);
|
|
}
|
|
free(dir_list);
|
|
}
|
|
|
|
clear_screen(COLOR_BG);
|
|
|
|
return return_value;
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
NUMBER_SELECTION_OPTION = 0x01,
|
|
STRING_SELECTION_OPTION = 0x02,
|
|
SUBMENU_OPTION = 0x04,
|
|
ACTION_OPTION = 0x08,
|
|
} menu_option_type_enum;
|
|
|
|
struct _menu_type
|
|
{
|
|
void (* init_function)();
|
|
void (* passive_function)();
|
|
struct _menu_option_type *options;
|
|
u32 num_options;
|
|
};
|
|
|
|
struct _menu_option_type
|
|
{
|
|
void (* action_function)();
|
|
void (* passive_function)();
|
|
struct _menu_type *sub_menu;
|
|
const char *display_string;
|
|
void *options;
|
|
u32 *current_option;
|
|
u32 num_options;
|
|
const char *help_string;
|
|
u32 line_number;
|
|
menu_option_type_enum option_type;
|
|
};
|
|
|
|
typedef struct _menu_option_type menu_option_type;
|
|
typedef struct _menu_type menu_type;
|
|
|
|
#define make_menu(name, init_function, passive_function) \
|
|
menu_type name##_menu = \
|
|
{ \
|
|
init_function, \
|
|
passive_function, \
|
|
name##_options, \
|
|
sizeof(name##_options) / sizeof(menu_option_type) \
|
|
} \
|
|
|
|
#define gamepad_config_option(display_string, number) \
|
|
{ \
|
|
NULL, \
|
|
menu_fix_gamepad_help, \
|
|
NULL, \
|
|
display_string ": %s", \
|
|
gamepad_config_buttons, \
|
|
gamepad_config_map + gamepad_config_line_to_button[number], \
|
|
sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
|
|
gamepad_help[gamepad_config_map[ \
|
|
gamepad_config_line_to_button[number]]], \
|
|
number, \
|
|
STRING_SELECTION_OPTION \
|
|
} \
|
|
|
|
#define analog_config_option(display_string, number) \
|
|
{ \
|
|
NULL, \
|
|
menu_fix_gamepad_help, \
|
|
NULL, \
|
|
display_string ": %s", \
|
|
gamepad_config_buttons, \
|
|
gamepad_config_map + number + 12, \
|
|
sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
|
|
gamepad_help[gamepad_config_map[number + 12]], \
|
|
number + 2, \
|
|
STRING_SELECTION_OPTION \
|
|
} \
|
|
|
|
#define cheat_option(number) \
|
|
{ \
|
|
NULL, \
|
|
NULL, \
|
|
NULL, \
|
|
cheat_format_str[number], \
|
|
enable_disable_options, \
|
|
&(cheats[number].cheat_active), \
|
|
2, \
|
|
"Activate/deactivate this cheat code.", \
|
|
number, \
|
|
STRING_SELECTION_OPTION \
|
|
} \
|
|
|
|
#define action_option(action_function, passive_function, display_string, \
|
|
help_string, line_number) \
|
|
{ \
|
|
action_function, \
|
|
passive_function, \
|
|
NULL, \
|
|
display_string, \
|
|
NULL, \
|
|
NULL, \
|
|
0, \
|
|
help_string, \
|
|
line_number, \
|
|
ACTION_OPTION \
|
|
} \
|
|
|
|
#define submenu_option(sub_menu, display_string, help_string, line_number) \
|
|
{ \
|
|
NULL, \
|
|
NULL, \
|
|
sub_menu, \
|
|
display_string, \
|
|
NULL, \
|
|
NULL, \
|
|
sizeof(sub_menu) / sizeof(menu_option_type), \
|
|
help_string, \
|
|
line_number, \
|
|
SUBMENU_OPTION \
|
|
} \
|
|
|
|
#define selection_option(passive_function, display_string, options, \
|
|
option_ptr, num_options, help_string, line_number, type) \
|
|
{ \
|
|
NULL, \
|
|
passive_function, \
|
|
NULL, \
|
|
display_string, \
|
|
options, \
|
|
option_ptr, \
|
|
num_options, \
|
|
help_string, \
|
|
line_number, \
|
|
type \
|
|
} \
|
|
|
|
#define action_selection_option(action_function, passive_function, \
|
|
display_string, options, option_ptr, num_options, help_string, line_number, \
|
|
type) \
|
|
{ \
|
|
action_function, \
|
|
passive_function, \
|
|
NULL, \
|
|
display_string, \
|
|
options, \
|
|
option_ptr, \
|
|
num_options, \
|
|
help_string, \
|
|
line_number, \
|
|
type | ACTION_OPTION \
|
|
} \
|
|
|
|
|
|
#define string_selection_option(passive_function, display_string, options, \
|
|
option_ptr, num_options, help_string, line_number) \
|
|
selection_option(passive_function, display_string ": %s", options, \
|
|
option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
|
|
|
|
#define numeric_selection_option(passive_function, display_string, \
|
|
option_ptr, num_options, help_string, line_number) \
|
|
selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
|
|
num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
|
|
|
|
#define string_selection_action_option(action_function, passive_function, \
|
|
display_string, options, option_ptr, num_options, help_string, line_number) \
|
|
action_selection_option(action_function, passive_function, \
|
|
display_string ": %s", options, option_ptr, num_options, help_string, \
|
|
line_number, STRING_SELECTION_OPTION) \
|
|
|
|
#define numeric_selection_action_option(action_function, passive_function, \
|
|
display_string, option_ptr, num_options, help_string, line_number) \
|
|
action_selection_option(action_function, passive_function, \
|
|
display_string ": %d", NULL, option_ptr, num_options, help_string, \
|
|
line_number, NUMBER_SELECTION_OPTION) \
|
|
|
|
#define numeric_selection_action_hide_option(action_function, \
|
|
passive_function, display_string, option_ptr, num_options, help_string, \
|
|
line_number) \
|
|
action_selection_option(action_function, passive_function, \
|
|
display_string, NULL, option_ptr, num_options, help_string, \
|
|
line_number, NUMBER_SELECTION_OPTION) \
|
|
|
|
|
|
#define GAMEPAD_MENU_WIDTH 15
|
|
|
|
#ifdef PSP_BUILD
|
|
|
|
u32 gamepad_config_line_to_button[] =
|
|
{ 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
|
|
|
|
#endif
|
|
|
|
static const char *scale_options[] =
|
|
{
|
|
#ifdef PSP_BUILD
|
|
"unscaled 3:2", "scaled 3:2", "fullscreen 16:9"
|
|
#else
|
|
"unscaled 3:2"
|
|
#endif
|
|
};
|
|
|
|
const char *filter2_options[] =
|
|
{
|
|
"none", "scale2x", "scale3x", "eagle2x"
|
|
};
|
|
|
|
#ifndef PSP_BUILD
|
|
static const char *audio_buffer_options[] =
|
|
{
|
|
"16 bytes", "32 bytes", "64 bytes",
|
|
"128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
|
|
"4096 bytes", "8192 bytes", "16284 bytes"
|
|
};
|
|
#else
|
|
const char *audio_buffer_options[] =
|
|
{
|
|
"3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
|
|
"8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
|
|
};
|
|
#endif
|
|
|
|
|
|
s32 load_game_config_file()
|
|
{
|
|
char game_config_filename[512];
|
|
u32 file_loaded = 0;
|
|
u32 i;
|
|
make_rpath(game_config_filename, sizeof(game_config_filename), ".cfg");
|
|
|
|
file_open(game_config_file, game_config_filename, read);
|
|
|
|
if(file_check_valid(game_config_file))
|
|
{
|
|
u32 file_size = file_length(game_config_filename, game_config_file);
|
|
|
|
// Sanity check: File size must be the right size
|
|
if(file_size == 56)
|
|
{
|
|
u32 file_options[file_size / 4];
|
|
|
|
file_read_array(game_config_file, file_options);
|
|
current_frameskip_type = file_options[0] % 3;
|
|
frameskip_value = file_options[1];
|
|
random_skip = file_options[2] % 2;
|
|
clock_speed = file_options[3];
|
|
|
|
if(clock_speed > 333)
|
|
clock_speed = 333;
|
|
|
|
if(clock_speed < 33)
|
|
clock_speed = 33;
|
|
|
|
if(frameskip_value < 0)
|
|
frameskip_value = 0;
|
|
|
|
if(frameskip_value > 99)
|
|
frameskip_value = 99;
|
|
|
|
for(i = 0; i < 10; i++)
|
|
{
|
|
cheats[i].cheat_active = file_options[4 + i] % 2;
|
|
cheats[i].cheat_name[0] = 0;
|
|
}
|
|
|
|
file_close(game_config_file);
|
|
file_loaded = 1;
|
|
}
|
|
}
|
|
|
|
if(file_loaded)
|
|
return 0;
|
|
|
|
current_frameskip_type = auto_frameskip;
|
|
frameskip_value = 4;
|
|
random_skip = 0;
|
|
clock_speed = default_clock_speed;
|
|
|
|
for(i = 0; i < 10; i++)
|
|
{
|
|
cheats[i].cheat_active = 0;
|
|
cheats[i].cheat_name[0] = 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
enum file_options {
|
|
fo_screen_scale = 0,
|
|
fo_screen_filter,
|
|
fo_global_enable_audio,
|
|
fo_audio_buffer_size,
|
|
fo_update_backup_flag,
|
|
fo_global_enable_analog,
|
|
fo_analog_sensitivity_level,
|
|
fo_screen_filter2,
|
|
fo_main_option_count,
|
|
};
|
|
|
|
#ifdef PC_BUILD
|
|
#define PLAT_BUTTON_COUNT 0
|
|
#endif
|
|
#define FILE_OPTION_COUNT (fo_main_option_count + PLAT_BUTTON_COUNT)
|
|
|
|
s32 load_config_file()
|
|
{
|
|
char config_path[512];
|
|
|
|
sprintf(config_path, "%s" PATH_SEPARATOR "%s", main_path, GPSP_CONFIG_FILENAME);
|
|
|
|
file_open(config_file, config_path, read);
|
|
|
|
if(file_check_valid(config_file))
|
|
{
|
|
u32 file_size = file_length(config_path, config_file);
|
|
|
|
// Sanity check: File size must be the right size
|
|
if(file_size == FILE_OPTION_COUNT * 4)
|
|
{
|
|
u32 file_options[file_size / 4];
|
|
file_read_array(config_file, file_options);
|
|
|
|
screen_scale = file_options[fo_screen_scale] %
|
|
(sizeof(scale_options) / sizeof(scale_options[0]));
|
|
screen_filter = file_options[fo_screen_filter] % 2;
|
|
global_enable_audio = file_options[fo_global_enable_audio] % 2;
|
|
screen_filter2 = file_options[fo_screen_filter2] %
|
|
(sizeof(filter2_options) / sizeof(filter2_options[0]));
|
|
|
|
audio_buffer_size_number = file_options[fo_audio_buffer_size] %
|
|
(sizeof(audio_buffer_options) / sizeof(audio_buffer_options[0]));
|
|
|
|
update_backup_flag = file_options[fo_update_backup_flag] % 2;
|
|
global_enable_analog = file_options[fo_global_enable_analog] % 2;
|
|
analog_sensitivity_level = file_options[fo_analog_sensitivity_level] % 8;
|
|
|
|
#ifdef PSP_BUILD
|
|
scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
|
|
#endif
|
|
|
|
// Sanity check: Make sure there's a MENU or FRAMESKIP
|
|
// key, if not assign to triangle
|
|
|
|
#ifndef PC_BUILD
|
|
u32 i;
|
|
s32 menu_button = -1;
|
|
for(i = 0; i < PLAT_BUTTON_COUNT; i++)
|
|
{
|
|
gamepad_config_map[i] = file_options[fo_main_option_count + i] %
|
|
(BUTTON_ID_NONE + 1);
|
|
|
|
if(gamepad_config_map[i] == BUTTON_ID_MENU)
|
|
{
|
|
menu_button = i;
|
|
}
|
|
}
|
|
|
|
if(menu_button == -1 && PLAT_MENU_BUTTON >= 0)
|
|
{
|
|
gamepad_config_map[PLAT_MENU_BUTTON] = BUTTON_ID_MENU;
|
|
}
|
|
#endif
|
|
|
|
file_close(config_file);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
s32 save_game_config_file()
|
|
{
|
|
char game_config_filename[512];
|
|
u32 i;
|
|
|
|
make_rpath(game_config_filename, sizeof(game_config_filename), ".cfg");
|
|
|
|
file_open(game_config_file, game_config_filename, write);
|
|
|
|
if(file_check_valid(game_config_file))
|
|
{
|
|
u32 file_options[14];
|
|
|
|
file_options[0] = current_frameskip_type;
|
|
file_options[1] = frameskip_value;
|
|
file_options[2] = random_skip;
|
|
file_options[3] = clock_speed;
|
|
|
|
for(i = 0; i < 10; i++)
|
|
{
|
|
file_options[4 + i] = cheats[i].cheat_active;
|
|
}
|
|
|
|
file_write_array(game_config_file, file_options);
|
|
|
|
file_close(game_config_file);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
s32 save_config_file()
|
|
{
|
|
char config_path[512];
|
|
|
|
sprintf(config_path, "%s" PATH_SEPARATOR "%s", main_path, GPSP_CONFIG_FILENAME);
|
|
|
|
file_open(config_file, config_path, write);
|
|
|
|
save_game_config_file();
|
|
|
|
if(file_check_valid(config_file))
|
|
{
|
|
u32 file_options[FILE_OPTION_COUNT];
|
|
|
|
file_options[fo_screen_scale] = screen_scale;
|
|
file_options[fo_screen_filter] = screen_filter;
|
|
file_options[fo_global_enable_audio] = global_enable_audio;
|
|
file_options[fo_audio_buffer_size] = audio_buffer_size_number;
|
|
file_options[fo_update_backup_flag] = update_backup_flag;
|
|
file_options[fo_global_enable_analog] = global_enable_analog;
|
|
file_options[fo_analog_sensitivity_level] = analog_sensitivity_level;
|
|
file_options[fo_screen_filter2] = screen_filter2;
|
|
|
|
#ifndef PC_BUILD
|
|
u32 i;
|
|
for(i = 0; i < PLAT_BUTTON_COUNT; i++)
|
|
{
|
|
file_options[fo_main_option_count + i] = gamepad_config_map[i];
|
|
}
|
|
#endif
|
|
|
|
file_write_array(config_file, file_options);
|
|
|
|
file_close(config_file);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
MAIN_MENU,
|
|
GAMEPAD_MENU,
|
|
SAVESTATE_MENU,
|
|
FRAMESKIP_MENU,
|
|
CHEAT_MENU
|
|
} menu_enum;
|
|
|
|
u32 savestate_slot = 0;
|
|
|
|
void get_savestate_snapshot(char *savestate_filename)
|
|
{
|
|
u16 snapshot_buffer[240 * 160];
|
|
char savestate_timestamp_string[80];
|
|
|
|
file_open(savestate_file, savestate_filename, read);
|
|
|
|
if(file_check_valid(savestate_file))
|
|
{
|
|
const char weekday_strings[7][11] =
|
|
{
|
|
"Sunday", "Monday", "Tuesday", "Wednesday",
|
|
"Thursday", "Friday", "Saturday"
|
|
};
|
|
time_t savestate_time_flat;
|
|
struct tm *current_time;
|
|
file_read_array(savestate_file, snapshot_buffer);
|
|
file_read_variable(savestate_file, savestate_time_flat);
|
|
|
|
file_close(savestate_file);
|
|
|
|
current_time = localtime(&savestate_time_flat);
|
|
sprintf(savestate_timestamp_string,
|
|
"%s %02d/%02d/%04d %02d:%02d:%02d ",
|
|
weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
|
|
current_time->tm_mday, current_time->tm_year + 1900,
|
|
current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
|
|
|
|
savestate_timestamp_string[40] = 0;
|
|
print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
|
|
10, 40);
|
|
}
|
|
else
|
|
{
|
|
memset(snapshot_buffer, 0, 240 * 160 * 2);
|
|
print_string_ext("No savestate in this slot.",
|
|
0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0, 0, FONT_HEIGHT);
|
|
print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
|
|
COLOR_BG, 10, 40);
|
|
}
|
|
|
|
blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
|
|
}
|
|
|
|
void get_savestate_filename_noshot(u32 slot, char *name_buffer)
|
|
{
|
|
char savestate_ext[16];
|
|
|
|
sprintf(savestate_ext, "%d.svs", slot);
|
|
make_rpath(name_buffer, 512, savestate_ext);
|
|
}
|
|
|
|
void get_savestate_filename(u32 slot, char *name_buffer)
|
|
{
|
|
get_savestate_filename_noshot(slot, name_buffer);
|
|
get_savestate_snapshot(name_buffer);
|
|
}
|
|
|
|
#ifdef PSP_BUILD
|
|
void _flush_cache()
|
|
{
|
|
invalidate_all_cache();
|
|
}
|
|
#endif
|
|
|
|
u32 menu(u16 *original_screen)
|
|
{
|
|
char print_buffer[81];
|
|
u32 clock_speed_number;
|
|
gui_action_type gui_action;
|
|
u32 i;
|
|
u32 repeat = 1;
|
|
u32 return_value = 0;
|
|
u32 first_load = 0;
|
|
char current_savestate_filename[512];
|
|
char line_buffer[80];
|
|
char cheat_format_str[10][41];
|
|
|
|
menu_type *current_menu;
|
|
menu_option_type *current_option;
|
|
menu_option_type *display_option;
|
|
u32 current_option_num;
|
|
|
|
auto void choose_menu();
|
|
auto void clear_help();
|
|
|
|
#ifndef PC_BUILD
|
|
static const char * const gamepad_help[] =
|
|
{
|
|
"Up button on GBA d-pad.",
|
|
"Down button on GBA d-pad.",
|
|
"Left button on GBA d-pad.",
|
|
"Right button on GBA d-pad.",
|
|
"A button on GBA.",
|
|
"B button on GBA.",
|
|
"Left shoulder button on GBA.",
|
|
"Right shoulder button on GBA.",
|
|
"Start button on GBA.",
|
|
"Select button on GBA.",
|
|
"Brings up the options menu.",
|
|
"Toggles fastforward on/off.",
|
|
"Loads the game state from the current slot.",
|
|
"Saves the game state to the current slot.",
|
|
"Rapidly press/release the A button on GBA.",
|
|
"Rapidly press/release the B button on GBA.",
|
|
"Rapidly press/release the L shoulder on GBA.",
|
|
"Rapidly press/release the R shoulder on GBA.",
|
|
"Increases the volume.",
|
|
"Decreases the volume.",
|
|
"Displays virtual/drawn frames per second.",
|
|
"Does nothing."
|
|
};
|
|
|
|
static const char *gamepad_config_buttons[] =
|
|
{
|
|
"UP",
|
|
"DOWN",
|
|
"LEFT",
|
|
"RIGHT",
|
|
"A",
|
|
"B",
|
|
"L",
|
|
"R",
|
|
"START",
|
|
"SELECT",
|
|
"MENU",
|
|
"FASTFORWARD",
|
|
"LOAD STATE",
|
|
"SAVE STATE",
|
|
"RAPIDFIRE A",
|
|
"RAPIDFIRE B",
|
|
"RAPIDFIRE L",
|
|
"RAPIDFIRE R",
|
|
"VOLUME UP",
|
|
"VOLUME DOWN",
|
|
"DISPLAY FPS",
|
|
"NOTHING"
|
|
};
|
|
#endif
|
|
|
|
void menu_update_clock()
|
|
{
|
|
get_clock_speed_number();
|
|
if (clock_speed_number < 0 || clock_speed_number >=
|
|
sizeof(clock_speed_options) / sizeof(clock_speed_options[0]))
|
|
{
|
|
clock_speed = default_clock_speed;
|
|
get_clock_speed_number();
|
|
}
|
|
}
|
|
|
|
void menu_exit()
|
|
{
|
|
if(!first_load)
|
|
repeat = 0;
|
|
}
|
|
|
|
void menu_quit()
|
|
{
|
|
menu_get_clock_speed();
|
|
save_config_file();
|
|
quit();
|
|
}
|
|
|
|
void menu_load()
|
|
{
|
|
const char *file_ext[] = { ".gba", ".bin", ".zip", NULL };
|
|
char load_filename[512];
|
|
save_game_config_file();
|
|
if(load_file(file_ext, load_filename) != -1)
|
|
{
|
|
if(load_gamepak(load_filename) == -1)
|
|
{
|
|
quit();
|
|
}
|
|
reset_gba();
|
|
return_value = 1;
|
|
repeat = 0;
|
|
reg[CHANGED_PC_STATUS] = 1;
|
|
menu_update_clock();
|
|
}
|
|
}
|
|
|
|
void menu_restart()
|
|
{
|
|
if(!first_load)
|
|
{
|
|
reset_gba();
|
|
reg[CHANGED_PC_STATUS] = 1;
|
|
return_value = 1;
|
|
repeat = 0;
|
|
}
|
|
}
|
|
|
|
void menu_change_state()
|
|
{
|
|
get_savestate_filename(savestate_slot, current_savestate_filename);
|
|
}
|
|
|
|
void menu_save_state()
|
|
{
|
|
if(!first_load)
|
|
{
|
|
get_savestate_filename_noshot(savestate_slot,
|
|
current_savestate_filename);
|
|
save_state(current_savestate_filename, original_screen);
|
|
}
|
|
menu_change_state();
|
|
}
|
|
|
|
void menu_load_state()
|
|
{
|
|
if(!first_load)
|
|
{
|
|
load_state(current_savestate_filename);
|
|
return_value = 1;
|
|
repeat = 0;
|
|
}
|
|
}
|
|
|
|
void menu_load_state_file()
|
|
{
|
|
const char *file_ext[] = { ".svs", NULL };
|
|
char load_filename[512];
|
|
if(load_file(file_ext, load_filename) != -1)
|
|
{
|
|
load_state(load_filename);
|
|
return_value = 1;
|
|
repeat = 0;
|
|
}
|
|
else
|
|
{
|
|
choose_menu(current_menu);
|
|
}
|
|
}
|
|
|
|
void menu_fix_gamepad_help()
|
|
{
|
|
#ifndef PC_BUILD
|
|
clear_help();
|
|
current_option->help_string =
|
|
gamepad_help[gamepad_config_map[
|
|
gamepad_config_line_to_button[current_option_num]]];
|
|
#endif
|
|
}
|
|
|
|
void submenu_graphics_sound()
|
|
{
|
|
|
|
}
|
|
|
|
void submenu_cheats_misc()
|
|
{
|
|
|
|
}
|
|
|
|
void submenu_gamepad()
|
|
{
|
|
|
|
}
|
|
|
|
void submenu_analog()
|
|
{
|
|
|
|
}
|
|
|
|
void submenu_savestate()
|
|
{
|
|
print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
|
|
menu_change_state();
|
|
}
|
|
|
|
void submenu_main()
|
|
{
|
|
strncpy(print_buffer, gamepak_filename, 80);
|
|
print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
|
|
sprintf(print_buffer, "%s %s %s", gamepak_title,
|
|
gamepak_code, gamepak_maker);
|
|
print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
|
|
|
|
get_savestate_filename_noshot(savestate_slot,
|
|
current_savestate_filename);
|
|
}
|
|
|
|
const char *yes_no_options[] = { "no", "yes" };
|
|
const char *enable_disable_options[] = { "disabled", "enabled" };
|
|
|
|
const char *frameskip_options[] = { "automatic", "manual", "off" };
|
|
const char *frameskip_variation_options[] = { "uniform", "random" };
|
|
|
|
static const char *update_backup_options[] = { "Exit only", "Automatic" };
|
|
|
|
// Marker for help information, don't go past this mark (except \n)------*
|
|
menu_option_type graphics_sound_options[] =
|
|
{
|
|
string_selection_option(NULL, "Display scaling", scale_options,
|
|
(u32 *)(&screen_scale),
|
|
sizeof(scale_options) / sizeof(scale_options[0]),
|
|
"Determines how the GBA screen is resized in relation to the\n"
|
|
"entire screen."
|
|
#ifdef PSP_BUILD
|
|
" Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
|
|
"aspect ratio scaled to fill the height of the PSP screen, and\n"
|
|
"fullscreen to fill the entire PSP screen."
|
|
#endif
|
|
"", 2),
|
|
|
|
string_selection_option(NULL, "Screen filtering", yes_no_options,
|
|
(u32 *)(&screen_filter), 2,
|
|
"Determines whether or not filtering should be used when\n"
|
|
"scaling the screen. Selecting this will produce a more even and\n"
|
|
"smooth image, at the cost of being blurry and having less vibrant\n"
|
|
"colors.", 3),
|
|
string_selection_option(NULL, "Scaling filter", filter2_options,
|
|
(u32 *)(&screen_filter2),
|
|
sizeof(filter2_options) / sizeof(filter2_options[0]),
|
|
"Optional pixel art scaling filter", 4),
|
|
string_selection_option(NULL, "Frameskip type", frameskip_options,
|
|
(u32 *)(¤t_frameskip_type), 3,
|
|
"Determines what kind of frameskipping to use.\n"
|
|
"Frameskipping may improve emulation speed of many games.\n"
|
|
"Off: Do not skip any frames.\n"
|
|
"Auto: Skip up to N frames (see next opt) as needed.\n"
|
|
"Manual: Always render only 1 out of N + 1 frames."
|
|
, 5),
|
|
numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
|
|
"For auto frameskip, determines the maximum number of frames that\n"
|
|
"are allowed to be skipped consecutively.\n"
|
|
"For manual frameskip, determines the number of frames that will\n"
|
|
"always be skipped."
|
|
"", 6),
|
|
string_selection_option(NULL, "Framskip variation",
|
|
frameskip_variation_options, &random_skip, 2,
|
|
"If objects in the game flicker at a regular rate certain manual\n"
|
|
"frameskip values may cause them to normally disappear. Change this\n"
|
|
"value to 'random' to avoid this. Do not use otherwise, as it tends\n"
|
|
"to make the image quality worse, especially in high motion games."
|
|
"", 7),
|
|
string_selection_option(NULL, "Audio output", yes_no_options,
|
|
&global_enable_audio, 2,
|
|
"Select 'no' to turn off all audio output. This will\n"
|
|
"not result in a significant change in performance.", 9),
|
|
#ifndef PSP_BUILD
|
|
string_selection_option(NULL, "Audio buffer", audio_buffer_options,
|
|
&audio_buffer_size_number, 11,
|
|
#else
|
|
string_selection_option(NULL, "Audio buffer", audio_buffer_options,
|
|
&audio_buffer_size_number, 10,
|
|
#endif
|
|
|
|
#ifdef PSP_BUILD
|
|
"Set the size (in bytes) of the audio buffer. Larger values may result\n"
|
|
"in slightly better performance at the cost of latency; the lowest\n"
|
|
"value will give the most responsive audio.\n"
|
|
"This option requires gpSP to be restarted before it will take effect.",
|
|
#else
|
|
"Set the size (in bytes) of the audio buffer.\n"
|
|
"This option requires gpSP restart to take effect.\n"
|
|
"Settable values may be limited by SDL implementation.",
|
|
#endif
|
|
10),
|
|
submenu_option(NULL, "Back", "Return to the main menu.", 12)
|
|
};
|
|
|
|
make_menu(graphics_sound, submenu_graphics_sound, NULL);
|
|
|
|
menu_option_type cheats_misc_options[] =
|
|
{
|
|
cheat_option(0),
|
|
cheat_option(1),
|
|
cheat_option(2),
|
|
cheat_option(3),
|
|
cheat_option(4),
|
|
cheat_option(5),
|
|
cheat_option(6),
|
|
cheat_option(7),
|
|
cheat_option(8),
|
|
cheat_option(9),
|
|
#if defined(PSP_BUILD)
|
|
string_selection_option(NULL, "Clock speed",
|
|
clock_speed_options, &clock_speed_number,
|
|
sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
|
|
"Change the clock speed of the device. Higher clock\n"
|
|
"speed will yield better performance, but will drain\n"
|
|
"battery life further.", 11),
|
|
#endif
|
|
string_selection_option(NULL, "Update backup",
|
|
update_backup_options, &update_backup_flag, 2,
|
|
"Determines when in-game save files should be written back to\n"
|
|
"card. If set to 'automatic' writebacks will occur shortly after\n"
|
|
"the game's backup is altered. On 'exit only' it will only be\n"
|
|
"written back when you exit from this menu.\n"
|
|
#ifdef PSP
|
|
"(NOT from using the home button), use the latter with extreme care."
|
|
#endif
|
|
"", 12),
|
|
submenu_option(NULL, "Back", "Return to the main menu.", 14)
|
|
};
|
|
|
|
make_menu(cheats_misc, submenu_cheats_misc, NULL);
|
|
|
|
menu_option_type savestate_options[] =
|
|
{
|
|
numeric_selection_action_hide_option(menu_load_state, menu_change_state,
|
|
"Load savestate from current slot", &savestate_slot, 10,
|
|
"Select to load the game state from the current slot\n"
|
|
"for this game.\n"
|
|
"Press left + right to change the current slot.", 6),
|
|
numeric_selection_action_hide_option(menu_save_state, menu_change_state,
|
|
"Save savestate to current slot", &savestate_slot, 10,
|
|
"Select to save the game state to the current slot\n"
|
|
"for this game.\n"
|
|
"Press left + right to change the current slot.", 7),
|
|
numeric_selection_action_hide_option(menu_load_state_file,
|
|
menu_change_state,
|
|
"Load savestate from file", &savestate_slot, 10,
|
|
"Restore gameplay from a savestate file.\n"
|
|
"Note: The same file used to save the state must be\n"
|
|
"present.\n", 9),
|
|
numeric_selection_option(menu_change_state,
|
|
"Current savestate slot", &savestate_slot, 10,
|
|
"Change the current savestate slot.\n", 11),
|
|
submenu_option(NULL, "Back", "Return to the main menu.", 13)
|
|
};
|
|
|
|
make_menu(savestate, submenu_savestate, NULL);
|
|
|
|
#ifdef PSP_BUILD
|
|
|
|
menu_option_type gamepad_config_options[] =
|
|
{
|
|
gamepad_config_option("D-pad up ", 0),
|
|
gamepad_config_option("D-pad down ", 1),
|
|
gamepad_config_option("D-pad left ", 2),
|
|
gamepad_config_option("D-pad right ", 3),
|
|
gamepad_config_option("Circle ", 4),
|
|
gamepad_config_option("Cross ", 5),
|
|
gamepad_config_option("Square ", 6),
|
|
gamepad_config_option("Triangle ", 7),
|
|
gamepad_config_option("Left Trigger ", 8),
|
|
gamepad_config_option("Right Trigger", 9),
|
|
gamepad_config_option("Start ", 10),
|
|
gamepad_config_option("Select ", 11),
|
|
submenu_option(NULL, "Back", "Return to the main menu.", 13)
|
|
};
|
|
|
|
|
|
menu_option_type analog_config_options[] =
|
|
{
|
|
analog_config_option("Analog up ", 0),
|
|
analog_config_option("Analog down ", 1),
|
|
analog_config_option("Analog left ", 2),
|
|
analog_config_option("Analog right", 3),
|
|
string_selection_option(NULL, "Enable analog", yes_no_options,
|
|
&global_enable_analog, 2,
|
|
"Select 'no' to block analog input entirely.", 7),
|
|
numeric_selection_option(NULL, "Analog sensitivity",
|
|
&analog_sensitivity_level, 10,
|
|
"Determine sensitivity/responsiveness of the analog input.\n"
|
|
"Lower numbers are less sensitive.", 8),
|
|
submenu_option(NULL, "Back", "Return to the main menu.", 11)
|
|
};
|
|
|
|
#endif
|
|
|
|
#if defined(PC_BUILD)
|
|
|
|
menu_option_type gamepad_config_options[] =
|
|
{
|
|
submenu_option(NULL, "Back", "Return to the main menu.", 13)
|
|
};
|
|
|
|
menu_option_type analog_config_options[] =
|
|
{
|
|
submenu_option(NULL, "Back", "Return to the main menu.", 11)
|
|
};
|
|
|
|
#endif
|
|
|
|
make_menu(gamepad_config, submenu_gamepad, NULL);
|
|
make_menu(analog_config, submenu_analog, NULL);
|
|
|
|
menu_option_type main_options[] =
|
|
{
|
|
submenu_option(&graphics_sound_menu, "Graphics and Sound options",
|
|
"Select to set display parameters and frameskip\n"
|
|
"behavior, audio on/off, buffer size, and filtering.", 0),
|
|
numeric_selection_action_option(menu_load_state, NULL,
|
|
"Load state from slot", &savestate_slot, 10,
|
|
"Select to load the game state from the current slot\n"
|
|
"for this game, if it exists.\n"
|
|
"Press left + right to change the current slot.", 2),
|
|
numeric_selection_action_option(menu_save_state, NULL,
|
|
"Save state to slot", &savestate_slot, 10,
|
|
"Select to save the game state to the current slot\n"
|
|
"for this game. See the extended menu for more info.\n"
|
|
"Press left + right to change the current slot.", 3),
|
|
submenu_option(&savestate_menu, "Savestate options",
|
|
"Select to enter a menu for loading, saving, and\n"
|
|
"viewing the currently active savestate for this game\n"
|
|
"(or to load a savestate file from another game)", 4),
|
|
submenu_option(&gamepad_config_menu, "Configure gamepad input",
|
|
"Select to change the in-game behavior of buttons\n"
|
|
"and d-pad.", 6),
|
|
submenu_option(&analog_config_menu, "Configure analog input",
|
|
"Select to change the in-game behavior of the analog nub.", 7),
|
|
submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
|
|
"Select to manage cheats, set backup behavior,\n"
|
|
"and set device clock speed.", 9),
|
|
action_option(menu_load, NULL, "Load new game",
|
|
"Select to load a new game\n"
|
|
"(will exit a game if currently playing).", 11),
|
|
action_option(menu_restart, NULL, "Restart game",
|
|
"Select to reset the GBA with the current game\n"
|
|
"loaded.", 12),
|
|
action_option(menu_exit, NULL, "Return to game",
|
|
"Select to exit this menu and resume gameplay.", 13),
|
|
action_option(menu_quit, NULL, "Exit gpSP",
|
|
"Select to exit gpSP and return to the menu.", 15)
|
|
};
|
|
|
|
make_menu(main, submenu_main, NULL);
|
|
|
|
void choose_menu(menu_type *new_menu)
|
|
{
|
|
if(new_menu == NULL)
|
|
new_menu = &main_menu;
|
|
|
|
clear_screen(COLOR_BG);
|
|
|
|
blit_to_screen(original_screen, 240, 160, 230, 40);
|
|
|
|
current_menu = new_menu;
|
|
current_option = new_menu->options;
|
|
current_option_num = 0;
|
|
if(current_menu->init_function)
|
|
current_menu->init_function();
|
|
}
|
|
|
|
void clear_help()
|
|
{
|
|
for(i = 0; i < 6; i++)
|
|
{
|
|
print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
|
|
}
|
|
}
|
|
|
|
menu_update_clock();
|
|
video_resolution_large();
|
|
|
|
SDL_LockMutex(sound_mutex);
|
|
SDL_PauseAudio(1);
|
|
|
|
SDL_UnlockMutex(sound_mutex);
|
|
|
|
if(gamepak_filename[0] == 0)
|
|
{
|
|
first_load = 1;
|
|
memset(original_screen, 0x00, 240 * 160 * 2);
|
|
print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
|
|
60, 75,original_screen, 240, 0, 0, FONT_HEIGHT);
|
|
}
|
|
|
|
choose_menu(&main_menu);
|
|
|
|
for(i = 0; i < 10; i++)
|
|
{
|
|
if(i >= num_cheats)
|
|
{
|
|
sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
|
|
}
|
|
else
|
|
{
|
|
sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
|
|
cheats[i].cheat_name);
|
|
}
|
|
}
|
|
|
|
current_menu->init_function();
|
|
|
|
while(repeat)
|
|
{
|
|
display_option = current_menu->options;
|
|
|
|
for(i = 0; i < current_menu->num_options; i++, display_option++)
|
|
{
|
|
if(display_option->option_type & NUMBER_SELECTION_OPTION)
|
|
{
|
|
sprintf(line_buffer, display_option->display_string,
|
|
*(display_option->current_option));
|
|
}
|
|
else
|
|
|
|
if(display_option->option_type & STRING_SELECTION_OPTION)
|
|
{
|
|
sprintf(line_buffer, display_option->display_string,
|
|
((u32 *)display_option->options)[*(display_option->current_option)]);
|
|
}
|
|
else
|
|
{
|
|
strcpy(line_buffer, display_option->display_string);
|
|
}
|
|
|
|
if(display_option == current_option)
|
|
{
|
|
print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 6,
|
|
(display_option->line_number * 10) + 40, 36);
|
|
}
|
|
else
|
|
{
|
|
print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 6,
|
|
(display_option->line_number * 10) + 40, 36);
|
|
}
|
|
}
|
|
|
|
print_string(current_option->help_string, COLOR_HELP_TEXT,
|
|
COLOR_BG, 8, 210);
|
|
|
|
flip_screen();
|
|
|
|
gui_action = get_gui_input();
|
|
|
|
switch(gui_action)
|
|
{
|
|
case CURSOR_DOWN:
|
|
current_option_num = (current_option_num + 1) %
|
|
current_menu->num_options;
|
|
|
|
current_option = current_menu->options + current_option_num;
|
|
clear_help();
|
|
break;
|
|
|
|
case CURSOR_UP:
|
|
if(current_option_num)
|
|
current_option_num--;
|
|
else
|
|
current_option_num = current_menu->num_options - 1;
|
|
|
|
current_option = current_menu->options + current_option_num;
|
|
clear_help();
|
|
break;
|
|
|
|
case CURSOR_RIGHT:
|
|
if(current_option->option_type & (NUMBER_SELECTION_OPTION |
|
|
STRING_SELECTION_OPTION))
|
|
{
|
|
*(current_option->current_option) =
|
|
(*current_option->current_option + 1) %
|
|
current_option->num_options;
|
|
|
|
if(current_option->passive_function)
|
|
current_option->passive_function();
|
|
}
|
|
break;
|
|
|
|
case CURSOR_LEFT:
|
|
if(current_option->option_type & (NUMBER_SELECTION_OPTION |
|
|
STRING_SELECTION_OPTION))
|
|
{
|
|
u32 current_option_val = *(current_option->current_option);
|
|
|
|
if(current_option_val)
|
|
current_option_val--;
|
|
else
|
|
current_option_val = current_option->num_options - 1;
|
|
|
|
*(current_option->current_option) = current_option_val;
|
|
|
|
if(current_option->passive_function)
|
|
current_option->passive_function();
|
|
}
|
|
break;
|
|
|
|
case CURSOR_EXIT:
|
|
if(current_menu == &main_menu)
|
|
menu_exit();
|
|
|
|
choose_menu(&main_menu);
|
|
break;
|
|
|
|
case CURSOR_SELECT:
|
|
if(current_option->option_type & ACTION_OPTION)
|
|
current_option->action_function();
|
|
|
|
if(current_option->option_type & SUBMENU_OPTION)
|
|
choose_menu(current_option->sub_menu);
|
|
|
|
if(current_menu == &main_menu)
|
|
choose_menu(&main_menu);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
set_gba_resolution(screen_scale);
|
|
video_resolution_small();
|
|
menu_get_clock_speed();
|
|
set_clock_speed();
|
|
|
|
SDL_PauseAudio(0);
|
|
num_skipped_frames = 100;
|
|
|
|
return return_value;
|
|
}
|