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