race condition fix from 2007 (gpsp09-2xb_1)
[gpsp.git] / gui.c
CommitLineData
2823a4c8 1/* gameplaySP
2 *
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.
8 *
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.
13 *
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
17 */
18
19#ifndef _WIN32_WCE
20
21#include <sys/stat.h>
22#include <unistd.h>
23#include <ctype.h>
24#include <dirent.h>
25
26#endif
27
28#include "common.h"
29#include "font.h"
30
31#define MAX_PATH 1024
32
33// Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
34
35#ifdef GP2X_BUILD
36
37#define FILE_LIST_ROWS ((int)((SDL_SCREEN_HEIGHT - 40) / FONT_HEIGHT))
38#define FILE_LIST_POSITION 5
39#define DIR_LIST_POSITION 260
40
41#else
42
43#define FILE_LIST_ROWS 25
44#define FILE_LIST_POSITION 5
45#define DIR_LIST_POSITION 360
46
47#endif
48
49#ifdef PSP_BUILD
50
51#define color16(red, green, blue) \
52 (blue << 11) | (green << 5) | red \
53
54#else
55
56#define color16(red, green, blue) \
57 (red << 11) | (green << 5) | blue \
58
59#endif
60
61#ifdef GP2X_BUILD
62
63#define COLOR_BG color16(0, 0, 0)
64
65#else
66
67#define COLOR_BG color16(2, 8, 10)
68
69#endif
70
71#define COLOR_ROM_INFO color16(22, 36, 26)
72#define COLOR_ACTIVE_ITEM color16(31, 63, 31)
73#define COLOR_INACTIVE_ITEM color16(13, 40, 18)
74#define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
75#define COLOR_HELP_TEXT color16(16, 40, 24)
76
77int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
78{
79 char *dest_str = *((char **)dest_str_ptr);
80 char *src_str = *((char **)src_str_ptr);
81
82 if(src_str[0] == '.')
83 return 1;
84
85 if(dest_str[0] == '.')
86 return -1;
87
88 return strcasecmp(dest_str, src_str);
89}
90
91s32 load_file(u8 **wildcards, u8 *result)
92{
93 DIR *current_dir;
94 struct dirent *current_file;
95 struct stat file_info;
96 u8 current_dir_name[MAX_PATH];
97 u8 current_dir_short[81];
98 u32 current_dir_length;
99 u32 total_filenames_allocated;
100 u32 total_dirnames_allocated;
101 u8 **file_list;
102 u8 **dir_list;
103 u32 num_files;
104 u32 num_dirs;
105 u8 *file_name;
106 u32 file_name_length;
107 u32 ext_pos = -1;
108 u32 chosen_file, chosen_dir;
109 u32 dialog_result = 1;
110 s32 return_value = 1;
111 u32 current_file_selection;
112 u32 current_file_scroll_value;
113 u32 current_dir_selection;
114 u32 current_dir_scroll_value;
115 u32 current_file_in_scroll;
116 u32 current_dir_in_scroll;
117 u32 current_file_number, current_dir_number;
118 u32 current_column = 0;
119 u32 repeat;
120 u32 i;
121 gui_action_type gui_action;
122
123 while(return_value == 1)
124 {
125 current_file_selection = 0;
126 current_file_scroll_value = 0;
127 current_dir_selection = 0;
128 current_dir_scroll_value = 0;
129 current_file_in_scroll = 0;
130 current_dir_in_scroll = 0;
131
132 total_filenames_allocated = 32;
133 total_dirnames_allocated = 32;
134 file_list = (u8 **)malloc(sizeof(u8 *) * 32);
135 dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
136 memset(file_list, 0, sizeof(u8 *) * 32);
137 memset(dir_list, 0, sizeof(u8 *) * 32);
138
139 num_files = 0;
140 num_dirs = 0;
141 chosen_file = 0;
142 chosen_dir = 0;
143
144 getcwd(current_dir_name, MAX_PATH);
145
146 current_dir = opendir(current_dir_name);
147
148 do
149 {
150 if(current_dir)
151 current_file = readdir(current_dir);
152 else
153 current_file = NULL;
154
155 if(current_file)
156 {
157 file_name = current_file->d_name;
158 file_name_length = strlen(file_name);
159
160 if((stat(file_name, &file_info) >= 0) &&
161 ((file_name[0] != '.') || (file_name[1] == '.')))
162 {
163 if(S_ISDIR(file_info.st_mode))
164 {
165 dir_list[num_dirs] =
166 (u8 *)malloc(file_name_length + 1);
167
168 sprintf(dir_list[num_dirs], "%s", file_name);
169
170 num_dirs++;
171 }
172 else
173 {
174 // Must match one of the wildcards, also ignore the .
175 if(file_name_length >= 4)
176 {
177 if(file_name[file_name_length - 4] == '.')
178 ext_pos = file_name_length - 4;
179 else
180
181 if(file_name[file_name_length - 3] == '.')
182 ext_pos = file_name_length - 3;
183
184 else
185 ext_pos = 0;
186
187 for(i = 0; wildcards[i] != NULL; i++)
188 {
189 if(!strcasecmp((file_name + ext_pos),
190 wildcards[i]))
191 {
192 file_list[num_files] =
193 (u8 *)malloc(file_name_length + 1);
194
195 sprintf(file_list[num_files], "%s", file_name);
196
197 num_files++;
198 break;
199 }
200 }
201 }
202 }
203 }
204
205 if(num_files == total_filenames_allocated)
206 {
207 file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
208 total_filenames_allocated * 2);
209 memset(file_list + total_filenames_allocated, 0,
210 sizeof(u8 *) * total_filenames_allocated);
211 total_filenames_allocated *= 2;
212 }
213
214 if(num_dirs == total_dirnames_allocated)
215 {
216 dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
217 total_dirnames_allocated * 2);
218 memset(dir_list + total_dirnames_allocated, 0,
219 sizeof(u8 *) * total_dirnames_allocated);
220 total_dirnames_allocated *= 2;
221 }
222 }
223 } while(current_file);
224
225 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
226 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
227
228 closedir(current_dir);
229
230 current_dir_length = strlen(current_dir_name);
231
232 if(current_dir_length > 80)
233 {
234
235#ifdef GP2X_BUILD
236 snprintf(current_dir_short, 80,
237 "...%s", current_dir_name + current_dir_length - 77);
238#else
239 memcpy(current_dir_short, "...", 3);
240 memcpy(current_dir_short + 3,
241 current_dir_name + current_dir_length - 77, 77);
242 current_dir_short[80] = 0;
243#endif
244 }
245 else
246 {
247#ifdef GP2X_BUILD
248 snprintf(current_dir_short, 80, "%s", current_dir_name);
249#else
250 memcpy(current_dir_short, current_dir_name,
251 current_dir_length + 1);
252#endif
253 }
254
255 repeat = 1;
256
257 if(num_files == 0)
258 current_column = 1;
259
260 clear_screen(COLOR_BG);
261 {
262 u8 print_buffer[81];
263
264 while(repeat)
265 {
266 flip_screen();
267
268 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
269#ifdef GP2X_BUILD
270 print_string("Press X to return to the main menu.",
271 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
272#else
273 print_string("Press X to return to the main menu.",
274 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
275#endif
276
277 for(i = 0, current_file_number = i + current_file_scroll_value;
278 i < FILE_LIST_ROWS; i++, current_file_number++)
279 {
280 if(current_file_number < num_files)
281 {
282 if((current_file_number == current_file_selection) &&
283 (current_column == 0))
284 {
285 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
286 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
287 }
288 else
289 {
290 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
291 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
292 }
293 }
294 }
295
296 for(i = 0, current_dir_number = i + current_dir_scroll_value;
297 i < FILE_LIST_ROWS; i++, current_dir_number++)
298 {
299 if(current_dir_number < num_dirs)
300 {
301 if((current_dir_number == current_dir_selection) &&
302 (current_column == 1))
303 {
304 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
305 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
306 }
307 else
308 {
309 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
310 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
311 }
312 }
313 }
314
315 gui_action = get_gui_input();
316
317 switch(gui_action)
318 {
319 case CURSOR_DOWN:
320 if(current_column == 0)
321 {
322 if(current_file_selection < (num_files - 1))
323 {
324 current_file_selection++;
325 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
326 {
327 clear_screen(COLOR_BG);
328 current_file_scroll_value++;
329 }
330 else
331 {
332 current_file_in_scroll++;
333 }
334 }
335 }
336 else
337 {
338 if(current_dir_selection < (num_dirs - 1))
339 {
340 current_dir_selection++;
341 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
342 {
343 clear_screen(COLOR_BG);
344 current_dir_scroll_value++;
345 }
346 else
347 {
348 current_dir_in_scroll++;
349 }
350 }
351 }
352
353 break;
354
355 case CURSOR_UP:
356 if(current_column == 0)
357 {
358 if(current_file_selection)
359 {
360 current_file_selection--;
361 if(current_file_in_scroll == 0)
362 {
363 clear_screen(COLOR_BG);
364 current_file_scroll_value--;
365 }
366 else
367 {
368 current_file_in_scroll--;
369 }
370 }
371 }
372 else
373 {
374 if(current_dir_selection)
375 {
376 current_dir_selection--;
377 if(current_dir_in_scroll == 0)
378 {
379 clear_screen(COLOR_BG);
380 current_dir_scroll_value--;
381 }
382 else
383 {
384 current_dir_in_scroll--;
385 }
386 }
387 }
388 break;
389
390 case CURSOR_RIGHT:
391 if(current_column == 0)
392 {
393 if(num_dirs != 0)
394 current_column = 1;
395 }
396 break;
397
398 case CURSOR_LEFT:
399 if(current_column == 1)
400 {
401 if(num_files != 0)
402 current_column = 0;
403 }
404 break;
405
406 case CURSOR_SELECT:
407 if(current_column == 1)
408 {
409 repeat = 0;
410 chdir(dir_list[current_dir_selection]);
411 }
412 else
413 {
414 if(num_files != 0)
415 {
416 repeat = 0;
417 return_value = 0;
418 strcpy(result, file_list[current_file_selection]);
419 }
420 }
421 break;
422
423 case CURSOR_BACK:
424#ifdef PSP_BUILD
425 if(!strcmp(current_dir_name, "ms0:/PSP"))
426 break;
427#endif
428 repeat = 0;
429 chdir("..");
430 break;
431
432 case CURSOR_EXIT:
433 return_value = -1;
434 repeat = 0;
435 break;
436 }
437 }
438 }
439
440 for(i = 0; i < num_files; i++)
441 {
442 free(file_list[i]);
443 }
444 free(file_list);
445
446 for(i = 0; i < num_dirs; i++)
447 {
448 free(dir_list[i]);
449 }
450 free(dir_list);
451 }
452
453 clear_screen(COLOR_BG);
454
455 return return_value;
456}
457
458typedef enum
459{
460 NUMBER_SELECTION_OPTION = 0x01,
461 STRING_SELECTION_OPTION = 0x02,
462 SUBMENU_OPTION = 0x04,
463 ACTION_OPTION = 0x08
464} menu_option_type_enum;
465
466struct _menu_type
467{
468 void (* init_function)();
469 void (* passive_function)();
470 struct _menu_option_type *options;
471 u32 num_options;
472};
473
474struct _menu_option_type
475{
476 void (* action_function)();
477 void (* passive_function)();
478 struct _menu_type *sub_menu;
479 char *display_string;
480 void *options;
481 u32 *current_option;
482 u32 num_options;
483 char *help_string;
484 u32 line_number;
485 menu_option_type_enum option_type;
486};
487
488typedef struct _menu_option_type menu_option_type;
489typedef struct _menu_type menu_type;
490
491#define make_menu(name, init_function, passive_function) \
492 menu_type name##_menu = \
493 { \
494 init_function, \
495 passive_function, \
496 name##_options, \
497 sizeof(name##_options) / sizeof(menu_option_type) \
498 } \
499
500#define gamepad_config_option(display_string, number) \
501{ \
502 NULL, \
503 menu_fix_gamepad_help, \
504 NULL, \
505 display_string ": %s", \
506 gamepad_config_buttons, \
507 gamepad_config_map + gamepad_config_line_to_button[number], \
508 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
509 gamepad_help[gamepad_config_map[ \
510 gamepad_config_line_to_button[number]]], \
511 number, \
512 STRING_SELECTION_OPTION \
513} \
514
515#define analog_config_option(display_string, number) \
516{ \
517 NULL, \
518 menu_fix_gamepad_help, \
519 NULL, \
520 display_string ": %s", \
521 gamepad_config_buttons, \
522 gamepad_config_map + number + 12, \
523 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
524 gamepad_help[gamepad_config_map[number + 12]], \
525 number + 2, \
526 STRING_SELECTION_OPTION \
527} \
528
529#define cheat_option(number) \
530{ \
531 NULL, \
532 NULL, \
533 NULL, \
534 cheat_format_str[number], \
535 enable_disable_options, \
536 &(cheats[number].cheat_active), \
537 2, \
538 "Activate/deactivate this cheat code.", \
539 number, \
540 STRING_SELECTION_OPTION \
541} \
542
543#define action_option(action_function, passive_function, display_string, \
544 help_string, line_number) \
545{ \
546 action_function, \
547 passive_function, \
548 NULL, \
549 display_string, \
550 NULL, \
551 NULL, \
552 0, \
553 help_string, \
554 line_number, \
555 ACTION_OPTION \
556} \
557
558#define submenu_option(sub_menu, display_string, help_string, line_number) \
559{ \
560 NULL, \
561 NULL, \
562 sub_menu, \
563 display_string, \
564 NULL, \
565 NULL, \
566 sizeof(sub_menu) / sizeof(menu_option_type), \
567 help_string, \
568 line_number, \
569 SUBMENU_OPTION \
570} \
571
572#define selection_option(passive_function, display_string, options, \
573 option_ptr, num_options, help_string, line_number, type) \
574{ \
575 NULL, \
576 passive_function, \
577 NULL, \
578 display_string, \
579 options, \
580 option_ptr, \
581 num_options, \
582 help_string, \
583 line_number, \
584 type \
585} \
586
587#define action_selection_option(action_function, passive_function, \
588 display_string, options, option_ptr, num_options, help_string, line_number, \
589 type) \
590{ \
591 action_function, \
592 passive_function, \
593 NULL, \
594 display_string, \
595 options, \
596 option_ptr, \
597 num_options, \
598 help_string, \
599 line_number, \
600 type | ACTION_OPTION \
601} \
602
603
604#define string_selection_option(passive_function, display_string, options, \
605 option_ptr, num_options, help_string, line_number) \
606 selection_option(passive_function, display_string ": %s", options, \
607 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
608
609#define numeric_selection_option(passive_function, display_string, \
610 option_ptr, num_options, help_string, line_number) \
611 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
612 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
613
614#define string_selection_action_option(action_function, passive_function, \
615 display_string, options, option_ptr, num_options, help_string, line_number) \
616 action_selection_option(action_function, passive_function, \
617 display_string ": %s", options, option_ptr, num_options, help_string, \
618 line_number, STRING_SELECTION_OPTION) \
619
620#define numeric_selection_action_option(action_function, passive_function, \
621 display_string, option_ptr, num_options, help_string, line_number) \
622 action_selection_option(action_function, passive_function, \
623 display_string ": %d", NULL, option_ptr, num_options, help_string, \
624 line_number, NUMBER_SELECTION_OPTION) \
625
626#define numeric_selection_action_hide_option(action_function, \
627 passive_function, display_string, option_ptr, num_options, help_string, \
628 line_number) \
629 action_selection_option(action_function, passive_function, \
630 display_string, NULL, option_ptr, num_options, help_string, \
631 line_number, NUMBER_SELECTION_OPTION) \
632
633
634#define GAMEPAD_MENU_WIDTH 15
635
636#ifdef PSP_BUILD
637
638u32 gamepad_config_line_to_button[] =
639 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
640
641#endif
642
643#ifdef GP2X_BUILD
644
645u32 gamepad_config_line_to_button[] =
646 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5 };
647
648#endif
649
650
651s32 load_game_config_file()
652{
653 u8 game_config_filename[512];
654 u32 file_loaded = 0;
655 u32 i;
656 change_ext(gamepak_filename, game_config_filename, ".cfg");
657
658 file_open(game_config_file, game_config_filename, read);
659
660 if(file_check_valid(game_config_file))
661 {
662 u32 file_size = file_length(game_config_filename, game_config_file);
663
664 // Sanity check: File size must be the right size
665 if(file_size == 56)
666 {
667 u32 file_options[file_size / 4];
668
669 file_read_array(game_config_file, file_options);
670 current_frameskip_type = file_options[0] % 3;
671 frameskip_value = file_options[1];
672 random_skip = file_options[2] % 2;
673 clock_speed = file_options[3];
674
675 if(clock_speed > 333)
676 clock_speed = 333;
677
678 if(clock_speed < 33)
679 clock_speed = 33;
680
681 if(frameskip_value < 0)
682 frameskip_value = 0;
683
684 if(frameskip_value > 99)
685 frameskip_value = 99;
686
687 for(i = 0; i < 10; i++)
688 {
689 cheats[i].cheat_active = file_options[3 + i] % 2;
690 cheats[i].cheat_name[0] = 0;
691 }
692
693 file_close(game_config_file);
694 file_loaded = 1;
695 }
696 }
697
698 if(file_loaded)
699 return 0;
700
701 current_frameskip_type = auto_frameskip;
702 frameskip_value = 4;
703 random_skip = 0;
704 clock_speed = 333;
705
706 for(i = 0; i < 10; i++)
707 {
708 cheats[i].cheat_active = 0;
709 cheats[i].cheat_name[0] = 0;
710 }
711
712 return -1;
713}
714
715s32 load_config_file()
716{
717 u8 config_path[512];
718
719 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
720 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
721 #else
722 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
723 #endif
724
725 file_open(config_file, config_path, read);
726
727 if(file_check_valid(config_file))
728 {
729 u32 file_size = file_length(config_path, config_file);
730
731 // Sanity check: File size must be the right size
732 if(file_size == 92)
733 {
734 u32 file_options[file_size / 4];
735 u32 i;
736 s32 menu_button = -1;
737 file_read_array(config_file, file_options);
738
739 screen_scale = file_options[0] % 3;
740 screen_filter = file_options[1] % 2;
741 global_enable_audio = file_options[2] % 2;
742
743#ifdef PSP_BUILD
744 audio_buffer_size_number = file_options[3] % 10;
745#else
746 audio_buffer_size_number = file_options[3] % 11;
747#endif
748
749 update_backup_flag = file_options[4] % 2;
750 global_enable_analog = file_options[5] % 2;
751 analog_sensitivity_level = file_options[6] % 8;
752
753#ifdef PSP_BUILD
754 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
755#endif
756
757 // Sanity check: Make sure there's a MENU or FRAMESKIP
758 // key, if not assign to triangle
759
760#ifndef PC_BUILD
761 for(i = 0; i < 16; i++)
762 {
763 gamepad_config_map[i] = file_options[7 + i] %
764 (BUTTON_ID_NONE + 1);
765
766 if(gamepad_config_map[i] == BUTTON_ID_MENU)
767 {
768 menu_button = i;
769 }
770 }
771
772 if(menu_button == -1)
773 {
774 gamepad_config_map[0] = BUTTON_ID_MENU;
775 }
776#endif
777
778 file_close(config_file);
779 }
780
781 return 0;
782 }
783
784 return -1;
785}
786
787s32 save_game_config_file()
788{
789 u8 game_config_filename[512];
790 u32 i;
791
792 change_ext(gamepak_filename, game_config_filename, ".cfg");
793
794 file_open(game_config_file, game_config_filename, write);
795
796 if(file_check_valid(game_config_file))
797 {
798 u32 file_options[14];
799
800 file_options[0] = current_frameskip_type;
801 file_options[1] = frameskip_value;
802 file_options[2] = random_skip;
803 file_options[3] = clock_speed;
804
805 for(i = 0; i < 10; i++)
806 {
807 file_options[4 + i] = cheats[i].cheat_active;
808 }
809
810 file_write_array(game_config_file, file_options);
811
812 file_close(game_config_file);
813
814 return 0;
815 }
816
817 return -1;
818}
819
820s32 save_config_file()
821{
822 u8 config_path[512];
823
824 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
825 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
826 #else
827 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
828 #endif
829
830 file_open(config_file, config_path, write);
831
832 save_game_config_file();
833
834 if(file_check_valid(config_file))
835 {
836 u32 file_options[23];
837 u32 i;
838
839 file_options[0] = screen_scale;
840 file_options[1] = screen_filter;
841 file_options[2] = global_enable_audio;
842 file_options[3] = audio_buffer_size_number;
843 file_options[4] = update_backup_flag;
844 file_options[5] = global_enable_analog;
845 file_options[6] = analog_sensitivity_level;
846
847#ifndef PC_BUILD
848 for(i = 0; i < 16; i++)
849 {
850 file_options[7 + i] = gamepad_config_map[i];
851 }
852#endif
853
854 file_write_array(config_file, file_options);
855
856 file_close(config_file);
857
858 return 0;
859 }
860
861 return -1;
862}
863
864typedef enum
865{
866 MAIN_MENU,
867 GAMEPAD_MENU,
868 SAVESTATE_MENU,
869 FRAMESKIP_MENU,
870 CHEAT_MENU
871} menu_enum;
872
873u32 savestate_slot = 0;
874
875void get_savestate_snapshot(u8 *savestate_filename)
876{
877 u16 snapshot_buffer[240 * 160];
878 u8 savestate_timestamp_string[80];
879
880 file_open(savestate_file, savestate_filename, read);
881
882 if(file_check_valid(savestate_file))
883 {
884 u8 weekday_strings[7][11] =
885 {
886 "Sunday", "Monday", "Tuesday", "Wednesday",
887 "Thursday", "Friday", "Saturday"
888 };
889 time_t savestate_time_flat;
890 struct tm *current_time;
891 file_read_array(savestate_file, snapshot_buffer);
892 file_read_variable(savestate_file, savestate_time_flat);
893
894 file_close(savestate_file);
895
896 current_time = localtime(&savestate_time_flat);
897 sprintf(savestate_timestamp_string,
898 "%s %02d/%02d/%04d %02d:%02d:%02d ",
899 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
900 current_time->tm_mday, current_time->tm_year + 1900,
901 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
902
903 savestate_timestamp_string[40] = 0;
904 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
905 10, 40);
906 }
907 else
908 {
909 memset(snapshot_buffer, 0, 240 * 160 * 2);
910 print_string_ext("No savestate exists for this slot.",
911 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0);
912 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
913 COLOR_BG, 10, 40);
914 }
915
916#ifndef GP2X_BUILD
917 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
918#endif
919}
920
921void get_savestate_filename(u32 slot, u8 *name_buffer)
922{
923 u8 savestate_ext[16];
924
925 sprintf(savestate_ext, "%d.svs", slot);
926 change_ext(gamepak_filename, name_buffer, savestate_ext);
927
928 get_savestate_snapshot(name_buffer);
929}
930
931void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
932{
933 u8 savestate_ext[16];
934
935 sprintf(savestate_ext, "%d.svs", slot);
936 change_ext(gamepak_filename, name_buffer, savestate_ext);
937}
938
939#ifdef PSP_BUILD
940 void _flush_cache()
941 {
942 invalidate_all_cache();
943 }
944#endif
945
946u32 menu(u16 *original_screen)
947{
948 u32 clock_speed_number = (clock_speed / 33) - 1;
949 u8 print_buffer[81];
950 u32 _current_option = 0;
951 gui_action_type gui_action;
952 menu_enum _current_menu = MAIN_MENU;
953 u32 i;
954 u32 repeat = 1;
955 u32 return_value = 0;
956 u32 first_load = 0;
957 u8 savestate_ext[16];
958 u8 current_savestate_filename[512];
959 u8 line_buffer[80];
960 u8 cheat_format_str[10][41];
961
962 menu_type *current_menu;
963 menu_option_type *current_option;
964 menu_option_type *display_option;
965 u32 current_option_num;
966
967 auto void choose_menu();
968 auto void clear_help();
969
970 u8 *gamepad_help[] =
971 {
972 "Up button on GBA d-pad.",
973 "Down button on GBA d-pad.",
974 "Left button on GBA d-pad.",
975 "Right button on GBA d-pad.",
976 "A button on GBA.",
977 "B button on GBA.",
978 "Left shoulder button on GBA.",
979 "Right shoulder button on GBA.",
980 "Start button on GBA.",
981 "Select button on GBA.",
982 "Brings up the options menu.",
983 "Toggles fastforward on/off.",
984 "Loads the game state from the current slot.",
985 "Saves the game state to the current slot.",
986 "Rapidly press/release the A button on GBA.",
987 "Rapidly press/release the B button on GBA.",
988 "Rapidly press/release the L shoulder on GBA.",
989 "Rapidly press/release the R shoulder on GBA.",
990 "Increases the volume.",
991 "Decreases the volume.",
992 "Displays virtual/drawn frames per second.",
993 "Does nothing."
994 };
995
996 void menu_exit()
997 {
998 if(!first_load)
999 repeat = 0;
1000 }
1001
1002 void menu_quit()
1003 {
1004 clock_speed = (clock_speed_number + 1) * 33;
1005 save_config_file();
1006 quit();
1007 }
1008
1009 void menu_load()
1010 {
1011 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1012 u8 load_filename[512];
1013 save_game_config_file();
1014 if(load_file(file_ext, load_filename) != -1)
1015 {
1016 if(load_gamepak(load_filename) == -1)
1017 {
1018 quit();
1019 }
1020 reset_gba();
1021 return_value = 1;
1022 repeat = 0;
1023 reg[CHANGED_PC_STATUS] = 1;
1024 }
1025 else
1026 {
1027 choose_menu(current_menu);
1028 }
1029 }
1030
1031 void menu_restart()
1032 {
1033 if(!first_load)
1034 {
1035 reset_gba();
1036 reg[CHANGED_PC_STATUS] = 1;
1037 return_value = 1;
1038 repeat = 0;
1039 }
1040 }
1041
1042 void menu_change_state()
1043 {
1044 get_savestate_filename(savestate_slot, current_savestate_filename);
1045 }
1046
1047 void menu_save_state()
1048 {
1049 if(!first_load)
1050 {
1051 get_savestate_filename_noshot(savestate_slot,
1052 current_savestate_filename);
1053 save_state(current_savestate_filename, original_screen);
1054 }
1055 menu_change_state();
1056 }
1057
1058 void menu_load_state()
1059 {
1060 if(!first_load)
1061 {
1062 load_state(current_savestate_filename);
1063 return_value = 1;
1064 repeat = 0;
1065 }
1066 }
1067
1068 void menu_load_state_file()
1069 {
1070 u8 *file_ext[] = { ".svs", NULL };
1071 u8 load_filename[512];
1072 if(load_file(file_ext, load_filename) != -1)
1073 {
1074 load_state(load_filename);
1075 return_value = 1;
1076 repeat = 0;
1077 }
1078 else
1079 {
1080 choose_menu(current_menu);
1081 }
1082 }
1083
1084 void menu_fix_gamepad_help()
1085 {
1086#ifndef PC_BUILD
1087 clear_help();
1088 current_option->help_string =
1089 gamepad_help[gamepad_config_map[
1090 gamepad_config_line_to_button[current_option_num]]];
1091#endif
1092 }
1093
1094 void submenu_graphics_sound()
1095 {
1096
1097 }
1098
1099 void submenu_cheats_misc()
1100 {
1101
1102 }
1103
1104 void submenu_gamepad()
1105 {
1106
1107 }
1108
1109 void submenu_analog()
1110 {
1111
1112 }
1113
1114 void submenu_savestate()
1115 {
1116 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1117 menu_change_state();
1118 }
1119
1120 void submenu_main()
1121 {
1122 strncpy(print_buffer, gamepak_filename, 80);
1123 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1124 sprintf(print_buffer, "%s %s %s", gamepak_title,
1125 gamepak_code, gamepak_maker);
1126 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1127
1128 get_savestate_filename_noshot(savestate_slot,
1129 current_savestate_filename);
1130 }
1131
1132 u8 *yes_no_options[] = { "no", "yes" };
1133 u8 *enable_disable_options[] = { "disabled", "enabled" };
1134
1135 u8 *scale_options[] =
1136 {
1137 "unscaled 3:2", "scaled 3:2", "fullscreen 16:9"
1138 };
1139
1140 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1141 u8 *frameskip_variation_options[] = { "uniform", "random" };
1142
1143#ifndef PSP_BUILD
1144 u8 *audio_buffer_options[] =
1145 {
1146 "16 bytes", "32 bytes", "64 bytes",
1147 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1148 "4096 bytes", "8192 bytes", "16284 bytes"
1149 };
1150#else
1151 u8 *audio_buffer_options[] =
1152 {
1153 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1154 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1155 };
1156
1157#endif
1158
1159 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1160
1161 u8 *clock_speed_options[] =
1162 {
1163 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
1164 "266MHz", "300MHz", "333MHz"
1165 };
1166
1167 u8 *gamepad_config_buttons[] =
1168 {
1169 "UP",
1170 "DOWN",
1171 "LEFT",
1172 "RIGHT",
1173 "A",
1174 "B",
1175 "L",
1176 "R",
1177 "START",
1178 "SELECT",
1179 "MENU",
1180 "FASTFORWARD",
1181 "LOAD STATE",
1182 "SAVE STATE",
1183 "RAPIDFIRE A",
1184 "RAPIDFIRE B",
1185 "RAPIDFIRE L",
1186 "RAPIDFIRE R",
1187 "VOLUME UP",
1188 "VOLUME DOWN",
1189 "DISPLAY FPS",
1190 "NOTHING"
1191 };
1192
1193 // Marker for help information, don't go past this mark (except \n)------*
1194 menu_option_type graphics_sound_options[] =
1195 {
1196 string_selection_option(NULL, "Display scaling", scale_options,
1197 (u32 *)(&screen_scale), 3,
1198 "Determines how the GBA screen is resized in relation to the entire\n"
1199 "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1200 "aspect ratio scaled to fill the height of the PSP screen, and\n"
1201 "fullscreen to fill the entire PSP screen.", 2),
1202 string_selection_option(NULL, "Screen filtering", yes_no_options,
1203 (u32 *)(&screen_filter), 2,
1204 "Determines whether or not bilinear filtering should be used when\n"
1205 "scaling the screen. Selecting this will produce a more even and\n"
1206 "smooth image, at the cost of being blurry and having less vibrant\n"
1207 "colors.", 3),
1208 string_selection_option(NULL, "Frameskip type", frameskip_options,
1209 (u32 *)(&current_frameskip_type), 3,
1210 "Determines what kind of frameskipping should be employed.\n"
1211 "Frameskipping may improve emulation speed of many games.\n"
1212 "Off: Do not skip any frames.\n"
1213 "Auto: Skip up to N frames (see next option) as needed.\n"
1214 "Manual: Always render only 1 out of N + 1 frames.", 5),
1215 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1216 "For auto frameskip, determines the maximum number of frames that\n"
1217 "are allowed to be skipped consecutively.\n"
1218 "For manual frameskip, determines the number of frames that will\n"
1219 "always be skipped.", 6),
1220 string_selection_option(NULL, "Framskip variation",
1221 frameskip_variation_options, &random_skip, 2,
1222 "If objects in the game flicker at a regular rate certain manual\n"
1223 "frameskip values may cause them to normally disappear. Change this\n"
1224 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
1225 "make the image quality worse, especially in high motion games.", 7),
1226 string_selection_option(NULL, "Audio output", yes_no_options,
1227 &global_enable_audio, 2,
1228 "Select 'no' to turn off all audio output. This will not result in a\n"
1229 "significant change in performance.", 9),
1230#ifndef PSP_BUILD
1231 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1232 &audio_buffer_size_number, 11,
1233#else
1234 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1235 &audio_buffer_size_number, 10,
1236#endif
1237
1238 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1239 "in slightly better performance at the cost of latency; the lowest\n"
1240 "value will give the most responsive audio.\n"
1241 "This option requires gpSP to be restarted before it will take effect.",
1242 10),
1243 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1244 };
1245
1246 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1247
1248 menu_option_type cheats_misc_options[] =
1249 {
1250 cheat_option(0),
1251 cheat_option(1),
1252 cheat_option(2),
1253 cheat_option(3),
1254 cheat_option(4),
1255 cheat_option(5),
1256 cheat_option(6),
1257 cheat_option(7),
1258 cheat_option(8),
1259 cheat_option(9),
1260 string_selection_option(NULL, "Clock speed",
1261 clock_speed_options, &clock_speed_number, 10,
1262 "Change the clock speed of the device. Higher clock speed will yield\n"
1263 "better performance, but will use drain battery life further.", 11),
1264 string_selection_option(NULL, "Update backup",
1265 update_backup_options, &update_backup_flag, 2,
1266 "Determines when in-game save files should be written back to\n"
1267 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1268 "the game's backup is altered. On 'exit only' it will only be written\n"
1269 "back when you exit from this menu (NOT from using the home button).\n"
1270 "Use the latter with extreme care.", 12),
1271 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1272 };
1273
1274 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1275
1276 menu_option_type savestate_options[] =
1277 {
1278 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1279 "Load savestate from current slot", &savestate_slot, 10,
1280 "Select to load the game state from the current slot for this game.\n"
1281 "Press left + right to change the current slot.", 6),
1282 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1283 "Save savestate to current slot", &savestate_slot, 10,
1284 "Select to save the game state to the current slot for this game.\n"
1285 "Press left + right to change the current slot.", 7),
1286 numeric_selection_action_hide_option(menu_load_state_file,
1287 menu_change_state,
1288 "Load savestate from file", &savestate_slot, 10,
1289 "Restore gameplay from a savestate file.\n"
1290 "Note: The same file used to save the state must be present.\n", 9),
1291 numeric_selection_option(menu_change_state,
1292 "Current savestate slot", &savestate_slot, 10,
1293 "Change the current savestate slot.\n", 11),
1294 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1295 };
1296
1297 make_menu(savestate, submenu_savestate, NULL);
1298
1299#ifdef PSP_BUILD
1300
1301 menu_option_type gamepad_config_options[] =
1302 {
1303 gamepad_config_option("D-pad up ", 0),
1304 gamepad_config_option("D-pad down ", 1),
1305 gamepad_config_option("D-pad left ", 2),
1306 gamepad_config_option("D-pad right ", 3),
1307 gamepad_config_option("Circle ", 4),
1308 gamepad_config_option("Cross ", 5),
1309 gamepad_config_option("Square ", 6),
1310 gamepad_config_option("Triangle ", 7),
1311 gamepad_config_option("Left Trigger ", 8),
1312 gamepad_config_option("Right Trigger", 9),
1313 gamepad_config_option("Start ", 10),
1314 gamepad_config_option("Select ", 11),
1315 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1316 };
1317
1318
1319 menu_option_type analog_config_options[] =
1320 {
1321 analog_config_option("Analog up ", 0),
1322 analog_config_option("Analog down ", 1),
1323 analog_config_option("Analog left ", 2),
1324 analog_config_option("Analog right", 3),
1325 string_selection_option(NULL, "Enable analog", yes_no_options,
1326 &global_enable_analog, 2,
1327 "Select 'no' to block analog input entirely.", 7),
1328 numeric_selection_option(NULL, "Analog sensitivity",
1329 &analog_sensitivity_level, 10,
1330 "Determine sensitivity/responsiveness of the analog input.\n"
1331 "Lower numbers are less sensitive.", 8),
1332 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1333 };
1334
1335#endif
1336
1337#ifdef GP2X_BUILD
1338
1339 menu_option_type gamepad_config_options[] =
1340 {
1341 gamepad_config_option("D-pad up ", 0),
1342 gamepad_config_option("D-pad down ", 1),
1343 gamepad_config_option("D-pad left ", 2),
1344 gamepad_config_option("D-pad right ", 3),
1345 gamepad_config_option("A ", 4),
1346 gamepad_config_option("B ", 5),
1347 gamepad_config_option("X ", 6),
1348 gamepad_config_option("Y ", 7),
1349 gamepad_config_option("Left Trigger ", 8),
1350 gamepad_config_option("Right Trigger", 9),
1351 gamepad_config_option("Start ", 10),
1352 gamepad_config_option("Select ", 11),
1353 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1354 };
1355
1356
1357 menu_option_type analog_config_options[] =
1358 {
1359 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1360 };
1361
1362#endif
1363
1364#ifdef PC_BUILD
1365
1366 menu_option_type gamepad_config_options[] =
1367 {
1368 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1369 };
1370
1371 menu_option_type analog_config_options[] =
1372 {
1373 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1374 };
1375
1376#endif
1377
1378 make_menu(gamepad_config, submenu_gamepad, NULL);
1379 make_menu(analog_config, submenu_analog, NULL);
1380
1381 menu_option_type main_options[] =
1382 {
1383 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1384 "Select to set display parameters and frameskip behavior,\n"
1385 "audio on/off, audio buffer size, and audio filtering.", 0),
1386 numeric_selection_action_option(menu_load_state, NULL,
1387 "Load state from slot", &savestate_slot, 10,
1388 "Select to load the game state from the current slot for this game,\n"
1389 "if it exists (see the extended menu for more information)\n"
1390 "Press left + right to change the current slot.", 2),
1391 numeric_selection_action_option(menu_save_state, NULL,
1392 "Save state to slot", &savestate_slot, 10,
1393 "Select to save the game state to the current slot for this game.\n"
1394 "See the extended menu for more information.\n"
1395 "Press left + right to change the current slot.", 3),
1396 submenu_option(&savestate_menu, "Savestate options",
1397 "Select to enter a menu for loading, saving, and viewing the\n"
1398 "currently active savestate for this game (or to load a savestate\n"
1399 "file from another game)", 4),
1400 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1401 "Select to change the in-game behavior of the PSP buttons and d-pad.",
1402 6),
1403 submenu_option(&analog_config_menu, "Configure analog input",
1404 "Select to change the in-game behavior of the PSP analog nub.", 7),
1405 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1406 "Select to manage cheats, set backup behavior, and set device clock\n"
1407 "speed.", 9),
1408 action_option(menu_load, NULL, "Load new game",
1409 "Select to load a new game (will exit a game if currently playing).",
1410 11),
1411 action_option(menu_restart, NULL, "Restart game",
1412 "Select to reset the GBA with the current game loaded.", 12),
1413 action_option(menu_exit, NULL, "Return to game",
1414 "Select to exit this menu and resume gameplay.", 13),
1415 action_option(menu_quit, NULL, "Exit gpSP",
1416 "Select to exit gpSP and return to the PSP XMB/loader.", 15)
1417 };
1418
1419 make_menu(main, submenu_main, NULL);
1420
1421 void choose_menu(menu_type *new_menu)
1422 {
1423 if(new_menu == NULL)
1424 new_menu = &main_menu;
1425
1426 clear_screen(COLOR_BG);
1427
1428#ifndef GP2X_BUILD
1429 blit_to_screen(original_screen, 240, 160, 230, 40);
1430#endif
1431
1432 current_menu = new_menu;
1433 current_option = new_menu->options;
1434 current_option_num = 0;
1435 if(current_menu->init_function)
1436 current_menu->init_function();
1437 }
1438
1439 void clear_help()
1440 {
1441 for(i = 0; i < 6; i++)
1442 {
1443 print_string_pad(" ", COLOR_BG, COLOR_BG, 30, 210 + (i * 10), 70);
1444 }
1445 }
1446
1447 video_resolution_large();
1448
1449#ifndef GP2X_BUILD
1450 SDL_LockMutex(sound_mutex);
1451#endif
1452 SDL_PauseAudio(1);
1453
1454#ifndef GP2X_BUILD
1455 SDL_UnlockMutex(sound_mutex);
1456#endif
1457
1458 if(gamepak_filename[0] == 0)
1459 {
1460 first_load = 1;
1461 memset(original_screen, 0x00, 240 * 160 * 2);
1462 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1463 60, 75,original_screen, 240, 0);
1464 }
1465
1466 choose_menu(&main_menu);
1467
1468 for(i = 0; i < 10; i++)
1469 {
1470 if(i >= num_cheats)
1471 {
1472 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1473 }
1474 else
1475 {
1476 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1477 cheats[i].cheat_name);
1478 }
1479 }
1480
1481 current_menu->init_function();
1482
1483 while(repeat)
1484 {
1485 display_option = current_menu->options;
1486
1487 for(i = 0; i < current_menu->num_options; i++, display_option++)
1488 {
1489 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1490 {
1491 sprintf(line_buffer, display_option->display_string,
1492 *(display_option->current_option));
1493 }
1494 else
1495
1496 if(display_option->option_type & STRING_SELECTION_OPTION)
1497 {
1498 sprintf(line_buffer, display_option->display_string,
1499 ((u32 *)display_option->options)[*(display_option->current_option)]);
1500 }
1501 else
1502 {
1503 strcpy(line_buffer, display_option->display_string);
1504 }
1505
1506 if(display_option == current_option)
1507 {
1508 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1509 (display_option->line_number * 10) + 40, 36);
1510 }
1511 else
1512 {
1513 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1514 (display_option->line_number * 10) + 40, 36);
1515 }
1516 }
1517
1518 print_string(current_option->help_string, COLOR_HELP_TEXT,
1519 COLOR_BG, 30, 210);
1520
1521 flip_screen();
1522
1523 gui_action = get_gui_input();
1524
1525 switch(gui_action)
1526 {
1527 case CURSOR_DOWN:
1528 current_option_num = (current_option_num + 1) %
1529 current_menu->num_options;
1530
1531 current_option = current_menu->options + current_option_num;
1532 clear_help();
1533 break;
1534
1535 case CURSOR_UP:
1536 if(current_option_num)
1537 current_option_num--;
1538 else
1539 current_option_num = current_menu->num_options - 1;
1540
1541 current_option = current_menu->options + current_option_num;
1542 clear_help();
1543 break;
1544
1545 case CURSOR_RIGHT:
1546 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1547 STRING_SELECTION_OPTION))
1548 {
1549 *(current_option->current_option) =
1550 (*current_option->current_option + 1) %
1551 current_option->num_options;
1552
1553 if(current_option->passive_function)
1554 current_option->passive_function();
1555 }
1556 break;
1557
1558 case CURSOR_LEFT:
1559 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1560 STRING_SELECTION_OPTION))
1561 {
1562 u32 current_option_val = *(current_option->current_option);
1563
1564 if(current_option_val)
1565 current_option_val--;
1566 else
1567 current_option_val = current_option->num_options - 1;
1568
1569 *(current_option->current_option) = current_option_val;
1570
1571 if(current_option->passive_function)
1572 current_option->passive_function();
1573 }
1574 break;
1575
1576 case CURSOR_EXIT:
1577 if(current_menu == &main_menu)
1578 menu_exit();
1579
1580 choose_menu(&main_menu);
1581 break;
1582
1583 case CURSOR_SELECT:
1584 if(current_option->option_type & ACTION_OPTION)
1585 current_option->action_function();
1586
1587 if(current_option->option_type & SUBMENU_OPTION)
1588 choose_menu(current_option->sub_menu);
1589 break;
1590 }
1591 }
1592
1593 set_gba_resolution(screen_scale);
1594 video_resolution_small();
1595
1596 clock_speed = (clock_speed_number + 1) * 33;
1597
1598 #ifdef PSP_BUILD
1599 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
1600 #endif
1601
1602 SDL_PauseAudio(0);
1603
1604 return return_value;
1605}