Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 1652 lines (1385 sloc) 50.573 kb
/* 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
*/
#ifndef _WIN32_WCE
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <dirent.h>
#endif
#include "common.h"
#include "font.h"
#define MAX_PATH 1024
// Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
#ifdef GP2X_BUILD
#define FILE_LIST_ROWS ((int)((SDL_SCREEN_HEIGHT - 40) / FONT_HEIGHT))
#define FILE_LIST_POSITION 5
#define DIR_LIST_POSITION 260
#else
#define FILE_LIST_ROWS 25
#define FILE_LIST_POSITION 5
#define DIR_LIST_POSITION 360
#endif
#ifdef PSP_BUILD
#define color16(red, green, blue) \
(blue << 11) | (green << 5) | red \
#else
#define color16(red, green, blue) \
(red << 11) | (green << 5) | blue \
#endif
#ifdef GP2X_BUILD
#define COLOR_BG color16(0, 0, 0)
#else
#define COLOR_BG color16(2, 8, 10)
#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)
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(u8 **wildcards, u8 *result)
{
DIR *current_dir;
struct dirent *current_file;
struct stat file_info;
u8 current_dir_name[MAX_PATH];
u8 current_dir_short[81];
u32 current_dir_length;
u32 total_filenames_allocated;
u32 total_dirnames_allocated;
u8 **file_list;
u8 **dir_list;
u32 num_files;
u32 num_dirs;
u8 *file_name;
u32 file_name_length;
u32 ext_pos = -1;
u32 chosen_file, chosen_dir;
u32 dialog_result = 1;
s32 return_value = 1;
u32 current_file_selection;
u32 current_file_scroll_value;
u32 current_dir_selection;
u32 current_dir_scroll_value;
u32 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 = (u8 **)malloc(sizeof(u8 *) * 32);
dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
memset(file_list, 0, sizeof(u8 *) * 32);
memset(dir_list, 0, sizeof(u8 *) * 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
{
//mkdir("/var/root/Media/ROMs", 0777);
//mkdir("/var/root/Media/ROMs/GBA", 0777);
current_dir = opendir(current_dir_name);
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] =
(u8 *)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] =
(u8 *)malloc(file_name_length + 1);
sprintf(file_list[num_files], "%s", file_name);
num_files++;
break;
}
}
}
}
}
if(num_files == total_filenames_allocated)
{
file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
total_filenames_allocated * 2);
memset(file_list + total_filenames_allocated, 0,
sizeof(u8 *) * total_filenames_allocated);
total_filenames_allocated *= 2;
}
if(num_dirs == total_dirnames_allocated)
{
dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
total_dirnames_allocated * 2);
memset(dir_list + total_dirnames_allocated, 0,
sizeof(u8 *) * total_dirnames_allocated);
total_dirnames_allocated *= 2;
}
}
} while(current_file);
qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
closedir(current_dir);
current_dir_length = strlen(current_dir_name);
if(current_dir_length > 80)
{
#ifdef GP2X_BUILD
snprintf(current_dir_short, 80,
"...%s", current_dir_name + current_dir_length - 77);
#else
memcpy(current_dir_short, "...", 3);
memcpy(current_dir_short + 3,
current_dir_name + current_dir_length - 77, 77);
current_dir_short[80] = 0;
#endif
}
else
{
#ifdef GP2X_BUILD
snprintf(current_dir_short, 80, "%s", current_dir_name);
#else
memcpy(current_dir_short, current_dir_name,
current_dir_length + 1);
#endif
}
repeat = 1;
if(num_files == 0)
current_column = 1;
clear_screen(COLOR_BG);
{
u8 print_buffer[81];
while(repeat)
{
flip_screen();
print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
#ifdef GP2X_BUILD
print_string("Press START to return to the main menu. (v0.0.4)",
COLOR_HELP_TEXT, COLOR_BG, 20, 220);
#else
print_string("Press X to return to the main menu.",
COLOR_HELP_TEXT, COLOR_BG, 20, 260);
#endif
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
{
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_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
{
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_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;
}
}
}
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;
char *display_string;
void *options;
u32 *current_option;
u32 num_options;
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_real(real_name, name, init_function, passive_function) \
menu_type real_name##_menu = \
{ \
init_function, \
passive_function, \
name##_options, \
sizeof(name##_options) / sizeof(menu_option_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
#ifdef GP2X_BUILD
u32 gamepad_config_line_to_button[] =
{ 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5 };
#endif
s32 load_game_config_file()
{
u8 game_config_filename[512];
u32 file_loaded = 0;
u32 i;
change_ext(gamepak_filename, 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[3 + 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 = 333;
for(i = 0; i < 10; i++)
{
cheats[i].cheat_active = 0;
cheats[i].cheat_name[0] = 0;
}
return -1;
}
s32 load_config_file()
{
u8 config_path[512];
#if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
#else
sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
#endif
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 == 92)
{
u32 file_options[file_size / 4];
u32 i;
s32 menu_button = -1;
file_read_array(config_file, file_options);
screen_scale = file_options[0] % 3;
screen_filter = file_options[1] % 2;
global_enable_audio = file_options[2] % 2;
#ifdef PSP_BUILD
audio_buffer_size_number = file_options[3] % 10;
#else
audio_buffer_size_number = file_options[3] % 11;
#endif
update_backup_flag = file_options[4] % 2;
global_enable_analog = file_options[5] % 2;
analog_sensitivity_level = file_options[6] % 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
for(i = 0; i < 16; i++)
{
gamepad_config_map[i] = file_options[7 + i] %
(BUTTON_ID_NONE + 1);
if(gamepad_config_map[i] == BUTTON_ID_MENU)
{
menu_button = i;
}
}
if(menu_button == -1)
{
gamepad_config_map[0] = BUTTON_ID_MENU;
}
#endif
file_close(config_file);
}
return 0;
}
return -1;
}
s32 save_game_config_file()
{
u8 game_config_filename[512];
u32 i;
change_ext(gamepak_filename, 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()
{
u8 config_path[512];
#if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
#else
sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
#endif
file_open(config_file, config_path, write);
save_game_config_file();
if(file_check_valid(config_file))
{
u32 file_options[23];
u32 i;
file_options[0] = screen_scale;
file_options[1] = screen_filter;
file_options[2] = global_enable_audio;
file_options[3] = audio_buffer_size_number;
file_options[4] = update_backup_flag;
file_options[5] = global_enable_analog;
file_options[6] = analog_sensitivity_level;
#ifndef PC_BUILD
for(i = 0; i < 16; i++)
{
file_options[7 + 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(u8 *savestate_filename)
{
u16 snapshot_buffer[240 * 160];
u8 savestate_timestamp_string[80];
file_open(savestate_file, savestate_filename, read);
if(file_check_valid(savestate_file))
{
u8 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 exists for this slot.",
0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0);
print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
COLOR_BG, 10, 40);
}
#ifndef GP2X_BUILD
blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
#endif
}
void get_savestate_filename(u32 slot, u8 *name_buffer)
{
u8 savestate_ext[16];
sprintf(savestate_ext, "%d.svs", slot);
change_ext(gamepak_filename, name_buffer, savestate_ext);
get_savestate_snapshot(name_buffer);
}
void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
{
u8 savestate_ext[16];
sprintf(savestate_ext, "%d.svs", slot);
change_ext(gamepak_filename, name_buffer, savestate_ext);
}
#ifdef PSP_BUILD
void _flush_cache()
{
invalidate_all_cache();
}
#endif
static u32 clock_speed_number;
static u8 print_buffer[81];
static u32 _current_option = 0;
static gui_action_type gui_action;
static menu_enum _current_menu = MAIN_MENU;
static u32 i;
static u32 repeat = 1;
static u32 return_value = 0;
static u32 first_load = 0;
static u8 savestate_ext[16];
static u8 current_savestate_filename[512];
static u8 line_buffer[80];
static u8 cheat_format_str[10][41];
static menu_type *current_menu;
static menu_option_type *current_option;
static menu_option_type *display_option;
static u32 current_option_num;
static u16* original_screen;
static menu_type gamepad_config_menu;
void choose_menu();
void clear_help();
static u8 *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."
};
void menu_exit()
{
if(!first_load)
repeat = 0;
}
void menu_quit()
{
clock_speed = (clock_speed_number + 1) * 33;
#ifndef GP2X_BUILD
save_config_file();
#endif
quit();
}
void menu_load()
{
u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
u8 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;
}
else
{
choose_menu(current_menu);
}
}
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()
{
u8 *file_ext[] = { ".svs", NULL };
u8 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);
}
static u8 *yes_no_options[] = { "no", "yes" };
static u8 *enable_disable_options[] = { "disabled", "enabled" };
static u8 *scale_options[] =
{
"unscaled 3:2", "scaled 3:2", "fullscreen 16:9"
};
static u8 *frameskip_options[] = { "automatic", "manual", "off" };
static u8 *frameskip_variation_options[] = { "uniform", "random" };
#ifndef PSP_BUILD
static u8 *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
static u8 *audio_buffer_options[] =
{
"3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
"8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
};
#endif
static u8 *update_backup_options[] = { "Exit only", "Automatic" };
static u8 *clock_speed_options[] =
{
"33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
"266MHz", "300MHz", "333MHz"
};
static u8 *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"
};
// Marker for help information, don't go past this mark (except \n)------*
static menu_option_type graphics_sound_options[] =
{
string_selection_option(NULL, "Display scaling", scale_options,
(u32 *)(&screen_scale), 3,
"Determines how the GBA screen is resized in relation to the entire\n"
"screen. 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.", 2),
string_selection_option(NULL, "Screen filtering", yes_no_options,
(u32 *)(&screen_filter), 2,
"Determines whether or not bilinear 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, "Frameskip type", frameskip_options,
(u32 *)(&current_frameskip_type), 3,
"Determines what kind of frameskipping should be employed.\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 option) 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 to\n"
"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 not result in a\n"
"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
"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.",
10),
submenu_option(NULL, "Back", "Return to the main menu.", 12)
};
make_menu(graphics_sound, submenu_graphics_sound, NULL);
static 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),
string_selection_option(NULL, "Clock speed",
clock_speed_options, &clock_speed_number, 10,
"Change the clock speed of the device. Higher clock speed will yield\n"
"better performance, but will use drain battery life further.", 11),
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"
"memstick. If set to 'automatic' writebacks will occur shortly after\n"
"the game's backup is altered. On 'exit only' it will only be written\n"
"back when you exit from this menu (NOT from using the home button).\n"
"Use the latter with extreme care.", 12),
submenu_option(NULL, "Back", "Return to the main menu.", 14)
};
make_menu(cheats_misc, submenu_cheats_misc, NULL);
static 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 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 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 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
static menu_option_type* gamepad_config_options;
static 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
#ifdef GP2X_BUILD
static menu_option_type* gamepad_config_options;
static menu_option_type analog_config_options[] =
{
submenu_option(NULL, "Back", "Return to the main menu.", 11)
};
#endif
#ifdef PC_BUILD
static menu_option_type* gamepad_config_options;
static menu_option_type analog_config_options[] =
{
submenu_option(NULL, "Back", "Return to the main menu.", 11)
};
#endif
static make_menu(analog_config, submenu_analog, NULL);
static menu_option_type main_options[] =
{
#ifndef GP2X_BUILD
submenu_option(&graphics_sound_menu, "Graphics and Sound options",
"Select to set display parameters and frameskip behavior,\n"
"audio on/off, audio buffer size, and audio 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 for this game,\n"
"if it exists (see the extended menu for more information)\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 for this game.\n"
"See the extended menu for more information.\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 viewing the\n"
"currently active savestate for this game (or to load a savestate\n"
"file from another game)", 4),
submenu_option(&gamepad_config_menu, "Configure gamepad input",
"Select to change the in-game behavior of the PSP buttons and d-pad.",
6),
submenu_option(&analog_config_menu, "Configure analog input",
"Select to change the in-game behavior of the PSP analog nub.", 7),
#endif
submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
"Select to manage cheats, set backup behavior, and set device clock\n"
"speed.", 9),
#ifndef GP2X_BUILD
action_option(menu_load, NULL, "Load new game",
"Select to load a new game (will exit a game if currently playing).",
11),
#endif
action_option(menu_restart, NULL, "Restart game",
"Select to reset the GBA with the current game 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 PSP XMB/loader.", 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);
#ifndef GP2X_BUILD
blit_to_screen(original_screen, 240, 160, 230, 40);
#endif
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, 30, 210 + (i * 10), 70);
}
}
u32 menu(u16 *real_original_screen)
{
#ifdef PSP_BUILD
menu_option_type real_gamepad_config_options[13] =
{
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)
};
#endif
#ifdef GP2X_BUILD
menu_option_type real_gamepad_config_options[13] =
{
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("A ", 4),
gamepad_config_option("B ", 5),
gamepad_config_option("X ", 6),
gamepad_config_option("Y ", 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)
};
#endif
#ifdef PC_BUILD
menu_option_type real_gamepad_config_options[1] =
{
submenu_option(NULL, "Back", "Return to the main menu.", 13)
};
#endif
gamepad_config_options = real_gamepad_config_options;
make_menu_real(real_gamepad_config, gamepad_config, submenu_gamepad, NULL);
gamepad_config_menu = real_gamepad_config_menu;
clock_speed_number = (clock_speed / 33) - 1;
original_screen = real_original_screen;
video_resolution_large();
#ifndef GP2X_BUILD
//SDL_LockMutex(sound_mutex);
#endif
//SDL_PauseAudio(1);
#ifndef GP2X_BUILD
// SDL_UnlockMutex(sound_mutex);
#endif
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);
}
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, 10,
(display_option->line_number * 10) + 40, 36);
}
else
{
print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
(display_option->line_number * 10) + 40, 36);
}
}
print_string(current_option->help_string, COLOR_HELP_TEXT,
COLOR_BG, 30, 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);
break;
}
}
set_gba_resolution(screen_scale);
video_resolution_small();
clock_speed = (clock_speed_number + 1) * 33;
#ifdef PSP_BUILD
scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
#endif
//SDL_PauseAudio(0);
return return_value;
}
Jump to Line
Something went wrong with that request. Please try again.