initial pandora port, with hardware scaling and stuff
[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
8b6232a6 19#include "common.h"
20#include "font.h"
21
2823a4c8 22#ifndef _WIN32_WCE
23
24#include <sys/stat.h>
25#include <unistd.h>
26#include <ctype.h>
27#include <dirent.h>
28
29#endif
30
2823a4c8 31#define MAX_PATH 1024
32
33// Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
34
35#ifdef GP2X_BUILD
36
ee0a3871 37#define FILE_LIST_ROWS 20
2823a4c8 38#define FILE_LIST_POSITION 5
39#define DIR_LIST_POSITION 260
40
41#else
42
43#define FILE_LIST_ROWS 25
44#define FILE_LIST_POSITION 5
45#define DIR_LIST_POSITION 360
46
47#endif
48
49#ifdef PSP_BUILD
50
ee0a3871 51#define COLOR_BG color16(2, 8, 10)
52
2823a4c8 53#define color16(red, green, blue) \
54 (blue << 11) | (green << 5) | red \
55
56#else
57
2823a4c8 58#define COLOR_BG color16(0, 0, 0)
59
ee0a3871 60#define color16(red, green, blue) \
61 (red << 11) | (green << 5) | blue \
2823a4c8 62
63#endif
64
65#define COLOR_ROM_INFO color16(22, 36, 26)
66#define COLOR_ACTIVE_ITEM color16(31, 63, 31)
67#define COLOR_INACTIVE_ITEM color16(13, 40, 18)
68#define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
69#define COLOR_HELP_TEXT color16(16, 40, 24)
70
638cc626 71#ifdef PSP_BUILD
1d02ca75 72 u8 *clock_speed_options[] =
73 {
74 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
75 "266MHz", "300MHz", "333MHz"
76 };
77 #define menu_get_clock_speed() \
638cc626 78 clock_speed = (clock_speed_number + 1) * 33
79 #define get_clock_speed_number() \
80 clock_speed_number = (clock_speed / 33) - 1
81#elif defined(WIZ_BUILD)
1d02ca75 82 u8 *clock_speed_options[] =
83 {
84 "300MHz", "333MHz", "366MHz", "400MHz", "433MHz",
85 "466MHz", "500MHz", "533MHz", "566MHz", "600MHz",
86 "633MHz", "666MHz", "700MHz", "733MHz", "766MHz",
87 "800MHz", "833MHz", "866MHz", "900MHz"
88 };
89 #define menu_get_clock_speed() \
638cc626 90 clock_speed = 300 + (clock_speed_number * 3333) / 100
91 #define get_clock_speed_number() \
92 clock_speed_number = (clock_speed - 300) / 33
93#elif defined(GP2X_BUILD)
1d02ca75 94 u8 *clock_speed_options[] =
95 {
96 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
97 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
98 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
99 };
100 #define menu_get_clock_speed() \
638cc626 101 clock_speed = 150 + clock_speed_number * 10
102 #define get_clock_speed_number() \
103 clock_speed_number = (clock_speed - 150) / 10
104#else
1d02ca75 105 u8 *clock_speed_options[] =
106 {
107 "0"
108 };
109 #define menu_get_clock_speed() 0
638cc626 110 #define get_clock_speed_number() 0
111#endif
112
1d02ca75 113
2823a4c8 114int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
115{
116 char *dest_str = *((char **)dest_str_ptr);
117 char *src_str = *((char **)src_str_ptr);
118
119 if(src_str[0] == '.')
120 return 1;
121
122 if(dest_str[0] == '.')
123 return -1;
124
125 return strcasecmp(dest_str, src_str);
126}
127
128s32 load_file(u8 **wildcards, u8 *result)
129{
130 DIR *current_dir;
131 struct dirent *current_file;
132 struct stat file_info;
133 u8 current_dir_name[MAX_PATH];
134 u8 current_dir_short[81];
135 u32 current_dir_length;
136 u32 total_filenames_allocated;
137 u32 total_dirnames_allocated;
138 u8 **file_list;
139 u8 **dir_list;
140 u32 num_files;
141 u32 num_dirs;
142 u8 *file_name;
143 u32 file_name_length;
144 u32 ext_pos = -1;
145 u32 chosen_file, chosen_dir;
146 u32 dialog_result = 1;
147 s32 return_value = 1;
42c81190 148 s32 current_file_selection;
149 s32 current_file_scroll_value;
2823a4c8 150 u32 current_dir_selection;
151 u32 current_dir_scroll_value;
42c81190 152 s32 current_file_in_scroll;
2823a4c8 153 u32 current_dir_in_scroll;
154 u32 current_file_number, current_dir_number;
155 u32 current_column = 0;
156 u32 repeat;
157 u32 i;
158 gui_action_type gui_action;
159
160 while(return_value == 1)
161 {
162 current_file_selection = 0;
163 current_file_scroll_value = 0;
164 current_dir_selection = 0;
165 current_dir_scroll_value = 0;
166 current_file_in_scroll = 0;
167 current_dir_in_scroll = 0;
168
169 total_filenames_allocated = 32;
170 total_dirnames_allocated = 32;
171 file_list = (u8 **)malloc(sizeof(u8 *) * 32);
172 dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
173 memset(file_list, 0, sizeof(u8 *) * 32);
174 memset(dir_list, 0, sizeof(u8 *) * 32);
175
176 num_files = 0;
177 num_dirs = 0;
178 chosen_file = 0;
179 chosen_dir = 0;
180
181 getcwd(current_dir_name, MAX_PATH);
182
183 current_dir = opendir(current_dir_name);
184
185 do
186 {
187 if(current_dir)
188 current_file = readdir(current_dir);
189 else
190 current_file = NULL;
191
192 if(current_file)
193 {
194 file_name = current_file->d_name;
195 file_name_length = strlen(file_name);
196
197 if((stat(file_name, &file_info) >= 0) &&
198 ((file_name[0] != '.') || (file_name[1] == '.')))
199 {
200 if(S_ISDIR(file_info.st_mode))
201 {
202 dir_list[num_dirs] =
203 (u8 *)malloc(file_name_length + 1);
204
205 sprintf(dir_list[num_dirs], "%s", file_name);
206
207 num_dirs++;
208 }
209 else
210 {
211 // Must match one of the wildcards, also ignore the .
212 if(file_name_length >= 4)
213 {
214 if(file_name[file_name_length - 4] == '.')
215 ext_pos = file_name_length - 4;
216 else
217
218 if(file_name[file_name_length - 3] == '.')
219 ext_pos = file_name_length - 3;
220
221 else
222 ext_pos = 0;
223
224 for(i = 0; wildcards[i] != NULL; i++)
225 {
226 if(!strcasecmp((file_name + ext_pos),
227 wildcards[i]))
228 {
229 file_list[num_files] =
230 (u8 *)malloc(file_name_length + 1);
231
232 sprintf(file_list[num_files], "%s", file_name);
233
234 num_files++;
235 break;
236 }
237 }
238 }
239 }
240 }
241
242 if(num_files == total_filenames_allocated)
243 {
244 file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
245 total_filenames_allocated * 2);
246 memset(file_list + total_filenames_allocated, 0,
247 sizeof(u8 *) * total_filenames_allocated);
248 total_filenames_allocated *= 2;
249 }
250
251 if(num_dirs == total_dirnames_allocated)
252 {
253 dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
254 total_dirnames_allocated * 2);
255 memset(dir_list + total_dirnames_allocated, 0,
256 sizeof(u8 *) * total_dirnames_allocated);
257 total_dirnames_allocated *= 2;
258 }
259 }
260 } while(current_file);
261
262 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
263 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
264
265 closedir(current_dir);
266
267 current_dir_length = strlen(current_dir_name);
268
269 if(current_dir_length > 80)
270 {
271
272#ifdef GP2X_BUILD
273 snprintf(current_dir_short, 80,
274 "...%s", current_dir_name + current_dir_length - 77);
275#else
276 memcpy(current_dir_short, "...", 3);
277 memcpy(current_dir_short + 3,
278 current_dir_name + current_dir_length - 77, 77);
279 current_dir_short[80] = 0;
280#endif
281 }
282 else
283 {
284#ifdef GP2X_BUILD
285 snprintf(current_dir_short, 80, "%s", current_dir_name);
286#else
287 memcpy(current_dir_short, current_dir_name,
288 current_dir_length + 1);
289#endif
290 }
291
292 repeat = 1;
293
294 if(num_files == 0)
295 current_column = 1;
296
297 clear_screen(COLOR_BG);
298 {
299 u8 print_buffer[81];
300
301 while(repeat)
302 {
303 flip_screen();
304
305 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
306#ifdef GP2X_BUILD
307 print_string("Press X to return to the main menu.",
308 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
309#else
310 print_string("Press X to return to the main menu.",
311 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
312#endif
313
314 for(i = 0, current_file_number = i + current_file_scroll_value;
315 i < FILE_LIST_ROWS; i++, current_file_number++)
316 {
317 if(current_file_number < num_files)
318 {
319 if((current_file_number == current_file_selection) &&
320 (current_column == 0))
321 {
322 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
323 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
324 }
325 else
326 {
327 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
328 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
329 }
330 }
331 }
332
333 for(i = 0, current_dir_number = i + current_dir_scroll_value;
334 i < FILE_LIST_ROWS; i++, current_dir_number++)
335 {
336 if(current_dir_number < num_dirs)
337 {
338 if((current_dir_number == current_dir_selection) &&
339 (current_column == 1))
340 {
341 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
342 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
343 }
344 else
345 {
346 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
347 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
348 }
349 }
350 }
351
352 gui_action = get_gui_input();
353
354 switch(gui_action)
355 {
356 case CURSOR_DOWN:
357 if(current_column == 0)
358 {
359 if(current_file_selection < (num_files - 1))
360 {
361 current_file_selection++;
362 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
363 {
364 clear_screen(COLOR_BG);
365 current_file_scroll_value++;
366 }
367 else
368 {
369 current_file_in_scroll++;
370 }
371 }
42c81190 372 else
373 {
374 clear_screen(COLOR_BG);
375 current_file_selection = 0;
376 current_file_scroll_value = 0;
377 current_file_in_scroll = 0;
378 }
2823a4c8 379 }
380 else
381 {
382 if(current_dir_selection < (num_dirs - 1))
383 {
384 current_dir_selection++;
385 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
386 {
387 clear_screen(COLOR_BG);
388 current_dir_scroll_value++;
389 }
390 else
391 {
392 current_dir_in_scroll++;
393 }
394 }
395 }
396
397 break;
398
42c81190 399 case CURSOR_R:
400 if (current_column != 0)
401 break;
402 clear_screen(COLOR_BG);
403 current_file_selection += FILE_LIST_ROWS;
404 if (current_file_selection > num_files - 1)
405 current_file_selection = num_files - 1;
406 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
407 if (current_file_scroll_value < 0)
408 {
409 current_file_scroll_value = 0;
410 current_file_in_scroll = current_file_selection;
411 }
412 else
413 {
414 current_file_in_scroll = FILE_LIST_ROWS / 2;
415 }
416 break;
417
2823a4c8 418 case CURSOR_UP:
419 if(current_column == 0)
420 {
421 if(current_file_selection)
422 {
423 current_file_selection--;
424 if(current_file_in_scroll == 0)
425 {
426 clear_screen(COLOR_BG);
427 current_file_scroll_value--;
428 }
429 else
430 {
431 current_file_in_scroll--;
432 }
433 }
42c81190 434 else
435 {
436 clear_screen(COLOR_BG);
437 current_file_selection = num_files - 1;
438 current_file_in_scroll = FILE_LIST_ROWS - 1;
439 if (current_file_in_scroll > num_files - 1)
440 current_file_in_scroll = num_files - 1;
441 current_file_scroll_value = num_files - FILE_LIST_ROWS;
442 if (current_file_scroll_value < 0)
443 current_file_scroll_value = 0;
444 }
2823a4c8 445 }
446 else
447 {
448 if(current_dir_selection)
449 {
450 current_dir_selection--;
451 if(current_dir_in_scroll == 0)
452 {
453 clear_screen(COLOR_BG);
454 current_dir_scroll_value--;
455 }
456 else
457 {
458 current_dir_in_scroll--;
459 }
460 }
461 }
462 break;
463
42c81190 464 case CURSOR_L:
465 if (current_column != 0)
466 break;
467 clear_screen(COLOR_BG);
468 current_file_selection -= FILE_LIST_ROWS;
469 if (current_file_selection < 0)
470 current_file_selection = 0;
471 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
472 if (current_file_scroll_value < 0)
473 {
474 current_file_scroll_value = 0;
475 current_file_in_scroll = current_file_selection;
476 }
477 else
478 {
479 current_file_in_scroll = FILE_LIST_ROWS / 2;
480 }
481 break;
482
483 case CURSOR_RIGHT:
2823a4c8 484 if(current_column == 0)
485 {
486 if(num_dirs != 0)
487 current_column = 1;
488 }
489 break;
490
491 case CURSOR_LEFT:
492 if(current_column == 1)
493 {
494 if(num_files != 0)
495 current_column = 0;
496 }
497 break;
498
499 case CURSOR_SELECT:
500 if(current_column == 1)
501 {
502 repeat = 0;
503 chdir(dir_list[current_dir_selection]);
504 }
505 else
506 {
507 if(num_files != 0)
508 {
509 repeat = 0;
510 return_value = 0;
511 strcpy(result, file_list[current_file_selection]);
512 }
513 }
514 break;
515
516 case CURSOR_BACK:
517#ifdef PSP_BUILD
518 if(!strcmp(current_dir_name, "ms0:/PSP"))
519 break;
520#endif
521 repeat = 0;
522 chdir("..");
523 break;
524
525 case CURSOR_EXIT:
526 return_value = -1;
527 repeat = 0;
528 break;
529 }
530 }
531 }
532
533 for(i = 0; i < num_files; i++)
534 {
535 free(file_list[i]);
536 }
537 free(file_list);
538
539 for(i = 0; i < num_dirs; i++)
540 {
541 free(dir_list[i]);
542 }
543 free(dir_list);
544 }
545
546 clear_screen(COLOR_BG);
547
548 return return_value;
549}
550
551typedef enum
552{
553 NUMBER_SELECTION_OPTION = 0x01,
554 STRING_SELECTION_OPTION = 0x02,
555 SUBMENU_OPTION = 0x04,
556 ACTION_OPTION = 0x08
557} menu_option_type_enum;
558
559struct _menu_type
560{
561 void (* init_function)();
562 void (* passive_function)();
563 struct _menu_option_type *options;
564 u32 num_options;
565};
566
567struct _menu_option_type
568{
569 void (* action_function)();
570 void (* passive_function)();
571 struct _menu_type *sub_menu;
eb3668fc 572 const char *display_string;
2823a4c8 573 void *options;
574 u32 *current_option;
575 u32 num_options;
eb3668fc 576 const char *help_string;
2823a4c8 577 u32 line_number;
578 menu_option_type_enum option_type;
579};
580
581typedef struct _menu_option_type menu_option_type;
582typedef struct _menu_type menu_type;
583
584#define make_menu(name, init_function, passive_function) \
585 menu_type name##_menu = \
586 { \
587 init_function, \
588 passive_function, \
589 name##_options, \
590 sizeof(name##_options) / sizeof(menu_option_type) \
591 } \
592
593#define gamepad_config_option(display_string, number) \
594{ \
595 NULL, \
596 menu_fix_gamepad_help, \
597 NULL, \
598 display_string ": %s", \
599 gamepad_config_buttons, \
600 gamepad_config_map + gamepad_config_line_to_button[number], \
601 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
602 gamepad_help[gamepad_config_map[ \
603 gamepad_config_line_to_button[number]]], \
604 number, \
605 STRING_SELECTION_OPTION \
606} \
607
608#define analog_config_option(display_string, number) \
609{ \
610 NULL, \
611 menu_fix_gamepad_help, \
612 NULL, \
613 display_string ": %s", \
614 gamepad_config_buttons, \
615 gamepad_config_map + number + 12, \
616 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
617 gamepad_help[gamepad_config_map[number + 12]], \
618 number + 2, \
619 STRING_SELECTION_OPTION \
620} \
621
622#define cheat_option(number) \
623{ \
624 NULL, \
625 NULL, \
626 NULL, \
627 cheat_format_str[number], \
628 enable_disable_options, \
629 &(cheats[number].cheat_active), \
630 2, \
631 "Activate/deactivate this cheat code.", \
632 number, \
633 STRING_SELECTION_OPTION \
634} \
635
636#define action_option(action_function, passive_function, display_string, \
637 help_string, line_number) \
638{ \
639 action_function, \
640 passive_function, \
641 NULL, \
642 display_string, \
643 NULL, \
644 NULL, \
645 0, \
646 help_string, \
647 line_number, \
648 ACTION_OPTION \
649} \
650
651#define submenu_option(sub_menu, display_string, help_string, line_number) \
652{ \
653 NULL, \
654 NULL, \
655 sub_menu, \
656 display_string, \
657 NULL, \
658 NULL, \
659 sizeof(sub_menu) / sizeof(menu_option_type), \
660 help_string, \
661 line_number, \
662 SUBMENU_OPTION \
663} \
664
665#define selection_option(passive_function, display_string, options, \
666 option_ptr, num_options, help_string, line_number, type) \
667{ \
668 NULL, \
669 passive_function, \
670 NULL, \
671 display_string, \
672 options, \
673 option_ptr, \
674 num_options, \
675 help_string, \
676 line_number, \
677 type \
678} \
679
680#define action_selection_option(action_function, passive_function, \
681 display_string, options, option_ptr, num_options, help_string, line_number, \
682 type) \
683{ \
684 action_function, \
685 passive_function, \
686 NULL, \
687 display_string, \
688 options, \
689 option_ptr, \
690 num_options, \
691 help_string, \
692 line_number, \
693 type | ACTION_OPTION \
694} \
695
696
697#define string_selection_option(passive_function, display_string, options, \
698 option_ptr, num_options, help_string, line_number) \
699 selection_option(passive_function, display_string ": %s", options, \
700 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
701
702#define numeric_selection_option(passive_function, display_string, \
703 option_ptr, num_options, help_string, line_number) \
704 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
705 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
706
707#define string_selection_action_option(action_function, passive_function, \
708 display_string, options, option_ptr, num_options, help_string, line_number) \
709 action_selection_option(action_function, passive_function, \
710 display_string ": %s", options, option_ptr, num_options, help_string, \
711 line_number, STRING_SELECTION_OPTION) \
712
713#define numeric_selection_action_option(action_function, passive_function, \
714 display_string, option_ptr, num_options, help_string, line_number) \
715 action_selection_option(action_function, passive_function, \
716 display_string ": %d", NULL, option_ptr, num_options, help_string, \
717 line_number, NUMBER_SELECTION_OPTION) \
718
719#define numeric_selection_action_hide_option(action_function, \
720 passive_function, display_string, option_ptr, num_options, help_string, \
721 line_number) \
722 action_selection_option(action_function, passive_function, \
723 display_string, NULL, option_ptr, num_options, help_string, \
724 line_number, NUMBER_SELECTION_OPTION) \
725
726
727#define GAMEPAD_MENU_WIDTH 15
728
729#ifdef PSP_BUILD
730
731u32 gamepad_config_line_to_button[] =
732 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
733
734#endif
735
736#ifdef GP2X_BUILD
737
738u32 gamepad_config_line_to_button[] =
90206450 739 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
2823a4c8 740
741#endif
742
eb3668fc 743#ifdef PND_BUILD
744
745u32 gamepad_config_line_to_button[] =
746 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 12, 13, 14, 15 };
747
748#endif
749
1d02ca75 750u8 *scale_options[] =
751{
eb3668fc 752#ifdef PSP_BUILD
753 "unscaled 3:2", "scaled 3:2", "fullscreen 16:9"
754#elif defined(WIZ_BUILD)
1d02ca75 755 "unscaled 3:2", "scaled 3:2 (slower)",
756 "unscaled 3:2 (anti-tear)", "scaled 3:2 (anti-tear)"
eb3668fc 757#elif defined(PND_BUILD)
758 "unscaled", "2x", "3x", "fullscreen"
759#elif defined(GP2X_BUILD)
4cadce97 760 "unscaled 3:2", "scaled 3:2", "fullscreen", "scaled 3:2 (software)"
eb3668fc 761#else
762 "unscaled 3:2"
1d02ca75 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
eac69717 845 #if defined(_WIN32) || defined(_WIN32_WCE)
2823a4c8 846 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
eac69717 847 #else
848 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
2823a4c8 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);
eb3668fc 1037 print_string_ext("No savestate in 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
eb3668fc 1097 static const u8 * const gamepad_help[] =
2823a4c8 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
eb3668fc 1328 "Determines how the GBA screen is resized in relation to the\n"
1329 "entire screen."
1330#ifdef PSP_BUILD
1331 " Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
2823a4c8 1332 "aspect ratio scaled to fill the height of the PSP screen, and\n"
90206450 1333 "fullscreen to fill the entire PSP screen."
eb3668fc 1334#endif
90206450 1335#endif
1336 "", 2),
1337#ifndef GP2X_BUILD
2823a4c8 1338 string_selection_option(NULL, "Screen filtering", yes_no_options,
1339 (u32 *)(&screen_filter), 2,
eb3668fc 1340 "Determines whether or not filtering should be used when\n"
2823a4c8 1341 "scaling the screen. Selecting this will produce a more even and\n"
1342 "smooth image, at the cost of being blurry and having less vibrant\n"
1343 "colors.", 3),
90206450 1344#endif
2823a4c8 1345 string_selection_option(NULL, "Frameskip type", frameskip_options,
1346 (u32 *)(&current_frameskip_type), 3,
90206450 1347#ifndef GP2X_BUILD
4cdfc0bc 1348 "Determines what kind of frameskipping to use.\n"
2823a4c8 1349 "Frameskipping may improve emulation speed of many games.\n"
4cdfc0bc 1350#endif
2823a4c8 1351 "Off: Do not skip any frames.\n"
4cdfc0bc 1352 "Auto: Skip up to N frames (see next opt) as needed.\n"
90206450 1353 "Manual: Always render only 1 out of N + 1 frames."
4cdfc0bc 1354 , 5),
2823a4c8 1355 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
90206450 1356#ifndef GP2X_BUILD
2823a4c8 1357 "For auto frameskip, determines the maximum number of frames that\n"
1358 "are allowed to be skipped consecutively.\n"
1359 "For manual frameskip, determines the number of frames that will\n"
90206450 1360 "always be skipped."
1361#endif
1362 "", 6),
2823a4c8 1363 string_selection_option(NULL, "Framskip variation",
1364 frameskip_variation_options, &random_skip, 2,
90206450 1365#ifndef GP2X_BUILD
2823a4c8 1366 "If objects in the game flicker at a regular rate certain manual\n"
1367 "frameskip values may cause them to normally disappear. Change this\n"
eb3668fc 1368 "value to 'random' to avoid this. Do not use otherwise, as it tends\n"
1369 "to make the image quality worse, especially in high motion games."
90206450 1370#endif
1371 "", 7),
2823a4c8 1372 string_selection_option(NULL, "Audio output", yes_no_options,
1373 &global_enable_audio, 2,
90206450 1374 "Select 'no' to turn off all audio output. This will\n"
1375 "not result in a significant change in performance.", 9),
2823a4c8 1376#ifndef PSP_BUILD
1377 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1378 &audio_buffer_size_number, 11,
1379#else
1380 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1381 &audio_buffer_size_number, 10,
1382#endif
1383
4742480d 1384#ifdef PSP_BUILD
2823a4c8 1385 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1386 "in slightly better performance at the cost of latency; the lowest\n"
1387 "value will give the most responsive audio.\n"
1388 "This option requires gpSP to be restarted before it will take effect.",
4742480d 1389#else
1390 "Set the size (in bytes) of the audio buffer.\n"
1391 "This option requires gpSP restart to take effect.",
1392#endif
2823a4c8 1393 10),
1394 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1395 };
1396
1397 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1398
1399 menu_option_type cheats_misc_options[] =
1400 {
1401 cheat_option(0),
1402 cheat_option(1),
1403 cheat_option(2),
1404 cheat_option(3),
1405 cheat_option(4),
1406 cheat_option(5),
1407 cheat_option(6),
1408 cheat_option(7),
1409 cheat_option(8),
1410 cheat_option(9),
eb3668fc 1411#if defined(PSP_BUILD) || defined(GP2X_BUILD)
2823a4c8 1412 string_selection_option(NULL, "Clock speed",
90206450 1413 clock_speed_options, &clock_speed_number,
638cc626 1414 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
90206450 1415 "Change the clock speed of the device. Higher clock\n"
1416 "speed will yield better performance, but will drain\n"
1417 "battery life further.", 11),
eb3668fc 1418#endif
2823a4c8 1419 string_selection_option(NULL, "Update backup",
1420 update_backup_options, &update_backup_flag, 2,
90206450 1421#ifdef GP2X_BUILD
1422 "Determines when in-game save files should be\n"
eb3668fc 1423 "written back to SD card."
90206450 1424#else
2823a4c8 1425 "Determines when in-game save files should be written back to\n"
eb3668fc 1426 "card. If set to 'automatic' writebacks will occur shortly after\n"
1427 "the game's backup is altered. On 'exit only' it will only be\n"
1428 "written back when you exit from this menu.\n"
1429#ifdef PSP
1430 "(NOT from using the home button), use the latter with extreme care."
1431#endif
90206450 1432#endif
eb3668fc 1433 "", 12),
2823a4c8 1434 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1435 };
1436
1437 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1438
1439 menu_option_type savestate_options[] =
1440 {
1441 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1442 "Load savestate from current slot", &savestate_slot, 10,
90206450 1443 "Select to load the game state from the current slot\n"
1444 "for this game.\n"
2823a4c8 1445 "Press left + right to change the current slot.", 6),
1446 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1447 "Save savestate to current slot", &savestate_slot, 10,
90206450 1448 "Select to save the game state to the current slot\n"
1449 "for this game.\n"
2823a4c8 1450 "Press left + right to change the current slot.", 7),
1451 numeric_selection_action_hide_option(menu_load_state_file,
1452 menu_change_state,
1453 "Load savestate from file", &savestate_slot, 10,
1454 "Restore gameplay from a savestate file.\n"
90206450 1455 "Note: The same file used to save the state must be\n"
1456 "present.\n", 9),
2823a4c8 1457 numeric_selection_option(menu_change_state,
1458 "Current savestate slot", &savestate_slot, 10,
1459 "Change the current savestate slot.\n", 11),
1460 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1461 };
1462
1463 make_menu(savestate, submenu_savestate, NULL);
1464
1465#ifdef PSP_BUILD
1466
1467 menu_option_type gamepad_config_options[] =
1468 {
1469 gamepad_config_option("D-pad up ", 0),
1470 gamepad_config_option("D-pad down ", 1),
1471 gamepad_config_option("D-pad left ", 2),
1472 gamepad_config_option("D-pad right ", 3),
1473 gamepad_config_option("Circle ", 4),
1474 gamepad_config_option("Cross ", 5),
1475 gamepad_config_option("Square ", 6),
1476 gamepad_config_option("Triangle ", 7),
1477 gamepad_config_option("Left Trigger ", 8),
1478 gamepad_config_option("Right Trigger", 9),
1479 gamepad_config_option("Start ", 10),
1480 gamepad_config_option("Select ", 11),
1481 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1482 };
1483
1484
1485 menu_option_type analog_config_options[] =
1486 {
1487 analog_config_option("Analog up ", 0),
1488 analog_config_option("Analog down ", 1),
1489 analog_config_option("Analog left ", 2),
1490 analog_config_option("Analog right", 3),
1491 string_selection_option(NULL, "Enable analog", yes_no_options,
1492 &global_enable_analog, 2,
1493 "Select 'no' to block analog input entirely.", 7),
1494 numeric_selection_option(NULL, "Analog sensitivity",
1495 &analog_sensitivity_level, 10,
1496 "Determine sensitivity/responsiveness of the analog input.\n"
1497 "Lower numbers are less sensitive.", 8),
1498 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1499 };
1500
1501#endif
1502
eb3668fc 1503#if defined(GP2X_BUILD) || defined(PND_BUILD)
2823a4c8 1504
1505 menu_option_type gamepad_config_options[] =
1506 {
1507 gamepad_config_option("D-pad up ", 0),
1508 gamepad_config_option("D-pad down ", 1),
1509 gamepad_config_option("D-pad left ", 2),
1510 gamepad_config_option("D-pad right ", 3),
1511 gamepad_config_option("A ", 4),
1512 gamepad_config_option("B ", 5),
1513 gamepad_config_option("X ", 6),
1514 gamepad_config_option("Y ", 7),
1515 gamepad_config_option("Left Trigger ", 8),
1516 gamepad_config_option("Right Trigger", 9),
4cdfc0bc 1517#ifdef WIZ_BUILD
1518 gamepad_config_option("Menu ", 10),
1519#else
2823a4c8 1520 gamepad_config_option("Start ", 10),
4cdfc0bc 1521#endif
2823a4c8 1522 gamepad_config_option("Select ", 11),
eb3668fc 1523#if !defined(WIZ_BUILD) && !defined(PND_BUILD)
90206450 1524 gamepad_config_option("Stick Push ", 12),
4cdfc0bc 1525#endif
eb3668fc 1526#ifdef PND_BUILD
1527 gamepad_config_option("1 ", 12),
1528 gamepad_config_option("2 ", 13),
1529 gamepad_config_option("3 ", 14),
1530 gamepad_config_option("4 ", 15),
1531 submenu_option(NULL, "Back", "Return to the main menu.", 16)
1532#else
90206450 1533 submenu_option(NULL, "Back", "Return to the main menu.", 14)
eb3668fc 1534#endif
2823a4c8 1535 };
1536
1537
1538 menu_option_type analog_config_options[] =
1539 {
1540 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1541 };
1542
1543#endif
1544
1545#ifdef PC_BUILD
1546
1547 menu_option_type gamepad_config_options[] =
1548 {
1549 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1550 };
1551
1552 menu_option_type analog_config_options[] =
1553 {
1554 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1555 };
1556
1557#endif
1558
1559 make_menu(gamepad_config, submenu_gamepad, NULL);
1560 make_menu(analog_config, submenu_analog, NULL);
1561
1562 menu_option_type main_options[] =
1563 {
1564 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
90206450 1565 "Select to set display parameters and frameskip\n"
1566 "behavior, audio on/off, buffer size, and filtering.", 0),
2823a4c8 1567 numeric_selection_action_option(menu_load_state, NULL,
1568 "Load state from slot", &savestate_slot, 10,
90206450 1569 "Select to load the game state from the current slot\n"
1570 "for this game, if it exists.\n"
2823a4c8 1571 "Press left + right to change the current slot.", 2),
1572 numeric_selection_action_option(menu_save_state, NULL,
1573 "Save state to slot", &savestate_slot, 10,
90206450 1574 "Select to save the game state to the current slot\n"
1575 "for this game. See the extended menu for more info.\n"
2823a4c8 1576 "Press left + right to change the current slot.", 3),
1577 submenu_option(&savestate_menu, "Savestate options",
90206450 1578 "Select to enter a menu for loading, saving, and\n"
1579 "viewing the currently active savestate for this game\n"
1580 "(or to load a savestate file from another game)", 4),
2823a4c8 1581 submenu_option(&gamepad_config_menu, "Configure gamepad input",
90206450 1582 "Select to change the in-game behavior of buttons\n"
1583 "and d-pad.", 6),
1584#ifndef GP2X_BUILD
2823a4c8 1585 submenu_option(&analog_config_menu, "Configure analog input",
1586 "Select to change the in-game behavior of the PSP analog nub.", 7),
90206450 1587#endif
2823a4c8 1588 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
90206450 1589 "Select to manage cheats, set backup behavior,\n"
1590 "and set device clock speed.", 9),
2823a4c8 1591 action_option(menu_load, NULL, "Load new game",
90206450 1592 "Select to load a new game\n"
1593 "(will exit a game if currently playing).", 11),
2823a4c8 1594 action_option(menu_restart, NULL, "Restart game",
90206450 1595 "Select to reset the GBA with the current game\n"
1596 "loaded.", 12),
2823a4c8 1597 action_option(menu_exit, NULL, "Return to game",
1598 "Select to exit this menu and resume gameplay.", 13),
1599 action_option(menu_quit, NULL, "Exit gpSP",
90206450 1600 "Select to exit gpSP and return to the menu.", 15)
2823a4c8 1601 };
1602
1603 make_menu(main, submenu_main, NULL);
1604
1605 void choose_menu(menu_type *new_menu)
1606 {
1607 if(new_menu == NULL)
1608 new_menu = &main_menu;
1609
1610 clear_screen(COLOR_BG);
1611
1612#ifndef GP2X_BUILD
1613 blit_to_screen(original_screen, 240, 160, 230, 40);
1614#endif
1615
1616 current_menu = new_menu;
1617 current_option = new_menu->options;
1618 current_option_num = 0;
1619 if(current_menu->init_function)
1620 current_menu->init_function();
1621 }
1622
1623 void clear_help()
1624 {
1625 for(i = 0; i < 6; i++)
1626 {
90206450 1627 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
2823a4c8 1628 }
1629 }
1630
1d02ca75 1631 menu_update_clock();
2823a4c8 1632 video_resolution_large();
1633
1634#ifndef GP2X_BUILD
1635 SDL_LockMutex(sound_mutex);
1636#endif
1637 SDL_PauseAudio(1);
1638
1639#ifndef GP2X_BUILD
1640 SDL_UnlockMutex(sound_mutex);
1641#endif
1642
1643 if(gamepak_filename[0] == 0)
1644 {
1645 first_load = 1;
1646 memset(original_screen, 0x00, 240 * 160 * 2);
1647 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
42c81190 1648 60, 75,original_screen, 240, 0, 0, FONT_HEIGHT);
2823a4c8 1649 }
1650
1651 choose_menu(&main_menu);
1652
1653 for(i = 0; i < 10; i++)
1654 {
1655 if(i >= num_cheats)
1656 {
1657 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1658 }
1659 else
1660 {
1661 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1662 cheats[i].cheat_name);
1663 }
1664 }
1665
1666 current_menu->init_function();
1667
1668 while(repeat)
1669 {
1670 display_option = current_menu->options;
1671
1672 for(i = 0; i < current_menu->num_options; i++, display_option++)
1673 {
1674 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1675 {
1676 sprintf(line_buffer, display_option->display_string,
1677 *(display_option->current_option));
1678 }
1679 else
1680
1681 if(display_option->option_type & STRING_SELECTION_OPTION)
1682 {
1683 sprintf(line_buffer, display_option->display_string,
1684 ((u32 *)display_option->options)[*(display_option->current_option)]);
1685 }
1686 else
1687 {
1688 strcpy(line_buffer, display_option->display_string);
1689 }
1690
1691 if(display_option == current_option)
1692 {
eb3668fc 1693 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 6,
1694 (display_option->line_number * 10) + 40, 36);
2823a4c8 1695 }
1696 else
1697 {
eb3668fc 1698 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 6,
1699 (display_option->line_number * 10) + 40, 36);
2823a4c8 1700 }
1701 }
1702
1703 print_string(current_option->help_string, COLOR_HELP_TEXT,
90206450 1704 COLOR_BG, 8, 210);
2823a4c8 1705
1706 flip_screen();
1707
1708 gui_action = get_gui_input();
1709
1710 switch(gui_action)
1711 {
1712 case CURSOR_DOWN:
1713 current_option_num = (current_option_num + 1) %
1714 current_menu->num_options;
1715
1716 current_option = current_menu->options + current_option_num;
1717 clear_help();
1718 break;
1719
1720 case CURSOR_UP:
1721 if(current_option_num)
1722 current_option_num--;
1723 else
1724 current_option_num = current_menu->num_options - 1;
1725
1726 current_option = current_menu->options + current_option_num;
1727 clear_help();
1728 break;
1729
1730 case CURSOR_RIGHT:
1731 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1732 STRING_SELECTION_OPTION))
1733 {
1734 *(current_option->current_option) =
1735 (*current_option->current_option + 1) %
1736 current_option->num_options;
1737
1738 if(current_option->passive_function)
1739 current_option->passive_function();
1740 }
1741 break;
1742
1743 case CURSOR_LEFT:
1744 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1745 STRING_SELECTION_OPTION))
1746 {
1747 u32 current_option_val = *(current_option->current_option);
1748
1749 if(current_option_val)
1750 current_option_val--;
1751 else
1752 current_option_val = current_option->num_options - 1;
1753
1754 *(current_option->current_option) = current_option_val;
1755
1756 if(current_option->passive_function)
1757 current_option->passive_function();
1758 }
1759 break;
1760
1761 case CURSOR_EXIT:
1762 if(current_menu == &main_menu)
1763 menu_exit();
1764
1765 choose_menu(&main_menu);
1766 break;
1767
1768 case CURSOR_SELECT:
1769 if(current_option->option_type & ACTION_OPTION)
1770 current_option->action_function();
1771
1772 if(current_option->option_type & SUBMENU_OPTION)
1773 choose_menu(current_option->sub_menu);
1774 break;
1775 }
1776 }
1777
1778 set_gba_resolution(screen_scale);
1779 video_resolution_small();
1d02ca75 1780 menu_get_clock_speed();
1781 set_clock_speed();
2823a4c8 1782
1783 SDL_PauseAudio(0);
2455b6a3 1784 num_skipped_frames = 100;
2823a4c8 1785
1786 return return_value;
1787}