1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #define DEBUG_JOYSTICKS 0
30 /* screens on the info screen */
31 #define INFO_MODE_MAIN 0
32 #define INFO_MODE_TITLE 1
33 #define INFO_MODE_ELEMENTS 2
34 #define INFO_MODE_MUSIC 3
35 #define INFO_MODE_CREDITS 4
36 #define INFO_MODE_PROGRAM 5
37 #define INFO_MODE_VERSION 6
38 #define INFO_MODE_LEVELSET 7
40 #define MAX_INFO_MODES 8
42 /* screens on the setup screen */
43 /* (must match GFX_SPECIAL_ARG_SETUP_* values as defined in src/main.h) */
44 /* (should also match corresponding entries in src/conf_gfx.c) */
45 #define SETUP_MODE_MAIN 0
46 #define SETUP_MODE_GAME 1
47 #define SETUP_MODE_EDITOR 2
48 #define SETUP_MODE_GRAPHICS 3
49 #define SETUP_MODE_SOUND 4
50 #define SETUP_MODE_ARTWORK 5
51 #define SETUP_MODE_INPUT 6
52 #define SETUP_MODE_TOUCH 7
53 #define SETUP_MODE_SHORTCUTS 8
54 #define SETUP_MODE_SHORTCUTS_1 9
55 #define SETUP_MODE_SHORTCUTS_2 10
56 #define SETUP_MODE_SHORTCUTS_3 11
57 #define SETUP_MODE_SHORTCUTS_4 12
58 #define SETUP_MODE_SHORTCUTS_5 13
60 /* sub-screens on the setup screen (generic) */
61 #define SETUP_MODE_CHOOSE_ARTWORK 14
62 #define SETUP_MODE_CHOOSE_OTHER 15
64 /* sub-screens on the setup screen (specific) */
65 #define SETUP_MODE_CHOOSE_GAME_SPEED 16
66 #define SETUP_MODE_CHOOSE_SCROLL_DELAY 17
67 #define SETUP_MODE_CHOOSE_SNAPSHOT_MODE 18
68 #define SETUP_MODE_CHOOSE_WINDOW_SIZE 19
69 #define SETUP_MODE_CHOOSE_SCALING_TYPE 20
70 #define SETUP_MODE_CHOOSE_RENDERING 21
71 #define SETUP_MODE_CHOOSE_GRAPHICS 22
72 #define SETUP_MODE_CHOOSE_SOUNDS 23
73 #define SETUP_MODE_CHOOSE_MUSIC 24
74 #define SETUP_MODE_CHOOSE_VOLUME_SIMPLE 25
75 #define SETUP_MODE_CHOOSE_VOLUME_LOOPS 26
76 #define SETUP_MODE_CHOOSE_VOLUME_MUSIC 27
77 #define SETUP_MODE_CHOOSE_TOUCH_CONTROL 28
78 #define SETUP_MODE_CHOOSE_MOVE_DISTANCE 29
79 #define SETUP_MODE_CHOOSE_DROP_DISTANCE 30
81 #define MAX_SETUP_MODES 31
83 #define MAX_MENU_MODES MAX(MAX_INFO_MODES, MAX_SETUP_MODES)
85 /* setup screen titles */
86 #define STR_SETUP_MAIN "Setup"
87 #define STR_SETUP_GAME "Game & Menu"
88 #define STR_SETUP_EDITOR "Editor"
89 #define STR_SETUP_GRAPHICS "Graphics"
90 #define STR_SETUP_SOUND "Sound & Music"
91 #define STR_SETUP_ARTWORK "Custom Artwork"
92 #define STR_SETUP_INPUT "Input Devices"
93 #define STR_SETUP_TOUCH "Touch Controls"
94 #define STR_SETUP_SHORTCUTS "Key Shortcuts"
95 #define STR_SETUP_EXIT "Exit"
96 #define STR_SETUP_SAVE_AND_EXIT "Save and Exit"
98 #define STR_SETUP_CHOOSE_GAME_SPEED "Game Speed"
99 #define STR_SETUP_CHOOSE_SCROLL_DELAY "Scroll Delay"
100 #define STR_SETUP_CHOOSE_SNAPSHOT_MODE "Snapshot Mode"
101 #define STR_SETUP_CHOOSE_WINDOW_SIZE "Window Scaling"
102 #define STR_SETUP_CHOOSE_SCALING_TYPE "Anti-Aliasing"
103 #define STR_SETUP_CHOOSE_RENDERING "Rendering Mode"
104 #define STR_SETUP_CHOOSE_VOLUME_SIMPLE "Sound Volume"
105 #define STR_SETUP_CHOOSE_VOLUME_LOOPS "Loops Volume"
106 #define STR_SETUP_CHOOSE_VOLUME_MUSIC "Music Volume"
107 #define STR_SETUP_CHOOSE_TOUCH_CONTROL "Control Type"
108 #define STR_SETUP_CHOOSE_MOVE_DISTANCE "Move Distance"
109 #define STR_SETUP_CHOOSE_DROP_DISTANCE "Drop Distance"
111 /* for input setup functions */
112 #define SETUPINPUT_SCREEN_POS_START 0
113 #define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4)
114 #define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3)
115 #define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1)
117 #define MENU_SETUP_FONT_TITLE FONT_TEXT_1
118 #define MENU_SETUP_FONT_TEXT FONT_TITLE_2
120 /* for various menu stuff */
121 #define MENU_SCREEN_START_XPOS 1
122 #define MENU_SCREEN_START_YPOS 2
123 #define MENU_SCREEN_VALUE_XPOS (SCR_FIELDX - 3)
124 #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1)
125 #define MENU_TITLE1_YPOS 8
126 #define MENU_TITLE2_YPOS 46
127 #define MENU_INFO_FONT_TITLE FONT_TEXT_1
128 #define MENU_INFO_FONT_HEAD FONT_TEXT_2
129 #define MENU_INFO_FONT_TEXT FONT_TEXT_3
130 #define MENU_INFO_FONT_FOOT FONT_TEXT_4
131 #define MENU_INFO_SPACE_HEAD (menu.headline2_spacing_info[info_mode])
132 #define MENU_SCREEN_INFO_XSTART 16
133 #define MENU_SCREEN_INFO_YSTART1 100
134 #define MENU_SCREEN_INFO_YSTART2 (MENU_SCREEN_INFO_YSTART1 + \
135 getMenuTextStep(MENU_INFO_SPACE_HEAD, \
136 MENU_INFO_FONT_TITLE))
137 #define MENU_SCREEN_INFO_YSTEP (TILEY + 4)
138 #define MENU_SCREEN_INFO_YBOTTOM (SYSIZE - 20)
139 #define MENU_SCREEN_INFO_YSIZE (MENU_SCREEN_INFO_YBOTTOM - \
140 MENU_SCREEN_INFO_YSTART2 - \
142 #define MAX_INFO_ELEMENTS_ON_SCREEN 128
143 #define STD_INFO_ELEMENTS_ON_SCREEN (MENU_SCREEN_INFO_YSIZE / \
144 MENU_SCREEN_INFO_YSTEP)
145 #define NUM_INFO_ELEMENTS_FROM_CONF \
146 (menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] > 0 ? \
147 menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] : \
148 MAX_MENU_ENTRIES_ON_SCREEN)
149 #define NUM_INFO_ELEMENTS_ON_SCREEN MIN(MIN(STD_INFO_ELEMENTS_ON_SCREEN, \
150 MAX_INFO_ELEMENTS_ON_SCREEN), \
151 NUM_INFO_ELEMENTS_FROM_CONF)
152 #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS)
153 #define MAX_MENU_TEXT_LENGTH_BIG 13
154 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2)
156 /* buttons and scrollbars identifiers */
157 #define SCREEN_CTRL_ID_PREV_LEVEL 0
158 #define SCREEN_CTRL_ID_NEXT_LEVEL 1
159 #define SCREEN_CTRL_ID_PREV_PLAYER 2
160 #define SCREEN_CTRL_ID_NEXT_PLAYER 3
161 #define SCREEN_CTRL_ID_SCROLL_UP 4
162 #define SCREEN_CTRL_ID_SCROLL_DOWN 5
163 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 6
165 #define NUM_SCREEN_GADGETS 7
167 #define NUM_SCREEN_MENUBUTTONS 4
168 #define NUM_SCREEN_SCROLLBUTTONS 2
169 #define NUM_SCREEN_SCROLLBARS 1
171 #define SCREEN_MASK_MAIN (1 << 0)
172 #define SCREEN_MASK_INPUT (1 << 1)
174 /* graphic position and size values for buttons and scrollbars */
175 #define SC_MENUBUTTON_XSIZE TILEX
176 #define SC_MENUBUTTON_YSIZE TILEY
178 #define SC_SCROLLBUTTON_XSIZE TILEX
179 #define SC_SCROLLBUTTON_YSIZE TILEY
181 #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
183 #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
184 #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
185 SC_SCROLLBUTTON_YSIZE)
187 #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS
188 #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE)
190 #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS
191 #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \
192 SC_SCROLLBUTTON_YSIZE)
194 #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS
195 #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \
196 SC_SCROLL_VERTICAL_YSIZE)
198 #define SC_BORDER_SIZE 14
201 /* forward declarations of internal functions */
202 static void HandleScreenGadgets(struct GadgetInfo *);
203 static void HandleSetupScreen_Generic(int, int, int, int, int);
204 static void HandleSetupScreen_Input(int, int, int, int, int);
205 static void CustomizeKeyboard(int);
206 static void ConfigureJoystick(int);
207 static void execSetupGame(void);
208 static void execSetupGraphics(void);
209 static void execSetupSound(void);
210 static void execSetupTouch(void);
211 static void execSetupArtwork(void);
212 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
214 static void DrawChooseLevelSet(void);
215 static void DrawChooseLevelNr(void);
216 static void DrawInfoScreen(void);
217 static void DrawSetupScreen(void);
219 static void DrawInfoScreen_NotAvailable(char *, char *);
220 static void DrawInfoScreen_HelpAnim(int, int, boolean);
221 static void DrawInfoScreen_HelpText(int, int, int, int);
222 static void HandleInfoScreen_Main(int, int, int, int, int);
223 static void HandleInfoScreen_TitleScreen(int);
224 static void HandleInfoScreen_Elements(int);
225 static void HandleInfoScreen_Music(int);
226 static void HandleInfoScreen_Credits(int);
227 static void HandleInfoScreen_Program(int);
228 static void HandleInfoScreen_Version(int);
230 static void MapScreenMenuGadgets(int);
231 static void MapScreenGadgets(int);
232 static void MapScreenTreeGadgets(TreeInfo *);
234 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
236 static int info_mode = INFO_MODE_MAIN;
237 static int setup_mode = SETUP_MODE_MAIN;
239 static TreeInfo *window_sizes = NULL;
240 static TreeInfo *window_size_current = NULL;
242 static TreeInfo *scaling_types = NULL;
243 static TreeInfo *scaling_type_current = NULL;
245 static TreeInfo *rendering_modes = NULL;
246 static TreeInfo *rendering_mode_current = NULL;
248 static TreeInfo *scroll_delays = NULL;
249 static TreeInfo *scroll_delay_current = NULL;
251 static TreeInfo *snapshot_modes = NULL;
252 static TreeInfo *snapshot_mode_current = NULL;
254 static TreeInfo *game_speeds = NULL;
255 static TreeInfo *game_speed_current = NULL;
257 static TreeInfo *volumes_simple = NULL;
258 static TreeInfo *volume_simple_current = NULL;
260 static TreeInfo *volumes_loops = NULL;
261 static TreeInfo *volume_loops_current = NULL;
263 static TreeInfo *volumes_music = NULL;
264 static TreeInfo *volume_music_current = NULL;
266 static TreeInfo *touch_controls = NULL;
267 static TreeInfo *touch_control_current = NULL;
269 static TreeInfo *move_distances = NULL;
270 static TreeInfo *move_distance_current = NULL;
272 static TreeInfo *drop_distances = NULL;
273 static TreeInfo *drop_distance_current = NULL;
275 static TreeInfo *level_number = NULL;
276 static TreeInfo *level_number_current = NULL;
282 } window_sizes_list[] =
287 { 100, "100 % (Default)" },
304 } scaling_types_list[] =
306 { SCALING_QUALITY_NEAREST, "Off" },
307 { SCALING_QUALITY_LINEAR, "Linear" },
308 { SCALING_QUALITY_BEST, "Anisotropic" },
317 } rendering_modes_list[] =
319 { STR_SPECIAL_RENDERING_OFF, "Off (May show artifacts, fast)" },
320 { STR_SPECIAL_RENDERING_BITMAP, "Bitmap/Texture mode (slower)" },
322 // this mode may work under certain conditions, but does not work on Windows
323 { STR_SPECIAL_RENDERING_TARGET, "Target Texture mode (slower)" },
325 { STR_SPECIAL_RENDERING_DOUBLE, "Double Texture mode (slower)" },
334 } game_speeds_list[] =
343 { 1000, "1/1s (Extremely Slow)" },
348 { 29, "1/35s (Original Supaplex)" },
350 { 20, "1/50s (Normal Speed)" },
351 { 14, "1/70s (Maximum Supaplex)" },
355 { 1, "1/1000s (Extremely Fast)" },
365 } scroll_delays_list[] =
367 { 0, "0 Tiles (No Scroll Delay)" },
370 { 3, "3 Tiles (Default)" },
375 { 8, "8 Tiles (Maximum Scroll Delay)"},
384 } snapshot_modes_list[] =
386 { STR_SNAPSHOT_MODE_OFF, "Off" },
387 { STR_SNAPSHOT_MODE_EVERY_STEP, "Every Step" },
388 { STR_SNAPSHOT_MODE_EVERY_MOVE, "Every Move" },
389 { STR_SNAPSHOT_MODE_EVERY_COLLECT, "Every Collect" },
422 } touch_controls_list[] =
424 { TOUCH_CONTROL_OFF, "Off" },
425 { TOUCH_CONTROL_VIRTUAL_BUTTONS, "Virtual Buttons" },
426 { TOUCH_CONTROL_WIPE_GESTURES, "Wipe Gestures" },
427 { TOUCH_CONTROL_FOLLOW_FINGER, "Follow Finger" },
451 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
452 (s) <= GAME_MODE_SETUP ? (s) : \
453 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
454 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
456 /* (there are no draw offset definitions needed for INFO_MODE_TITLE) */
457 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_TITLE && \
458 (i) <= INFO_MODE_LEVELSET ? (i) : \
461 #define DRAW_MODE_SETUP(i) ((i) >= SETUP_MODE_MAIN && \
462 (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) : \
463 (i) >= SETUP_MODE_CHOOSE_GRAPHICS && \
464 (i) <= SETUP_MODE_CHOOSE_MUSIC ? \
465 SETUP_MODE_CHOOSE_ARTWORK : \
466 SETUP_MODE_CHOOSE_OTHER)
468 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
469 menu.draw_xoffset[GAME_MODE_INFO] : \
470 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
471 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
472 menu.draw_yoffset[GAME_MODE_INFO] : \
473 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
474 #define EXTRA_SPACING_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
475 menu.extra_spacing[GAME_MODE_INFO] : \
476 menu.extra_spacing_info[DRAW_MODE_INFO(i)])
478 #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
479 menu.draw_xoffset[GAME_MODE_SETUP] : \
480 menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)])
481 #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
482 menu.draw_yoffset[GAME_MODE_SETUP] : \
483 menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)])
484 #define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
485 menu.extra_spacing[GAME_MODE_SETUP] : \
486 menu.extra_spacing_setup[DRAW_MODE_SETUP(i)])
488 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
489 DRAW_XOFFSET_INFO(info_mode) : \
490 (s) == GAME_MODE_SETUP ? \
491 DRAW_XOFFSET_SETUP(setup_mode) : \
492 menu.draw_xoffset[DRAW_MODE(s)])
493 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
494 DRAW_YOFFSET_INFO(info_mode) : \
495 (s) == GAME_MODE_SETUP ? \
496 DRAW_YOFFSET_SETUP(setup_mode) : \
497 menu.draw_yoffset[DRAW_MODE(s)])
498 #define EXTRA_SPACING(s) ((s) == GAME_MODE_INFO ? \
499 EXTRA_SPACING_INFO(info_mode) : \
500 (s) == GAME_MODE_SETUP ? \
501 EXTRA_SPACING_SETUP(setup_mode) : \
502 menu.extra_spacing[DRAW_MODE(s)])
504 #define mSX (SX + DRAW_XOFFSET(game_status))
505 #define mSY (SY + DRAW_YOFFSET(game_status))
507 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
508 menu.list_size[game_status] : \
509 MAX_MENU_ENTRIES_ON_SCREEN)
511 #define IN_VIS_MENU(x, y) IN_FIELD(x, y, SCR_FIELDX, \
512 NUM_MENU_ENTRIES_ON_SCREEN)
515 /* title display and control definitions */
517 #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \
518 2 * MAX_NUM_TITLE_MESSAGES)
520 #define NO_DIRECT_LEVEL_SELECT (-1)
523 static int num_title_screens = 0;
525 struct TitleControlInfo
534 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
536 /* main menu display and control definitions */
538 #define MAIN_CONTROL_NAME 0
539 #define MAIN_CONTROL_LEVELS 1
540 #define MAIN_CONTROL_SCORES 2
541 #define MAIN_CONTROL_EDITOR 3
542 #define MAIN_CONTROL_INFO 4
543 #define MAIN_CONTROL_GAME 5
544 #define MAIN_CONTROL_SETUP 6
545 #define MAIN_CONTROL_QUIT 7
546 #define MAIN_CONTROL_PREV_LEVEL 8
547 #define MAIN_CONTROL_NEXT_LEVEL 9
548 #define MAIN_CONTROL_FIRST_LEVEL 10
549 #define MAIN_CONTROL_LAST_LEVEL 11
550 #define MAIN_CONTROL_LEVEL_NUMBER 12
551 #define MAIN_CONTROL_LEVEL_INFO_1 13
552 #define MAIN_CONTROL_LEVEL_INFO_2 14
553 #define MAIN_CONTROL_LEVEL_NAME 15
554 #define MAIN_CONTROL_LEVEL_AUTHOR 16
555 #define MAIN_CONTROL_LEVEL_YEAR 17
556 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM 18
557 #define MAIN_CONTROL_LEVEL_IMPORTED_BY 19
558 #define MAIN_CONTROL_LEVEL_TESTED_BY 20
559 #define MAIN_CONTROL_TITLE_1 21
560 #define MAIN_CONTROL_TITLE_2 22
561 #define MAIN_CONTROL_TITLE_3 23
563 static char str_main_text_name[10];
564 static char str_main_text_first_level[10];
565 static char str_main_text_last_level[10];
566 static char str_main_text_level_number[10];
568 static char *main_text_name = str_main_text_name;
569 static char *main_text_first_level = str_main_text_first_level;
570 static char *main_text_last_level = str_main_text_last_level;
571 static char *main_text_level_number = str_main_text_level_number;
572 static char *main_text_levels = "Levelset";
573 static char *main_text_scores = "Hall Of Fame";
574 static char *main_text_editor = "Level Creator";
575 static char *main_text_info = "Info Screen";
576 static char *main_text_game = "Start Game";
577 static char *main_text_setup = "Setup";
578 static char *main_text_quit = "Quit";
579 static char *main_text_level_name = level.name;
580 static char *main_text_level_author = level.author;
581 static char *main_text_level_year = NULL;
582 static char *main_text_level_imported_from = NULL;
583 static char *main_text_level_imported_by = NULL;
584 static char *main_text_level_tested_by = NULL;
585 static char *main_text_title_1 = NULL;
586 static char *main_text_title_2 = NULL;
587 static char *main_text_title_3 = NULL;
589 struct MainControlInfo
593 struct MenuPosInfo *pos_button;
596 struct TextPosInfo *pos_text;
599 struct TextPosInfo *pos_input;
603 static struct MainControlInfo main_controls[] =
607 &menu.main.button.name, IMG_MENU_BUTTON_NAME,
608 &menu.main.text.name, &main_text_name,
609 &menu.main.input.name, &setup.player_name,
613 &menu.main.button.levels, IMG_MENU_BUTTON_LEVELS,
614 &menu.main.text.levels, &main_text_levels,
619 &menu.main.button.scores, IMG_MENU_BUTTON_SCORES,
620 &menu.main.text.scores, &main_text_scores,
625 &menu.main.button.editor, IMG_MENU_BUTTON_EDITOR,
626 &menu.main.text.editor, &main_text_editor,
631 &menu.main.button.info, IMG_MENU_BUTTON_INFO,
632 &menu.main.text.info, &main_text_info,
637 &menu.main.button.game, IMG_MENU_BUTTON_GAME,
638 &menu.main.text.game, &main_text_game,
643 &menu.main.button.setup, IMG_MENU_BUTTON_SETUP,
644 &menu.main.text.setup, &main_text_setup,
649 &menu.main.button.quit, IMG_MENU_BUTTON_QUIT,
650 &menu.main.text.quit, &main_text_quit,
654 /* (these two buttons are real gadgets) */
656 MAIN_CONTROL_PREV_LEVEL,
657 &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL,
662 MAIN_CONTROL_NEXT_LEVEL,
663 &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL,
669 MAIN_CONTROL_FIRST_LEVEL,
671 &menu.main.text.first_level, &main_text_first_level,
675 MAIN_CONTROL_LAST_LEVEL,
677 &menu.main.text.last_level, &main_text_last_level,
681 MAIN_CONTROL_LEVEL_NUMBER,
683 &menu.main.text.level_number, &main_text_level_number,
687 MAIN_CONTROL_LEVEL_INFO_1,
689 &menu.main.text.level_info_1, NULL,
693 MAIN_CONTROL_LEVEL_INFO_2,
695 &menu.main.text.level_info_2, NULL,
699 MAIN_CONTROL_LEVEL_NAME,
701 &menu.main.text.level_name, &main_text_level_name,
705 MAIN_CONTROL_LEVEL_AUTHOR,
707 &menu.main.text.level_author, &main_text_level_author,
711 MAIN_CONTROL_LEVEL_YEAR,
713 &menu.main.text.level_year, &main_text_level_year,
717 MAIN_CONTROL_LEVEL_IMPORTED_FROM,
719 &menu.main.text.level_imported_from, &main_text_level_imported_from,
723 MAIN_CONTROL_LEVEL_IMPORTED_BY,
725 &menu.main.text.level_imported_by, &main_text_level_imported_by,
729 MAIN_CONTROL_LEVEL_TESTED_BY,
731 &menu.main.text.level_tested_by, &main_text_level_tested_by,
735 MAIN_CONTROL_TITLE_1,
737 &menu.main.text.title_1, &main_text_title_1,
741 MAIN_CONTROL_TITLE_2,
743 &menu.main.text.title_2, &main_text_title_2,
747 MAIN_CONTROL_TITLE_3,
749 &menu.main.text.title_3, &main_text_title_3,
762 static int getTitleScreenGraphic(int nr, boolean initial)
764 return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
767 static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial)
769 return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]);
773 static int getTitleScreenGameMode(boolean initial)
775 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
779 static int getTitleMessageGameMode(boolean initial)
781 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
784 static int getTitleAnimMode(struct TitleControlInfo *tci)
786 int base = (tci->initial ? GAME_MODE_TITLE_INITIAL_1 : GAME_MODE_TITLE_1);
788 return base + tci->local_nr;
792 static int getTitleScreenBackground(boolean initial)
794 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
799 static int getTitleMessageBackground(int nr, boolean initial)
801 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
805 static int getTitleBackground(int nr, boolean initial, boolean is_image)
807 int base = (is_image ?
808 (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 :
809 IMG_BACKGROUND_TITLESCREEN_1) :
810 (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
811 IMG_BACKGROUND_TITLEMESSAGE_1));
812 int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL :
813 IMG_BACKGROUND_TITLE);
814 int graphic_local = base + nr;
816 if (graphic_info[graphic_local].bitmap != NULL)
817 return graphic_local;
819 if (graphic_info[graphic_global].bitmap != NULL)
820 return graphic_global;
822 return IMG_UNDEFINED;
825 static int getTitleSound(struct TitleControlInfo *tci)
827 boolean is_image = tci->is_image;
828 int initial = tci->initial;
829 int nr = tci->local_nr;
830 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
831 int base = (is_image ?
832 (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 :
833 SND_BACKGROUND_TITLESCREEN_1) :
834 (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
835 SND_BACKGROUND_TITLEMESSAGE_1));
836 int sound_global = menu.sound[mode];
837 int sound_local = base + nr;
840 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
841 nr, initial, is_image,
842 sound_global, getSoundListEntry(sound_global)->filename,
843 sound_local, getSoundListEntry(sound_local)->filename);
846 if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME))
849 if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME))
852 return SND_UNDEFINED;
855 static int getTitleMusic(struct TitleControlInfo *tci)
857 boolean is_image = tci->is_image;
858 int initial = tci->initial;
859 int nr = tci->local_nr;
860 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
861 int base = (is_image ?
862 (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 :
863 MUS_BACKGROUND_TITLESCREEN_1) :
864 (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
865 MUS_BACKGROUND_TITLEMESSAGE_1));
866 int music_global = menu.music[mode];
867 int music_local = base + nr;
870 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
871 nr, initial, is_image,
872 music_global, getMusicListEntry(music_global)->filename,
873 music_local, getMusicListEntry(music_local)->filename);
876 if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME))
879 if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME))
882 return MUS_UNDEFINED;
885 static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci)
887 boolean is_image = tci->is_image;
888 boolean initial = tci->initial;
889 boolean first = tci->first;
890 int nr = tci->local_nr;
891 struct TitleMessageInfo tmi;
892 struct TitleFadingInfo ti;
894 tmi = (is_image ? (initial ? (first ?
895 titlescreen_initial_first[nr] :
896 titlescreen_initial[nr])
898 titlescreen_first[nr] :
900 : (initial ? (first ?
901 titlemessage_initial_first[nr] :
902 titlemessage_initial[nr])
904 titlemessage_first[nr] :
907 ti.fade_mode = tmi.fade_mode;
908 ti.fade_delay = tmi.fade_delay;
909 ti.post_delay = tmi.post_delay;
910 ti.auto_delay = tmi.auto_delay;
915 static int compareTitleControlInfo(const void *object1, const void *object2)
917 const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1;
918 const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2;
921 if (tci1->initial != tci2->initial)
922 compare_result = (tci1->initial ? -1 : +1);
923 else if (tci1->sort_priority != tci2->sort_priority)
924 compare_result = tci1->sort_priority - tci2->sort_priority;
925 else if (tci1->is_image != tci2->is_image)
926 compare_result = (tci1->is_image ? -1 : +1);
928 compare_result = tci1->local_nr - tci2->local_nr;
930 return compare_result;
933 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
935 int nr, int sort_priority)
937 title_controls[num_title_screens].is_image = is_image;
938 title_controls[num_title_screens].initial = initial;
939 title_controls[num_title_screens].local_nr = nr;
940 title_controls[num_title_screens].sort_priority = sort_priority;
942 title_controls[num_title_screens].first = FALSE; /* will be set later */
947 static void InitializeTitleControls_CheckTitleInfo(boolean initial)
951 for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++)
953 int graphic = getTitleScreenGraphic(i, initial);
954 Bitmap *bitmap = graphic_info[graphic].bitmap;
955 int sort_priority = graphic_info[graphic].sort_priority;
958 InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority);
961 for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
963 struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial);
964 char *filename = getLevelSetTitleMessageFilename(i, initial);
965 int sort_priority = tmi->sort_priority;
967 if (filename != NULL)
968 InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority);
972 static void InitializeTitleControls(boolean show_title_initial)
974 num_title_screens = 0;
976 /* 1st step: initialize title screens for game start (only when starting) */
977 if (show_title_initial)
978 InitializeTitleControls_CheckTitleInfo(TRUE);
980 /* 2nd step: initialize title screens for current level set */
981 InitializeTitleControls_CheckTitleInfo(FALSE);
983 /* sort title screens according to sort_priority and title number */
984 qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo),
985 compareTitleControlInfo);
987 /* mark first title screen */
988 title_controls[0].first = TRUE;
991 static boolean visibleMenuPos(struct MenuPosInfo *pos)
993 return (pos != NULL && pos->x != -1 && pos->y != -1);
996 static boolean visibleTextPos(struct TextPosInfo *pos)
998 return (pos != NULL && pos->x != -1 && pos->y != -1);
1001 static void InitializeMainControls()
1003 boolean local_team_mode = (!options.network && setup.team_mode);
1006 /* set main control text values to dynamically determined values */
1007 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
1009 strcpy(main_text_first_level, int2str(leveldir_current->first_level,
1010 menu.main.text.first_level.size));
1011 strcpy(main_text_last_level, int2str(leveldir_current->last_level,
1012 menu.main.text.last_level.size));
1013 strcpy(main_text_level_number, int2str(level_nr,
1014 menu.main.text.level_number.size));
1016 main_text_level_year = leveldir_current->year;
1017 main_text_level_imported_from = leveldir_current->imported_from;
1018 main_text_level_imported_by = leveldir_current->imported_by;
1019 main_text_level_tested_by = leveldir_current->tested_by;
1021 main_text_title_1 = getConfigProgramTitleString();
1022 main_text_title_2 = getConfigProgramCopyrightString();
1023 main_text_title_3 = getConfigProgramCompanyString();
1025 /* set main control screen positions to dynamically determined values */
1026 for (i = 0; main_controls[i].nr != -1; i++)
1028 struct MainControlInfo *mci = &main_controls[i];
1030 struct MenuPosInfo *pos_button = mci->pos_button;
1031 struct TextPosInfo *pos_text = mci->pos_text;
1032 struct TextPosInfo *pos_input = mci->pos_input;
1033 char *text = (mci->text ? *mci->text : NULL);
1034 char *input = (mci->input ? *mci->input : NULL);
1035 int button_graphic = mci->button_graphic;
1036 int font_text = (pos_text ? pos_text->font : -1);
1037 int font_input = (pos_input ? pos_input->font : -1);
1039 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
1040 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
1041 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
1042 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
1043 int text_chars = (text != NULL ? strlen(text) : 0);
1044 int input_chars = (input != NULL ? strlen(input) : 0);
1047 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
1049 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
1050 int text_width = font_text_width * text_chars;
1051 int text_height = font_text_height;
1052 int input_width = font_input_width * input_chars;
1053 int input_height = font_input_height;
1055 if (nr == MAIN_CONTROL_NAME)
1057 menu.main.input.name.width = input_width;
1058 menu.main.input.name.height = input_height;
1061 if (pos_button != NULL) /* (x/y may be -1/-1 here) */
1063 pos_button->width = button_width;
1064 pos_button->height = button_height;
1067 if (pos_text != NULL) /* (x/y may be -1/-1 here) */
1069 /* calculate size for non-clickable text -- needed for text alignment */
1070 boolean calculate_text_size = (pos_button == NULL && text != NULL);
1072 if (pos_text->width == -1 || calculate_text_size)
1073 pos_text->width = text_width;
1074 if (pos_text->height == -1 || calculate_text_size)
1075 pos_text->height = text_height;
1077 if (visibleMenuPos(pos_button))
1079 if (pos_text->x == -1)
1080 pos_text->x = pos_button->x + pos_button->width;
1081 if (pos_text->y == -1)
1083 pos_button->y + (pos_button->height - pos_text->height) / 2;
1087 if (pos_input != NULL) /* (x/y may be -1/-1 here) */
1089 if (visibleTextPos(pos_text))
1091 if (pos_input->x == -1)
1092 pos_input->x = pos_text->x + pos_text->width;
1093 if (pos_input->y == -1)
1094 pos_input->y = pos_text->y;
1097 if (pos_input->width == -1)
1098 pos_input->width = input_width;
1099 if (pos_input->height == -1)
1100 pos_input->height = input_height;
1105 static void DrawPressedGraphicThruMask(int dst_x, int dst_y,
1106 int graphic, boolean pressed)
1108 struct GraphicInfo *g = &graphic_info[graphic];
1111 int xoffset = (pressed ? g->pressed_xoffset : 0);
1112 int yoffset = (pressed ? g->pressed_yoffset : 0);
1114 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1116 BlitBitmapMasked(src_bitmap, drawto, src_x + xoffset, src_y + yoffset,
1117 g->width, g->height, dst_x, dst_y);
1120 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
1121 boolean active_input,
1122 boolean pressed_button)
1126 for (i = 0; main_controls[i].nr != -1; i++)
1128 struct MainControlInfo *mci = &main_controls[i];
1130 if (mci->nr == nr || nr == -1)
1132 struct MenuPosInfo *pos_button = mci->pos_button;
1133 struct TextPosInfo *pos_text = mci->pos_text;
1134 struct TextPosInfo *pos_input = mci->pos_input;
1135 char *text = (mci->text ? *mci->text : NULL);
1136 char *input = (mci->input ? *mci->input : NULL);
1137 int button_graphic = mci->button_graphic;
1138 int font_text = (pos_text ? pos_text->font : -1);
1139 int font_input = (pos_input ? pos_input->font : -1);
1143 button_graphic = BUTTON_ACTIVE(button_graphic);
1144 font_text = FONT_ACTIVE(font_text);
1149 font_input = FONT_ACTIVE(font_input);
1152 if (visibleMenuPos(pos_button))
1154 struct MenuPosInfo *pos = pos_button;
1155 int x = mSX + pos->x;
1156 int y = mSY + pos->y;
1158 DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
1159 DrawPressedGraphicThruMask(x, y, button_graphic, pressed_button);
1162 if (visibleTextPos(pos_text) && text != NULL)
1164 struct TextPosInfo *pos = pos_text;
1165 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1166 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1169 /* (check why/if this is needed) */
1170 DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
1172 DrawText(x, y, text, font_text);
1175 if (visibleTextPos(pos_input) && input != NULL)
1177 struct TextPosInfo *pos = pos_input;
1178 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1179 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1182 /* (check why/if this is needed) */
1183 DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
1185 DrawText(x, y, input, font_input);
1191 static void DrawCursorAndText_Main(int nr, boolean active_text,
1192 boolean pressed_button)
1194 DrawCursorAndText_Main_Ext(nr, active_text, FALSE, pressed_button);
1198 static void DrawCursorAndText_Main_Input(int nr, boolean active_text,
1199 boolean pressed_button)
1201 DrawCursorAndText_Main_Ext(nr, active_text, TRUE, pressed_button);
1205 static struct MainControlInfo *getMainControlInfo(int nr)
1209 for (i = 0; main_controls[i].nr != -1; i++)
1210 if (main_controls[i].nr == nr)
1211 return &main_controls[i];
1216 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
1221 int rect_x = ALIGNED_TEXT_XPOS(rect);
1222 int rect_y = ALIGNED_TEXT_YPOS(rect);
1224 return (x >= rect_x && x < rect_x + rect->width &&
1225 y >= rect_y && y < rect_y + rect->height);
1228 static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
1233 int rect_x = ALIGNED_TEXT_XPOS(rect);
1234 int rect_y = ALIGNED_TEXT_YPOS(rect);
1237 printf("::: insideTextPosRect: (%d, %d), (%d, %d) [%d, %d] (%d, %d) => %d\n",
1238 x, y, rect_x, rect_y, rect->x, rect->y, rect->width, rect->height,
1239 (x >= rect_x && x < rect_x + rect->width &&
1240 y >= rect_y && y < rect_y + rect->height));
1243 return (x >= rect_x && x < rect_x + rect->width &&
1244 y >= rect_y && y < rect_y + rect->height);
1247 static boolean insidePreviewRect(struct PreviewInfo *preview, int x, int y)
1249 int rect_width = preview->xsize * preview->tile_size;
1250 int rect_height = preview->ysize * preview->tile_size;
1251 int rect_x = ALIGNED_XPOS(preview->x, rect_width, preview->align);
1252 int rect_y = ALIGNED_YPOS(preview->y, rect_height, preview->valign);
1254 return (x >= rect_x && x < rect_x + rect_width &&
1255 y >= rect_y && y < rect_y + rect_height);
1258 static void AdjustScrollbar(int id, int items_max, int items_visible,
1261 struct GadgetInfo *gi = screen_gadget[id];
1263 if (item_position > items_max - items_visible)
1264 item_position = items_max - items_visible;
1266 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
1267 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1268 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
1271 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
1273 AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN,
1277 static void clearMenuListArea()
1279 int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
1281 /* correct scrollbar position if placed outside menu (playfield) area */
1282 if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS)
1283 scrollbar_xpos = SX + SC_SCROLLBAR_XPOS;
1285 /* clear menu list area, but not title or scrollbar */
1286 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
1287 scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32);
1290 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
1292 static int cursor_array[MAX_LEV_FIELDY];
1293 int x = mSX + TILEX * xpos;
1294 int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
1299 cursor_array[ypos] = graphic;
1301 graphic = cursor_array[ypos];
1305 graphic = BUTTON_ACTIVE(graphic);
1307 DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
1308 DrawFixedGraphicThruMaskExt(drawto, x, y, graphic, 0);
1311 static void initCursor(int ypos, int graphic)
1313 drawCursorExt(0, ypos, FALSE, graphic);
1316 static void drawCursor(int ypos, boolean active)
1318 drawCursorExt(0, ypos, active, -1);
1321 static void drawCursorXY(int xpos, int ypos, int graphic)
1323 drawCursorExt(xpos, ypos, FALSE, graphic);
1326 static void drawChooseTreeCursor(int ypos, boolean active)
1328 drawCursorExt(0, ypos, active, -1);
1333 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, main_text_title_1);
1334 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, main_text_title_2);
1337 void DrawTitleScreenImage(int nr, boolean initial)
1339 int graphic = getTitleScreenGraphic(nr, initial);
1340 Bitmap *bitmap = graphic_info[graphic].bitmap;
1341 int width = graphic_info[graphic].width;
1342 int height = graphic_info[graphic].height;
1343 int src_x = graphic_info[graphic].src_x;
1344 int src_y = graphic_info[graphic].src_y;
1350 if (width > WIN_XSIZE)
1352 /* image width too large for window => center image horizontally */
1353 src_x = (width - WIN_XSIZE) / 2;
1357 if (height > WIN_YSIZE)
1359 /* image height too large for window => center image vertically */
1360 src_y = (height - WIN_YSIZE) / 2;
1364 /* always display title screens centered */
1365 dst_x = (WIN_XSIZE - width) / 2;
1366 dst_y = (WIN_YSIZE - height) / 2;
1368 SetDrawBackgroundMask(REDRAW_ALL);
1369 SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE));
1371 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1373 if (DrawingOnBackground(dst_x, dst_y))
1374 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1376 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1378 redraw_mask = REDRAW_ALL;
1381 void DrawTitleScreenMessage(int nr, boolean initial)
1383 char *filename = getLevelSetTitleMessageFilename(nr, initial);
1384 struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
1386 if (filename == NULL)
1389 /* force TITLE font on title message screen */
1390 SetFontStatus(getTitleMessageGameMode(initial));
1392 /* if chars *and* width set to "-1", automatically determine width */
1393 if (tmi->chars == -1 && tmi->width == -1)
1394 tmi->width = viewport.window[game_status].width;
1396 /* if lines *and* height set to "-1", automatically determine height */
1397 if (tmi->lines == -1 && tmi->height == -1)
1398 tmi->height = viewport.window[game_status].height;
1400 /* if chars set to "-1", automatically determine by text and font width */
1401 if (tmi->chars == -1)
1402 tmi->chars = tmi->width / getFontWidth(tmi->font);
1404 tmi->width = tmi->chars * getFontWidth(tmi->font);
1406 /* if lines set to "-1", automatically determine by text and font height */
1407 if (tmi->lines == -1)
1408 tmi->lines = tmi->height / getFontHeight(tmi->font);
1410 tmi->height = tmi->lines * getFontHeight(tmi->font);
1412 /* if x set to "-1", automatically determine by width and alignment */
1414 tmi->x = -1 * ALIGNED_XPOS(0, tmi->width, tmi->align);
1416 /* if y set to "-1", automatically determine by height and alignment */
1418 tmi->y = -1 * ALIGNED_YPOS(0, tmi->height, tmi->valign);
1420 SetDrawBackgroundMask(REDRAW_ALL);
1421 SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE));
1423 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1425 DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi),
1426 filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
1427 tmi->autowrap, tmi->centered, tmi->parse_comments);
1432 void DrawTitleScreen()
1434 KeyboardAutoRepeatOff();
1436 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
1439 boolean CheckTitleScreen(boolean levelset_has_changed)
1441 static boolean show_title_initial = TRUE;
1442 boolean show_titlescreen = FALSE;
1444 /* needed to be able to skip title screen, if no image or message defined */
1445 InitializeTitleControls(show_title_initial);
1447 if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
1448 show_titlescreen = TRUE;
1450 /* show initial title images and messages only once at program start */
1451 show_title_initial = FALSE;
1453 return (show_titlescreen && num_title_screens > 0);
1458 static LevelDirTree *leveldir_last_valid = NULL;
1459 boolean levelset_has_changed = FALSE;
1460 int fade_mask = REDRAW_FIELD;
1462 LimitScreenUpdates(FALSE);
1464 FadeSetLeaveScreen();
1466 /* do not fade out here -- function may continue and fade on editor screen */
1469 FadeMenuSoundsAndMusic();
1471 ExpireSoundLoops(FALSE);
1473 KeyboardAutoRepeatOn();
1475 audio.sound_deactivated = FALSE;
1479 /* needed if last screen was the playing screen, invoked from level editor */
1480 if (level_editor_test_game)
1482 CloseDoor(DOOR_CLOSE_ALL);
1484 SetGameStatus(GAME_MODE_EDITOR);
1491 /* needed if last screen was the setup screen and fullscreen state changed */
1492 // (moved to "execSetupGraphics()" to change fullscreen state directly)
1493 // ToggleFullscreenOrChangeWindowScalingIfNeeded();
1495 /* leveldir_current may be invalid (level group, parent link) */
1496 if (!validLevelSeries(leveldir_current))
1497 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
1499 if (leveldir_current != leveldir_last_valid)
1500 levelset_has_changed = TRUE;
1502 /* store valid level series information */
1503 leveldir_last_valid = leveldir_current;
1505 init_last = init; /* switch to new busy animation */
1507 /* needed if last screen (level choice) changed graphics, sounds or music */
1508 ReloadCustomArtwork(0);
1510 if (CheckTitleScreen(levelset_has_changed))
1512 SetGameStatus(GAME_MODE_TITLE);
1519 if (redraw_mask & REDRAW_ALL)
1520 fade_mask = REDRAW_ALL;
1522 if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
1523 fade_mask = REDRAW_ALL;
1527 /* needed if different viewport properties defined for menues */
1528 ChangeViewportPropertiesIfNeeded();
1530 SetDrawtoField(DRAW_TO_BACKBUFFER);
1532 /* level_nr may have been set to value over handicap with level editor */
1533 if (setup.handicap && level_nr > leveldir_current->handicap_level)
1534 level_nr = leveldir_current->handicap_level;
1536 LoadLevel(level_nr);
1537 LoadScore(level_nr);
1539 SaveLevelSetup_SeriesInfo();
1541 // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it)
1542 SetDrawDeactivationMask(REDRAW_NONE);
1543 SetDrawBackgroundMask(REDRAW_FIELD);
1545 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
1548 if (fade_mask == REDRAW_ALL)
1549 RedrawGlobalBorder();
1554 InitializeMainControls();
1556 DrawCursorAndText_Main(-1, FALSE, FALSE);
1557 DrawPreviewLevelInitial();
1559 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
1562 if (TAPE_IS_EMPTY(tape))
1564 DrawCompleteVideoDisplay();
1566 PlayMenuSoundsAndMusic();
1568 /* create gadgets for main menu screen */
1569 FreeScreenGadgets();
1570 CreateScreenGadgets();
1572 /* map gadgets for main menu screen */
1574 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
1576 /* copy actual game door content to door double buffer for OpenDoor() */
1577 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
1578 BlitBitmap(drawto, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0);
1580 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1582 DrawMaskedBorder(fade_mask);
1587 /* update screen area with special editor door */
1588 redraw_mask |= REDRAW_ALL;
1591 SetMouseCursor(CURSOR_DEFAULT);
1593 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
1596 static void gotoTopLevelDir()
1598 /* move upwards until inside (but not above) top level directory */
1599 while (leveldir_current->node_parent &&
1600 !strEqual(leveldir_current->node_parent->subdir, STRING_TOP_DIRECTORY))
1602 /* write a "path" into level tree for easy navigation to last level */
1603 if (leveldir_current->node_parent->node_group->cl_first == -1)
1605 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
1606 int leveldir_pos = posTreeInfo(leveldir_current);
1607 int num_page_entries;
1608 int cl_first, cl_cursor;
1610 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
1611 num_page_entries = num_leveldirs;
1613 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1615 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
1616 cl_cursor = leveldir_pos - cl_first;
1618 leveldir_current->node_parent->node_group->cl_first = cl_first;
1619 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
1622 leveldir_current = leveldir_current->node_parent;
1626 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1628 static unsigned int title_delay = 0;
1629 static int title_screen_nr = 0;
1630 static int last_sound = -1, last_music = -1;
1631 boolean return_to_main_menu = FALSE;
1632 struct TitleControlInfo *tci;
1635 if (button == MB_MENU_INITIALIZE)
1638 title_screen_nr = 0;
1639 tci = &title_controls[title_screen_nr];
1641 SetAnimStatus(getTitleAnimMode(tci));
1643 last_sound = SND_UNDEFINED;
1644 last_music = MUS_UNDEFINED;
1646 if (num_title_screens != 0)
1648 FadeSetEnterScreen();
1650 /* use individual title fading instead of global "enter screen" fading */
1651 fading = getTitleFading(tci);
1654 if (game_status_last_screen == GAME_MODE_INFO)
1656 if (num_title_screens == 0)
1658 /* switch game mode from title screen mode back to info screen mode */
1659 SetGameStatus(GAME_MODE_INFO);
1661 /* store that last screen was info screen, not main menu screen */
1662 game_status_last_screen = GAME_MODE_INFO;
1664 DrawInfoScreen_NotAvailable("Title screen information:",
1665 "No title screen for this level set.");
1669 FadeMenuSoundsAndMusic();
1672 FadeOut(REDRAW_ALL);
1674 /* title screens may have different window size */
1675 ChangeViewportPropertiesIfNeeded();
1677 /* only required to update logic for redrawing global border */
1681 DrawTitleScreenImage(tci->local_nr, tci->initial);
1683 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1685 sound = getTitleSound(tci);
1686 music = getTitleMusic(tci);
1688 if (sound != last_sound)
1689 PlayMenuSoundExt(sound);
1690 if (music != last_music)
1691 PlayMenuMusicExt(music);
1696 SetMouseCursor(CURSOR_NONE);
1700 DelayReached(&title_delay, 0); /* reset delay counter */
1705 if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay))
1706 button = MB_MENU_CHOICE;
1708 if (button == MB_MENU_LEAVE)
1710 return_to_main_menu = TRUE;
1712 else if (button == MB_MENU_CHOICE)
1714 if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0)
1716 SetGameStatus(GAME_MODE_INFO);
1718 info_mode = INFO_MODE_MAIN;
1727 if (title_screen_nr < num_title_screens)
1729 tci = &title_controls[title_screen_nr];
1731 SetAnimStatus(getTitleAnimMode(tci));
1733 sound = getTitleSound(tci);
1734 music = getTitleMusic(tci);
1736 if (last_sound != SND_UNDEFINED && sound != last_sound)
1737 FadeSound(last_sound);
1738 if (last_music != MUS_UNDEFINED && music != last_music)
1741 fading = getTitleFading(tci);
1743 FadeOut(REDRAW_ALL);
1746 DrawTitleScreenImage(tci->local_nr, tci->initial);
1748 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1750 sound = getTitleSound(tci);
1751 music = getTitleMusic(tci);
1753 if (sound != last_sound)
1754 PlayMenuSoundExt(sound);
1755 if (music != last_music)
1756 PlayMenuMusicExt(music);
1763 DelayReached(&title_delay, 0); /* reset delay counter */
1767 FadeMenuSoundsAndMusic();
1769 return_to_main_menu = TRUE;
1773 if (return_to_main_menu)
1775 SetMouseCursor(CURSOR_DEFAULT);
1777 /* force full menu screen redraw after displaying title screens */
1778 redraw_mask = REDRAW_ALL;
1780 if (game_status_last_screen == GAME_MODE_INFO)
1782 SetGameStatus(GAME_MODE_INFO);
1784 info_mode = INFO_MODE_MAIN;
1788 else /* default: return to main menu */
1790 SetGameStatus(GAME_MODE_MAIN);
1797 void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr)
1799 int old_level_nr = level_nr;
1802 if (selected_level_nr != NO_DIRECT_LEVEL_SELECT)
1803 new_level_nr = selected_level_nr;
1805 new_level_nr = old_level_nr + step * direction;
1807 if (new_level_nr < leveldir_current->first_level)
1808 new_level_nr = leveldir_current->first_level;
1809 if (new_level_nr > leveldir_current->last_level)
1810 new_level_nr = leveldir_current->last_level;
1812 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1814 /* skipping levels is only allowed when trying to skip single level */
1815 if (setup.skip_levels && new_level_nr == old_level_nr + 1 &&
1816 Request("Level still unsolved! Skip despite handicap?", REQ_ASK))
1818 leveldir_current->handicap_level++;
1819 SaveLevelSetup_SeriesInfo();
1822 new_level_nr = leveldir_current->handicap_level;
1825 if (new_level_nr != old_level_nr)
1827 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER);
1829 PlaySound(SND_MENU_ITEM_SELECTING);
1831 level_nr = new_level_nr;
1833 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1834 int2str(level_nr, menu.main.text.level_number.size),
1835 mci->pos_text->font);
1837 LoadLevel(level_nr);
1838 DrawPreviewLevelInitial();
1842 DrawCompleteVideoDisplay();
1844 SaveLevelSetup_SeriesInfo();
1846 /* needed because DrawPreviewLevelInitial() takes some time */
1848 /* SyncDisplay(); */
1852 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1854 static int choice = MAIN_CONTROL_GAME;
1855 static boolean button_pressed_last = FALSE;
1856 boolean button_pressed = FALSE;
1860 if (button == MB_MENU_INITIALIZE)
1862 DrawCursorAndText_Main(choice, TRUE, FALSE);
1867 if (mx || my) /* mouse input */
1871 for (i = 0; main_controls[i].nr != -1; i++)
1873 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1874 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1875 insideTextPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1877 pos = main_controls[i].nr;
1883 /* check if level preview was clicked */
1884 if (insidePreviewRect(&preview, mx - SX, my - SY))
1885 pos = MAIN_CONTROL_GAME;
1887 // handle pressed/unpressed state for active/inactive menu buttons
1888 // (if pos != -1, "i" contains index position corresponding to "pos")
1890 pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT &&
1891 insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY))
1892 button_pressed = TRUE;
1894 if (button_pressed != button_pressed_last)
1896 DrawCursorAndText_Main(choice, TRUE, button_pressed);
1899 PlaySound(SND_MENU_BUTTON_PRESSING);
1901 PlaySound(SND_MENU_BUTTON_RELEASING);
1904 else if (dx || dy) /* keyboard input */
1906 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1907 choice == MAIN_CONTROL_SETUP))
1908 button = MB_MENU_CHOICE;
1913 if (pos == MAIN_CONTROL_FIRST_LEVEL && !button)
1915 HandleMainMenu_SelectLevel(MAX_LEVELS, -1, NO_DIRECT_LEVEL_SELECT);
1917 else if (pos == MAIN_CONTROL_LAST_LEVEL && !button)
1919 HandleMainMenu_SelectLevel(MAX_LEVELS, +1, NO_DIRECT_LEVEL_SELECT);
1921 else if (pos == MAIN_CONTROL_LEVEL_NUMBER && !button)
1923 CloseDoor(DOOR_CLOSE_2);
1925 SetGameStatus(GAME_MODE_LEVELNR);
1927 DrawChooseLevelNr();
1929 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
1935 PlaySound(SND_MENU_ITEM_ACTIVATING);
1937 DrawCursorAndText_Main(choice, FALSE, FALSE);
1938 DrawCursorAndText_Main(pos, TRUE, button_pressed);
1944 if (choice != MAIN_CONTROL_INFO &&
1945 choice != MAIN_CONTROL_SETUP)
1946 HandleMainMenu_SelectLevel(1, dx, NO_DIRECT_LEVEL_SELECT);
1951 PlaySound(SND_MENU_ITEM_SELECTING);
1953 if (pos == MAIN_CONTROL_NAME)
1955 SetGameStatus(GAME_MODE_PSEUDO_TYPENAME);
1957 HandleTypeName(strlen(setup.player_name), 0);
1959 else if (pos == MAIN_CONTROL_LEVELS)
1963 CloseDoor(DOOR_CLOSE_2);
1965 SetGameStatus(GAME_MODE_LEVELS);
1967 SaveLevelSetup_LastSeries();
1968 SaveLevelSetup_SeriesInfo();
1970 if (setup.internal.choose_from_top_leveldir)
1973 DrawChooseLevelSet();
1976 else if (pos == MAIN_CONTROL_SCORES)
1978 CloseDoor(DOOR_CLOSE_2);
1980 SetGameStatus(GAME_MODE_SCORES);
1984 else if (pos == MAIN_CONTROL_EDITOR)
1986 if (leveldir_current->readonly &&
1987 !strEqual(setup.player_name, "Artsoft"))
1988 Request("This level is read only!", REQ_CONFIRM);
1990 CloseDoor(DOOR_CLOSE_2);
1992 SetGameStatus(GAME_MODE_EDITOR);
1994 FadeSetEnterScreen();
1998 else if (pos == MAIN_CONTROL_INFO)
2000 CloseDoor(DOOR_CLOSE_2);
2002 SetGameStatus(GAME_MODE_INFO);
2004 info_mode = INFO_MODE_MAIN;
2008 else if (pos == MAIN_CONTROL_GAME)
2010 StartGameActions(options.network, setup.autorecord, level.random_seed);
2012 else if (pos == MAIN_CONTROL_SETUP)
2014 CloseDoor(DOOR_CLOSE_2);
2016 SetGameStatus(GAME_MODE_SETUP);
2018 setup_mode = SETUP_MODE_MAIN;
2022 else if (pos == MAIN_CONTROL_QUIT)
2024 SaveLevelSetup_LastSeries();
2025 SaveLevelSetup_SeriesInfo();
2027 if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED))
2028 SetGameStatus(GAME_MODE_QUIT);
2033 button_pressed_last = button_pressed;
2037 /* ========================================================================= */
2038 /* info screen functions */
2039 /* ========================================================================= */
2041 static struct TokenInfo *info_info;
2042 static int num_info_info; /* number of info entries shown on screen */
2043 static int max_info_info; /* total number of info entries in list */
2045 static void execInfoTitleScreen()
2047 info_mode = INFO_MODE_TITLE;
2052 static void execInfoElements()
2054 info_mode = INFO_MODE_ELEMENTS;
2059 static void execInfoMusic()
2061 info_mode = INFO_MODE_MUSIC;
2066 static void execInfoCredits()
2068 info_mode = INFO_MODE_CREDITS;
2073 static void execInfoProgram()
2075 info_mode = INFO_MODE_PROGRAM;
2080 static void execInfoVersion()
2082 info_mode = INFO_MODE_VERSION;
2087 static void execInfoLevelSet()
2089 info_mode = INFO_MODE_LEVELSET;
2094 static void execExitInfo()
2096 SetGameStatus(GAME_MODE_MAIN);
2101 static struct TokenInfo info_info_main[] =
2103 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
2104 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
2105 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
2106 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
2107 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
2108 { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" },
2109 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
2110 { TYPE_EMPTY, NULL, "" },
2111 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
2116 static int getMenuTextFont(int type)
2118 if (type & (TYPE_SWITCH |
2130 static struct TokenInfo *setup_info;
2131 static struct TokenInfo setup_info_input[];
2133 static struct TokenInfo *menu_info;
2135 static void DrawCursorAndText_Menu_Ext(struct TokenInfo *token_info,
2136 int screen_pos, int menu_info_pos_raw,
2139 int pos = (menu_info_pos_raw < 0 ? screen_pos : menu_info_pos_raw);
2140 struct TokenInfo *ti = &token_info[pos];
2141 int xpos = MENU_SCREEN_START_XPOS;
2142 int ypos = MENU_SCREEN_START_YPOS + screen_pos;
2143 int font_nr = getMenuTextFont(ti->type);
2145 if (token_info == setup_info_input)
2146 font_nr = FONT_MENU_1;
2149 font_nr = FONT_ACTIVE(font_nr);
2151 DrawText(mSX + xpos * 32, mSY + ypos * 32, ti->text, font_nr);
2153 if (ti->type & ~TYPE_SKIP_ENTRY)
2154 drawCursor(screen_pos, active);
2157 static void DrawCursorAndText_Menu(int screen_pos, int menu_info_pos_raw,
2160 DrawCursorAndText_Menu_Ext(menu_info, screen_pos, menu_info_pos_raw, active);
2163 static void DrawCursorAndText_Setup(int screen_pos, int menu_info_pos_raw,
2166 DrawCursorAndText_Menu_Ext(setup_info, screen_pos, menu_info_pos_raw, active);
2169 static char *window_size_text;
2170 static char *scaling_type_text;
2172 static void drawSetupValue(int, int);
2174 static void drawMenuInfoList(int first_entry, int num_page_entries,
2175 int max_page_entries)
2179 if (first_entry + num_page_entries > max_page_entries)
2182 clearMenuListArea();
2184 for (i = 0; i < num_page_entries; i++)
2186 int menu_info_pos = first_entry + i;
2187 struct TokenInfo *si = &menu_info[menu_info_pos];
2188 void *value_ptr = si->value;
2190 /* set some entries to "unchangeable" according to other variables */
2191 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
2192 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
2193 (value_ptr == &setup.sound_music && !audio.music_available) ||
2194 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
2195 (value_ptr == &window_size_text && !video.window_scaling_available) ||
2196 (value_ptr == &scaling_type_text && !video.window_scaling_available))
2197 si->type |= TYPE_GHOSTED;
2199 if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
2200 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
2201 else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
2202 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
2203 else if (si->type & ~TYPE_SKIP_ENTRY)
2204 initCursor(i, IMG_MENU_BUTTON);
2206 DrawCursorAndText_Menu(i, menu_info_pos, FALSE);
2208 if (si->type & TYPE_VALUE &&
2209 menu_info == setup_info)
2210 drawSetupValue(i, menu_info_pos);
2214 static void DrawInfoScreen_Main()
2216 int fade_mask = REDRAW_FIELD;
2219 if (redraw_mask & REDRAW_ALL)
2220 fade_mask = REDRAW_ALL;
2222 if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
2223 fade_mask = REDRAW_ALL;
2226 FadeMenuSoundsAndMusic();
2228 FreeScreenGadgets();
2229 CreateScreenGadgets();
2231 /* (needed after displaying title screens which disable auto repeat) */
2232 KeyboardAutoRepeatOn();
2234 FadeSetLeaveScreen();
2238 /* needed if different viewport properties defined for info screen */
2239 ChangeViewportPropertiesIfNeeded();
2241 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
2245 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
2247 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
2249 info_info = info_info_main;
2251 // determine maximal number of info entries that can be displayed on screen
2253 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
2256 // determine maximal number of info entries available for menu of info screen
2258 for (i = 0; info_info[i].type != 0; i++)
2261 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
2263 MapScreenGadgets(max_info_info);
2265 PlayMenuSoundsAndMusic();
2267 DrawMaskedBorder(fade_mask);
2272 static void changeSetupValue(int, int, int);
2274 void HandleMenuScreen(int mx, int my, int dx, int dy, int button,
2275 int mode, int num_page_entries, int max_page_entries)
2277 static int num_page_entries_all_last[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2278 static int choice_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2279 static int first_entry_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2280 int *num_page_entries_last = num_page_entries_all_last[game_status];
2281 int *choice_store = choice_stores[game_status];
2282 int *first_entry_store = first_entry_stores[game_status];
2283 int choice = choice_store[mode]; /* starts with 0 */
2284 int first_entry = first_entry_store[mode]; /* starts with 0 */
2286 int y = choice - first_entry;
2288 boolean position_set_by_scrollbar = (dx == 999);
2289 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2292 if (button == MB_MENU_INITIALIZE)
2294 // check if number of menu page entries has changed (may happen by change
2295 // of custom artwork definition value for 'list_size' for this menu screen)
2296 // (in this case, the last menu position most probably has to be corrected)
2297 if (num_page_entries != num_page_entries_last[mode])
2299 choice_store[mode] = first_entry_store[mode] = 0;
2301 choice = first_entry = 0;
2304 num_page_entries_last[mode] = num_page_entries;
2307 /* advance to first valid menu entry */
2308 while (choice < num_page_entries &&
2309 menu_info[choice].type & TYPE_SKIP_ENTRY)
2312 if (position_set_by_scrollbar)
2313 first_entry = first_entry_store[mode] = dy;
2315 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2316 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2318 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2320 if (choice < first_entry)
2322 choice = first_entry;
2324 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2327 else if (choice > first_entry + num_page_entries - 1)
2329 choice = first_entry + num_page_entries - 1;
2331 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2335 choice_store[mode] = choice;
2337 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2341 else if (button == MB_MENU_LEAVE)
2343 PlaySound(SND_MENU_ITEM_SELECTING);
2345 for (i = 0; i < max_page_entries; i++)
2347 if (menu_info[i].type & TYPE_LEAVE_MENU)
2349 void (*menu_callback_function)(void) = menu_info[i].value;
2353 menu_callback_function();
2355 break; /* absolutely needed because function changes 'menu_info'! */
2362 if (mx || my) /* mouse input */
2364 x = (mx - mSX) / 32;
2365 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2367 else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */
2369 /* move cursor instead of scrolling when already at start/end of list */
2370 if (dy == -1 * SCROLL_LINE && first_entry == 0)
2372 else if (dy == +1 * SCROLL_LINE &&
2373 first_entry + num_page_entries == max_page_entries)
2376 /* handle scrolling screen one line or page */
2378 y + dy > num_page_entries - 1)
2380 boolean redraw = FALSE;
2382 if (ABS(dy) == SCROLL_PAGE)
2383 step = num_page_entries - 1;
2385 if (dy < 0 && first_entry > 0)
2387 /* scroll page/line up */
2389 first_entry -= step;
2390 if (first_entry < 0)
2395 else if (dy > 0 && first_entry + num_page_entries < max_page_entries)
2397 /* scroll page/line down */
2399 first_entry += step;
2400 if (first_entry + num_page_entries > max_page_entries)
2401 first_entry = MAX(0, max_page_entries - num_page_entries);
2408 choice += first_entry - first_entry_store[mode];
2410 if (choice < first_entry)
2412 choice = first_entry;
2414 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2417 else if (choice > first_entry + num_page_entries - 1)
2419 choice = first_entry + num_page_entries - 1;
2421 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2424 else if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2428 if (choice < first_entry ||
2429 choice > first_entry + num_page_entries - 1)
2430 first_entry += SIGN(dy);
2433 first_entry_store[mode] = first_entry;
2434 choice_store[mode] = choice;
2436 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2438 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2440 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2441 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2449 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
2451 if (menu_info[choice].type & menu_navigation_type ||
2452 menu_info[choice].type & TYPE_BOOLEAN_STYLE ||
2453 menu_info[choice].type & TYPE_YES_NO_AUTO)
2454 button = MB_MENU_CHOICE;
2459 /* jump to next non-empty menu entry (up or down) */
2460 while (first_entry + y > 0 &&
2461 first_entry + y < max_page_entries - 1 &&
2462 menu_info[first_entry + y].type & TYPE_SKIP_ENTRY)
2465 if (!IN_VIS_MENU(x, y))
2467 choice += y - y_old;
2469 if (choice < first_entry)
2470 first_entry = choice;
2471 else if (choice > first_entry + num_page_entries - 1)
2472 first_entry = choice - num_page_entries + 1;
2474 if (first_entry >= 0 &&
2475 first_entry + num_page_entries <= max_page_entries)
2477 first_entry_store[mode] = first_entry;
2479 if (choice < first_entry)
2480 choice = first_entry;
2481 else if (choice > first_entry + num_page_entries - 1)
2482 choice = first_entry + num_page_entries - 1;
2484 choice_store[mode] = choice;
2486 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2488 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2490 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2491 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2498 if (!anyScrollbarGadgetActive() &&
2499 IN_VIS_MENU(x, y) &&
2500 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
2501 y >= 0 && y < num_page_entries)
2505 if (first_entry + y != choice &&
2506 menu_info[first_entry + y].type & ~TYPE_SKIP_ENTRY)
2508 PlaySound(SND_MENU_ITEM_ACTIVATING);
2510 DrawCursorAndText_Menu(choice - first_entry, choice, FALSE);
2511 DrawCursorAndText_Menu(y, first_entry + y, TRUE);
2513 choice = choice_store[mode] = first_entry + y;
2517 PlaySound(SND_MENU_ITEM_SELECTING);
2519 for (i = 0; menu_info[i].type != 0; i++)
2521 if (menu_info[i].type & TYPE_LEAVE_MENU)
2523 void (*menu_callback_function)(void) = menu_info[i].value;
2527 menu_callback_function();
2529 /* absolutely needed because function changes 'menu_info'! */
2537 else if (!(menu_info[first_entry + y].type & TYPE_GHOSTED))
2539 PlaySound(SND_MENU_ITEM_SELECTING);
2541 /* when selecting key headline, execute function for key value change */
2542 if (menu_info[first_entry + y].type & TYPE_KEYTEXT &&
2543 menu_info[first_entry + y + 1].type & TYPE_KEY)
2546 /* when selecting string value, execute function for list selection */
2547 if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 &&
2548 menu_info[first_entry + y - 1].type & TYPE_ENTER_LIST)
2551 if (menu_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE)
2553 void (*menu_callback_function)(void) =
2554 menu_info[first_entry + y].value;
2556 FadeSetFromType(menu_info[first_entry + y].type);
2558 menu_callback_function();
2560 else if (menu_info[first_entry + y].type & TYPE_VALUE &&
2561 menu_info == setup_info)
2563 changeSetupValue(y, first_entry + y, dx);
2569 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
2571 menu_info = info_info;
2573 HandleMenuScreen(mx, my, dx, dy, button,
2574 info_mode, num_info_info, max_info_info);
2577 static int getMenuFontSpacing(int spacing_height, int font_nr)
2579 int font_spacing = getFontHeight(font_nr) + EXTRA_SPACING(game_status);
2581 return (spacing_height < 0 ? ABS(spacing_height) * font_spacing :
2585 static int getMenuTextSpacing(int spacing_height, int font_nr)
2587 return (getMenuFontSpacing(spacing_height, font_nr) +
2588 EXTRA_SPACING(game_status));
2591 static int getMenuTextStep(int spacing_height, int font_nr)
2593 return getFontHeight(font_nr) + getMenuTextSpacing(spacing_height, font_nr);
2596 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
2598 int font_title = MENU_INFO_FONT_TITLE;
2599 int font_error = FONT_TEXT_2;
2600 int font_foot = MENU_INFO_FONT_FOOT;
2601 int spacing_title = menu.headline1_spacing_info[info_mode];
2602 int ystep_title = getMenuTextStep(spacing_title, font_title);
2603 int ystart1 = mSY - SY + 100;
2604 int ystart2 = ystart1 + ystep_title;
2605 int ybottom = mSY - SY + SYSIZE - 20;
2607 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO);
2609 FadeOut(REDRAW_FIELD);
2614 DrawTextSCentered(ystart1, font_title, text_title);
2615 DrawTextSCentered(ystart2, font_error, text_error);
2617 DrawTextSCentered(ybottom, font_foot,
2618 "Press any key or button for info menu");
2620 FadeIn(REDRAW_FIELD);
2623 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
2625 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
2626 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
2627 int font_title = MENU_INFO_FONT_TITLE;
2628 int font_foot = MENU_INFO_FONT_FOOT;
2629 int xstart = mSX + MENU_SCREEN_INFO_XSTART;
2630 int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2631 int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2;
2632 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2633 int ystep = MENU_SCREEN_INFO_YSTEP;
2634 int element, action, direction;
2642 for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++)
2643 infoscreen_step[i] = infoscreen_frame[i] = 0;
2648 DrawTextSCentered(ystart1, font_title, "The Game Elements:");
2650 DrawTextSCentered(ybottom, font_foot,
2651 "Press any key or button for next page");
2657 while (helpanim_info[j].element != HELPANIM_LIST_END)
2659 if (i >= start + NUM_INFO_ELEMENTS_ON_SCREEN ||
2664 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2673 j += infoscreen_step[i - start];
2675 element = helpanim_info[j].element;
2676 action = helpanim_info[j].action;
2677 direction = helpanim_info[j].direction;
2680 element = EL_UNKNOWN;
2682 if (action != -1 && direction != -1)
2683 graphic = el_act_dir2img(element, action, direction);
2684 else if (action != -1)
2685 graphic = el_act2img(element, action);
2686 else if (direction != -1)
2687 graphic = el_dir2img(element, direction);
2689 graphic = el2img(element);
2691 delay = helpanim_info[j++].delay;
2696 if (infoscreen_frame[i - start] == 0)
2699 infoscreen_frame[i - start] = delay - 1;
2703 sync_frame = delay - infoscreen_frame[i - start];
2704 infoscreen_frame[i - start]--;
2707 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
2709 if (!infoscreen_frame[i - start])
2710 infoscreen_step[i - start] = 0;
2714 if (!infoscreen_frame[i - start])
2715 infoscreen_step[i - start]++;
2716 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2722 ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep,
2724 DrawFixedGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep,
2725 graphic, sync_frame, USE_MASKING);
2728 DrawInfoScreen_HelpText(element, action, direction, i - start);
2733 redraw_mask |= REDRAW_FIELD;
2738 static char *getHelpText(int element, int action, int direction)
2740 char token[MAX_LINE_LEN];
2742 strcpy(token, element_info[element].token_name);
2745 strcat(token, element_action_info[action].suffix);
2747 if (direction != -1)
2748 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
2750 return getHashEntry(helptext_info, token);
2753 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
2755 int font_nr = FONT_INFO_ELEMENTS;
2756 int font_width = getFontWidth(font_nr);
2757 int font_height = getFontHeight(font_nr);
2758 int yoffset = (TILEX - 2 * font_height) / 2;
2759 int xstart = mSX + MINI_TILEX + TILEX + MINI_TILEX;
2760 int ystart = mSY + MENU_SCREEN_INFO_YSTART2 + yoffset;
2761 int ystep = TILEY + 4;
2762 int pad_x = xstart - SX;
2763 int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width;
2764 int max_lines_per_text = 2;
2767 if (action != -1 && direction != -1) /* element.action.direction */
2768 text = getHelpText(element, action, direction);
2770 if (text == NULL && action != -1) /* element.action */
2771 text = getHelpText(element, action, -1);
2773 if (text == NULL && direction != -1) /* element.direction */
2774 text = getHelpText(element, -1, direction);
2776 if (text == NULL) /* base element */
2777 text = getHelpText(element, -1, -1);
2779 if (text == NULL) /* not found */
2780 text = "No description available";
2782 if (strlen(text) <= max_chars_per_line) /* only one line of text */
2783 ystart += getFontHeight(font_nr) / 2;
2785 DrawTextBuffer(xstart, ystart + ypos * ystep, text, font_nr,
2786 max_chars_per_line, -1, max_lines_per_text, 0, -1,
2787 TRUE, FALSE, FALSE);
2790 void DrawInfoScreen_TitleScreen()
2792 SetGameStatus(GAME_MODE_TITLE);
2797 void HandleInfoScreen_TitleScreen(int button)
2799 HandleTitleScreen(0, 0, 0, 0, button);
2802 void DrawInfoScreen_Elements()
2804 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
2806 FadeOut(REDRAW_FIELD);
2811 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
2813 FadeIn(REDRAW_FIELD);
2816 void HandleInfoScreen_Elements(int button)
2818 static unsigned int info_delay = 0;
2819 static int num_anims;
2820 static int num_pages;
2822 int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN;
2825 if (button == MB_MENU_INITIALIZE)
2827 boolean new_element = TRUE;
2831 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
2833 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
2835 else if (new_element)
2838 new_element = FALSE;
2842 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
2846 if (button == MB_MENU_LEAVE)
2848 PlaySound(SND_MENU_ITEM_SELECTING);
2850 info_mode = INFO_MODE_MAIN;
2855 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2857 if (button != MB_MENU_INITIALIZE)
2859 PlaySound(SND_MENU_ITEM_SELECTING);
2864 if (page >= num_pages)
2866 FadeMenuSoundsAndMusic();
2868 info_mode = INFO_MODE_MAIN;
2875 FadeSetNextScreen();
2877 if (button != MB_MENU_INITIALIZE)
2878 FadeOut(REDRAW_FIELD);
2880 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
2882 if (button != MB_MENU_INITIALIZE)
2883 FadeIn(REDRAW_FIELD);
2887 if (DelayReached(&info_delay, GameFrameDelay))
2888 if (page < num_pages)
2889 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
2891 PlayMenuSoundIfLoop();
2895 void DrawInfoScreen_Music()
2897 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
2899 FadeOut(REDRAW_FIELD);
2906 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
2908 FadeIn(REDRAW_FIELD);
2911 void HandleInfoScreen_Music(int button)
2913 static struct MusicFileInfo *list = NULL;
2914 int font_title = MENU_INFO_FONT_TITLE;
2915 int font_head = MENU_INFO_FONT_HEAD;
2916 int font_text = MENU_INFO_FONT_TEXT;
2917 int font_foot = MENU_INFO_FONT_FOOT;
2918 int spacing_title = menu.headline1_spacing_info[info_mode];
2919 int spacing_head = menu.headline2_spacing_info[info_mode];
2920 int ystep_title = getMenuTextStep(spacing_title, font_title);
2921 int ystep_head = getMenuTextStep(spacing_head, font_head);
2922 int ystart = mSY - SY + 100;
2923 int ybottom = mSY - SY + SYSIZE - 20;
2925 if (button == MB_MENU_INITIALIZE)
2927 list = music_file_info;
2931 FadeMenuSoundsAndMusic();
2936 DrawTextSCentered(ystart, font_title,
2937 "No music info for this level set.");
2939 DrawTextSCentered(ybottom, font_foot,
2940 "Press any key or button for info menu");
2946 if (button == MB_MENU_LEAVE)
2948 PlaySound(SND_MENU_ITEM_SELECTING);
2950 FadeMenuSoundsAndMusic();
2952 info_mode = INFO_MODE_MAIN;
2957 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2959 if (button != MB_MENU_INITIALIZE)
2961 PlaySound(SND_MENU_ITEM_SELECTING);
2969 FadeMenuSoundsAndMusic();
2971 info_mode = INFO_MODE_MAIN;
2977 FadeMenuSoundsAndMusic();
2979 if (list != music_file_info)
2980 FadeSetNextScreen();
2982 if (button != MB_MENU_INITIALIZE)
2983 FadeOut(REDRAW_FIELD);
2990 int sound = list->music;
2992 if (sound_info[sound].loop)
2993 PlaySoundLoop(sound);
2997 DrawTextSCentered(ystart, font_title, "The Game Background Sounds:");
3001 PlayMusic(list->music);
3003 DrawTextSCentered(ystart, font_title, "The Game Background Music:");
3006 ystart += ystep_title;
3008 if (!strEqual(list->title, UNKNOWN_NAME))
3010 if (!strEqual(list->title_header, UNKNOWN_NAME))
3012 DrawTextSCentered(ystart, font_head, list->title_header);
3013 ystart += ystep_head;
3016 DrawTextFCentered(ystart, font_text, "\"%s\"", list->title);
3017 ystart += ystep_head;
3020 if (!strEqual(list->artist, UNKNOWN_NAME))
3022 if (!strEqual(list->artist_header, UNKNOWN_NAME))
3023 DrawTextSCentered(ystart, font_head, list->artist_header);
3025 DrawTextSCentered(ystart, font_head, "by");
3027 ystart += ystep_head;
3029 DrawTextFCentered(ystart, font_text, "%s", list->artist);
3030 ystart += ystep_head;
3033 if (!strEqual(list->album, UNKNOWN_NAME))
3035 if (!strEqual(list->album_header, UNKNOWN_NAME))
3036 DrawTextSCentered(ystart, font_head, list->album_header);
3038 DrawTextSCentered(ystart, font_head, "from the album");
3040 ystart += ystep_head;
3042 DrawTextFCentered(ystart, font_text, "\"%s\"", list->album);
3043 ystart += ystep_head;
3046 if (!strEqual(list->year, UNKNOWN_NAME))
3048 if (!strEqual(list->year_header, UNKNOWN_NAME))
3049 DrawTextSCentered(ystart, font_head, list->year_header);
3051 DrawTextSCentered(ystart, font_head, "from the year");
3053 ystart += ystep_head;
3055 DrawTextFCentered(ystart, font_text, "%s", list->year);
3056 ystart += ystep_head;
3059 DrawTextSCentered(ybottom, FONT_TEXT_4,
3060 "Press any key or button for next page");
3062 if (button != MB_MENU_INITIALIZE)
3063 FadeIn(REDRAW_FIELD);
3066 if (list != NULL && list->is_sound && sound_info[list->music].loop)
3067 PlaySoundLoop(list->music);
3070 static void DrawInfoScreen_CreditsScreen(int screen_nr)
3072 int font_title = MENU_INFO_FONT_TITLE;
3073 int font_head = MENU_INFO_FONT_HEAD;
3074 int font_text = MENU_INFO_FONT_TEXT;
3075 int font_foot = MENU_INFO_FONT_FOOT;
3076 int spacing_title = menu.headline1_spacing_info[info_mode];
3077 int spacing_head = menu.headline2_spacing_info[info_mode];
3078 int spacing_para = menu.paragraph_spacing_info[info_mode];
3079 int spacing_line = menu.line_spacing_info[info_mode];
3080 int ystep_title = getMenuTextStep(spacing_title, font_title);
3081 int ystep_head = getMenuTextStep(spacing_head, font_head);
3082 int ystep_para = getMenuTextStep(spacing_para, font_text);
3083 int ystep_line = getMenuTextStep(spacing_line, font_text);
3084 int ystart = mSY - SY + 100;
3085 int ybottom = mSY - SY + SYSIZE - 20;
3090 DrawTextSCentered(ystart, font_title, "Credits:");
3091 ystart += ystep_title;
3095 DrawTextSCentered(ystart, font_head,
3096 "Special thanks to");
3097 ystart += ystep_head;
3098 DrawTextSCentered(ystart, font_text,
3100 ystart += ystep_head;
3101 DrawTextSCentered(ystart, font_head,
3103 ystart += ystep_head;
3104 DrawTextSCentered(ystart, font_text,
3105 "\"Boulder Dash\"");
3106 ystart += ystep_head;
3107 DrawTextSCentered(ystart, font_head,
3109 ystart += ystep_head;
3110 DrawTextSCentered(ystart, font_text,
3112 ystart += ystep_head;
3113 DrawTextSCentered(ystart, font_head,
3115 ystart += ystep_head;
3116 DrawTextSCentered(ystart, font_text,
3117 "First Star Software");
3119 else if (screen_nr == 1)
3121 DrawTextSCentered(ystart, font_head,
3122 "Special thanks to");
3123 ystart += ystep_head;
3124 DrawTextSCentered(ystart, font_text,
3125 "Klaus Heinz & Volker Wertich");
3126 ystart += ystep_head;
3127 DrawTextSCentered(ystart, font_head,
3129 ystart += ystep_head;
3130 DrawTextSCentered(ystart, font_text,
3131 "\"Emerald Mine\"");
3132 ystart += ystep_head;
3133 DrawTextSCentered(ystart, font_head,
3135 ystart += ystep_head;
3136 DrawTextSCentered(ystart, font_text,
3138 ystart += ystep_head;
3139 DrawTextSCentered(ystart, font_head,
3141 ystart += ystep_head;
3142 DrawTextSCentered(ystart, font_text,
3145 else if (screen_nr == 2)
3147 DrawTextSCentered(ystart, font_head,
3148 "Special thanks to");
3149 ystart += ystep_head;
3150 DrawTextSCentered(ystart, font_text,
3151 "Michael Stopp & Philip Jespersen");
3152 ystart += ystep_head;
3153 DrawTextSCentered(ystart, font_head,
3155 ystart += ystep_head;
3156 DrawTextSCentered(ystart, font_text,
3158 ystart += ystep_head;
3159 DrawTextSCentered(ystart, font_head,
3161 ystart += ystep_head;
3162 DrawTextSCentered(ystart, font_text,
3164 ystart += ystep_head;
3165 DrawTextSCentered(ystart, font_head,
3167 ystart += ystep_head;
3168 DrawTextSCentered(ystart, font_text,
3169 "Digital Integration");
3171 else if (screen_nr == 3)
3173 DrawTextSCentered(ystart, font_head,
3174 "Special thanks to");
3175 ystart += ystep_head;
3176 DrawTextSCentered(ystart, font_text,
3177 "Hiroyuki Imabayashi");
3178 ystart += ystep_head;
3179 DrawTextSCentered(ystart, font_head,
3181 ystart += ystep_head;
3182 DrawTextSCentered(ystart, font_text,
3184 ystart += ystep_head;
3185 DrawTextSCentered(ystart, font_head,
3187 ystart += ystep_head;
3188 DrawTextSCentered(ystart, font_text,
3190 ystart += ystep_head;
3191 DrawTextSCentered(ystart, font_head,
3193 ystart += ystep_head;
3194 DrawTextSCentered(ystart, font_text,
3197 else if (screen_nr == 4)
3199 DrawTextSCentered(ystart, font_head,
3200 "Special thanks to");
3201 ystart += ystep_head;
3202 DrawTextSCentered(ystart, font_text,
3204 ystart += ystep_head;
3205 DrawTextSCentered(ystart, font_head,
3207 ystart += ystep_head;
3208 DrawTextSCentered(ystart, font_text,
3209 "J\xfcrgen Bonhagen");
3210 ystart += ystep_head;
3211 DrawTextSCentered(ystart, font_head,
3212 "for the continuous creation");
3213 ystart += ystep_line;
3214 DrawTextSCentered(ystart, font_head,
3215 "of outstanding level sets");
3217 else if (screen_nr == 5)
3219 DrawTextSCentered(ystart, font_head,
3221 ystart += ystep_head;
3222 DrawTextSCentered(ystart, font_text,
3224 ystart += ystep_head;
3225 DrawTextSCentered(ystart, font_head,
3226 "for ideas and inspiration by");
3227 ystart += ystep_head;
3228 DrawTextSCentered(ystart, font_text,
3230 ystart += ystep_para;
3232 DrawTextSCentered(ystart, font_head,
3234 ystart += ystep_head;
3235 DrawTextSCentered(ystart, font_text,
3237 ystart += ystep_head;
3238 DrawTextSCentered(ystart, font_head,
3239 "for ideas and inspiration by");
3240 ystart += ystep_head;
3241 DrawTextSCentered(ystart, font_text,
3244 else if (screen_nr == 6)
3246 DrawTextSCentered(ystart, font_head,
3248 ystart += ystep_head;
3249 DrawTextSCentered(ystart, font_text,
3251 ystart += ystep_head;
3252 DrawTextSCentered(ystart, font_head,
3253 "for the code base used for the");
3254 ystart += ystep_line;
3255 DrawTextSCentered(ystart, font_head,
3256 "native Emerald Mine engine");
3258 else if (screen_nr == 7)
3260 DrawTextSCentered(ystart, font_head,
3262 ystart += ystep_head;
3263 DrawTextSCentered(ystart, font_text,
3265 ystart += ystep_head;
3266 DrawTextSCentered(ystart, font_head,
3267 "for the initial DOS port");
3268 ystart += ystep_para;
3270 DrawTextSCentered(ystart, font_head,
3272 ystart += ystep_head;
3273 DrawTextSCentered(ystart, font_text,
3275 ystart += ystep_head;
3276 DrawTextSCentered(ystart, font_head,
3277 "for some additional toons");
3279 else if (screen_nr == 8)
3281 DrawTextSCentered(ystart, font_head,
3282 "And not to forget:");
3283 ystart += ystep_head;
3284 DrawTextSCentered(ystart, font_head,
3286 ystart += ystep_head;
3287 DrawTextSCentered(ystart, font_text,
3288 "All those who contributed");
3289 ystart += ystep_line;
3290 DrawTextSCentered(ystart, font_text,
3291 "levels to this game");
3292 ystart += ystep_line;
3293 DrawTextSCentered(ystart, font_text,
3297 DrawTextSCentered(ybottom, font_foot,
3298 "Press any key or button for next page");
3301 void DrawInfoScreen_Credits()
3303 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
3305 FadeMenuSoundsAndMusic();
3307 FadeOut(REDRAW_FIELD);
3309 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
3311 FadeIn(REDRAW_FIELD);
3314 void HandleInfoScreen_Credits(int button)
3316 static int screen_nr = 0;
3317 int num_screens = 9;
3319 if (button == MB_MENU_INITIALIZE)
3323 // DrawInfoScreen_CreditsScreen(screen_nr);
3326 if (button == MB_MENU_LEAVE)
3328 PlaySound(SND_MENU_ITEM_SELECTING);
3330 info_mode = INFO_MODE_MAIN;
3335 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3337 if (button != MB_MENU_INITIALIZE)
3339 PlaySound(SND_MENU_ITEM_SELECTING);
3344 if (screen_nr >= num_screens)
3346 FadeMenuSoundsAndMusic();
3348 info_mode = INFO_MODE_MAIN;
3355 FadeSetNextScreen();
3357 if (button != MB_MENU_INITIALIZE)
3358 FadeOut(REDRAW_FIELD);
3360 DrawInfoScreen_CreditsScreen(screen_nr);
3362 if (button != MB_MENU_INITIALIZE)
3363 FadeIn(REDRAW_FIELD);
3367 PlayMenuSoundIfLoop();
3371 void DrawInfoScreen_Program()
3373 int font_title = MENU_INFO_FONT_TITLE;
3374 int font_head = MENU_INFO_FONT_HEAD;
3375 int font_text = MENU_INFO_FONT_TEXT;
3376 int font_foot = MENU_INFO_FONT_FOOT;
3377 int spacing_title = menu.headline1_spacing_info[info_mode];
3378 int spacing_head = menu.headline2_spacing_info[info_mode];
3379 int spacing_para = menu.paragraph_spacing_info[info_mode];
3380 int spacing_line = menu.line_spacing_info[info_mode];
3381 int ystep_title = getMenuTextStep(spacing_title, font_title);
3382 int ystep_head = getMenuTextStep(spacing_head, font_head);
3383 int ystep_para = getMenuTextStep(spacing_para, font_text);
3384 int ystep_line = getMenuTextStep(spacing_line, font_text);
3385 int ystart = mSY - SY + 100;
3386 int ybottom = mSY - SY + SYSIZE - 20;
3388 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
3390 FadeOut(REDRAW_FIELD);
3395 DrawTextSCentered(ystart, font_title, "Program Information:");
3396 ystart += ystep_title;
3398 DrawTextSCentered(ystart, font_head,
3399 "This game is Freeware!");
3400 ystart += ystep_head;
3401 DrawTextSCentered(ystart, font_head,
3402 "If you like it, send e-mail to:");
3403 ystart += ystep_head;
3404 DrawTextSCentered(ystart, font_text,
3405 setup.internal.program_email);
3406 ystart += ystep_para;
3408 DrawTextSCentered(ystart, font_head,
3409 "More information and levels:");
3410 ystart += ystep_head;
3411 DrawTextSCentered(ystart, font_text,
3412 setup.internal.program_website);
3413 ystart += ystep_para;
3415 DrawTextSCentered(ystart, font_head,
3416 "If you have created new levels,");
3417 ystart += ystep_line;
3418 DrawTextSCentered(ystart, font_head,
3419 "send them to me to include them!");
3420 ystart += ystep_head;
3421 DrawTextSCentered(ystart, font_head,
3424 DrawTextSCentered(ybottom, font_foot,
3425 "Press any key or button for info menu");
3427 FadeIn(REDRAW_FIELD);
3430 void HandleInfoScreen_Program(int button)
3432 if (button == MB_MENU_LEAVE)
3434 PlaySound(SND_MENU_ITEM_SELECTING);
3436 info_mode = INFO_MODE_MAIN;
3441 else if (button == MB_MENU_CHOICE)
3443 PlaySound(SND_MENU_ITEM_SELECTING);
3445 FadeMenuSoundsAndMusic();
3447 info_mode = INFO_MODE_MAIN;
3452 PlayMenuSoundIfLoop();
3456 void DrawInfoScreen_Version()
3458 int font_title = MENU_INFO_FONT_TITLE;
3459 int font_head = MENU_INFO_FONT_HEAD;
3460 int font_text = MENU_INFO_FONT_TEXT;
3461 int font_foot = MENU_INFO_FONT_FOOT;
3462 int spacing_title = menu.headline1_spacing_info[info_mode];
3463 int spacing_head = menu.headline2_spacing_info[info_mode];
3464 int spacing_para = menu.paragraph_spacing_info[info_mode];
3465 int spacing_line = menu.line_spacing_info[info_mode];
3466 int xstep = getFontWidth(font_text);
3467 int ystep_title = getMenuTextStep(spacing_title, font_title);
3468 int ystep_head = getMenuTextStep(spacing_head, font_head);
3469 int ystep_para = getMenuTextStep(spacing_para, font_text);
3470 int ystep_line = getMenuTextStep(spacing_line, font_text);
3471 int ystart = mSY - SY + 100;
3472 int ybottom = mSY - SY + SYSIZE - 20;
3473 int xstart1 = mSX - SX + 2 * xstep;
3474 int xstart2 = mSX - SX + 18 * xstep;
3475 int xstart3 = mSX - SX + 28 * xstep;
3476 SDL_version sdl_version_compiled;
3477 const SDL_version *sdl_version_linked;
3478 int driver_name_len = 10;
3479 #if defined(TARGET_SDL2)
3480 SDL_version sdl_version_linked_ext;
3481 const char *driver_name = NULL;
3483 char driver_name[driver_name_len];
3486 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION);
3488 FadeOut(REDRAW_FIELD);
3493 DrawTextSCentered(ystart, font_title, "Version Information:");
3494 ystart += ystep_title;
3496 DrawTextF(xstart1, ystart, font_head, "Name");
3497 DrawTextF(xstart2, ystart, font_text, getProgramTitleString());
3498 ystart += ystep_line;
3500 if (!strEqual(getProgramVersionString(), getProgramRealVersionString()))
3502 DrawTextF(xstart1, ystart, font_head, "Version (fake)");
3503 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3504 ystart += ystep_line;
3506 DrawTextF(xstart1, ystart, font_head, "Version (real)");
3507 DrawTextF(xstart2, ystart, font_text, getProgramRealVersionString());
3508 ystart += ystep_line;
3512 DrawTextF(xstart1, ystart, font_head, "Version");
3513 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3514 ystart += ystep_line;
3517 DrawTextF(xstart1, ystart, font_head, "Platform");
3518 DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING);
3519 ystart += ystep_line;
3521 DrawTextF(xstart1, ystart, font_head, "Target");
3522 DrawTextF(xstart2, ystart, font_text, TARGET_STRING);
3523 ystart += ystep_line;
3525 DrawTextF(xstart1, ystart, font_head, "Source date");
3526 DrawTextF(xstart2, ystart, font_text, getSourceDateString());
3527 ystart += ystep_para;
3529 DrawTextF(xstart1, ystart, font_head, "Library");
3530 DrawTextF(xstart2, ystart, font_head, "compiled");
3531 DrawTextF(xstart3, ystart, font_head, "linked");
3532 ystart += ystep_head;
3534 SDL_VERSION(&sdl_version_compiled);
3535 #if defined(TARGET_SDL2)
3536 SDL_GetVersion(&sdl_version_linked_ext);
3537 sdl_version_linked = &sdl_version_linked_ext;
3539 sdl_version_linked = SDL_Linked_Version();
3542 DrawTextF(xstart1, ystart, font_text, "SDL");
3543 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3544 sdl_version_compiled.major,
3545 sdl_version_compiled.minor,
3546 sdl_version_compiled.patch);
3547 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3548 sdl_version_linked->major,
3549 sdl_version_linked->minor,
3550 sdl_version_linked->patch);
3551 ystart += ystep_line;
3553 SDL_IMAGE_VERSION(&sdl_version_compiled);
3554 sdl_version_linked = IMG_Linked_Version();
3556 DrawTextF(xstart1, ystart, font_text, "SDL_image");
3557 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3558 sdl_version_compiled.major,
3559 sdl_version_compiled.minor,
3560 sdl_version_compiled.patch);
3561 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3562 sdl_version_linked->major,
3563 sdl_version_linked->minor,
3564 sdl_version_linked->patch);
3565 ystart += ystep_line;
3567 SDL_MIXER_VERSION(&sdl_version_compiled);
3568 sdl_version_linked = Mix_Linked_Version();
3570 DrawTextF(xstart1, ystart, font_text, "SDL_mixer");
3571 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3572 sdl_version_compiled.major,
3573 sdl_version_compiled.minor,
3574 sdl_version_compiled.patch);
3575 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3576 sdl_version_linked->major,
3577 sdl_version_linked->minor,
3578 sdl_version_linked->patch);
3579 ystart += ystep_line;
3581 SDL_NET_VERSION(&sdl_version_compiled);
3582 sdl_version_linked = SDLNet_Linked_Version();
3584 DrawTextF(xstart1, ystart, font_text, "SDL_net");
3585 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3586 sdl_version_compiled.major,
3587 sdl_version_compiled.minor,
3588 sdl_version_compiled.patch);
3589 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3590 sdl_version_linked->major,
3591 sdl_version_linked->minor,
3592 sdl_version_linked->patch);
3593 ystart += ystep_para;
3595 DrawTextF(xstart1, ystart, font_head, "Driver");
3596 DrawTextF(xstart2, ystart, font_head, "Requested");
3597 DrawTextF(xstart3, ystart, font_head, "Used");
3598 ystart += ystep_head;
3600 #if defined(TARGET_SDL2)
3601 driver_name = getStringCopyNStatic(SDL_GetVideoDriver(0), driver_name_len);
3603 SDL_VideoDriverName(driver_name, driver_name_len);
3606 DrawTextF(xstart1, ystart, font_text, "SDL_VideoDriver");
3607 DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_videodriver);
3608 DrawTextF(xstart3, ystart, font_text, "%s", driver_name);
3609 ystart += ystep_line;
3611 #if defined(TARGET_SDL2)
3612 driver_name = getStringCopyNStatic(SDL_GetAudioDriver(0), driver_name_len);
3614 SDL_AudioDriverName(driver_name, driver_name_len);
3617 DrawTextF(xstart1, ystart, font_text, "SDL_AudioDriver");
3618 DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_audiodriver);
3619 DrawTextF(xstart3, ystart, font_text, "%s", driver_name);
3621 DrawTextSCentered(ybottom, font_foot,
3622 "Press any key or button for info menu");
3624 FadeIn(REDRAW_FIELD);
3627 void HandleInfoScreen_Version(int button)
3629 if (button == MB_MENU_LEAVE)
3631 PlaySound(SND_MENU_ITEM_SELECTING);
3633 info_mode = INFO_MODE_MAIN;
3638 else if (button == MB_MENU_CHOICE)
3640 PlaySound(SND_MENU_ITEM_SELECTING);
3642 FadeMenuSoundsAndMusic();
3644 info_mode = INFO_MODE_MAIN;
3649 PlayMenuSoundIfLoop();
3653 void DrawInfoScreen_LevelSet()
3655 struct TitleMessageInfo *tmi = &readme;
3656 char *filename = getLevelSetInfoFilename();
3657 char *title = "Level Set Information:";
3658 int ystart = mSY - SY + 100;
3659 int ybottom = mSY - SY + SYSIZE - 20;
3661 if (filename == NULL)
3663 DrawInfoScreen_NotAvailable(title, "No information for this level set.");
3668 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
3670 FadeOut(REDRAW_FIELD);
3675 DrawTextSCentered(ystart, FONT_TEXT_1, title);
3677 /* if x position set to "-1", automatically determine by playfield width */
3679 tmi->x = SXSIZE / 2;
3681 /* if y position set to "-1", use static default value */
3685 /* if width set to "-1", automatically determine by playfield width */
3686 if (tmi->width == -1)
3687 tmi->width = SXSIZE - 2 * TILEX;
3689 /* if height set to "-1", automatically determine by playfield height */
3690 if (tmi->height == -1)
3691 tmi->height = SYSIZE - 20 - tmi->y - 10;
3693 /* if chars set to "-1", automatically determine by text and font width */
3694 if (tmi->chars == -1)
3695 tmi->chars = tmi->width / getFontWidth(tmi->font);
3697 tmi->width = tmi->chars * getFontWidth(tmi->font);
3699 /* if lines set to "-1", automatically determine by text and font height */
3700 if (tmi->lines == -1)
3701 tmi->lines = tmi->height / getFontHeight(tmi->font);
3703 tmi->height = tmi->lines * getFontHeight(tmi->font);
3705 DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi),
3706 filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
3707 tmi->autowrap, tmi->centered, tmi->parse_comments);
3709 DrawTextSCentered(ybottom, FONT_TEXT_4,
3710 "Press any key or button for info menu");
3712 FadeIn(REDRAW_FIELD);
3715 void HandleInfoScreen_LevelSet(int button)
3717 if (button == MB_MENU_LEAVE)
3719 PlaySound(SND_MENU_ITEM_SELECTING);
3721 info_mode = INFO_MODE_MAIN;
3726 else if (button == MB_MENU_CHOICE)
3728 PlaySound(SND_MENU_ITEM_SELECTING);
3730 FadeMenuSoundsAndMusic();
3732 info_mode = INFO_MODE_MAIN;
3737 PlayMenuSoundIfLoop();
3741 static void DrawInfoScreen()
3743 if (info_mode == INFO_MODE_TITLE)
3744 DrawInfoScreen_TitleScreen();
3745 else if (info_mode == INFO_MODE_ELEMENTS)
3746 DrawInfoScreen_Elements();
3747 else if (info_mode == INFO_MODE_MUSIC)
3748 DrawInfoScreen_Music();
3749 else if (info_mode == INFO_MODE_CREDITS)
3750 DrawInfoScreen_Credits();
3751 else if (info_mode == INFO_MODE_PROGRAM)
3752 DrawInfoScreen_Program();
3753 else if (info_mode == INFO_MODE_VERSION)
3754 DrawInfoScreen_Version();
3755 else if (info_mode == INFO_MODE_LEVELSET)
3756 DrawInfoScreen_LevelSet();
3758 DrawInfoScreen_Main();
3760 if (info_mode != INFO_MODE_MAIN &&
3761 info_mode != INFO_MODE_TITLE &&
3762 info_mode != INFO_MODE_MUSIC)
3763 PlayMenuSoundsAndMusic();
3766 void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
3768 if (info_mode == INFO_MODE_TITLE)
3769 HandleInfoScreen_TitleScreen(button);
3770 else if (info_mode == INFO_MODE_ELEMENTS)
3771 HandleInfoScreen_Elements(button);
3772 else if (info_mode == INFO_MODE_MUSIC)
3773 HandleInfoScreen_Music(button);
3774 else if (info_mode == INFO_MODE_CREDITS)
3775 HandleInfoScreen_Credits(button);
3776 else if (info_mode == INFO_MODE_PROGRAM)
3777 HandleInfoScreen_Program(button);
3778 else if (info_mode == INFO_MODE_VERSION)
3779 HandleInfoScreen_Version(button);
3780 else if (info_mode == INFO_MODE_LEVELSET)
3781 HandleInfoScreen_LevelSet(button);
3783 HandleInfoScreen_Main(mx, my, dx, dy, button);
3787 /* ========================================================================= */
3788 /* type name functions */
3789 /* ========================================================================= */
3791 void HandleTypeName(int newxpos, Key key)
3793 static char last_player_name[MAX_PLAYER_NAME_LEN + 1];
3794 struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME);
3795 struct TextPosInfo *pos = mci->pos_input;
3796 int startx = mSX + ALIGNED_TEXT_XPOS(pos);
3797 int starty = mSY + ALIGNED_TEXT_YPOS(pos);
3798 static int xpos = 0;
3799 int font_nr = pos->font;
3800 int font_active_nr = FONT_ACTIVE(font_nr);
3801 int font_width = getFontWidth(font_active_nr);
3802 char key_char = getValidConfigValueChar(getCharFromKey(key));
3803 boolean is_valid_key_char = (key_char != 0 && (key_char != ' ' || xpos > 0));
3804 boolean is_active = TRUE;
3806 DrawBackgroundForFont(startx,starty, pos->width, pos->height, font_active_nr);
3810 strcpy(last_player_name, setup.player_name);
3814 StartTextInput(startx, starty, pos->width, pos->height);
3816 else if (is_valid_key_char && xpos < MAX_PLAYER_NAME_LEN)
3818 setup.player_name[xpos] = key_char;
3819 setup.player_name[xpos + 1] = 0;
3823 else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
3827 setup.player_name[xpos] = 0;
3829 else if (key == KSYM_Return && xpos > 0)
3835 SetGameStatus(GAME_MODE_MAIN);
3837 else if (key == KSYM_Escape)
3839 strcpy(setup.player_name, last_player_name);
3843 SetGameStatus(GAME_MODE_MAIN);
3848 pos->width = (strlen(setup.player_name) + 1) * font_width;
3849 startx = mSX + ALIGNED_TEXT_XPOS(pos);
3851 DrawText(startx, starty, setup.player_name, font_active_nr);
3852 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
3856 pos->width = strlen(setup.player_name) * font_width;
3857 startx = mSX + ALIGNED_TEXT_XPOS(pos);
3859 DrawText(startx, starty, setup.player_name, font_nr);
3866 /* ========================================================================= */
3867 /* tree menu functions */
3868 /* ========================================================================= */
3870 static void DrawChooseTree(TreeInfo **ti_ptr)
3872 int fade_mask = REDRAW_FIELD;
3874 if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
3875 fade_mask = REDRAW_ALL;
3877 if (strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY))
3879 SetGameStatus(GAME_MODE_MAIN);
3888 FreeScreenGadgets();
3889 CreateScreenGadgets();
3893 /* needed if different viewport properties defined for choosing level (set) */
3894 ChangeViewportPropertiesIfNeeded();
3896 if (game_status == GAME_MODE_LEVELNR)
3897 SetMainBackgroundImage(IMG_BACKGROUND_LEVELNR);
3898 else if (game_status == GAME_MODE_LEVELS)
3899 SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
3903 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
3905 HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
3906 MapScreenTreeGadgets(*ti_ptr);
3908 DrawMaskedBorder(fade_mask);
3913 static void drawChooseTreeList(int first_entry, int num_page_entries,
3917 char *title_string = NULL;
3918 int yoffset_sets = MENU_TITLE1_YPOS;
3919 int yoffset_setup = 16;
3920 int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ||
3921 ti->type == TREE_TYPE_LEVEL_NR ? yoffset_sets : yoffset_setup);
3923 title_string = ti->infotext;
3925 DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
3927 clearMenuListArea();
3929 for (i = 0; i < num_page_entries; i++)
3931 TreeInfo *node, *node_first;
3932 int entry_pos = first_entry + i;
3933 int xpos = MENU_SCREEN_START_XPOS;
3934 int ypos = MENU_SCREEN_START_YPOS + i;
3935 int startx = mSX + xpos * 32;
3936 int starty = mSY + ypos * 32;
3937 int font_nr = FONT_TEXT_1;
3938 int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
3939 int startx_text = startx + font_xoffset;
3940 int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
3941 int text_size = startx_scrollbar - startx_text;
3942 int max_buffer_len = text_size / getFontWidth(font_nr);
3943 char buffer[max_buffer_len + 1];
3945 node_first = getTreeInfoFirstGroupEntry(ti);
3946 node = getTreeInfoFromPos(node_first, entry_pos);
3948 strncpy(buffer, node->name, max_buffer_len);
3949 buffer[max_buffer_len] = '\0';
3951 DrawText(startx, starty, buffer, font_nr + node->color);
3953 if (node->parent_link)
3954 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
3955 else if (node->level_group)
3956 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
3958 initCursor(i, IMG_MENU_BUTTON);
3961 redraw_mask |= REDRAW_FIELD;
3964 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
3966 TreeInfo *node, *node_first;
3967 int x, last_redraw_mask = redraw_mask;
3968 int ypos = MENU_TITLE2_YPOS;
3969 int font_nr = FONT_TITLE_2;
3971 if (ti->type == TREE_TYPE_LEVEL_NR)
3972 DrawTextFCentered(ypos, font_nr, leveldir_current->name);
3974 if (ti->type != TREE_TYPE_LEVEL_DIR)
3977 node_first = getTreeInfoFirstGroupEntry(ti);
3978 node = getTreeInfoFromPos(node_first, entry_pos);
3980 DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr);
3982 if (node->parent_link)
3983 DrawTextFCentered(ypos, font_nr, "leave \"%s\"",
3984 node->node_parent->name);
3985 else if (node->level_group)
3986 DrawTextFCentered(ypos, font_nr, "enter \"%s\"",
3988 else if (ti->type == TREE_TYPE_LEVEL_DIR)
3989 DrawTextFCentered(ypos, font_nr, "%3d %s (%s)",
3990 node->levels, (node->levels > 1 ? "levels" : "level"),
3993 /* let BackToFront() redraw only what is needed */
3994 redraw_mask = last_redraw_mask;
3995 for (x = 0; x < SCR_FIELDX; x++)
3996 MarkTileDirty(x, 1);
3999 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
4002 TreeInfo *ti = *ti_ptr;
4004 int y = ti->cl_cursor;
4005 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
4006 int num_entries = numTreeInfoInGroup(ti);
4007 int num_page_entries;
4008 boolean position_set_by_scrollbar = (dx == 999);
4010 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
4011 num_page_entries = num_entries;
4013 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
4015 if (button == MB_MENU_INITIALIZE)
4017 int num_entries = numTreeInfoInGroup(ti);
4018 int entry_pos = posTreeInfo(ti);
4020 if (ti->cl_first == -1)
4022 /* only on initialization */
4023 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
4024 ti->cl_cursor = entry_pos - ti->cl_first;
4026 else if (ti->cl_cursor >= num_page_entries ||
4027 (num_entries > num_page_entries &&
4028 num_entries - ti->cl_first < num_page_entries))
4030 /* only after change of list size (by custom graphic configuration) */
4031 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
4032 ti->cl_cursor = entry_pos - ti->cl_first;
4035 if (position_set_by_scrollbar)
4038 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
4041 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
4042 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
4043 drawChooseTreeCursor(ti->cl_cursor, TRUE);
4047 else if (button == MB_MENU_LEAVE)
4051 PlaySound(SND_MENU_ITEM_SELECTING);
4053 if (ti->node_parent)
4055 *ti_ptr = ti->node_parent;
4056 DrawChooseTree(ti_ptr);
4058 else if (game_status == GAME_MODE_SETUP)
4060 if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
4061 setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
4062 setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
4064 else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
4065 setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
4066 setup_mode == SETUP_MODE_CHOOSE_RENDERING)
4067 execSetupGraphics();
4068 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
4069 setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
4070 setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
4072 else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL ||
4073 setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE ||
4074 setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE)
4081 if (game_status == GAME_MODE_LEVELNR)
4083 int new_level_nr = atoi(level_number_current->identifier);
4085 HandleMainMenu_SelectLevel(0, 0, new_level_nr);
4088 SetGameStatus(GAME_MODE_MAIN);
4096 if (mx || my) /* mouse input */
4098 x = (mx - mSX) / 32;
4099 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
4101 else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */
4103 /* move cursor instead of scrolling when already at start/end of list */
4104 if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
4106 else if (dy == +1 * SCROLL_LINE &&
4107 ti->cl_first + num_page_entries == num_entries)
4110 /* handle scrolling screen one line or page */
4111 if (ti->cl_cursor + dy < 0 ||
4112 ti->cl_cursor + dy > num_page_entries - 1)
4114 boolean redraw = FALSE;
4116 if (ABS(dy) == SCROLL_PAGE)
4117 step = num_page_entries - 1;
4119 if (dy < 0 && ti->cl_first > 0)
4121 /* scroll page/line up */
4123 ti->cl_first -= step;
4124 if (ti->cl_first < 0)
4129 else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
4131 /* scroll page/line down */
4133 ti->cl_first += step;
4134 if (ti->cl_first + num_page_entries > num_entries)
4135 ti->cl_first = MAX(0, num_entries - num_page_entries);
4142 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
4143 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
4144 drawChooseTreeCursor(ti->cl_cursor, TRUE);
4146 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
4153 /* handle moving cursor one line */
4154 y = ti->cl_cursor + dy;
4159 TreeInfo *node_first, *node_cursor;
4160 int entry_pos = ti->cl_first + y;
4162 node_first = getTreeInfoFirstGroupEntry(ti);
4163 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
4165 if (node_cursor->node_group)
4169 PlaySound(SND_MENU_ITEM_SELECTING);
4171 node_cursor->cl_first = ti->cl_first;
4172 node_cursor->cl_cursor = ti->cl_cursor;
4173 *ti_ptr = node_cursor->node_group;
4174 DrawChooseTree(ti_ptr);
4179 else if (dx == -1 && ti->node_parent)
4183 PlaySound(SND_MENU_ITEM_SELECTING);
4185 *ti_ptr = ti->node_parent;
4186 DrawChooseTree(ti_ptr);
4191 if (!anyScrollbarGadgetActive() &&
4192 IN_VIS_MENU(x, y) &&
4193 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
4194 y >= 0 && y < num_page_entries)
4198 if (y != ti->cl_cursor)
4200 PlaySound(SND_MENU_ITEM_ACTIVATING);
4202 drawChooseTreeCursor(ti->cl_cursor, FALSE);
4203 drawChooseTreeCursor(y, TRUE);
4204 drawChooseTreeInfo(ti->cl_first + y, ti);
4210 if (game_status == GAME_MODE_SETUP)
4212 if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
4213 setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
4214 setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
4216 else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
4217 setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
4218 setup_mode == SETUP_MODE_CHOOSE_RENDERING)
4219 execSetupGraphics();
4220 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
4221 setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
4222 setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
4224 else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL ||
4225 setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE ||
4226 setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE)
4235 TreeInfo *node_first, *node_cursor;
4236 int entry_pos = ti->cl_first + y;
4238 PlaySound(SND_MENU_ITEM_SELECTING);
4240 node_first = getTreeInfoFirstGroupEntry(ti);
4241 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
4243 if (node_cursor->node_group)
4247 node_cursor->cl_first = ti->cl_first;
4248 node_cursor->cl_cursor = ti->cl_cursor;
4249 *ti_ptr = node_cursor->node_group;
4250 DrawChooseTree(ti_ptr);
4252 else if (node_cursor->parent_link)
4256 *ti_ptr = node_cursor->node_parent;
4257 DrawChooseTree(ti_ptr);
4263 node_cursor->cl_first = ti->cl_first;
4264 node_cursor->cl_cursor = ti->cl_cursor;
4265 *ti_ptr = node_cursor;
4267 if (ti->type == TREE_TYPE_LEVEL_DIR)
4269 LoadLevelSetup_SeriesInfo();
4271 SaveLevelSetup_LastSeries();
4272 SaveLevelSetup_SeriesInfo();
4276 if (game_status == GAME_MODE_SETUP)
4278 if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
4279 setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
4280 setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
4282 else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
4283 setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
4284 setup_mode == SETUP_MODE_CHOOSE_RENDERING)
4285 execSetupGraphics();
4286 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
4287 setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
4288 setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
4290 else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL ||
4291 setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE ||
4292 setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE)
4299 if (game_status == GAME_MODE_LEVELNR)
4301 int new_level_nr = atoi(level_number_current->identifier);
4303 HandleMainMenu_SelectLevel(0, 0, new_level_nr);
4306 SetGameStatus(GAME_MODE_MAIN);
4315 void DrawChooseLevelSet()
4317 FadeMenuSoundsAndMusic();
4319 DrawChooseTree(&leveldir_current);
4321 PlayMenuSoundsAndMusic();
4324 void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button)
4326 HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
4329 void DrawChooseLevelNr()
4333 FadeMenuSoundsAndMusic();
4335 if (level_number != NULL)
4337 freeTreeInfo(level_number);
4339 level_number = NULL;
4342 for (i = leveldir_current->first_level; i <= leveldir_current->last_level;i++)
4344 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_LEVEL_NR);
4345 char identifier[32], name[32];
4348 /* temporarily load level info to get level name */
4349 LoadLevelInfoOnly(i);
4351 ti->node_top = &level_number;
4352 ti->sort_priority = 10000 + value;
4353 ti->color = (level.no_level_file ? FC_BLUE :
4354 LevelStats_getSolved(i) ? FC_GREEN :
4355 LevelStats_getPlayed(i) ? FC_YELLOW : FC_RED);
4357 snprintf(identifier, sizeof(identifier), "%d", value);
4358 snprintf(name, sizeof(name), "%03d: %s", value,
4359 (level.no_level_file ? "(no file)" : level.name));
4361 setString(&ti->identifier, identifier);
4362 setString(&ti->name, name);
4363 setString(&ti->name_sorting, name);
4365 pushTreeInfo(&level_number, ti);
4368 /* sort level number values to start with lowest level number */
4369 sortTreeInfo(&level_number);
4371 /* set current level number to current level number */
4372 level_number_current =
4373 getTreeInfoFromIdentifier(level_number, i_to_a(level_nr));
4375 /* if that also fails, set current level number to first available level */
4376 if (level_number_current == NULL)
4377 level_number_current = level_number;
4379 DrawChooseTree(&level_number_current);
4381 PlayMenuSoundsAndMusic();
4384 void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button)
4386 HandleChooseTree(mx, my, dx, dy, button, &level_number_current);
4389 void DrawHallOfFame(int highlight_position)
4391 int fade_mask = REDRAW_FIELD;
4393 if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
4394 fade_mask = REDRAW_ALL;
4397 FadeMenuSoundsAndMusic();
4399 /* (this is needed when called from GameEnd() after winning a game) */
4400 KeyboardAutoRepeatOn();
4402 /* (this is needed when called from GameEnd() after winning a game) */
4403 SetDrawDeactivationMask(REDRAW_NONE);
4404 SetDrawBackgroundMask(REDRAW_FIELD);
4406 if (highlight_position < 0)
4407 LoadScore(level_nr);
4409 SetAnimStatus(GAME_MODE_PSEUDO_SCORESNEW);
4411 FadeSetEnterScreen();
4415 /* needed if different viewport properties defined for scores */
4416 ChangeViewportPropertiesIfNeeded();
4418 PlayMenuSoundsAndMusic();
4420 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
4422 HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
4424 DrawMaskedBorder(fade_mask);
4429 static void drawHallOfFameList(int first_entry, int highlight_position)
4433 SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
4436 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
4437 DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
4438 "HighScores of Level %d", level_nr);
4440 for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
4442 int entry = first_entry + i;
4443 boolean active = (entry == highlight_position);
4444 int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
4445 int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
4446 int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
4447 int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
4448 int dxoff = getFontDrawOffsetX(font_nr1);
4449 int dx1 = 3 * getFontWidth(font_nr1);
4450 int dx2 = dx1 + getFontWidth(font_nr1);
4451 int dx3 = SXSIZE - 2 * (mSX - SX + dxoff) - 5 * getFontWidth(font_nr4);
4452 int num_dots = (dx3 - dx2) / getFontWidth(font_nr3);
4453 int sy = mSY + 64 + i * 32;
4455 DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
4456 DrawText(mSX + dx1, sy, ".", font_nr1);
4458 for (j = 0; j < num_dots; j++)
4459 DrawText(mSX + dx2 + j * getFontWidth(font_nr3), sy, ".", font_nr3);
4461 if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
4462 DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
4464 DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
4467 redraw_mask |= REDRAW_FIELD;
4470 void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
4472 static int first_entry = 0;
4473 static int highlight_position = 0;
4474 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
4476 if (button == MB_MENU_INITIALIZE)
4479 highlight_position = mx;
4480 drawHallOfFameList(first_entry, highlight_position);
4485 if (ABS(dy) == SCROLL_PAGE) /* handle scrolling one page */
4486 step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
4490 if (first_entry > 0)
4492 first_entry -= step;
4493 if (first_entry < 0)
4496 drawHallOfFameList(first_entry, highlight_position);
4501 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
4503 first_entry += step;
4504 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
4505 first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
4507 drawHallOfFameList(first_entry, highlight_position);
4510 else if (button == MB_MENU_LEAVE)
4512 PlaySound(SND_MENU_ITEM_SELECTING);
4514 FadeSound(SND_BACKGROUND_SCORES);
4516 SetGameStatus(GAME_MODE_MAIN);
4520 else if (button == MB_MENU_CHOICE)
4522 PlaySound(SND_MENU_ITEM_SELECTING);
4524 FadeSound(SND_BACKGROUND_SCORES);
4526 SetGameStatus(GAME_MODE_MAIN);
4531 if (game_status == GAME_MODE_SCORES)
4532 PlayMenuSoundIfLoop();
4536 /* ========================================================================= */
4537 /* setup screen functions */
4538 /* ========================================================================= */
4540 static struct TokenInfo *setup_info;
4541 static int num_setup_info; /* number of setup entries shown on screen */
4542 static int max_setup_info; /* total number of setup entries in list */
4544 static char *window_size_text;
4545 static char *scaling_type_text;
4546 static char *rendering_mode_text;
4547 static char *scroll_delay_text;
4548 static char *snapshot_mode_text;
4549 static char *game_speed_text;
4550 static char *graphics_set_name;
4551 static char *sounds_set_name;
4552 static char *music_set_name;
4553 static char *volume_simple_text;
4554 static char *volume_loops_text;
4555 static char *volume_music_text;
4556 static char *touch_controls_text;
4557 static char *move_distance_text;
4558 static char *drop_distance_text;
4560 static void execSetupMain()
4562 setup_mode = SETUP_MODE_MAIN;
4567 static void execSetupGame_setGameSpeeds()
4569 if (game_speeds == NULL)
4573 for (i = 0; game_speeds_list[i].value != -1; i++)
4575 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4576 char identifier[32], name[32];
4577 int value = game_speeds_list[i].value;
4578 char *text = game_speeds_list[i].text;
4580 ti->node_top = &game_speeds;
4581 ti->sort_priority = 10000 - value;
4583 sprintf(identifier, "%d", value);
4584 sprintf(name, "%s", text);
4586 setString(&ti->identifier, identifier);
4587 setString(&ti->name, name);
4588 setString(&ti->name_sorting, name);
4589 setString(&ti->infotext, STR_SETUP_CHOOSE_GAME_SPEED);
4591 pushTreeInfo(&game_speeds, ti);
4594 /* sort game speed values to start with slowest game speed */
4595 sortTreeInfo(&game_speeds);
4597 /* set current game speed to configured game speed value */
4598 game_speed_current =
4599 getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay));
4601 /* if that fails, set current game speed to reliable default value */
4602 if (game_speed_current == NULL)
4603 game_speed_current =
4604 getTreeInfoFromIdentifier(game_speeds, i_to_a(GAME_FRAME_DELAY));
4606 /* if that also fails, set current game speed to first available speed */
4607 if (game_speed_current == NULL)
4608 game_speed_current = game_speeds;
4611 setup.game_frame_delay = atoi(game_speed_current->identifier);
4613 /* needed for displaying game speed text instead of identifier */
4614 game_speed_text = game_speed_current->name;
4617 static void execSetupGame_setScrollDelays()
4619 if (scroll_delays == NULL)
4623 for (i = 0; scroll_delays_list[i].value != -1; i++)
4625 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4626 char identifier[32], name[32];
4627 int value = scroll_delays_list[i].value;
4628 char *text = scroll_delays_list[i].text;
4630 ti->node_top = &scroll_delays;
4631 ti->sort_priority = value;
4633 sprintf(identifier, "%d", value);
4634 sprintf(name, "%s", text);
4636 setString(&ti->identifier, identifier);
4637 setString(&ti->name, name);
4638 setString(&ti->name_sorting, name);
4639 setString(&ti->infotext, STR_SETUP_CHOOSE_SCROLL_DELAY);
4641 pushTreeInfo(&scroll_delays, ti);
4644 /* sort scroll delay values to start with lowest scroll delay value */
4645 sortTreeInfo(&scroll_delays);
4647 /* set current scroll delay value to configured scroll delay value */
4648 scroll_delay_current =
4649 getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value));
4651 /* if that fails, set current scroll delay to reliable default value */
4652 if (scroll_delay_current == NULL)
4653 scroll_delay_current =
4654 getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY));
4656 /* if that also fails, set current scroll delay to first available value */
4657 if (scroll_delay_current == NULL)
4658 scroll_delay_current = scroll_delays;
4661 setup.scroll_delay_value = atoi(scroll_delay_current->identifier);
4663 /* needed for displaying scroll delay text instead of identifier */
4664 scroll_delay_text = scroll_delay_current->name;
4667 static void execSetupGame_setSnapshotModes()
4669 if (snapshot_modes == NULL)
4673 for (i = 0; snapshot_modes_list[i].value != NULL; i++)
4675 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4676 char identifier[32], name[32];
4677 char *value = snapshot_modes_list[i].value;
4678 char *text = snapshot_modes_list[i].text;
4680 ti->node_top = &snapshot_modes;
4681 ti->sort_priority = i;
4683 sprintf(identifier, "%s", value);
4684 sprintf(name, "%s", text);
4686 setString(&ti->identifier, identifier);
4687 setString(&ti->name, name);
4688 setString(&ti->name_sorting, name);
4689 setString(&ti->infotext, STR_SETUP_CHOOSE_SNAPSHOT_MODE);
4691 pushTreeInfo(&snapshot_modes, ti);
4694 /* sort snapshot mode values to start with lowest snapshot mode value */
4695 sortTreeInfo(&snapshot_modes);
4697 /* set current snapshot mode value to configured snapshot mode value */
4698 snapshot_mode_current =
4699 getTreeInfoFromIdentifier(snapshot_modes, setup.engine_snapshot_mode);
4701 /* if that fails, set current snapshot mode to reliable default value */
4702 if (snapshot_mode_current == NULL)
4703 snapshot_mode_current =
4704 getTreeInfoFromIdentifier(snapshot_modes, STR_SNAPSHOT_MODE_DEFAULT);
4706 /* if that also fails, set current snapshot mode to first available value */
4707 if (snapshot_mode_current == NULL)
4708 snapshot_mode_current = snapshot_modes;
4711 setup.engine_snapshot_mode = snapshot_mode_current->identifier;
4713 /* needed for displaying snapshot mode text instead of identifier */
4714 snapshot_mode_text = snapshot_mode_current->name;
4717 static void execSetupGame()
4719 execSetupGame_setGameSpeeds();
4720 execSetupGame_setScrollDelays();
4721 execSetupGame_setSnapshotModes();
4723 setup_mode = SETUP_MODE_GAME;
4728 static void execSetupChooseGameSpeed()
4730 setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED;
4735 static void execSetupChooseScrollDelay()
4737 setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY;
4742 static void execSetupChooseSnapshotMode()
4744 setup_mode = SETUP_MODE_CHOOSE_SNAPSHOT_MODE;
4749 static void execSetupEditor()
4751 setup_mode = SETUP_MODE_EDITOR;
4756 static void execSetupGraphics_setWindowSizes(boolean update_list)
4758 if (window_sizes != NULL && update_list)
4760 freeTreeInfo(window_sizes);
4762 window_sizes = NULL;
4765 if (window_sizes == NULL)
4767 boolean current_window_size_found = FALSE;
4770 for (i = 0; window_sizes_list[i].value != -1; i++)
4772 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4773 char identifier[32], name[32];
4774 int value = window_sizes_list[i].value;
4775 char *text = window_sizes_list[i].text;
4777 ti->node_top = &window_sizes;
4778 ti->sort_priority = value;
4780 sprintf(identifier, "%d", value);
4781 sprintf(name, "%s", text);
4783 setString(&ti->identifier, identifier);
4784 setString(&ti->name, name);
4785 setString(&ti->name_sorting, name);
4786 setString(&ti->infotext, STR_SETUP_CHOOSE_WINDOW_SIZE);
4788 pushTreeInfo(&window_sizes, ti);
4790 if (value == setup.window_scaling_percent)
4791 current_window_size_found = TRUE;
4794 if (!current_window_size_found)
4796 // add entry for non-preset window scaling value
4798 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4799 char identifier[32], name[32];
4800 int value = setup.window_scaling_percent;
4802 ti->node_top = &window_sizes;
4803 ti->sort_priority = value;
4805 sprintf(identifier, "%d", value);
4806 sprintf(name, "%d %% (Current)", value);
4808 setString(&ti->identifier, identifier);
4809 setString(&ti->name, name);
4810 setString(&ti->name_sorting, name);
4811 setString(&ti->infotext, STR_SETUP_CHOOSE_WINDOW_SIZE);
4813 pushTreeInfo(&window_sizes, ti);
4816 /* sort window size values to start with lowest window size value */
4817 sortTreeInfo(&window_sizes);
4819 /* set current window size value to configured window size value */
4820 window_size_current =
4821 getTreeInfoFromIdentifier(window_sizes,
4822 i_to_a(setup.window_scaling_percent));
4824 /* if that fails, set current window size to reliable default value */
4825 if (window_size_current == NULL)
4826 window_size_current =
4827 getTreeInfoFromIdentifier(window_sizes,
4828 i_to_a(STD_WINDOW_SCALING_PERCENT));
4830 /* if that also fails, set current window size to first available value */
4831 if (window_size_current == NULL)
4832 window_size_current = window_sizes;
4835 setup.window_scaling_percent = atoi(window_size_current->identifier);
4837 /* needed for displaying window size text instead of identifier */
4838 window_size_text = window_size_current->name;
4841 static void execSetupGraphics_setScalingTypes()
4843 if (scaling_types == NULL)
4847 for (i = 0; scaling_types_list[i].value != NULL; i++)
4849 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4850 char identifier[32], name[32];
4851 char *value = scaling_types_list[i].value;
4852 char *text = scaling_types_list[i].text;
4854 ti->node_top = &scaling_types;
4855 ti->sort_priority = i;
4857 sprintf(identifier, "%s", value);
4858 sprintf(name, "%s", text);
4860 setString(&ti->identifier, identifier);
4861 setString(&ti->name, name);
4862 setString(&ti->name_sorting, name);
4863 setString(&ti->infotext, STR_SETUP_CHOOSE_SCALING_TYPE);
4865 pushTreeInfo(&scaling_types, ti);
4868 /* sort scaling type values to start with lowest scaling type value */
4869 sortTreeInfo(&scaling_types);
4871 /* set current scaling type value to configured scaling type value */
4872 scaling_type_current =
4873 getTreeInfoFromIdentifier(scaling_types, setup.window_scaling_quality);
4875 /* if that fails, set current scaling type to reliable default value */
4876 if (scaling_type_current == NULL)
4877 scaling_type_current =
4878 getTreeInfoFromIdentifier(scaling_types, SCALING_QUALITY_DEFAULT);
4880 /* if that also fails, set current scaling type to first available value */
4881 if (scaling_type_current == NULL)
4882 scaling_type_current = scaling_types;
4885 setup.window_scaling_quality = scaling_type_current->identifier;
4887 /* needed for displaying scaling type text instead of identifier */
4888 scaling_type_text = scaling_type_current->name;
4891 static void execSetupGraphics_setRenderingModes()
4893 if (rendering_modes == NULL)
4897 for (i = 0; rendering_modes_list[i].value != NULL; i++)
4899 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4900 char identifier[32], name[32];
4901 char *value = rendering_modes_list[i].value;
4902 char *text = rendering_modes_list[i].text;
4904 ti->node_top = &rendering_modes;
4905 ti->sort_priority = i;
4907 sprintf(identifier, "%s", value);
4908 sprintf(name, "%s", text);
4910 setString(&ti->identifier, identifier);
4911 setString(&ti->name, name);
4912 setString(&ti->name_sorting, name);
4913 setString(&ti->infotext, STR_SETUP_CHOOSE_RENDERING);
4915 pushTreeInfo(&rendering_modes, ti);
4918 /* sort rendering mode values to start with lowest rendering mode value */
4919 sortTreeInfo(&rendering_modes);
4921 /* set current rendering mode value to configured rendering mode value */
4922 rendering_mode_current =
4923 getTreeInfoFromIdentifier(rendering_modes, setup.screen_rendering_mode);
4925 /* if that fails, set current rendering mode to reliable default value */
4926 if (rendering_mode_current == NULL)
4927 rendering_mode_current =
4928 getTreeInfoFromIdentifier(rendering_modes,
4929 STR_SPECIAL_RENDERING_DEFAULT);
4931 /* if that also fails, set current rendering mode to first available one */
4932 if (rendering_mode_current == NULL)
4933 rendering_mode_current = rendering_modes;
4936 setup.screen_rendering_mode = rendering_mode_current->identifier;
4938 /* needed for displaying rendering mode text instead of identifier */
4939 rendering_mode_text = rendering_mode_current->name;
4942 static void execSetupGraphics()
4944 // update "setup.window_scaling_percent" from list selection
4945 // (in this case, window scaling was changed on setup screen)
4946 if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
4947 execSetupGraphics_setWindowSizes(FALSE);
4949 // update list selection from "setup.window_scaling_percent"
4950 // (window scaling may have changed by resizing the window)
4951 execSetupGraphics_setWindowSizes(TRUE);
4953 execSetupGraphics_setScalingTypes();
4954 execSetupGraphics_setRenderingModes();
4956 setup_mode = SETUP_MODE_GRAPHICS;
4960 #if defined(TARGET_SDL2)
4961 // window scaling may have changed at this point
4962 ToggleFullscreenOrChangeWindowScalingIfNeeded();
4964 // window scaling quality may have changed at this point
4965 if (!strEqual(setup.window_scaling_quality, video.window_scaling_quality))
4966 SDLSetWindowScalingQuality(setup.window_scaling_quality);
4968 // screen rendering mode may have changed at this point
4969 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
4973 #if defined(TARGET_SDL2) && !defined(PLATFORM_ANDROID)
4974 static void execSetupChooseWindowSize()
4976 setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE;
4981 static void execSetupChooseScalingType()
4983 setup_mode = SETUP_MODE_CHOOSE_SCALING_TYPE;
4988 static void execSetupChooseRenderingMode()
4990 setup_mode = SETUP_MODE_CHOOSE_RENDERING;
4996 static void execSetupChooseVolumeSimple()
4998 setup_mode = SETUP_MODE_CHOOSE_VOLUME_SIMPLE;
5003 static void execSetupChooseVolumeLoops()
5005 setup_mode = SETUP_MODE_CHOOSE_VOLUME_LOOPS;
5010 static void execSetupChooseVolumeMusic()
5012 setup_mode = SETUP_MODE_CHOOSE_VOLUME_MUSIC;
5017 static void execSetupSound()
5019 if (volumes_simple == NULL)
5021 boolean current_volume_simple_found = FALSE;
5024 for (i = 0; volumes_list[i].value != -1; i++)
5026 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5027 char identifier[32], name[32];
5028 int value = volumes_list[i].value;
5029 char *text = volumes_list[i].text;
5031 ti->node_top = &volumes_simple;
5032 ti->sort_priority = value;
5034 sprintf(identifier, "%d", value);
5035 sprintf(name, "%s", text);
5037 setString(&ti->identifier, identifier);
5038 setString(&ti->name, name);
5039 setString(&ti->name_sorting, name);
5040 setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_SIMPLE);
5042 pushTreeInfo(&volumes_simple, ti);
5044 if (value == setup.volume_simple)
5045 current_volume_simple_found = TRUE;
5048 if (!current_volume_simple_found)
5050 // add entry for non-preset volume value
5052 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5053 char identifier[32], name[32];
5054 int value = setup.volume_simple;
5056 ti->node_top = &volumes_simple;
5057 ti->sort_priority = value;
5059 sprintf(identifier, "%d", value);
5060 sprintf(name, "%d %% (Current)", value);
5062 setString(&ti->identifier, identifier);
5063 setString(&ti->name, name);
5064 setString(&ti->name_sorting, name);
5065 setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_SIMPLE);
5067 pushTreeInfo(&volumes_simple, ti);
5070 /* sort volume values to start with lowest volume value */
5071 sortTreeInfo(&volumes_simple);
5073 /* set current volume value to configured volume value */
5074 volume_simple_current =
5075 getTreeInfoFromIdentifier(volumes_simple,i_to_a(setup.volume_simple));
5077 /* if that fails, set current volume to reliable default value */
5078 if (volume_simple_current == NULL)
5079 volume_simple_current =
5080 getTreeInfoFromIdentifier(volumes_simple, i_to_a(100));
5082 /* if that also fails, set current volume to first available value */
5083 if (volume_simple_current == NULL)
5084 volume_simple_current = volumes_simple;
5087 if (volumes_loops == NULL)
5089 boolean current_volume_loops_found = FALSE;
5092 for (i = 0; volumes_list[i].value != -1; i++)
5094 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5095 char identifier[32], name[32];
5096 int value = volumes_list[i].value;
5097 char *text = volumes_list[i].text;
5099 ti->node_top = &volumes_loops;
5100 ti->sort_priority = value;
5102 sprintf(identifier, "%d", value);
5103 sprintf(name, "%s", text);
5105 setString(&ti->identifier, identifier);
5106 setString(&ti->name, name);
5107 setString(&ti->name_sorting, name);
5108 setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_LOOPS);
5110 pushTreeInfo(&volumes_loops, ti);
5112 if (value == setup.volume_loops)
5113 current_volume_loops_found = TRUE;
5116 if (!current_volume_loops_found)
5118 // add entry for non-preset volume value
5120 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5121 char identifier[32], name[32];
5122 int value = setup.volume_loops;
5124 ti->node_top = &volumes_loops;
5125 ti->sort_priority = value;
5127 sprintf(identifier, "%d", value);
5128 sprintf(name, "%d %% (Current)", value);
5130 setString(&ti->identifier, identifier);
5131 setString(&ti->name, name);
5132 setString(&ti->name_sorting, name);
5133 setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_LOOPS);
5135 pushTreeInfo(&volumes_loops, ti);
5138 /* sort volume values to start with lowest volume value */
5139 sortTreeInfo(&volumes_loops);
5141 /* set current volume value to configured volume value */
5142 volume_loops_current =
5143 getTreeInfoFromIdentifier(volumes_loops,i_to_a(setup.volume_loops));
5145 /* if that fails, set current volume to reliable default value */
5146 if (volume_loops_current == NULL)
5147 volume_loops_current =
5148 getTreeInfoFromIdentifier(volumes_loops, i_to_a(100));
5150 /* if that also fails, set current volume to first available value */
5151 if (volume_loops_current == NULL)
5152 volume_loops_current = volumes_loops;
5155 if (volumes_music == NULL)
5157 boolean current_volume_music_found = FALSE;
5160 for (i = 0; volumes_list[i].value != -1; i++)
5162 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5163 char identifier[32], name[32];
5164 int value = volumes_list[i].value;
5165 char *text = volumes_list[i].text;
5167 ti->node_top = &volumes_music;
5168 ti->sort_priority = value;
5170 sprintf(identifier, "%d", value);
5171 sprintf(name, "%s", text);
5173 setString(&ti->identifier, identifier);
5174 setString(&ti->name, name);
5175 setString(&ti->name_sorting, name);
5176 setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_MUSIC);
5178 pushTreeInfo(&volumes_music, ti);
5180 if (value == setup.volume_music)
5181 current_volume_music_found = TRUE;
5184 if (!current_volume_music_found)
5186 // add entry for non-preset volume value
5188 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5189 char identifier[32], name[32];
5190 int value = setup.volume_music;
5192 ti->node_top = &volumes_music;
5193 ti->sort_priority = value;
5195 sprintf(identifier, "%d", value);
5196 sprintf(name, "%d %% (Current)", value);
5198 setString(&ti->identifier, identifier);
5199 setString(&ti->name, name);
5200 setString(&ti->name_sorting, name);
5201 setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_MUSIC);
5203 pushTreeInfo(&volumes_music, ti);
5206 /* sort volume values to start with lowest volume value */
5207 sortTreeInfo(&volumes_music);
5209 /* set current volume value to configured volume value */
5210 volume_music_current =
5211 getTreeInfoFromIdentifier(volumes_music,i_to_a(setup.volume_music));
5213 /* if that fails, set current volume to reliable default value */
5214 if (volume_music_current == NULL)
5215 volume_music_current =
5216 getTreeInfoFromIdentifier(volumes_music, i_to_a(100));
5218 /* if that also fails, set current volume to first available value */
5219 if (volume_music_current == NULL)
5220 volume_music_current = volumes_music;
5223 setup.volume_simple = atoi(volume_simple_current->identifier);
5224 setup.volume_loops = atoi(volume_loops_current->identifier);
5225 setup.volume_music = atoi(volume_music_current->identifier);
5227 /* needed for displaying volume text instead of identifier */
5228 volume_simple_text = volume_simple_current->name;
5229 volume_loops_text = volume_loops_current->name;
5230 volume_music_text = volume_music_current->name;
5232 setup_mode = SETUP_MODE_SOUND;
5237 static void execSetupChooseTouchControls()
5239 setup_mode = SETUP_MODE_CHOOSE_TOUCH_CONTROL;
5244 static void execSetupChooseMoveDistance()
5246 setup_mode = SETUP_MODE_CHOOSE_MOVE_DISTANCE;
5251 static void execSetupChooseDropDistance()
5253 setup_mode = SETUP_MODE_CHOOSE_DROP_DISTANCE;
5258 static void execSetupTouch()
5260 if (touch_controls == NULL)
5264 for (i = 0; touch_controls_list[i].value != NULL; i++)
5266 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5267 char identifier[32], name[32];
5268 char *value = touch_controls_list[i].value;
5269 char *text = touch_controls_list[i].text;
5271 ti->node_top = &touch_controls;
5272 ti->sort_priority = i;
5274 sprintf(identifier, "%s", value);
5275 sprintf(name, "%s", text);
5277 setString(&ti->identifier, identifier);
5278 setString(&ti->name, name);
5279 setString(&ti->name_sorting, name);
5280 setString(&ti->infotext, STR_SETUP_CHOOSE_TOUCH_CONTROL);
5282 pushTreeInfo(&touch_controls, ti);
5285 /* sort touch control values to start with lowest touch control value */
5286 sortTreeInfo(&touch_controls);
5288 /* set current touch control value to configured touch control value */
5289 touch_control_current =
5290 getTreeInfoFromIdentifier(touch_controls, setup.touch.control_type);
5292 /* if that fails, set current touch control to reliable default value */
5293 if (touch_control_current == NULL)
5294 touch_control_current =
5295 getTreeInfoFromIdentifier(touch_controls, TOUCH_CONTROL_DEFAULT);
5297 /* if that also fails, set current touch control to first available value */
5298 if (touch_control_current == NULL)
5299 touch_control_current = touch_controls;
5302 if (move_distances == NULL)
5306 for (i = 0; distances_list[i].value != -1; i++)
5308 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5309 char identifier[32], name[32];
5310 int value = distances_list[i].value;
5311 char *text = distances_list[i].text;
5313 ti->node_top = &move_distances;
5314 ti->sort_priority = value;
5316 sprintf(identifier, "%d", value);
5317 sprintf(name, "%s", text);
5319 setString(&ti->identifier, identifier);
5320 setString(&ti->name, name);
5321 setString(&ti->name_sorting, name);
5322 setString(&ti->infotext, STR_SETUP_CHOOSE_MOVE_DISTANCE);
5324 pushTreeInfo(&move_distances, ti);
5327 /* sort distance values to start with lowest distance value */
5328 sortTreeInfo(&move_distances);
5330 /* set current distance value to configured distance value */
5331 move_distance_current =
5332 getTreeInfoFromIdentifier(move_distances,
5333 i_to_a(setup.touch.move_distance));
5335 /* if that fails, set current distance to reliable default value */
5336 if (move_distance_current == NULL)
5337 move_distance_current =
5338 getTreeInfoFromIdentifier(move_distances, i_to_a(1));
5340 /* if that also fails, set current distance to first available value */
5341 if (move_distance_current == NULL)
5342 move_distance_current = move_distances;
5345 if (drop_distances == NULL)
5349 for (i = 0; distances_list[i].value != -1; i++)
5351 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
5352 char identifier[32], name[32];
5353 int value = distances_list[i].value;
5354 char *text = distances_list[i].text;
5356 ti->node_top = &drop_distances;
5357 ti->sort_priority = value;
5359 sprintf(identifier, "%d", value);
5360 sprintf(name, "%s", text);
5362 setString(&ti->identifier, identifier);
5363 setString(&ti->name, name);
5364 setString(&ti->name_sorting, name);
5365 setString(&ti->infotext, STR_SETUP_CHOOSE_DROP_DISTANCE);
5367 pushTreeInfo(&drop_distances, ti);
5370 /* sort distance values to start with lowest distance value */
5371 sortTreeInfo(&drop_distances);
5373 /* set current distance value to configured distance value */
5374 drop_distance_current =
5375 getTreeInfoFromIdentifier(drop_distances,
5376 i_to_a(setup.touch.drop_distance));
5378 /* if that fails, set current distance to reliable default value */
5379 if (drop_distance_current == NULL)
5380 drop_distance_current =
5381 getTreeInfoFromIdentifier(drop_distances, i_to_a(1));
5383 /* if that also fails, set current distance to first available value */
5384 if (drop_distance_current == NULL)
5385 drop_distance_current = drop_distances;
5388 setup.touch.control_type = touch_control_current->identifier;
5389 setup.touch.move_distance = atoi(move_distance_current->identifier);
5390 setup.touch.drop_distance = atoi(drop_distance_current->identifier);
5392 /* needed for displaying volume text instead of identifier */
5393 touch_controls_text = touch_control_current->name;
5394 move_distance_text = move_distance_current->name;
5395 drop_distance_text = drop_distance_current->name;
5397 setup_mode = SETUP_MODE_TOUCH;
5402 static void execSetupArtwork()
5405 printf("::: '%s', '%s', '%s'\n",
5406 artwork.gfx_current->subdir,
5407 artwork.gfx_current->fullpath,
5408 artwork.gfx_current->basepath);
5411 setup.graphics_set = artwork.gfx_current->identifier;
5412 setup.sounds_set = artwork.snd_current->identifier;
5413 setup.music_set = artwork.mus_current->identifier;
5415 /* needed if last screen (setup choice) changed graphics, sounds or music */
5416 ReloadCustomArtwork(0);
5418 /* needed for displaying artwork name instead of artwork identifier */
5419 graphics_set_name = artwork.gfx_current->name;
5420 sounds_set_name = artwork.snd_current->name;
5421 music_set_name = artwork.mus_current->name;
5423 setup_mode = SETUP_MODE_ARTWORK;
5428 static void execSetupChooseGraphics()
5430 setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
5435 static void execSetupChooseSounds()
5437 setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
5442 static void execSetupChooseMusic()
5444 setup_mode = SETUP_MODE_CHOOSE_MUSIC;
5449 static void execSetupInput()
5451 setup_mode = SETUP_MODE_INPUT;
5456 static void execSetupShortcuts()
5458 setup_mode = SETUP_MODE_SHORTCUTS;
5463 static void execSetupShortcuts1()
5465 setup_mode = SETUP_MODE_SHORTCUTS_1;
5470 static void execSetupShortcuts2()
5472 setup_mode = SETUP_MODE_SHORTCUTS_2;
5477 static void execSetupShortcuts3()
5479 setup_mode = SETUP_MODE_SHORTCUTS_3;
5484 static void execSetupShortcuts4()
5486 setup_mode = SETUP_MODE_SHORTCUTS_4;
5491 static void execSetupShortcuts5()
5493 setup_mode = SETUP_MODE_SHORTCUTS_5;
5498 static void execExitSetup()
5500 SetGameStatus(GAME_MODE_MAIN);
5505 static void execSaveAndExitSetup()
5511 static struct TokenInfo setup_info_main[] =
5513 { TYPE_ENTER_MENU, execSetupGame, STR_SETUP_GAME },
5514 { TYPE_ENTER_MENU, execSetupEditor, STR_SETUP_EDITOR },
5515 { TYPE_ENTER_MENU, execSetupGraphics, STR_SETUP_GRAPHICS },
5516 { TYPE_ENTER_MENU, execSetupSound, STR_SETUP_SOUND },
5517 { TYPE_ENTER_MENU, execSetupArtwork, STR_SETUP_ARTWORK },
5518 { TYPE_ENTER_MENU, execSetupInput, STR_SETUP_INPUT },
5519 { TYPE_ENTER_MENU, execSetupTouch, STR_SETUP_TOUCH },
5520 { TYPE_ENTER_MENU, execSetupShortcuts, STR_SETUP_SHORTCUTS },
5521 { TYPE_EMPTY, NULL, "" },
5522 { TYPE_LEAVE_MENU, execExitSetup, STR_SETUP_EXIT },
5523 { TYPE_LEAVE_MENU, execSaveAndExitSetup, STR_SETUP_SAVE_AND_EXIT },
5528 static struct TokenInfo setup_info_game[] =
5530 { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" },
5531 { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" },
5532 { TYPE_SWITCH, &setup.time_limit, "Time Limit:" },
5533 { TYPE_SWITCH, &setup.handicap, "Handicap:" },
5534 { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" },
5535 { TYPE_SWITCH, &setup.increment_levels,"Increment Solved Levels:" },
5536 { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" },
5537 { TYPE_ENTER_LIST, execSetupChooseGameSpeed, "Game Speed:" },
5538 { TYPE_STRING, &game_speed_text, "" },
5540 { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay:" },
5541 { TYPE_STRING, &scroll_delay_text, "" },
5543 { TYPE_ENTER_LIST, execSetupChooseSnapshotMode,"Game Engine Snapshot Mode:" },
5544 { TYPE_STRING, &snapshot_mode_text, "" },
5545 { TYPE_SWITCH, &setup.show_snapshot_buttons,"Show Snapshot Buttons:" },
5546 { TYPE_EMPTY, NULL, "" },
5547 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5552 static struct TokenInfo setup_info_editor[] =
5555 { TYPE_SWITCH, &setup.editor.el_boulderdash, "Boulder Dash:" },
5556 { TYPE_SWITCH, &setup.editor.el_emerald_mine, "Emerald Mine:" },
5557 { TYPE_SWITCH, &setup.editor.el_emerald_mine_club, "Emerald Mine Club:" },
5558 { TYPE_SWITCH, &setup.editor.el_more, "Rocks'n'Diamonds:" },
5559 { TYPE_SWITCH, &setup.editor.el_sokoban, "Sokoban:" },
5560 { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" },
5561 { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" },
5562 { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
5563 { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" },
5564 { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" },
5566 { TYPE_SWITCH, &setup.editor.el_classic, "Classic Elements:" },
5567 { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" },
5569 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" },
5571 { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
5572 { TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" },
5573 { TYPE_EMPTY, NULL, "" },
5575 { TYPE_SWITCH, &setup.editor.el_by_game, "Show elements by game:" },
5576 { TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" },
5577 { TYPE_EMPTY, NULL, "" },
5579 { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" },
5580 { TYPE_EMPTY, NULL, "" },
5581 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5586 static struct TokenInfo setup_info_graphics[] =
5588 #if defined(TARGET_SDL2) && !defined(PLATFORM_ANDROID)
5589 { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" },
5590 { TYPE_ENTER_LIST, execSetupChooseWindowSize, "Window Scaling:" },
5591 { TYPE_STRING, &window_size_text, "" },
5592 { TYPE_ENTER_LIST, execSetupChooseScalingType, "Anti-Aliasing:" },
5593 { TYPE_STRING, &scaling_type_text, "" },
5594 { TYPE_ENTER_LIST, execSetupChooseRenderingMode, "Special Rendering:" },
5595 { TYPE_STRING, &rendering_mode_text, "" },
5598 { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay:" },
5599 { TYPE_STRING, &scroll_delay_text, "" },
5601 { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" },
5602 { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" },
5603 { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" },
5604 { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" },
5605 { TYPE_SWITCH, &setup.toons, "Show Menu Animations:" },
5606 { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" },
5607 { TYPE_SWITCH, &setup.sp_show_border_elements,"Supaplex Border Elements:" },
5608 { TYPE_SWITCH, &setup.small_game_graphics, "Small Game Graphics:" },
5609 { TYPE_EMPTY, NULL, "" },
5610 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5615 static struct TokenInfo setup_info_sound[] =
5617 { TYPE_SWITCH, &setup.sound_simple, "Sound Effects (Normal):" },
5618 { TYPE_SWITCH, &setup.sound_loops, "Sound Effects (Looping):" },
5619 { TYPE_SWITCH, &setup.sound_music, "Music:" },
5620 { TYPE_EMPTY, NULL, "" },
5621 { TYPE_ENTER_LIST, execSetupChooseVolumeSimple, "Sound Volume (Normal):" },
5622 { TYPE_STRING, &volume_simple_text, "" },
5623 { TYPE_ENTER_LIST, execSetupChooseVolumeLoops, "Sound Volume (Looping):" },
5624 { TYPE_STRING, &volume_loops_text, "" },
5625 { TYPE_ENTER_LIST, execSetupChooseVolumeMusic, "Music Volume:" },
5626 { TYPE_STRING, &volume_music_text, "" },
5627 { TYPE_EMPTY, NULL, "" },
5628 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5633 static struct TokenInfo setup_info_artwork[] =
5635 { TYPE_ENTER_LIST, execSetupChooseGraphics,"Custom Graphics:" },
5636 { TYPE_STRING, &graphics_set_name, "" },
5637 { TYPE_ENTER_LIST, execSetupChooseSounds, "Custom Sounds:" },
5638 { TYPE_STRING, &sounds_set_name, "" },
5639 { TYPE_ENTER_LIST, execSetupChooseMusic, "Custom Music:" },
5640 { TYPE_STRING, &music_set_name, "" },
5641 { TYPE_EMPTY, NULL, "" },
5642 { TYPE_YES_NO_AUTO,&setup.override_level_graphics,"Override Level Graphics:"},
5643 { TYPE_YES_NO_AUTO,&setup.override_level_sounds, "Override Level Sounds:" },
5644 { TYPE_YES_NO_AUTO,&setup.override_level_music, "Override Level Music:" },
5645 { TYPE_EMPTY, NULL, "" },
5646 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5651 static struct TokenInfo setup_info_input[] =
5653 { TYPE_SWITCH, NULL, "Player:" },
5654 { TYPE_SWITCH, NULL, "Device:" },
5655 { TYPE_SWITCH, NULL, "" },
5656 { TYPE_EMPTY, NULL, "" },
5657 { TYPE_EMPTY, NULL, "" },
5658 { TYPE_EMPTY, NULL, "" },
5659 { TYPE_EMPTY, NULL, "" },
5660 { TYPE_EMPTY, NULL, "" },
5661 { TYPE_EMPTY, NULL, "" },
5662 { TYPE_EMPTY, NULL, "" },
5663 { TYPE_EMPTY, NULL, "" },
5664 { TYPE_EMPTY, NULL, "" },
5665 { TYPE_EMPTY, NULL, "" },
5666 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5671 static struct TokenInfo setup_info_touch[] =
5673 { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" },
5674 { TYPE_STRING, &touch_controls_text, "" },
5675 { TYPE_EMPTY, NULL, "" },
5676 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5681 static struct TokenInfo setup_info_touch_wipe_gestures[] =
5683 { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" },
5684 { TYPE_STRING, &touch_controls_text, "" },
5685 { TYPE_EMPTY, NULL, "" },
5686 { TYPE_ENTER_LIST, execSetupChooseMoveDistance, "Move Trigger Distance:" },
5687 { TYPE_STRING, &move_distance_text, "" },
5688 { TYPE_ENTER_LIST, execSetupChooseDropDistance, "Drop Trigger Distance:" },
5689 { TYPE_STRING, &drop_distance_text, "" },
5690 { TYPE_EMPTY, NULL, "" },
5691 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5696 static struct TokenInfo setup_info_shortcuts[] =
5698 { TYPE_ENTER_MENU, execSetupShortcuts1, "Various Keys" },
5699 { TYPE_ENTER_MENU, execSetupShortcuts2, "Player Focus" },
5700 { TYPE_ENTER_MENU, execSetupShortcuts3, "Tape Buttons" },
5701 { TYPE_ENTER_MENU, execSetupShortcuts4, "Sound & Music" },
5702 { TYPE_ENTER_MENU, execSetupShortcuts5, "TAS Snap Keys" },
5703 { TYPE_EMPTY, NULL, "" },
5704 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
5709 static struct TokenInfo setup_info_shortcuts_1[] =
5711 { TYPE_KEYTEXT, NULL, "Quick Save Game to Tape:", },
5712 { TYPE_KEY, &setup.shortcut.save_game, "" },
5713 { TYPE_KEYTEXT, NULL, "Quick Load Game from Tape:", },
5714 { TYPE_KEY, &setup.shortcut.load_game, "" },
5715 { TYPE_KEYTEXT, NULL, "Start Game & Toggle Pause:", },
5716 { TYPE_KEY, &setup.shortcut.toggle_pause, "" },
5717 { TYPE_EMPTY, NULL, "" },
5718 { TYPE_YES_NO, &setup.ask_on_escape, "Ask on 'Esc' Key:" },
5719 { TYPE_YES_NO, &setup.ask_on_escape_editor, "Ask on 'Esc' Key (Editor):" },
5720 { TYPE_EMPTY, NULL, "" },
5721 { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" },
5726 static struct TokenInfo setup_info_shortcuts_2[] =
5728 { TYPE_KEYTEXT, NULL, "Set Focus to Player 1:", },
5729 { TYPE_KEY, &setup.shortcut.focus_player[0], "" },
5730 { TYPE_KEYTEXT, NULL, "Set Focus to Player 2:", },
5731 { TYPE_KEY, &setup.shortcut.focus_player[1], "" },
5732 { TYPE_KEYTEXT, NULL, "Set Focus to Player 3:", },
5733 { TYPE_KEY, &setup.shortcut.focus_player[2], "" },
5734 { TYPE_KEYTEXT, NULL, "Set Focus to Player 4:", },
5735 { TYPE_KEY, &setup.shortcut.focus_player[3], "" },
5736 { TYPE_KEYTEXT, NULL, "Set Focus to All Players:", },
5737 { TYPE_KEY, &setup.shortcut.focus_player_all, "" },
5738 { TYPE_EMPTY, NULL, "" },
5739 { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" },
5744 static struct TokenInfo setup_info_shortcuts_3[] =
5746 { TYPE_KEYTEXT, NULL, "Eject Tape:", },
5747 { TYPE_KEY, &setup.shortcut.tape_eject, "" },
5748 { TYPE_KEYTEXT, NULL, "Warp / Single Step:", },
5749 { TYPE_KEY, &setup.shortcut.tape_extra, "" },
5750 { TYPE_KEYTEXT, NULL, "Stop Tape:", },
5751 { TYPE_KEY, &setup.shortcut.tape_stop, "" },
5752 { TYPE_KEYTEXT, NULL, "Pause / Unpause Tape:",},
5753 { TYPE_KEY, &setup.shortcut.tape_pause, "" },
5754 { TYPE_KEYTEXT, NULL, "Record Tape:", },
5755 { TYPE_KEY, &setup.shortcut.tape_record, "" },
5756 { TYPE_KEYTEXT, NULL, "Play Tape:", },
5757 { TYPE_KEY, &setup.shortcut.tape_play, "" },
5758 { TYPE_EMPTY, NULL, "" },
5759 { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" },
5764 static struct TokenInfo setup_info_shortcuts_4[] =
5766 { TYPE_KEYTEXT, NULL, "Toggle Sound Effects (Normal):", },
5767 { TYPE_KEY, &setup.shortcut.sound_simple, "" },
5768 { TYPE_KEYTEXT, NULL, "Toggle Sound Effects (Looping):", },
5769 { TYPE_KEY, &setup.shortcut.sound_loops, "" },
5770 { TYPE_KEYTEXT, NULL, "Toggle Music:", },
5771 { TYPE_KEY, &setup.shortcut.sound_music, "" },
5772 { TYPE_EMPTY, NULL, "" },
5773 { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" },
5778 static struct TokenInfo setup_info_shortcuts_5[] =
5780 { TYPE_KEYTEXT, NULL, "Snap Left:", },
5781 { TYPE_KEY, &setup.shortcut.snap_left, "" },
5782 { TYPE_KEYTEXT, NULL, "Snap Right:", },
5783 { TYPE_KEY, &setup.shortcut.snap_right, "" },
5784 { TYPE_KEYTEXT, NULL, "Snap Up:", },
5785 { TYPE_KEY, &setup.shortcut.snap_up, "" },
5786 { TYPE_KEYTEXT, NULL, "Snap Down:", },
5787 { TYPE_KEY, &setup.shortcut.snap_down, "" },
5788 { TYPE_EMPTY, NULL, "" },
5789 { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" },
5794 static Key getSetupKey()
5796 Key key = KSYM_UNDEFINED;
5797 boolean got_key_event = FALSE;
5799 while (!got_key_event)
5803 if (NextValidEvent(&event))
5807 case EVENT_KEYPRESS:
5809 key = GetEventKey((KeyEvent *)&event, TRUE);
5811 /* press 'Escape' or 'Enter' to keep the existing key binding */
5812 if (key == KSYM_Escape || key == KSYM_Return)
5813 key = KSYM_UNDEFINED; /* keep old value */
5815 got_key_event = TRUE;
5819 case EVENT_KEYRELEASE:
5820 key_joystick_mapping = 0;
5824 HandleOtherEvents(&event);
5835 static int getSetupValueFont(int type, void *value)
5837 if (type & TYPE_GHOSTED)
5838 return FONT_OPTION_OFF;
5839 else if (type & TYPE_KEY)
5840 return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1);
5841 else if (type & TYPE_STRING)
5842 return FONT_VALUE_2;
5843 else if (type & TYPE_ECS_AGA)
5844 return FONT_VALUE_1;
5845 else if (type & TYPE_BOOLEAN_STYLE)
5846 return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
5847 else if (type & TYPE_YES_NO_AUTO)
5848 return (*(int *)value == AUTO ? FONT_OPTION_ON :
5849 *(int *)value == FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON);
5851 return FONT_VALUE_1;
5854 static int getSetupValueFontNarrow(int type, int font_nr)
5856 return (font_nr == FONT_VALUE_1 ? FONT_VALUE_NARROW :
5857 font_nr == FONT_OPTION_ON ? FONT_OPTION_ON_NARROW :
5858 font_nr == FONT_OPTION_OFF ? FONT_OPTION_OFF_NARROW :
5862 static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
5864 int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw);
5865 struct TokenInfo *si = &setup_info[si_pos];
5866 boolean font_draw_xoffset_modified = FALSE;
5867 boolean scrollbar_needed = (num_setup_info < max_setup_info);
5868 int font_draw_xoffset_old = -1;
5869 int xoffset = (scrollbar_needed ? -1 : 0);
5870 int menu_screen_value_xpos = MENU_SCREEN_VALUE_XPOS + xoffset;
5871 int menu_screen_max_xpos = MENU_SCREEN_MAX_XPOS + xoffset;
5872 int xpos = menu_screen_value_xpos;
5873 int ypos = MENU_SCREEN_START_YPOS + screen_pos;
5874 int startx = mSX + xpos * 32;
5875 int starty = mSY + ypos * 32;
5876 int font_nr, font_nr_default, font_width_default;
5877 int type = si->type;
5878 void *value = si->value;
5879 char *value_string = getSetupValue(type, value);
5882 if (value_string == NULL)
5885 if (type & TYPE_KEY)
5887 xpos = MENU_SCREEN_START_XPOS;
5889 if (type & TYPE_QUERY)
5890 value_string = "<press key>";
5892 else if (type & TYPE_STRING)
5894 int max_value_len = (SCR_FIELDX - 2) * 2;
5896 xpos = MENU_SCREEN_START_XPOS;
5898 if (strlen(value_string) > max_value_len)
5899 value_string[max_value_len] = '\0';
5901 else if (type & TYPE_YES_NO_AUTO)
5903 xpos = menu_screen_value_xpos - 1;
5906 startx = mSX + xpos * 32;
5907 starty = mSY + ypos * 32;
5908 font_nr_default = getSetupValueFont(type, value);
5909 font_width_default = getFontWidth(font_nr_default);
5911 font_nr = font_nr_default;
5913 // special check if right-side setup values moved left due to scrollbar
5914 if (scrollbar_needed && xpos > MENU_SCREEN_START_XPOS)
5916 int max_menu_text_length = 26; // maximum text length for classic menu
5917 int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
5918 int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
5919 int text_font_nr = getMenuTextFont(FONT_MENU_2);
5920 int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
5921 int text_width = max_menu_text_length * getFontWidth(text_font_nr);
5923 if (startx + font_xoffset < text_startx + text_width + text_font_xoffset)
5926 startx = mSX + xpos * 32;
5928 font_nr = getSetupValueFontNarrow(type, font_nr);
5932 /* downward compatibility correction for Juergen Bonhagen's menu settings */
5933 if (setup_mode != SETUP_MODE_INPUT)
5935 int max_menu_text_length_big = (menu_screen_value_xpos -
5936 MENU_SCREEN_START_XPOS);
5937 int max_menu_text_length_medium = max_menu_text_length_big * 2;
5938 int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
5939 int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
5940 int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
5941 int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
5942 int text_font_nr = getMenuTextFont(FONT_MENU_2);
5943 int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
5944 int text_width = max_menu_text_length_medium * getFontWidth(text_font_nr);
5945 boolean correct_font_draw_xoffset = FALSE;
5947 if (xpos == MENU_SCREEN_START_XPOS &&
5948 startx + font1_xoffset < text_startx + text_font_xoffset)
5949 correct_font_draw_xoffset = TRUE;
5951 if (xpos == menu_screen_value_xpos &&
5952 startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
5953 correct_font_draw_xoffset = TRUE;
5955 /* check if setup value would overlap with setup text when printed */
5956 /* (this can happen for extreme/wrong values for font draw offset) */
5957 if (correct_font_draw_xoffset)
5959 font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
5960 font_draw_xoffset_modified = TRUE;
5962 if (type & TYPE_KEY)
5963 getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
5964 else if (!(type & TYPE_STRING))
5965 getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
5966 max_menu_text_length_medium * (16 - getFontWidth(text_font_nr));
5970 for (i = 0; i <= menu_screen_max_xpos - xpos; i++)
5971 DrawText(startx + i * font_width_default, starty, " ", font_nr_default);
5973 DrawText(startx, starty, value_string, font_nr);
5975 if (font_draw_xoffset_modified)
5976 getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
5979 static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx)
5981 int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw);
5982 struct TokenInfo *si = &setup_info[si_pos];
5984 if (si->type & TYPE_BOOLEAN_STYLE)
5986 *(boolean *)si->value ^= TRUE;
5988 else if (si->type & TYPE_YES_NO_AUTO)
5992 (*(int *)si->value == AUTO ? TRUE :
5993 *(int *)si->value == TRUE ? FALSE : AUTO) :
5994 (*(int *)si->value == TRUE ? AUTO :
5995 *(int *)si->value == AUTO ? FALSE : TRUE));
5997 else if (si->type & TYPE_KEY)
6001 si->type |= TYPE_QUERY;
6002 drawSetupValue(screen_pos, setup_info_pos_raw);
6003 si->type &= ~TYPE_QUERY;
6005 key = getSetupKey();
6006 if (key != KSYM_UNDEFINED)
6007 *(Key *)si->value = key;
6010 drawSetupValue(screen_pos, setup_info_pos_raw);
6012 // fullscreen state may have changed at this point
6013 if (si->value == &setup.fullscreen)
6014 ToggleFullscreenOrChangeWindowScalingIfNeeded();
6017 static struct TokenInfo *getSetupInfoFinal(struct TokenInfo *setup_info_orig)
6019 static struct TokenInfo *setup_info_hide = NULL;
6024 /* determine maximum list size of target list */
6025 while (setup_info_orig[list_size++].type != 0);
6027 /* free, allocate and clear memory for target list */
6028 checked_free(setup_info_hide);
6029 setup_info_hide = checked_calloc(list_size * sizeof(struct TokenInfo));
6031 /* copy setup info list without setup entries marked as hidden */
6032 for (i = 0; setup_info_orig[i].type != 0; i++)
6033 if (!hideSetupEntry(setup_info_orig[i].value))
6034 setup_info_hide[list_pos++] = setup_info_orig[i];
6036 return setup_info_hide;
6039 static void DrawSetupScreen_Generic()
6041 int fade_mask = REDRAW_FIELD;
6042 boolean redraw_all = FALSE;
6043 char *title_string = NULL;
6046 if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
6047 fade_mask = REDRAW_ALL;
6050 FadeMenuSoundsAndMusic();
6052 FreeScreenGadgets();
6053 CreateScreenGadgets();
6055 if (redraw_mask & REDRAW_ALL)
6060 /* needed if different viewport properties defined for setup screen */
6061 ChangeViewportPropertiesIfNeeded();
6063 SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
6067 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
6069 if (setup_mode == SETUP_MODE_MAIN)
6071 setup_info = setup_info_main;
6072 title_string = STR_SETUP_MAIN;
6074 else if (setup_mode == SETUP_MODE_GAME)
6076 setup_info = setup_info_game;
6077 title_string = STR_SETUP_GAME;
6079 else if (setup_mode == SETUP_MODE_EDITOR)
6081 setup_info = setup_info_editor;
6082 title_string = STR_SETUP_EDITOR;
6084 else if (setup_mode == SETUP_MODE_GRAPHICS)
6086 setup_info = setup_info_graphics;
6087 title_string = STR_SETUP_GRAPHICS;
6089 else if (setup_mode == SETUP_MODE_SOUND)
6091 setup_info = setup_info_sound;
6092 title_string = STR_SETUP_SOUND;
6094 else if (setup_mode == SETUP_MODE_ARTWORK)
6096 setup_info = setup_info_artwork;
6097 title_string = STR_SETUP_ARTWORK;
6099 else if (setup_mode == SETUP_MODE_TOUCH)
6101 setup_info = setup_info_touch;
6102 title_string = STR_SETUP_TOUCH;
6104 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_WIPE_GESTURES))
6105 setup_info = setup_info_touch_wipe_gestures;
6107 else if (setup_mode == SETUP_MODE_SHORTCUTS)
6109 setup_info = setup_info_shortcuts;
6110 title_string = STR_SETUP_SHORTCUTS;
6112 else if (setup_mode == SETUP_MODE_SHORTCUTS_1)
6114 setup_info = setup_info_shortcuts_1;
6115 title_string = STR_SETUP_SHORTCUTS;
6117 else if (setup_mode == SETUP_MODE_SHORTCUTS_2)
6119 setup_info = setup_info_shortcuts_2;
6120 title_string = STR_SETUP_SHORTCUTS;
6122 else if (setup_mode == SETUP_MODE_SHORTCUTS_3)
6124 setup_info = setup_info_shortcuts_3;
6125 title_string = STR_SETUP_SHORTCUTS;
6127 else if (setup_mode == SETUP_MODE_SHORTCUTS_4)
6129 setup_info = setup_info_shortcuts_4;
6130 title_string = STR_SETUP_SHORTCUTS;
6132 else if (setup_mode == SETUP_MODE_SHORTCUTS_5)
6134 setup_info = setup_info_shortcuts_5;
6135 title_string = STR_SETUP_SHORTCUTS;
6138 /* use modified setup info without setup entries marked as hidden */
6139 setup_info = getSetupInfoFinal(setup_info);
6141 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
6143 // determine maximal number of setup entries that can be displayed on screen
6145 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
6148 // determine maximal number of setup entries available for this setup screen
6150 for (i = 0; setup_info[i].type != 0; i++)
6153 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
6155 MapScreenGadgets(max_setup_info);
6158 redraw_mask = fade_mask = REDRAW_ALL;
6160 DrawMaskedBorder(fade_mask);
6165 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
6167 menu_info = setup_info;
6169 HandleMenuScreen(mx, my, dx, dy, button,
6170 setup_mode, num_setup_info, max_setup_info);
6173 void DrawSetupScreen_Input()
6177 FadeOut(REDRAW_FIELD);
6181 setup_info = setup_info_input;
6183 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, STR_SETUP_INPUT);
6185 for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
6187 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
6188 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
6189 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
6190 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
6191 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
6192 initCursor(i, IMG_MENU_BUTTON);
6194 DrawCursorAndText_Setup(i, -1, FALSE);
6197 /* create gadgets for setup input menu screen */
6198 FreeScreenGadgets();
6199 CreateScreenGadgets();
6201 /* map gadgets for setup input menu screen */
6202 MapScreenMenuGadgets(SCREEN_MASK_INPUT);
6204 HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE);
6206 FadeIn(REDRAW_FIELD);
6209 static void setJoystickDeviceToNr(char *device_name, int device_nr)
6211 if (device_name == NULL)
6214 if (device_nr < 0 || device_nr >= MAX_PLAYERS)
6217 if (strlen(device_name) > 1)
6219 char c1 = device_name[strlen(device_name) - 1];
6220 char c2 = device_name[strlen(device_name) - 2];
6222 if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9'))
6223 device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
6226 strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
6227 strlen(device_name));
6230 static void drawPlayerSetupInputInfo(int player_nr, boolean active)
6233 static struct SetupKeyboardInfo custom_key;
6240 { &custom_key.left, "Axis/Pad Left" },
6241 { &custom_key.right, "Axis/Pad Right" },
6242 { &custom_key.up, "Axis/Pad Up" },
6243 { &custom_key.down, "Axis/Pad Down" },
6244 { &custom_key.snap, "Button 1/A/X" },
6245 { &custom_key.drop, "Button 2/B/Y" }
6247 static char *joystick_name[MAX_PLAYERS] =
6254 int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1);
6256 custom_key = setup.input[player_nr].key;
6258 DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
6259 FONT_INPUT_1_ACTIVE);
6261 ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
6263 DrawFixedGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
6264 PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
6266 if (setup.input[player_nr].use_joystick)
6268 char *device_name = setup.input[player_nr].joy.device_name;
6269 int joystick_nr = getJoystickNrFromDeviceName(device_name);
6270 boolean joystick_active = CheckJoystickOpened(joystick_nr);
6271 char *text = joystick_name[joystick_nr];
6272 int font_nr = (joystick_active ? FONT_VALUE_1 : FONT_VALUE_OLD);
6274 DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
6275 DrawText(mSX + 32, mSY + 4 * 32, "Configure", text_font_nr);
6279 DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1);
6280 DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr);
6283 DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1);
6285 drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
6286 drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
6287 drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
6288 drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
6290 DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD);
6291 DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD);
6292 DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD);
6293 DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD);
6294 DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD);
6295 DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD);
6297 for (i = 0; i < 6; i++)
6299 int ypos = 6 + i + (i > 3 ? i-3 : 0);
6301 DrawText(mSX + 3 * 32, mSY + ypos * 32,
6303 DrawText(mSX + 3 * 32, mSY + ypos * 32,
6304 (setup.input[player_nr].use_joystick ?
6306 getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
6310 static int input_player_nr = 0;
6312 void HandleSetupScreen_Input_Player(int step, int direction)
6314 int old_player_nr = input_player_nr;
6317 new_player_nr = old_player_nr + step * direction;
6318 if (new_player_nr < 0)
6320 if (new_player_nr > MAX_PLAYERS - 1)
6321 new_player_nr = MAX_PLAYERS - 1;
6323 if (new_player_nr != old_player_nr)
6325 input_player_nr = new_player_nr;
6327 drawPlayerSetupInputInfo(input_player_nr, FALSE);
6331 void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
6333 static int choice = 0;
6336 int pos_start = SETUPINPUT_SCREEN_POS_START;
6337 int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1;
6338 int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2;
6339 int pos_end = SETUPINPUT_SCREEN_POS_END;
6341 if (button == MB_MENU_INITIALIZE)
6343 drawPlayerSetupInputInfo(input_player_nr, (choice == 2));
6345 DrawCursorAndText_Setup(choice, -1, TRUE);
6349 else if (button == MB_MENU_LEAVE)
6351 setup_mode = SETUP_MODE_MAIN;
6358 if (mx || my) /* mouse input */
6360 x = (mx - mSX) / 32;
6361 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
6363 else if (dx || dy) /* keyboard input */
6365 if (dx && choice == 0)
6366 x = (dx < 0 ? 10 : 12);
6367 else if ((dx && choice == 1) ||
6368 (dx == -1 && choice == pos_end))
6369 button = MB_MENU_CHOICE;
6373 if (y >= pos_empty1 && y <= pos_empty2)
6374 y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
6377 if (y == 0 && dx != 0 && button)
6379 HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1);
6381 else if (IN_VIS_FIELD(x, y) && // (does not use "IN_VIS_MENU()" yet)
6382 y >= pos_start && y <= pos_end &&
6383 !(y >= pos_empty1 && y <= pos_empty2))
6389 DrawCursorAndText_Setup(choice, -1, FALSE);
6390 DrawCursorAndText_Setup(y, -1, TRUE);
6392 drawPlayerSetupInputInfo(input_player_nr, (y == 2));
6401 char *device_name = setup.input[input_player_nr].joy.device_name;
6403 if (!setup.input[input_player_nr].use_joystick)
6405 int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1);
6407 setJoystickDeviceToNr(device_name, new_device_nr);
6408 setup.input[input_player_nr].use_joystick = TRUE;
6412 int device_nr = getJoystickNrFromDeviceName(device_name);
6413 int new_device_nr = device_nr + (dx >= 0 ? +1 : -1);
6415 if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS)
6416 setup.input[input_player_nr].use_joystick = FALSE;
6418 setJoystickDeviceToNr(device_name, new_device_nr);
6421 drawPlayerSetupInputInfo(input_player_nr, FALSE);
6425 if (setup.input[input_player_nr].use_joystick)
6426 ConfigureJoystick(input_player_nr);
6428 CustomizeKeyboard(input_player_nr);
6430 else if (y == pos_end)
6436 setup_mode = SETUP_MODE_MAIN;
6443 void CustomizeKeyboard(int player_nr)
6447 boolean finished = FALSE;
6448 static struct SetupKeyboardInfo custom_key;
6453 } customize_step[] =
6455 { &custom_key.left, "Move Left" },
6456 { &custom_key.right, "Move Right" },
6457 { &custom_key.up, "Move Up" },
6458 { &custom_key.down, "Move Down" },
6459 { &custom_key.snap, "Snap Field" },
6460 { &custom_key.drop, "Drop Element" }
6463 /* read existing key bindings from player setup */
6464 custom_key = setup.input[player_nr].key;
6467 FadeOut(REDRAW_FIELD);
6471 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input");
6474 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
6475 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
6476 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
6477 "Key:", FONT_INPUT_1_ACTIVE);
6478 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
6479 getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
6481 FadeIn(REDRAW_FIELD);
6487 if (NextValidEvent(&event))
6491 case EVENT_KEYPRESS:
6493 Key key = GetEventKey((KeyEvent *)&event, FALSE);
6495 if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
6497 if (key == KSYM_Escape)
6498 FadeSkipNextFadeIn();
6504 /* all keys configured -- wait for "Escape" or "Return" key */
6508 /* press 'Enter' to keep the existing key binding */
6509 if (key == KSYM_Return)
6510 key = *customize_step[step_nr].key;
6512 /* check if key already used */
6513 for (i = 0; i < step_nr; i++)
6514 if (*customize_step[i].key == key)
6519 /* got new key binding */
6520 *customize_step[step_nr].key = key;
6521 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
6523 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
6524 getKeyNameFromKey(key), FONT_VALUE_1);
6527 /* un-highlight last query */
6528 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32,
6529 customize_step[step_nr - 1].text, FONT_MENU_1);
6530 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32,
6531 "Key:", FONT_MENU_1);
6533 /* press 'Enter' to leave */
6536 DrawText(mSX + 16, mSY + 15 * 32 + 16,
6537 "Press Enter", FONT_TITLE_1);
6541 /* query next key binding */
6542 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
6543 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
6544 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
6545 "Key:", FONT_INPUT_1_ACTIVE);
6546 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
6547 getKeyNameFromKey(*customize_step[step_nr].key),
6552 case EVENT_KEYRELEASE:
6553 key_joystick_mapping = 0;
6557 HandleOtherEvents(&event);
6565 /* write new key bindings back to player setup */
6566 setup.input[player_nr].key = custom_key;
6568 DrawSetupScreen_Input();
6571 /* game controller mapping generator by Gabriel Jacobo <gabomdq@gmail.com> */
6573 #define MARKER_BUTTON 1
6574 #define MARKER_AXIS_X 2
6575 #define MARKER_AXIS_Y 3
6577 static boolean ConfigureJoystickMapButtonsAndAxes(SDL_Joystick *joystick)
6579 #if defined(TARGET_SDL2)
6580 static boolean bitmaps_initialized = FALSE;
6581 boolean screen_initialized = FALSE;
6582 static Bitmap *controller, *button, *axis_x, *axis_y;
6584 boolean success = TRUE;
6585 boolean done = FALSE, next = FALSE;
6587 int alpha = 200, alpha_step = -1;
6588 int alpha_ticks = 0;
6589 char mapping[4096], temp[4096];
6590 int font_name = MENU_SETUP_FONT_TITLE;
6591 int font_info = MENU_SETUP_FONT_TEXT;
6592 int spacing_name = menu.line_spacing_setup[SETUP_MODE_INPUT];
6593 int spacing_line = menu.line_spacing_setup[SETUP_MODE_INPUT];
6594 int spacing_para = menu.paragraph_spacing_setup[SETUP_MODE_INPUT];
6595 int ystep_name = getMenuTextStep(spacing_name, font_name);
6596 int ystep_line = getMenuTextStep(spacing_line, font_info);
6597 int ystep_para = getMenuTextStep(spacing_para, font_info);
6605 int axis, button, hat, hat_value;
6608 *step, *prev_step, steps[] =
6610 { 356, 155, MARKER_BUTTON, "a", },
6611 { 396, 122, MARKER_BUTTON, "b", },
6612 { 320, 125, MARKER_BUTTON, "x", },
6613 { 358, 95, MARKER_BUTTON, "y", },
6614 { 162, 125, MARKER_BUTTON, "back", },
6615 { 216, 125, MARKER_BUTTON, "guide", },
6616 { 271, 125, MARKER_BUTTON, "start", },
6617 { 110, 200, MARKER_BUTTON, "dpleft", },
6618 { 146, 228, MARKER_BUTTON, "dpdown", },
6619 { 178, 200, MARKER_BUTTON, "dpright", },
6620 { 146, 172, MARKER_BUTTON, "dpup", },
6621 { 50, 40, MARKER_BUTTON, "leftshoulder", },
6622 { 88, -10, MARKER_AXIS_Y, "lefttrigger", },
6623 { 382, 40, MARKER_BUTTON, "rightshoulder", },
6624 { 346, -10, MARKER_AXIS_Y, "righttrigger", },
6625 { 73, 141, MARKER_BUTTON, "leftstick", },
6626 { 282, 210, MARKER_BUTTON, "rightstick", },
6627 { 73, 141, MARKER_AXIS_X, "leftx", },
6628 { 73, 141, MARKER_AXIS_Y, "lefty", },
6629 { 282, 210, MARKER_AXIS_X, "rightx", },
6630 { 282, 210, MARKER_AXIS_Y, "righty", },
6633 unsigned int event_frame_delay = 0;
6634 unsigned int event_frame_delay_value = GAME_FRAME_DELAY;
6636 ResetDelayCounter(&event_frame_delay);
6638 if (!bitmaps_initialized)
6640 controller = LoadCustomImage("joystick/controller.png");
6641 button = LoadCustomImage("joystick/button.png");
6642 axis_x = LoadCustomImage("joystick/axis_x.png");
6643 axis_y = LoadCustomImage("joystick/axis_y.png");
6645 bitmaps_initialized = TRUE;
6648 name = getFormattedJoystickName(SDL_JoystickName(joystick));
6651 /* print info about the joystick we are watching */
6652 Error(ERR_DEBUG, "watching joystick %d: (%s)\n",
6653 SDL_JoystickInstanceID(joystick), name);
6654 Error(ERR_DEBUG, "joystick has %d axes, %d hats, %d balls, and %d buttons\n",
6655 SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
6656 SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
6659 /* initialize mapping with GUID and name */
6660 SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), temp, sizeof(temp));
6662 snprintf(mapping, sizeof(mapping), "%s,%s,platform:%s,",
6663 temp, name, SDL_GetPlatform());
6665 /* loop through all steps (buttons and axes), getting joystick events */
6666 for (i = 0; i < SDL_arraysize(steps) && !done;)
6668 Bitmap *marker = button; /* initialize with reliable default value */
6671 strcpy(step->mapping, mapping);
6675 step->hat_value = -1;
6677 marker = (step->marker == MARKER_BUTTON ? button :
6678 step->marker == MARKER_AXIS_X ? axis_x :
6679 step->marker == MARKER_AXIS_Y ? axis_y : marker);
6683 while (!done && !next)
6685 alpha += alpha_step * (int)(SDL_GetTicks() - alpha_ticks) / 5;
6686 alpha_ticks = SDL_GetTicks();
6693 else if (alpha < 128)
6699 int controller_x = SX + (SXSIZE - controller->width) / 2;
6700 int controller_y = SY + ystep_line;
6702 int marker_x = controller_x + step->x;
6703 int marker_y = controller_y + step->y;
6705 int ystart1 = mSY - 2 * SY + controller_y + controller->height;
6706 int ystart2 = ystart1 + ystep_name + ystep_line;
6710 DrawTextSCentered(ystart1, font_name, name);
6712 DrawTextSCentered(ystart2, font_info,
6713 "Press buttons and move axes on");
6714 ystart2 += ystep_line;
6715 DrawTextSCentered(ystart2, font_info,
6716 "your controller when indicated.");
6717 ystart2 += ystep_line;
6718 DrawTextSCentered(ystart2, font_info,
6719 "(Your controller may look different.)");
6720 ystart2 += ystep_para;
6722 #if defined(PLATFORM_ANDROID)
6723 DrawTextSCentered(ystart2, font_info,
6724 "To correct a mistake,");
6725 ystart2 += ystep_line;
6726 DrawTextSCentered(ystart2, font_info,
6727 "press the 'back' button.");
6728 ystart2 += ystep_line;
6729 DrawTextSCentered(ystart2, font_info,
6730 "To skip a button or axis,");
6731 ystart2 += ystep_line;
6732 DrawTextSCentered(ystart2, font_info,
6733 "press the 'menu' button.");
6735 DrawTextSCentered(ystart2, font_info,
6736 "To correct a mistake,");
6737 ystart2 += ystep_line;
6738 DrawTextSCentered(ystart2, font_info,
6739 "press the 'backspace' key.");
6740 ystart2 += ystep_line;
6741 DrawTextSCentered(ystart2, font_info,
6742 "To skip a button or axis,");
6743 ystart2 += ystep_line;
6744 DrawTextSCentered(ystart2, font_info,
6745 "press the 'return' key.");
6746 ystart2 += ystep_line;
6747 DrawTextSCentered(ystart2, font_info,
6748 "To exit, press the 'escape' key.");
6751 BlitBitmapMasked(controller, drawto, 0, 0,
6752 controller->width, controller->height,
6753 controller_x, controller_y);
6755 SDL_SetSurfaceAlphaMod(marker->surface_masked, alpha);
6757 BlitBitmapMasked(marker, drawto, 0, 0,
6758 marker->width, marker->height,
6759 marker_x, marker_y);
6761 if (!screen_initialized)
6762 FadeIn(REDRAW_FIELD);
6766 screen_initialized = TRUE;
6768 while (NextValidEvent(&event))
6772 case SDL_JOYAXISMOTION:
6773 if (event.jaxis.value > 20000 ||
6774 event.jaxis.value < -20000)
6776 for (j = 0; j < i; j++)
6777 if (steps[j].axis == event.jaxis.axis)
6782 if (step->marker != MARKER_AXIS_X &&
6783 step->marker != MARKER_AXIS_Y)
6786 step->axis = event.jaxis.axis;
6787 strcat(mapping, step->field);
6788 snprintf(temp, sizeof(temp), ":a%u,", event.jaxis.axis);
6789 strcat(mapping, temp);
6797 case SDL_JOYHATMOTION:
6798 /* ignore centering; we're probably just coming back
6799 to the center from the previous item we set */
6800 if (event.jhat.value == SDL_HAT_CENTERED)
6803 for (j = 0; j < i; j++)
6804 if (steps[j].hat == event.jhat.hat &&
6805 steps[j].hat_value == event.jhat.value)
6810 step->hat = event.jhat.hat;
6811 step->hat_value = event.jhat.value;
6812 strcat(mapping, step->field);
6813 snprintf(temp, sizeof(temp), ":h%u.%u,",
6814 event.jhat.hat, event.jhat.value );
6815 strcat(mapping, temp);
6822 case SDL_JOYBALLMOTION:
6825 case SDL_JOYBUTTONUP:
6826 for (j = 0; j < i; j++)
6827 if (steps[j].button == event.jbutton.button)
6832 step->button = event.jbutton.button;
6833 strcat(mapping, step->field);
6834 snprintf(temp, sizeof(temp), ":b%u,", event.jbutton.button);
6835 strcat(mapping, temp);
6842 case SDL_FINGERDOWN:
6843 case SDL_MOUSEBUTTONDOWN:
6844 /* skip this step */
6851 if (event.key.keysym.sym == KSYM_BackSpace ||
6852 event.key.keysym.sym == KSYM_Back)
6861 /* undo this step */
6862 prev_step = &steps[i - 1];
6863 strcpy(mapping, prev_step->mapping);
6870 if (event.key.keysym.sym == KSYM_space ||
6871 event.key.keysym.sym == KSYM_Return ||
6872 event.key.keysym.sym == KSYM_Menu)
6874 /* skip this step */
6881 if (event.key.keysym.sym == KSYM_Escape)
6891 program.exit_function(0);
6898 // do not handle events for longer than standard frame delay period
6899 if (DelayReached(&event_frame_delay, event_frame_delay_value))
6908 Error(ERR_DEBUG, "New game controller mapping:\n\n%s\n\n", mapping);
6911 // activate mapping for this game
6912 SDL_GameControllerAddMapping(mapping);
6914 // save mapping to personal mappings
6915 SaveSetup_AddGameControllerMapping(mapping);
6918 /* wait until the last pending event was removed from event queue */
6919 while (NextValidEvent(&event));
6927 static int ConfigureJoystickMain(int player_nr)
6929 char *device_name = setup.input[player_nr].joy.device_name;
6930 int joystick_nr = getJoystickNrFromDeviceName(device_name);
6931 boolean joystick_active = CheckJoystickOpened(joystick_nr);
6932 int success = FALSE;
6935 if (joystick.status == JOYSTICK_NOT_AVAILABLE)
6936 return JOYSTICK_NOT_AVAILABLE;
6938 if (!joystick_active || !setup.input[player_nr].use_joystick)
6939 return JOYSTICK_NOT_AVAILABLE;
6942 FadeOut(REDRAW_FIELD);
6944 // close all joystick devices (potentially opened as game controllers)
6945 for (i = 0; i < SDL_NumJoysticks(); i++)
6946 SDLCloseJoystick(i);
6948 // open joystick device as plain joystick to configure as game controller
6949 SDL_Joystick *joystick = SDL_JoystickOpen(joystick_nr);
6951 // as the joystick was successfully opened before, this should not happen
6952 if (joystick == NULL)
6955 // create new game controller mapping (buttons and axes) for joystick device
6956 success = ConfigureJoystickMapButtonsAndAxes(joystick);
6958 // close joystick (and maybe re-open as configured game controller later)
6959 SDL_JoystickClose(joystick);
6961 // re-open all joystick devices (potentially as game controllers)
6962 for (i = 0; i < SDL_NumJoysticks(); i++)
6965 // clear all joystick input actions for all joystick devices
6966 SDLClearJoystickState();
6968 return (success ? JOYSTICK_CONFIGURED : JOYSTICK_NOT_CONFIGURED);
6971 void ConfigureJoystick(int player_nr)
6973 boolean state = ConfigureJoystickMain(player_nr);
6975 if (state != JOYSTICK_NOT_CONFIGURED)
6977 boolean success = (state == JOYSTICK_CONFIGURED);
6978 char *message = (success ? " IS CONFIGURED! " : " NOT AVAILABLE! ");
6979 char *device_name = setup.input[player_nr].joy.device_name;
6980 int nr = getJoystickNrFromDeviceName(device_name) + 1;
6981 int xpos = mSX - SX;
6982 int ypos = mSY - SY;
6983 unsigned int wait_frame_delay = 0;
6984 unsigned int wait_frame_delay_value = 2000;
6986 ResetDelayCounter(&wait_frame_delay);
6990 DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr);
6991 DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, message);
6993 while (!DelayReached(&wait_frame_delay, wait_frame_delay_value))
6999 DrawSetupScreen_Input();
7002 void DrawSetupScreen()
7004 if (setup_mode == SETUP_MODE_INPUT)
7005 DrawSetupScreen_Input();
7006 else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
7007 DrawChooseTree(&game_speed_current);
7008 else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
7009 DrawChooseTree(&scroll_delay_current);
7010 else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
7011 DrawChooseTree(&snapshot_mode_current);
7012 else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
7013 DrawChooseTree(&window_size_current);
7014 else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
7015 DrawChooseTree(&scaling_type_current);
7016 else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING)
7017 DrawChooseTree(&rendering_mode_current);
7018 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
7019 DrawChooseTree(&artwork.gfx_current);
7020 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
7021 DrawChooseTree(&artwork.snd_current);
7022 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
7023 DrawChooseTree(&artwork.mus_current);
7024 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE)
7025 DrawChooseTree(&volume_simple_current);
7026 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS)
7027 DrawChooseTree(&volume_loops_current);
7028 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
7029 DrawChooseTree(&volume_music_current);
7030 else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL)
7031 DrawChooseTree(&touch_control_current);
7032 else if (setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE)
7033 DrawChooseTree(&move_distance_current);
7034 else if (setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE)
7035 DrawChooseTree(&drop_distance_current);
7037 DrawSetupScreen_Generic();
7039 PlayMenuSoundsAndMusic();
7042 void RedrawSetupScreenAfterFullscreenToggle()
7044 if (setup_mode == SETUP_MODE_GRAPHICS ||
7045 setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
7047 // update list selection from "setup.window_scaling_percent"
7048 execSetupGraphics_setWindowSizes(TRUE);
7054 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
7056 if (setup_mode == SETUP_MODE_INPUT)
7057 HandleSetupScreen_Input(mx, my, dx, dy, button);
7058 else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
7059 HandleChooseTree(mx, my, dx, dy, button, &game_speed_current);
7060 else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
7061 HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
7062 else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
7063 HandleChooseTree(mx, my, dx, dy, button, &snapshot_mode_current);
7064 else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
7065 HandleChooseTree(mx, my, dx, dy, button, &window_size_current);
7066 else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
7067 HandleChooseTree(mx, my, dx, dy, button, &scaling_type_current);
7068 else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING)
7069 HandleChooseTree(mx, my, dx, dy, button, &rendering_mode_current);
7070 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
7071 HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
7072 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
7073 HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
7074 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
7075 HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
7076 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE)
7077 HandleChooseTree(mx, my, dx, dy, button, &volume_simple_current);
7078 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS)
7079 HandleChooseTree(mx, my, dx, dy, button, &volume_loops_current);
7080 else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
7081 HandleChooseTree(mx, my, dx, dy, button, &volume_music_current);
7082 else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL)
7083 HandleChooseTree(mx, my, dx, dy, button, &touch_control_current);
7084 else if (setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE)
7085 HandleChooseTree(mx, my, dx, dy, button, &move_distance_current);
7086 else if (setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE)
7087 HandleChooseTree(mx, my, dx, dy, button, &drop_distance_current);
7089 HandleSetupScreen_Generic(mx, my, dx, dy, button);
7092 void HandleGameActions()
7094 if (game.restart_game_message != NULL)
7095 RequestRestartGame(game.restart_game_message);
7097 if (game_status != GAME_MODE_PLAYING)
7100 GameActions(); /* main game loop */
7102 if (tape.auto_play && !tape.playing)
7103 AutoPlayTape(); /* continue automatically playing next tape */
7107 /* ---------- new screen button stuff -------------------------------------- */
7109 static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
7113 case SCREEN_CTRL_ID_PREV_LEVEL:
7114 *x = mSX + GDI_ACTIVE_POS(menu.main.button.prev_level.x);
7115 *y = mSY + GDI_ACTIVE_POS(menu.main.button.prev_level.y);
7118 case SCREEN_CTRL_ID_NEXT_LEVEL:
7119 *x = mSX + GDI_ACTIVE_POS(menu.main.button.next_level.x);
7120 *y = mSY + GDI_ACTIVE_POS(menu.main.button.next_level.y);
7123 case SCREEN_CTRL_ID_PREV_PLAYER:
7124 *x = mSX + TILEX * 10;
7125 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
7128 case SCREEN_CTRL_ID_NEXT_PLAYER:
7129 *x = mSX + TILEX * 12;
7130 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
7134 Error(ERR_EXIT, "unknown gadget ID %d", gadget_id);
7140 int gfx_unpressed, gfx_pressed;
7141 void (*get_gadget_position)(int *, int *, int);
7145 } menubutton_info[NUM_SCREEN_MENUBUTTONS] =
7148 IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE,
7149 getScreenMenuButtonPos,
7150 SCREEN_CTRL_ID_PREV_LEVEL,
7155 IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE,
7156 getScreenMenuButtonPos,
7157 SCREEN_CTRL_ID_NEXT_LEVEL,
7162 IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE,
7163 getScreenMenuButtonPos,
7164 SCREEN_CTRL_ID_PREV_PLAYER,
7169 IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE,
7170 getScreenMenuButtonPos,
7171 SCREEN_CTRL_ID_NEXT_PLAYER,
7179 int gfx_unpressed, gfx_pressed;
7183 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
7186 IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
7187 -1, -1, /* these values are not constant, but can change at runtime */
7188 SCREEN_CTRL_ID_SCROLL_UP,
7192 IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
7193 -1, -1, /* these values are not constant, but can change at runtime */
7194 SCREEN_CTRL_ID_SCROLL_DOWN,
7201 int gfx_unpressed, gfx_pressed;
7207 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
7210 IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
7211 -1, -1, /* these values are not constant, but can change at runtime */
7212 -1, -1, /* these values are not constant, but can change at runtime */
7213 GD_TYPE_SCROLLBAR_VERTICAL,
7214 SCREEN_CTRL_ID_SCROLL_VERTICAL,
7215 "scroll level series vertically"
7219 static void CreateScreenMenubuttons()
7221 struct GadgetInfo *gi;
7222 unsigned int event_mask;
7225 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
7227 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
7228 int gfx_unpressed, gfx_pressed;
7229 int x, y, width, height;
7230 int gd_x1, gd_x2, gd_y1, gd_y2;
7231 int id = menubutton_info[i].gadget_id;
7233 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7235 menubutton_info[i].get_gadget_position(&x, &y, id);
7237 width = SC_MENUBUTTON_XSIZE;
7238 height = SC_MENUBUTTON_YSIZE;
7240 gfx_unpressed = menubutton_info[i].gfx_unpressed;
7241 gfx_pressed = menubutton_info[i].gfx_pressed;
7242 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
7243 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
7244 gd_x1 = graphic_info[gfx_unpressed].src_x;
7245 gd_y1 = graphic_info[gfx_unpressed].src_y;
7246 gd_x2 = graphic_info[gfx_pressed].src_x;
7247 gd_y2 = graphic_info[gfx_pressed].src_y;
7249 gi = CreateGadget(GDI_CUSTOM_ID, id,
7250 GDI_CUSTOM_TYPE_ID, i,
7251 GDI_INFO_TEXT, menubutton_info[i].infotext,
7256 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7257 GDI_STATE, GD_BUTTON_UNPRESSED,
7258 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
7259 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
7260 GDI_DIRECT_DRAW, FALSE,
7261 GDI_EVENT_MASK, event_mask,
7262 GDI_CALLBACK_ACTION, HandleScreenGadgets,
7266 Error(ERR_EXIT, "cannot create gadget");
7268 screen_gadget[id] = gi;
7272 static void CreateScreenScrollbuttons()
7274 struct GadgetInfo *gi;
7275 unsigned int event_mask;
7278 /* these values are not constant, but can change at runtime */
7279 scrollbutton_info[0].x = SC_SCROLL_UP_XPOS;
7280 scrollbutton_info[0].y = SC_SCROLL_UP_YPOS;
7281 scrollbutton_info[1].x = SC_SCROLL_DOWN_XPOS;
7282 scrollbutton_info[1].y = SC_SCROLL_DOWN_YPOS;
7284 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
7286 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
7287 int gfx_unpressed, gfx_pressed;
7288 int x, y, width, height;
7289 int gd_x1, gd_x2, gd_y1, gd_y2;
7290 int id = scrollbutton_info[i].gadget_id;
7292 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7294 x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset;
7295 y = mSY + scrollbutton_info[i].y;
7296 width = SC_SCROLLBUTTON_XSIZE;
7297 height = SC_SCROLLBUTTON_YSIZE;
7299 /* correct scrollbar position if placed outside menu (playfield) area */
7300 if (x > SX + SC_SCROLL_UP_XPOS)
7301 x = SX + SC_SCROLL_UP_XPOS;
7303 if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
7304 y = mSY + (SC_SCROLL_VERTICAL_YPOS +
7305 (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE);
7307 gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
7308 gfx_pressed = scrollbutton_info[i].gfx_pressed;
7309 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
7310 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
7311 gd_x1 = graphic_info[gfx_unpressed].src_x;
7312 gd_y1 = graphic_info[gfx_unpressed].src_y;
7313 gd_x2 = graphic_info[gfx_pressed].src_x;
7314 gd_y2 = graphic_info[gfx_pressed].src_y;
7316 gi = CreateGadget(GDI_CUSTOM_ID, id,
7317 GDI_CUSTOM_TYPE_ID, i,
7318 GDI_INFO_TEXT, scrollbutton_info[i].infotext,
7323 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7324 GDI_STATE, GD_BUTTON_UNPRESSED,
7325 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
7326 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
7327 GDI_DIRECT_DRAW, FALSE,
7328 GDI_EVENT_MASK, event_mask,
7329 GDI_CALLBACK_ACTION, HandleScreenGadgets,
7333 Error(ERR_EXIT, "cannot create gadget");
7335 screen_gadget[id] = gi;
7339 static void CreateScreenScrollbars()
7343 /* these values are not constant, but can change at runtime */
7344 scrollbar_info[0].x = SC_SCROLL_VERTICAL_XPOS;
7345 scrollbar_info[0].y = SC_SCROLL_VERTICAL_YPOS;
7346 scrollbar_info[0].width = SC_SCROLL_VERTICAL_XSIZE;
7347 scrollbar_info[0].height = SC_SCROLL_VERTICAL_YSIZE;
7349 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
7351 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
7352 int gfx_unpressed, gfx_pressed;
7353 int x, y, width, height;
7354 int gd_x1, gd_x2, gd_y1, gd_y2;
7355 struct GadgetInfo *gi;
7356 int items_max, items_visible, item_position;
7357 unsigned int event_mask;
7358 int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
7359 int id = scrollbar_info[i].gadget_id;
7361 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
7363 x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset;
7364 y = mSY + scrollbar_info[i].y;
7365 width = scrollbar_info[i].width;
7366 height = scrollbar_info[i].height;
7368 /* correct scrollbar position if placed outside menu (playfield) area */
7369 if (x > SX + SC_SCROLL_VERTICAL_XPOS)
7370 x = SX + SC_SCROLL_VERTICAL_XPOS;
7372 if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
7373 height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;
7375 items_max = num_page_entries;
7376 items_visible = num_page_entries;
7379 gfx_unpressed = scrollbar_info[i].gfx_unpressed;
7380 gfx_pressed = scrollbar_info[i].gfx_pressed;
7381 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
7382 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
7383 gd_x1 = graphic_info[gfx_unpressed].src_x;
7384 gd_y1 = graphic_info[gfx_unpressed].src_y;
7385 gd_x2 = graphic_info[gfx_pressed].src_x;
7386 gd_y2 = graphic_info[gfx_pressed].src_y;
7388 gi = CreateGadget(GDI_CUSTOM_ID, id,
7389 GDI_CUSTOM_TYPE_ID, i,
7390 GDI_INFO_TEXT, scrollbar_info[i].infotext,
7395 GDI_TYPE, scrollbar_info[i].type,
7396 GDI_SCROLLBAR_ITEMS_MAX, items_max,
7397 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
7398 GDI_SCROLLBAR_ITEM_POSITION, item_position,
7399 GDI_WHEEL_AREA_X, SX,
7400 GDI_WHEEL_AREA_Y, SY,
7401 GDI_WHEEL_AREA_WIDTH, SXSIZE,
7402 GDI_WHEEL_AREA_HEIGHT, SYSIZE,
7403 GDI_STATE, GD_BUTTON_UNPRESSED,
7404 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
7405 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
7406 GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
7407 GDI_DIRECT_DRAW, FALSE,
7408 GDI_EVENT_MASK, event_mask,
7409 GDI_CALLBACK_ACTION, HandleScreenGadgets,
7413 Error(ERR_EXIT, "cannot create gadget");
7415 screen_gadget[id] = gi;
7419 void CreateScreenGadgets()
7421 CreateScreenMenubuttons();
7423 CreateScreenScrollbuttons();
7424 CreateScreenScrollbars();
7427 void FreeScreenGadgets()
7431 for (i = 0; i < NUM_SCREEN_GADGETS; i++)
7432 FreeGadget(screen_gadget[i]);
7435 void MapScreenMenuGadgets(int screen_mask)
7439 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
7440 if (screen_mask & menubutton_info[i].screen_mask)
7441 MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
7444 void MapScreenGadgets(int num_entries)
7448 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
7451 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
7452 MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
7454 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
7455 MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
7458 void MapScreenTreeGadgets(TreeInfo *ti)
7460 MapScreenGadgets(numTreeInfoInGroup(ti));
7463 static void HandleScreenGadgets(struct GadgetInfo *gi)
7465 int id = gi->custom_id;
7466 int button = gi->event.button;
7467 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
7471 case SCREEN_CTRL_ID_PREV_LEVEL:
7472 HandleMainMenu_SelectLevel(step, -1, NO_DIRECT_LEVEL_SELECT);
7475 case SCREEN_CTRL_ID_NEXT_LEVEL:
7476 HandleMainMenu_SelectLevel(step, +1, NO_DIRECT_LEVEL_SELECT);
7479 case SCREEN_CTRL_ID_PREV_PLAYER:
7480 HandleSetupScreen_Input_Player(step, -1);
7483 case SCREEN_CTRL_ID_NEXT_PLAYER:
7484 HandleSetupScreen_Input_Player(step, +1);
7487 case SCREEN_CTRL_ID_SCROLL_UP:
7488 if (game_status == GAME_MODE_LEVELS)
7489 HandleChooseLevelSet(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
7490 else if (game_status == GAME_MODE_LEVELNR)
7491 HandleChooseLevelNr(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
7492 else if (game_status == GAME_MODE_SETUP)
7493 HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
7494 else if (game_status == GAME_MODE_INFO)
7495 HandleInfoScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
7498 case SCREEN_CTRL_ID_SCROLL_DOWN:
7499 if (game_status == GAME_MODE_LEVELS)
7500 HandleChooseLevelSet(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
7501 else if (game_status == GAME_MODE_LEVELNR)
7502 HandleChooseLevelNr(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
7503 else if (game_status == GAME_MODE_SETUP)
7504 HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
7505 else if (game_status == GAME_MODE_INFO)
7506 HandleInfoScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
7509 case SCREEN_CTRL_ID_SCROLL_VERTICAL:
7510 if (game_status == GAME_MODE_LEVELS)
7511 HandleChooseLevelSet(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE);
7512 else if (game_status == GAME_MODE_LEVELNR)
7513 HandleChooseLevelNr(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE);
7514 else if (game_status == GAME_MODE_SETUP)
7515 HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
7516 else if (game_status == GAME_MODE_INFO)
7517 HandleInfoScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);