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 static int align_xoffset = 0;
527 static int align_yoffset = 0;
529 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
530 (s) <= GAME_MODE_SETUP ? (s) : \
531 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
532 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
534 // (there are no draw offset definitions needed for INFO_MODE_TITLE)
535 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_TITLE && \
536 (i) <= INFO_MODE_LEVELSET ? (i) : \
539 #define DRAW_MODE_SETUP(i) ((i) >= SETUP_MODE_MAIN && \
540 (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) : \
541 (i) >= SETUP_MODE_CHOOSE_GRAPHICS && \
542 (i) <= SETUP_MODE_CHOOSE_MUSIC ? \
543 SETUP_MODE_CHOOSE_ARTWORK : \
544 SETUP_MODE_CHOOSE_OTHER)
546 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
547 menu.draw_xoffset[GAME_MODE_INFO] : \
548 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
549 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
550 menu.draw_yoffset[GAME_MODE_INFO] : \
551 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
552 #define EXTRA_SPACING_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
553 menu.extra_spacing[GAME_MODE_INFO] : \
554 menu.extra_spacing_info[DRAW_MODE_INFO(i)])
556 #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
557 menu.draw_xoffset[GAME_MODE_SETUP] : \
558 menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)])
559 #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
560 menu.draw_yoffset[GAME_MODE_SETUP] : \
561 menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)])
562 #define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
563 menu.extra_spacing[GAME_MODE_SETUP] : \
564 menu.extra_spacing_setup[DRAW_MODE_SETUP(i)])
566 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
567 DRAW_XOFFSET_INFO(info_mode) : \
568 (s) == GAME_MODE_SETUP ? \
569 DRAW_XOFFSET_SETUP(setup_mode) : \
570 menu.draw_xoffset[DRAW_MODE(s)])
571 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
572 DRAW_YOFFSET_INFO(info_mode) : \
573 (s) == GAME_MODE_SETUP ? \
574 DRAW_YOFFSET_SETUP(setup_mode) : \
575 menu.draw_yoffset[DRAW_MODE(s)])
576 #define EXTRA_SPACING(s) ((s) == GAME_MODE_INFO ? \
577 EXTRA_SPACING_INFO(info_mode) : \
578 (s) == GAME_MODE_SETUP ? \
579 EXTRA_SPACING_SETUP(setup_mode) : \
580 menu.extra_spacing[DRAW_MODE(s)])
582 #define mSX (SX + DRAW_XOFFSET(game_status))
583 #define mSY (SY + DRAW_YOFFSET(game_status))
585 #define amSX (mSX + align_xoffset)
586 #define amSY (mSY + align_yoffset)
588 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
589 menu.list_size[game_status] : \
590 MAX_MENU_ENTRIES_ON_SCREEN)
592 #define IN_VIS_MENU(x, y) IN_FIELD(x, y, SCR_FIELDX, \
593 NUM_MENU_ENTRIES_ON_SCREEN)
596 // title display and control definitions
598 #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \
599 2 * MAX_NUM_TITLE_MESSAGES)
601 #define NO_DIRECT_LEVEL_SELECT (-1)
604 static int num_title_screens = 0;
606 struct TitleControlInfo
615 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
617 // main menu display and control definitions
619 #define MAIN_CONTROL_NAME 0
620 #define MAIN_CONTROL_LEVELS 1
621 #define MAIN_CONTROL_SCORES 2
622 #define MAIN_CONTROL_EDITOR 3
623 #define MAIN_CONTROL_INFO 4
624 #define MAIN_CONTROL_GAME 5
625 #define MAIN_CONTROL_SETUP 6
626 #define MAIN_CONTROL_QUIT 7
627 #define MAIN_CONTROL_PREV_LEVEL 8
628 #define MAIN_CONTROL_NEXT_LEVEL 9
629 #define MAIN_CONTROL_FIRST_LEVEL 10
630 #define MAIN_CONTROL_LAST_LEVEL 11
631 #define MAIN_CONTROL_LEVEL_NUMBER 12
632 #define MAIN_CONTROL_LEVEL_INFO_1 13
633 #define MAIN_CONTROL_LEVEL_INFO_2 14
634 #define MAIN_CONTROL_LEVEL_NAME 15
635 #define MAIN_CONTROL_LEVEL_AUTHOR 16
636 #define MAIN_CONTROL_LEVEL_YEAR 17
637 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM 18
638 #define MAIN_CONTROL_LEVEL_IMPORTED_BY 19
639 #define MAIN_CONTROL_LEVEL_TESTED_BY 20
640 #define MAIN_CONTROL_TITLE_1 21
641 #define MAIN_CONTROL_TITLE_2 22
642 #define MAIN_CONTROL_TITLE_3 23
644 static char str_main_text_name[10];
645 static char str_main_text_first_level[10];
646 static char str_main_text_last_level[10];
647 static char str_main_text_level_number[10];
649 static char network_server_hostname[MAX_SETUP_TEXT_INPUT_LEN + 1];
651 static char *main_text_name = str_main_text_name;
652 static char *main_text_first_level = str_main_text_first_level;
653 static char *main_text_last_level = str_main_text_last_level;
654 static char *main_text_level_number = str_main_text_level_number;
655 static char *main_text_levels = "Levelset";
656 static char *main_text_scores = "Hall Of Fame";
657 static char *main_text_editor = "Level Creator";
658 static char *main_text_info = "Info Screen";
659 static char *main_text_game = "Start Game";
660 static char *main_text_setup = "Setup";
661 static char *main_text_quit = "Quit";
662 static char *main_text_level_name = level.name;
663 static char *main_text_level_author = level.author;
664 static char *main_text_level_year = NULL;
665 static char *main_text_level_imported_from = NULL;
666 static char *main_text_level_imported_by = NULL;
667 static char *main_text_level_tested_by = NULL;
668 static char *main_text_title_1 = NULL;
669 static char *main_text_title_2 = NULL;
670 static char *main_text_title_3 = NULL;
672 struct MainControlInfo
676 struct MenuPosInfo *pos_button;
679 struct TextPosInfo *pos_text;
682 struct TextPosInfo *pos_input;
686 static struct MainControlInfo main_controls[] =
690 &menu.main.button.name, IMG_MENU_BUTTON_NAME,
691 &menu.main.text.name, &main_text_name,
692 &menu.main.input.name, &setup.player_name,
696 &menu.main.button.levels, IMG_MENU_BUTTON_LEVELS,
697 &menu.main.text.levels, &main_text_levels,
702 &menu.main.button.scores, IMG_MENU_BUTTON_SCORES,
703 &menu.main.text.scores, &main_text_scores,
708 &menu.main.button.editor, IMG_MENU_BUTTON_EDITOR,
709 &menu.main.text.editor, &main_text_editor,
714 &menu.main.button.info, IMG_MENU_BUTTON_INFO,
715 &menu.main.text.info, &main_text_info,
720 &menu.main.button.game, IMG_MENU_BUTTON_GAME,
721 &menu.main.text.game, &main_text_game,
726 &menu.main.button.setup, IMG_MENU_BUTTON_SETUP,
727 &menu.main.text.setup, &main_text_setup,
732 &menu.main.button.quit, IMG_MENU_BUTTON_QUIT,
733 &menu.main.text.quit, &main_text_quit,
737 MAIN_CONTROL_PREV_LEVEL,
743 MAIN_CONTROL_NEXT_LEVEL,
749 MAIN_CONTROL_FIRST_LEVEL,
751 &menu.main.text.first_level, &main_text_first_level,
755 MAIN_CONTROL_LAST_LEVEL,
757 &menu.main.text.last_level, &main_text_last_level,
761 MAIN_CONTROL_LEVEL_NUMBER,
763 &menu.main.text.level_number, &main_text_level_number,
767 MAIN_CONTROL_LEVEL_INFO_1,
769 &menu.main.text.level_info_1, NULL,
773 MAIN_CONTROL_LEVEL_INFO_2,
775 &menu.main.text.level_info_2, NULL,
779 MAIN_CONTROL_LEVEL_NAME,
781 &menu.main.text.level_name, &main_text_level_name,
785 MAIN_CONTROL_LEVEL_AUTHOR,
787 &menu.main.text.level_author, &main_text_level_author,
791 MAIN_CONTROL_LEVEL_YEAR,
793 &menu.main.text.level_year, &main_text_level_year,
797 MAIN_CONTROL_LEVEL_IMPORTED_FROM,
799 &menu.main.text.level_imported_from, &main_text_level_imported_from,
803 MAIN_CONTROL_LEVEL_IMPORTED_BY,
805 &menu.main.text.level_imported_by, &main_text_level_imported_by,
809 MAIN_CONTROL_LEVEL_TESTED_BY,
811 &menu.main.text.level_tested_by, &main_text_level_tested_by,
815 MAIN_CONTROL_TITLE_1,
817 &menu.main.text.title_1, &main_text_title_1,
821 MAIN_CONTROL_TITLE_2,
823 &menu.main.text.title_2, &main_text_title_2,
827 MAIN_CONTROL_TITLE_3,
829 &menu.main.text.title_3, &main_text_title_3,
842 static int getTitleScreenGraphic(int nr, boolean initial)
844 return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
847 static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial)
849 return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]);
853 static int getTitleScreenGameMode(boolean initial)
855 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
859 static int getTitleMessageGameMode(boolean initial)
861 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
864 static int getTitleAnimMode(struct TitleControlInfo *tci)
866 int base = (tci->initial ? GAME_MODE_TITLE_INITIAL_1 : GAME_MODE_TITLE_1);
868 return base + tci->local_nr;
872 static int getTitleScreenBackground(boolean initial)
874 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
879 static int getTitleMessageBackground(int nr, boolean initial)
881 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
885 static int getTitleBackground(int nr, boolean initial, boolean is_image)
887 int base = (is_image ?
888 (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 :
889 IMG_BACKGROUND_TITLESCREEN_1) :
890 (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
891 IMG_BACKGROUND_TITLEMESSAGE_1));
892 int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL :
893 IMG_BACKGROUND_TITLE);
894 int graphic_local = base + nr;
896 if (graphic_info[graphic_local].bitmap != NULL)
897 return graphic_local;
899 if (graphic_info[graphic_global].bitmap != NULL)
900 return graphic_global;
902 return IMG_UNDEFINED;
905 static int getTitleSound(struct TitleControlInfo *tci)
907 boolean is_image = tci->is_image;
908 int initial = tci->initial;
909 int nr = tci->local_nr;
910 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
911 int base = (is_image ?
912 (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 :
913 SND_BACKGROUND_TITLESCREEN_1) :
914 (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
915 SND_BACKGROUND_TITLEMESSAGE_1));
916 int sound_global = menu.sound[mode];
917 int sound_local = base + nr;
920 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
921 nr, initial, is_image,
922 sound_global, getSoundListEntry(sound_global)->filename,
923 sound_local, getSoundListEntry(sound_local)->filename);
926 if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME))
929 if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME))
932 return SND_UNDEFINED;
935 static int getTitleMusic(struct TitleControlInfo *tci)
937 boolean is_image = tci->is_image;
938 int initial = tci->initial;
939 int nr = tci->local_nr;
940 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
941 int base = (is_image ?
942 (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 :
943 MUS_BACKGROUND_TITLESCREEN_1) :
944 (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
945 MUS_BACKGROUND_TITLEMESSAGE_1));
946 int music_global = menu.music[mode];
947 int music_local = base + nr;
950 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
951 nr, initial, is_image,
952 music_global, getMusicListEntry(music_global)->filename,
953 music_local, getMusicListEntry(music_local)->filename);
956 if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME))
959 if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME))
962 return MUS_UNDEFINED;
965 static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci)
967 boolean is_image = tci->is_image;
968 boolean initial = tci->initial;
969 boolean first = tci->first;
970 int nr = tci->local_nr;
971 struct TitleMessageInfo tmi;
972 struct TitleFadingInfo ti;
974 tmi = (is_image ? (initial ? (first ?
975 titlescreen_initial_first[nr] :
976 titlescreen_initial[nr])
978 titlescreen_first[nr] :
980 : (initial ? (first ?
981 titlemessage_initial_first[nr] :
982 titlemessage_initial[nr])
984 titlemessage_first[nr] :
987 ti.fade_mode = tmi.fade_mode;
988 ti.fade_delay = tmi.fade_delay;
989 ti.post_delay = tmi.post_delay;
990 ti.auto_delay = tmi.auto_delay;
995 static int compareTitleControlInfo(const void *object1, const void *object2)
997 const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1;
998 const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2;
1001 if (tci1->initial != tci2->initial)
1002 compare_result = (tci1->initial ? -1 : +1);
1003 else if (tci1->sort_priority != tci2->sort_priority)
1004 compare_result = tci1->sort_priority - tci2->sort_priority;
1005 else if (tci1->is_image != tci2->is_image)
1006 compare_result = (tci1->is_image ? -1 : +1);
1008 compare_result = tci1->local_nr - tci2->local_nr;
1010 return compare_result;
1013 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
1015 int nr, int sort_priority)
1017 title_controls[num_title_screens].is_image = is_image;
1018 title_controls[num_title_screens].initial = initial;
1019 title_controls[num_title_screens].local_nr = nr;
1020 title_controls[num_title_screens].sort_priority = sort_priority;
1022 title_controls[num_title_screens].first = FALSE; // will be set later
1024 num_title_screens++;
1027 static void InitializeTitleControls_CheckTitleInfo(boolean initial)
1031 for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++)
1033 int graphic = getTitleScreenGraphic(i, initial);
1034 Bitmap *bitmap = graphic_info[graphic].bitmap;
1035 int sort_priority = graphic_info[graphic].sort_priority;
1038 InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority);
1041 for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
1043 struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial);
1044 char *filename = getLevelSetTitleMessageFilename(i, initial);
1045 int sort_priority = tmi->sort_priority;
1047 if (filename != NULL)
1048 InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority);
1052 static void InitializeTitleControls(boolean show_title_initial)
1054 num_title_screens = 0;
1056 // 1st step: initialize title screens for game start (only when starting)
1057 if (show_title_initial)
1058 InitializeTitleControls_CheckTitleInfo(TRUE);
1060 // 2nd step: initialize title screens for current level set
1061 InitializeTitleControls_CheckTitleInfo(FALSE);
1063 // sort title screens according to sort_priority and title number
1064 qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo),
1065 compareTitleControlInfo);
1067 // mark first title screen
1068 title_controls[0].first = TRUE;
1071 static boolean visibleMenuPos(struct MenuPosInfo *pos)
1073 return (pos != NULL && pos->x != -1 && pos->y != -1);
1076 static boolean visibleTextPos(struct TextPosInfo *pos)
1078 return (pos != NULL && pos->x != -1 && pos->y != -1);
1081 static void InitializeMainControls(void)
1083 boolean local_team_mode = (!network.enabled && setup.team_mode);
1086 // set main control text values to dynamically determined values
1087 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
1089 strcpy(main_text_first_level, int2str(leveldir_current->first_level,
1090 menu.main.text.first_level.size));
1091 strcpy(main_text_last_level, int2str(leveldir_current->last_level,
1092 menu.main.text.last_level.size));
1093 strcpy(main_text_level_number, int2str(level_nr,
1094 menu.main.text.level_number.size));
1096 main_text_level_year = leveldir_current->year;
1097 main_text_level_imported_from = leveldir_current->imported_from;
1098 main_text_level_imported_by = leveldir_current->imported_by;
1099 main_text_level_tested_by = leveldir_current->tested_by;
1101 main_text_title_1 = getConfigProgramTitleString();
1102 main_text_title_2 = getConfigProgramCopyrightString();
1103 main_text_title_3 = getConfigProgramCompanyString();
1105 // set main control screen positions to dynamically determined values
1106 for (i = 0; main_controls[i].nr != -1; i++)
1108 struct MainControlInfo *mci = &main_controls[i];
1110 struct MenuPosInfo *pos_button = mci->pos_button;
1111 struct TextPosInfo *pos_text = mci->pos_text;
1112 struct TextPosInfo *pos_input = mci->pos_input;
1113 char *text = (mci->text ? *mci->text : NULL);
1114 char *input = (mci->input ? *mci->input : NULL);
1115 int button_graphic = mci->button_graphic;
1116 int font_text = (pos_text ? pos_text->font : -1);
1117 int font_input = (pos_input ? pos_input->font : -1);
1119 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
1120 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
1121 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
1122 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
1123 int text_chars = (text != NULL ? strlen(text) : 0);
1124 int input_chars = (input != NULL ? strlen(input) : 0);
1127 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
1129 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
1130 int text_width = font_text_width * text_chars;
1131 int text_height = font_text_height;
1132 int input_width = font_input_width * input_chars;
1133 int input_height = font_input_height;
1135 if (nr == MAIN_CONTROL_NAME)
1137 menu.main.input.name.width = input_width;
1138 menu.main.input.name.height = input_height;
1141 if (pos_button != NULL) // (x/y may be -1/-1 here)
1143 pos_button->width = button_width;
1144 pos_button->height = button_height;
1147 if (pos_text != NULL) // (x/y may be -1/-1 here)
1149 // calculate text size -- needed for text alignment
1150 boolean calculate_text_size = (text != NULL);
1152 if (pos_text->width == -1 || calculate_text_size)
1153 pos_text->width = text_width;
1154 if (pos_text->height == -1 || calculate_text_size)
1155 pos_text->height = text_height;
1157 if (visibleMenuPos(pos_button))
1159 if (pos_text->x == -1)
1160 pos_text->x = pos_button->x + pos_button->width;
1161 if (pos_text->y == -1)
1163 pos_button->y + (pos_button->height - pos_text->height) / 2;
1167 if (pos_input != NULL) // (x/y may be -1/-1 here)
1169 if (visibleTextPos(pos_text))
1171 if (pos_input->x == -1)
1172 pos_input->x = pos_text->x + pos_text->width;
1173 if (pos_input->y == -1)
1174 pos_input->y = pos_text->y;
1177 if (pos_input->width == -1)
1178 pos_input->width = input_width;
1179 if (pos_input->height == -1)
1180 pos_input->height = input_height;
1185 static void DrawPressedGraphicThruMask(int dst_x, int dst_y,
1186 int graphic, boolean pressed)
1188 struct GraphicInfo *g = &graphic_info[graphic];
1191 int xoffset = (pressed ? g->pressed_xoffset : 0);
1192 int yoffset = (pressed ? g->pressed_yoffset : 0);
1194 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1196 BlitBitmapMasked(src_bitmap, drawto, src_x + xoffset, src_y + yoffset,
1197 g->width, g->height, dst_x, dst_y);
1200 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
1201 boolean active_input,
1202 boolean pressed_button)
1206 for (i = 0; main_controls[i].nr != -1; i++)
1208 struct MainControlInfo *mci = &main_controls[i];
1210 if (mci->nr == nr || nr == -1)
1212 struct MenuPosInfo *pos_button = mci->pos_button;
1213 struct TextPosInfo *pos_text = mci->pos_text;
1214 struct TextPosInfo *pos_input = mci->pos_input;
1215 char *text = (mci->text ? *mci->text : NULL);
1216 char *input = (mci->input ? *mci->input : NULL);
1217 int button_graphic = mci->button_graphic;
1218 int font_text = (pos_text ? pos_text->font : -1);
1219 int font_input = (pos_input ? pos_input->font : -1);
1223 button_graphic = BUTTON_ACTIVE(button_graphic);
1224 font_text = FONT_ACTIVE(font_text);
1229 font_input = FONT_ACTIVE(font_input);
1232 if (visibleMenuPos(pos_button))
1234 struct MenuPosInfo *pos = pos_button;
1235 int x = mSX + pos->x;
1236 int y = mSY + pos->y;
1238 DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
1239 DrawPressedGraphicThruMask(x, y, button_graphic, pressed_button);
1242 if (visibleTextPos(pos_text) && text != NULL)
1244 struct TextPosInfo *pos = pos_text;
1245 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1246 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1249 // (check why/if this is needed)
1250 DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
1252 DrawText(x, y, text, font_text);
1255 if (visibleTextPos(pos_input) && input != NULL)
1257 struct TextPosInfo *pos = pos_input;
1258 int x = mSX + ALIGNED_TEXT_XPOS(pos);
1259 int y = mSY + ALIGNED_TEXT_YPOS(pos);
1262 // (check why/if this is needed)
1263 DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
1265 DrawText(x, y, input, font_input);
1271 static void DrawCursorAndText_Main(int nr, boolean active_text,
1272 boolean pressed_button)
1274 DrawCursorAndText_Main_Ext(nr, active_text, FALSE, pressed_button);
1278 static void DrawCursorAndText_Main_Input(int nr, boolean active_text,
1279 boolean pressed_button)
1281 DrawCursorAndText_Main_Ext(nr, active_text, TRUE, pressed_button);
1285 static struct MainControlInfo *getMainControlInfo(int nr)
1289 for (i = 0; main_controls[i].nr != -1; i++)
1290 if (main_controls[i].nr == nr)
1291 return &main_controls[i];
1296 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
1301 int rect_x = ALIGNED_TEXT_XPOS(rect);
1302 int rect_y = ALIGNED_TEXT_YPOS(rect);
1304 return (x >= rect_x && x < rect_x + rect->width &&
1305 y >= rect_y && y < rect_y + rect->height);
1308 static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
1313 int rect_x = ALIGNED_TEXT_XPOS(rect);
1314 int rect_y = ALIGNED_TEXT_YPOS(rect);
1317 printf("::: insideTextPosRect: (%d, %d), (%d, %d) [%d, %d] (%d, %d) => %d\n",
1318 x, y, rect_x, rect_y, rect->x, rect->y, rect->width, rect->height,
1319 (x >= rect_x && x < rect_x + rect->width &&
1320 y >= rect_y && y < rect_y + rect->height));
1323 return (x >= rect_x && x < rect_x + rect->width &&
1324 y >= rect_y && y < rect_y + rect->height);
1327 static boolean insidePreviewRect(struct PreviewInfo *preview, int x, int y)
1329 int rect_width = preview->xsize * preview->tile_size;
1330 int rect_height = preview->ysize * preview->tile_size;
1331 int rect_x = ALIGNED_XPOS(preview->x, rect_width, preview->align);
1332 int rect_y = ALIGNED_YPOS(preview->y, rect_height, preview->valign);
1334 return (x >= rect_x && x < rect_x + rect_width &&
1335 y >= rect_y && y < rect_y + rect_height);
1338 static void AdjustScrollbar(int id, int items_max, int items_visible,
1341 struct GadgetInfo *gi = screen_gadget[id];
1343 if (item_position > items_max - items_visible)
1344 item_position = items_max - items_visible;
1346 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
1347 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1348 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
1351 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
1353 AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN,
1357 static void clearMenuListArea(void)
1359 int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
1361 // correct scrollbar position if placed outside menu (playfield) area
1362 if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS)
1363 scrollbar_xpos = SX + SC_SCROLLBAR_XPOS;
1365 // clear menu list area, but not title or scrollbar
1366 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
1367 scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32);
1370 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
1372 static int cursor_array[MAX_LEV_FIELDY];
1373 int x = amSX + TILEX * xpos;
1374 int y = amSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
1379 cursor_array[ypos] = graphic;
1381 graphic = cursor_array[ypos];
1385 graphic = BUTTON_ACTIVE(graphic);
1387 DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
1388 DrawFixedGraphicThruMaskExt(drawto, x, y, graphic, 0);
1391 static void initCursor(int ypos, int graphic)
1393 drawCursorExt(0, ypos, FALSE, graphic);
1396 static void drawCursor(int ypos, boolean active)
1398 drawCursorExt(0, ypos, active, -1);
1401 static void drawCursorXY(int xpos, int ypos, int graphic)
1403 drawCursorExt(xpos, ypos, FALSE, graphic);
1406 static void drawChooseTreeCursor(int ypos, boolean active)
1408 drawCursorExt(0, ypos, active, -1);
1411 static void DrawHeadline(void)
1413 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, main_text_title_1);
1414 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, main_text_title_2);
1417 static void DrawTitleScreenImage(int nr, boolean initial)
1419 int graphic = getTitleScreenGraphic(nr, initial);
1420 Bitmap *bitmap = graphic_info[graphic].bitmap;
1421 int width = graphic_info[graphic].width;
1422 int height = graphic_info[graphic].height;
1423 int src_x = graphic_info[graphic].src_x;
1424 int src_y = graphic_info[graphic].src_y;
1430 if (width > WIN_XSIZE)
1432 // image width too large for window => center image horizontally
1433 src_x = (width - WIN_XSIZE) / 2;
1437 if (height > WIN_YSIZE)
1439 // image height too large for window => center image vertically
1440 src_y = (height - WIN_YSIZE) / 2;
1444 // always display title screens centered
1445 dst_x = (WIN_XSIZE - width) / 2;
1446 dst_y = (WIN_YSIZE - height) / 2;
1448 SetDrawBackgroundMask(REDRAW_ALL);
1449 SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE));
1451 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1453 if (DrawingOnBackground(dst_x, dst_y))
1454 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1456 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1458 redraw_mask = REDRAW_ALL;
1461 static void DrawTitleScreenMessage(int nr, boolean initial)
1463 char *filename = getLevelSetTitleMessageFilename(nr, initial);
1464 struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
1466 if (filename == NULL)
1469 // force TITLE font on title message screen
1470 SetFontStatus(getTitleMessageGameMode(initial));
1472 // if chars *and* width set to "-1", automatically determine width
1473 if (tmi->chars == -1 && tmi->width == -1)
1474 tmi->width = viewport.window[game_status].width;
1476 // if lines *and* height set to "-1", automatically determine height
1477 if (tmi->lines == -1 && tmi->height == -1)
1478 tmi->height = viewport.window[game_status].height;
1480 // if chars set to "-1", automatically determine by text and font width
1481 if (tmi->chars == -1)
1482 tmi->chars = tmi->width / getFontWidth(tmi->font);
1484 tmi->width = tmi->chars * getFontWidth(tmi->font);
1486 // if lines set to "-1", automatically determine by text and font height
1487 if (tmi->lines == -1)
1488 tmi->lines = tmi->height / getFontHeight(tmi->font);
1490 tmi->height = tmi->lines * getFontHeight(tmi->font);
1492 // if x set to "-1", automatically determine by width and alignment
1494 tmi->x = -1 * ALIGNED_XPOS(0, tmi->width, tmi->align);
1496 // if y set to "-1", automatically determine by height and alignment
1498 tmi->y = -1 * ALIGNED_YPOS(0, tmi->height, tmi->valign);
1500 SetDrawBackgroundMask(REDRAW_ALL);
1501 SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE));
1503 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1505 DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi),
1506 filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
1507 tmi->autowrap, tmi->centered, tmi->parse_comments);
1512 static void DrawTitleScreen(void)
1514 KeyboardAutoRepeatOff();
1516 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
1519 static boolean CheckTitleScreen(boolean levelset_has_changed)
1521 static boolean show_title_initial = TRUE;
1522 boolean show_titlescreen = FALSE;
1524 // needed to be able to skip title screen, if no image or message defined
1525 InitializeTitleControls(show_title_initial);
1527 if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
1528 show_titlescreen = TRUE;
1530 // show initial title images and messages only once at program start
1531 show_title_initial = FALSE;
1533 return (show_titlescreen && num_title_screens > 0);
1536 void DrawMainMenu(void)
1538 static LevelDirTree *leveldir_last_valid = NULL;
1539 boolean levelset_has_changed = FALSE;
1540 int fade_mask = REDRAW_FIELD;
1542 LimitScreenUpdates(FALSE);
1544 FadeSetLeaveScreen();
1546 // do not fade out here -- function may continue and fade on editor screen
1549 FadeMenuSoundsAndMusic();
1551 ExpireSoundLoops(FALSE);
1553 KeyboardAutoRepeatOn();
1555 audio.sound_deactivated = FALSE;
1559 // needed if last screen was the playing screen, invoked from level editor
1560 if (level_editor_test_game)
1562 CloseDoor(DOOR_CLOSE_ALL);
1564 SetGameStatus(GAME_MODE_EDITOR);
1571 // needed if last screen was the setup screen and fullscreen state changed
1572 // (moved to "execSetupGraphics()" to change fullscreen state directly)
1573 // ToggleFullscreenOrChangeWindowScalingIfNeeded();
1575 // leveldir_current may be invalid (level group, parent link)
1576 if (!validLevelSeries(leveldir_current))
1577 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
1579 if (leveldir_current != leveldir_last_valid)
1580 levelset_has_changed = TRUE;
1582 // store valid level series information
1583 leveldir_last_valid = leveldir_current;
1585 init_last = init; // switch to new busy animation
1587 // needed if last screen (level choice) changed graphics, sounds or music
1588 ReloadCustomArtwork(0);
1590 if (CheckTitleScreen(levelset_has_changed))
1592 SetGameStatus(GAME_MODE_TITLE);
1599 if (redraw_mask & REDRAW_ALL)
1600 fade_mask = REDRAW_ALL;
1603 fade_mask = REDRAW_ALL;
1607 // needed if different viewport properties defined for menues
1608 ChangeViewportPropertiesIfNeeded();
1610 SetDrawtoField(DRAW_TO_BACKBUFFER);
1612 // level_nr may have been set to value over handicap with level editor
1613 if (setup.handicap && level_nr > leveldir_current->handicap_level)
1614 level_nr = leveldir_current->handicap_level;
1616 LoadLevel(level_nr);
1617 LoadScore(level_nr);
1619 SaveLevelSetup_SeriesInfo();
1621 // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it)
1622 SetDrawDeactivationMask(REDRAW_NONE);
1623 SetDrawBackgroundMask(REDRAW_FIELD);
1625 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
1628 if (fade_mask == REDRAW_ALL)
1629 RedrawGlobalBorder();
1634 InitializeMainControls();
1636 DrawCursorAndText_Main(-1, FALSE, FALSE);
1637 DrawPreviewLevelInitial();
1638 DrawNetworkPlayers();
1640 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
1643 if (TAPE_IS_EMPTY(tape))
1645 DrawCompleteVideoDisplay();
1647 PlayMenuSoundsAndMusic();
1649 // create gadgets for main menu screen
1650 FreeScreenGadgets();
1651 CreateScreenGadgets();
1653 // may be required if audio buttons shown on tape and changed in setup menu
1655 CreateGameButtons();
1657 // map gadgets for main menu screen
1659 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
1660 UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
1662 // copy actual game door content to door double buffer for OpenDoor()
1663 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
1664 BlitBitmap(drawto, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0);
1666 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1668 DrawMaskedBorder(fade_mask);
1673 // update screen area with special editor door
1674 redraw_mask |= REDRAW_ALL;
1677 SetMouseCursor(CURSOR_DEFAULT);
1679 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
1682 static void gotoTopLevelDir(void)
1684 // move upwards until inside (but not above) top level directory
1685 while (leveldir_current->node_parent &&
1686 !strEqual(leveldir_current->node_parent->subdir, STRING_TOP_DIRECTORY))
1688 // write a "path" into level tree for easy navigation to last level
1689 if (leveldir_current->node_parent->node_group->cl_first == -1)
1691 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
1692 int leveldir_pos = posTreeInfo(leveldir_current);
1693 int num_page_entries;
1694 int cl_first, cl_cursor;
1696 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
1697 num_page_entries = num_leveldirs;
1699 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1701 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
1702 cl_cursor = leveldir_pos - cl_first;
1704 leveldir_current->node_parent->node_group->cl_first = cl_first;
1705 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
1708 leveldir_current = leveldir_current->node_parent;
1712 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1714 static unsigned int title_delay = 0;
1715 static int title_screen_nr = 0;
1716 static int last_sound = -1, last_music = -1;
1717 boolean return_to_main_menu = FALSE;
1718 struct TitleControlInfo *tci;
1721 if (button == MB_MENU_INITIALIZE)
1724 title_screen_nr = 0;
1725 tci = &title_controls[title_screen_nr];
1727 SetAnimStatus(getTitleAnimMode(tci));
1729 last_sound = SND_UNDEFINED;
1730 last_music = MUS_UNDEFINED;
1732 if (num_title_screens != 0)
1734 FadeSetEnterScreen();
1736 // use individual title fading instead of global "enter screen" fading
1737 fading = getTitleFading(tci);
1740 if (game_status_last_screen == GAME_MODE_INFO)
1742 if (num_title_screens == 0)
1744 // switch game mode from title screen mode back to info screen mode
1745 SetGameStatus(GAME_MODE_INFO);
1747 // store that last screen was info screen, not main menu screen
1748 game_status_last_screen = GAME_MODE_INFO;
1750 DrawInfoScreen_NotAvailable("Title screen information:",
1751 "No title screen for this level set.");
1756 FadeMenuSoundsAndMusic();
1758 FadeOut(REDRAW_ALL);
1760 // title screens may have different window size
1761 ChangeViewportPropertiesIfNeeded();
1763 // only required to update logic for redrawing global border
1767 DrawTitleScreenImage(tci->local_nr, tci->initial);
1769 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1771 sound = getTitleSound(tci);
1772 music = getTitleMusic(tci);
1774 if (sound != last_sound)
1775 PlayMenuSoundExt(sound);
1776 if (music != last_music)
1777 PlayMenuMusicExt(music);
1782 SetMouseCursor(CURSOR_NONE);
1786 DelayReached(&title_delay, 0); // reset delay counter
1791 if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay))
1792 button = MB_MENU_CHOICE;
1794 if (button == MB_MENU_LEAVE)
1796 return_to_main_menu = TRUE;
1798 else if (button == MB_MENU_CHOICE)
1800 if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0)
1802 SetGameStatus(GAME_MODE_INFO);
1804 info_mode = INFO_MODE_MAIN;
1813 if (title_screen_nr < num_title_screens)
1815 tci = &title_controls[title_screen_nr];
1817 SetAnimStatus(getTitleAnimMode(tci));
1819 sound = getTitleSound(tci);
1820 music = getTitleMusic(tci);
1822 if (last_sound != SND_UNDEFINED && sound != last_sound)
1823 FadeSound(last_sound);
1824 if (last_music != MUS_UNDEFINED && music != last_music)
1827 fading = getTitleFading(tci);
1829 FadeOut(REDRAW_ALL);
1832 DrawTitleScreenImage(tci->local_nr, tci->initial);
1834 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1836 sound = getTitleSound(tci);
1837 music = getTitleMusic(tci);
1839 if (sound != last_sound)
1840 PlayMenuSoundExt(sound);
1841 if (music != last_music)
1842 PlayMenuMusicExt(music);
1849 DelayReached(&title_delay, 0); // reset delay counter
1853 FadeMenuSoundsAndMusic();
1855 return_to_main_menu = TRUE;
1859 if (return_to_main_menu)
1861 SetMouseCursor(CURSOR_DEFAULT);
1863 // force full menu screen redraw after displaying title screens
1864 redraw_mask = REDRAW_ALL;
1866 if (game_status_last_screen == GAME_MODE_INFO)
1868 SetGameStatus(GAME_MODE_INFO);
1870 info_mode = INFO_MODE_MAIN;
1874 else // default: return to main menu
1876 SetGameStatus(GAME_MODE_MAIN);
1883 static void HandleMainMenu_SelectLevel(int step, int direction,
1884 int selected_level_nr)
1886 int old_level_nr = level_nr;
1889 if (selected_level_nr != NO_DIRECT_LEVEL_SELECT)
1890 new_level_nr = selected_level_nr;
1892 new_level_nr = old_level_nr + step * direction;
1894 if (new_level_nr < leveldir_current->first_level)
1895 new_level_nr = leveldir_current->first_level;
1896 if (new_level_nr > leveldir_current->last_level)
1897 new_level_nr = leveldir_current->last_level;
1899 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1901 // skipping levels is only allowed when trying to skip single level
1902 if (setup.skip_levels && new_level_nr == old_level_nr + 1 &&
1903 Request("Level still unsolved! Skip despite handicap?", REQ_ASK))
1905 leveldir_current->handicap_level++;
1906 SaveLevelSetup_SeriesInfo();
1909 new_level_nr = leveldir_current->handicap_level;
1912 if (new_level_nr != old_level_nr)
1914 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER);
1916 PlaySound(SND_MENU_ITEM_SELECTING);
1918 level_nr = new_level_nr;
1920 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1921 int2str(level_nr, menu.main.text.level_number.size),
1922 mci->pos_text->font);
1924 LoadLevel(level_nr);
1925 DrawPreviewLevelInitial();
1929 DrawCompleteVideoDisplay();
1931 SaveLevelSetup_SeriesInfo();
1933 UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
1935 // needed because DrawPreviewLevelInitial() takes some time
1941 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1943 static int choice = MAIN_CONTROL_GAME;
1944 static boolean button_pressed_last = FALSE;
1945 boolean button_pressed = FALSE;
1949 if (button == MB_MENU_INITIALIZE)
1951 DrawCursorAndText_Main(choice, TRUE, FALSE);
1956 if (mx || my) // mouse input
1960 for (i = 0; main_controls[i].nr != -1; i++)
1962 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1963 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1964 insideTextPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1966 pos = main_controls[i].nr;
1972 // check if level preview was clicked
1973 if (insidePreviewRect(&preview, mx - SX, my - SY))
1974 pos = MAIN_CONTROL_GAME;
1976 // handle pressed/unpressed state for active/inactive menu buttons
1977 // (if pos != -1, "i" contains index position corresponding to "pos")
1979 pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT &&
1980 insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY))
1981 button_pressed = TRUE;
1983 if (button_pressed != button_pressed_last)
1985 DrawCursorAndText_Main(choice, TRUE, button_pressed);
1988 PlaySound(SND_MENU_BUTTON_PRESSING);
1990 PlaySound(SND_MENU_BUTTON_RELEASING);
1993 else if (dx || dy) // keyboard input
1995 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1996 choice == MAIN_CONTROL_SETUP))
1997 button = MB_MENU_CHOICE;
2002 if (pos == MAIN_CONTROL_FIRST_LEVEL && !button)
2004 HandleMainMenu_SelectLevel(MAX_LEVELS, -1, NO_DIRECT_LEVEL_SELECT);
2006 else if (pos == MAIN_CONTROL_LAST_LEVEL && !button)
2008 HandleMainMenu_SelectLevel(MAX_LEVELS, +1, NO_DIRECT_LEVEL_SELECT);
2010 else if (pos == MAIN_CONTROL_LEVEL_NUMBER && !button)
2012 CloseDoor(DOOR_CLOSE_2);
2014 SetGameStatus(GAME_MODE_LEVELNR);
2016 DrawChooseLevelNr();
2018 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
2024 PlaySound(SND_MENU_ITEM_ACTIVATING);
2026 DrawCursorAndText_Main(choice, FALSE, FALSE);
2027 DrawCursorAndText_Main(pos, TRUE, button_pressed);
2033 if (choice != MAIN_CONTROL_INFO &&
2034 choice != MAIN_CONTROL_SETUP)
2035 HandleMainMenu_SelectLevel(1, dx, NO_DIRECT_LEVEL_SELECT);
2040 PlaySound(SND_MENU_ITEM_SELECTING);
2042 if (pos == MAIN_CONTROL_NAME)
2045 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY))
2047 // special case: menu text "name/team" clicked -- toggle team mode
2048 setup.team_mode = !setup.team_mode;
2050 InitializeMainControls();
2051 DrawCursorAndText_Main(choice, TRUE, FALSE);
2053 DrawPreviewPlayers();
2057 SetGameStatus(GAME_MODE_PSEUDO_TYPENAME);
2059 HandleTypeName(strlen(setup.player_name), 0);
2062 else if (pos == MAIN_CONTROL_LEVELS)
2066 CloseDoor(DOOR_CLOSE_2);
2068 SetGameStatus(GAME_MODE_LEVELS);
2070 SaveLevelSetup_LastSeries();
2071 SaveLevelSetup_SeriesInfo();
2073 if (setup.internal.choose_from_top_leveldir)
2076 DrawChooseLevelSet();
2079 else if (pos == MAIN_CONTROL_SCORES)
2081 CloseDoor(DOOR_CLOSE_2);
2083 SetGameStatus(GAME_MODE_SCORES);
2085 DrawHallOfFame(level_nr, -1);
2087 else if (pos == MAIN_CONTROL_EDITOR)
2089 if (leveldir_current->readonly &&
2090 !strEqual(setup.player_name, "Artsoft"))
2091 Request("This level is read only!", REQ_CONFIRM);
2093 CloseDoor(DOOR_CLOSE_2);
2095 SetGameStatus(GAME_MODE_EDITOR);
2097 FadeSetEnterScreen();
2101 else if (pos == MAIN_CONTROL_INFO)
2103 CloseDoor(DOOR_CLOSE_2);
2105 SetGameStatus(GAME_MODE_INFO);
2107 info_mode = INFO_MODE_MAIN;
2111 else if (pos == MAIN_CONTROL_GAME)
2113 StartGameActions(network.enabled, setup.autorecord, level.random_seed);
2115 else if (pos == MAIN_CONTROL_SETUP)
2117 CloseDoor(DOOR_CLOSE_2);
2119 SetGameStatus(GAME_MODE_SETUP);
2121 setup_mode = SETUP_MODE_MAIN;
2125 else if (pos == MAIN_CONTROL_QUIT)
2127 SaveLevelSetup_LastSeries();
2128 SaveLevelSetup_SeriesInfo();
2130 if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED))
2131 SetGameStatus(GAME_MODE_QUIT);
2136 button_pressed_last = button_pressed;
2140 // ============================================================================
2141 // info screen functions
2142 // ============================================================================
2144 static struct TokenInfo *info_info;
2145 static int num_info_info; // number of info entries shown on screen
2146 static int max_info_info; // total number of info entries in list
2148 static void execInfoTitleScreen(void)
2150 info_mode = INFO_MODE_TITLE;
2155 static void execInfoElements(void)
2157 info_mode = INFO_MODE_ELEMENTS;
2162 static void execInfoMusic(void)
2164 info_mode = INFO_MODE_MUSIC;
2169 static void execInfoCredits(void)
2171 info_mode = INFO_MODE_CREDITS;
2176 static void execInfoProgram(void)
2178 info_mode = INFO_MODE_PROGRAM;
2183 static void execInfoVersion(void)
2185 info_mode = INFO_MODE_VERSION;
2190 static void execInfoLevelSet(void)
2192 info_mode = INFO_MODE_LEVELSET;
2197 static void execExitInfo(void)
2199 SetGameStatus(GAME_MODE_MAIN);
2204 static struct TokenInfo info_info_main[] =
2206 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
2207 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
2208 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
2209 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
2210 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
2211 { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" },
2212 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
2213 { TYPE_EMPTY, NULL, "" },
2214 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
2219 static int getMenuTextFont(int type)
2221 if (type & (TYPE_SWITCH |
2235 static struct TokenInfo *setup_info;
2236 static struct TokenInfo setup_info_input[];
2238 static struct TokenInfo *menu_info;
2240 static void DrawCursorAndText_Menu_Ext(struct TokenInfo *token_info,
2241 int screen_pos, int menu_info_pos_raw,
2244 int pos = (menu_info_pos_raw < 0 ? screen_pos : menu_info_pos_raw);
2245 struct TokenInfo *ti = &token_info[pos];
2246 int xpos = MENU_SCREEN_START_XPOS;
2247 int ypos = MENU_SCREEN_START_YPOS + screen_pos;
2248 int font_nr = getMenuTextFont(ti->type);
2250 if (setup_mode == SETUP_MODE_INPUT)
2251 font_nr = FONT_MENU_1;
2254 font_nr = FONT_ACTIVE(font_nr);
2256 DrawText(mSX + xpos * 32, mSY + ypos * 32, ti->text, font_nr);
2258 if (ti->type & ~TYPE_SKIP_ENTRY)
2259 drawCursor(screen_pos, active);
2262 static void DrawCursorAndText_Menu(int screen_pos, int menu_info_pos_raw,
2265 DrawCursorAndText_Menu_Ext(menu_info, screen_pos, menu_info_pos_raw, active);
2268 static void DrawCursorAndText_Setup(int screen_pos, int menu_info_pos_raw,
2271 DrawCursorAndText_Menu_Ext(setup_info, screen_pos, menu_info_pos_raw, active);
2274 static char *window_size_text;
2275 static char *scaling_type_text;
2276 static char *network_server_text;
2278 static void drawSetupValue(int, int);
2280 static void drawMenuInfoList(int first_entry, int num_page_entries,
2281 int max_page_entries)
2285 if (first_entry + num_page_entries > max_page_entries)
2288 clearMenuListArea();
2290 for (i = 0; i < num_page_entries; i++)
2292 int menu_info_pos = first_entry + i;
2293 struct TokenInfo *si = &menu_info[menu_info_pos];
2294 void *value_ptr = si->value;
2296 // set some entries to "unchangeable" according to other variables
2297 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
2298 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
2299 (value_ptr == &setup.sound_music && !audio.music_available) ||
2300 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
2301 (value_ptr == &window_size_text && !video.window_scaling_available) ||
2302 (value_ptr == &scaling_type_text && !video.window_scaling_available))
2303 si->type |= TYPE_GHOSTED;
2305 if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
2306 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
2307 else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
2308 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
2309 else if (si->type & ~TYPE_SKIP_ENTRY)
2310 initCursor(i, IMG_MENU_BUTTON);
2312 DrawCursorAndText_Menu(i, menu_info_pos, FALSE);
2314 if (si->type & TYPE_STRING)
2318 if (value_ptr == &network_server_text)
2319 gadget_id = SCREEN_CTRL_ID_NETWORK_SERVER;
2321 if (gadget_id != -1)
2323 struct GadgetInfo *gi = screen_gadget[gadget_id];
2324 int xpos = MENU_SCREEN_START_XPOS;
2325 int ypos = MENU_SCREEN_START_YPOS + i;
2326 int x = mSX + xpos * 32;
2327 int y = mSY + ypos * 32;
2329 ModifyGadget(gi, GDI_X, x, GDI_Y, y, GDI_END);
2333 if (si->type & TYPE_VALUE &&
2334 menu_info == setup_info)
2335 drawSetupValue(i, menu_info_pos);
2339 static void DrawInfoScreen_Main(void)
2341 int fade_mask = REDRAW_FIELD;
2344 if (redraw_mask & REDRAW_ALL)
2345 fade_mask = REDRAW_ALL;
2348 fade_mask = REDRAW_ALL;
2351 FadeMenuSoundsAndMusic();
2353 FreeScreenGadgets();
2354 CreateScreenGadgets();
2356 // (needed after displaying title screens which disable auto repeat)
2357 KeyboardAutoRepeatOn();
2359 FadeSetLeaveScreen();
2363 // needed if different viewport properties defined for info screen
2364 ChangeViewportPropertiesIfNeeded();
2366 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
2370 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
2372 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
2374 info_info = info_info_main;
2376 // determine maximal number of info entries that can be displayed on screen
2378 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
2381 // determine maximal number of info entries available for menu of info screen
2383 for (i = 0; info_info[i].type != 0; i++)
2386 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
2388 MapScreenGadgets(max_info_info);
2390 PlayMenuSoundsAndMusic();
2392 DrawMaskedBorder(fade_mask);
2397 static void changeSetupValue(int, int, int);
2399 static void HandleMenuScreen(int mx, int my, int dx, int dy, int button,
2400 int mode, int num_page_entries,
2401 int max_page_entries)
2403 static int num_page_entries_all_last[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2404 static int choice_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2405 static int first_entry_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES];
2406 int *num_page_entries_last = num_page_entries_all_last[game_status];
2407 int *choice_store = choice_stores[game_status];
2408 int *first_entry_store = first_entry_stores[game_status];
2409 int choice = choice_store[mode]; // starts with 0
2410 int first_entry = first_entry_store[mode]; // starts with 0
2412 int y = choice - first_entry;
2414 boolean position_set_by_scrollbar = (dx == 999);
2415 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2418 if (button == MB_MENU_INITIALIZE)
2420 // check if number of menu page entries has changed (may happen by change
2421 // of custom artwork definition value for 'list_size' for this menu screen)
2422 // (in this case, the last menu position most probably has to be corrected)
2423 if (num_page_entries != num_page_entries_last[mode])
2425 choice_store[mode] = first_entry_store[mode] = 0;
2427 choice = first_entry = 0;
2430 num_page_entries_last[mode] = num_page_entries;
2433 // advance to first valid menu entry
2434 while (choice < num_page_entries &&
2435 menu_info[choice].type & TYPE_SKIP_ENTRY)
2438 if (position_set_by_scrollbar)
2439 first_entry = first_entry_store[mode] = dy;
2441 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2442 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2444 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2446 if (choice < first_entry)
2448 choice = first_entry;
2450 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2453 else if (choice > first_entry + num_page_entries - 1)
2455 choice = first_entry + num_page_entries - 1;
2457 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2461 choice_store[mode] = choice;
2463 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2467 else if (button == MB_MENU_LEAVE)
2469 PlaySound(SND_MENU_ITEM_SELECTING);
2471 for (i = 0; i < max_page_entries; i++)
2473 if (menu_info[i].type & TYPE_LEAVE_MENU)
2475 void (*menu_callback_function)(void) = menu_info[i].value;
2479 menu_callback_function();
2481 break; // absolutely needed because function changes 'menu_info'!
2488 if (mx || my) // mouse input
2490 x = (mx - mSX) / 32;
2491 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2493 else if (dx || dy) // keyboard or scrollbar/scrollbutton input
2495 // move cursor instead of scrolling when already at start/end of list
2496 if (dy == -1 * SCROLL_LINE && first_entry == 0)
2498 else if (dy == +1 * SCROLL_LINE &&
2499 first_entry + num_page_entries == max_page_entries)
2502 // handle scrolling screen one line or page
2504 y + dy > num_page_entries - 1)
2506 boolean redraw = FALSE;
2508 if (ABS(dy) == SCROLL_PAGE)
2509 step = num_page_entries - 1;
2511 if (dy < 0 && first_entry > 0)
2513 // scroll page/line up
2515 first_entry -= step;
2516 if (first_entry < 0)
2521 else if (dy > 0 && first_entry + num_page_entries < max_page_entries)
2523 // scroll page/line down
2525 first_entry += step;
2526 if (first_entry + num_page_entries > max_page_entries)
2527 first_entry = MAX(0, max_page_entries - num_page_entries);
2534 choice += first_entry - first_entry_store[mode];
2536 if (choice < first_entry)
2538 choice = first_entry;
2540 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2543 else if (choice > first_entry + num_page_entries - 1)
2545 choice = first_entry + num_page_entries - 1;
2547 if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2550 else if (menu_info[choice].type & TYPE_SKIP_ENTRY)
2554 if (choice < first_entry ||
2555 choice > first_entry + num_page_entries - 1)
2556 first_entry += SIGN(dy);
2559 first_entry_store[mode] = first_entry;
2560 choice_store[mode] = choice;
2562 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2564 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2566 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2567 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2575 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
2577 if (menu_info[choice].type & menu_navigation_type ||
2578 menu_info[choice].type & TYPE_BOOLEAN_STYLE ||
2579 menu_info[choice].type & TYPE_YES_NO_AUTO ||
2580 menu_info[choice].type & TYPE_PLAYER)
2581 button = MB_MENU_CHOICE;
2586 // jump to next non-empty menu entry (up or down)
2587 while (first_entry + y > 0 &&
2588 first_entry + y < max_page_entries - 1 &&
2589 menu_info[first_entry + y].type & TYPE_SKIP_ENTRY)
2592 if (!IN_VIS_MENU(x, y))
2594 choice += y - y_old;
2596 if (choice < first_entry)
2597 first_entry = choice;
2598 else if (choice > first_entry + num_page_entries - 1)
2599 first_entry = choice - num_page_entries + 1;
2601 if (first_entry >= 0 &&
2602 first_entry + num_page_entries <= max_page_entries)
2604 first_entry_store[mode] = first_entry;
2606 if (choice < first_entry)
2607 choice = first_entry;
2608 else if (choice > first_entry + num_page_entries - 1)
2609 choice = first_entry + num_page_entries - 1;
2611 choice_store[mode] = choice;
2613 drawMenuInfoList(first_entry, num_page_entries, max_page_entries);
2615 DrawCursorAndText_Menu(choice - first_entry, choice, TRUE);
2617 AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries,
2618 NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
2625 if (!anyScrollbarGadgetActive() &&
2626 IN_VIS_MENU(x, y) &&
2627 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
2628 y >= 0 && y < num_page_entries)
2632 if (first_entry + y != choice &&
2633 menu_info[first_entry + y].type & ~TYPE_SKIP_ENTRY)
2635 PlaySound(SND_MENU_ITEM_ACTIVATING);
2637 DrawCursorAndText_Menu(choice - first_entry, choice, FALSE);
2638 DrawCursorAndText_Menu(y, first_entry + y, TRUE);
2640 choice = choice_store[mode] = first_entry + y;
2644 PlaySound(SND_MENU_ITEM_SELECTING);
2646 for (i = 0; menu_info[i].type != 0; i++)
2648 if (menu_info[i].type & TYPE_LEAVE_MENU)
2650 void (*menu_callback_function)(void) = menu_info[i].value;
2654 menu_callback_function();
2656 // absolutely needed because function changes 'menu_info'!
2664 else if (!(menu_info[first_entry + y].type & TYPE_GHOSTED))
2666 PlaySound(SND_MENU_ITEM_SELECTING);
2668 // when selecting key headline, execute function for key value change
2669 if (menu_info[first_entry + y].type & TYPE_KEYTEXT &&
2670 menu_info[first_entry + y + 1].type & TYPE_KEY)
2673 // when selecting string value, execute function for list selection
2674 if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 &&
2675 menu_info[first_entry + y - 1].type & TYPE_ENTER_LIST)
2678 // when selecting string value, execute function for text input gadget
2679 if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 &&
2680 menu_info[first_entry + y - 1].type & TYPE_TEXT_INPUT)
2683 if (menu_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE)
2685 void (*menu_callback_function)(void) =
2686 menu_info[first_entry + y].value;
2688 FadeSetFromType(menu_info[first_entry + y].type);
2690 menu_callback_function();
2692 else if (menu_info[first_entry + y].type & TYPE_TEXT_INPUT)
2694 void (*gadget_callback_function)(void) =
2695 menu_info[first_entry + y].value;
2697 gadget_callback_function();
2699 else if (menu_info[first_entry + y].type & TYPE_VALUE &&
2700 menu_info == setup_info)
2702 changeSetupValue(y, first_entry + y, dx);
2708 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
2710 menu_info = info_info;
2712 HandleMenuScreen(mx, my, dx, dy, button,
2713 info_mode, num_info_info, max_info_info);
2716 static int getMenuFontSpacing(int spacing_height, int font_nr)
2718 int font_spacing = getFontHeight(font_nr) + EXTRA_SPACING(game_status);
2720 return (spacing_height < 0 ? ABS(spacing_height) * font_spacing :
2724 static int getMenuTextSpacing(int spacing_height, int font_nr)
2726 return (getMenuFontSpacing(spacing_height, font_nr) +
2727 EXTRA_SPACING(game_status));
2730 static int getMenuTextStep(int spacing_height, int font_nr)
2732 return getFontHeight(font_nr) + getMenuTextSpacing(spacing_height, font_nr);
2735 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
2737 int font_title = MENU_INFO_FONT_TITLE;
2738 int font_error = FONT_TEXT_2;
2739 int font_foot = MENU_INFO_FONT_FOOT;
2740 int spacing_title = menu.headline1_spacing_info[info_mode];
2741 int ystep_title = getMenuTextStep(spacing_title, font_title);
2742 int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2743 int ystart2 = ystart1 + ystep_title;
2744 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2746 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO);
2748 FadeOut(REDRAW_FIELD);
2753 DrawTextSCentered(ystart1, font_title, text_title);
2754 DrawTextSCentered(ystart2, font_error, text_error);
2756 DrawTextSCentered(ybottom, font_foot,
2757 "Press any key or button for info menu");
2759 FadeIn(REDRAW_FIELD);
2762 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
2764 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
2765 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
2766 int font_title = MENU_INFO_FONT_TITLE;
2767 int font_foot = MENU_INFO_FONT_FOOT;
2768 int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT;
2769 int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2770 int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2;
2771 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2772 int ystep = MENU_SCREEN_INFO_YSTEP;
2773 int element, action, direction;
2781 for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++)
2782 infoscreen_step[i] = infoscreen_frame[i] = 0;
2787 DrawTextSCentered(ystart1, font_title, "The Game Elements:");
2789 DrawTextSCentered(ybottom, font_foot,
2790 "Press any key or button for next page");
2796 while (helpanim_info[j].element != HELPANIM_LIST_END)
2798 if (i >= start + NUM_INFO_ELEMENTS_ON_SCREEN ||
2803 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2812 j += infoscreen_step[i - start];
2814 element = helpanim_info[j].element;
2815 action = helpanim_info[j].action;
2816 direction = helpanim_info[j].direction;
2819 element = EL_UNKNOWN;
2821 if (action != -1 && direction != -1)
2822 graphic = el_act_dir2img(element, action, direction);
2823 else if (action != -1)
2824 graphic = el_act2img(element, action);
2825 else if (direction != -1)
2826 graphic = el_dir2img(element, direction);
2828 graphic = el2img(element);
2830 delay = helpanim_info[j++].delay;
2835 if (infoscreen_frame[i - start] == 0)
2838 infoscreen_frame[i - start] = delay - 1;
2842 sync_frame = delay - infoscreen_frame[i - start];
2843 infoscreen_frame[i - start]--;
2846 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
2848 if (!infoscreen_frame[i - start])
2849 infoscreen_step[i - start] = 0;
2853 if (!infoscreen_frame[i - start])
2854 infoscreen_step[i - start]++;
2855 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2861 ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep,
2863 DrawFixedGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep,
2864 graphic, sync_frame, USE_MASKING);
2867 DrawInfoScreen_HelpText(element, action, direction, i - start);
2872 redraw_mask |= REDRAW_FIELD;
2877 static char *getHelpText(int element, int action, int direction)
2879 char token[MAX_LINE_LEN];
2881 strcpy(token, element_info[element].token_name);
2884 strcat(token, element_action_info[action].suffix);
2886 if (direction != -1)
2887 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
2889 return getHashEntry(helptext_info, token);
2892 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
2894 int font_nr = FONT_INFO_ELEMENTS;
2895 int font_width = getFontWidth(font_nr);
2896 int font_height = getFontHeight(font_nr);
2897 int yoffset = (TILEX - 2 * font_height) / 2;
2898 int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT + TILEX + MINI_TILEX;
2899 int ystart = mSY + MENU_SCREEN_INFO_YSTART2 + yoffset;
2900 int ystep = TILEY + 4;
2901 int pad_left = xstart - SX;
2902 int pad_right = MENU_SCREEN_INFO_SPACE_RIGHT;
2903 int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width;
2904 int max_lines_per_text = 2;
2907 if (action != -1 && direction != -1) // element.action.direction
2908 text = getHelpText(element, action, direction);
2910 if (text == NULL && action != -1) // element.action
2911 text = getHelpText(element, action, -1);
2913 if (text == NULL && direction != -1) // element.direction
2914 text = getHelpText(element, -1, direction);
2916 if (text == NULL) // base element
2917 text = getHelpText(element, -1, -1);
2919 if (text == NULL) // not found
2920 text = "No description available";
2922 if (strlen(text) <= max_chars_per_line) // only one line of text
2923 ystart += getFontHeight(font_nr) / 2;
2925 DrawTextBuffer(xstart, ystart + ypos * ystep, text, font_nr,
2926 max_chars_per_line, -1, max_lines_per_text, 0, -1,
2927 TRUE, FALSE, FALSE);
2930 static void DrawInfoScreen_TitleScreen(void)
2932 SetGameStatus(GAME_MODE_TITLE);
2937 void HandleInfoScreen_TitleScreen(int button)
2939 HandleTitleScreen(0, 0, 0, 0, button);
2942 static void DrawInfoScreen_Elements(void)
2944 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
2946 FadeOut(REDRAW_FIELD);
2951 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
2953 FadeIn(REDRAW_FIELD);
2956 void HandleInfoScreen_Elements(int button)
2958 static unsigned int info_delay = 0;
2959 static int num_anims;
2960 static int num_pages;
2962 int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN;
2965 if (button == MB_MENU_INITIALIZE)
2967 boolean new_element = TRUE;
2971 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
2973 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
2975 else if (new_element)
2978 new_element = FALSE;
2982 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
2986 if (button == MB_MENU_LEAVE)
2988 PlaySound(SND_MENU_ITEM_SELECTING);
2990 info_mode = INFO_MODE_MAIN;
2995 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2997 if (button != MB_MENU_INITIALIZE)
2999 PlaySound(SND_MENU_ITEM_SELECTING);
3004 if (page >= num_pages)
3006 FadeMenuSoundsAndMusic();
3008 info_mode = INFO_MODE_MAIN;
3015 FadeSetNextScreen();
3017 if (button != MB_MENU_INITIALIZE)
3018 FadeOut(REDRAW_FIELD);
3020 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
3022 if (button != MB_MENU_INITIALIZE)
3023 FadeIn(REDRAW_FIELD);
3027 if (DelayReached(&info_delay, GameFrameDelay))
3028 if (page < num_pages)
3029 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
3031 PlayMenuSoundIfLoop();
3035 static void DrawInfoScreen_Music(void)
3037 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
3039 FadeOut(REDRAW_FIELD);
3046 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
3048 FadeIn(REDRAW_FIELD);
3051 void HandleInfoScreen_Music(int button)
3053 static struct MusicFileInfo *list = NULL;
3054 int font_title = MENU_INFO_FONT_TITLE;
3055 int font_head = MENU_INFO_FONT_HEAD;
3056 int font_text = MENU_INFO_FONT_TEXT;
3057 int font_foot = MENU_INFO_FONT_FOOT;
3058 int spacing_title = menu.headline1_spacing_info[info_mode];
3059 int spacing_head = menu.headline2_spacing_info[info_mode];
3060 int ystep_title = getMenuTextStep(spacing_title, font_title);
3061 int ystep_head = getMenuTextStep(spacing_head, font_head);
3062 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3063 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3065 if (button == MB_MENU_INITIALIZE)
3067 list = music_file_info;
3071 FadeMenuSoundsAndMusic();
3076 DrawTextSCentered(ystart, font_title,
3077 "No music info for this level set.");
3079 DrawTextSCentered(ybottom, font_foot,
3080 "Press any key or button for info menu");
3086 if (button == MB_MENU_LEAVE)
3088 PlaySound(SND_MENU_ITEM_SELECTING);
3090 FadeMenuSoundsAndMusic();
3092 info_mode = INFO_MODE_MAIN;
3097 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3099 if (button != MB_MENU_INITIALIZE)
3101 PlaySound(SND_MENU_ITEM_SELECTING);
3109 FadeMenuSoundsAndMusic();
3111 info_mode = INFO_MODE_MAIN;
3117 FadeMenuSoundsAndMusic();
3119 if (list != music_file_info)
3120 FadeSetNextScreen();
3122 if (button != MB_MENU_INITIALIZE)
3123 FadeOut(REDRAW_FIELD);
3130 int sound = list->music;
3132 if (sound_info[sound].loop)
3133 PlaySoundLoop(sound);
3137 DrawTextSCentered(ystart, font_title, "The Game Background Sounds:");
3141 int music = list->music;
3143 if (music_info[music].loop)
3144 PlayMusicLoop(music);
3148 DrawTextSCentered(ystart, font_title, "The Game Background Music:");
3151 ystart += ystep_title;
3153 if (!strEqual(list->title, UNKNOWN_NAME))
3155 if (!strEqual(list->title_header, UNKNOWN_NAME))
3157 DrawTextSCentered(ystart, font_head, list->title_header);
3158 ystart += ystep_head;
3161 DrawTextFCentered(ystart, font_text, "\"%s\"", list->title);
3162 ystart += ystep_head;
3165 if (!strEqual(list->artist, UNKNOWN_NAME))
3167 if (!strEqual(list->artist_header, UNKNOWN_NAME))
3168 DrawTextSCentered(ystart, font_head, list->artist_header);
3170 DrawTextSCentered(ystart, font_head, "by");
3172 ystart += ystep_head;
3174 DrawTextFCentered(ystart, font_text, "%s", list->artist);
3175 ystart += ystep_head;
3178 if (!strEqual(list->album, UNKNOWN_NAME))
3180 if (!strEqual(list->album_header, UNKNOWN_NAME))
3181 DrawTextSCentered(ystart, font_head, list->album_header);
3183 DrawTextSCentered(ystart, font_head, "from the album");
3185 ystart += ystep_head;
3187 DrawTextFCentered(ystart, font_text, "\"%s\"", list->album);
3188 ystart += ystep_head;
3191 if (!strEqual(list->year, UNKNOWN_NAME))
3193 if (!strEqual(list->year_header, UNKNOWN_NAME))
3194 DrawTextSCentered(ystart, font_head, list->year_header);
3196 DrawTextSCentered(ystart, font_head, "from the year");
3198 ystart += ystep_head;
3200 DrawTextFCentered(ystart, font_text, "%s", list->year);
3201 ystart += ystep_head;
3204 DrawTextSCentered(ybottom, FONT_TEXT_4,
3205 "Press any key or button for next page");
3207 if (button != MB_MENU_INITIALIZE)
3208 FadeIn(REDRAW_FIELD);
3211 if (list != NULL && list->is_sound && sound_info[list->music].loop)
3212 PlaySoundLoop(list->music);
3215 static void DrawInfoScreen_CreditsScreen(int screen_nr)
3217 int font_title = MENU_INFO_FONT_TITLE;
3218 int font_head = MENU_INFO_FONT_HEAD;
3219 int font_text = MENU_INFO_FONT_TEXT;
3220 int font_foot = MENU_INFO_FONT_FOOT;
3221 int spacing_title = menu.headline1_spacing_info[info_mode];
3222 int spacing_head = menu.headline2_spacing_info[info_mode];
3223 int spacing_para = menu.paragraph_spacing_info[info_mode];
3224 int spacing_line = menu.line_spacing_info[info_mode];
3225 int ystep_title = getMenuTextStep(spacing_title, font_title);
3226 int ystep_head = getMenuTextStep(spacing_head, font_head);
3227 int ystep_para = getMenuTextStep(spacing_para, font_text);
3228 int ystep_line = getMenuTextStep(spacing_line, font_text);
3229 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3230 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3235 DrawTextSCentered(ystart, font_title, "Credits:");
3236 ystart += ystep_title;
3240 DrawTextSCentered(ystart, font_head,
3241 "Special thanks to");
3242 ystart += ystep_head;
3243 DrawTextSCentered(ystart, font_text,
3245 ystart += ystep_head;
3246 DrawTextSCentered(ystart, font_head,
3248 ystart += ystep_head;
3249 DrawTextSCentered(ystart, font_text,
3250 "\"Boulder Dash\"");
3251 ystart += ystep_head;
3252 DrawTextSCentered(ystart, font_head,
3254 ystart += ystep_head;
3255 DrawTextSCentered(ystart, font_text,
3257 ystart += ystep_head;
3258 DrawTextSCentered(ystart, font_head,
3260 ystart += ystep_head;
3261 DrawTextSCentered(ystart, font_text,
3262 "First Star Software");
3264 else if (screen_nr == 1)
3266 DrawTextSCentered(ystart, font_head,
3267 "Special thanks to");
3268 ystart += ystep_head;
3269 DrawTextSCentered(ystart, font_text,
3270 "Klaus Heinz & Volker Wertich");
3271 ystart += ystep_head;
3272 DrawTextSCentered(ystart, font_head,
3274 ystart += ystep_head;
3275 DrawTextSCentered(ystart, font_text,
3276 "\"Emerald Mine\"");
3277 ystart += ystep_head;
3278 DrawTextSCentered(ystart, font_head,
3280 ystart += ystep_head;
3281 DrawTextSCentered(ystart, font_text,
3283 ystart += ystep_head;
3284 DrawTextSCentered(ystart, font_head,
3286 ystart += ystep_head;
3287 DrawTextSCentered(ystart, font_text,
3290 else if (screen_nr == 2)
3292 DrawTextSCentered(ystart, font_head,
3293 "Special thanks to");
3294 ystart += ystep_head;
3295 DrawTextSCentered(ystart, font_text,
3296 "Michael Stopp & Philip Jespersen");
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,
3309 ystart += ystep_head;
3310 DrawTextSCentered(ystart, font_head,
3312 ystart += ystep_head;
3313 DrawTextSCentered(ystart, font_text,
3314 "Digital Integration");
3316 else if (screen_nr == 3)
3318 DrawTextSCentered(ystart, font_head,
3319 "Special thanks to");
3320 ystart += ystep_head;
3321 DrawTextSCentered(ystart, font_text,
3322 "Hiroyuki Imabayashi");
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,
3335 ystart += ystep_head;
3336 DrawTextSCentered(ystart, font_head,
3338 ystart += ystep_head;
3339 DrawTextSCentered(ystart, font_text,
3342 else if (screen_nr == 4)
3344 DrawTextSCentered(ystart, font_head,
3345 "Special thanks to");
3346 ystart += ystep_head;
3347 DrawTextSCentered(ystart, font_text,
3349 ystart += ystep_head;
3350 DrawTextSCentered(ystart, font_head,
3352 ystart += ystep_head;
3353 DrawTextSCentered(ystart, font_text,
3354 "J\xfcrgen Bonhagen");
3355 ystart += ystep_head;
3356 DrawTextSCentered(ystart, font_head,
3357 "for the continuous creation");
3358 ystart += ystep_line;
3359 DrawTextSCentered(ystart, font_head,
3360 "of outstanding level sets");
3362 else if (screen_nr == 5)
3364 DrawTextSCentered(ystart, font_head,
3366 ystart += ystep_head;
3367 DrawTextSCentered(ystart, font_text,
3369 ystart += ystep_head;
3370 DrawTextSCentered(ystart, font_head,
3371 "for ideas and inspiration by");
3372 ystart += ystep_head;
3373 DrawTextSCentered(ystart, font_text,
3375 ystart += ystep_para;
3377 DrawTextSCentered(ystart, font_head,
3379 ystart += ystep_head;
3380 DrawTextSCentered(ystart, font_text,
3382 ystart += ystep_head;
3383 DrawTextSCentered(ystart, font_head,
3384 "for ideas and inspiration by");
3385 ystart += ystep_head;
3386 DrawTextSCentered(ystart, font_text,
3389 else if (screen_nr == 6)
3391 DrawTextSCentered(ystart, font_head,
3393 ystart += ystep_head;
3394 DrawTextSCentered(ystart, font_text,
3396 ystart += ystep_head;
3397 DrawTextSCentered(ystart, font_head,
3398 "for the code base used for the");
3399 ystart += ystep_line;
3400 DrawTextSCentered(ystart, font_head,
3401 "native Emerald Mine engine");
3403 else if (screen_nr == 7)
3405 DrawTextSCentered(ystart, font_head,
3407 ystart += ystep_head;
3408 DrawTextSCentered(ystart, font_text,
3410 ystart += ystep_head;
3411 DrawTextSCentered(ystart, font_head,
3412 "for the initial DOS port");
3413 ystart += ystep_para;
3415 DrawTextSCentered(ystart, font_head,
3417 ystart += ystep_head;
3418 DrawTextSCentered(ystart, font_text,
3420 ystart += ystep_head;
3421 DrawTextSCentered(ystart, font_head,
3422 "for some additional toons");
3424 else if (screen_nr == 8)
3426 DrawTextSCentered(ystart, font_head,
3427 "And not to forget:");
3428 ystart += ystep_head;
3429 DrawTextSCentered(ystart, font_head,
3431 ystart += ystep_head;
3432 DrawTextSCentered(ystart, font_text,
3433 "All those who contributed");
3434 ystart += ystep_line;
3435 DrawTextSCentered(ystart, font_text,
3436 "levels to this game");
3437 ystart += ystep_line;
3438 DrawTextSCentered(ystart, font_text,
3442 DrawTextSCentered(ybottom, font_foot,
3443 "Press any key or button for next page");
3446 static void DrawInfoScreen_Credits(void)
3448 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
3450 FadeMenuSoundsAndMusic();
3452 FadeOut(REDRAW_FIELD);
3454 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
3456 FadeIn(REDRAW_FIELD);
3459 void HandleInfoScreen_Credits(int button)
3461 static int screen_nr = 0;
3462 int num_screens = 9;
3464 if (button == MB_MENU_INITIALIZE)
3468 // DrawInfoScreen_CreditsScreen(screen_nr);
3471 if (button == MB_MENU_LEAVE)
3473 PlaySound(SND_MENU_ITEM_SELECTING);
3475 info_mode = INFO_MODE_MAIN;
3480 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
3482 if (button != MB_MENU_INITIALIZE)
3484 PlaySound(SND_MENU_ITEM_SELECTING);
3489 if (screen_nr >= num_screens)
3491 FadeMenuSoundsAndMusic();
3493 info_mode = INFO_MODE_MAIN;
3500 FadeSetNextScreen();
3502 if (button != MB_MENU_INITIALIZE)
3503 FadeOut(REDRAW_FIELD);
3505 DrawInfoScreen_CreditsScreen(screen_nr);
3507 if (button != MB_MENU_INITIALIZE)
3508 FadeIn(REDRAW_FIELD);
3512 PlayMenuSoundIfLoop();
3516 static void DrawInfoScreen_Program(void)
3518 int font_title = MENU_INFO_FONT_TITLE;
3519 int font_head = MENU_INFO_FONT_HEAD;
3520 int font_text = MENU_INFO_FONT_TEXT;
3521 int font_foot = MENU_INFO_FONT_FOOT;
3522 int spacing_title = menu.headline1_spacing_info[info_mode];
3523 int spacing_head = menu.headline2_spacing_info[info_mode];
3524 int spacing_para = menu.paragraph_spacing_info[info_mode];
3525 int spacing_line = menu.line_spacing_info[info_mode];
3526 int ystep_title = getMenuTextStep(spacing_title, font_title);
3527 int ystep_head = getMenuTextStep(spacing_head, font_head);
3528 int ystep_para = getMenuTextStep(spacing_para, font_text);
3529 int ystep_line = getMenuTextStep(spacing_line, font_text);
3530 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3531 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3533 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
3535 FadeOut(REDRAW_FIELD);
3540 DrawTextSCentered(ystart, font_title, "Program Information:");
3541 ystart += ystep_title;
3543 DrawTextSCentered(ystart, font_head,
3544 "This game is Freeware!");
3545 ystart += ystep_head;
3546 DrawTextSCentered(ystart, font_head,
3547 "If you like it, send e-mail to:");
3548 ystart += ystep_head;
3549 DrawTextSCentered(ystart, font_text,
3550 setup.internal.program_email);
3551 ystart += ystep_para;
3553 DrawTextSCentered(ystart, font_head,
3554 "More information and levels:");
3555 ystart += ystep_head;
3556 DrawTextSCentered(ystart, font_text,
3557 setup.internal.program_website);
3558 ystart += ystep_para;
3560 DrawTextSCentered(ystart, font_head,
3561 "If you have created new levels,");
3562 ystart += ystep_line;
3563 DrawTextSCentered(ystart, font_head,
3564 "send them to me to include them!");
3565 ystart += ystep_head;
3566 DrawTextSCentered(ystart, font_head,
3569 DrawTextSCentered(ybottom, font_foot,
3570 "Press any key or button for info menu");
3572 FadeIn(REDRAW_FIELD);
3575 void HandleInfoScreen_Program(int button)
3577 if (button == MB_MENU_LEAVE)
3579 PlaySound(SND_MENU_ITEM_SELECTING);
3581 info_mode = INFO_MODE_MAIN;
3586 else if (button == MB_MENU_CHOICE)
3588 PlaySound(SND_MENU_ITEM_SELECTING);
3590 FadeMenuSoundsAndMusic();
3592 info_mode = INFO_MODE_MAIN;
3597 PlayMenuSoundIfLoop();
3601 static void DrawInfoScreen_Version(void)
3603 int font_title = MENU_INFO_FONT_TITLE;
3604 int font_head = MENU_INFO_FONT_HEAD;
3605 int font_text = MENU_INFO_FONT_TEXT;
3606 int font_foot = MENU_INFO_FONT_FOOT;
3607 int spacing_title = menu.headline1_spacing_info[info_mode];
3608 int spacing_head = menu.headline2_spacing_info[info_mode];
3609 int spacing_para = menu.paragraph_spacing_info[info_mode];
3610 int spacing_line = menu.line_spacing_info[info_mode];
3611 int xstep = getFontWidth(font_text);
3612 int ystep_title = getMenuTextStep(spacing_title, font_title);
3613 int ystep_head = getMenuTextStep(spacing_head, font_head);
3614 int ystep_para = getMenuTextStep(spacing_para, font_text);
3615 int ystep_line = getMenuTextStep(spacing_line, font_text);
3616 int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1;
3617 int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
3618 int xstart1 = mSX - SX + 2 * xstep;
3619 int xstart2 = mSX - SX + 18 * xstep;
3620 int xstart3 = mSX - SX + 28 * xstep;
3621 SDL_version sdl_version_compiled;
3622 const SDL_version *sdl_version_linked;
3623 int driver_name_len = 10;
3624 SDL_version sdl_version_linked_ext;
3625 const char *driver_name = NULL;
3627 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION);
3629 FadeOut(REDRAW_FIELD);
3634 DrawTextSCentered(ystart, font_title, "Version Information:");
3635 ystart += ystep_title;
3637 DrawTextF(xstart1, ystart, font_head, "Name");
3638 DrawTextF(xstart2, ystart, font_text, getProgramTitleString());
3639 ystart += ystep_line;
3641 if (!strEqual(getProgramVersionString(), getProgramRealVersionString()))
3643 DrawTextF(xstart1, ystart, font_head, "Version (fake)");
3644 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3645 ystart += ystep_line;
3647 DrawTextF(xstart1, ystart, font_head, "Version (real)");
3648 DrawTextF(xstart2, ystart, font_text, getProgramRealVersionString());
3649 ystart += ystep_line;
3653 DrawTextF(xstart1, ystart, font_head, "Version");
3654 DrawTextF(xstart2, ystart, font_text, getProgramVersionString());
3655 ystart += ystep_line;
3658 DrawTextF(xstart1, ystart, font_head, "Platform");
3659 DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING);
3660 ystart += ystep_line;
3662 DrawTextF(xstart1, ystart, font_head, "Target");
3663 DrawTextF(xstart2, ystart, font_text, TARGET_STRING);
3664 ystart += ystep_line;
3666 DrawTextF(xstart1, ystart, font_head, "Source date");
3667 DrawTextF(xstart2, ystart, font_text, getSourceDateString());
3668 ystart += ystep_para;
3670 DrawTextF(xstart1, ystart, font_head, "Library");
3671 DrawTextF(xstart2, ystart, font_head, "compiled");
3672 DrawTextF(xstart3, ystart, font_head, "linked");
3673 ystart += ystep_head;
3675 SDL_VERSION(&sdl_version_compiled);
3676 SDL_GetVersion(&sdl_version_linked_ext);
3677 sdl_version_linked = &sdl_version_linked_ext;
3679 DrawTextF(xstart1, ystart, font_text, "SDL");
3680 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3681 sdl_version_compiled.major,
3682 sdl_version_compiled.minor,
3683 sdl_version_compiled.patch);
3684 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3685 sdl_version_linked->major,
3686 sdl_version_linked->minor,
3687 sdl_version_linked->patch);
3688 ystart += ystep_line;
3690 SDL_IMAGE_VERSION(&sdl_version_compiled);
3691 sdl_version_linked = IMG_Linked_Version();
3693 DrawTextF(xstart1, ystart, font_text, "SDL_image");
3694 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3695 sdl_version_compiled.major,
3696 sdl_version_compiled.minor,
3697 sdl_version_compiled.patch);
3698 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3699 sdl_version_linked->major,
3700 sdl_version_linked->minor,
3701 sdl_version_linked->patch);
3702 ystart += ystep_line;
3704 SDL_MIXER_VERSION(&sdl_version_compiled);
3705 sdl_version_linked = Mix_Linked_Version();
3707 DrawTextF(xstart1, ystart, font_text, "SDL_mixer");
3708 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3709 sdl_version_compiled.major,
3710 sdl_version_compiled.minor,
3711 sdl_version_compiled.patch);
3712 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3713 sdl_version_linked->major,
3714 sdl_version_linked->minor,
3715 sdl_version_linked->patch);
3716 ystart += ystep_line;
3718 SDL_NET_VERSION(&sdl_version_compiled);
3719 sdl_version_linked = SDLNet_Linked_Version();
3721 DrawTextF(xstart1, ystart, font_text, "SDL_net");
3722 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
3723 sdl_version_compiled.major,
3724 sdl_version_compiled.minor,
3725 sdl_version_compiled.patch);
3726 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
3727 sdl_version_linked->major,
3728 sdl_version_linked->minor,
3729 sdl_version_linked->patch);
3730 ystart += ystep_para;
3732 DrawTextF(xstart1, ystart, font_head, "Driver");
3733 DrawTextF(xstart2, ystart, font_head, "Requested");
3734 DrawTextF(xstart3, ystart, font_head, "Used");
3735 ystart += ystep_head;
3737 driver_name = getStringCopyNStatic(SDL_GetVideoDriver(0), driver_name_len);
3739 DrawTextF(xstart1, ystart, font_text, "SDL_VideoDriver");
3740 DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_videodriver);
3741 DrawTextF(xstart3, ystart, font_text, "%s", driver_name);
3742 ystart += ystep_line;
3744 driver_name = getStringCopyNStatic(SDL_GetAudioDriver(0), driver_name_len);
3746 DrawTextF(xstart1, ystart, font_text, "SDL_AudioDriver");