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