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