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_VSYNC 22
72 #define SETUP_MODE_CHOOSE_GRAPHICS 23
73 #define SETUP_MODE_CHOOSE_SOUNDS 24
74 #define SETUP_MODE_CHOOSE_MUSIC 25
75 #define SETUP_MODE_CHOOSE_VOLUME_SIMPLE 26
76 #define SETUP_MODE_CHOOSE_VOLUME_LOOPS 27
77 #define SETUP_MODE_CHOOSE_VOLUME_MUSIC 28
78 #define SETUP_MODE_CHOOSE_TOUCH_CONTROL 29
79 #define SETUP_MODE_CHOOSE_MOVE_DISTANCE 30
80 #define SETUP_MODE_CHOOSE_DROP_DISTANCE 31
81 #define SETUP_MODE_CHOOSE_TRANSPARENCY 32
82 #define SETUP_MODE_CHOOSE_GRID_XSIZE_0 33
83 #define SETUP_MODE_CHOOSE_GRID_YSIZE_0 34
84 #define SETUP_MODE_CHOOSE_GRID_XSIZE_1 35
85 #define SETUP_MODE_CHOOSE_GRID_YSIZE_1 36
86 #define SETUP_MODE_CONFIG_VIRT_BUTTONS 37
88 #define MAX_SETUP_MODES 38
90 #define MAX_MENU_MODES MAX(MAX_INFO_MODES, MAX_SETUP_MODES)
92 /* setup screen titles */
93 #define STR_SETUP_MAIN "Setup"
94 #define STR_SETUP_GAME "Game & Menu"
95 #define STR_SETUP_EDITOR "Editor"
96 #define STR_SETUP_GRAPHICS "Graphics"
97 #define STR_SETUP_SOUND "Sound & Music"
98 #define STR_SETUP_ARTWORK "Custom Artwork"
99 #define STR_SETUP_INPUT "Input Devices"
100 #define STR_SETUP_TOUCH "Touch Controls"
101 #define STR_SETUP_SHORTCUTS "Key Shortcuts"
102 #define STR_SETUP_EXIT "Exit"
103 #define STR_SETUP_SAVE_AND_EXIT "Save and Exit"
105 #define STR_SETUP_CHOOSE_GAME_SPEED "Game Speed"
106 #define STR_SETUP_CHOOSE_SCROLL_DELAY "Scroll Delay"
107 #define STR_SETUP_CHOOSE_SNAPSHOT_MODE "Snapshot Mode"
108 #define STR_SETUP_CHOOSE_WINDOW_SIZE "Window Scaling"
109 #define STR_SETUP_CHOOSE_SCALING_TYPE "Anti-Aliasing"
110 #define STR_SETUP_CHOOSE_RENDERING "Rendering Mode"
111 #define STR_SETUP_CHOOSE_VSYNC "VSync Mode"
112 #define STR_SETUP_CHOOSE_VOLUME_SIMPLE "Sound Volume"
113 #define STR_SETUP_CHOOSE_VOLUME_LOOPS "Loops Volume"
114 #define STR_SETUP_CHOOSE_VOLUME_MUSIC "Music Volume"
115 #define STR_SETUP_CHOOSE_TOUCH_CONTROL "Control Type"
116 #define STR_SETUP_CHOOSE_MOVE_DISTANCE "Move Distance"
117 #define STR_SETUP_CHOOSE_DROP_DISTANCE "Drop Distance"
118 #define STR_SETUP_CHOOSE_TRANSPARENCY "Transparency"
119 #define STR_SETUP_CHOOSE_GRID_XSIZE_0 "Horiz. Buttons"
120 #define STR_SETUP_CHOOSE_GRID_YSIZE_0 "Vert. Buttons"
121 #define STR_SETUP_CHOOSE_GRID_XSIZE_1 "Horiz. Buttons"
122 #define STR_SETUP_CHOOSE_GRID_YSIZE_1 "Vert. Buttons"
124 /* for input setup functions */
125 #define SETUPINPUT_SCREEN_POS_START 0
126 #define SETUPINPUT_SCREEN_POS_EMPTY1 3
127 #define SETUPINPUT_SCREEN_POS_EMPTY2 12
128 #define SETUPINPUT_SCREEN_POS_END 13
130 #define MENU_SETUP_FONT_TITLE FONT_TEXT_1
131 #define MENU_SETUP_FONT_TEXT FONT_TITLE_2
133 #define MAX_SETUP_TEXT_INPUT_LEN 28
135 /* for various menu stuff */
136 #define MENU_SCREEN_START_XPOS 1
137 #define MENU_SCREEN_START_YPOS 2
138 #define MENU_SCREEN_VALUE_XPOS (SCR_FIELDX - 3)
139 #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1)
140 #define MENU_TITLE1_YPOS 8
141 #define MENU_TITLE2_YPOS 46
142 #define MENU_INFO_FONT_TITLE FONT_TEXT_1
143 #define MENU_INFO_FONT_HEAD FONT_TEXT_2
144 #define MENU_INFO_FONT_TEXT FONT_TEXT_3
145 #define MENU_INFO_FONT_FOOT FONT_TEXT_4
146 #define MENU_INFO_SPACE_HEAD (menu.headline2_spacing_info[info_mode])
147 #define MENU_SCREEN_INFO_SPACE_LEFT (menu.left_spacing_info[info_mode])
148 #define MENU_SCREEN_INFO_SPACE_RIGHT (menu.right_spacing_info[info_mode])
149 #define MENU_SCREEN_INFO_SPACE_TOP (menu.top_spacing_info[info_mode])
150 #define MENU_SCREEN_INFO_SPACE_BOTTOM (menu.bottom_spacing_info[info_mode])
151 #define MENU_SCREEN_INFO_YSTART1 MENU_SCREEN_INFO_SPACE_TOP
152 #define MENU_SCREEN_INFO_YSTART2 (MENU_SCREEN_INFO_YSTART1 + \
153 getMenuTextStep(MENU_INFO_SPACE_HEAD, \
154 MENU_INFO_FONT_TITLE))
155 #define MENU_SCREEN_INFO_YSTEP (TILEY + 4)
156 #define MENU_SCREEN_INFO_YBOTTOM (SYSIZE - MENU_SCREEN_INFO_SPACE_BOTTOM)
157 #define MENU_SCREEN_INFO_YSIZE (MENU_SCREEN_INFO_YBOTTOM - \
158 MENU_SCREEN_INFO_YSTART2 - \
160 #define MAX_INFO_ELEMENTS_ON_SCREEN 128
161 #define STD_INFO_ELEMENTS_ON_SCREEN (MENU_SCREEN_INFO_YSIZE / \
162 MENU_SCREEN_INFO_YSTEP)
163 #define NUM_INFO_ELEMENTS_FROM_CONF \
164 (menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] > 0 ? \
165 menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] : \
166 MAX_MENU_ENTRIES_ON_SCREEN)
167 #define NUM_INFO_ELEMENTS_ON_SCREEN MIN(MIN(STD_INFO_ELEMENTS_ON_SCREEN, \
168 MAX_INFO_ELEMENTS_ON_SCREEN), \
169 NUM_INFO_ELEMENTS_FROM_CONF)
170 #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS)
171 #define MAX_MENU_TEXT_LENGTH_BIG 13
172 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2)
174 /* screen gadget identifiers */
175 #define SCREEN_CTRL_ID_PREV_LEVEL 0
176 #define SCREEN_CTRL_ID_NEXT_LEVEL 1
177 #define SCREEN_CTRL_ID_PREV_PLAYER 2
178 #define SCREEN_CTRL_ID_NEXT_PLAYER 3
179 #define SCREEN_CTRL_ID_INSERT_SOLUTION 4
180 #define SCREEN_CTRL_ID_PLAY_SOLUTION 5
181 #define SCREEN_CTRL_ID_SCROLL_UP 6
182 #define SCREEN_CTRL_ID_SCROLL_DOWN 7
183 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 8
184 #define SCREEN_CTRL_ID_NETWORK_SERVER 9
186 #define NUM_SCREEN_GADGETS 10
188 #define NUM_SCREEN_MENUBUTTONS 6
189 #define NUM_SCREEN_SCROLLBUTTONS 2
190 #define NUM_SCREEN_SCROLLBARS 1
191 #define NUM_SCREEN_TEXTINPUT 1
193 #define SCREEN_MASK_MAIN (1 << 0)
194 #define SCREEN_MASK_MAIN_HAS_SOLUTION (1 << 1)
195 #define SCREEN_MASK_INPUT (1 << 2)
197 /* graphic position and size values for buttons and scrollbars */
198 #define SC_MENUBUTTON_XSIZE TILEX
199 #define SC_MENUBUTTON_YSIZE TILEY
201 #define SC_SCROLLBUTTON_XSIZE TILEX
202 #define SC_SCROLLBUTTON_YSIZE TILEY
204 #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
206 #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
207 #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
208 SC_SCROLLBUTTON_YSIZE)
210 #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS
211 #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE)
213 #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS
214 #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \
215 SC_SCROLLBUTTON_YSIZE)
217 #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS
218 #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \
219 SC_SCROLL_VERTICAL_YSIZE)
221 #define SC_BORDER_SIZE 14
224 /* forward declarations of internal functions */
225 static void HandleScreenGadgets(struct GadgetInfo *);
226 static void HandleSetupScreen_Generic(int, int, int, int, int);
227 static void HandleSetupScreen_Input(int, int, int, int, int);
228 static void CustomizeKeyboard(int);
229 static void ConfigureJoystick(int);
230 static void ConfigureVirtualButtons(void);
231 static void execSetupGame(void);
232 static void execSetupGraphics(void);
233 static void execSetupSound(void);
234 static void execSetupTouch(void);
235 static void execSetupArtwork(void);
236 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
238 static void DrawChooseLevelSet(void);
239 static void DrawChooseLevelNr(void);
240 static void DrawInfoScreen(void);
241 static void DrawSetupScreen(void);
243 static void DrawInfoScreen_NotAvailable(char *, char *);
244 static void DrawInfoScreen_HelpAnim(int, int, boolean);
245 static void DrawInfoScreen_HelpText(int, int, int, int);
246 static void HandleInfoScreen_Main(int, int, int, int, int);
247 static void HandleInfoScreen_TitleScreen(int);
248 static void HandleInfoScreen_Elements(int);
249 static void HandleInfoScreen_Music(int);
250 static void HandleInfoScreen_Credits(int);
251 static void HandleInfoScreen_Program(int);
252 static void HandleInfoScreen_Version(int);
254 static void MapScreenMenuGadgets(int);
255 static void MapScreenGadgets(int);
256 static void MapScreenTreeGadgets(TreeInfo *);
258 static void UpdateScreenMenuGadgets(int, boolean);
260 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
262 static int info_mode = INFO_MODE_MAIN;
263 static int setup_mode = SETUP_MODE_MAIN;
265 static TreeInfo *window_sizes = NULL;
266 static TreeInfo *window_size_current = NULL;
268 static TreeInfo *scaling_types = NULL;
269 static TreeInfo *scaling_type_current = NULL;
271 static TreeInfo *rendering_modes = NULL;
272 static TreeInfo *rendering_mode_current = NULL;
274 static TreeInfo *vsync_modes = NULL;
275 static TreeInfo *vsync_mode_current = NULL;
277 static TreeInfo *scroll_delays = NULL;
278 static TreeInfo *scroll_delay_current = NULL;
280 static TreeInfo *snapshot_modes = NULL;
281 static TreeInfo *snapshot_mode_current = NULL;
283 static TreeInfo *game_speeds = NULL;
284 static TreeInfo *game_speed_current = NULL;
286 static TreeInfo *volumes_simple = NULL;
287 static TreeInfo *volume_simple_current = NULL;
289 static TreeInfo *volumes_loops = NULL;
290 static TreeInfo *volume_loops_current = NULL;
292 static TreeInfo *volumes_music = NULL;
293 static TreeInfo *volume_music_current = NULL;
295 static TreeInfo *touch_controls = NULL;
296 static TreeInfo *touch_control_current = NULL;
298 static TreeInfo *move_distances = NULL;
299 static TreeInfo *move_distance_current = NULL;
301 static TreeInfo *drop_distances = NULL;
302 static TreeInfo *drop_distance_current = NULL;
304 static TreeInfo *transparencies = NULL;
305 static TreeInfo *transparency_current = NULL;
307 static TreeInfo *grid_sizes[2][2] = { { NULL, NULL }, { NULL, NULL } };
308 static TreeInfo *grid_size_current[2][2] = { { NULL, NULL }, { NULL, NULL } };
310 static TreeInfo *level_number = NULL;
311 static TreeInfo *level_number_current = NULL;
317 } window_sizes_list[] =
322 { 100, "100 % (Default)" },
339 } scaling_types_list[] =
341 { SCALING_QUALITY_NEAREST, "Off" },
342 { SCALING_QUALITY_LINEAR, "Linear" },
343 { SCALING_QUALITY_BEST, "Anisotropic" },
352 } rendering_modes_list[] =
354 { STR_SPECIAL_RENDERING_OFF, "Off (May show artifacts, fast)" },
355 { STR_SPECIAL_RENDERING_BITMAP, "Bitmap/Texture mode (slower)" },
357 // this mode may work under certain conditions, but does not work on Windows
358 { STR_SPECIAL_RENDERING_TARGET, "Target Texture mode (slower)" },
360 { STR_SPECIAL_RENDERING_DOUBLE, "Double Texture mode (slower)" },
369 } vsync_modes_list[] =
371 { STR_VSYNC_MODE_OFF, "Off" },
372 { STR_VSYNC_MODE_NORMAL, "Normal" },
373 { STR_VSYNC_MODE_ADAPTIVE, "Adaptive" },
382 } game_speeds_list[] =
391 { 1000, "1/1s (Extremely Slow)" },
396 { 29, "1/35s (Original Supaplex)" },
398 { 20, "1/50s (Normal Speed)" },
399 { 14, "1/70s (Maximum Supaplex)" },
403 { 1, "1/1000s (Extremely Fast)" },
413 } scroll_delays_list[] =
415 { 0, "0 Tiles (No Scroll Delay)" },
418 { 3, "3 Tiles (Default)" },
423 { 8, "8 Tiles (Maximum Scroll Delay)"},
432 } snapshot_modes_list[] =
434 { STR_SNAPSHOT_MODE_OFF, "Off" },
435 { STR_SNAPSHOT_MODE_EVERY_STEP, "Every Step" },
436 { STR_SNAPSHOT_MODE_EVERY_MOVE, "Every Move" },
437 { STR_SNAPSHOT_MODE_EVERY_COLLECT, "Every Collect" },
470 } touch_controls_list[] =
472 { TOUCH_CONTROL_OFF, "Off" },
473 { TOUCH_CONTROL_VIRTUAL_BUTTONS, "Virtual Buttons" },
474 { TOUCH_CONTROL_WIPE_GESTURES, "Wipe Gestures" },
475 { TOUCH_CONTROL_FOLLOW_FINGER, "Follow Finger" },
503 } transparencies_list[] =
505 { 0, "0 % (Opaque)" },
515 { 100, "100 % (Invisible)" },
524 } grid_sizes_list[] =
560 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
561 (s) <= GAME_MODE_SETUP ? (s) : \
562 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
563 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
565 /* (there are no draw offset definitions needed for INFO_MODE_TITLE) */
566 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_TITLE && \
567 (i) <= INFO_MODE_LEVELSET ? (i) : \
570 #define DRAW_MODE_SETUP(i) ((i) >= SETUP_MODE_MAIN && \
571 (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) : \
572 (i) >= SETUP_MODE_CHOOSE_GRAPHICS && \
573 (i) <= SETUP_MODE_CHOOSE_MUSIC ? \
574 SETUP_MODE_CHOOSE_ARTWORK : \
575 SETUP_MODE_CHOOSE_OTHER)
577 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
578 menu.draw_xoffset[GAME_MODE_INFO] : \
579 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
580 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
581 menu.draw_yoffset[GAME_MODE_INFO] : \
582 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
583 #define EXTRA_SPACING_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
584 menu.extra_spacing[GAME_MODE_INFO] : \
585 menu.extra_spacing_info[DRAW_MODE_INFO(i)])
587 #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
588 menu.draw_xoffset[GAME_MODE_SETUP] : \
589 menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)])
590 #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
591 menu.draw_yoffset[GAME_MODE_SETUP] : \
592 menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)])
593 #define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
594 menu.extra_spacing[GAME_MODE_SETUP] : \
595 menu.extra_spacing_setup[DRAW_MODE_SETUP(i)])
597 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
598 DRAW_XOFFSET_INFO(info_mode) : \
599 (s) == GAME_MODE_SETUP ? \
600 DRAW_XOFFSET_SETUP(setup_mode) : \
601 menu.draw_xoffset[DRAW_MODE(s)])
602 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
603 DRAW_YOFFSET_INFO(info_mode) : \
604 (s) == GAME_MODE_SETUP ? \
605 DRAW_YOFFSET_SETUP(setup_mode) : \
606 menu.draw_yoffset[DRAW_MODE(s)])
607 #define EXTRA_SPACING(s) ((s) == GAME_MODE_INFO ? \
608 EXTRA_SPACING_INFO(info_mode) : \
609 (s) == GAME_MODE_SETUP ? \
610 EXTRA_SPACING_SETUP(setup_mode) : \
611 menu.extra_spacing[DRAW_MODE(s)])
613 #define mSX (SX + DRAW_XOFFSET(game_status))
614 #define mSY (SY + DRAW_YOFFSET(game_status))
616 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
617 menu.list_size[game_status] : \
618 MAX_MENU_ENTRIES_ON_SCREEN)
620 #define IN_VIS_MENU(x, y) IN_FIELD(x, y, SCR_FIELDX, \
621 NUM_MENU_ENTRIES_ON_SCREEN)
624 /* title display and control definitions */
626 #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \
627 2 * MAX_NUM_TITLE_MESSAGES)
629 #define NO_DIRECT_LEVEL_SELECT (-1)
632 static int num_title_screens = 0;
634 struct TitleControlInfo
643 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
645 /* main menu display and control definitions */
647 #define MAIN_CONTROL_NAME 0
648 #define MAIN_CONTROL_LEVELS 1
649 #define MAIN_CONTROL_SCORES 2
650 #define MAIN_CONTROL_EDITOR 3
651 #define MAIN_CONTROL_INFO 4
652 #define MAIN_CONTROL_GAME 5
653 #define MAIN_CONTROL_SETUP 6
654 #define MAIN_CONTROL_QUIT 7
655 #define MAIN_CONTROL_PREV_LEVEL 8
656 #define MAIN_CONTROL_NEXT_LEVEL 9
657 #define MAIN_CONTROL_FIRST_LEVEL 10
658 #define MAIN_CONTROL_LAST_LEVEL 11
659 #define MAIN_CONTROL_LEVEL_NUMBER 12
660 #define MAIN_CONTROL_LEVEL_INFO_1 13
661 #define MAIN_CONTROL_LEVEL_INFO_2 14
662 #define MAIN_CONTROL_LEVEL_NAME 15
663 #define MAIN_CONTROL_LEVEL_AUTHOR 16
664 #define MAIN_CONTROL_LEVEL_YEAR 17
665 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM 18
666 #define MAIN_CONTROL_LEVEL_IMPORTED_BY 19
667 #define MAIN_CONTROL_LEVEL_TESTED_BY 20
668 #define MAIN_CONTROL_TITLE_1 21
669 #define MAIN_CONTROL_TITLE_2 22
670 #define MAIN_CONTROL_TITLE_3 23
672 static char str_main_text_name[10];
673 static char str_main_text_first_level[10];
674 static char str_main_text_last_level[10];
675 static char str_main_text_level_number[10];
677 static char network_server_hostname[MAX_SETUP_TEXT_INPUT_LEN + 1];
679 static char *main_text_name = str_main_text_name;
680 static char *main_text_first_level = str_main_text_first_level;
681 static char *main_text_last_level = str_main_text_last_level;
682 static char *main_text_level_number = str_main_text_level_number;
683 static char *main_text_levels = "Levelset";
684 static char *main_text_scores = "Hall Of Fame";
685 static char *main_text_editor = "Level Creator";
686 static char *main_text_info = "Info Screen";
687 static char *main_text_game = "Start Game";
688 static char *main_text_setup = "Setup";
689 static char *main_text_quit = "Quit";
690 static char *main_text_level_name = level.name;
691 static char *main_text_level_author = level.author;
692 static char *main_text_level_year = NULL;
693 static char *main_text_level_imported_from = NULL;
694 static char *main_text_level_imported_by = NULL;
695 static char *main_text_level_tested_by = NULL;
696 static char *main_text_title_1 = NULL;
697 static char *main_text_title_2 = NULL;
698 static char *main_text_title_3 = NULL;
700 struct MainControlInfo
704 struct MenuPosInfo *pos_button;
707 struct TextPosInfo *pos_text;
710 struct TextPosInfo *pos_input;
714 static struct MainControlInfo main_controls[] =
718 &menu.main.button.name, IMG_MENU_BUTTON_NAME,
719 &menu.main.text.name, &main_text_name,
720 &menu.main.input.name, &setup.player_name,
724 &menu.main.button.levels, IMG_MENU_BUTTON_LEVELS,
725 &menu.main.text.levels, &main_text_levels,
730 &menu.main.button.scores, IMG_MENU_BUTTON_SCORES,
731 &menu.main.text.scores, &main_text_scores,
736 &menu.main.button.editor, IMG_MENU_BUTTON_EDITOR,
737 &menu.main.text.editor, &main_text_editor,
742 &menu.main.button.info, IMG_MENU_BUTTON_INFO,
743 &menu.main.text.info, &main_text_info,
748 &menu.main.button.game, IMG_MENU_BUTTON_GAME,
749 &menu.main.text.game, &main_text_game,
754 &menu.main.button.setup, IMG_MENU_BUTTON_SETUP,
755 &menu.main.text.setup, &main_text_setup,
760 &menu.main.button.quit, IMG_MENU_BUTTON_QUIT,
761 &menu.main.text.quit, &main_text_quit,
765 /* (these two buttons are real gadgets) */
767 MAIN_CONTROL_PREV_LEVEL,
768 &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL,
773 MAIN_CONTROL_NEXT_LEVEL,
774 &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL,
780 MAIN_CONTROL_FIRST_LEVEL,
781 &menu.main.button.first_level, IMG_MENU_BUTTON_FIRST_LEVEL,
782 &menu.main.text.first_level, &main_text_first_level,
786 MAIN_CONTROL_LAST_LEVEL,
787 &menu.main.button.last_level, IMG_MENU_BUTTON_LAST_LEVEL,
788 &menu.main.text.last_level, &main_text_last_level,
792 MAIN_CONTROL_LEVEL_NUMBER,
793 &menu.main.button.level_number, IMG_MENU_BUTTON_LEVEL_NUMBER,
794 &menu.main.text.level_number, &main_text_level_number,
798 MAIN_CONTROL_LEVEL_INFO_1,
800 &menu.main.text.level_info_1, NULL,
804 MAIN_CONTROL_LEVEL_INFO_2,
806 &menu.main.text.level_info_2, NULL,
810 MAIN_CONTROL_LEVEL_NAME,
812 &menu.main.text.level_name, &main_text_level_name,
816 MAIN_CONTROL_LEVEL_AUTHOR,
818 &menu.main.text.level_author, &main_text_level_author,
822 MAIN_CONTROL_LEVEL_YEAR,
824 &menu.main.text.level_year, &main_text_level_year,
828 MAIN_CONTROL_LEVEL_IMPORTED_FROM,
830 &menu.main.text.level_imported_from, &main_text_level_imported_from,
834 MAIN_CONTROL_LEVEL_IMPORTED_BY,
836 &menu.main.text.level_imported_by, &main_text_level_imported_by,
840 MAIN_CONTROL_LEVEL_TESTED_BY,
842 &menu.main.text.level_tested_by, &main_text_level_tested_by,
846 MAIN_CONTROL_TITLE_1,
848 &menu.main.text.title_1, &main_text_title_1,
852 MAIN_CONTROL_TITLE_2,
854 &menu.main.text.title_2, &main_text_title_2,
858 MAIN_CONTROL_TITLE_3,
860 &menu.main.text.title_3, &main_text_title_3,
873 static int getTitleScreenGraphic(int nr, boolean initial)
875 return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
878 static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial)
880 return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]);
884 static int getTitleScreenGameMode(boolean initial)
886 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
890 static int getTitleMessageGameMode(boolean initial)
892 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
895 static int getTitleAnimMode(struct TitleControlInfo *tci)
897 int base = (tci->initial ? GAME_MODE_TITLE_INITIAL_1 : GAME_MODE_TITLE_1);
899 return base + tci->local_nr;
903 static int getTitleScreenBackground(boolean initial)
905 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
910 static int getTitleMessageBackground(int nr, boolean initial)
912 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
916 static int getTitleBackground(int nr, boolean initial, boolean is_image)
918 int base = (is_image ?
919 (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 :
920 IMG_BACKGROUND_TITLESCREEN_1) :
921 (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
922 IMG_BACKGROUND_TITLEMESSAGE_1));
923 int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL :
924 IMG_BACKGROUND_TITLE);
925 int graphic_local = base + nr;
927 if (graphic_info[graphic_local].bitmap != NULL)
928 return graphic_local;
930 if (graphic_info[graphic_global].bitmap != NULL)
931 return graphic_global;
933 return IMG_UNDEFINED;
936 static int getTitleSound(struct TitleControlInfo *tci)
938 boolean is_image = tci->is_image;
939 int initial = tci->initial;
940 int nr = tci->local_nr;
941 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
942 int base = (is_image ?
943 (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 :
944 SND_BACKGROUND_TITLESCREEN_1) :
945 (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
946 SND_BACKGROUND_TITLEMESSAGE_1));
947 int sound_global = menu.sound[mode];
948 int sound_local = base + nr;
951 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
952 nr, initial, is_image,
953 sound_global, getSoundListEntry(sound_global)->filename,
954 sound_local, getSoundListEntry(sound_local)->filename);
957 if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME))
960 if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME))
963 return SND_UNDEFINED;
966 static int getTitleMusic(struct TitleControlInfo *tci)
968 boolean is_image = tci->is_image;
969 int initial = tci->initial;
970 int nr = tci->local_nr;
971 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
972 int base = (is_image ?
973 (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 :
974 MUS_BACKGROUND_TITLESCREEN_1) :
975 (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
976 MUS_BACKGROUND_TITLEMESSAGE_1));
977 int music_global = menu.music[mode];
978 int music_local = base + nr;
981 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
982 nr, initial, is_image,
983 music_global, getMusicListEntry(music_global)->filename,
984 music_local, getMusicListEntry(music_local)->filename);
987 if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME))
990 if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME))
993 return MUS_UNDEFINED;
996 static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci)
998 boolean is_image = tci->is_image;
999 boolean initial = tci->initial;
1000 boolean first = tci->first;
1001 int nr = tci->local_nr;
1002 struct TitleMessageInfo tmi;
1003 struct TitleFadingInfo ti;
1005 tmi = (is_image ? (initial ? (first ?
1006 titlescreen_initial_first[nr] :
1007 titlescreen_initial[nr])
1009 titlescreen_first[nr] :
1011 : (initial ? (first ?
1012 titlemessage_initial_first[nr] :
1013 titlemessage_initial[nr])
1015 titlemessage_first[nr] :
1016 titlemessage[nr])));
1018 ti.fade_mode = tmi.fade_mode;
1019 ti.fade_delay = tmi.fade_delay;
1020 ti.post_delay = tmi.post_delay;
1021 ti.auto_delay = tmi.auto_delay;
1026 static int compareTitleControlInfo(const void *object1, const void *object2)
1028 const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1;
1029 const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2;
1032 if (tci1->initial != tci2->initial)
1033 compare_result = (tci1->initial ? -1 : +1);
1034 else if (tci1->sort_priority != tci2->sort_priority)
1035 compare_result = tci1->sort_priority - tci2->sort_priority;
1036 else if (tci1->is_image != tci2->is_image)
1037 compare_result = (tci1->is_image ? -1 : +1);
1039 compare_result = tci1->local_nr - tci2->local_nr;
1041 return compare_result;
1044 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
1046 int nr, int sort_priority)
1048 title_controls[num_title_screens].is_image = is_image;
1049 title_controls[num_title_screens].initial = initial;
1050 title_controls[num_title_screens].local_nr = nr;
1051 title_controls[num_title_screens].sort_priority = sort_priority;
1053 title_controls[num_title_screens].first = FALSE; /* will be set later */
1055 num_title_screens++;
1058 static void InitializeTitleControls_CheckTitleInfo(boolean initial)
1062 for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++)
1064 int graphic = getTitleScreenGraphic(i, initial);
1065 Bitmap *bitmap = graphic_info[graphic].bitmap;
1066 int sort_priority = graphic_info[graphic].sort_priority;
1069 InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority);
1072 for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
1074 struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial);
1075 char *filename = getLevelSetTitleMessageFilename(i, initial);
1076 int sort_priority = tmi->sort_priority;
1078 if (filename != NULL)
1079 InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority);
1083 static void InitializeTitleControls(boolean show_title_initial)
1085 num_title_screens = 0;
1087 /* 1st step: initialize title screens for game start (only when starting) */
1088 if (show_title_initial)
1089 InitializeTitleControls_CheckTitleInfo(TRUE);
1091 /* 2nd step: initialize title screens for current level set */
1092 InitializeTitleControls_CheckTitleInfo(FALSE);
1094 /* sort title screens according to sort_priority and title number */
1095 qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo),
1096 compareTitleControlInfo);
1098 /* mark first title screen */
1099 title_controls[0].first = TRUE;
1102 static boolean visibleMenuPos(struct MenuPosInfo *pos)
1104 return (pos != NULL && pos->x != -1 && pos->y != -1);
1107 static boolean visibleTextPos(struct TextPosInfo *pos)
1109 return (pos != NULL && pos->x != -1 && pos->y != -1);
1112 static void InitializeMainControls(void)
1114 boolean local_team_mode = (!network.enabled && setup.team_mode);
1117 /* set main control text values to dynamically determined values */
1118 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
1120 strcpy(main_text_first_level, int2str(leveldir_current->first_level,
1121 menu.main.text.first_level.size));
1122 strcpy(main_text_last_level, int2str(leveldir_current->last_level,
1123 menu.main.text.last_level.size));
1124 strcpy(main_text_level_number, int2str(level_nr,
1125 menu.main.text.level_number.size));
1127 main_text_level_year = leveldir_current->year;
1128 main_text_level_imported_from = leveldir_current->imported_from;
1129 main_text_level_imported_by = leveldir_current->imported_by;
1130 main_text_level_tested_by = leveldir_current->tested_by;
1132 main_text_title_1 = getConfigProgramTitleString();
1133 main_text_title_2 = getConfigProgramCopyrightString();
1134 main_text_title_3 = getConfigProgramCompanyString();
1136 /* set main control screen positions to dynamically determined values */
1137 for (i = 0; main_controls[i].nr != -1; i++)
1139 struct MainControlInfo *mci = &main_controls[i];
1141 struct MenuPosInfo *pos_button = mci->pos_button;
1142 struct TextPosInfo *pos_text = mci->pos_text;
1143 struct TextPosInfo *pos_input = mci->pos_input;
1144 char *text = (mci->text ? *mci->text : NULL);
1145 char *input = (mci->input ? *mci->input : NULL);
1146 int button_graphic = mci->button_graphic;
1147 int font_text = (pos_text ? pos_text->font : -1);
1148 int font_input = (pos_input ? pos_input->font : -1);
1150 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
1151 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
1152 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
1153 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
1154 int text_chars = (text != NULL ? strlen(text) : 0);
1155 int input_chars = (input != NULL ? strlen(input) : 0);
1158 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
1160 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
1161 int text_width = font_text_width * text_chars;
1162 int text_height = font_text_height;
1163 int input_width = font_input_width * input_chars;
1164 int input_height = font_input_height;
1166 if (nr == MAIN_CONTROL_NAME)
1168 menu.main.input.name.width = input_width;
1169 menu.main.input.name.height = input_height;
1172 if (pos_button != NULL) /* (x/y may be -1/-1 here) */
1174 pos_button->width = button_width;
1175 pos_button->height = button_height;
1178 if (pos_text != NULL) /* (x/y may be -1/-1 here) */
1180 /* calculate text size -- needed for text alignment */
1181 boolean calculate_text_size = (text != NULL);
1183 if (pos_text->width == -1 || calculate_text_size)
1184 pos_text->width = text_width;
1185 if (pos_text->height == -1 || calculate_text_size)
1186 pos_text->height = text_height;
1188 if (visibleMenuPos(pos_button))
1190 if (pos_text->x == -1)
1191 pos_text->x = pos_button->x + pos_button->width;
1192 if (pos_text->y == -1)
1194 pos_button->y + (pos_button->height - pos_text->height) / 2;
1198 if (pos_input != NULL) /* (x/y may be -1/-1 here) */
1200 if (visibleTextPos(pos_text))
1202 if (pos_input->x == -1)
1203 pos_input->x = pos_text->x + pos_text->width;
1204 if (pos_input->y == -1)
1205 pos_input->y = pos_text->y;
1208 if (pos_input->width == -1)
1209 pos_input->width = input_width;
1210 if (pos_input->height == -1)
1211 pos_input->height = input_height;
1216 static void DrawPressedGraphicThruMask(int dst_x, int dst_y,
1217 int graphic, boolean pressed)
1219 struct GraphicInfo *g = &graphic_info[graphic];
1222 int xoffset = (pressed ? g->pressed_xoffset : 0);
1223 int yoffset = (pressed ? g->pressed_yoffset : 0);
1225 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1227 BlitBitmapMasked(src_bitmap, drawto, src_x + xoffset, src_y + yoffset,
1228 g->width, g->height, dst_x, dst_y);
1231 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
1232 boolean active_input,
1233 boolean pressed_button)
1237 for (i = 0; main_controls[i].nr != -1; i++)
1239 struct MainControlInfo *mci = &main_controls[i];
1241 if (mci->nr == nr || nr == -1)
1243 struct MenuPosInfo *pos_button = mci->pos_button;
1244 struct TextPosInfo *pos_text = mci->pos_text;
1245 struct TextPosInfo *pos_input = mci->pos_input;
1246 char *text = (mci->text ? *mci->text : NULL);
1247 char *input = (mci->input ? *mci->input : NULL);
1248 int button_graphic = mci->button_graphic;
1249 int font_text = (pos_text ? pos_text->font : -1);
1250 int font_input = (pos_input ? pos_input->font : -1);
1254 button_graphic = BUTTON_ACTIVE(button_graphic);
1255 font_text = FONT_ACTIVE(font_text);
1260 font_input = FONT_ACTIVE(font_input);
1263 if (visibleMenuPos(pos_button))
1265 struct MenuPosInfo *pos = pos_button;
1266 int x = mSX + pos->x;
1267 int y = mSY + pos->y;
1269 DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
1270 DrawPressedGraphicThruMask(x, y, button_graphic, pressed_button);
1273 if (visibleTextPos(pos_text) && text != NULL)
1275 struct TextPosInfo *pos = pos_text;
1276 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1277 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1280 /* (check why/if this is needed) */
1281 DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
1283 DrawText(x, y, text, font_text);
1286 if (visibleTextPos(pos_input) && input != NULL)
1288 struct TextPosInfo *pos = pos_input;
1289 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1290 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1293 /* (check why/if this is needed) */
1294 DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
1296 DrawText(x, y, input, font_input);
1302 static void DrawCursorAndText_Main(int nr, boolean active_text,
1303 boolean pressed_button)
1305 DrawCursorAndText_Main_Ext(nr, active_text, FALSE, pressed_button);
1309 static void DrawCursorAndText_Main_Input(int nr, boolean active_text,
1310 boolean pressed_button)
1312 DrawCursorAndText_Main_Ext(nr, active_text, TRUE, pressed_button);
1316 static struct MainControlInfo *getMainControlInfo(int nr)
1320 for (i = 0; main_controls[i].nr != -1; i++)
1321 if (main_controls[i].nr == nr)
1322 return &main_controls[i];
1327 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
1332 int rect_x = ALIGNED_TEXT_XPOS(rect);
1333 int rect_y = ALIGNED_TEXT_YPOS(rect);
1335 return (x >= rect_x && x < rect_x + rect->width &&
1336 y >= rect_y && y < rect_y + rect->height);
1339 static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
1344 int rect_x = ALIGNED_TEXT_XPOS(rect);
1345 int rect_y = ALIGNED_TEXT_YPOS(rect);
1348 printf("::: insideTextPosRect: (%d, %d), (%d, %d) [%d, %d] (%d, %d) => %d\n",
1349 x, y, rect_x, rect_y, rect->x, rect->y, rect->width, rect->height,
1350 (x >= rect_x && x < rect_x + rect->width &&
1351 y >= rect_y && y < rect_y + rect->height));
1354 return (x >= rect_x && x < rect_x + rect->width &&
1355 y >= rect_y && y < rect_y + rect->height);
1358 static boolean insidePreviewRect(struct PreviewInfo *preview, int x, int y)
1360 int rect_width = preview->xsize * preview->tile_size;
1361 int rect_height = preview->ysize * preview->tile_size;
1362 int rect_x = ALIGNED_XPOS(preview->x, rect_width, preview->align);
1363 int rect_y = ALIGNED_YPOS(preview->y, rect_height, preview->valign);
1365 return (x >= rect_x && x < rect_x + rect_width &&
1366 y >= rect_y && y < rect_y + rect_height);
1369 static void AdjustScrollbar(int id, int items_max, int items_visible,
1372 struct GadgetInfo *gi = screen_gadget[id];
1374 if (item_position > items_max - items_visible)
1375 item_position = items_max - items_visible;
1377 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
1378 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1379 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
1382 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
1384 AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN,
1388 static void clearMenuListArea(void)
1390 int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
1392 /* correct scrollbar position if placed outside menu (playfield) area */
1393 if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS)
1394 scrollbar_xpos = SX + SC_SCROLLBAR_XPOS;
1396 /* clear menu list area, but not title or scrollbar */
1397 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
1398 scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32);
1401 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
1403 static int cursor_array[MAX_LEV_FIELDY];
1404 int x = mSX + TILEX * xpos;
1405 int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
1410 cursor_array[ypos] = graphic;
1412 graphic = cursor_array[ypos];
1416 graphic = BUTTON_ACTIVE(graphic);
1418 DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
1419 DrawFixedGraphicThruMaskExt(drawto, x, y, graphic, 0);
1422 static void initCursor(int ypos, int graphic)
1424 drawCursorExt(0, ypos, FALSE, graphic);
1427 static void drawCursor(int ypos, boolean active)
1429 drawCursorExt(0, ypos, active, -1);
1432 static void drawCursorXY(int xpos, int ypos, int graphic)
1434 drawCursorExt(xpos, ypos, FALSE, graphic);
1437 static void drawChooseTreeCursor(int ypos, boolean active)
1439 drawCursorExt(0, ypos, active, -1);
1442 static void DrawHeadline(void)
1444 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, main_text_title_1);
1445 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, main_text_title_2);
1448 static void DrawTitleScreenImage(int nr, boolean initial)
1450 int graphic = getTitleScreenGraphic(nr, initial);
1451 Bitmap *bitmap = graphic_info[graphic].bitmap;
1452 int width = graphic_info[graphic].width;
1453 int height = graphic_info[graphic].height;
1454 int src_x = graphic_info[graphic].src_x;
1455 int src_y = graphic_info[graphic].src_y;
1461 if (width > WIN_XSIZE)
1463 /* image width too large for window => center image horizontally */
1464 src_x = (width - WIN_XSIZE) / 2;
1468 if (height > WIN_YSIZE)
1470 /* image height too large for window => center image vertically */
1471 src_y = (height - WIN_YSIZE) / 2;
1475 /* always display title screens centered */
1476 dst_x = (WIN_XSIZE - width) / 2;
1477 dst_y = (WIN_YSIZE - height) / 2;
1479 SetDrawBackgroundMask(REDRAW_ALL);
1480 SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE));
1482 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1484 if (DrawingOnBackground(dst_x, dst_y))
1485 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1487 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1489 redraw_mask = REDRAW_ALL;
1492 static void DrawTitleScreenMessage(int nr, boolean initial)
1494 char *filename = getLevelSetTitleMessageFilename(nr, initial);
1495 struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
1497 if (filename == NULL)
1500 /* force TITLE font on title message screen */
1501 SetFontStatus(getTitleMessageGameMode(initial));
1503 /* if chars *and* width set to "-1", automatically determine width */
1504 if (tmi->chars == -1 && tmi->width == -1)
1505 tmi->width = viewport.window[game_status].width;
1507 /* if lines *and* height set to "-1", automatically determine height */
1508 if (tmi->lines == -1 && tmi->height == -1)
1509 tmi->height = viewport.window[game_status].height;
1511 /* if chars set to "-1", automatically determine by text and font width */
1512 if (tmi->chars == -1)
1513 tmi->chars = tmi->width / getFontWidth(tmi->font);
1515 tmi->width = tmi->chars * getFontWidth(tmi->font);
1517 /* if lines set to "-1", automatically determine by text and font height */
1518 if (tmi->lines == -1)
1519 tmi->lines = tmi->height / getFontHeight(tmi->font);
1521 tmi->height = tmi->lines * getFontHeight(tmi->font);
1523 /* if x set to "-1", automatically determine by width and alignment */
1525 tmi->x = -1 * ALIGNED_XPOS(0, tmi->width, tmi->align);
1527 /* if y set to "-1", automatically determine by height and alignment */
1529 tmi->y = -1 * ALIGNED_YPOS(0, tmi->height, tmi->valign);
1531 SetDrawBackgroundMask(REDRAW_ALL);
1532 SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE));
1534 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1536 DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi),
1537 filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
1538 tmi->autowrap, tmi->centered, tmi->parse_comments);
1543 static void DrawTitleScreen(void)
1545 KeyboardAutoRepeatOff();
1547 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
1550 static boolean CheckTitleScreen(boolean levelset_has_changed)
1552 static boolean show_title_initial = TRUE;
1553 boolean show_titlescreen = FALSE;
1555 /* needed to be able to skip title screen, if no image or message defined */
1556 InitializeTitleControls(show_title_initial);
1558 if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
1559 show_titlescreen = TRUE;
1561 /* show initial title images and messages only once at program start */
1562 show_title_initial = FALSE;
1564 return (show_titlescreen && num_title_screens > 0);
1567 void DrawMainMenu(void)
1569 static LevelDirTree *leveldir_last_valid = NULL;
1570 boolean levelset_has_changed = FALSE;
1571 int fade_mask = REDRAW_FIELD;
1573 LimitScreenUpdates(FALSE);
1575 FadeSetLeaveScreen();
1577 /* do not fade out here -- function may continue and fade on editor screen */
1580 FadeMenuSoundsAndMusic();
1582 ExpireSoundLoops(FALSE);
1584 KeyboardAutoRepeatOn();
1586 audio.sound_deactivated = FALSE;
1590 /* needed if last screen was the playing screen, invoked from level editor */
1591 if (level_editor_test_game)
1593 CloseDoor(DOOR_CLOSE_ALL);
1595 SetGameStatus(GAME_MODE_EDITOR);
1602 /* needed if last screen was the setup screen and fullscreen state changed */
1603 // (moved to "execSetupGraphics()" to change fullscreen state directly)
1604 // ToggleFullscreenOrChangeWindowScalingIfNeeded();
1606 /* leveldir_current may be invalid (level group, parent link) */
1607 if (!validLevelSeries(leveldir_current))
1608 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
1610 if (leveldir_current != leveldir_last_valid)
1611 levelset_has_changed = TRUE;
1613 /* store valid level series information */
1614 leveldir_last_valid = leveldir_current;
1616 init_last = init; /* switch to new busy animation */
1618 /* needed if last screen (level choice) changed graphics, sounds or music */
1619 ReloadCustomArtwork(0);
1621 if (CheckTitleScreen(levelset_has_changed))
1623 SetGameStatus(GAME_MODE_TITLE);
1630 if (redraw_mask & REDRAW_ALL)
1631 fade_mask = REDRAW_ALL;
1633 if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
1634 fade_mask = REDRAW_ALL;
1638 /* needed if different viewport properties defined for menues */
1639 ChangeViewportPropertiesIfNeeded();
1641 SetDrawtoField(DRAW_TO_BACKBUFFER);
1643 /* level_nr may have been set to value over handicap with level editor */
1644 if (setup.handicap && level_nr > leveldir_current->handicap_level)
1645 level_nr = leveldir_current->handicap_level;
1647 LoadLevel(level_nr);
1648 LoadScore(level_nr);
1650 SaveLevelSetup_SeriesInfo();
1652 // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it)
1653 SetDrawDeactivationMask(REDRAW_NONE);
1654 SetDrawBackgroundMask(REDRAW_FIELD);
1656 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
1659 if (fade_mask == REDRAW_ALL)
1660 RedrawGlobalBorder();
1665 InitializeMainControls();
1667 DrawCursorAndText_Main(-1, FALSE, FALSE);
1668 DrawPreviewLevelInitial();
1669 DrawNetworkPlayers();
1671 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
1674 if (TAPE_IS_EMPTY(tape))
1676 DrawCompleteVideoDisplay();
1678 PlayMenuSoundsAndMusic();
1680 /* create gadgets for main menu screen */
1681 FreeScreenGadgets();
1682 CreateScreenGadgets();
1684 /* may be required if audio buttons shown on tape and changed in setup menu */
1686 CreateGameButtons();
1688 /* map gadgets for main menu screen */
1690 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
1691 UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
1693 /* copy actual game door content to door double buffer for OpenDoor() */
1694 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
1695 BlitBitmap(drawto, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0);
1697 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1699 DrawMaskedBorder(fade_mask);
1704 /* update screen area with special editor door */
1705 redraw_mask |= REDRAW_ALL;
1708 SetMouseCursor(CURSOR_DEFAULT);
1710 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
1713 static void gotoTopLevelDir(void)
1715 /* move upwards until inside (but not above) top level directory */
1716 while (leveldir_current->node_parent &&
1717 !strEqual(leveldir_current->node_parent->subdir, STRING_TOP_DIRECTORY))
1719 /* write a "path" into level tree for easy navigation to last level */
1720 if (leveldir_current->node_parent->node_group->cl_first == -1)
1722 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
1723 int leveldir_pos = posTreeInfo(leveldir_current);
1724 int num_page_entries;
1725 int cl_first, cl_cursor;
1727 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
1728 num_page_entries = num_leveldirs;
1730 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1732 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
1733 cl_cursor = leveldir_pos - cl_first;
1735 leveldir_current->node_parent->node_group->cl_first = cl_first;
1736 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
1739 leveldir_current = leveldir_current->node_parent;
1743 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1745 static unsigned int title_delay = 0;
1746 static int title_screen_nr = 0;
1747 static int last_sound = -1, last_music = -1;
1748 boolean return_to_main_menu = FALSE;
1749 struct TitleControlInfo *tci;
1752 if (button == MB_MENU_INITIALIZE)
1755 title_screen_nr = 0;
1756 tci = &title_controls[title_screen_nr];
1758 SetAnimStatus(getTitleAnimMode(tci));
1760 last_sound = SND_UNDEFINED;
1761 last_music = MUS_UNDEFINED;
1763 if (num_title_screens != 0)
1765 FadeSetEnterScreen();
1767 /* use individual title fading instead of global "enter screen" fading */
1768 fading = getTitleFading(tci);
1771 if (game_status_last_screen == GAME_MODE_INFO)
1773 if (num_title_screens == 0)
1775 /* switch game mode from title screen mode back to info screen mode */
1776 SetGameStatus(GAME_MODE_INFO);
1778 /* store that last screen was info screen, not main menu screen */
1779 game_status_last_screen = GAME_MODE_INFO;
1781 DrawInfoScreen_NotAvailable("Title screen information:",
1782 "No title screen for this level set.");
1786 FadeMenuSoundsAndMusic();
1789 FadeOut(REDRAW_ALL);
1791 /* title screens may have different window size */
1792 ChangeViewportPropertiesIfNeeded();
1794 /* only required to update logic for redrawing global border */
1798 DrawTitleScreenImage(tci->local_nr, tci->initial);
1800 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1802 sound = getTitleSound(tci);
1803 music = getTitleMusic(tci);
1805 if (sound != last_sound)
1806 PlayMenuSoundExt(sound);
1807 if (music != last_music)
1808 PlayMenuMusicExt(music);
1813 SetMouseCursor(CURSOR_NONE);
1817 DelayReached(&title_delay, 0); /* reset delay counter */
1822 if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay))
1823 button = MB_MENU_CHOICE;
1825 if (button == MB_MENU_LEAVE)
1827 return_to_main_menu = TRUE;
1829 else if (button == MB_MENU_CHOICE)
1831 if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0)
1833 SetGameStatus(GAME_MODE_INFO);
1835 info_mode = INFO_MODE_MAIN;
1844 if (title_screen_nr < num_title_screens)
1846 tci = &title_controls[title_screen_nr];
1848 SetAnimStatus(getTitleAnimMode(tci));
1850 sound = getTitleSound(tci);
1851 music = getTitleMusic(tci);
1853 if (last_sound != SND_UNDEFINED && sound != last_sound)
1854 FadeSound(last_sound);
1855 if (last_music != MUS_UNDEFINED && music != last_music)
1858 fading = getTitleFading(tci);
1860 FadeOut(REDRAW_ALL);
1863 DrawTitleScreenImage(tci->local_nr, tci->initial);
1865 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1867 sound = getTitleSound(tci);
1868 music = getTitleMusic(tci);
1870 if (sound != last_sound)
1871 PlayMenuSoundExt(sound);
1872 if (music != last_music)
1873 PlayMenuMusicExt(music);
1880 DelayReached(&title_delay, 0); /* reset delay counter */
1884 FadeMenuSoundsAndMusic();
1886 return_to_main_menu = TRUE;
1890 if (return_to_main_menu)
1892 SetMouseCursor(CURSOR_DEFAULT);
1894 /* force full menu screen redraw after displaying title screens */
1895 redraw_mask = REDRAW_ALL;
1897 if (game_status_last_screen == GAME_MODE_INFO)
1899 SetGameStatus(GAME_MODE_INFO);
1901 info_mode = INFO_MODE_MAIN;
1905 else /* default: return to main menu */
1907 SetGameStatus(GAME_MODE_MAIN);
1914 static void HandleMainMenu_SelectLevel(int step, int direction,
1915 int selected_level_nr)
1917 int old_level_nr = level_nr;
1920 if (selected_level_nr != NO_DIRECT_LEVEL_SELECT)
1921 new_level_nr = selected_level_nr;
1923 new_level_nr = old_level_nr + step * direction;
1925 if (new_level_nr < leveldir_current->first_level)
1926 new_level_nr = leveldir_current->first_level;
1927 if (new_level_nr > leveldir_current->last_level)
1928 new_level_nr = leveldir_current->last_level;
1930 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1932 /* skipping levels is only allowed when trying to skip single level */
1933 if (setup.skip_levels && new_level_nr == old_level_nr + 1 &&
1934 Request("Level still unsolved! Skip despite handicap?", REQ_ASK))
1936 leveldir_current->handicap_level++;
1937 SaveLevelSetup_SeriesInfo();
1940 new_level_nr = leveldir_current->handicap_level;
1943 if (new_level_nr != old_level_nr)
1945 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER);
1947 PlaySound(SND_MENU_ITEM_SELECTING);
1949 level_nr = new_level_nr;
1951 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1952 int2str(level_nr, menu.main.text.level_number.size),
1953 mci->pos_text->font);
1955 LoadLevel(level_nr);
1956 DrawPreviewLevelInitial();
1960 DrawCompleteVideoDisplay();
1962 SaveLevelSetup_SeriesInfo();
1964 UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
1966 /* needed because DrawPreviewLevelInitial() takes some time */
1968 /* SyncDisplay(); */
1972 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1974 static int choice = MAIN_CONTROL_GAME;
1975 static boolean button_pressed_last = FALSE;
1976 boolean button_pressed = FALSE;
1980 if (button == MB_MENU_INITIALIZE)
1982 DrawCursorAndText_Main(choice, TRUE, FALSE);
1987 if (mx || my) /* mouse input */
1991 for (i = 0; main_controls[i].nr != -1; i++)
1993 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1994 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1995 insideTextPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1997 pos = main_controls[i].nr;
2003 /* check if level preview was clicked */
2004 if (insidePreviewRect(&preview, mx - SX, my - SY))
2005 pos = MAIN_CONTROL_GAME;
2007 // handle pressed/unpressed state for active/inactive menu buttons
2008 // (if pos != -1, "i" contains index position corresponding to "pos")
2010 pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT &&
2011 insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY))
2012 button_pressed = TRUE;
2014 if (button_pressed != button_pressed_last)
2016 DrawCursorAndText_Main(choice, TRUE, button_pressed);
2019 PlaySound(SND_MENU_BUTTON_PRESSING);
2021 PlaySound(SND_MENU_BUTTON_RELEASING);
2024 else if (dx || dy) /* keyboard input */
2026 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
2027 choice == MAIN_CONTROL_SETUP))
2028 button = MB_MENU_CHOICE;
2033 if (pos == MAIN_CONTROL_FIRST_LEVEL && !button)
2035 HandleMainMenu_SelectLevel(MAX_LEVELS, -1, NO_DIRECT_LEVEL_SELECT);
2037 else if (pos == MAIN_CONTROL_LAST_LEVEL && !button)
2039 HandleMainMenu_SelectLevel(MAX_LEVELS, +1, NO_DIRECT_LEVEL_SELECT);
2041 else if (pos == MAIN_CONTROL_LEVEL_NUMBER && !button)
2043 CloseDoor(DOOR_CLOSE_2);
2045 SetGameStatus(GAME_MODE_LEVELNR);
2047 DrawChooseLevelNr();
2049 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
2055 PlaySound(SND_MENU_ITEM_ACTIVATING);
2057 DrawCursorAndText_Main(choice, FALSE, FALSE);
2058 DrawCursorAndText_Main(pos, TRUE, button_pressed);
2064 if (choice != MAIN_CONTROL_INFO &&
2065 choice != MAIN_CONTROL_SETUP)
2066 HandleMainMenu_SelectLevel(1, dx, NO_DIRECT_LEVEL_SELECT);
2071 PlaySound(SND_MENU_ITEM_SELECTING);
2073 if (pos == MAIN_CONTROL_NAME)
2075 SetGameStatus(GAME_MODE_PSEUDO_TYPENAME);
2077 HandleTypeName(strlen(setup.player_name), 0);
2079 else if (pos == MAIN_CONTROL_LEVELS)
2083 CloseDoor(DOOR_CLOSE_2);
2085 SetGameStatus(GAME_MODE_LEVELS);
2087 SaveLevelSetup_LastSeries();
2088 SaveLevelSetup_SeriesInfo();
2090 if (setup.internal.choose_from_top_leveldir)
2093 DrawChooseLevelSet();
2096 else if (pos == MAIN_CONTROL_SCORES)
2098 CloseDoor(DOOR_CLOSE_2);
2100 SetGameStatus(GAME_MODE_SCORES);
2102 DrawHallOfFame(level_nr, -1);
2104 else if (pos == MAIN_CONTROL_EDITOR)
2106 if (leveldir_current->readonly &&
2107 !strEqual(setup.player_name, "Artsoft"))
2108 Request("This level is read only!", REQ_CONFIRM);
2110 CloseDoor(DOOR_CLOSE_2);
2112 SetGameStatus(GAME_MODE_EDITOR);
2114 FadeSetEnterScreen();
2118 else if (pos == MAIN_CONTROL_INFO)
2120 CloseDoor(DOOR_CLOSE_2);
2122 SetGameStatus(GAME_MODE_INFO);
2124 info_mode = INFO_MODE_MAIN;
2128 else if (pos == MAIN_CONTROL_GAME)
2130 StartGameActions(network.enabled, setup.autorecord, level.random_seed);
2132 else if (pos == MAIN_CONTROL_SETUP)
2134 CloseDoor(DOOR_CLOSE_2);
2136 SetGameStatus(GAME_MODE_SETUP);
2138 setup_mode = SETUP_MODE_MAIN;
2142 else if (pos == MAIN_CONTROL_QUIT)
2144 SaveLevelSetup_LastSeries();
2145 SaveLevelSetup_SeriesInfo();
2147 if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED))
2148 SetGameStatus(GAME_MODE_QUIT);
2153 button_pressed_last = button_pressed;
2157 /* ========================================================================= */
2158 /* info screen functions */
2159 /* ========================================================================= */
2161 static struct TokenInfo *info_info;
2162 static int num_info_info; /* number of info entries shown on screen */
2163 static int max_info_info; /* total number of info entries in list */
2165 static void execInfoTitleScreen(void)
2167 info_mode = INFO_MODE_TITLE;
2172 static void execInfoElements(void)
2174 info_mode = INFO_MODE_ELEMENTS;
2179 static void execInfoMusic(void)
2181 info_mode = INFO_MODE_MUSIC;
2186 static void execInfoCredits(void)
2188 info_mode = INFO_MODE_CREDITS;
2193 static void execInfoProgram(void)
2195 info_mode = INFO_MODE_PROGRAM;
2200 static void execInfoVersion(void)
2202 info_mode = INFO_MODE_VERSION;
2207 static void execInfoLevelSet(void)
2209 info_mode = INFO_MODE_LEVELSET;
2214 static void execExitInfo(void)
2216 SetGameStatus(GAME_MODE_MAIN);
2221 static struct TokenInfo info_info_main[] =
2223 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
2224 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
2225 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
2226 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
2227 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
2228 { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" },
2229 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
2230 { TYPE_EMPTY, NULL, "" },
2231 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
2236 static int getMenuTextFont(int type)
2238 if (type & (TYPE_SWITCH |
2252 static struct TokenInfo *setup_info;
2253 static struct TokenInfo setup_info_input[];
2255 static struct TokenInfo *menu_info;
2257 static void DrawCursorAndText_Menu_Ext(struct TokenInfo *token_info,
2258 int screen_pos, int menu_info_pos_raw,
2261 int pos = (menu_info_pos_raw < 0 ? screen_pos : menu_info_pos_raw);
2262 struct TokenInfo *ti = &token_info[pos];
2263 int xpos = MENU_SCREEN_START_XPOS;
2264 int ypos = MENU_SCREEN_START_YPOS + screen_pos;
2265 int font_nr = getMenuTextFont(ti->type);
2267 if (setup_mode == SETUP_MODE_INPUT)
2268 font_nr = FONT_MENU_1;
2271 font_nr = FONT_ACTIVE(font_nr);
2273 DrawText(mSX + xpos * 32, mSY + ypos * 32, ti->text, font_nr);
2275 if (ti->type & ~TYPE_SKIP_ENTRY)
2276 drawCursor(screen_pos, active);
2279 static void DrawCursorAndText_Menu(int screen_pos, int menu_info_pos_raw,
2282 DrawCursorAndText_Menu_Ext(menu_info, screen_pos, menu_info_pos_raw, active);
2285 static void DrawCursorAndText_Setup(int screen_pos, int menu_info_pos_raw,
2288 DrawCursorAndText_Menu_Ext(setup_info, screen_pos, menu_info_pos_raw, active);
2291 static char *window_size_text;
2292 static char *scaling_type_text;
2293 static char *network_server_text;
2295 static void drawSetupValue(int, int);
2297 static void drawMenuInfoList(int first_entry, int num_page_entries,
2298 int max_page_entries)
2302 if (first_entry + num_page_entries > max_page_entries)
2305 clearMenuListArea();
2307 for (i = 0; i < num_page_entries; i++)
2309 int menu_info_pos = first_entry + i;
2310 struct TokenInfo *si = &menu_info[menu_info_pos];
2311 void *value_ptr = si->value;
2313 /* set some entries to "unchangeable" according to other variables */
2314 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
2315 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
2316 (value_ptr == &setup.sound_music && !audio.music_available) ||
2317 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
2318 (value_ptr == &window_size_text && !video.window_scaling_available) ||
2319 (value_ptr == &scaling_type_text && !video.window_scaling_available))
2320 si->type |= TYPE_GHOSTED;
2322 if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
2323 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
2324 else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
2325 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
2326 else if (si->type & ~TYPE_SKIP_ENTRY)
2327 initCursor(i, IMG_MENU_BUTTON);
2329 DrawCursorAndText_Menu(i, menu_info_pos, FALSE);
2331 if (si->type & TYPE_STRING)
2335 if (value_ptr == &network_server_text)
2336 gadget_id = SCREEN_CTRL_ID_NETWORK_SERVER;
2338 if (gadget_id != -1)
2340 struct GadgetInfo *gi = screen_gadget[gadget_id];
2341 int xpos = MENU_SCREEN_START_XPOS;
2342 int ypos = MENU_SCREEN_START_YPOS + i;
2343 int x = mSX + xpos * 32;
2344 int y = mSY + ypos * 32;
2346 ModifyGadget(gi, GDI_X, x, GDI_Y, y, GDI_END);
2350 if (si->type & TYPE_VALUE &&
2351 menu_info == setup_info)
2352 drawSetupValue(i, menu_info_pos);
2356 static void DrawInfoScreen_Main(void)
2358 int fade_mask = REDRAW_FIELD;
2361 if (redraw_mask & REDRAW_ALL)
2362 fade_mask = REDRAW_ALL;
2364 if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
2365 fade_mask = REDRAW_ALL;
2368 FadeMenuSoundsAndMusic();
2370 FreeScreenGadgets();
2371 CreateScreenGadgets();
2373 /* (needed after displaying title screens which disable auto repeat) */
2374 KeyboardAutoRepeatOn();
2376 FadeSetLeaveScreen();
2380 /* needed if different viewport properties defined for info screen */
2381 ChangeViewportPropertiesIfNeeded();
2383 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
2387 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
2389 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
2391 info_info = info_info_main;
2393 // determine maximal number of info entries that can be displayed on screen
2395 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
2398 // determine maximal number of info entries available for menu of info screen
2400 for (i = 0; info_info[i].type != 0; i++)
2403 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
2405 MapScreenGadgets(max_info_info);
2407 PlayMenuSoundsAndMusic();
2409 DrawMaskedBorder(fade_mask);
2414 static void changeSetupValue(int, int, int);
2416 static void HandleMenuScreen(int mx, int my, int dx, int dy, int button,
2417 int mode, int num_page_entries,
2418 int max_page_entries)
2420 static int num_page_entries_all_last[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2421 static int choice_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2422 static int first_entry_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2423 int *num_page_entries_last = num_page_entries_all_last[game_status];
2424 int *choice_store = choice_stores[game_status];
2425 int *first_entry_store = first_entry_stores[game_status];
2426 int choice = choice_store[mode]; /* starts with 0 */
2427 int first_entry = first_entry_store[mode]; /* starts with 0 */
2429 int y = choice - first_entry;
2431 boolean position_set_by_scrollbar = (dx == 999);
2432 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2435 if (button == MB_MENU_INITIALIZE)
2437 // check if number of menu page entries has changed (may happen by change
2438 // of custom artwork definition value for 'list_size' for this menu screen)
2439 // (in this case, the last menu position most probably has to be corrected)
2440 if (num_page_entries != num_page_entries_last[mode])
2442 choice_store[mode] = first_entry_store[mode] = 0;
2444 choice = first_entry = 0;
2447 num_page_entries_last[mode] = num_page_entries;
2450 /* advance to first valid menu entry */
2451 while (choice < num_page_entries &&
2452 menu_info[choice].type & TYPE_SKIP_ENTRY)
2455 if (position_set_by_scrollbar)
2456 first_entry = first_entry_store[mode] = dy;
2458 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2459 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2461 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2463 if (choice < first_entry)
2465 choice = first_entry;
2467 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2470 else if (choice > first_entry + num_page_entries - 1)
2472 choice = first_entry + num_page_entries - 1;
2474 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2478 choice_store[mode] = choice;
2480 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2484 else if (button == MB_MENU_LEAVE)
2486 PlaySound(SND_MENU_ITEM_SELECTING);
2488 for (i = 0; i < max_page_entries; i++)
2490 if (menu_info[i].type & TYPE_LEAVE_MENU)
2492 void (*menu_callback_function)(void) = menu_info[i].value;
2496 menu_callback_function();
2498 break; /* absolutely needed because function changes 'menu_info'! */
2505 if (mx || my) /* mouse input */
2507 x = (mx - mSX) / 32;
2508 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2510 else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */
2512 /* move cursor instead of scrolling when already at start/end of list */
2513 if (dy == -1 * SCROLL_LINE && first_entry == 0)
2515 else if (dy == +1 * SCROLL_LINE &&
2516 first_entry + num_page_entries == max_page_entries)
2519 /* handle scrolling screen one line or page */
2521 y + dy > num_page_entries - 1)
2523 boolean redraw = FALSE;
2525 if (ABS(dy) == SCROLL_PAGE)
2526 step = num_page_entries - 1;
2528 if (dy < 0 && first_entry > 0)
2530 /* scroll page/line up */
2532 first_entry -= step;
2533 if (first_entry < 0)
2538 else if (dy > 0 && first_entry + num_page_entries < max_page_entries)
2540 /* scroll page/line down */
2542 first_entry += step;
2543 if (first_entry + num_page_entries > max_page_entries)
2544 first_entry = MAX(0, max_page_entries - num_page_entries);
2551 choice += first_entry - first_entry_store[mode];
2553 if (choice < first_entry)
2555 choice = first_entry;
2557 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2560 else if (choice > first_entry + num_page_entries - 1)
2562 choice = first_entry + num_page_entries - 1;
2564 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2567 else if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2571 if (choice < first_entry ||
2572 choice > first_entry + num_page_entries - 1)
2573 first_entry += SIGN(dy);
2576 first_entry_store[mode] = first_entry;
2577 choice_store[mode] = choice;
2579 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2581 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2583 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2584 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2592 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
2594 if (menu_info[choice].type & menu_navigation_type ||
2595 menu_info[choice].type & TYPE_BOOLEAN_STYLE ||
2596 menu_info[choice].type & TYPE_YES_NO_AUTO ||
2597 menu_info[choice].type & TYPE_PLAYER)
2598 button = MB_MENU_CHOICE;
2603 /* jump to next non-empty menu entry (up or down) */
2604 while (first_entry + y > 0 &&
2605 first_entry + y < max_page_entries - 1 &&
2606 menu_info[first_entry + y].type & TYPE_SKIP_ENTRY)
2609 if (!IN_VIS_MENU(x, y))
2611 choice += y - y_old;
2613 if (choice < first_entry)
2614 first_entry = choice;
2615 else if (choice > first_entry + num_page_entries - 1)
2616 first_entry = choice - num_page_entries + 1;
2618 if (first_entry >= 0 &&
2619 first_entry + num_page_entries <= max_page_entries)
2621 first_entry_store[mode] = first_entry;
2623 if (choice < first_entry)
2624 choice = first_entry;
2625 else if (choice > first_entry + num_page_entries - 1)
2626 choice = first_entry + num_page_entries - 1;
2628 choice_store[mode] = choice;
2630 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2632 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2634 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2635 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2642 if (!anyScrollbarGadgetActive() &&
2643 IN_VIS_MENU(x, y) &&
2644 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
2645 y >= 0 && y < num_page_entries)
2649 if (first_entry + y != choice &&
2650 menu_info[first_entry + y].type & ~TYPE_SKIP_ENTRY)
2652 PlaySound(SND_MENU_ITEM_ACTIVATING);
2654 DrawCursorAndText_Menu(choice - first_entry, choice, FALSE);
2655 DrawCursorAndText_Menu(y, first_entry + y, TRUE);
2657 choice = choice_store[mode] = first_entry + y;
2661 PlaySound(SND_MENU_ITEM_SELECTING);
2663 for (i = 0; menu_info[i].type != 0; i++)
2665 if (menu_info[i].type & TYPE_LEAVE_MENU)
2667 void (*menu_callback_function)(void) = menu_info[i].value;
2671 menu_callback_function();
2673 /* absolutely needed because function changes 'menu_info'! */
2681 else if (!(menu_info[first_entry + y].type & TYPE_GHOSTED))
2683 PlaySound(SND_MENU_ITEM_SELECTING);
2685 /* when selecting key headline, execute function for key value change */
2686 if (menu_info[first_entry + y].type & TYPE_KEYTEXT &&
2687 menu_info[first_entry + y + 1].type & TYPE_KEY)
2690 /* when selecting string value, execute function for list selection */
2691 if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 &&
2692 menu_info[first_entry + y - 1].type & TYPE_ENTER_LIST)
2695 /* when selecting string value, execute function for text input gadget */
2696 if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 &&
2697 menu_info[first_entry + y - 1].type & TYPE_TEXT_INPUT)
2700 if (menu_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE)
2702 void (*menu_callback_function)(void) =
2703 menu_info[first_entry + y].value;
2705 FadeSetFromType(menu_info[first_entry + y].type);
2707 menu_callback_function();
2709 else if (menu_info[first_entry + y].type & TYPE_TEXT_INPUT)
2711 void (*gadget_callback_function)(void) =
2712 menu_info[first_entry + y].value;
2714 gadget_callback_function();
2716 else if (menu_info[first_entry + y].type & TYPE_VALUE &&
2717 menu_info == setup_info)
2719 changeSetupValue(y, first_entry + y, dx);
2725 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
2727 menu_info = info_info;
2729 HandleMenuScreen(mx, my, dx, dy, button,
2730 info_mode, num_info_info, max_info_info);
2733 static int getMenuFontSpacing(int spacing_height, int font_nr)
2735 int font_spacing = getFontHeight(font_nr) + EXTRA_SPACING(game_status);
2737 return (spacing_height < 0 ? ABS(spacing_height) * font_spacing :
2741 static int getMenuTextSpacing(int spacing_height, int font_nr)
2743 return (getMenuFontSpacing(spacing_height, font_nr) +
2744 EXTRA_SPACING(game_status));
2747 static int getMenuTextStep(int spacing_height, int font_nr)
2749 return getFontHeight(font_nr) + getMenuTextSpacing(spacing_height, font_nr);
2752 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
2754 int font_title = MENU_INFO_FONT_TITLE;
2755 int font_error = FONT_TEXT_2;
2756 int font_foot = MENU_INFO_FONT_FOOT;
2757 int spacing_title = menu.headline1_spacing_info[info_mode];
2758 int ystep_title = getMenuTextStep(spacing_title, font_title);
2759 int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2760 int ystart2 = ystart1 + ystep_title;
2761 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2763 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO);
2765 FadeOut(REDRAW_FIELD);
2770 DrawTextSCentered(ystart1, font_title, text_title);
2771 DrawTextSCentered(ystart2, font_error, text_error);
2773 DrawTextSCentered(ybottom, font_foot,
2774 "Press any key or button for info menu");
2776 FadeIn(REDRAW_FIELD);
2779 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
2781 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
2782 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
2783 int font_title = MENU_INFO_FONT_TITLE;
2784 int font_foot = MENU_INFO_FONT_FOOT;
2785 int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT;
2786 int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2787 int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2;
2788 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2789 int ystep = MENU_SCREEN_INFO_YSTEP;
2790 int element, action, direction;
2798 for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++)
2799 infoscreen_step[i] = infoscreen_frame[i] = 0;
2804 DrawTextSCentered(ystart1, font_title, "The Game Elements:");
2806 DrawTextSCentered(ybottom, font_foot,
2807 "Press any key or button for next page");
2813 while (helpanim_info[j].element != HELPANIM_LIST_END)
2815 if (i >= start + NUM_INFO_ELEMENTS_ON_SCREEN ||
2820 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2829 j += infoscreen_step[i - start];
2831 element = helpanim_info[j].element;
2832 action = helpanim_info[j].action;
2833 direction = helpanim_info[j].direction;
2836 element = EL_UNKNOWN;
2838 if (action != -1 && direction != -1)
2839 graphic = el_act_dir2img(element, action, direction);
2840 else if (action != -1)
2841 graphic = el_act2img(element, action);
2842 else if (direction != -1)
2843 graphic = el_dir2img(element, direction);
2845 graphic = el2img(element);
2847 delay = helpanim_info[j++].delay;
2852 if (infoscreen_frame[i - start] == 0)
2855 infoscreen_frame[i - start] = delay - 1;
2859 sync_frame = delay - infoscreen_frame[i - start];
2860 infoscreen_frame[i - start]--;
2863 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
2865 if (!infoscreen_frame[i - start])
2866 infoscreen_step[i - start] = 0;
2870 if (!infoscreen_frame[i - start])
2871 infoscreen_step[i - start]++;
2872 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2878 ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep,
2880 DrawFixedGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep,
2881 graphic, sync_frame, USE_MASKING);
2884 DrawInfoScreen_HelpText(element, action, direction, i - start);
2889 redraw_mask |= REDRAW_FIELD;
2894 static char *getHelpText(int element, int action, int direction)
2896 char token[MAX_LINE_LEN];
2898 strcpy(token, element_info[element].token_name);
2901 strcat(token, element_action_info[action].suffix);
2903 if (direction != -1)
2904 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
2906 return getHashEntry(helptext_info, token);
2909 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
2911 int font_nr = FONT_INFO_ELEMENTS;
2912 int font_width = getFontWidth(font_nr);
2913 int font_height = getFontHeight(font_nr);
2914 int yoffset = (TILEX - 2 * font_height) / 2;
2915 int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT + TILEX + MINI_TILEX;
2916 int ystart = mSY + MENU_SCREEN_INFO_YSTART2 + yoffset;
2917 int ystep = TILEY + 4;
2918 int pad_left = xstart - SX;
2919 int pad_right = MENU_SCREEN_INFO_SPACE_RIGHT;
2920 int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width;
2921 int max_lines_per_text = 2;
2924 if (action != -1 && direction != -1) /* element.action.direction */
2925 text = getHelpText(element, action, direction);
2927 if (text == NULL && action != -1) /* element.action */
2928 text = getHelpText(element, action, -1);
2930 if (text == NULL && direction != -1) /* element.direction */
2931 text = getHelpText(element, -1, direction);
2933 if (text == NULL) /* base element */
2934 text = getHelpText(element, -1, -1);
2936 if (text == NULL) /* not found */
2937 text = "No description available";
2939 if (strlen(text) <= max_chars_per_line) /* only one line of text */
2940 ystart += getFontHeight(font_nr) / 2;
2942 DrawTextBuffer(xstart, ystart + ypos * ystep, text, font_nr,
2943 max_chars_per_line, -1, max_lines_per_text, 0, -1,
2944 TRUE, FALSE, FALSE);
2947 static void DrawInfoScreen_TitleScreen(void)
2949 SetGameStatus(GAME_MODE_TITLE);
2954 void HandleInfoScreen_TitleScreen(int button)
2956 HandleTitleScreen(0, 0, 0, 0, button);
2959 static void DrawInfoScreen_Elements(void)
2961 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
2963 FadeOut(REDRAW_FIELD);
2968 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
2970 FadeIn(REDRAW_FIELD);
2973 void HandleInfoScreen_Elements(int button)
2975 static unsigned int info_delay = 0;
2976 static int num_anims;
2977 static int num_pages;
2979 int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN;
2982 if (button == MB_MENU_INITIALIZE)
2984 boolean new_element = TRUE;
2988 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
2990 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
2992 else if (new_element)
2995 new_element = FALSE;
2999 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
3003 if (button == MB_MENU_LEAVE)
3005 PlaySound(SND_MENU_ITEM_SELECTING);
3007 info_mode = INFO_MODE_MAIN;
3012 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3014 if (button != MB_MENU_INITIALIZE)
3016 PlaySound(SND_MENU_ITEM_SELECTING);
3021 if (page >= num_pages)
3023 FadeMenuSoundsAndMusic();
3025 info_mode = INFO_MODE_MAIN;
3032 FadeSetNextScreen();
3034 if (button != MB_MENU_INITIALIZE)
3035 FadeOut(REDRAW_FIELD);
3037 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
3039 if (button != MB_MENU_INITIALIZE)
3040 FadeIn(REDRAW_FIELD);
3044 if (DelayReached(&info_delay, GameFrameDelay))
3045 if (page < num_pages)
3046 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
3048 PlayMenuSoundIfLoop();
3052 static void DrawInfoScreen_Music(void)
3054 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
3056 FadeOut(REDRAW_FIELD);
3063 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
3065 FadeIn(REDRAW_FIELD);
3068 void HandleInfoScreen_Music(int button)
3070 static struct MusicFileInfo *list = NULL;
3071 int font_title = MENU_INFO_FONT_TITLE;
3072 int font_head = MENU_INFO_FONT_HEAD;
3073 int font_text = MENU_INFO_FONT_TEXT;
3074 int font_foot = MENU_INFO_FONT_FOOT;
3075 int spacing_title = menu.headline1_spacing_info[info_mode];
3076 int spacing_head = menu.headline2_spacing_info[info_mode];
3077 int ystep_title = getMenuTextStep(spacing_title, font_title);
3078 int ystep_head = getMenuTextStep(spacing_head, font_head);
3079 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3080 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3082 if (button == MB_MENU_INITIALIZE)
3084 list = music_file_info;
3088 FadeMenuSoundsAndMusic();
3093 DrawTextSCentered(ystart, font_title,
3094 "No music info for this level set.");
3096 DrawTextSCentered(ybottom, font_foot,
3097 "Press any key or button for info menu");
3103 if (button == MB_MENU_LEAVE)
3105 PlaySound(SND_MENU_ITEM_SELECTING);
3107 FadeMenuSoundsAndMusic();
3109 info_mode = INFO_MODE_MAIN;
3114 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3116 if (button != MB_MENU_INITIALIZE)
3118 PlaySound(SND_MENU_ITEM_SELECTING);
3126 FadeMenuSoundsAndMusic();
3128 info_mode = INFO_MODE_MAIN;
3134 FadeMenuSoundsAndMusic();
3136 if (list != music_file_info)
3137 FadeSetNextScreen();
3139 if (button != MB_MENU_INITIALIZE)
3140 FadeOut(REDRAW_FIELD);
3147 int sound = list->music;
3149 if (sound_info[sound].loop)
3150 PlaySoundLoop(sound);
3154 DrawTextSCentered(ystart, font_title, "The Game Background Sounds:");
3158 int music = list->music;
3160 if (music_info[music].loop)
3161 PlayMusicLoop(music);
3165 DrawTextSCentered(ystart, font_title, "The Game Background Music:");
3168 ystart += ystep_title;
3170 if (!strEqual(list->title, UNKNOWN_NAME))
3172 if (!strEqual(list->title_header, UNKNOWN_NAME))
3174 DrawTextSCentered(ystart, font_head, list->title_header);
3175 ystart += ystep_head;
3178 DrawTextFCentered(ystart, font_text, "\"%s\"", list->title);
3179 ystart += ystep_head;
3182 if (!strEqual(list->artist, UNKNOWN_NAME))
3184 if (!strEqual(list->artist_header, UNKNOWN_NAME))
3185 DrawTextSCentered(ystart, font_head, list->artist_header);
3187 DrawTextSCentered(ystart, font_head, "by");
3189 ystart += ystep_head;
3191 DrawTextFCentered(ystart, font_text, "%s", list->artist);
3192 ystart += ystep_head;
3195 if (!strEqual(list->album, UNKNOWN_NAME))
3197 if (!strEqual(list->album_header, UNKNOWN_NAME))
3198 DrawTextSCentered(ystart, font_head, list->album_header);
3200 DrawTextSCentered(ystart, font_head, "from the album");
3202 ystart += ystep_head;
3204 DrawTextFCentered(ystart, font_text, "\"%s\"", list->album);
3205 ystart += ystep_head;
3208 if (!strEqual(list->year, UNKNOWN_NAME))
3210 if (!strEqual(list->year_header, UNKNOWN_NAME))
3211 DrawTextSCentered(ystart, font_head, list->year_header);
3213 DrawTextSCentered(ystart, font_head, "from the year");
3215 ystart += ystep_head;
3217 DrawTextFCentered(ystart, font_text, "%s", list->year);
3218 ystart += ystep_head;
3221 DrawTextSCentered(ybottom, FONT_TEXT_4,
3222 "Press any key or button for next page");
3224 if (button != MB_MENU_INITIALIZE)
3225 FadeIn(REDRAW_FIELD);
3228 if (list != NULL && list->is_sound && sound_info[list->music].loop)
3229 PlaySoundLoop(list->music);
3232 static void DrawInfoScreen_CreditsScreen(int screen_nr)
3234 int font_title = MENU_INFO_FONT_TITLE;
3235 int font_head = MENU_INFO_FONT_HEAD;
3236 int font_text = MENU_INFO_FONT_TEXT;
3237 int font_foot = MENU_INFO_FONT_FOOT;
3238 int spacing_title = menu.headline1_spacing_info[info_mode];
3239 int spacing_head = menu.headline2_spacing_info[info_mode];
3240 int spacing_para = menu.paragraph_spacing_info[info_mode];
3241 int spacing_line = menu.line_spacing_info[info_mode];
3242 int ystep_title = getMenuTextStep(spacing_title, font_title);
3243 int ystep_head = getMenuTextStep(spacing_head, font_head);
3244 int ystep_para = getMenuTextStep(spacing_para, font_text);
3245 int ystep_line = getMenuTextStep(spacing_line, font_text);
3246 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3247 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3252 DrawTextSCentered(ystart, font_title, "Credits:");
3253 ystart += ystep_title;
3257 DrawTextSCentered(ystart, font_head,
3258 "Special thanks to");
3259 ystart += ystep_head;
3260 DrawTextSCentered(ystart, font_text,
3262 ystart += ystep_head;
3263 DrawTextSCentered(ystart, font_head,
3265 ystart += ystep_head;
3266 DrawTextSCentered(ystart, font_text,
3267 "\"Boulder Dash\"");
3268 ystart += ystep_head;
3269 DrawTextSCentered(ystart, font_head,
3271 ystart += ystep_head;
3272 DrawTextSCentered(ystart, font_text,
3274 ystart += ystep_head;
3275 DrawTextSCentered(ystart, font_head,
3277 ystart += ystep_head;
3278 DrawTextSCentered(ystart, font_text,
3279 "First Star Software");
3281 else if (screen_nr == 1)
3283 DrawTextSCentered(ystart, font_head,
3284 "Special thanks to");
3285 ystart += ystep_head;
3286 DrawTextSCentered(ystart, font_text,
3287 "Klaus Heinz & Volker Wertich");
3288 ystart += ystep_head;
3289 DrawTextSCentered(ystart, font_head,
3291 ystart += ystep_head;
3292 DrawTextSCentered(ystart, font_text,
3293 "\"Emerald Mine\"");
3294 ystart += ystep_head;
3295 DrawTextSCentered(ystart, font_head,
3297 ystart += ystep_head;
3298 DrawTextSCentered(ystart, font_text,
3300 ystart += ystep_head;
3301 DrawTextSCentered(ystart, font_head,
3303 ystart += ystep_head;
3304 DrawTextSCentered(ystart, font_text,
3307 else if (screen_nr == 2)
3309 DrawTextSCentered(ystart, font_head,
3310 "Special thanks to");
3311 ystart += ystep_head;
3312 DrawTextSCentered(ystart, font_text,
3313 "Michael Stopp & Philip Jespersen");
3314 ystart += ystep_head;
3315 DrawTextSCentered(ystart, font_head,
3317 ystart += ystep_head;
3318 DrawTextSCentered(ystart, font_text,
3320 ystart += ystep_head;
3321 DrawTextSCentered(ystart, font_head,
3323 ystart += ystep_head;
3324 DrawTextSCentered(ystart, font_text,
3326 ystart += ystep_head;
3327 DrawTextSCentered(ystart, font_head,
3329 ystart += ystep_head;
3330 DrawTextSCentered(ystart, font_text,
3331 "Digital Integration");
3333 else if (screen_nr == 3)
3335 DrawTextSCentered(ystart, font_head,
3336 "Special thanks to");
3337 ystart += ystep_head;
3338 DrawTextSCentered(ystart, font_text,
3339 "Hiroyuki Imabayashi");
3340 ystart += ystep_head;
3341 DrawTextSCentered(ystart, font_head,
3343 ystart += ystep_head;
3344 DrawTextSCentered(ystart, font_text,
3346 ystart += ystep_head;
3347 DrawTextSCentered(ystart, font_head,
3349 ystart += ystep_head;
3350 DrawTextSCentered(ystart, font_text,
3352 ystart += ystep_head;
3353 DrawTextSCentered(ystart, font_head,
3355 ystart += ystep_head;
3356 DrawTextSCentered(ystart, font_text,
3359 else if (screen_nr == 4)
3361 DrawTextSCentered(ystart, font_head,
3362 "Special thanks to");
3363 ystart += ystep_head;
3364 DrawTextSCentered(ystart, font_text,
3366 ystart += ystep_head;
3367 DrawTextSCentered(ystart, font_head,
3369 ystart += ystep_head;
3370 DrawTextSCentered(ystart, font_text,
3371 "J\xfcrgen Bonhagen");
3372 ystart += ystep_head;
3373 DrawTextSCentered(ystart, font_head,
3374 "for the continuous creation");
3375 ystart += ystep_line;
3376 DrawTextSCentered(ystart, font_head,
3377 "of outstanding level sets");
3379 else if (screen_nr == 5)
3381 DrawTextSCentered(ystart, font_head,
3383 ystart += ystep_head;
3384 DrawTextSCentered(ystart, font_text,
3386 ystart += ystep_head;
3387 DrawTextSCentered(ystart, font_head,
3388 "for ideas and inspiration by");
3389 ystart += ystep_head;
3390 DrawTextSCentered(ystart, font_text,
3392 ystart += ystep_para;
3394 DrawTextSCentered(ystart, font_head,
3396 ystart += ystep_head;
3397 DrawTextSCentered(ystart, font_text,
3399 ystart += ystep_head;
3400 DrawTextSCentered(ystart, font_head,
3401 "for ideas and inspiration by");
3402 ystart += ystep_head;
3403 DrawTextSCentered(ystart, font_text,
3406 else if (screen_nr == 6)
3408 DrawTextSCentered(ystart, font_head,
3410 ystart += ystep_head;
3411 DrawTextSCentered(ystart, font_text,
3413 ystart += ystep_head;
3414 DrawTextSCentered(ystart, font_head,
3415 "for the code base used for the");
3416 ystart += ystep_line;
3417 DrawTextSCentered(ystart, font_head,
3418 "native Emerald Mine engine");
3420 else if (screen_nr == 7)
3422 DrawTextSCentered(ystart, font_head,
3424 ystart += ystep_head;
3425 DrawTextSCentered(ystart, font_text,
3427 ystart += ystep_head;
3428 DrawTextSCentered(ystart, font_head,
3429 "for the initial DOS port");
3430 ystart += ystep_para;
3432 DrawTextSCentered(ystart, font_head,
3434 ystart += ystep_head;
3435 DrawTextSCentered(ystart, font_text,
3437 ystart += ystep_head;
3438 DrawTextSCentered(ystart, font_head,
3439 "for some additional toons");
3441 else if (screen_nr == 8)
3443 DrawTextSCentered(ystart, font_head,
3444 "And not to forget:");
3445 ystart += ystep_head;
3446 DrawTextSCentered(ystart, font_head,
3448 ystart += ystep_head;
3449 DrawTextSCentered(ystart, font_text,
3450 "All those who contributed");
3451 ystart += ystep_line;
3452 DrawTextSCentered(ystart, font_text,
3453 "levels to this game");
3454 ystart += ystep_line;
3455 DrawTextSCentered(ystart, font_text,
3459 DrawTextSCentered(ybottom, font_foot,
3460 "Press any key or button for next page");
3463 static void DrawInfoScreen_Credits(void)
3465 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
3467 FadeMenuSoundsAndMusic();
3469 FadeOut(REDRAW_FIELD);
3471 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
3473 FadeIn(REDRAW_FIELD);
3476 void HandleInfoScreen_Credits(int button)
3478 static int screen_nr = 0;
3479 int num_screens = 9;
3481 if (button == MB_MENU_INITIALIZE)
3485 // DrawInfoScreen_CreditsScreen(screen_nr);
3488 if (button == MB_MENU_LEAVE)
3490 PlaySound(SND_MENU_ITEM_SELECTING);
3492 info_mode = INFO_MODE_MAIN;
3497 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3499 if (button != MB_MENU_INITIALIZE)
3501 PlaySound(SND_MENU_ITEM_SELECTING);
3506 if (screen_nr >= num_screens)
3508 FadeMenuSoundsAndMusic();
3510 info_mode = INFO_MODE_MAIN;
3517 FadeSetNextScreen();
3519 if (button != MB_MENU_INITIALIZE)
3520 FadeOut(REDRAW_FIELD);
3522 DrawInfoScreen_CreditsScreen(screen_nr);
3524 if (button != MB_MENU_INITIALIZE)
3525 FadeIn(REDRAW_FIELD);
3529 PlayMenuSoundIfLoop();
3533 static void DrawInfoScreen_Program(void)
3535 int font_title = MENU_INFO_FONT_TITLE;
3536 int font_head = MENU_INFO_FONT_HEAD;
3537 int font_text = MENU_INFO_FONT_TEXT;
3538 int font_foot = MENU_INFO_FONT_FOOT;
3539 int spacing_title = menu.headline1_spacing_info[info_mode];
3540 int spacing_head = menu.headline2_spacing_info[info_mode];
3541 int spacing_para = menu.paragraph_spacing_info[info_mode];
3542 int spacing_line = menu.line_spacing_info[info_mode];
3543 int ystep_title = getMenuTextStep(spacing_title, font_title);
3544 int ystep_head = getMenuTextStep(spacing_head, font_head);
3545 int ystep_para = getMenuTextStep(spacing_para, font_text);
3546 int ystep_line = getMenuTextStep(spacing_line, font_text);
3547 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3548 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3550 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
3552 FadeOut(REDRAW_FIELD);
3557 DrawTextSCentered(ystart, font_title, "Program Information:");
3558 ystart += ystep_title;
3560 DrawTextSCentered(ystart, font_head,
3561 "This game is Freeware!");
3562 ystart += ystep_head;
3563 DrawTextSCentered(ystart, font_head,
3564 "If you like it, send e-mail to:");
3565 ystart += ystep_head;
3566 DrawTextSCentered(ystart, font_text,
3567 setup.internal.program_email);
3568 ystart += ystep_para;
3570 DrawTextSCentered(ystart, font_head,
3571 "More information and levels:");
3572 ystart += ystep_head;
3573 DrawTextSCentered(ystart, font_text,
3574 setup.internal.program_website);
3575 ystart += ystep_para;
3577 DrawTextSCentered(ystart, font_head,
3578 "If you have created new levels,");
3579 ystart += ystep_line;
3580 DrawTextSCentered(ystart, font_head,
3581 "send them to me to include them!");
3582 ystart += ystep_head;
3583 DrawTextSCentered(ystart, font_head,
3586 DrawTextSCentered(ybottom, font_foot,
3587 "Press any key or button for info menu");
3589 FadeIn(REDRAW_FIELD);
3592 void HandleInfoScreen_Program(int button)
3594 if (button == MB_MENU_LEAVE)
3596 PlaySound(SND_MENU_ITEM_SELECTING);
3598 info_mode = INFO_MODE_MAIN;
3603 else if (button == MB_MENU_CHOICE)
3605 PlaySound(SND_MENU_ITEM_SELECTING);
3607 FadeMenuSoundsAndMusic();
3609 info_mode = INFO_MODE_MAIN;
3614 PlayMenuSoundIfLoop();
3618 static void DrawInfoScreen_Version(void)
3620 int font_title = MENU_INFO_FONT_TITLE;
3621 int font_head = MENU_INFO_FONT_HEAD;
3622 int font_text = MENU_INFO_FONT_TEXT;
3623 int font_foot = MENU_INFO_FONT_FOOT;
3624 int spacing_title = menu.headline1_spacing_info[info_mode];
3625 int spacing_head = menu.headline2_spacing_info[info_mode];
3626 int spacing_para = menu.paragraph_spacing_info[info_mode];
3627 int spacing_line = menu.line_spacing_info[info_mode];
3628 int xstep = getFontWidth(font_text);
3629 int ystep_title = getMenuTextStep(spacing_title, font_title);
3630 int ystep_head = getMenuTextStep(spacing_head, font_head);
3631 int ystep_para = getMenuTextStep(spacing_para, font_text);
3632 int ystep_line = getMenuTextStep(spacing_line, font_text);
3633 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3634 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3635 int xstart1 = mSX - SX + 2 * xstep;
3636 int xstart2 = mSX - SX + 18 * xstep;
3637 int xstart3 = mSX - SX + 28 * xstep;
3638 SDL_version sdl_version_compiled;
3639 const SDL_version *sdl_version_linked;
3640 int driver_name_len = 10;
3641 #if defined(TARGET_SDL2)
3642 SDL_version sdl_version_linked_ext;
3643 const char *driver_name = NULL;
3645 char driver_name[driver_name_len];
3648 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION);
3650 FadeOut(REDRAW_FIELD);
3655 DrawTextSCentered(ystart, font_title, "Version Information:");
3656 ystart += ystep_title;
3658 DrawTextF(xstart1, ystart, font_head, "Name");
3659 DrawTextF(xstart2, ystart, font_text, getProgramTitleString());
3660 ystart += ystep_line;
3662 if (!strEqual(getProgramVersionString(), getProgramRealVersionString()))
3664 DrawTextF(xstart1, ystart, font_head, "Version (fake)");
3665 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3666 ystart += ystep_line;
3668 DrawTextF(xstart1, ystart, font_head, "Version (real)");
3669 DrawTextF(xstart2, ystart, font_text, getProgramRealVersionString());
3670 ystart += ystep_line;
3674 DrawTextF(xstart1, ystart, font_head, "Version");
3675 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3676 ystart += ystep_line;
3679 DrawTextF(xstart1, ystart, font_head, "Platform");
3680 DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING);
3681 ystart += ystep_line;
3683 DrawTextF(xstart1, ystart, font_head, "Target");
3684 DrawTextF(xstart2, ystart, font_text, TARGET_STRING);
3685 ystart += ystep_line;
3687 DrawTextF(xstart1, ystart, font_head, "Source date");
3688 DrawTextF(xstart2, ystart, font_text, getSourceDateString());
3689 ystart += ystep_para;
3691 DrawTextF(xstart1, ystart, font_head, "Library");
3692 DrawTextF(xstart2, ystart, font_head, "compiled");
3693 DrawTextF(xstart3, ystart, font_head, "linked");
3694 ystart += ystep_head;
3696 SDL_VERSION(&sdl_version_compiled);
3697 #if defined(TARGET_SDL2)
3698 SDL_GetVersion(&sdl_version_linked_ext);
3699 sdl_version_linked = &sdl_version_linked_ext;
3701 sdl_version_linked = SDL_Linked_Version();
3704 DrawTextF(xstart1, ystart, font_text, "SDL");
3705 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3706 sdl_version_compiled.major,
3707 sdl_version_compiled.minor,
3708 sdl_version_compiled.patch);
3709 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3710 sdl_version_linked->major,
3711 sdl_version_linked->minor,
3712 sdl_version_linked->patch);
3713 ystart += ystep_line;
3715 SDL_IMAGE_VERSION(&sdl_version_compiled);
3716 sdl_version_linked = IMG_Linked_Version();
3718 DrawTextF(xstart1, ystart, font_text, "SDL_image");
3719 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3720 sdl_version_compiled.major,
3721 sdl_version_compiled.minor,
3722 sdl_version_compiled.patch);
3723 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3724 sdl_version_linked->major,
3725 sdl_version_linked->minor,
3726 sdl_version_linked->patch);
3727 ystart += ystep_line;
3729 SDL_MIXER_VERSION(&sdl_version_compiled);
3730 sdl_version_linked = Mix_Linked_Version();
3732 DrawTextF(xstart1, ystart, font_text, "SDL_mixer");
3733 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3734 sdl_version_compiled.major,
3735 sdl_version_compiled.minor,
3736 sdl_version_compiled.patch);
3737 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3738 sdl_version_linked->major,
3739 sdl_version_linked->minor,
3740 sdl_version_linked->patch);
3741 ystart += ystep_line;
3743 SDL_NET_VERSION(&sdl_version_compiled);
3744 sdl_version_linked = SDLNet_Linked_Version();
3746 DrawTextF(xstart1, ystart, font_text, "SDL_net");
3747 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3748 sdl_version_compiled.major,
3749 sdl_version_compiled.minor,
3750 sdl_version_compiled.patch);
3751 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3752 sdl_version_linked->major,
3753 sdl_version_linked->minor,
3754 sdl_version_linked->patch);
3755 ystart += ystep_para;