portrait mode asm
[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;
8ff85457 743#ifdef WIZ_BUILD
744 frameskip_value = 1;
745#endif
2823a4c8 746 random_skip = 0;
638cc626 747 clock_speed = default_clock_speed;
2823a4c8 748
749 for(i = 0; i < 10; i++)
750 {
751 cheats[i].cheat_active = 0;
752 cheats[i].cheat_name[0] = 0;
753 }
754
755 return -1;
756}
757
758s32 load_config_file()
759{
760 u8 config_path[512];
761
762 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
763 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
764 #else
765 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
766 #endif
767
768 file_open(config_file, config_path, read);
769
770 if(file_check_valid(config_file))
771 {
772 u32 file_size = file_length(config_path, config_file);
773
774 // Sanity check: File size must be the right size
775 if(file_size == 92)
776 {
777 u32 file_options[file_size / 4];
778 u32 i;
779 s32 menu_button = -1;
780 file_read_array(config_file, file_options);
781
782 screen_scale = file_options[0] % 3;
783 screen_filter = file_options[1] % 2;
784 global_enable_audio = file_options[2] % 2;
785
786#ifdef PSP_BUILD
787 audio_buffer_size_number = file_options[3] % 10;
788#else
789 audio_buffer_size_number = file_options[3] % 11;
790#endif
791
792 update_backup_flag = file_options[4] % 2;
793 global_enable_analog = file_options[5] % 2;
794 analog_sensitivity_level = file_options[6] % 8;
795
796#ifdef PSP_BUILD
797 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
798#endif
799
800 // Sanity check: Make sure there's a MENU or FRAMESKIP
801 // key, if not assign to triangle
802
803#ifndef PC_BUILD
804 for(i = 0; i < 16; i++)
805 {
806 gamepad_config_map[i] = file_options[7 + i] %
807 (BUTTON_ID_NONE + 1);
808
809 if(gamepad_config_map[i] == BUTTON_ID_MENU)
810 {
811 menu_button = i;
812 }
813 }
814
815 if(menu_button == -1)
816 {
817 gamepad_config_map[0] = BUTTON_ID_MENU;
818 }
819#endif
820
821 file_close(config_file);
822 }
823
824 return 0;
825 }
826
827 return -1;
828}
829
830s32 save_game_config_file()
831{
832 u8 game_config_filename[512];
833 u32 i;
834
835 change_ext(gamepak_filename, game_config_filename, ".cfg");
836
837 file_open(game_config_file, game_config_filename, write);
838
839 if(file_check_valid(game_config_file))
840 {
841 u32 file_options[14];
842
843 file_options[0] = current_frameskip_type;
844 file_options[1] = frameskip_value;
845 file_options[2] = random_skip;
846 file_options[3] = clock_speed;
847
848 for(i = 0; i < 10; i++)
849 {
850 file_options[4 + i] = cheats[i].cheat_active;
851 }
852
853 file_write_array(game_config_file, file_options);
854
855 file_close(game_config_file);
856
857 return 0;
858 }
859
860 return -1;
861}
862
863s32 save_config_file()
864{
865 u8 config_path[512];
866
867 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
868 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
869 #else
870 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
871 #endif
872
873 file_open(config_file, config_path, write);
874
875 save_game_config_file();
876
877 if(file_check_valid(config_file))
878 {
879 u32 file_options[23];
880 u32 i;
881
882 file_options[0] = screen_scale;
883 file_options[1] = screen_filter;
884 file_options[2] = global_enable_audio;
885 file_options[3] = audio_buffer_size_number;
886 file_options[4] = update_backup_flag;
887 file_options[5] = global_enable_analog;
888 file_options[6] = analog_sensitivity_level;
889
890#ifndef PC_BUILD
891 for(i = 0; i < 16; i++)
892 {
893 file_options[7 + i] = gamepad_config_map[i];
894 }
895#endif
896
897 file_write_array(config_file, file_options);
898
899 file_close(config_file);
900
901 return 0;
902 }
903
904 return -1;
905}
906
907typedef enum
908{
909 MAIN_MENU,
910 GAMEPAD_MENU,
911 SAVESTATE_MENU,
912 FRAMESKIP_MENU,
913 CHEAT_MENU
914} menu_enum;
915
916u32 savestate_slot = 0;
917
918void get_savestate_snapshot(u8 *savestate_filename)
919{
920 u16 snapshot_buffer[240 * 160];
921 u8 savestate_timestamp_string[80];
922
923 file_open(savestate_file, savestate_filename, read);
924
925 if(file_check_valid(savestate_file))
926 {
927 u8 weekday_strings[7][11] =
928 {
929 "Sunday", "Monday", "Tuesday", "Wednesday",
930 "Thursday", "Friday", "Saturday"
931 };
932 time_t savestate_time_flat;
933 struct tm *current_time;
934 file_read_array(savestate_file, snapshot_buffer);
935 file_read_variable(savestate_file, savestate_time_flat);
936
937 file_close(savestate_file);
938
939 current_time = localtime(&savestate_time_flat);
940 sprintf(savestate_timestamp_string,
941 "%s %02d/%02d/%04d %02d:%02d:%02d ",
942 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
943 current_time->tm_mday, current_time->tm_year + 1900,
944 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
945
946 savestate_timestamp_string[40] = 0;
947 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
948 10, 40);
949 }
950 else
951 {
952 memset(snapshot_buffer, 0, 240 * 160 * 2);
953 print_string_ext("No savestate exists for this slot.",
954 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0);
955 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
956 COLOR_BG, 10, 40);
957 }
958
959#ifndef GP2X_BUILD
960 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
961#endif
962}
963
964void get_savestate_filename(u32 slot, u8 *name_buffer)
965{
966 u8 savestate_ext[16];
967
968 sprintf(savestate_ext, "%d.svs", slot);
969 change_ext(gamepak_filename, name_buffer, savestate_ext);
970
971 get_savestate_snapshot(name_buffer);
972}
973
974void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
975{
976 u8 savestate_ext[16];
977
978 sprintf(savestate_ext, "%d.svs", slot);
979 change_ext(gamepak_filename, name_buffer, savestate_ext);
980}
981
982#ifdef PSP_BUILD
983 void _flush_cache()
984 {
985 invalidate_all_cache();
986 }
987#endif
988
989u32 menu(u16 *original_screen)
990{
90206450 991 u32 clock_speed_number;
638cc626 992 static u32 clock_speed_old = default_clock_speed;
2823a4c8 993 u8 print_buffer[81];
994 u32 _current_option = 0;
995 gui_action_type gui_action;
996 menu_enum _current_menu = MAIN_MENU;
997 u32 i;
998 u32 repeat = 1;
999 u32 return_value = 0;
1000 u32 first_load = 0;
1001 u8 savestate_ext[16];
1002 u8 current_savestate_filename[512];
1003 u8 line_buffer[80];
1004 u8 cheat_format_str[10][41];
1005
1006 menu_type *current_menu;
1007 menu_option_type *current_option;
1008 menu_option_type *display_option;
1009 u32 current_option_num;
1010
1011 auto void choose_menu();
1012 auto void clear_help();
1013
1014 u8 *gamepad_help[] =
1015 {
1016 "Up button on GBA d-pad.",
1017 "Down button on GBA d-pad.",
1018 "Left button on GBA d-pad.",
1019 "Right button on GBA d-pad.",
1020 "A button on GBA.",
1021 "B button on GBA.",
1022 "Left shoulder button on GBA.",
1023 "Right shoulder button on GBA.",
1024 "Start button on GBA.",
1025 "Select button on GBA.",
1026 "Brings up the options menu.",
1027 "Toggles fastforward on/off.",
1028 "Loads the game state from the current slot.",
1029 "Saves the game state to the current slot.",
1030 "Rapidly press/release the A button on GBA.",
1031 "Rapidly press/release the B button on GBA.",
1032 "Rapidly press/release the L shoulder on GBA.",
1033 "Rapidly press/release the R shoulder on GBA.",
1034 "Increases the volume.",
1035 "Decreases the volume.",
1036 "Displays virtual/drawn frames per second.",
1037 "Does nothing."
1038 };
1039
1040 void menu_exit()
1041 {
1042 if(!first_load)
1043 repeat = 0;
1044 }
1045
1046 void menu_quit()
1047 {
638cc626 1048 get_clock_speed();
2823a4c8 1049 save_config_file();
1050 quit();
1051 }
1052
1053 void menu_load()
1054 {
1055 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1056 u8 load_filename[512];
1057 save_game_config_file();
1058 if(load_file(file_ext, load_filename) != -1)
1059 {
1060 if(load_gamepak(load_filename) == -1)
1061 {
1062 quit();
1063 }
1064 reset_gba();
1065 return_value = 1;
1066 repeat = 0;
1067 reg[CHANGED_PC_STATUS] = 1;
1068 }
1069 else
1070 {
1071 choose_menu(current_menu);
1072 }
1073 }
1074
1075 void menu_restart()
1076 {
1077 if(!first_load)
1078 {
1079 reset_gba();
1080 reg[CHANGED_PC_STATUS] = 1;
1081 return_value = 1;
1082 repeat = 0;
1083 }
1084 }
1085
1086 void menu_change_state()
1087 {
1088 get_savestate_filename(savestate_slot, current_savestate_filename);
1089 }
1090
1091 void menu_save_state()
1092 {
1093 if(!first_load)
1094 {
1095 get_savestate_filename_noshot(savestate_slot,
1096 current_savestate_filename);
1097 save_state(current_savestate_filename, original_screen);
1098 }
1099 menu_change_state();
1100 }
1101
1102 void menu_load_state()
1103 {
1104 if(!first_load)
1105 {
1106 load_state(current_savestate_filename);
1107 return_value = 1;
1108 repeat = 0;
1109 }
1110 }
1111
1112 void menu_load_state_file()
1113 {
1114 u8 *file_ext[] = { ".svs", NULL };
1115 u8 load_filename[512];
1116 if(load_file(file_ext, load_filename) != -1)
1117 {
1118 load_state(load_filename);
1119 return_value = 1;
1120 repeat = 0;
1121 }
1122 else
1123 {
1124 choose_menu(current_menu);
1125 }
1126 }
1127
1128 void menu_fix_gamepad_help()
1129 {
1130#ifndef PC_BUILD
1131 clear_help();
1132 current_option->help_string =
1133 gamepad_help[gamepad_config_map[
1134 gamepad_config_line_to_button[current_option_num]]];
1135#endif
1136 }
1137
1138 void submenu_graphics_sound()
1139 {
1140
1141 }
1142
1143 void submenu_cheats_misc()
1144 {
1145
1146 }
1147
1148 void submenu_gamepad()
1149 {
1150
1151 }
1152
1153 void submenu_analog()
1154 {
1155
1156 }
1157
1158 void submenu_savestate()
1159 {
1160 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1161 menu_change_state();
1162 }
1163
1164 void submenu_main()
1165 {
1166 strncpy(print_buffer, gamepak_filename, 80);
1167 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1168 sprintf(print_buffer, "%s %s %s", gamepak_title,
1169 gamepak_code, gamepak_maker);
1170 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1171
1172 get_savestate_filename_noshot(savestate_slot,
1173 current_savestate_filename);
1174 }
1175
1176 u8 *yes_no_options[] = { "no", "yes" };
1177 u8 *enable_disable_options[] = { "disabled", "enabled" };
1178
1179 u8 *scale_options[] =
1180 {
638cc626 1181#ifdef WIZ_BUILD
1182 "unscaled 3:2", "scaled 3:2 (slower)"
1183#else
90206450 1184 "unscaled 3:2", "scaled 3:2", "fullscreen"
1185#ifdef PSP_BUILD
1186 " 16:9"
638cc626 1187#endif
90206450 1188#endif
2823a4c8 1189 };
1190
1191 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1192 u8 *frameskip_variation_options[] = { "uniform", "random" };
1193
1194#ifndef PSP_BUILD
1195 u8 *audio_buffer_options[] =
1196 {
1197 "16 bytes", "32 bytes", "64 bytes",
1198 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1199 "4096 bytes", "8192 bytes", "16284 bytes"
1200 };
1201#else
1202 u8 *audio_buffer_options[] =
1203 {
1204 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1205 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1206 };
1207
1208#endif
1209
1210 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1211
638cc626 1212#ifdef WIZ_BUILD
1213 u8 *clock_speed_options[] =
1214 {
1215 "300MHz", "333MHz", "366MHz", "400MHz", "433MHz",
1216 "466MHz", "500MHz", "533MHz", "566MHz", "600MHz",
1217 "633MHz", "666MHz", "700MHz", "733MHz", "766MHz",
1218 "800MHz", "833MHz", "866MHz", "900MHz"
1219 };
1220#elif defined(GP2X_BUILD)
90206450 1221 u8 *clock_speed_options[] =
1222 {
1223 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
1224 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
1225 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
1226 };
1227#else
2823a4c8 1228 u8 *clock_speed_options[] =
1229 {
1230 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
1231 "266MHz", "300MHz", "333MHz"
1232 };
90206450 1233#endif
2823a4c8 1234
1235 u8 *gamepad_config_buttons[] =
1236 {
1237 "UP",
1238 "DOWN",
1239 "LEFT",
1240 "RIGHT",
1241 "A",
1242 "B",
1243 "L",
1244 "R",
1245 "START",
1246 "SELECT",
1247 "MENU",
1248 "FASTFORWARD",
1249 "LOAD STATE",
1250 "SAVE STATE",
1251 "RAPIDFIRE A",
1252 "RAPIDFIRE B",
1253 "RAPIDFIRE L",
1254 "RAPIDFIRE R",
1255 "VOLUME UP",
1256 "VOLUME DOWN",
1257 "DISPLAY FPS",
1258 "NOTHING"
1259 };
1260
1261 // Marker for help information, don't go past this mark (except \n)------*
1262 menu_option_type graphics_sound_options[] =
1263 {
1264 string_selection_option(NULL, "Display scaling", scale_options,
4cdfc0bc 1265 (u32 *)(&screen_scale),
1266#ifdef WIZ_BUILD
1267 2,
1268#else
1269 3,
1270#endif
90206450 1271#ifndef GP2X_BUILD
2823a4c8 1272 "Determines how the GBA screen is resized in relation to the entire\n"
1273 "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1274 "aspect ratio scaled to fill the height of the PSP screen, and\n"
90206450 1275 "fullscreen to fill the entire PSP screen."
1276#endif
1277 "", 2),
1278#ifndef GP2X_BUILD
2823a4c8 1279 string_selection_option(NULL, "Screen filtering", yes_no_options,
1280 (u32 *)(&screen_filter), 2,
1281 "Determines whether or not bilinear filtering should be used when\n"
1282 "scaling the screen. Selecting this will produce a more even and\n"
1283 "smooth image, at the cost of being blurry and having less vibrant\n"
1284 "colors.", 3),
90206450 1285#endif
2823a4c8 1286 string_selection_option(NULL, "Frameskip type", frameskip_options,
1287 (u32 *)(&current_frameskip_type), 3,
90206450 1288#ifndef GP2X_BUILD
4cdfc0bc 1289 "Determines what kind of frameskipping to use.\n"
2823a4c8 1290 "Frameskipping may improve emulation speed of many games.\n"
4cdfc0bc 1291#endif
2823a4c8 1292 "Off: Do not skip any frames.\n"
4cdfc0bc 1293 "Auto: Skip up to N frames (see next opt) as needed.\n"
90206450 1294 "Manual: Always render only 1 out of N + 1 frames."
4cdfc0bc 1295 , 5),
2823a4c8 1296 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
90206450 1297#ifndef GP2X_BUILD
2823a4c8 1298 "For auto frameskip, determines the maximum number of frames that\n"
1299 "are allowed to be skipped consecutively.\n"
1300 "For manual frameskip, determines the number of frames that will\n"
90206450 1301 "always be skipped."
1302#endif
1303 "", 6),
2823a4c8 1304 string_selection_option(NULL, "Framskip variation",
1305 frameskip_variation_options, &random_skip, 2,
90206450 1306#ifndef GP2X_BUILD
2823a4c8 1307 "If objects in the game flicker at a regular rate certain manual\n"
1308 "frameskip values may cause them to normally disappear. Change this\n"
1309 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
90206450 1310 "make the image quality worse, especially in high motion games."
1311#endif
1312 "", 7),
2823a4c8 1313 string_selection_option(NULL, "Audio output", yes_no_options,
1314 &global_enable_audio, 2,
90206450 1315 "Select 'no' to turn off all audio output. This will\n"
1316 "not result in a significant change in performance.", 9),
2823a4c8 1317#ifndef PSP_BUILD
1318 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1319 &audio_buffer_size_number, 11,
1320#else
1321 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1322 &audio_buffer_size_number, 10,
1323#endif
1324
4742480d 1325#ifdef PSP_BUILD
2823a4c8 1326 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1327 "in slightly better performance at the cost of latency; the lowest\n"
1328 "value will give the most responsive audio.\n"
1329 "This option requires gpSP to be restarted before it will take effect.",
4742480d 1330#else
1331 "Set the size (in bytes) of the audio buffer.\n"
1332 "This option requires gpSP restart to take effect.",
1333#endif
2823a4c8 1334 10),
1335 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1336 };
1337
1338 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1339
1340 menu_option_type cheats_misc_options[] =
1341 {
1342 cheat_option(0),
1343 cheat_option(1),
1344 cheat_option(2),
1345 cheat_option(3),
1346 cheat_option(4),
1347 cheat_option(5),
1348 cheat_option(6),
1349 cheat_option(7),
1350 cheat_option(8),
1351 cheat_option(9),
1352 string_selection_option(NULL, "Clock speed",
90206450 1353 clock_speed_options, &clock_speed_number,
638cc626 1354 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
90206450 1355 "Change the clock speed of the device. Higher clock\n"
1356 "speed will yield better performance, but will drain\n"
1357 "battery life further.", 11),
2823a4c8 1358 string_selection_option(NULL, "Update backup",
1359 update_backup_options, &update_backup_flag, 2,
90206450 1360#ifdef GP2X_BUILD
1361 "Determines when in-game save files should be\n"
1362 "written back to SD card.",
1363#else
2823a4c8 1364 "Determines when in-game save files should be written back to\n"
1365 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1366 "the game's backup is altered. On 'exit only' it will only be written\n"
1367 "back when you exit from this menu (NOT from using the home button).\n"
90206450 1368 "Use the latter with extreme care.",
1369#endif
1370 12),
2823a4c8 1371 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1372 };
1373
1374 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1375
1376 menu_option_type savestate_options[] =
1377 {
1378 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1379 "Load savestate from current slot", &savestate_slot, 10,
90206450 1380 "Select to load the game state from the current slot\n"
1381 "for this game.\n"
2823a4c8 1382 "Press left + right to change the current slot.", 6),
1383 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1384 "Save savestate to current slot", &savestate_slot, 10,
90206450 1385 "Select to save the game state to the current slot\n"
1386 "for this game.\n"
2823a4c8 1387 "Press left + right to change the current slot.", 7),
1388 numeric_selection_action_hide_option(menu_load_state_file,
1389 menu_change_state,
1390 "Load savestate from file", &savestate_slot, 10,
1391 "Restore gameplay from a savestate file.\n"
90206450 1392 "Note: The same file used to save the state must be\n"
1393 "present.\n", 9),
2823a4c8 1394 numeric_selection_option(menu_change_state,
1395 "Current savestate slot", &savestate_slot, 10,
1396 "Change the current savestate slot.\n", 11),
1397 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1398 };
1399
1400 make_menu(savestate, submenu_savestate, NULL);
1401
1402#ifdef PSP_BUILD
1403
1404 menu_option_type gamepad_config_options[] =
1405 {
1406 gamepad_config_option("D-pad up ", 0),
1407 gamepad_config_option("D-pad down ", 1),
1408 gamepad_config_option("D-pad left ", 2),
1409 gamepad_config_option("D-pad right ", 3),
1410 gamepad_config_option("Circle ", 4),
1411 gamepad_config_option("Cross ", 5),
1412 gamepad_config_option("Square ", 6),
1413 gamepad_config_option("Triangle ", 7),
1414 gamepad_config_option("Left Trigger ", 8),
1415 gamepad_config_option("Right Trigger", 9),
1416 gamepad_config_option("Start ", 10),
1417 gamepad_config_option("Select ", 11),
1418 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1419 };
1420
1421
1422 menu_option_type analog_config_options[] =
1423 {
1424 analog_config_option("Analog up ", 0),
1425 analog_config_option("Analog down ", 1),
1426 analog_config_option("Analog left ", 2),
1427 analog_config_option("Analog right", 3),
1428 string_selection_option(NULL, "Enable analog", yes_no_options,
1429 &global_enable_analog, 2,
1430 "Select 'no' to block analog input entirely.", 7),
1431 numeric_selection_option(NULL, "Analog sensitivity",
1432 &analog_sensitivity_level, 10,
1433 "Determine sensitivity/responsiveness of the analog input.\n"
1434 "Lower numbers are less sensitive.", 8),
1435 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1436 };
1437
1438#endif
1439
1440#ifdef GP2X_BUILD
1441
1442 menu_option_type gamepad_config_options[] =
1443 {
1444 gamepad_config_option("D-pad up ", 0),
1445 gamepad_config_option("D-pad down ", 1),
1446 gamepad_config_option("D-pad left ", 2),
1447 gamepad_config_option("D-pad right ", 3),
1448 gamepad_config_option("A ", 4),
1449 gamepad_config_option("B ", 5),
1450 gamepad_config_option("X ", 6),
1451 gamepad_config_option("Y ", 7),
1452 gamepad_config_option("Left Trigger ", 8),
1453 gamepad_config_option("Right Trigger", 9),
4cdfc0bc 1454#ifdef WIZ_BUILD
1455 gamepad_config_option("Menu ", 10),
1456#else
2823a4c8 1457 gamepad_config_option("Start ", 10),
4cdfc0bc 1458#endif
2823a4c8 1459 gamepad_config_option("Select ", 11),
4cdfc0bc 1460#ifndef WIZ_BUILD
90206450 1461 gamepad_config_option("Stick Push ", 12),
4cdfc0bc 1462#endif
90206450 1463 submenu_option(NULL, "Back", "Return to the main menu.", 14)
2823a4c8 1464 };
1465
1466
1467 menu_option_type analog_config_options[] =
1468 {
1469 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1470 };
1471
1472#endif
1473
1474#ifdef PC_BUILD
1475
1476 menu_option_type gamepad_config_options[] =
1477 {
1478 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1479 };
1480
1481 menu_option_type analog_config_options[] =
1482 {
1483 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1484 };
1485
1486#endif
1487
1488 make_menu(gamepad_config, submenu_gamepad, NULL);
1489 make_menu(analog_config, submenu_analog, NULL);
1490
1491 menu_option_type main_options[] =
1492 {
1493 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
90206450 1494 "Select to set display parameters and frameskip\n"
1495 "behavior, audio on/off, buffer size, and filtering.", 0),
2823a4c8 1496 numeric_selection_action_option(menu_load_state, NULL,
1497 "Load state from slot", &savestate_slot, 10,
90206450 1498 "Select to load the game state from the current slot\n"
1499 "for this game, if it exists.\n"
2823a4c8 1500 "Press left + right to change the current slot.", 2),
1501 numeric_selection_action_option(menu_save_state, NULL,
1502 "Save state to slot", &savestate_slot, 10,
90206450 1503 "Select to save the game state to the current slot\n"
1504 "for this game. See the extended menu for more info.\n"
2823a4c8 1505 "Press left + right to change the current slot.", 3),
1506 submenu_option(&savestate_menu, "Savestate options",
90206450 1507 "Select to enter a menu for loading, saving, and\n"
1508 "viewing the currently active savestate for this game\n"
1509 "(or to load a savestate file from another game)", 4),
2823a4c8 1510 submenu_option(&gamepad_config_menu, "Configure gamepad input",
90206450 1511 "Select to change the in-game behavior of buttons\n"
1512 "and d-pad.", 6),
1513#ifndef GP2X_BUILD
2823a4c8 1514 submenu_option(&analog_config_menu, "Configure analog input",
1515 "Select to change the in-game behavior of the PSP analog nub.", 7),
90206450 1516#endif
2823a4c8 1517 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
90206450 1518 "Select to manage cheats, set backup behavior,\n"
1519 "and set device clock speed.", 9),
2823a4c8 1520 action_option(menu_load, NULL, "Load new game",
90206450 1521 "Select to load a new game\n"
1522 "(will exit a game if currently playing).", 11),
2823a4c8 1523 action_option(menu_restart, NULL, "Restart game",
90206450 1524 "Select to reset the GBA with the current game\n"
1525 "loaded.", 12),
2823a4c8 1526 action_option(menu_exit, NULL, "Return to game",
1527 "Select to exit this menu and resume gameplay.", 13),
1528 action_option(menu_quit, NULL, "Exit gpSP",
90206450 1529 "Select to exit gpSP and return to the menu.", 15)
2823a4c8 1530 };
1531
1532 make_menu(main, submenu_main, NULL);
1533
1534 void choose_menu(menu_type *new_menu)
1535 {
1536 if(new_menu == NULL)
1537 new_menu = &main_menu;
1538
1539 clear_screen(COLOR_BG);
1540
1541#ifndef GP2X_BUILD
1542 blit_to_screen(original_screen, 240, 160, 230, 40);
1543#endif
1544
1545 current_menu = new_menu;
1546 current_option = new_menu->options;
1547 current_option_num = 0;
1548 if(current_menu->init_function)
1549 current_menu->init_function();
1550 }
1551
1552 void clear_help()
1553 {
1554 for(i = 0; i < 6; i++)
1555 {
90206450 1556 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
2823a4c8 1557 }
1558 }
1559
638cc626 1560 get_clock_speed_number();
1561 if (clock_speed_number < 0 || clock_speed_number >=
1562 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]))
1563 {
1564 clock_speed = default_clock_speed;
1565 get_clock_speed_number();
1566 }
90206450 1567
2823a4c8 1568 video_resolution_large();
1569
1570#ifndef GP2X_BUILD
1571 SDL_LockMutex(sound_mutex);
1572#endif
1573 SDL_PauseAudio(1);
1574
1575#ifndef GP2X_BUILD
1576 SDL_UnlockMutex(sound_mutex);
1577#endif
1578
1579 if(gamepak_filename[0] == 0)
1580 {
1581 first_load = 1;
1582 memset(original_screen, 0x00, 240 * 160 * 2);
1583 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1584 60, 75,original_screen, 240, 0);
1585 }
1586
1587 choose_menu(&main_menu);
1588
1589 for(i = 0; i < 10; i++)
1590 {
1591 if(i >= num_cheats)
1592 {
1593 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1594 }
1595 else
1596 {
1597 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1598 cheats[i].cheat_name);
1599 }
1600 }
1601
1602 current_menu->init_function();
1603
1604 while(repeat)
1605 {
1606 display_option = current_menu->options;
1607
1608 for(i = 0; i < current_menu->num_options; i++, display_option++)
1609 {
1610 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1611 {
1612 sprintf(line_buffer, display_option->display_string,
1613 *(display_option->current_option));
1614 }
1615 else
1616
1617 if(display_option->option_type & STRING_SELECTION_OPTION)
1618 {
1619 sprintf(line_buffer, display_option->display_string,
1620 ((u32 *)display_option->options)[*(display_option->current_option)]);
1621 }
1622 else
1623 {
1624 strcpy(line_buffer, display_option->display_string);
1625 }
1626
1627 if(display_option == current_option)
1628 {
1629 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1630 (display_option->line_number * 10) + 40, 36);
1631 }
1632 else
1633 {
1634 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1635 (display_option->line_number * 10) + 40, 36);
1636 }
1637 }
1638
1639 print_string(current_option->help_string, COLOR_HELP_TEXT,
90206450 1640 COLOR_BG, 8, 210);
2823a4c8 1641
1642 flip_screen();
1643
1644 gui_action = get_gui_input();
1645
1646 switch(gui_action)
1647 {
1648 case CURSOR_DOWN:
1649 current_option_num = (current_option_num + 1) %
1650 current_menu->num_options;
1651
1652 current_option = current_menu->options + current_option_num;
1653 clear_help();
1654 break;
1655
1656 case CURSOR_UP:
1657 if(current_option_num)
1658 current_option_num--;
1659 else
1660 current_option_num = current_menu->num_options - 1;
1661
1662 current_option = current_menu->options + current_option_num;
1663 clear_help();
1664 break;
1665
1666 case CURSOR_RIGHT:
1667 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1668 STRING_SELECTION_OPTION))
1669 {
1670 *(current_option->current_option) =
1671 (*current_option->current_option + 1) %
1672 current_option->num_options;
1673
1674 if(current_option->passive_function)
1675 current_option->passive_function();
1676 }
1677 break;
1678
1679 case CURSOR_LEFT:
1680 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1681 STRING_SELECTION_OPTION))
1682 {
1683 u32 current_option_val = *(current_option->current_option);
1684
1685 if(current_option_val)
1686 current_option_val--;
1687 else
1688 current_option_val = current_option->num_options - 1;
1689
1690 *(current_option->current_option) = current_option_val;
1691
1692 if(current_option->passive_function)
1693 current_option->passive_function();
1694 }
1695 break;
1696
1697 case CURSOR_EXIT:
1698 if(current_menu == &main_menu)
1699 menu_exit();
1700
1701 choose_menu(&main_menu);
1702 break;
1703
1704 case CURSOR_SELECT:
1705 if(current_option->option_type & ACTION_OPTION)
1706 current_option->action_function();
1707
1708 if(current_option->option_type & SUBMENU_OPTION)
1709 choose_menu(current_option->sub_menu);
1710 break;
1711 }
1712 }
1713
1714 set_gba_resolution(screen_scale);
1715 video_resolution_small();
1716
638cc626 1717 get_clock_speed();
1718 if (clock_speed != clock_speed_old)
1719 {
1720 printf("about to set CPU clock to %iMHz\n", clock_speed);
2823a4c8 1721 #ifdef PSP_BUILD
1722 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
90206450 1723 #elif defined(GP2X_BUILD)
638cc626 1724 set_FCLK(clock_speed);
2823a4c8 1725 #endif
638cc626 1726 clock_speed_old = clock_speed;
1727 }
2823a4c8 1728
1729 SDL_PauseAudio(0);
1730
1731 return return_value;
1732}