cleanup: remove cpu ctrl files, move tests
[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
1284 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1285 "in slightly better performance at the cost of latency; the lowest\n"
1286 "value will give the most responsive audio.\n"
1287 "This option requires gpSP to be restarted before it will take effect.",
1288 10),
1289 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1290 };
1291
1292 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1293
1294 menu_option_type cheats_misc_options[] =
1295 {
1296 cheat_option(0),
1297 cheat_option(1),
1298 cheat_option(2),
1299 cheat_option(3),
1300 cheat_option(4),
1301 cheat_option(5),
1302 cheat_option(6),
1303 cheat_option(7),
1304 cheat_option(8),
1305 cheat_option(9),
1306 string_selection_option(NULL, "Clock speed",
90206450 1307 clock_speed_options, &clock_speed_number,
1308#ifdef GP2X_BUILD
1309 15,
1310#else
1311 10,
1312#endif
1313 "Change the clock speed of the device. Higher clock\n"
1314 "speed will yield better performance, but will drain\n"
1315 "battery life further.", 11),
2823a4c8 1316 string_selection_option(NULL, "Update backup",
1317 update_backup_options, &update_backup_flag, 2,
90206450 1318#ifdef GP2X_BUILD
1319 "Determines when in-game save files should be\n"
1320 "written back to SD card.",
1321#else
2823a4c8 1322 "Determines when in-game save files should be written back to\n"
1323 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1324 "the game's backup is altered. On 'exit only' it will only be written\n"
1325 "back when you exit from this menu (NOT from using the home button).\n"
90206450 1326 "Use the latter with extreme care.",
1327#endif
1328 12),
2823a4c8 1329 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1330 };
1331
1332 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1333
1334 menu_option_type savestate_options[] =
1335 {
1336 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1337 "Load savestate from current slot", &savestate_slot, 10,
90206450 1338 "Select to load the game state from the current slot\n"
1339 "for this game.\n"
2823a4c8 1340 "Press left + right to change the current slot.", 6),
1341 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1342 "Save savestate to current slot", &savestate_slot, 10,
90206450 1343 "Select to save the game state to the current slot\n"
1344 "for this game.\n"
2823a4c8 1345 "Press left + right to change the current slot.", 7),
1346 numeric_selection_action_hide_option(menu_load_state_file,
1347 menu_change_state,
1348 "Load savestate from file", &savestate_slot, 10,
1349 "Restore gameplay from a savestate file.\n"
90206450 1350 "Note: The same file used to save the state must be\n"
1351 "present.\n", 9),
2823a4c8 1352 numeric_selection_option(menu_change_state,
1353 "Current savestate slot", &savestate_slot, 10,
1354 "Change the current savestate slot.\n", 11),
1355 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1356 };
1357
1358 make_menu(savestate, submenu_savestate, NULL);
1359
1360#ifdef PSP_BUILD
1361
1362 menu_option_type gamepad_config_options[] =
1363 {
1364 gamepad_config_option("D-pad up ", 0),
1365 gamepad_config_option("D-pad down ", 1),
1366 gamepad_config_option("D-pad left ", 2),
1367 gamepad_config_option("D-pad right ", 3),
1368 gamepad_config_option("Circle ", 4),
1369 gamepad_config_option("Cross ", 5),
1370 gamepad_config_option("Square ", 6),
1371 gamepad_config_option("Triangle ", 7),
1372 gamepad_config_option("Left Trigger ", 8),
1373 gamepad_config_option("Right Trigger", 9),
1374 gamepad_config_option("Start ", 10),
1375 gamepad_config_option("Select ", 11),
1376 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1377 };
1378
1379
1380 menu_option_type analog_config_options[] =
1381 {
1382 analog_config_option("Analog up ", 0),
1383 analog_config_option("Analog down ", 1),
1384 analog_config_option("Analog left ", 2),
1385 analog_config_option("Analog right", 3),
1386 string_selection_option(NULL, "Enable analog", yes_no_options,
1387 &global_enable_analog, 2,
1388 "Select 'no' to block analog input entirely.", 7),
1389 numeric_selection_option(NULL, "Analog sensitivity",
1390 &analog_sensitivity_level, 10,
1391 "Determine sensitivity/responsiveness of the analog input.\n"
1392 "Lower numbers are less sensitive.", 8),
1393 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1394 };
1395
1396#endif
1397
1398#ifdef GP2X_BUILD
1399
1400 menu_option_type gamepad_config_options[] =
1401 {
1402 gamepad_config_option("D-pad up ", 0),
1403 gamepad_config_option("D-pad down ", 1),
1404 gamepad_config_option("D-pad left ", 2),
1405 gamepad_config_option("D-pad right ", 3),
1406 gamepad_config_option("A ", 4),
1407 gamepad_config_option("B ", 5),
1408 gamepad_config_option("X ", 6),
1409 gamepad_config_option("Y ", 7),
1410 gamepad_config_option("Left Trigger ", 8),
1411 gamepad_config_option("Right Trigger", 9),
1412 gamepad_config_option("Start ", 10),
1413 gamepad_config_option("Select ", 11),
90206450 1414 gamepad_config_option("Stick Push ", 12),
1415 submenu_option(NULL, "Back", "Return to the main menu.", 14)
2823a4c8 1416 };
1417
1418
1419 menu_option_type analog_config_options[] =
1420 {
1421 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1422 };
1423
1424#endif
1425
1426#ifdef PC_BUILD
1427
1428 menu_option_type gamepad_config_options[] =
1429 {
1430 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1431 };
1432
1433 menu_option_type analog_config_options[] =
1434 {
1435 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1436 };
1437
1438#endif
1439
1440 make_menu(gamepad_config, submenu_gamepad, NULL);
1441 make_menu(analog_config, submenu_analog, NULL);
1442
1443 menu_option_type main_options[] =
1444 {
1445 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
90206450 1446 "Select to set display parameters and frameskip\n"
1447 "behavior, audio on/off, buffer size, and filtering.", 0),
2823a4c8 1448 numeric_selection_action_option(menu_load_state, NULL,
1449 "Load state from slot", &savestate_slot, 10,
90206450 1450 "Select to load the game state from the current slot\n"
1451 "for this game, if it exists.\n"
2823a4c8 1452 "Press left + right to change the current slot.", 2),
1453 numeric_selection_action_option(menu_save_state, NULL,
1454 "Save state to slot", &savestate_slot, 10,
90206450 1455 "Select to save the game state to the current slot\n"
1456 "for this game. See the extended menu for more info.\n"
2823a4c8 1457 "Press left + right to change the current slot.", 3),
1458 submenu_option(&savestate_menu, "Savestate options",
90206450 1459 "Select to enter a menu for loading, saving, and\n"
1460 "viewing the currently active savestate for this game\n"
1461 "(or to load a savestate file from another game)", 4),
2823a4c8 1462 submenu_option(&gamepad_config_menu, "Configure gamepad input",
90206450 1463 "Select to change the in-game behavior of buttons\n"
1464 "and d-pad.", 6),
1465#ifndef GP2X_BUILD
2823a4c8 1466 submenu_option(&analog_config_menu, "Configure analog input",
1467 "Select to change the in-game behavior of the PSP analog nub.", 7),
90206450 1468#endif
2823a4c8 1469 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
90206450 1470 "Select to manage cheats, set backup behavior,\n"
1471 "and set device clock speed.", 9),
2823a4c8 1472 action_option(menu_load, NULL, "Load new game",
90206450 1473 "Select to load a new game\n"
1474 "(will exit a game if currently playing).", 11),
2823a4c8 1475 action_option(menu_restart, NULL, "Restart game",
90206450 1476 "Select to reset the GBA with the current game\n"
1477 "loaded.", 12),
2823a4c8 1478 action_option(menu_exit, NULL, "Return to game",
1479 "Select to exit this menu and resume gameplay.", 13),
1480 action_option(menu_quit, NULL, "Exit gpSP",
90206450 1481 "Select to exit gpSP and return to the menu.", 15)
2823a4c8 1482 };
1483
1484 make_menu(main, submenu_main, NULL);
1485
1486 void choose_menu(menu_type *new_menu)
1487 {
1488 if(new_menu == NULL)
1489 new_menu = &main_menu;
1490
1491 clear_screen(COLOR_BG);
1492
1493#ifndef GP2X_BUILD
1494 blit_to_screen(original_screen, 240, 160, 230, 40);
1495#endif
1496
1497 current_menu = new_menu;
1498 current_option = new_menu->options;
1499 current_option_num = 0;
1500 if(current_menu->init_function)
1501 current_menu->init_function();
1502 }
1503
1504 void clear_help()
1505 {
1506 for(i = 0; i < 6; i++)
1507 {
90206450 1508 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
2823a4c8 1509 }
1510 }
1511
90206450 1512#ifdef PSP_BUILD
1513 clock_speed_number = (clock_speed / 33) - 1;
1514#elif defined(GP2X_BUILD)
1515 clock_speed_number = (clock_speed - 150) / 10;
1516#endif
1517
2823a4c8 1518 video_resolution_large();
1519
1520#ifndef GP2X_BUILD
1521 SDL_LockMutex(sound_mutex);
1522#endif
1523 SDL_PauseAudio(1);
1524
1525#ifndef GP2X_BUILD
1526 SDL_UnlockMutex(sound_mutex);
1527#endif
1528
1529 if(gamepak_filename[0] == 0)
1530 {
1531 first_load = 1;
1532 memset(original_screen, 0x00, 240 * 160 * 2);
1533 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1534 60, 75,original_screen, 240, 0);
1535 }
1536
1537 choose_menu(&main_menu);
1538
1539 for(i = 0; i < 10; i++)
1540 {
1541 if(i >= num_cheats)
1542 {
1543 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1544 }
1545 else
1546 {
1547 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1548 cheats[i].cheat_name);
1549 }
1550 }
1551
1552 current_menu->init_function();
1553
1554 while(repeat)
1555 {
1556 display_option = current_menu->options;
1557
1558 for(i = 0; i < current_menu->num_options; i++, display_option++)
1559 {
1560 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1561 {
1562 sprintf(line_buffer, display_option->display_string,
1563 *(display_option->current_option));
1564 }
1565 else
1566
1567 if(display_option->option_type & STRING_SELECTION_OPTION)
1568 {
1569 sprintf(line_buffer, display_option->display_string,
1570 ((u32 *)display_option->options)[*(display_option->current_option)]);
1571 }
1572 else
1573 {
1574 strcpy(line_buffer, display_option->display_string);
1575 }
1576
1577 if(display_option == current_option)
1578 {
1579 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1580 (display_option->line_number * 10) + 40, 36);
1581 }
1582 else
1583 {
1584 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1585 (display_option->line_number * 10) + 40, 36);
1586 }
1587 }
1588
1589 print_string(current_option->help_string, COLOR_HELP_TEXT,
90206450 1590 COLOR_BG, 8, 210);
2823a4c8 1591
1592 flip_screen();
1593
1594 gui_action = get_gui_input();
1595
1596 switch(gui_action)
1597 {
1598 case CURSOR_DOWN:
1599 current_option_num = (current_option_num + 1) %
1600 current_menu->num_options;
1601
1602 current_option = current_menu->options + current_option_num;
1603 clear_help();
1604 break;
1605
1606 case CURSOR_UP:
1607 if(current_option_num)
1608 current_option_num--;
1609 else
1610 current_option_num = current_menu->num_options - 1;
1611
1612 current_option = current_menu->options + current_option_num;
1613 clear_help();
1614 break;
1615
1616 case CURSOR_RIGHT:
1617 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1618 STRING_SELECTION_OPTION))
1619 {
1620 *(current_option->current_option) =
1621 (*current_option->current_option + 1) %
1622 current_option->num_options;
1623
1624 if(current_option->passive_function)
1625 current_option->passive_function();
1626 }
1627 break;
1628
1629 case CURSOR_LEFT:
1630 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1631 STRING_SELECTION_OPTION))
1632 {
1633 u32 current_option_val = *(current_option->current_option);
1634
1635 if(current_option_val)
1636 current_option_val--;
1637 else
1638 current_option_val = current_option->num_options - 1;
1639
1640 *(current_option->current_option) = current_option_val;
1641
1642 if(current_option->passive_function)
1643 current_option->passive_function();
1644 }
1645 break;
1646
1647 case CURSOR_EXIT:
1648 if(current_menu == &main_menu)
1649 menu_exit();
1650
1651 choose_menu(&main_menu);
1652 break;
1653
1654 case CURSOR_SELECT:
1655 if(current_option->option_type & ACTION_OPTION)
1656 current_option->action_function();
1657
1658 if(current_option->option_type & SUBMENU_OPTION)
1659 choose_menu(current_option->sub_menu);
1660 break;
1661 }
1662 }
1663
1664 set_gba_resolution(screen_scale);
1665 video_resolution_small();
1666
2823a4c8 1667 #ifdef PSP_BUILD
90206450 1668 clock_speed = (clock_speed_number + 1) * 33;
2823a4c8 1669 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
90206450 1670 #elif defined(GP2X_BUILD)
1671 clock_speed = 150 + clock_speed_number * 10;
1672 if (clock_speed != clock_speed_old)
1673 {
1674 printf("about to set CPU clock to %iMHz\n", clock_speed);
1675 set_FCLK(clock_speed);
1676 clock_speed_old = clock_speed;
1677 }
2823a4c8 1678 #endif
1679
1680 SDL_PauseAudio(0);
1681
1682 return return_value;
1683}