3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public Licens e as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 // Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
37 #define FILE_LIST_ROWS 20
38 #define FILE_LIST_POSITION 5
39 #define DIR_LIST_POSITION 260
43 #define FILE_LIST_ROWS 25
44 #define FILE_LIST_POSITION 5
45 #define DIR_LIST_POSITION 360
51 #define COLOR_BG color16(2, 8, 10)
53 #define color16(red, green, blue) \
54 (blue << 11) | (green << 5) | red \
58 #define COLOR_BG color16(0, 0, 0)
60 #define color16(red, green, blue) \
61 (red << 11) | (green << 5) | blue \
65 #define COLOR_ROM_INFO color16(22, 36, 26)
66 #define COLOR_ACTIVE_ITEM color16(31, 63, 31)
67 #define COLOR_INACTIVE_ITEM color16(13, 40, 18)
68 #define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
69 #define COLOR_HELP_TEXT color16(16, 40, 24)
72 u8 *clock_speed_options[] =
74 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
75 "266MHz", "300MHz", "333MHz"
77 #define menu_get_clock_speed() \
78 clock_speed = (clock_speed_number + 1) * 33
79 #define get_clock_speed_number() \
80 clock_speed_number = (clock_speed / 33) - 1
81 #elif defined(WIZ_BUILD)
82 u8 *clock_speed_options[] =
84 "300MHz", "333MHz", "366MHz", "400MHz", "433MHz",
85 "466MHz", "500MHz", "533MHz", "566MHz", "600MHz",
86 "633MHz", "666MHz", "700MHz", "733MHz", "766MHz",
87 "800MHz", "833MHz", "866MHz", "900MHz"
89 #define menu_get_clock_speed() \
90 clock_speed = 300 + (clock_speed_number * 3333) / 100
91 #define get_clock_speed_number() \
92 clock_speed_number = (clock_speed - 300) / 33
93 #elif defined(GP2X_BUILD)
94 u8 *clock_speed_options[] =
96 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
97 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
98 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
100 #define menu_get_clock_speed() \
101 clock_speed = 150 + clock_speed_number * 10
102 #define get_clock_speed_number() \
103 clock_speed_number = (clock_speed - 150) / 10
105 u8 *clock_speed_options[] =
109 #define menu_get_clock_speed() 0
110 #define get_clock_speed_number() 0
114 int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
116 char *dest_str = *((char **)dest_str_ptr);
117 char *src_str = *((char **)src_str_ptr);
119 if(src_str[0] == '.')
122 if(dest_str[0] == '.')
125 return strcasecmp(dest_str, src_str);
128 s32 load_file(u8 **wildcards, u8 *result)
131 struct dirent *current_file;
132 struct stat file_info;
133 u8 current_dir_name[MAX_PATH];
134 u8 current_dir_short[81];
135 u32 current_dir_length;
136 u32 total_filenames_allocated;
137 u32 total_dirnames_allocated;
143 u32 file_name_length;
145 u32 chosen_file, chosen_dir;
146 u32 dialog_result = 1;
147 s32 return_value = 1;
148 s32 current_file_selection;
149 s32 current_file_scroll_value;
150 u32 current_dir_selection;
151 u32 current_dir_scroll_value;
152 s32 current_file_in_scroll;
153 u32 current_dir_in_scroll;
154 u32 current_file_number, current_dir_number;
155 u32 current_column = 0;
158 gui_action_type gui_action;
160 while(return_value == 1)
162 current_file_selection = 0;
163 current_file_scroll_value = 0;
164 current_dir_selection = 0;
165 current_dir_scroll_value = 0;
166 current_file_in_scroll = 0;
167 current_dir_in_scroll = 0;
169 total_filenames_allocated = 32;
170 total_dirnames_allocated = 32;
171 file_list = (u8 **)malloc(sizeof(u8 *) * 32);
172 dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
173 memset(file_list, 0, sizeof(u8 *) * 32);
174 memset(dir_list, 0, sizeof(u8 *) * 32);
181 getcwd(current_dir_name, MAX_PATH);
183 current_dir = opendir(current_dir_name);
188 current_file = readdir(current_dir);
194 file_name = current_file->d_name;
195 file_name_length = strlen(file_name);
197 if((stat(file_name, &file_info) >= 0) &&
198 ((file_name[0] != '.') || (file_name[1] == '.')))
200 if(S_ISDIR(file_info.st_mode))
203 (u8 *)malloc(file_name_length + 1);
205 sprintf(dir_list[num_dirs], "%s", file_name);
211 // Must match one of the wildcards, also ignore the .
212 if(file_name_length >= 4)
214 if(file_name[file_name_length - 4] == '.')
215 ext_pos = file_name_length - 4;
218 if(file_name[file_name_length - 3] == '.')
219 ext_pos = file_name_length - 3;
224 for(i = 0; wildcards[i] != NULL; i++)
226 if(!strcasecmp((file_name + ext_pos),
229 file_list[num_files] =
230 (u8 *)malloc(file_name_length + 1);
232 sprintf(file_list[num_files], "%s", file_name);
242 if(num_files == total_filenames_allocated)
244 file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
245 total_filenames_allocated * 2);
246 memset(file_list + total_filenames_allocated, 0,
247 sizeof(u8 *) * total_filenames_allocated);
248 total_filenames_allocated *= 2;
251 if(num_dirs == total_dirnames_allocated)
253 dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
254 total_dirnames_allocated * 2);
255 memset(dir_list + total_dirnames_allocated, 0,
256 sizeof(u8 *) * total_dirnames_allocated);
257 total_dirnames_allocated *= 2;
260 } while(current_file);
262 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
263 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
265 closedir(current_dir);
267 current_dir_length = strlen(current_dir_name);
269 if(current_dir_length > 80)
273 snprintf(current_dir_short, 80,
274 "...%s", current_dir_name + current_dir_length - 77);
276 memcpy(current_dir_short, "...", 3);
277 memcpy(current_dir_short + 3,
278 current_dir_name + current_dir_length - 77, 77);
279 current_dir_short[80] = 0;
285 snprintf(current_dir_short, 80, "%s", current_dir_name);
287 memcpy(current_dir_short, current_dir_name,
288 current_dir_length + 1);
297 clear_screen(COLOR_BG);
305 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
307 print_string("Press X to return to the main menu.",
308 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
310 print_string("Press X to return to the main menu.",
311 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
314 for(i = 0, current_file_number = i + current_file_scroll_value;
315 i < FILE_LIST_ROWS; i++, current_file_number++)
317 if(current_file_number < num_files)
319 if((current_file_number == current_file_selection) &&
320 (current_column == 0))
322 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
323 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
327 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
328 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
333 for(i = 0, current_dir_number = i + current_dir_scroll_value;
334 i < FILE_LIST_ROWS; i++, current_dir_number++)
336 if(current_dir_number < num_dirs)
338 if((current_dir_number == current_dir_selection) &&
339 (current_column == 1))
341 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
342 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
346 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
347 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
352 gui_action = get_gui_input();
357 if(current_column == 0)
359 if(current_file_selection < (num_files - 1))
361 current_file_selection++;
362 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
364 clear_screen(COLOR_BG);
365 current_file_scroll_value++;
369 current_file_in_scroll++;
374 clear_screen(COLOR_BG);
375 current_file_selection = 0;
376 current_file_scroll_value = 0;
377 current_file_in_scroll = 0;
382 if(current_dir_selection < (num_dirs - 1))
384 current_dir_selection++;
385 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
387 clear_screen(COLOR_BG);
388 current_dir_scroll_value++;
392 current_dir_in_scroll++;
400 if (current_column != 0)
402 clear_screen(COLOR_BG);
403 current_file_selection += FILE_LIST_ROWS;
404 if (current_file_selection > num_files - 1)
405 current_file_selection = num_files - 1;
406 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
407 if (current_file_scroll_value < 0)
409 current_file_scroll_value = 0;
410 current_file_in_scroll = current_file_selection;
414 current_file_in_scroll = FILE_LIST_ROWS / 2;
419 if(current_column == 0)
421 if(current_file_selection)
423 current_file_selection--;
424 if(current_file_in_scroll == 0)
426 clear_screen(COLOR_BG);
427 current_file_scroll_value--;
431 current_file_in_scroll--;
436 clear_screen(COLOR_BG);
437 current_file_selection = num_files - 1;
438 current_file_in_scroll = FILE_LIST_ROWS - 1;
439 if (current_file_in_scroll > num_files - 1)
440 current_file_in_scroll = num_files - 1;
441 current_file_scroll_value = num_files - FILE_LIST_ROWS;
442 if (current_file_scroll_value < 0)
443 current_file_scroll_value = 0;
448 if(current_dir_selection)
450 current_dir_selection--;
451 if(current_dir_in_scroll == 0)
453 clear_screen(COLOR_BG);
454 current_dir_scroll_value--;
458 current_dir_in_scroll--;
465 if (current_column != 0)
467 clear_screen(COLOR_BG);
468 current_file_selection -= FILE_LIST_ROWS;
469 if (current_file_selection < 0)
470 current_file_selection = 0;
471 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
472 if (current_file_scroll_value < 0)
474 current_file_scroll_value = 0;
475 current_file_in_scroll = current_file_selection;
479 current_file_in_scroll = FILE_LIST_ROWS / 2;
484 if(current_column == 0)
492 if(current_column == 1)
500 if(current_column == 1)
503 chdir(dir_list[current_dir_selection]);
511 strcpy(result, file_list[current_file_selection]);
518 if(!strcmp(current_dir_name, "ms0:/PSP"))
533 for(i = 0; i < num_files; i++)
539 for(i = 0; i < num_dirs; i++)
546 clear_screen(COLOR_BG);
553 NUMBER_SELECTION_OPTION = 0x01,
554 STRING_SELECTION_OPTION = 0x02,
555 SUBMENU_OPTION = 0x04,
557 } menu_option_type_enum;
561 void (* init_function)();
562 void (* passive_function)();
563 struct _menu_option_type *options;
567 struct _menu_option_type
569 void (* action_function)();
570 void (* passive_function)();
571 struct _menu_type *sub_menu;
572 const char *display_string;
576 const char *help_string;
578 menu_option_type_enum option_type;
581 typedef struct _menu_option_type menu_option_type;
582 typedef struct _menu_type menu_type;
584 #define make_menu(name, init_function, passive_function) \
585 menu_type name##_menu = \
590 sizeof(name##_options) / sizeof(menu_option_type) \
593 #define gamepad_config_option(display_string, number) \
596 menu_fix_gamepad_help, \
598 display_string ": %s", \
599 gamepad_config_buttons, \
600 gamepad_config_map + gamepad_config_line_to_button[number], \
601 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
602 gamepad_help[gamepad_config_map[ \
603 gamepad_config_line_to_button[number]]], \
605 STRING_SELECTION_OPTION \
608 #define analog_config_option(display_string, number) \
611 menu_fix_gamepad_help, \
613 display_string ": %s", \
614 gamepad_config_buttons, \
615 gamepad_config_map + number + 12, \
616 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
617 gamepad_help[gamepad_config_map[number + 12]], \
619 STRING_SELECTION_OPTION \
622 #define cheat_option(number) \
627 cheat_format_str[number], \
628 enable_disable_options, \
629 &(cheats[number].cheat_active), \
631 "Activate/deactivate this cheat code.", \
633 STRING_SELECTION_OPTION \
636 #define action_option(action_function, passive_function, display_string, \
637 help_string, line_number) \
651 #define submenu_option(sub_menu, display_string, help_string, line_number) \
659 sizeof(sub_menu) / sizeof(menu_option_type), \
665 #define selection_option(passive_function, display_string, options, \
666 option_ptr, num_options, help_string, line_number, type) \
680 #define action_selection_option(action_function, passive_function, \
681 display_string, options, option_ptr, num_options, help_string, line_number, \
693 type | ACTION_OPTION \
697 #define string_selection_option(passive_function, display_string, options, \
698 option_ptr, num_options, help_string, line_number) \
699 selection_option(passive_function, display_string ": %s", options, \
700 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
702 #define numeric_selection_option(passive_function, display_string, \
703 option_ptr, num_options, help_string, line_number) \
704 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
705 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
707 #define string_selection_action_option(action_function, passive_function, \
708 display_string, options, option_ptr, num_options, help_string, line_number) \
709 action_selection_option(action_function, passive_function, \
710 display_string ": %s", options, option_ptr, num_options, help_string, \
711 line_number, STRING_SELECTION_OPTION) \
713 #define numeric_selection_action_option(action_function, passive_function, \
714 display_string, option_ptr, num_options, help_string, line_number) \
715 action_selection_option(action_function, passive_function, \
716 display_string ": %d", NULL, option_ptr, num_options, help_string, \
717 line_number, NUMBER_SELECTION_OPTION) \
719 #define numeric_selection_action_hide_option(action_function, \
720 passive_function, display_string, option_ptr, num_options, help_string, \
722 action_selection_option(action_function, passive_function, \
723 display_string, NULL, option_ptr, num_options, help_string, \
724 line_number, NUMBER_SELECTION_OPTION) \
727 #define GAMEPAD_MENU_WIDTH 15
731 u32 gamepad_config_line_to_button[] =
732 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
738 u32 gamepad_config_line_to_button[] =
739 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
745 u32 gamepad_config_line_to_button[] =
746 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 12, 13, 14, 15 };
750 u8 *scale_options[] =
753 "unscaled 3:2", "scaled 3:2", "fullscreen 16:9"
754 #elif defined(WIZ_BUILD)
755 "unscaled 3:2", "scaled 3:2 (slower)",
756 "unscaled 3:2 (anti-tear)", "scaled 3:2 (anti-tear)"
757 #elif defined(PND_BUILD)
758 "unscaled", "2x", "3x", "fullscreen"
759 #elif defined(GP2X_BUILD)
760 "unscaled 3:2", "scaled 3:2", "fullscreen", "scaled 3:2 (software)"
766 s32 load_game_config_file()
768 u8 game_config_filename[512];
771 change_ext(gamepak_filename, game_config_filename, ".cfg");
773 file_open(game_config_file, game_config_filename, read);
775 if(file_check_valid(game_config_file))
777 u32 file_size = file_length(game_config_filename, game_config_file);
779 // Sanity check: File size must be the right size
782 u32 file_options[file_size / 4];
784 file_read_array(game_config_file, file_options);
785 current_frameskip_type = file_options[0] % 3;
786 frameskip_value = file_options[1];
787 random_skip = file_options[2] % 2;
788 clock_speed = file_options[3];
791 if(clock_speed > 900)
793 #elif defined(GP2X_BUILD)
794 if(clock_speed >= 300)
797 if(clock_speed > 333)
804 if(frameskip_value < 0)
807 if(frameskip_value > 99)
808 frameskip_value = 99;
810 for(i = 0; i < 10; i++)
812 cheats[i].cheat_active = file_options[3 + i] % 2;
813 cheats[i].cheat_name[0] = 0;
816 file_close(game_config_file);
824 current_frameskip_type = auto_frameskip;
830 clock_speed = default_clock_speed;
832 for(i = 0; i < 10; i++)
834 cheats[i].cheat_active = 0;
835 cheats[i].cheat_name[0] = 0;
841 s32 load_config_file()
845 #if defined(_WIN32) || defined(_WIN32_WCE)
846 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
848 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
851 file_open(config_file, config_path, read);
853 if(file_check_valid(config_file))
855 u32 file_size = file_length(config_path, config_file);
857 // Sanity check: File size must be the right size
860 u32 file_options[file_size / 4];
862 s32 menu_button = -1;
863 file_read_array(config_file, file_options);
865 screen_scale = file_options[0] %
866 (sizeof(scale_options) / sizeof(scale_options[0]));
867 screen_filter = file_options[1] % 2;
868 global_enable_audio = file_options[2] % 2;
871 audio_buffer_size_number = file_options[3] % 10;
873 audio_buffer_size_number = file_options[3] % 11;
876 update_backup_flag = file_options[4] % 2;
877 global_enable_analog = file_options[5] % 2;
878 analog_sensitivity_level = file_options[6] % 8;
881 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
884 // Sanity check: Make sure there's a MENU or FRAMESKIP
885 // key, if not assign to triangle
888 for(i = 0; i < 16; i++)
890 gamepad_config_map[i] = file_options[7 + i] %
891 (BUTTON_ID_NONE + 1);
893 if(gamepad_config_map[i] == BUTTON_ID_MENU)
899 if(menu_button == -1)
901 gamepad_config_map[0] = BUTTON_ID_MENU;
905 file_close(config_file);
914 s32 save_game_config_file()
916 u8 game_config_filename[512];
919 change_ext(gamepak_filename, game_config_filename, ".cfg");
921 file_open(game_config_file, game_config_filename, write);
923 if(file_check_valid(game_config_file))
925 u32 file_options[14];
927 file_options[0] = current_frameskip_type;
928 file_options[1] = frameskip_value;
929 file_options[2] = random_skip;
930 file_options[3] = clock_speed;
932 for(i = 0; i < 10; i++)
934 file_options[4 + i] = cheats[i].cheat_active;
937 file_write_array(game_config_file, file_options);
939 file_close(game_config_file);
947 s32 save_config_file()
951 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
952 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
954 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
957 file_open(config_file, config_path, write);
959 save_game_config_file();
961 if(file_check_valid(config_file))
963 u32 file_options[23];
966 file_options[0] = screen_scale;
967 file_options[1] = screen_filter;
968 file_options[2] = global_enable_audio;
969 file_options[3] = audio_buffer_size_number;
970 file_options[4] = update_backup_flag;
971 file_options[5] = global_enable_analog;
972 file_options[6] = analog_sensitivity_level;
975 for(i = 0; i < 16; i++)
977 file_options[7 + i] = gamepad_config_map[i];
981 file_write_array(config_file, file_options);
983 file_close(config_file);
1000 u32 savestate_slot = 0;
1002 void get_savestate_snapshot(u8 *savestate_filename)
1004 u16 snapshot_buffer[240 * 160];
1005 u8 savestate_timestamp_string[80];
1007 file_open(savestate_file, savestate_filename, read);
1009 if(file_check_valid(savestate_file))
1011 u8 weekday_strings[7][11] =
1013 "Sunday", "Monday", "Tuesday", "Wednesday",
1014 "Thursday", "Friday", "Saturday"
1016 time_t savestate_time_flat;
1017 struct tm *current_time;
1018 file_read_array(savestate_file, snapshot_buffer);
1019 file_read_variable(savestate_file, savestate_time_flat);
1021 file_close(savestate_file);
1023 current_time = localtime(&savestate_time_flat);
1024 sprintf(savestate_timestamp_string,
1025 "%s %02d/%02d/%04d %02d:%02d:%02d ",
1026 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
1027 current_time->tm_mday, current_time->tm_year + 1900,
1028 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
1030 savestate_timestamp_string[40] = 0;
1031 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
1036 memset(snapshot_buffer, 0, 240 * 160 * 2);
1037 print_string_ext("No savestate in this slot.",
1038 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0, 0, FONT_HEIGHT);
1039 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
1044 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
1048 void get_savestate_filename(u32 slot, u8 *name_buffer)
1050 u8 savestate_ext[16];
1052 sprintf(savestate_ext, "%d.svs", slot);
1053 change_ext(gamepak_filename, name_buffer, savestate_ext);
1055 get_savestate_snapshot(name_buffer);
1058 void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
1060 u8 savestate_ext[16];
1062 sprintf(savestate_ext, "%d.svs", slot);
1063 change_ext(gamepak_filename, name_buffer, savestate_ext);
1069 invalidate_all_cache();
1073 u32 menu(u16 *original_screen)
1075 u8 print_buffer[81];
1076 u32 clock_speed_number;
1077 u32 _current_option = 0;
1078 gui_action_type gui_action;
1079 menu_enum _current_menu = MAIN_MENU;
1082 u32 return_value = 0;
1084 u8 savestate_ext[16];
1085 u8 current_savestate_filename[512];
1087 u8 cheat_format_str[10][41];
1089 menu_type *current_menu;
1090 menu_option_type *current_option;
1091 menu_option_type *display_option;
1092 u32 current_option_num;
1094 auto void choose_menu();
1095 auto void clear_help();
1097 static const u8 * const gamepad_help[] =
1099 "Up button on GBA d-pad.",
1100 "Down button on GBA d-pad.",
1101 "Left button on GBA d-pad.",
1102 "Right button on GBA d-pad.",
1105 "Left shoulder button on GBA.",
1106 "Right shoulder button on GBA.",
1107 "Start button on GBA.",
1108 "Select button on GBA.",
1109 "Brings up the options menu.",
1110 "Toggles fastforward on/off.",
1111 "Loads the game state from the current slot.",
1112 "Saves the game state to the current slot.",
1113 "Rapidly press/release the A button on GBA.",
1114 "Rapidly press/release the B button on GBA.",
1115 "Rapidly press/release the L shoulder on GBA.",
1116 "Rapidly press/release the R shoulder on GBA.",
1117 "Increases the volume.",
1118 "Decreases the volume.",
1119 "Displays virtual/drawn frames per second.",
1123 void menu_update_clock()
1125 get_clock_speed_number();
1126 if (clock_speed_number < 0 || clock_speed_number >=
1127 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]))
1129 clock_speed = default_clock_speed;
1130 get_clock_speed_number();
1142 menu_get_clock_speed();
1149 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1150 u8 load_filename[512];
1151 save_game_config_file();
1152 if(load_file(file_ext, load_filename) != -1)
1154 if(load_gamepak(load_filename) == -1)
1161 reg[CHANGED_PC_STATUS] = 1;
1162 menu_update_clock();
1166 choose_menu(current_menu);
1175 reg[CHANGED_PC_STATUS] = 1;
1181 void menu_change_state()
1183 get_savestate_filename(savestate_slot, current_savestate_filename);
1186 void menu_save_state()
1190 get_savestate_filename_noshot(savestate_slot,
1191 current_savestate_filename);
1192 save_state(current_savestate_filename, original_screen);
1194 menu_change_state();
1197 void menu_load_state()
1201 load_state(current_savestate_filename);
1207 void menu_load_state_file()
1209 u8 *file_ext[] = { ".svs", NULL };
1210 u8 load_filename[512];
1211 if(load_file(file_ext, load_filename) != -1)
1213 load_state(load_filename);
1219 choose_menu(current_menu);
1223 void menu_fix_gamepad_help()
1227 current_option->help_string =
1228 gamepad_help[gamepad_config_map[
1229 gamepad_config_line_to_button[current_option_num]]];
1233 void submenu_graphics_sound()
1238 void submenu_cheats_misc()
1243 void submenu_gamepad()
1248 void submenu_analog()
1253 void submenu_savestate()
1255 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1256 menu_change_state();
1261 strncpy(print_buffer, gamepak_filename, 80);
1262 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1263 sprintf(print_buffer, "%s %s %s", gamepak_title,
1264 gamepak_code, gamepak_maker);
1265 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1267 get_savestate_filename_noshot(savestate_slot,
1268 current_savestate_filename);
1271 u8 *yes_no_options[] = { "no", "yes" };
1272 u8 *enable_disable_options[] = { "disabled", "enabled" };
1274 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1275 u8 *frameskip_variation_options[] = { "uniform", "random" };
1278 u8 *audio_buffer_options[] =
1280 "16 bytes", "32 bytes", "64 bytes",
1281 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1282 "4096 bytes", "8192 bytes", "16284 bytes"
1285 u8 *audio_buffer_options[] =
1287 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1288 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1293 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1295 u8 *gamepad_config_buttons[] =
1321 // Marker for help information, don't go past this mark (except \n)------*
1322 menu_option_type graphics_sound_options[] =
1324 string_selection_option(NULL, "Display scaling", scale_options,
1325 (u32 *)(&screen_scale),
1326 sizeof(scale_options) / sizeof(scale_options[0]),
1328 "Determines how the GBA screen is resized in relation to the\n"
1331 " Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1332 "aspect ratio scaled to fill the height of the PSP screen, and\n"
1333 "fullscreen to fill the entire PSP screen."
1338 string_selection_option(NULL, "Screen filtering", yes_no_options,
1339 (u32 *)(&screen_filter), 2,
1340 "Determines whether or not filtering should be used when\n"
1341 "scaling the screen. Selecting this will produce a more even and\n"
1342 "smooth image, at the cost of being blurry and having less vibrant\n"
1345 string_selection_option(NULL, "Frameskip type", frameskip_options,
1346 (u32 *)(¤t_frameskip_type), 3,
1348 "Determines what kind of frameskipping to use.\n"
1349 "Frameskipping may improve emulation speed of many games.\n"
1351 "Off: Do not skip any frames.\n"
1352 "Auto: Skip up to N frames (see next opt) as needed.\n"
1353 "Manual: Always render only 1 out of N + 1 frames."
1355 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1357 "For auto frameskip, determines the maximum number of frames that\n"
1358 "are allowed to be skipped consecutively.\n"
1359 "For manual frameskip, determines the number of frames that will\n"
1360 "always be skipped."
1363 string_selection_option(NULL, "Framskip variation",
1364 frameskip_variation_options, &random_skip, 2,
1366 "If objects in the game flicker at a regular rate certain manual\n"
1367 "frameskip values may cause them to normally disappear. Change this\n"
1368 "value to 'random' to avoid this. Do not use otherwise, as it tends\n"
1369 "to make the image quality worse, especially in high motion games."
1372 string_selection_option(NULL, "Audio output", yes_no_options,
1373 &global_enable_audio, 2,
1374 "Select 'no' to turn off all audio output. This will\n"
1375 "not result in a significant change in performance.", 9),
1377 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1378 &audio_buffer_size_number, 11,
1380 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1381 &audio_buffer_size_number, 10,
1385 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1386 "in slightly better performance at the cost of latency; the lowest\n"
1387 "value will give the most responsive audio.\n"
1388 "This option requires gpSP to be restarted before it will take effect.",
1390 "Set the size (in bytes) of the audio buffer.\n"
1391 "This option requires gpSP restart to take effect.",
1394 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1397 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1399 menu_option_type cheats_misc_options[] =
1411 #if defined(PSP_BUILD) || defined(GP2X_BUILD)
1412 string_selection_option(NULL, "Clock speed",
1413 clock_speed_options, &clock_speed_number,
1414 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
1415 "Change the clock speed of the device. Higher clock\n"
1416 "speed will yield better performance, but will drain\n"
1417 "battery life further.", 11),
1419 string_selection_option(NULL, "Update backup",
1420 update_backup_options, &update_backup_flag, 2,
1422 "Determines when in-game save files should be\n"
1423 "written back to SD card."
1425 "Determines when in-game save files should be written back to\n"
1426 "card. If set to 'automatic' writebacks will occur shortly after\n"
1427 "the game's backup is altered. On 'exit only' it will only be\n"
1428 "written back when you exit from this menu.\n"
1430 "(NOT from using the home button), use the latter with extreme care."
1434 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1437 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1439 menu_option_type savestate_options[] =
1441 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1442 "Load savestate from current slot", &savestate_slot, 10,
1443 "Select to load the game state from the current slot\n"
1445 "Press left + right to change the current slot.", 6),
1446 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1447 "Save savestate to current slot", &savestate_slot, 10,
1448 "Select to save the game state to the current slot\n"
1450 "Press left + right to change the current slot.", 7),
1451 numeric_selection_action_hide_option(menu_load_state_file,
1453 "Load savestate from file", &savestate_slot, 10,
1454 "Restore gameplay from a savestate file.\n"
1455 "Note: The same file used to save the state must be\n"
1457 numeric_selection_option(menu_change_state,
1458 "Current savestate slot", &savestate_slot, 10,
1459 "Change the current savestate slot.\n", 11),
1460 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1463 make_menu(savestate, submenu_savestate, NULL);
1467 menu_option_type gamepad_config_options[] =
1469 gamepad_config_option("D-pad up ", 0),
1470 gamepad_config_option("D-pad down ", 1),
1471 gamepad_config_option("D-pad left ", 2),
1472 gamepad_config_option("D-pad right ", 3),
1473 gamepad_config_option("Circle ", 4),
1474 gamepad_config_option("Cross ", 5),
1475 gamepad_config_option("Square ", 6),
1476 gamepad_config_option("Triangle ", 7),
1477 gamepad_config_option("Left Trigger ", 8),
1478 gamepad_config_option("Right Trigger", 9),
1479 gamepad_config_option("Start ", 10),
1480 gamepad_config_option("Select ", 11),
1481 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1485 menu_option_type analog_config_options[] =
1487 analog_config_option("Analog up ", 0),
1488 analog_config_option("Analog down ", 1),
1489 analog_config_option("Analog left ", 2),
1490 analog_config_option("Analog right", 3),
1491 string_selection_option(NULL, "Enable analog", yes_no_options,
1492 &global_enable_analog, 2,
1493 "Select 'no' to block analog input entirely.", 7),
1494 numeric_selection_option(NULL, "Analog sensitivity",
1495 &analog_sensitivity_level, 10,
1496 "Determine sensitivity/responsiveness of the analog input.\n"
1497 "Lower numbers are less sensitive.", 8),
1498 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1503 #if defined(GP2X_BUILD) || defined(PND_BUILD)
1505 menu_option_type gamepad_config_options[] =
1507 gamepad_config_option("D-pad up ", 0),
1508 gamepad_config_option("D-pad down ", 1),
1509 gamepad_config_option("D-pad left ", 2),
1510 gamepad_config_option("D-pad right ", 3),
1511 gamepad_config_option("A ", 4),
1512 gamepad_config_option("B ", 5),
1513 gamepad_config_option("X ", 6),
1514 gamepad_config_option("Y ", 7),
1515 gamepad_config_option("Left Trigger ", 8),
1516 gamepad_config_option("Right Trigger", 9),
1518 gamepad_config_option("Menu ", 10),
1520 gamepad_config_option("Start ", 10),
1522 gamepad_config_option("Select ", 11),
1523 #if !defined(WIZ_BUILD) && !defined(PND_BUILD)
1524 gamepad_config_option("Stick Push ", 12),
1527 gamepad_config_option("1 ", 12),
1528 gamepad_config_option("2 ", 13),
1529 gamepad_config_option("3 ", 14),
1530 gamepad_config_option("4 ", 15),
1531 submenu_option(NULL, "Back", "Return to the main menu.", 16)
1533 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1538 menu_option_type analog_config_options[] =
1540 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1547 menu_option_type gamepad_config_options[] =
1549 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1552 menu_option_type analog_config_options[] =
1554 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1559 make_menu(gamepad_config, submenu_gamepad, NULL);
1560 make_menu(analog_config, submenu_analog, NULL);
1562 menu_option_type main_options[] =
1564 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1565 "Select to set display parameters and frameskip\n"
1566 "behavior, audio on/off, buffer size, and filtering.", 0),
1567 numeric_selection_action_option(menu_load_state, NULL,
1568 "Load state from slot", &savestate_slot, 10,
1569 "Select to load the game state from the current slot\n"
1570 "for this game, if it exists.\n"
1571 "Press left + right to change the current slot.", 2),
1572 numeric_selection_action_option(menu_save_state, NULL,
1573 "Save state to slot", &savestate_slot, 10,
1574 "Select to save the game state to the current slot\n"
1575 "for this game. See the extended menu for more info.\n"
1576 "Press left + right to change the current slot.", 3),
1577 submenu_option(&savestate_menu, "Savestate options",
1578 "Select to enter a menu for loading, saving, and\n"
1579 "viewing the currently active savestate for this game\n"
1580 "(or to load a savestate file from another game)", 4),
1581 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1582 "Select to change the in-game behavior of buttons\n"
1585 submenu_option(&analog_config_menu, "Configure analog input",
1586 "Select to change the in-game behavior of the PSP analog nub.", 7),
1588 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1589 "Select to manage cheats, set backup behavior,\n"
1590 "and set device clock speed.", 9),
1591 action_option(menu_load, NULL, "Load new game",
1592 "Select to load a new game\n"
1593 "(will exit a game if currently playing).", 11),
1594 action_option(menu_restart, NULL, "Restart game",
1595 "Select to reset the GBA with the current game\n"
1597 action_option(menu_exit, NULL, "Return to game",
1598 "Select to exit this menu and resume gameplay.", 13),
1599 action_option(menu_quit, NULL, "Exit gpSP",
1600 "Select to exit gpSP and return to the menu.", 15)
1603 make_menu(main, submenu_main, NULL);
1605 void choose_menu(menu_type *new_menu)
1607 if(new_menu == NULL)
1608 new_menu = &main_menu;
1610 clear_screen(COLOR_BG);
1613 blit_to_screen(original_screen, 240, 160, 230, 40);
1616 current_menu = new_menu;
1617 current_option = new_menu->options;
1618 current_option_num = 0;
1619 if(current_menu->init_function)
1620 current_menu->init_function();
1625 for(i = 0; i < 6; i++)
1627 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
1631 menu_update_clock();
1632 video_resolution_large();
1635 SDL_LockMutex(sound_mutex);
1640 SDL_UnlockMutex(sound_mutex);
1643 if(gamepak_filename[0] == 0)
1646 memset(original_screen, 0x00, 240 * 160 * 2);
1647 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1648 60, 75,original_screen, 240, 0, 0, FONT_HEIGHT);
1651 choose_menu(&main_menu);
1653 for(i = 0; i < 10; i++)
1657 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1661 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1662 cheats[i].cheat_name);
1666 current_menu->init_function();
1670 display_option = current_menu->options;
1672 for(i = 0; i < current_menu->num_options; i++, display_option++)
1674 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1676 sprintf(line_buffer, display_option->display_string,
1677 *(display_option->current_option));
1681 if(display_option->option_type & STRING_SELECTION_OPTION)
1683 sprintf(line_buffer, display_option->display_string,
1684 ((u32 *)display_option->options)[*(display_option->current_option)]);
1688 strcpy(line_buffer, display_option->display_string);
1691 if(display_option == current_option)
1693 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 6,
1694 (display_option->line_number * 10) + 40, 36);
1698 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 6,
1699 (display_option->line_number * 10) + 40, 36);
1703 print_string(current_option->help_string, COLOR_HELP_TEXT,
1708 gui_action = get_gui_input();
1713 current_option_num = (current_option_num + 1) %
1714 current_menu->num_options;
1716 current_option = current_menu->options + current_option_num;
1721 if(current_option_num)
1722 current_option_num--;
1724 current_option_num = current_menu->num_options - 1;
1726 current_option = current_menu->options + current_option_num;
1731 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1732 STRING_SELECTION_OPTION))
1734 *(current_option->current_option) =
1735 (*current_option->current_option + 1) %
1736 current_option->num_options;
1738 if(current_option->passive_function)
1739 current_option->passive_function();
1744 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1745 STRING_SELECTION_OPTION))
1747 u32 current_option_val = *(current_option->current_option);
1749 if(current_option_val)
1750 current_option_val--;
1752 current_option_val = current_option->num_options - 1;
1754 *(current_option->current_option) = current_option_val;
1756 if(current_option->passive_function)
1757 current_option->passive_function();
1762 if(current_menu == &main_menu)
1765 choose_menu(&main_menu);
1769 if(current_option->option_type & ACTION_OPTION)
1770 current_option->action_function();
1772 if(current_option->option_type & SUBMENU_OPTION)
1773 choose_menu(current_option->sub_menu);
1778 set_gba_resolution(screen_scale);
1779 video_resolution_small();
1780 menu_get_clock_speed();
1784 num_skipped_frames = 100;
1786 return return_value;