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