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_FIRST_LEVEL 2
178 #define SCREEN_CTRL_ID_LAST_LEVEL 3
179 #define SCREEN_CTRL_ID_LEVEL_NUMBER 4
180 #define SCREEN_CTRL_ID_PREV_PLAYER 5
181 #define SCREEN_CTRL_ID_NEXT_PLAYER 6
182 #define SCREEN_CTRL_ID_INSERT_SOLUTION 7
183 #define SCREEN_CTRL_ID_PLAY_SOLUTION 8
184 #define SCREEN_CTRL_ID_SCROLL_UP 9
185 #define SCREEN_CTRL_ID_SCROLL_DOWN 10
186 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 11
187 #define SCREEN_CTRL_ID_NETWORK_SERVER 12
189 #define NUM_SCREEN_GADGETS 13
191 #define NUM_SCREEN_MENUBUTTONS 9
192 #define NUM_SCREEN_SCROLLBUTTONS 2
193 #define NUM_SCREEN_SCROLLBARS 1
194 #define NUM_SCREEN_TEXTINPUT 1
196 #define SCREEN_MASK_MAIN (1 << 0)
197 #define SCREEN_MASK_MAIN_HAS_SOLUTION (1 << 1)
198 #define SCREEN_MASK_INPUT (1 << 2)
200 // graphic position and size values for buttons and scrollbars
201 #define SC_MENUBUTTON_XSIZE TILEX
202 #define SC_MENUBUTTON_YSIZE TILEY
204 #define SC_SCROLLBUTTON_XSIZE TILEX
205 #define SC_SCROLLBUTTON_YSIZE TILEY
207 #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
209 #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
210 #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
211 SC_SCROLLBUTTON_YSIZE)
213 #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS
214 #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE)
216 #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS
217 #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \
218 SC_SCROLLBUTTON_YSIZE)
220 #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS
221 #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \
222 SC_SCROLL_VERTICAL_YSIZE)
224 #define SC_BORDER_SIZE 14
227 // forward declarations of internal functions
228 static void HandleScreenGadgets(struct GadgetInfo *);
229 static void HandleSetupScreen_Generic(int, int, int, int, int);
230 static void HandleSetupScreen_Input(int, int, int, int, int);
231 static void CustomizeKeyboard(int);
232 static void ConfigureJoystick(int);
233 static void ConfigureVirtualButtons(void);
234 static void execSetupGame(void);
235 static void execSetupGraphics(void);
236 static void execSetupSound(void);
237 static void execSetupTouch(void);
238 static void execSetupArtwork(void);
239 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
241 static void DrawChooseLevelSet(void);
242 static void DrawChooseLevelNr(void);
243 static void DrawInfoScreen(void);
244 static void DrawSetupScreen(void);
246 static void DrawInfoScreen_NotAvailable(char *, char *);
247 static void DrawInfoScreen_HelpAnim(int, int, boolean);
248 static void DrawInfoScreen_HelpText(int, int, int, int);
249 static void HandleInfoScreen_Main(int, int, int, int, int);
250 static void HandleInfoScreen_TitleScreen(int);
251 static void HandleInfoScreen_Elements(int);
252 static void HandleInfoScreen_Music(int);
253 static void HandleInfoScreen_Credits(int);
254 static void HandleInfoScreen_Program(int);
255 static void HandleInfoScreen_Version(int);
257 static void ModifyGameSpeedIfNeeded(void);
258 static void DisableVsyncIfNeeded(void);
260 static void MapScreenMenuGadgets(int);
261 static void MapScreenGadgets(int);
262 static void MapScreenTreeGadgets(TreeInfo *);
264 static void UpdateScreenMenuGadgets(int, boolean);
266 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
268 static int info_mode = INFO_MODE_MAIN;
269 static int setup_mode = SETUP_MODE_MAIN;
271 static TreeInfo *window_sizes = NULL;
272 static TreeInfo *window_size_current = NULL;
274 static TreeInfo *scaling_types = NULL;
275 static TreeInfo *scaling_type_current = NULL;
277 static TreeInfo *rendering_modes = NULL;
278 static TreeInfo *rendering_mode_current = NULL;
280 static TreeInfo *vsync_modes = NULL;
281 static TreeInfo *vsync_mode_current = NULL;
283 static TreeInfo *scroll_delays = NULL;
284 static TreeInfo *scroll_delay_current = NULL;
286 static TreeInfo *snapshot_modes = NULL;
287 static TreeInfo *snapshot_mode_current = NULL;
289 static TreeInfo *game_speeds_normal = NULL;
290 static TreeInfo *game_speeds_extended = NULL;
291 static TreeInfo *game_speeds = NULL;
292 static TreeInfo *game_speed_current = NULL;
294 static TreeInfo *volumes_simple = NULL;
295 static TreeInfo *volume_simple_current = NULL;
297 static TreeInfo *volumes_loops = NULL;
298 static TreeInfo *volume_loops_current = NULL;
300 static TreeInfo *volumes_music = NULL;
301 static TreeInfo *volume_music_current = NULL;
303 static TreeInfo *touch_controls = NULL;
304 static TreeInfo *touch_control_current = NULL;
306 static TreeInfo *move_distances = NULL;
307 static TreeInfo *move_distance_current = NULL;
309 static TreeInfo *drop_distances = NULL;
310 static TreeInfo *drop_distance_current = NULL;
312 static TreeInfo *transparencies = NULL;
313 static TreeInfo *transparency_current = NULL;
315 static TreeInfo *grid_sizes[2][2] = { { NULL, NULL }, { NULL, NULL } };
316 static TreeInfo *grid_size_current[2][2] = { { NULL, NULL }, { NULL, NULL } };
318 static TreeInfo *level_number = NULL;
319 static TreeInfo *level_number_current = NULL;
321 static struct ValueTextInfo window_sizes_list[] =
326 { 100, "100 % (Default)" },
339 static struct StringValueTextInfo scaling_types_list[] =
341 { SCALING_QUALITY_NEAREST, "Off" },
342 { SCALING_QUALITY_LINEAR, "Linear" },
343 { SCALING_QUALITY_BEST, "Anisotropic" },
348 static struct StringValueTextInfo rendering_modes_list[] =
350 { STR_SPECIAL_RENDERING_OFF, "Off (May show artifacts, fast)" },
351 { STR_SPECIAL_RENDERING_BITMAP, "Bitmap/Texture mode (slower)" },
353 // this mode may work under certain conditions, but does not work on Windows
354 { STR_SPECIAL_RENDERING_TARGET, "Target Texture mode (slower)" },
356 { STR_SPECIAL_RENDERING_DOUBLE, "Double Texture mode (slower)" },
361 static struct StringValueTextInfo vsync_modes_list[] =
363 { STR_VSYNC_MODE_OFF, "Off" },
364 { STR_VSYNC_MODE_NORMAL, "Normal" },
365 { STR_VSYNC_MODE_ADAPTIVE, "Adaptive" },
370 static struct ValueTextInfo game_speeds_list_normal[] =
381 static struct ValueTextInfo game_speeds_list_extended[] =
383 { 1000, "1 fps (Extremely Slow)" },
388 { 29, "35 fps (Original Supaplex)" },
390 { 20, "50 fps (=== Normal Speed ===)" },
391 { 16, "60 fps (60 Hz VSync Speed)" },
392 { 14, "70 fps (Maximum Supaplex)" },
396 { 1, "1000 fps (Extremely Fast)" },
401 static struct ValueTextInfo *game_speeds_list;
403 static struct ValueTextInfo scroll_delays_list[] =
405 { 0, "0 Tiles (No Scroll Delay)" },
408 { 3, "3 Tiles (Default)" },
413 { 8, "8 Tiles (Maximum Scroll Delay)"},
418 static struct StringValueTextInfo snapshot_modes_list[] =
420 { STR_SNAPSHOT_MODE_OFF, "Off" },
421 { STR_SNAPSHOT_MODE_EVERY_STEP, "Every Step" },
422 { STR_SNAPSHOT_MODE_EVERY_MOVE, "Every Move" },
423 { STR_SNAPSHOT_MODE_EVERY_COLLECT, "Every Collect" },
428 static struct ValueTextInfo volumes_list[] =
448 static struct StringValueTextInfo touch_controls_list[] =
450 { TOUCH_CONTROL_OFF, "Off" },
451 { TOUCH_CONTROL_VIRTUAL_BUTTONS, "Virtual Buttons" },
452 { TOUCH_CONTROL_WIPE_GESTURES, "Wipe Gestures" },
453 { TOUCH_CONTROL_FOLLOW_FINGER, "Follow Finger" },
458 static struct ValueTextInfo distances_list[] =
473 static struct ValueTextInfo transparencies_list[] =
475 { 0, "0 % (Opaque)" },
485 { 100, "100 % (Invisible)" },
490 static struct ValueTextInfo grid_sizes_list[] =
526 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
527 (s) <= GAME_MODE_SETUP ? (s) : \
528 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
529 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
531 // (there are no draw offset definitions needed for INFO_MODE_TITLE)
532 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_TITLE && \
533 (i) <= INFO_MODE_LEVELSET ? (i) : \
536 #define DRAW_MODE_SETUP(i) ((i) >= SETUP_MODE_MAIN && \
537 (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) : \
538 (i) >= SETUP_MODE_CHOOSE_GRAPHICS && \
539 (i) <= SETUP_MODE_CHOOSE_MUSIC ? \
540 SETUP_MODE_CHOOSE_ARTWORK : \
541 SETUP_MODE_CHOOSE_OTHER)
543 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
544 menu.draw_xoffset[GAME_MODE_INFO] : \
545 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
546 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
547 menu.draw_yoffset[GAME_MODE_INFO] : \
548 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
549 #define EXTRA_SPACING_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
550 menu.extra_spacing[GAME_MODE_INFO] : \
551 menu.extra_spacing_info[DRAW_MODE_INFO(i)])
553 #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
554 menu.draw_xoffset[GAME_MODE_SETUP] : \
555 menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)])
556 #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
557 menu.draw_yoffset[GAME_MODE_SETUP] : \
558 menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)])
559 #define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
560 menu.extra_spacing[GAME_MODE_SETUP] : \
561 menu.extra_spacing_setup[DRAW_MODE_SETUP(i)])
563 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
564 DRAW_XOFFSET_INFO(info_mode) : \
565 (s) == GAME_MODE_SETUP ? \
566 DRAW_XOFFSET_SETUP(setup_mode) : \
567 menu.draw_xoffset[DRAW_MODE(s)])
568 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
569 DRAW_YOFFSET_INFO(info_mode) : \
570 (s) == GAME_MODE_SETUP ? \
571 DRAW_YOFFSET_SETUP(setup_mode) : \
572 menu.draw_yoffset[DRAW_MODE(s)])
573 #define EXTRA_SPACING(s) ((s) == GAME_MODE_INFO ? \
574 EXTRA_SPACING_INFO(info_mode) : \
575 (s) == GAME_MODE_SETUP ? \
576 EXTRA_SPACING_SETUP(setup_mode) : \
577 menu.extra_spacing[DRAW_MODE(s)])
579 #define mSX (SX + DRAW_XOFFSET(game_status))
580 #define mSY (SY + DRAW_YOFFSET(game_status))
582 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
583 menu.list_size[game_status] : \
584 MAX_MENU_ENTRIES_ON_SCREEN)
586 #define IN_VIS_MENU(x, y) IN_FIELD(x, y, SCR_FIELDX, \
587 NUM_MENU_ENTRIES_ON_SCREEN)
590 // title display and control definitions
592 #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \
593 2 * MAX_NUM_TITLE_MESSAGES)
595 #define NO_DIRECT_LEVEL_SELECT (-1)
598 static int num_title_screens = 0;
600 struct TitleControlInfo
609 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
611 // main menu display and control definitions
613 #define MAIN_CONTROL_NAME 0
614 #define MAIN_CONTROL_LEVELS 1
615 #define MAIN_CONTROL_SCORES 2
616 #define MAIN_CONTROL_EDITOR 3
617 #define MAIN_CONTROL_INFO 4
618 #define MAIN_CONTROL_GAME 5
619 #define MAIN_CONTROL_SETUP 6
620 #define MAIN_CONTROL_QUIT 7
621 #define MAIN_CONTROL_PREV_LEVEL 8
622 #define MAIN_CONTROL_NEXT_LEVEL 9
623 #define MAIN_CONTROL_FIRST_LEVEL 10
624 #define MAIN_CONTROL_LAST_LEVEL 11
625 #define MAIN_CONTROL_LEVEL_NUMBER 12
626 #define MAIN_CONTROL_LEVEL_INFO_1 13
627 #define MAIN_CONTROL_LEVEL_INFO_2 14
628 #define MAIN_CONTROL_LEVEL_NAME 15
629 #define MAIN_CONTROL_LEVEL_AUTHOR 16
630 #define MAIN_CONTROL_LEVEL_YEAR 17
631 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM 18
632 #define MAIN_CONTROL_LEVEL_IMPORTED_BY 19
633 #define MAIN_CONTROL_LEVEL_TESTED_BY 20
634 #define MAIN_CONTROL_TITLE_1 21
635 #define MAIN_CONTROL_TITLE_2 22
636 #define MAIN_CONTROL_TITLE_3 23
638 static char str_main_text_name[10];
639 static char str_main_text_first_level[10];
640 static char str_main_text_last_level[10];
641 static char str_main_text_level_number[10];
643 static char network_server_hostname[MAX_SETUP_TEXT_INPUT_LEN + 1];
645 static char *main_text_name = str_main_text_name;
646 static char *main_text_first_level = str_main_text_first_level;
647 static char *main_text_last_level = str_main_text_last_level;
648 static char *main_text_level_number = str_main_text_level_number;
649 static char *main_text_levels = "Levelset";
650 static char *main_text_scores = "Hall Of Fame";
651 static char *main_text_editor = "Level Creator";
652 static char *main_text_info = "Info Screen";
653 static char *main_text_game = "Start Game";
654 static char *main_text_setup = "Setup";
655 static char *main_text_quit = "Quit";
656 static char *main_text_level_name = level.name;
657 static char *main_text_level_author = level.author;
658 static char *main_text_level_year = NULL;
659 static char *main_text_level_imported_from = NULL;
660 static char *main_text_level_imported_by = NULL;
661 static char *main_text_level_tested_by = NULL;
662 static char *main_text_title_1 = NULL;
663 static char *main_text_title_2 = NULL;
664 static char *main_text_title_3 = NULL;
666 struct MainControlInfo
670 struct MenuPosInfo *pos_button;
673 struct TextPosInfo *pos_text;
676 struct TextPosInfo *pos_input;
680 static struct MainControlInfo main_controls[] =
684 &menu.main.button.name, IMG_MENU_BUTTON_NAME,
685 &menu.main.text.name, &main_text_name,
686 &menu.main.input.name, &setup.player_name,
690 &menu.main.button.levels, IMG_MENU_BUTTON_LEVELS,
691 &menu.main.text.levels, &main_text_levels,
696 &menu.main.button.scores, IMG_MENU_BUTTON_SCORES,
697 &menu.main.text.scores, &main_text_scores,
702 &menu.main.button.editor, IMG_MENU_BUTTON_EDITOR,
703 &menu.main.text.editor, &main_text_editor,
708 &menu.main.button.info, IMG_MENU_BUTTON_INFO,
709 &menu.main.text.info, &main_text_info,
714 &menu.main.button.game, IMG_MENU_BUTTON_GAME,
715 &menu.main.text.game, &main_text_game,
720 &menu.main.button.setup, IMG_MENU_BUTTON_SETUP,
721 &menu.main.text.setup, &main_text_setup,
726 &menu.main.button.quit, IMG_MENU_BUTTON_QUIT,
727 &menu.main.text.quit, &main_text_quit,
731 MAIN_CONTROL_PREV_LEVEL,
737 MAIN_CONTROL_NEXT_LEVEL,
743 MAIN_CONTROL_FIRST_LEVEL,
745 &menu.main.text.first_level, &main_text_first_level,
749 MAIN_CONTROL_LAST_LEVEL,
751 &menu.main.text.last_level, &main_text_last_level,
755 MAIN_CONTROL_LEVEL_NUMBER,
757 &menu.main.text.level_number, &main_text_level_number,
761 MAIN_CONTROL_LEVEL_INFO_1,
763 &menu.main.text.level_info_1, NULL,
767 MAIN_CONTROL_LEVEL_INFO_2,
769 &menu.main.text.level_info_2, NULL,
773 MAIN_CONTROL_LEVEL_NAME,
775 &menu.main.text.level_name, &main_text_level_name,
779 MAIN_CONTROL_LEVEL_AUTHOR,
781 &menu.main.text.level_author, &main_text_level_author,
785 MAIN_CONTROL_LEVEL_YEAR,
787 &menu.main.text.level_year, &main_text_level_year,
791 MAIN_CONTROL_LEVEL_IMPORTED_FROM,
793 &menu.main.text.level_imported_from, &main_text_level_imported_from,
797 MAIN_CONTROL_LEVEL_IMPORTED_BY,
799 &menu.main.text.level_imported_by, &main_text_level_imported_by,
803 MAIN_CONTROL_LEVEL_TESTED_BY,
805 &menu.main.text.level_tested_by, &main_text_level_tested_by,
809 MAIN_CONTROL_TITLE_1,
811 &menu.main.text.title_1, &main_text_title_1,
815 MAIN_CONTROL_TITLE_2,
817 &menu.main.text.title_2, &main_text_title_2,
821 MAIN_CONTROL_TITLE_3,
823 &menu.main.text.title_3, &main_text_title_3,
836 static int getTitleScreenGraphic(int nr, boolean initial)
838 return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
841 static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial)
843 return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]);
847 static int getTitleScreenGameMode(boolean initial)
849 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
853 static int getTitleMessageGameMode(boolean initial)
855 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
858 static int getTitleAnimMode(struct TitleControlInfo *tci)
860 int base = (tci->initial ? GAME_MODE_TITLE_INITIAL_1 : GAME_MODE_TITLE_1);
862 return base + tci->local_nr;
866 static int getTitleScreenBackground(boolean initial)
868 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
873 static int getTitleMessageBackground(int nr, boolean initial)
875 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
879 static int getTitleBackground(int nr, boolean initial, boolean is_image)
881 int base = (is_image ?
882 (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 :
883 IMG_BACKGROUND_TITLESCREEN_1) :
884 (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
885 IMG_BACKGROUND_TITLEMESSAGE_1));
886 int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL :
887 IMG_BACKGROUND_TITLE);
888 int graphic_local = base + nr;
890 if (graphic_info[graphic_local].bitmap != NULL)
891 return graphic_local;
893 if (graphic_info[graphic_global].bitmap != NULL)
894 return graphic_global;
896 return IMG_UNDEFINED;
899 static int getTitleSound(struct TitleControlInfo *tci)
901 boolean is_image = tci->is_image;
902 int initial = tci->initial;
903 int nr = tci->local_nr;
904 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
905 int base = (is_image ?
906 (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 :
907 SND_BACKGROUND_TITLESCREEN_1) :
908 (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
909 SND_BACKGROUND_TITLEMESSAGE_1));
910 int sound_global = menu.sound[mode];
911 int sound_local = base + nr;
914 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
915 nr, initial, is_image,
916 sound_global, getSoundListEntry(sound_global)->filename,
917 sound_local, getSoundListEntry(sound_local)->filename);
920 if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME))
923 if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME))
926 return SND_UNDEFINED;
929 static int getTitleMusic(struct TitleControlInfo *tci)
931 boolean is_image = tci->is_image;
932 int initial = tci->initial;
933 int nr = tci->local_nr;
934 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
935 int base = (is_image ?
936 (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 :
937 MUS_BACKGROUND_TITLESCREEN_1) :
938 (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
939 MUS_BACKGROUND_TITLEMESSAGE_1));
940 int music_global = menu.music[mode];
941 int music_local = base + nr;
944 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
945 nr, initial, is_image,
946 music_global, getMusicListEntry(music_global)->filename,
947 music_local, getMusicListEntry(music_local)->filename);
950 if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME))
953 if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME))
956 return MUS_UNDEFINED;
959 static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci)
961 boolean is_image = tci->is_image;
962 boolean initial = tci->initial;
963 boolean first = tci->first;
964 int nr = tci->local_nr;
965 struct TitleMessageInfo tmi;
966 struct TitleFadingInfo ti;
968 tmi = (is_image ? (initial ? (first ?
969 titlescreen_initial_first[nr] :
970 titlescreen_initial[nr])
972 titlescreen_first[nr] :
974 : (initial ? (first ?
975 titlemessage_initial_first[nr] :
976 titlemessage_initial[nr])
978 titlemessage_first[nr] :
981 ti.fade_mode = tmi.fade_mode;
982 ti.fade_delay = tmi.fade_delay;
983 ti.post_delay = tmi.post_delay;
984 ti.auto_delay = tmi.auto_delay;
989 static int compareTitleControlInfo(const void *object1, const void *object2)
991 const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1;
992 const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2;
995 if (tci1->initial != tci2->initial)
996 compare_result = (tci1->initial ? -1 : +1);
997 else if (tci1->sort_priority != tci2->sort_priority)
998 compare_result = tci1->sort_priority - tci2->sort_priority;
999 else if (tci1->is_image != tci2->is_image)
1000 compare_result = (tci1->is_image ? -1 : +1);
1002 compare_result = tci1->local_nr - tci2->local_nr;
1004 return compare_result;
1007 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
1009 int nr, int sort_priority)
1011 title_controls[num_title_screens].is_image = is_image;
1012 title_controls[num_title_screens].initial = initial;
1013 title_controls[num_title_screens].local_nr = nr;
1014 title_controls[num_title_screens].sort_priority = sort_priority;
1016 title_controls[num_title_screens].first = FALSE; // will be set later
1018 num_title_screens++;
1021 static void InitializeTitleControls_CheckTitleInfo(boolean initial)
1025 for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++)
1027 int graphic = getTitleScreenGraphic(i, initial);
1028 Bitmap *bitmap = graphic_info[graphic].bitmap;
1029 int sort_priority = graphic_info[graphic].sort_priority;
1032 InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority);
1035 for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
1037 struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial);
1038 char *filename = getLevelSetTitleMessageFilename(i, initial);
1039 int sort_priority = tmi->sort_priority;
1041 if (filename != NULL)
1042 InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority);
1046 static void InitializeTitleControls(boolean show_title_initial)
1048 num_title_screens = 0;
1050 // 1st step: initialize title screens for game start (only when starting)
1051 if (show_title_initial)
1052 InitializeTitleControls_CheckTitleInfo(TRUE);
1054 // 2nd step: initialize title screens for current level set
1055 InitializeTitleControls_CheckTitleInfo(FALSE);
1057 // sort title screens according to sort_priority and title number
1058 qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo),
1059 compareTitleControlInfo);
1061 // mark first title screen
1062 title_controls[0].first = TRUE;
1065 static boolean visibleMenuPos(struct MenuPosInfo *pos)
1067 return (pos != NULL && pos->x != -1 && pos->y != -1);
1070 static boolean visibleTextPos(struct TextPosInfo *pos)
1072 return (pos != NULL && pos->x != -1 && pos->y != -1);
1075 static void InitializeMainControls(void)
1077 boolean local_team_mode = (!network.enabled && setup.team_mode);
1080 // set main control text values to dynamically determined values
1081 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
1083 strcpy(main_text_first_level, int2str(leveldir_current->first_level,
1084 menu.main.text.first_level.size));
1085 strcpy(main_text_last_level, int2str(leveldir_current->last_level,
1086 menu.main.text.last_level.size));
1087 strcpy(main_text_level_number, int2str(level_nr,
1088 menu.main.text.level_number.size));
1090 main_text_level_year = leveldir_current->year;
1091 main_text_level_imported_from = leveldir_current->imported_from;
1092 main_text_level_imported_by = leveldir_current->imported_by;
1093 main_text_level_tested_by = leveldir_current->tested_by;
1095 main_text_title_1 = getConfigProgramTitleString();
1096 main_text_title_2 = getConfigProgramCopyrightString();
1097 main_text_title_3 = getConfigProgramCompanyString();
1099 // set main control screen positions to dynamically determined values
1100 for (i = 0; main_controls[i].nr != -1; i++)
1102 struct MainControlInfo *mci = &main_controls[i];
1104 struct MenuPosInfo *pos_button = mci->pos_button;
1105 struct TextPosInfo *pos_text = mci->pos_text;
1106 struct TextPosInfo *pos_input = mci->pos_input;
1107 char *text = (mci->text ? *mci->text : NULL);
1108 char *input = (mci->input ? *mci->input : NULL);
1109 int button_graphic = mci->button_graphic;
1110 int font_text = (pos_text ? pos_text->font : -1);
1111 int font_input = (pos_input ? pos_input->font : -1);
1113 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
1114 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
1115 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
1116 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
1117 int text_chars = (text != NULL ? strlen(text) : 0);
1118 int input_chars = (input != NULL ? strlen(input) : 0);
1121 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
1123 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
1124 int text_width = font_text_width * text_chars;
1125 int text_height = font_text_height;
1126 int input_width = font_input_width * input_chars;
1127 int input_height = font_input_height;
1129 if (nr == MAIN_CONTROL_NAME)
1131 menu.main.input.name.width = input_width;
1132 menu.main.input.name.height = input_height;
1135 if (pos_button != NULL) // (x/y may be -1/-1 here)
1137 pos_button->width = button_width;
1138 pos_button->height = button_height;
1141 if (pos_text != NULL) // (x/y may be -1/-1 here)
1143 // calculate text size -- needed for text alignment
1144 boolean calculate_text_size = (text != NULL);
1146 if (pos_text->width == -1 || calculate_text_size)
1147 pos_text->width = text_width;
1148 if (pos_text->height == -1 || calculate_text_size)
1149 pos_text->height = text_height;
1151 if (visibleMenuPos(pos_button))
1153 if (pos_text->x == -1)
1154 pos_text->x = pos_button->x + pos_button->width;
1155 if (pos_text->y == -1)
1157 pos_button->y + (pos_button->height - pos_text->height) / 2;
1161 if (pos_input != NULL) // (x/y may be -1/-1 here)
1163 if (visibleTextPos(pos_text))
1165 if (pos_input->x == -1)
1166 pos_input->x = pos_text->x + pos_text->width;
1167 if (pos_input->y == -1)
1168 pos_input->y = pos_text->y;
1171 if (pos_input->width == -1)
1172 pos_input->width = input_width;
1173 if (pos_input->height == -1)
1174 pos_input->height = input_height;
1179 static void DrawPressedGraphicThruMask(int dst_x, int dst_y,
1180 int graphic, boolean pressed)
1182 struct GraphicInfo *g = &graphic_info[graphic];
1185 int xoffset = (pressed ? g->pressed_xoffset : 0);
1186 int yoffset = (pressed ? g->pressed_yoffset : 0);
1188 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1190 BlitBitmapMasked(src_bitmap, drawto, src_x + xoffset, src_y + yoffset,
1191 g->width, g->height, dst_x, dst_y);
1194 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
1195 boolean active_input,
1196 boolean pressed_button)
1200 for (i = 0; main_controls[i].nr != -1; i++)
1202 struct MainControlInfo *mci = &main_controls[i];
1204 if (mci->nr == nr || nr == -1)
1206 struct MenuPosInfo *pos_button = mci->pos_button;
1207 struct TextPosInfo *pos_text = mci->pos_text;
1208 struct TextPosInfo *pos_input = mci->pos_input;
1209 char *text = (mci->text ? *mci->text : NULL);
1210 char *input = (mci->input ? *mci->input : NULL);
1211 int button_graphic = mci->button_graphic;
1212 int font_text = (pos_text ? pos_text->font : -1);
1213 int font_input = (pos_input ? pos_input->font : -1);
1217 button_graphic = BUTTON_ACTIVE(button_graphic);
1218 font_text = FONT_ACTIVE(font_text);
1223 font_input = FONT_ACTIVE(font_input);
1226 if (visibleMenuPos(pos_button))
1228 struct MenuPosInfo *pos = pos_button;
1229 int x = mSX + pos->x;
1230 int y = mSY + pos->y;
1232 DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
1233 DrawPressedGraphicThruMask(x, y, button_graphic, pressed_button);
1236 if (visibleTextPos(pos_text) && text != NULL)
1238 struct TextPosInfo *pos = pos_text;
1239 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1240 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1243 // (check why/if this is needed)
1244 DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
1246 DrawText(x, y, text, font_text);
1249 if (visibleTextPos(pos_input) && input != NULL)
1251 struct TextPosInfo *pos = pos_input;
1252 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1253 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1256 // (check why/if this is needed)
1257 DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
1259 DrawText(x, y, input, font_input);
1265 static void DrawCursorAndText_Main(int nr, boolean active_text,
1266 boolean pressed_button)
1268 DrawCursorAndText_Main_Ext(nr, active_text, FALSE, pressed_button);
1272 static void DrawCursorAndText_Main_Input(int nr, boolean active_text,
1273 boolean pressed_button)
1275 DrawCursorAndText_Main_Ext(nr, active_text, TRUE, pressed_button);
1279 static struct MainControlInfo *getMainControlInfo(int nr)
1283 for (i = 0; main_controls[i].nr != -1; i++)
1284 if (main_controls[i].nr == nr)
1285 return &main_controls[i];
1290 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
1295 int rect_x = ALIGNED_TEXT_XPOS(rect);
1296 int rect_y = ALIGNED_TEXT_YPOS(rect);
1298 return (x >= rect_x && x < rect_x + rect->width &&
1299 y >= rect_y && y < rect_y + rect->height);
1302 static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
1307 int rect_x = ALIGNED_TEXT_XPOS(rect);
1308 int rect_y = ALIGNED_TEXT_YPOS(rect);
1311 printf("::: insideTextPosRect: (%d, %d), (%d, %d) [%d, %d] (%d, %d) => %d\n",
1312 x, y, rect_x, rect_y, rect->x, rect->y, rect->width, rect->height,
1313 (x >= rect_x && x < rect_x + rect->width &&
1314 y >= rect_y && y < rect_y + rect->height));
1317 return (x >= rect_x && x < rect_x + rect->width &&
1318 y >= rect_y && y < rect_y + rect->height);
1321 static boolean insidePreviewRect(struct PreviewInfo *preview, int x, int y)
1323 int rect_width = preview->xsize * preview->tile_size;
1324 int rect_height = preview->ysize * preview->tile_size;
1325 int rect_x = ALIGNED_XPOS(preview->x, rect_width, preview->align);
1326 int rect_y = ALIGNED_YPOS(preview->y, rect_height, preview->valign);
1328 return (x >= rect_x && x < rect_x + rect_width &&
1329 y >= rect_y && y < rect_y + rect_height);
1332 static void AdjustScrollbar(int id, int items_max, int items_visible,
1335 struct GadgetInfo *gi = screen_gadget[id];
1337 if (item_position > items_max - items_visible)
1338 item_position = items_max - items_visible;
1340 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
1341 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1342 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
1345 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
1347 AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN,
1351 static void clearMenuListArea(void)
1353 int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
1355 // correct scrollbar position if placed outside menu (playfield) area
1356 if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS)
1357 scrollbar_xpos = SX + SC_SCROLLBAR_XPOS;
1359 // clear menu list area, but not title or scrollbar
1360 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
1361 scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32);
1364 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
1366 static int cursor_array[MAX_LEV_FIELDY];
1367 int x = mSX + TILEX * xpos;
1368 int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
1373 cursor_array[ypos] = graphic;
1375 graphic = cursor_array[ypos];
1379 graphic = BUTTON_ACTIVE(graphic);
1381 DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
1382 DrawFixedGraphicThruMaskExt(drawto, x, y, graphic, 0);
1385 static void initCursor(int ypos, int graphic)
1387 drawCursorExt(0, ypos, FALSE, graphic);
1390 static void drawCursor(int ypos, boolean active)
1392 drawCursorExt(0, ypos, active, -1);
1395 static void drawCursorXY(int xpos, int ypos, int graphic)
1397 drawCursorExt(xpos, ypos, FALSE, graphic);
1400 static void drawChooseTreeCursor(int ypos, boolean active)
1402 drawCursorExt(0, ypos, active, -1);
1405 static void DrawHeadline(void)
1407 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, main_text_title_1);
1408 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, main_text_title_2);
1411 static void DrawTitleScreenImage(int nr, boolean initial)
1413 int graphic = getTitleScreenGraphic(nr, initial);
1414 Bitmap *bitmap = graphic_info[graphic].bitmap;
1415 int width = graphic_info[graphic].width;
1416 int height = graphic_info[graphic].height;
1417 int src_x = graphic_info[graphic].src_x;
1418 int src_y = graphic_info[graphic].src_y;
1424 if (width > WIN_XSIZE)
1426 // image width too large for window => center image horizontally
1427 src_x = (width - WIN_XSIZE) / 2;
1431 if (height > WIN_YSIZE)
1433 // image height too large for window => center image vertically
1434 src_y = (height - WIN_YSIZE) / 2;
1438 // always display title screens centered
1439 dst_x = (WIN_XSIZE - width) / 2;
1440 dst_y = (WIN_YSIZE - height) / 2;
1442 SetDrawBackgroundMask(REDRAW_ALL);
1443 SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE));
1445 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1447 if (DrawingOnBackground(dst_x, dst_y))
1448 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1450 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1452 redraw_mask = REDRAW_ALL;
1455 static void DrawTitleScreenMessage(int nr, boolean initial)
1457 char *filename = getLevelSetTitleMessageFilename(nr, initial);
1458 struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
1460 if (filename == NULL)
1463 // force TITLE font on title message screen
1464 SetFontStatus(getTitleMessageGameMode(initial));
1466 // if chars *and* width set to "-1", automatically determine width
1467 if (tmi->chars == -1 && tmi->width == -1)
1468 tmi->width = viewport.window[game_status].width;
1470 // if lines *and* height set to "-1", automatically determine height
1471 if (tmi->lines == -1 && tmi->height == -1)
1472 tmi->height = viewport.window[game_status].height;
1474 // if chars set to "-1", automatically determine by text and font width
1475 if (tmi->chars == -1)
1476 tmi->chars = tmi->width / getFontWidth(tmi->font);
1478 tmi->width = tmi->chars * getFontWidth(tmi->font);
1480 // if lines set to "-1", automatically determine by text and font height
1481 if (tmi->lines == -1)
1482 tmi->lines = tmi->height / getFontHeight(tmi->font);
1484 tmi->height = tmi->lines * getFontHeight(tmi->font);
1486 // if x set to "-1", automatically determine by width and alignment
1488 tmi->x = -1 * ALIGNED_XPOS(0, tmi->width, tmi->align);
1490 // if y set to "-1", automatically determine by height and alignment
1492 tmi->y = -1 * ALIGNED_YPOS(0, tmi->height, tmi->valign);
1494 SetDrawBackgroundMask(REDRAW_ALL);
1495 SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE));
1497 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1499 DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi),
1500 filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
1501 tmi->autowrap, tmi->centered, tmi->parse_comments);
1506 static void DrawTitleScreen(void)
1508 KeyboardAutoRepeatOff();
1510 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
1513 static boolean CheckTitleScreen(boolean levelset_has_changed)
1515 static boolean show_title_initial = TRUE;
1516 boolean show_titlescreen = FALSE;
1518 // needed to be able to skip title screen, if no image or message defined
1519 InitializeTitleControls(show_title_initial);
1521 if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
1522 show_titlescreen = TRUE;
1524 // show initial title images and messages only once at program start
1525 show_title_initial = FALSE;
1527 return (show_titlescreen && num_title_screens > 0);
1530 void DrawMainMenu(void)
1532 static LevelDirTree *leveldir_last_valid = NULL;
1533 boolean levelset_has_changed = FALSE;
1534 int fade_mask = REDRAW_FIELD;
1536 LimitScreenUpdates(FALSE);
1538 FadeSetLeaveScreen();
1540 // do not fade out here -- function may continue and fade on editor screen
1543 FadeMenuSoundsAndMusic();
1545 ExpireSoundLoops(FALSE);
1547 KeyboardAutoRepeatOn();
1549 audio.sound_deactivated = FALSE;
1553 // needed if last screen was the playing screen, invoked from level editor
1554 if (level_editor_test_game)
1556 CloseDoor(DOOR_CLOSE_ALL);
1558 SetGameStatus(GAME_MODE_EDITOR);
1565 // needed if last screen was the setup screen and fullscreen state changed
1566 // (moved to "execSetupGraphics()" to change fullscreen state directly)
1567 // ToggleFullscreenOrChangeWindowScalingIfNeeded();
1569 // leveldir_current may be invalid (level group, parent link)
1570 if (!validLevelSeries(leveldir_current))
1571 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
1573 if (leveldir_current != leveldir_last_valid)
1574 levelset_has_changed = TRUE;
1576 // store valid level series information
1577 leveldir_last_valid = leveldir_current;
1579 init_last = init; // switch to new busy animation
1581 // needed if last screen (level choice) changed graphics, sounds or music
1582 ReloadCustomArtwork(0);
1584 if (CheckTitleScreen(levelset_has_changed))
1586 SetGameStatus(GAME_MODE_TITLE);
1593 if (redraw_mask & REDRAW_ALL)
1594 fade_mask = REDRAW_ALL;
1597 fade_mask = REDRAW_ALL;
1601 // needed if different viewport properties defined for menues
1602 ChangeViewportPropertiesIfNeeded();
1604 SetDrawtoField(DRAW_TO_BACKBUFFER);
1606 // level_nr may have been set to value over handicap with level editor
1607 if (setup.handicap && level_nr > leveldir_current->handicap_level)
1608 level_nr = leveldir_current->handicap_level;
1610 LoadLevel(level_nr);
1611 LoadScore(level_nr);
1613 SaveLevelSetup_SeriesInfo();
1615 // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it)
1616 SetDrawDeactivationMask(REDRAW_NONE);
1617 SetDrawBackgroundMask(REDRAW_FIELD);
1619 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
1622 if (fade_mask == REDRAW_ALL)
1623 RedrawGlobalBorder();
1628 InitializeMainControls();
1630 DrawCursorAndText_Main(-1, FALSE, FALSE);
1631 DrawPreviewLevelInitial();
1632 DrawNetworkPlayers();
1634 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
1637 if (TAPE_IS_EMPTY(tape))
1639 DrawCompleteVideoDisplay();
1641 PlayMenuSoundsAndMusic();
1643 // create gadgets for main menu screen
1644 FreeScreenGadgets();
1645 CreateScreenGadgets();
1647 // may be required if audio buttons shown on tape and changed in setup menu
1649 CreateGameButtons();
1651 // map gadgets for main menu screen
1653 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
1654 UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
1656 // copy actual game door content to door double buffer for OpenDoor()
1657 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
1658 BlitBitmap(drawto, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0);
1660 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1662 DrawMaskedBorder(fade_mask);
1667 // update screen area with special editor door
1668 redraw_mask |= REDRAW_ALL;
1671 SetMouseCursor(CURSOR_DEFAULT);
1673 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
1676 static void gotoTopLevelDir(void)
1678 // move upwards until inside (but not above) top level directory
1679 while (leveldir_current->node_parent &&
1680 !strEqual(leveldir_current->node_parent->subdir, STRING_TOP_DIRECTORY))
1682 // write a "path" into level tree for easy navigation to last level
1683 if (leveldir_current->node_parent->node_group->cl_first == -1)
1685 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
1686 int leveldir_pos = posTreeInfo(leveldir_current);
1687 int num_page_entries;
1688 int cl_first, cl_cursor;
1690 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
1691 num_page_entries = num_leveldirs;
1693 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1695 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
1696 cl_cursor = leveldir_pos - cl_first;
1698 leveldir_current->node_parent->node_group->cl_first = cl_first;
1699 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
1702 leveldir_current = leveldir_current->node_parent;
1706 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1708 static unsigned int title_delay = 0;
1709 static int title_screen_nr = 0;
1710 static int last_sound = -1, last_music = -1;
1711 boolean return_to_main_menu = FALSE;
1712 struct TitleControlInfo *tci;
1715 if (button == MB_MENU_INITIALIZE)
1718 title_screen_nr = 0;
1719 tci = &title_controls[title_screen_nr];
1721 SetAnimStatus(getTitleAnimMode(tci));
1723 last_sound = SND_UNDEFINED;
1724 last_music = MUS_UNDEFINED;
1726 if (num_title_screens != 0)
1728 FadeSetEnterScreen();
1730 // use individual title fading instead of global "enter screen" fading
1731 fading = getTitleFading(tci);
1734 if (game_status_last_screen == GAME_MODE_INFO)
1736 if (num_title_screens == 0)
1738 // switch game mode from title screen mode back to info screen mode
1739 SetGameStatus(GAME_MODE_INFO);
1741 // store that last screen was info screen, not main menu screen
1742 game_status_last_screen = GAME_MODE_INFO;
1744 DrawInfoScreen_NotAvailable("Title screen information:",
1745 "No title screen for this level set.");
1750 FadeMenuSoundsAndMusic();
1752 FadeOut(REDRAW_ALL);
1754 // title screens may have different window size
1755 ChangeViewportPropertiesIfNeeded();
1757 // only required to update logic for redrawing global border
1761 DrawTitleScreenImage(tci->local_nr, tci->initial);
1763 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1765 sound = getTitleSound(tci);
1766 music = getTitleMusic(tci);
1768 if (sound != last_sound)
1769 PlayMenuSoundExt(sound);
1770 if (music != last_music)
1771 PlayMenuMusicExt(music);
1776 SetMouseCursor(CURSOR_NONE);
1780 DelayReached(&title_delay, 0); // reset delay counter
1785 if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay))
1786 button = MB_MENU_CHOICE;
1788 if (button == MB_MENU_LEAVE)
1790 return_to_main_menu = TRUE;
1792 else if (button == MB_MENU_CHOICE)
1794 if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0)
1796 SetGameStatus(GAME_MODE_INFO);
1798 info_mode = INFO_MODE_MAIN;
1807 if (title_screen_nr < num_title_screens)
1809 tci = &title_controls[title_screen_nr];
1811 SetAnimStatus(getTitleAnimMode(tci));
1813 sound = getTitleSound(tci);
1814 music = getTitleMusic(tci);
1816 if (last_sound != SND_UNDEFINED && sound != last_sound)
1817 FadeSound(last_sound);
1818 if (last_music != MUS_UNDEFINED && music != last_music)
1821 fading = getTitleFading(tci);
1823 FadeOut(REDRAW_ALL);
1826 DrawTitleScreenImage(tci->local_nr, tci->initial);
1828 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1830 sound = getTitleSound(tci);
1831 music = getTitleMusic(tci);
1833 if (sound != last_sound)
1834 PlayMenuSoundExt(sound);
1835 if (music != last_music)
1836 PlayMenuMusicExt(music);
1843 DelayReached(&title_delay, 0); // reset delay counter
1847 FadeMenuSoundsAndMusic();
1849 return_to_main_menu = TRUE;
1853 if (return_to_main_menu)
1855 SetMouseCursor(CURSOR_DEFAULT);
1857 // force full menu screen redraw after displaying title screens
1858 redraw_mask = REDRAW_ALL;
1860 if (game_status_last_screen == GAME_MODE_INFO)
1862 SetGameStatus(GAME_MODE_INFO);
1864 info_mode = INFO_MODE_MAIN;
1868 else // default: return to main menu
1870 SetGameStatus(GAME_MODE_MAIN);
1877 static void HandleMainMenu_SelectLevel(int step, int direction,
1878 int selected_level_nr)
1880 int old_level_nr = level_nr;
1883 if (selected_level_nr != NO_DIRECT_LEVEL_SELECT)
1884 new_level_nr = selected_level_nr;
1886 new_level_nr = old_level_nr + step * direction;
1888 if (new_level_nr < leveldir_current->first_level)
1889 new_level_nr = leveldir_current->first_level;
1890 if (new_level_nr > leveldir_current->last_level)
1891 new_level_nr = leveldir_current->last_level;
1893 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1895 // skipping levels is only allowed when trying to skip single level
1896 if (setup.skip_levels && new_level_nr == old_level_nr + 1 &&
1897 Request("Level still unsolved! Skip despite handicap?", REQ_ASK))
1899 leveldir_current->handicap_level++;
1900 SaveLevelSetup_SeriesInfo();
1903 new_level_nr = leveldir_current->handicap_level;
1906 if (new_level_nr != old_level_nr)
1908 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER);
1910 PlaySound(SND_MENU_ITEM_SELECTING);
1912 level_nr = new_level_nr;
1914 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1915 int2str(level_nr, menu.main.text.level_number.size),
1916 mci->pos_text->font);
1918 LoadLevel(level_nr);
1919 DrawPreviewLevelInitial();
1923 DrawCompleteVideoDisplay();
1925 SaveLevelSetup_SeriesInfo();
1927 UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
1929 // needed because DrawPreviewLevelInitial() takes some time
1935 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1937 static int choice = MAIN_CONTROL_GAME;
1938 static boolean button_pressed_last = FALSE;
1939 boolean button_pressed = FALSE;
1943 if (button == MB_MENU_INITIALIZE)
1945 DrawCursorAndText_Main(choice, TRUE, FALSE);
1950 if (mx || my) // mouse input
1954 for (i = 0; main_controls[i].nr != -1; i++)
1956 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1957 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1958 insideTextPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1960 pos = main_controls[i].nr;
1966 // check if level preview was clicked
1967 if (insidePreviewRect(&preview, mx - SX, my - SY))
1968 pos = MAIN_CONTROL_GAME;
1970 // handle pressed/unpressed state for active/inactive menu buttons
1971 // (if pos != -1, "i" contains index position corresponding to "pos")
1973 pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT &&
1974 insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY))
1975 button_pressed = TRUE;
1977 if (button_pressed != button_pressed_last)
1979 DrawCursorAndText_Main(choice, TRUE, button_pressed);
1982 PlaySound(SND_MENU_BUTTON_PRESSING);
1984 PlaySound(SND_MENU_BUTTON_RELEASING);
1987 else if (dx || dy) // keyboard input
1989 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1990 choice == MAIN_CONTROL_SETUP))
1991 button = MB_MENU_CHOICE;
1996 if (pos == MAIN_CONTROL_FIRST_LEVEL && !button)
1998 HandleMainMenu_SelectLevel(MAX_LEVELS, -1, NO_DIRECT_LEVEL_SELECT);
2000 else if (pos == MAIN_CONTROL_LAST_LEVEL && !button)
2002 HandleMainMenu_SelectLevel(MAX_LEVELS, +1, NO_DIRECT_LEVEL_SELECT);
2004 else if (pos == MAIN_CONTROL_LEVEL_NUMBER && !button)
2006 CloseDoor(DOOR_CLOSE_2);
2008 SetGameStatus(GAME_MODE_LEVELNR);
2010 DrawChooseLevelNr();
2012 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
2018 PlaySound(SND_MENU_ITEM_ACTIVATING);
2020 DrawCursorAndText_Main(choice, FALSE, FALSE);
2021 DrawCursorAndText_Main(pos, TRUE, button_pressed);
2027 if (choice != MAIN_CONTROL_INFO &&
2028 choice != MAIN_CONTROL_SETUP)
2029 HandleMainMenu_SelectLevel(1, dx, NO_DIRECT_LEVEL_SELECT);
2034 PlaySound(SND_MENU_ITEM_SELECTING);
2036 if (pos == MAIN_CONTROL_NAME)
2039 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY))
2041 // special case: menu text "name/team" clicked -- toggle team mode
2042 setup.team_mode = !setup.team_mode;
2044 InitializeMainControls();
2045 DrawCursorAndText_Main(choice, TRUE, FALSE);
2047 DrawPreviewPlayers();
2051 SetGameStatus(GAME_MODE_PSEUDO_TYPENAME);
2053 HandleTypeName(strlen(setup.player_name), 0);
2056 else if (pos == MAIN_CONTROL_LEVELS)
2060 CloseDoor(DOOR_CLOSE_2);
2062 SetGameStatus(GAME_MODE_LEVELS);
2064 SaveLevelSetup_LastSeries();
2065 SaveLevelSetup_SeriesInfo();
2067 if (setup.internal.choose_from_top_leveldir)
2070 DrawChooseLevelSet();
2073 else if (pos == MAIN_CONTROL_SCORES)
2075 CloseDoor(DOOR_CLOSE_2);
2077 SetGameStatus(GAME_MODE_SCORES);
2079 DrawHallOfFame(level_nr, -1);
2081 else if (pos == MAIN_CONTROL_EDITOR)
2083 if (leveldir_current->readonly &&
2084 !strEqual(setup.player_name, "Artsoft"))
2085 Request("This level is read only!", REQ_CONFIRM);
2087 CloseDoor(DOOR_CLOSE_2);
2089 SetGameStatus(GAME_MODE_EDITOR);
2091 FadeSetEnterScreen();
2095 else if (pos == MAIN_CONTROL_INFO)
2097 CloseDoor(DOOR_CLOSE_2);
2099 SetGameStatus(GAME_MODE_INFO);
2101 info_mode = INFO_MODE_MAIN;
2105 else if (pos == MAIN_CONTROL_GAME)
2107 StartGameActions(network.enabled, setup.autorecord, level.random_seed);
2109 else if (pos == MAIN_CONTROL_SETUP)
2111 CloseDoor(DOOR_CLOSE_2);
2113 SetGameStatus(GAME_MODE_SETUP);
2115 setup_mode = SETUP_MODE_MAIN;
2119 else if (pos == MAIN_CONTROL_QUIT)
2121 SaveLevelSetup_LastSeries();
2122 SaveLevelSetup_SeriesInfo();
2124 if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED))
2125 SetGameStatus(GAME_MODE_QUIT);
2130 button_pressed_last = button_pressed;
2134 // ============================================================================
2135 // info screen functions
2136 // ============================================================================
2138 static struct TokenInfo *info_info;
2139 static int num_info_info; // number of info entries shown on screen
2140 static int max_info_info; // total number of info entries in list
2142 static void execInfoTitleScreen(void)
2144 info_mode = INFO_MODE_TITLE;
2149 static void execInfoElements(void)
2151 info_mode = INFO_MODE_ELEMENTS;
2156 static void execInfoMusic(void)
2158 info_mode = INFO_MODE_MUSIC;
2163 static void execInfoCredits(void)
2165 info_mode = INFO_MODE_CREDITS;
2170 static void execInfoProgram(void)
2172 info_mode = INFO_MODE_PROGRAM;
2177 static void execInfoVersion(void)
2179 info_mode = INFO_MODE_VERSION;
2184 static void execInfoLevelSet(void)
2186 info_mode = INFO_MODE_LEVELSET;
2191 static void execExitInfo(void)
2193 SetGameStatus(GAME_MODE_MAIN);
2198 static struct TokenInfo info_info_main[] =
2200 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
2201 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
2202 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
2203 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
2204 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
2205 { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" },
2206 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
2207 { TYPE_EMPTY, NULL, "" },
2208 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
2213 static int getMenuTextFont(int type)
2215 if (type & (TYPE_SWITCH |
2229 static struct TokenInfo *setup_info;
2230 static struct TokenInfo setup_info_input[];
2232 static struct TokenInfo *menu_info;
2234 static void DrawCursorAndText_Menu_Ext(struct TokenInfo *token_info,
2235 int screen_pos, int menu_info_pos_raw,
2238 int pos = (menu_info_pos_raw < 0 ? screen_pos : menu_info_pos_raw);
2239 struct TokenInfo *ti = &token_info[pos];
2240 int xpos = MENU_SCREEN_START_XPOS;
2241 int ypos = MENU_SCREEN_START_YPOS + screen_pos;
2242 int font_nr = getMenuTextFont(ti->type);
2244 if (setup_mode == SETUP_MODE_INPUT)
2245 font_nr = FONT_MENU_1;
2248 font_nr = FONT_ACTIVE(font_nr);
2250 DrawText(mSX + xpos * 32, mSY + ypos * 32, ti->text, font_nr);
2252 if (ti->type & ~TYPE_SKIP_ENTRY)
2253 drawCursor(screen_pos, active);
2256 static void DrawCursorAndText_Menu(int screen_pos, int menu_info_pos_raw,
2259 DrawCursorAndText_Menu_Ext(menu_info, screen_pos, menu_info_pos_raw, active);
2262 static void DrawCursorAndText_Setup(int screen_pos, int menu_info_pos_raw,
2265 DrawCursorAndText_Menu_Ext(setup_info, screen_pos, menu_info_pos_raw, active);
2268 static char *window_size_text;
2269 static char *scaling_type_text;
2270 static char *network_server_text;
2272 static void drawSetupValue(int, int);
2274 static void drawMenuInfoList(int first_entry, int num_page_entries,
2275 int max_page_entries)
2279 if (first_entry + num_page_entries > max_page_entries)
2282 clearMenuListArea();
2284 for (i = 0; i < num_page_entries; i++)
2286 int menu_info_pos = first_entry + i;
2287 struct TokenInfo *si = &menu_info[menu_info_pos];
2288 void *value_ptr = si->value;
2290 // set some entries to "unchangeable" according to other variables
2291 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
2292 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
2293 (value_ptr == &setup.sound_music && !audio.music_available) ||
2294 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
2295 (value_ptr == &window_size_text && !video.window_scaling_available) ||
2296 (value_ptr == &scaling_type_text && !video.window_scaling_available))
2297 si->type |= TYPE_GHOSTED;
2299 if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
2300 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
2301 else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
2302 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
2303 else if (si->type & ~TYPE_SKIP_ENTRY)
2304 initCursor(i, IMG_MENU_BUTTON);
2306 DrawCursorAndText_Menu(i, menu_info_pos, FALSE);
2308 if (si->type & TYPE_STRING)
2312 if (value_ptr == &network_server_text)
2313 gadget_id = SCREEN_CTRL_ID_NETWORK_SERVER;
2315 if (gadget_id != -1)
2317 struct GadgetInfo *gi = screen_gadget[gadget_id];
2318 int xpos = MENU_SCREEN_START_XPOS;
2319 int ypos = MENU_SCREEN_START_YPOS + i;
2320 int x = mSX + xpos * 32;
2321 int y = mSY + ypos * 32;
2323 ModifyGadget(gi, GDI_X, x, GDI_Y, y, GDI_END);
2327 if (si->type & TYPE_VALUE &&
2328 menu_info == setup_info)
2329 drawSetupValue(i, menu_info_pos);
2333 static void DrawInfoScreen_Main(void)
2335 int fade_mask = REDRAW_FIELD;
2338 if (redraw_mask & REDRAW_ALL)
2339 fade_mask = REDRAW_ALL;
2342 fade_mask = REDRAW_ALL;
2345 FadeMenuSoundsAndMusic();
2347 FreeScreenGadgets();
2348 CreateScreenGadgets();
2350 // (needed after displaying title screens which disable auto repeat)
2351 KeyboardAutoRepeatOn();
2353 FadeSetLeaveScreen();
2357 // needed if different viewport properties defined for info screen
2358 ChangeViewportPropertiesIfNeeded();
2360 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
2364 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
2366 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
2368 info_info = info_info_main;
2370 // determine maximal number of info entries that can be displayed on screen
2372 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
2375 // determine maximal number of info entries available for menu of info screen
2377 for (i = 0; info_info[i].type != 0; i++)
2380 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
2382 MapScreenGadgets(max_info_info);
2384 PlayMenuSoundsAndMusic();
2386 DrawMaskedBorder(fade_mask);
2391 static void changeSetupValue(int, int, int);
2393 static void HandleMenuScreen(int mx, int my, int dx, int dy, int button,
2394 int mode, int num_page_entries,
2395 int max_page_entries)
2397 static int num_page_entries_all_last[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2398 static int choice_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2399 static int first_entry_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2400 int *num_page_entries_last = num_page_entries_all_last[game_status];
2401 int *choice_store = choice_stores[game_status];
2402 int *first_entry_store = first_entry_stores[game_status];
2403 int choice = choice_store[mode]; // starts with 0
2404 int first_entry = first_entry_store[mode]; // starts with 0
2406 int y = choice - first_entry;
2408 boolean position_set_by_scrollbar = (dx == 999);
2409 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2412 if (button == MB_MENU_INITIALIZE)
2414 // check if number of menu page entries has changed (may happen by change
2415 // of custom artwork definition value for 'list_size' for this menu screen)
2416 // (in this case, the last menu position most probably has to be corrected)
2417 if (num_page_entries != num_page_entries_last[mode])
2419 choice_store[mode] = first_entry_store[mode] = 0;
2421 choice = first_entry = 0;
2424 num_page_entries_last[mode] = num_page_entries;
2427 // advance to first valid menu entry
2428 while (choice < num_page_entries &&
2429 menu_info[choice].type & TYPE_SKIP_ENTRY)
2432 if (position_set_by_scrollbar)
2433 first_entry = first_entry_store[mode] = dy;
2435 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2436 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2438 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2440 if (choice < first_entry)
2442 choice = first_entry;
2444 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2447 else if (choice > first_entry + num_page_entries - 1)
2449 choice = first_entry + num_page_entries - 1;
2451 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2455 choice_store[mode] = choice;
2457 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2461 else if (button == MB_MENU_LEAVE)
2463 PlaySound(SND_MENU_ITEM_SELECTING);
2465 for (i = 0; i < max_page_entries; i++)
2467 if (menu_info[i].type & TYPE_LEAVE_MENU)
2469 void (*menu_callback_function)(void) = menu_info[i].value;
2473 menu_callback_function();
2475 break; // absolutely needed because function changes 'menu_info'!
2482 if (mx || my) // mouse input
2484 x = (mx - mSX) / 32;
2485 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2487 else if (dx || dy) // keyboard or scrollbar/scrollbutton input
2489 // move cursor instead of scrolling when already at start/end of list
2490 if (dy == -1 * SCROLL_LINE && first_entry == 0)
2492 else if (dy == +1 * SCROLL_LINE &&
2493 first_entry + num_page_entries == max_page_entries)
2496 // handle scrolling screen one line or page
2498 y + dy > num_page_entries - 1)
2500 boolean redraw = FALSE;
2502 if (ABS(dy) == SCROLL_PAGE)
2503 step = num_page_entries - 1;
2505 if (dy < 0 && first_entry > 0)
2507 // scroll page/line up
2509 first_entry -= step;
2510 if (first_entry < 0)
2515 else if (dy > 0 && first_entry + num_page_entries < max_page_entries)
2517 // scroll page/line down
2519 first_entry += step;
2520 if (first_entry + num_page_entries > max_page_entries)
2521 first_entry = MAX(0, max_page_entries - num_page_entries);
2528 choice += first_entry - first_entry_store[mode];
2530 if (choice < first_entry)
2532 choice = first_entry;
2534 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2537 else if (choice > first_entry + num_page_entries - 1)
2539 choice = first_entry + num_page_entries - 1;
2541 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2544 else if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2548 if (choice < first_entry ||
2549 choice > first_entry + num_page_entries - 1)
2550 first_entry += SIGN(dy);
2553 first_entry_store[mode] = first_entry;
2554 choice_store[mode] = choice;
2556 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2558 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2560 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2561 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2569 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
2571 if (menu_info[choice].type & menu_navigation_type ||
2572 menu_info[choice].type & TYPE_BOOLEAN_STYLE ||
2573 menu_info[choice].type & TYPE_YES_NO_AUTO ||
2574 menu_info[choice].type & TYPE_PLAYER)
2575 button = MB_MENU_CHOICE;
2580 // jump to next non-empty menu entry (up or down)
2581 while (first_entry + y > 0 &&
2582 first_entry + y < max_page_entries - 1 &&
2583 menu_info[first_entry + y].type & TYPE_SKIP_ENTRY)
2586 if (!IN_VIS_MENU(x, y))
2588 choice += y - y_old;
2590 if (choice < first_entry)
2591 first_entry = choice;
2592 else if (choice > first_entry + num_page_entries - 1)
2593 first_entry = choice - num_page_entries + 1;
2595 if (first_entry >= 0 &&
2596 first_entry + num_page_entries <= max_page_entries)
2598 first_entry_store[mode] = first_entry;
2600 if (choice < first_entry)
2601 choice = first_entry;
2602 else if (choice > first_entry + num_page_entries - 1)
2603 choice = first_entry + num_page_entries - 1;
2605 choice_store[mode] = choice;
2607 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2609 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2611 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2612 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2619 if (!anyScrollbarGadgetActive() &&
2620 IN_VIS_MENU(x, y) &&
2621 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
2622 y >= 0 && y < num_page_entries)
2626 if (first_entry + y != choice &&
2627 menu_info[first_entry + y].type & ~TYPE_SKIP_ENTRY)
2629 PlaySound(SND_MENU_ITEM_ACTIVATING);
2631 DrawCursorAndText_Menu(choice - first_entry, choice, FALSE);
2632 DrawCursorAndText_Menu(y, first_entry + y, TRUE);
2634 choice = choice_store[mode] = first_entry + y;
2638 PlaySound(SND_MENU_ITEM_SELECTING);
2640 for (i = 0; menu_info[i].type != 0; i++)
2642 if (menu_info[i].type & TYPE_LEAVE_MENU)
2644 void (*menu_callback_function)(void) = menu_info[i].value;
2648 menu_callback_function();
2650 // absolutely needed because function changes 'menu_info'!
2658 else if (!(menu_info[first_entry + y].type & TYPE_GHOSTED))
2660 PlaySound(SND_MENU_ITEM_SELECTING);
2662 // when selecting key headline, execute function for key value change
2663 if (menu_info[first_entry + y].type & TYPE_KEYTEXT &&
2664 menu_info[first_entry + y + 1].type & TYPE_KEY)
2667 // when selecting string value, execute function for list selection
2668 if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 &&
2669 menu_info[first_entry + y - 1].type & TYPE_ENTER_LIST)
2672 // when selecting string value, execute function for text input gadget
2673 if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 &&
2674 menu_info[first_entry + y - 1].type & TYPE_TEXT_INPUT)
2677 if (menu_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE)
2679 void (*menu_callback_function)(void) =
2680 menu_info[first_entry + y].value;
2682 FadeSetFromType(menu_info[first_entry + y].type);
2684 menu_callback_function();
2686 else if (menu_info[first_entry + y].type & TYPE_TEXT_INPUT)
2688 void (*gadget_callback_function)(void) =
2689 menu_info[first_entry + y].value;
2691 gadget_callback_function();
2693 else if (menu_info[first_entry + y].type & TYPE_VALUE &&
2694 menu_info == setup_info)
2696 changeSetupValue(y, first_entry + y, dx);
2702 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
2704 menu_info = info_info;
2706 HandleMenuScreen(mx, my, dx, dy, button,
2707 info_mode, num_info_info, max_info_info);
2710 static int getMenuFontSpacing(int spacing_height, int font_nr)
2712 int font_spacing = getFontHeight(font_nr) + EXTRA_SPACING(game_status);
2714 return (spacing_height < 0 ? ABS(spacing_height) * font_spacing :
2718 static int getMenuTextSpacing(int spacing_height, int font_nr)
2720 return (getMenuFontSpacing(spacing_height, font_nr) +
2721 EXTRA_SPACING(game_status));
2724 static int getMenuTextStep(int spacing_height, int font_nr)
2726 return getFontHeight(font_nr) + getMenuTextSpacing(spacing_height, font_nr);
2729 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
2731 int font_title = MENU_INFO_FONT_TITLE;
2732 int font_error = FONT_TEXT_2;
2733 int font_foot = MENU_INFO_FONT_FOOT;
2734 int spacing_title = menu.headline1_spacing_info[info_mode];
2735 int ystep_title = getMenuTextStep(spacing_title, font_title);
2736 int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2737 int ystart2 = ystart1 + ystep_title;
2738 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2740 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO);
2742 FadeOut(REDRAW_FIELD);
2747 DrawTextSCentered(ystart1, font_title, text_title);
2748 DrawTextSCentered(ystart2, font_error, text_error);
2750 DrawTextSCentered(ybottom, font_foot,
2751 "Press any key or button for info menu");
2753 FadeIn(REDRAW_FIELD);
2756 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
2758 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
2759 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
2760 int font_title = MENU_INFO_FONT_TITLE;
2761 int font_foot = MENU_INFO_FONT_FOOT;
2762 int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT;
2763 int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2764 int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2;
2765 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2766 int ystep = MENU_SCREEN_INFO_YSTEP;
2767 int element, action, direction;
2775 for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++)
2776 infoscreen_step[i] = infoscreen_frame[i] = 0;
2781 DrawTextSCentered(ystart1, font_title, "The Game Elements:");
2783 DrawTextSCentered(ybottom, font_foot,
2784 "Press any key or button for next page");
2790 while (helpanim_info[j].element != HELPANIM_LIST_END)
2792 if (i >= start + NUM_INFO_ELEMENTS_ON_SCREEN ||
2797 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2806 j += infoscreen_step[i - start];
2808 element = helpanim_info[j].element;
2809 action = helpanim_info[j].action;
2810 direction = helpanim_info[j].direction;
2813 element = EL_UNKNOWN;
2815 if (action != -1 && direction != -1)
2816 graphic = el_act_dir2img(element, action, direction);
2817 else if (action != -1)
2818 graphic = el_act2img(element, action);
2819 else if (direction != -1)
2820 graphic = el_dir2img(element, direction);
2822 graphic = el2img(element);
2824 delay = helpanim_info[j++].delay;
2829 if (infoscreen_frame[i - start] == 0)
2832 infoscreen_frame[i - start] = delay - 1;
2836 sync_frame = delay - infoscreen_frame[i - start];
2837 infoscreen_frame[i - start]--;
2840 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
2842 if (!infoscreen_frame[i - start])
2843 infoscreen_step[i - start] = 0;
2847 if (!infoscreen_frame[i - start])
2848 infoscreen_step[i - start]++;
2849 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2855 ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep,
2857 DrawFixedGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep,
2858 graphic, sync_frame, USE_MASKING);
2861 DrawInfoScreen_HelpText(element, action, direction, i - start);
2866 redraw_mask |= REDRAW_FIELD;
2871 static char *getHelpText(int element, int action, int direction)
2873 char token[MAX_LINE_LEN];
2875 strcpy(token, element_info[element].token_name);
2878 strcat(token, element_action_info[action].suffix);
2880 if (direction != -1)
2881 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
2883 return getHashEntry(helptext_info, token);
2886 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
2888 int font_nr = FONT_INFO_ELEMENTS;
2889 int font_width = getFontWidth(font_nr);
2890 int font_height = getFontHeight(font_nr);
2891 int yoffset = (TILEX - 2 * font_height) / 2;
2892 int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT + TILEX + MINI_TILEX;
2893 int ystart = mSY + MENU_SCREEN_INFO_YSTART2 + yoffset;
2894 int ystep = TILEY + 4;
2895 int pad_left = xstart - SX;
2896 int pad_right = MENU_SCREEN_INFO_SPACE_RIGHT;
2897 int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width;
2898 int max_lines_per_text = 2;
2901 if (action != -1 && direction != -1) // element.action.direction
2902 text = getHelpText(element, action, direction);
2904 if (text == NULL && action != -1) // element.action
2905 text = getHelpText(element, action, -1);
2907 if (text == NULL && direction != -1) // element.direction
2908 text = getHelpText(element, -1, direction);
2910 if (text == NULL) // base element
2911 text = getHelpText(element, -1, -1);
2913 if (text == NULL) // not found
2914 text = "No description available";
2916 if (strlen(text) <= max_chars_per_line) // only one line of text
2917 ystart += getFontHeight(font_nr) / 2;
2919 DrawTextBuffer(xstart, ystart + ypos * ystep, text, font_nr,
2920 max_chars_per_line, -1, max_lines_per_text, 0, -1,
2921 TRUE, FALSE, FALSE);
2924 static void DrawInfoScreen_TitleScreen(void)
2926 SetGameStatus(GAME_MODE_TITLE);
2931 void HandleInfoScreen_TitleScreen(int button)
2933 HandleTitleScreen(0, 0, 0, 0, button);
2936 static void DrawInfoScreen_Elements(void)
2938 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
2940 FadeOut(REDRAW_FIELD);
2945 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
2947 FadeIn(REDRAW_FIELD);
2950 void HandleInfoScreen_Elements(int button)
2952 static unsigned int info_delay = 0;
2953 static int num_anims;
2954 static int num_pages;
2956 int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN;
2959 if (button == MB_MENU_INITIALIZE)
2961 boolean new_element = TRUE;
2965 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
2967 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
2969 else if (new_element)
2972 new_element = FALSE;
2976 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
2980 if (button == MB_MENU_LEAVE)
2982 PlaySound(SND_MENU_ITEM_SELECTING);
2984 info_mode = INFO_MODE_MAIN;
2989 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2991 if (button != MB_MENU_INITIALIZE)
2993 PlaySound(SND_MENU_ITEM_SELECTING);
2998 if (page >= num_pages)
3000 FadeMenuSoundsAndMusic();
3002 info_mode = INFO_MODE_MAIN;
3009 FadeSetNextScreen();
3011 if (button != MB_MENU_INITIALIZE)
3012 FadeOut(REDRAW_FIELD);
3014 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
3016 if (button != MB_MENU_INITIALIZE)
3017 FadeIn(REDRAW_FIELD);
3021 if (DelayReached(&info_delay, GameFrameDelay))
3022 if (page < num_pages)
3023 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
3025 PlayMenuSoundIfLoop();
3029 static void DrawInfoScreen_Music(void)
3031 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
3033 FadeOut(REDRAW_FIELD);
3040 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
3042 FadeIn(REDRAW_FIELD);
3045 void HandleInfoScreen_Music(int button)
3047 static struct MusicFileInfo *list = NULL;
3048 int font_title = MENU_INFO_FONT_TITLE;
3049 int font_head = MENU_INFO_FONT_HEAD;
3050 int font_text = MENU_INFO_FONT_TEXT;
3051 int font_foot = MENU_INFO_FONT_FOOT;
3052 int spacing_title = menu.headline1_spacing_info[info_mode];
3053 int spacing_head = menu.headline2_spacing_info[info_mode];
3054 int ystep_title = getMenuTextStep(spacing_title, font_title);
3055 int ystep_head = getMenuTextStep(spacing_head, font_head);
3056 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3057 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3059 if (button == MB_MENU_INITIALIZE)
3061 list = music_file_info;
3065 FadeMenuSoundsAndMusic();
3070 DrawTextSCentered(ystart, font_title,
3071 "No music info for this level set.");
3073 DrawTextSCentered(ybottom, font_foot,
3074 "Press any key or button for info menu");
3080 if (button == MB_MENU_LEAVE)
3082 PlaySound(SND_MENU_ITEM_SELECTING);
3084 FadeMenuSoundsAndMusic();
3086 info_mode = INFO_MODE_MAIN;
3091 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3093 if (button != MB_MENU_INITIALIZE)
3095 PlaySound(SND_MENU_ITEM_SELECTING);
3103 FadeMenuSoundsAndMusic();
3105 info_mode = INFO_MODE_MAIN;
3111 FadeMenuSoundsAndMusic();
3113 if (list != music_file_info)
3114 FadeSetNextScreen();
3116 if (button != MB_MENU_INITIALIZE)
3117 FadeOut(REDRAW_FIELD);
3124 int sound = list->music;
3126 if (sound_info[sound].loop)
3127 PlaySoundLoop(sound);
3131 DrawTextSCentered(ystart, font_title, "The Game Background Sounds:");
3135 int music = list->music;
3137 if (music_info[music].loop)
3138 PlayMusicLoop(music);
3142 DrawTextSCentered(ystart, font_title, "The Game Background Music:");
3145 ystart += ystep_title;
3147 if (!strEqual(list->title, UNKNOWN_NAME))
3149 if (!strEqual(list->title_header, UNKNOWN_NAME))
3151 DrawTextSCentered(ystart, font_head, list->title_header);
3152 ystart += ystep_head;
3155 DrawTextFCentered(ystart, font_text, "\"%s\"", list->title);
3156 ystart += ystep_head;
3159 if (!strEqual(list->artist, UNKNOWN_NAME))
3161 if (!strEqual(list->artist_header, UNKNOWN_NAME))
3162 DrawTextSCentered(ystart, font_head, list->artist_header);
3164 DrawTextSCentered(ystart, font_head, "by");
3166 ystart += ystep_head;
3168 DrawTextFCentered(ystart, font_text, "%s", list->artist);
3169 ystart += ystep_head;
3172 if (!strEqual(list->album, UNKNOWN_NAME))
3174 if (!strEqual(list->album_header, UNKNOWN_NAME))
3175 DrawTextSCentered(ystart, font_head, list->album_header);
3177 DrawTextSCentered(ystart, font_head, "from the album");
3179 ystart += ystep_head;
3181 DrawTextFCentered(ystart, font_text, "\"%s\"", list->album);
3182 ystart += ystep_head;
3185 if (!strEqual(list->year, UNKNOWN_NAME))
3187 if (!strEqual(list->year_header, UNKNOWN_NAME))
3188 DrawTextSCentered(ystart, font_head, list->year_header);
3190 DrawTextSCentered(ystart, font_head, "from the year");
3192 ystart += ystep_head;
3194 DrawTextFCentered(ystart, font_text, "%s", list->year);
3195 ystart += ystep_head;
3198 DrawTextSCentered(ybottom, FONT_TEXT_4,
3199 "Press any key or button for next page");
3201 if (button != MB_MENU_INITIALIZE)
3202 FadeIn(REDRAW_FIELD);
3205 if (list != NULL && list->is_sound && sound_info[list->music].loop)
3206 PlaySoundLoop(list->music);
3209 static void DrawInfoScreen_CreditsScreen(int screen_nr)
3211 int font_title = MENU_INFO_FONT_TITLE;
3212 int font_head = MENU_INFO_FONT_HEAD;
3213 int font_text = MENU_INFO_FONT_TEXT;
3214 int font_foot = MENU_INFO_FONT_FOOT;
3215 int spacing_title = menu.headline1_spacing_info[info_mode];
3216 int spacing_head = menu.headline2_spacing_info[info_mode];
3217 int spacing_para = menu.paragraph_spacing_info[info_mode];
3218 int spacing_line = menu.line_spacing_info[info_mode];
3219 int ystep_title = getMenuTextStep(spacing_title, font_title);
3220 int ystep_head = getMenuTextStep(spacing_head, font_head);
3221 int ystep_para = getMenuTextStep(spacing_para, font_text);
3222 int ystep_line = getMenuTextStep(spacing_line, font_text);
3223 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3224 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3229 DrawTextSCentered(ystart, font_title, "Credits:");
3230 ystart += ystep_title;
3234 DrawTextSCentered(ystart, font_head,
3235 "Special thanks to");
3236 ystart += ystep_head;
3237 DrawTextSCentered(ystart, font_text,
3239 ystart += ystep_head;
3240 DrawTextSCentered(ystart, font_head,
3242 ystart += ystep_head;
3243 DrawTextSCentered(ystart, font_text,
3244 "\"Boulder Dash\"");
3245 ystart += ystep_head;
3246 DrawTextSCentered(ystart, font_head,
3248 ystart += ystep_head;
3249 DrawTextSCentered(ystart, font_text,
3251 ystart += ystep_head;
3252 DrawTextSCentered(ystart, font_head,
3254 ystart += ystep_head;
3255 DrawTextSCentered(ystart, font_text,
3256 "First Star Software");
3258 else if (screen_nr == 1)
3260 DrawTextSCentered(ystart, font_head,
3261 "Special thanks to");
3262 ystart += ystep_head;
3263 DrawTextSCentered(ystart, font_text,
3264 "Klaus Heinz & Volker Wertich");
3265 ystart += ystep_head;
3266 DrawTextSCentered(ystart, font_head,
3268 ystart += ystep_head;
3269 DrawTextSCentered(ystart, font_text,
3270 "\"Emerald Mine\"");
3271 ystart += ystep_head;
3272 DrawTextSCentered(ystart, font_head,
3274 ystart += ystep_head;
3275 DrawTextSCentered(ystart, font_text,
3277 ystart += ystep_head;
3278 DrawTextSCentered(ystart, font_head,
3280 ystart += ystep_head;
3281 DrawTextSCentered(ystart, font_text,
3284 else if (screen_nr == 2)
3286 DrawTextSCentered(ystart, font_head,
3287 "Special thanks to");
3288 ystart += ystep_head;
3289 DrawTextSCentered(ystart, font_text,
3290 "Michael Stopp & Philip Jespersen");
3291 ystart += ystep_head;
3292 DrawTextSCentered(ystart, font_head,
3294 ystart += ystep_head;
3295 DrawTextSCentered(ystart, font_text,
3297 ystart += ystep_head;
3298 DrawTextSCentered(ystart, font_head,
3300 ystart += ystep_head;
3301 DrawTextSCentered(ystart, font_text,
3303 ystart += ystep_head;
3304 DrawTextSCentered(ystart, font_head,
3306 ystart += ystep_head;
3307 DrawTextSCentered(ystart, font_text,
3308 "Digital Integration");
3310 else if (screen_nr == 3)
3312 DrawTextSCentered(ystart, font_head,
3313 "Special thanks to");
3314 ystart += ystep_head;
3315 DrawTextSCentered(ystart, font_text,
3316 "Hiroyuki Imabayashi");
3317 ystart += ystep_head;
3318 DrawTextSCentered(ystart, font_head,
3320 ystart += ystep_head;
3321 DrawTextSCentered(ystart, font_text,
3323 ystart += ystep_head;
3324 DrawTextSCentered(ystart, font_head,
3326 ystart += ystep_head;
3327 DrawTextSCentered(ystart, font_text,
3329 ystart += ystep_head;
3330 DrawTextSCentered(ystart, font_head,
3332 ystart += ystep_head;
3333 DrawTextSCentered(ystart, font_text,
3336 else if (screen_nr == 4)
3338 DrawTextSCentered(ystart, font_head,
3339 "Special thanks to");
3340 ystart += ystep_head;
3341 DrawTextSCentered(ystart, font_text,
3343 ystart += ystep_head;
3344 DrawTextSCentered(ystart, font_head,
3346 ystart += ystep_head;
3347 DrawTextSCentered(ystart, font_text,
3348 "J\xfcrgen Bonhagen");
3349 ystart += ystep_head;
3350 DrawTextSCentered(ystart, font_head,
3351 "for the continuous creation");
3352 ystart += ystep_line;
3353 DrawTextSCentered(ystart, font_head,
3354 "of outstanding level sets");
3356 else if (screen_nr == 5)
3358 DrawTextSCentered(ystart, font_head,
3360 ystart += ystep_head;
3361 DrawTextSCentered(ystart, font_text,
3363 ystart += ystep_head;
3364 DrawTextSCentered(ystart, font_head,
3365 "for ideas and inspiration by");
3366 ystart += ystep_head;
3367 DrawTextSCentered(ystart, font_text,
3369 ystart += ystep_para;
3371 DrawTextSCentered(ystart, font_head,
3373 ystart += ystep_head;
3374 DrawTextSCentered(ystart, font_text,
3376 ystart += ystep_head;
3377 DrawTextSCentered(ystart, font_head,
3378 "for ideas and inspiration by");
3379 ystart += ystep_head;
3380 DrawTextSCentered(ystart, font_text,
3383 else if (screen_nr == 6)
3385 DrawTextSCentered(ystart, font_head,
3387 ystart += ystep_head;
3388 DrawTextSCentered(ystart, font_text,
3390 ystart += ystep_head;
3391 DrawTextSCentered(ystart, font_head,
3392 "for the code base used for the");
3393 ystart += ystep_line;
3394 DrawTextSCentered(ystart, font_head,
3395 "native Emerald Mine engine");
3397 else if (screen_nr == 7)
3399 DrawTextSCentered(ystart, font_head,
3401 ystart += ystep_head;
3402 DrawTextSCentered(ystart, font_text,
3404 ystart += ystep_head;
3405 DrawTextSCentered(ystart, font_head,
3406 "for the initial DOS port");
3407 ystart += ystep_para;
3409 DrawTextSCentered(ystart, font_head,
3411 ystart += ystep_head;
3412 DrawTextSCentered(ystart, font_text,
3414 ystart += ystep_head;
3415 DrawTextSCentered(ystart, font_head,
3416 "for some additional toons");
3418 else if (screen_nr == 8)
3420 DrawTextSCentered(ystart, font_head,
3421 "And not to forget:");
3422 ystart += ystep_head;
3423 DrawTextSCentered(ystart, font_head,
3425 ystart += ystep_head;
3426 DrawTextSCentered(ystart, font_text,
3427 "All those who contributed");
3428 ystart += ystep_line;
3429 DrawTextSCentered(ystart, font_text,
3430 "levels to this game");
3431 ystart += ystep_line;
3432 DrawTextSCentered(ystart, font_text,
3436 DrawTextSCentered(ybottom, font_foot,
3437 "Press any key or button for next page");
3440 static void DrawInfoScreen_Credits(void)
3442 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
3444 FadeMenuSoundsAndMusic();
3446 FadeOut(REDRAW_FIELD);
3448 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
3450 FadeIn(REDRAW_FIELD);
3453 void HandleInfoScreen_Credits(int button)
3455 static int screen_nr = 0;
3456 int num_screens = 9;
3458 if (button == MB_MENU_INITIALIZE)
3462 // DrawInfoScreen_CreditsScreen(screen_nr);
3465 if (button == MB_MENU_LEAVE)
3467 PlaySound(SND_MENU_ITEM_SELECTING);
3469 info_mode = INFO_MODE_MAIN;
3474 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3476 if (button != MB_MENU_INITIALIZE)
3478 PlaySound(SND_MENU_ITEM_SELECTING);
3483 if (screen_nr >= num_screens)
3485 FadeMenuSoundsAndMusic();
3487 info_mode = INFO_MODE_MAIN;
3494 FadeSetNextScreen();
3496 if (button != MB_MENU_INITIALIZE)
3497 FadeOut(REDRAW_FIELD);
3499 DrawInfoScreen_CreditsScreen(screen_nr);
3501 if (button != MB_MENU_INITIALIZE)
3502 FadeIn(REDRAW_FIELD);
3506 PlayMenuSoundIfLoop();
3510 static void DrawInfoScreen_Program(void)
3512 int font_title = MENU_INFO_FONT_TITLE;
3513 int font_head = MENU_INFO_FONT_HEAD;
3514 int font_text = MENU_INFO_FONT_TEXT;
3515 int font_foot = MENU_INFO_FONT_FOOT;
3516 int spacing_title = menu.headline1_spacing_info[info_mode];
3517 int spacing_head = menu.headline2_spacing_info[info_mode];
3518 int spacing_para = menu.paragraph_spacing_info[info_mode];
3519 int spacing_line = menu.line_spacing_info[info_mode];
3520 int ystep_title = getMenuTextStep(spacing_title, font_title);
3521 int ystep_head = getMenuTextStep(spacing_head, font_head);
3522 int ystep_para = getMenuTextStep(spacing_para, font_text);
3523 int ystep_line = getMenuTextStep(spacing_line, font_text);
3524 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3525 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3527 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
3529 FadeOut(REDRAW_FIELD);
3534 DrawTextSCentered(ystart, font_title, "Program Information:");
3535 ystart += ystep_title;
3537 DrawTextSCentered(ystart, font_head,
3538 "This game is Freeware!");
3539 ystart += ystep_head;
3540 DrawTextSCentered(ystart, font_head,
3541 "If you like it, send e-mail to:");
3542 ystart += ystep_head;
3543 DrawTextSCentered(ystart, font_text,
3544 setup.internal.program_email);
3545 ystart += ystep_para;
3547 DrawTextSCentered(ystart, font_head,
3548 "More information and levels:");
3549 ystart += ystep_head;
3550 DrawTextSCentered(ystart, font_text,
3551 setup.internal.program_website);
3552 ystart += ystep_para;
3554 DrawTextSCentered(ystart, font_head,
3555 "If you have created new levels,");
3556 ystart += ystep_line;
3557 DrawTextSCentered(ystart, font_head,
3558 "send them to me to include them!");
3559 ystart += ystep_head;
3560 DrawTextSCentered(ystart, font_head,
3563 DrawTextSCentered(ybottom, font_foot,
3564 "Press any key or button for info menu");
3566 FadeIn(REDRAW_FIELD);
3569 void HandleInfoScreen_Program(int button)
3571 if (button == MB_MENU_LEAVE)
3573 PlaySound(SND_MENU_ITEM_SELECTING);
3575 info_mode = INFO_MODE_MAIN;
3580 else if (button == MB_MENU_CHOICE)
3582 PlaySound(SND_MENU_ITEM_SELECTING);
3584 FadeMenuSoundsAndMusic();
3586 info_mode = INFO_MODE_MAIN;
3591 PlayMenuSoundIfLoop();
3595 static void DrawInfoScreen_Version(void)
3597 int font_title = MENU_INFO_FONT_TITLE;
3598 int font_head = MENU_INFO_FONT_HEAD;
3599 int font_text = MENU_INFO_FONT_TEXT;
3600 int font_foot = MENU_INFO_FONT_FOOT;
3601 int spacing_title = menu.headline1_spacing_info[info_mode];
3602 int spacing_head = menu.headline2_spacing_info[info_mode];
3603 int spacing_para = menu.paragraph_spacing_info[info_mode];
3604 int spacing_line = menu.line_spacing_info[info_mode];
3605 int xstep = getFontWidth(font_text);
3606 int ystep_title = getMenuTextStep(spacing_title, font_title);
3607 int ystep_head = getMenuTextStep(spacing_head, font_head);
3608 int ystep_para = getMenuTextStep(spacing_para, font_text);
3609 int ystep_line = getMenuTextStep(spacing_line, font_text);
3610 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3611 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3612 int xstart1 = mSX - SX + 2 * xstep;
3613 int xstart2 = mSX - SX + 18 * xstep;
3614 int xstart3 = mSX - SX + 28 * xstep;
3615 SDL_version sdl_version_compiled;
3616 const SDL_version *sdl_version_linked;
3617 int driver_name_len = 10;
3618 SDL_version sdl_version_linked_ext;
3619 const char *driver_name = NULL;
3621 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION);
3623 FadeOut(REDRAW_FIELD);
3628 DrawTextSCentered(ystart, font_title, "Version Information:");
3629 ystart += ystep_title;
3631 DrawTextF(xstart1, ystart, font_head, "Name");
3632 DrawTextF(xstart2, ystart, font_text, getProgramTitleString());
3633 ystart += ystep_line;
3635 if (!strEqual(getProgramVersionString(), getProgramRealVersionString()))
3637 DrawTextF(xstart1, ystart, font_head, "Version (fake)");
3638 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3639 ystart += ystep_line;
3641 DrawTextF(xstart1, ystart, font_head, "Version (real)");
3642 DrawTextF(xstart2, ystart, font_text, getProgramRealVersionString());
3643 ystart += ystep_line;
3647 DrawTextF(xstart1, ystart, font_head, "Version");
3648 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3649 ystart += ystep_line;
3652 DrawTextF(xstart1, ystart, font_head, "Platform");
3653 DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING);
3654 ystart += ystep_line;
3656 DrawTextF(xstart1, ystart, font_head, "Target");
3657 DrawTextF(xstart2, ystart, font_text, TARGET_STRING);
3658 ystart += ystep_line;
3660 DrawTextF(xstart1, ystart, font_head, "Source date");
3661 DrawTextF(xstart2, ystart, font_text, getSourceDateString());
3662 ystart += ystep_para;
3664 DrawTextF(xstart1, ystart, font_head, "Library");
3665 DrawTextF(xstart2, ystart, font_head, "compiled");
3666 DrawTextF(xstart3, ystart, font_head, "linked");
3667 ystart += ystep_head;
3669 SDL_VERSION(&sdl_version_compiled);
3670 SDL_GetVersion(&sdl_version_linked_ext);
3671 sdl_version_linked = &sdl_version_linked_ext;
3673 DrawTextF(xstart1, ystart, font_text, "SDL");
3674 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3675 sdl_version_compiled.major,
3676 sdl_version_compiled.minor,
3677 sdl_version_compiled.patch);
3678 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3679 sdl_version_linked->major,
3680 sdl_version_linked->minor,
3681 sdl_version_linked->patch);
3682 ystart += ystep_line;
3684 SDL_IMAGE_VERSION(&sdl_version_compiled);
3685 sdl_version_linked = IMG_Linked_Version();
3687 DrawTextF(xstart1, ystart, font_text, "SDL_image");
3688 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3689 sdl_version_compiled.major,
3690 sdl_version_compiled.minor,
3691 sdl_version_compiled.patch);
3692 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3693 sdl_version_linked->major,
3694 sdl_version_linked->minor,
3695 sdl_version_linked->patch);
3696 ystart += ystep_line;
3698 SDL_MIXER_VERSION(&sdl_version_compiled);
3699 sdl_version_linked = Mix_Linked_Version();
3701 DrawTextF(xstart1, ystart, font_text, "SDL_mixer");
3702 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3703 sdl_version_compiled.major,
3704 sdl_version_compiled.minor,
3705 sdl_version_compiled.patch);
3706 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3707 sdl_version_linked->major,
3708 sdl_version_linked->minor,
3709 sdl_version_linked->patch);
3710 ystart += ystep_line;
3712 SDL_NET_VERSION(&sdl_version_compiled);
3713 sdl_version_linked = SDLNet_Linked_Version();
3715 DrawTextF(xstart1, ystart, font_text, "SDL_net");
3716 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3717 sdl_version_compiled.major,
3718 sdl_version_compiled.minor,
3719 sdl_version_compiled.patch);
3720 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3721 sdl_version_linked->major,
3722 sdl_version_linked->minor,
3723 sdl_version_linked->patch);
3724 ystart += ystep_para;
3726 DrawTextF(xstart1, ystart, font_head, "Driver");
3727 DrawTextF(xstart2, ystart, font_head, "Requested");
3728 DrawTextF(xstart3, ystart, font_head, "Used");
3729 ystart += ystep_head;
3731 driver_name = getStringCopyNStatic(SDL_GetVideoDriver(0), driver_name_len);
3733 DrawTextF(xstart1, ystart, font_text, "SDL_VideoDriver");
3734 DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_videodriver);
3735 DrawTextF(xstart3, ystart, font_text, "%s", driver_name);
3736 ystart += ystep_line;
3738 driver_name = getStringCopyNStatic(SDL_GetAudioDriver(0), driver_name_len);
3740 DrawTextF(xstart1, ystart, font_text, "SDL_AudioDriver");
3741 DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_audiodriver);
3742 DrawTextF(xstart3, ystart, font_text, "%s", driver_name);
3744 DrawTextSCentered(ybottom, font_foot,
3745 "Press any key or button for info menu");