1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
28 /* screens in the setup menu */
29 #define SETUP_MODE_MAIN 0
30 #define SETUP_MODE_GAME 1
31 #define SETUP_MODE_EDITOR 2
32 #define SETUP_MODE_INPUT 3
33 #define SETUP_MODE_SHORTCUT_1 4
34 #define SETUP_MODE_SHORTCUT_2 5
35 #define SETUP_MODE_GRAPHICS 6
36 #define SETUP_MODE_CHOOSE_SCREEN_MODE 7
37 #define SETUP_MODE_SOUND 8
38 #define SETUP_MODE_ARTWORK 9
39 #define SETUP_MODE_CHOOSE_GRAPHICS 10
40 #define SETUP_MODE_CHOOSE_SOUNDS 11
41 #define SETUP_MODE_CHOOSE_MUSIC 12
43 #define MAX_SETUP_MODES 13
45 /* for input setup functions */
46 #define SETUPINPUT_SCREEN_POS_START 0
47 #define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4)
48 #define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3)
49 #define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1)
51 /* screens on the info screen */
52 #define INFO_MODE_MAIN 0
53 #define INFO_MODE_TITLE 1
54 #define INFO_MODE_ELEMENTS 2
55 #define INFO_MODE_MUSIC 3
56 #define INFO_MODE_CREDITS 4
57 #define INFO_MODE_PROGRAM 5
58 #define INFO_MODE_VERSION 6
59 #define INFO_MODE_LEVELSET 7
61 #define MAX_INFO_MODES 8
63 /* for various menu stuff */
64 #define MENU_SCREEN_START_XPOS 1
65 #define MENU_SCREEN_START_YPOS 2
66 #define MENU_SCREEN_VALUE_XPOS 14
67 #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1)
68 #define MENU_TITLE1_YPOS 8
69 #define MENU_TITLE2_YPOS 46
70 #define MAX_INFO_ELEMENTS_ON_SCREEN 10
71 #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS)
72 #define MAX_MENU_TEXT_LENGTH_BIG (MENU_SCREEN_VALUE_XPOS - \
73 MENU_SCREEN_START_XPOS)
74 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2)
76 /* buttons and scrollbars identifiers */
77 #define SCREEN_CTRL_ID_PREV_LEVEL 0
78 #define SCREEN_CTRL_ID_NEXT_LEVEL 1
79 #define SCREEN_CTRL_ID_PREV_PLAYER 2
80 #define SCREEN_CTRL_ID_NEXT_PLAYER 3
81 #define SCREEN_CTRL_ID_SCROLL_UP 4
82 #define SCREEN_CTRL_ID_SCROLL_DOWN 5
83 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 6
85 #define NUM_SCREEN_GADGETS 7
87 #define NUM_SCREEN_MENUBUTTONS 4
88 #define NUM_SCREEN_SCROLLBUTTONS 2
89 #define NUM_SCREEN_SCROLLBARS 1
91 #define SCREEN_MASK_MAIN (1 << 0)
92 #define SCREEN_MASK_INPUT (1 << 1)
94 /* graphic position and size values for buttons and scrollbars */
95 #define SC_MENUBUTTON_XSIZE TILEX
96 #define SC_MENUBUTTON_YSIZE TILEY
98 #define SC_SCROLLBUTTON_XSIZE TILEX
99 #define SC_SCROLLBUTTON_YSIZE TILEY
101 #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
103 #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
104 #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
105 SC_SCROLLBUTTON_YSIZE)
107 #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS
108 #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE)
110 #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS
111 #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \
112 SC_SCROLLBUTTON_YSIZE)
114 #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS
115 #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \
116 SC_SCROLL_VERTICAL_YSIZE)
118 #define SC_BORDER_SIZE 14
120 /* other useful macro definitions */
121 #define BUTTON_GRAPHIC_ACTIVE(g) \
122 (g == IMG_MENU_BUTTON_LEFT ? IMG_MENU_BUTTON_LEFT_ACTIVE : \
123 g == IMG_MENU_BUTTON_RIGHT ? IMG_MENU_BUTTON_RIGHT_ACTIVE : \
124 g == IMG_MENU_BUTTON_UP ? IMG_MENU_BUTTON_UP_ACTIVE : \
125 g == IMG_MENU_BUTTON_DOWN ? IMG_MENU_BUTTON_DOWN_ACTIVE : \
126 g == IMG_MENU_BUTTON_LEAVE_MENU ? IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE : \
127 g == IMG_MENU_BUTTON_ENTER_MENU ? IMG_MENU_BUTTON_ENTER_MENU_ACTIVE : \
128 g == IMG_MENU_BUTTON_PREV_LEVEL ? IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE : \
129 g == IMG_MENU_BUTTON_NEXT_LEVEL ? IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE : \
130 IMG_MENU_BUTTON_ACTIVE)
133 /* forward declarations of internal functions */
134 static void HandleScreenGadgets(struct GadgetInfo *);
135 static void HandleSetupScreen_Generic(int, int, int, int, int);
136 static void HandleSetupScreen_Input(int, int, int, int, int);
137 static void CustomizeKeyboard(int);
138 static void CalibrateJoystick(int);
139 static void execSetupGraphics(void);
140 static void execSetupArtwork(void);
141 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
143 static void DrawChooseLevel(void);
144 static void DrawInfoScreen(void);
145 static void DrawAndFadeInInfoScreen(int);
146 static void DrawSetupScreen(void);
148 static void DrawInfoScreenExt(int, int);
149 static void DrawInfoScreen_NotAvailable(char *, char *);
150 static void DrawInfoScreen_HelpAnim(int, int, boolean);
151 static void DrawInfoScreen_HelpText(int, int, int, int);
152 static void HandleInfoScreen_Main(int, int, int, int, int);
153 static void HandleInfoScreen_TitleScreen(int);
154 static void HandleInfoScreen_Elements(int);
155 static void HandleInfoScreen_Music(int);
156 static void HandleInfoScreen_Credits(int);
157 static void HandleInfoScreen_Program(int);
158 static void HandleInfoScreen_Version(int);
160 static void MapScreenMenuGadgets(int);
161 static void MapScreenTreeGadgets(TreeInfo *);
163 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
165 static boolean show_titlescreen_initial = TRUE;
167 static int setup_mode = SETUP_MODE_MAIN;
168 static int info_mode = INFO_MODE_MAIN;
170 static TreeInfo *screen_modes = NULL;
171 static TreeInfo *screen_mode_current = NULL;
173 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
174 (s) <= GAME_MODE_SETUP ? (s) : \
175 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
176 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
178 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_ELEMENTS && \
179 (i) <= INFO_MODE_LEVELSET ? (i) : \
182 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
183 menu.draw_xoffset[GAME_MODE_INFO] : \
184 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
185 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
186 menu.draw_yoffset[GAME_MODE_INFO] : \
187 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
189 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
190 DRAW_XOFFSET_INFO(info_mode) : \
191 menu.draw_xoffset[DRAW_MODE(s)])
192 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
193 DRAW_YOFFSET_INFO(info_mode) : \
194 menu.draw_yoffset[DRAW_MODE(s)])
196 #define mSX (SX + DRAW_XOFFSET(game_status))
197 #define mSY (SY + DRAW_YOFFSET(game_status))
199 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
200 menu.list_size[game_status] : \
201 MAX_MENU_ENTRIES_ON_SCREEN)
203 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
204 #define NUM_SCROLLBAR_BITMAPS 2
205 static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
209 #define MAIN_CONTROL_NAME 0
210 #define MAIN_CONTROL_LEVELS 1
211 #define MAIN_CONTROL_SCORES 2
212 #define MAIN_CONTROL_EDITOR 3
213 #define MAIN_CONTROL_INFO 4
214 #define MAIN_CONTROL_GAME 5
215 #define MAIN_CONTROL_SETUP 6
216 #define MAIN_CONTROL_QUIT 7
217 #define MAIN_CONTROL_PREV_LEVEL 8
218 #define MAIN_CONTROL_NEXT_LEVEL 9
219 #define MAIN_CONTROL_CURRENT_LEVEL 10
220 #define MAIN_CONTROL_FIRST_LEVEL 11
221 #define MAIN_CONTROL_LAST_LEVEL 12
222 #define MAIN_CONTROL_LEVEL_INFO_1 13
223 #define MAIN_CONTROL_LEVEL_INFO_2 14
224 #define MAIN_CONTROL_TITLE_1 15
225 #define MAIN_CONTROL_TITLE_2 16
226 #define MAIN_CONTROL_TITLE_3 17
228 static char main_text_name[10];
229 static char main_text_current_level[10];
230 static char main_text_first_level[10];
231 static char main_text_last_level[10];
232 static char main_input_name[MAX_PLAYER_NAME_LEN + 1];
234 struct MainControlInfo
238 struct MenuPosInfo *pos_button;
241 struct MenuPosInfo *pos_text;
245 struct MenuPosInfo *pos_input;
250 static struct MainControlInfo main_controls[] =
254 &menu.main.button.name, IMG_MENU_BUTTON,
255 &menu.main.text.name, main_text_name, FONT_MENU_1,
256 &menu.main.input.name, main_input_name, FONT_INPUT_1,
260 &menu.main.button.levels, IMG_MENU_BUTTON_ENTER_MENU,
261 &menu.main.text.levels, "Levelset", FONT_MENU_1,
266 &menu.main.button.scores, IMG_MENU_BUTTON,
267 &menu.main.text.scores, "Hall Of Fame", FONT_MENU_1,
272 &menu.main.button.editor, IMG_MENU_BUTTON,
273 &menu.main.text.editor, "Level Creator", FONT_MENU_1,
278 &menu.main.button.info, IMG_MENU_BUTTON_ENTER_MENU,
279 &menu.main.text.info, "Info Screen", FONT_MENU_1,
284 &menu.main.button.game, IMG_MENU_BUTTON,
285 &menu.main.text.game, "Start Game", FONT_MENU_1,
290 &menu.main.button.setup, IMG_MENU_BUTTON_ENTER_MENU,
291 &menu.main.text.setup, "Setup", FONT_MENU_1,
296 &menu.main.button.quit, IMG_MENU_BUTTON,
297 &menu.main.text.quit, "Quit", FONT_MENU_1,
301 /* (these two buttons are real gadgets) */
303 MAIN_CONTROL_PREV_LEVEL,
304 &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL,
309 MAIN_CONTROL_NEXT_LEVEL,
310 &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL,
316 MAIN_CONTROL_CURRENT_LEVEL,
318 &menu.main.text.current_level, main_text_current_level,FONT_VALUE_1,
322 MAIN_CONTROL_FIRST_LEVEL,
324 &menu.main.text.first_level, main_text_first_level, FONT_TEXT_3,
328 MAIN_CONTROL_LAST_LEVEL,
330 &menu.main.text.last_level, main_text_last_level, FONT_TEXT_3,
334 MAIN_CONTROL_LEVEL_INFO_1,
336 &menu.main.text.level_info_1, NULL, -1,
340 MAIN_CONTROL_LEVEL_INFO_2,
342 &menu.main.text.level_info_2, NULL, -1,
346 MAIN_CONTROL_TITLE_1,
348 &menu.main.text.title_1, PROGRAM_TITLE_STRING, FONT_TITLE_1,
352 MAIN_CONTROL_TITLE_2,
354 &menu.main.text.title_2, PROGRAM_COPYRIGHT_STRING, FONT_TITLE_2,
358 MAIN_CONTROL_TITLE_3,
360 &menu.main.text.title_3, PROGRAM_GAME_BY_STRING, FONT_TITLE_2,
373 static void InitializeMainControls()
375 boolean local_team_mode = (!options.network && setup.team_mode);
378 /* set main control text values to dynamically determined values */
379 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
380 sprintf(main_text_current_level, "%s", int2str(level_nr, 3));
381 sprintf(main_text_first_level, "%03d", leveldir_current->first_level);
382 sprintf(main_text_last_level, "%03d", leveldir_current->last_level);
383 sprintf(main_input_name, "%s", setup.player_name);
385 /* set main control screen positions to dynamically determined values */
386 for (i = 0; main_controls[i].nr != -1; i++)
388 struct MainControlInfo *mci = &main_controls[i];
390 struct MenuPosInfo *pos_button = mci->pos_button;
391 struct MenuPosInfo *pos_text = mci->pos_text;
392 struct MenuPosInfo *pos_input = mci->pos_input;
393 char *text = mci->text;
394 char *input = mci->input;
395 int button_graphic = mci->button_graphic;
396 int font_text = mci->font_text;
397 int font_input = mci->font_input;
399 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
400 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
401 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
402 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
403 int text_chars = (text != NULL ? strlen(text) : 0);
404 int input_chars = (input != NULL ? strlen(input) : 0);
407 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
409 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
410 int text_width = font_text_width * text_chars;
411 int text_height = font_text_height;
412 int input_width = font_input_width * input_chars;
413 int input_height = font_input_height;
415 if (nr == MAIN_CONTROL_NAME)
418 if (menu.main.input.name.x == -1)
419 menu.main.input.name.x = menu.main.text.name.x + text_width;
420 if (menu.main.input.name.y == -1)
421 menu.main.input.name.y = menu.main.text.name.y;
424 menu.main.input.name.width = font_input_width * MAX_PLAYER_NAME_LEN;
425 menu.main.input.name.height = font_input_height;
428 if (pos_button != NULL)
430 if (pos_button->width == 0)
431 pos_button->width = button_width;
432 if (pos_button->height == 0)
433 pos_button->height = button_height;
436 if (pos_text != NULL)
438 /* calculate width for non-clickable text -- needed for text alignment */
439 boolean calculate_text_width = (pos_button == NULL && text != NULL);
441 if (pos_text->x == -1 && pos_button != NULL)
442 pos_text->x = pos_button->x + pos_button->width;
443 if (pos_text->y == -1 && pos_button != NULL)
444 pos_text->y = pos_button->y;
446 if (pos_text->width == -1 || calculate_text_width)
447 pos_text->width = text_width;
448 if (pos_text->height == -1)
449 pos_text->height = text_height;
452 if (pos_input != NULL)
454 if (pos_input->x == -1 && pos_text != NULL)
455 pos_input->x = pos_text->x + pos_text->width;
456 if (pos_input->y == -1 && pos_text != NULL)
457 pos_input->y = pos_text->y;
459 if (pos_input->width == -1)
460 pos_input->width = input_width;
461 if (pos_input->height == -1)
462 pos_input->height = input_height;
467 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
468 boolean active_input)
472 for (i = 0; main_controls[i].nr != -1; i++)
474 struct MainControlInfo *mci = &main_controls[i];
476 if (mci->nr == nr || nr == -1)
478 struct MenuPosInfo *pos_button = mci->pos_button;
479 struct MenuPosInfo *pos_text = mci->pos_text;
480 struct MenuPosInfo *pos_input = mci->pos_input;
481 char *text = mci->text;
482 char *input = mci->input;
483 int button_graphic = mci->button_graphic;
484 int font_text = mci->font_text;
485 int font_input = mci->font_input;
489 button_graphic = BUTTON_GRAPHIC_ACTIVE(button_graphic);
490 font_text = FONT_ACTIVE(font_text);
495 font_input = FONT_ACTIVE(font_input);
498 if (pos_button != NULL)
500 struct MenuPosInfo *pos = pos_button;
501 int x = mSX + pos->x;
502 int y = mSY + pos->y;
504 DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
505 DrawGraphicThruMaskExt(drawto, x, y, button_graphic, 0);
508 if (pos_text != NULL && text != NULL)
510 struct MenuPosInfo *pos = pos_text;
511 int x = mSX + ALIGNED_MENU_XPOS(pos);
512 int y = mSY + ALIGNED_MENU_YPOS(pos);
514 DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
515 DrawText(x, y, text, font_text);
518 if (pos_input != NULL && input != NULL)
520 struct MenuPosInfo *pos = pos_input;
521 int x = mSX + ALIGNED_MENU_XPOS(pos);
522 int y = mSY + ALIGNED_MENU_YPOS(pos);
524 DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
525 DrawText(x, y, input, font_input);
531 static void DrawCursorAndText_Main(int nr, boolean active_text)
533 DrawCursorAndText_Main_Ext(nr, active_text, FALSE);
537 static void DrawCursorAndText_Main_Input(int nr, boolean active_text)
539 DrawCursorAndText_Main_Ext(nr, active_text, TRUE);
543 static struct MainControlInfo *getMainControlInfo(int nr)
547 for (i = 0; main_controls[i].nr != -1; i++)
548 if (main_controls[i].nr == nr)
549 return &main_controls[i];
554 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
559 int rect_x = ALIGNED_MENU_XPOS(rect);
560 int rect_y = ALIGNED_MENU_YPOS(rect);
562 return (x >= rect_x && x < rect_x + rect->width &&
563 y >= rect_y && y < rect_y + rect->height);
566 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
568 static int cursor_array[SCR_FIELDY];
569 int x = mSX + TILEX * xpos;
570 int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
575 cursor_array[ypos] = graphic;
577 graphic = cursor_array[ypos];
581 graphic = BUTTON_GRAPHIC_ACTIVE(graphic);
583 DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
584 DrawGraphicThruMaskExt(drawto, x, y, graphic, 0);
587 static void initCursor(int ypos, int graphic)
589 drawCursorExt(0, ypos, FALSE, graphic);
592 static void drawCursor(int ypos, boolean active)
594 drawCursorExt(0, ypos, active, -1);
597 static void drawCursorXY(int xpos, int ypos, int graphic)
599 drawCursorExt(xpos, ypos, FALSE, graphic);
602 static void drawChooseTreeCursor(int ypos, boolean active)
604 int last_game_status = game_status; /* save current game status */
606 /* force LEVELS draw offset on artwork setup screen */
607 game_status = GAME_MODE_LEVELS;
609 drawCursorExt(0, ypos, active, -1);
611 game_status = last_game_status; /* restore current game status */
616 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
617 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
621 static int getPrevlevelButtonPos()
626 static int getCurrentLevelTextPos()
628 return (getPrevlevelButtonPos() + 1);
631 static int getNextLevelButtonPos()
633 return getPrevlevelButtonPos() + 3 + 1;
636 static int getLevelRangeTextPos()
638 return getNextLevelButtonPos() + 1;
642 static int getTitleScreenGraphic()
644 return (show_titlescreen_initial ? IMG_TITLESCREEN_INITIAL_1 :
648 int effectiveGameStatus()
650 if (game_status == GAME_MODE_INFO && info_mode == INFO_MODE_TITLE)
651 return GAME_MODE_TITLE;
656 void DrawTitleScreenImage(int nr)
658 int graphic = getTitleScreenGraphic() + nr;
659 Bitmap *bitmap = graphic_info[graphic].bitmap;
661 int width = graphic_info[graphic].width;
662 int height = graphic_info[graphic].height;
663 int src_x = graphic_info[graphic].src_x;
664 int src_y = graphic_info[graphic].src_y;
666 int width = graphic_info[graphic].src_image_width;
667 int height = graphic_info[graphic].src_image_height;
668 int src_x = 0, src_y = 0;
675 if (width > WIN_XSIZE)
677 /* image width too large for window => center image horizontally */
678 src_x = (width - WIN_XSIZE) / 2;
682 if (height > WIN_YSIZE)
684 /* image height too large for window => center image vertically */
685 src_y = (height - WIN_YSIZE) / 2;
689 dst_x = (WIN_XSIZE - width) / 2;
690 dst_y = (WIN_YSIZE - height) / 2;
692 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
694 if (DrawingOnBackground(dst_x, dst_y))
695 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
697 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
699 redraw_mask = REDRAW_ALL;
701 /* reset fading control values to default config settings */
702 title.fade_delay_final = title.fade_delay;
703 title.post_delay_final = title.post_delay;
704 title.auto_delay_final = title.auto_delay;
706 /* override default settings with image config settings, if defined */
707 if (graphic_info[graphic].fade_delay > -1)
708 title.fade_delay_final = graphic_info[graphic].fade_delay;
709 if (graphic_info[graphic].post_delay > -1)
710 title.post_delay_final = graphic_info[graphic].post_delay;
711 if (graphic_info[graphic].auto_delay > -1)
712 title.auto_delay_final = graphic_info[graphic].auto_delay;
715 void DrawTitleScreenMessage(char *filename)
717 int font_nr = FONT_TEXT_1;
724 int max_chars_per_line;
725 int max_lines_per_screen;
726 int last_game_status = game_status; /* save current game status */
728 if (filename == NULL)
731 SetDrawBackgroundMask(REDRAW_ALL);
732 SetWindowBackgroundImageIfDefined(IMG_BACKGROUND_MESSAGE);
734 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
736 /* force MESSAGE font on title message screen */
737 game_status = GAME_MODE_MESSAGE;
739 font_width = getFontWidth(font_nr);
740 font_height = getFontHeight(font_nr);
741 max_chars_per_line = (WIN_XSIZE - 2 * pad_x) / font_width;
742 max_lines_per_screen = (WIN_YSIZE - pad_y) / font_height - 1;
744 DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line,
745 max_lines_per_screen, FALSE);
747 game_status = last_game_status; /* restore current game status */
750 void DrawTitleScreen()
752 KeyboardAutoRepeatOff();
754 SetMainBackgroundImage(IMG_BACKGROUND_TITLE);
756 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
761 void DrawMainMenuExt(int redraw_mask, boolean do_fading)
763 static LevelDirTree *leveldir_last_valid = NULL;
764 boolean levelset_has_changed = FALSE;
766 boolean local_team_mode = (!options.network && setup.team_mode);
767 char *name_text = (local_team_mode ? "Team:" : "Name:");
768 int name_width, level_width;
775 FadeSoundsAndMusic();
777 KeyboardAutoRepeatOn();
780 SetDrawDeactivationMask(REDRAW_NONE);
781 SetDrawBackgroundMask(REDRAW_FIELD);
783 audio.sound_deactivated = FALSE;
787 /* needed if last screen was the playing screen, invoked from level editor */
788 if (level_editor_test_game)
790 game_status = GAME_MODE_EDITOR;
796 /* needed if last screen was the editor screen */
797 UndrawSpecialEditorDoor();
799 /* needed if last screen was the setup screen and fullscreen state changed */
800 ToggleFullscreenIfNeeded();
802 /* leveldir_current may be invalid (level group, parent link) */
803 if (!validLevelSeries(leveldir_current))
804 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
806 if (leveldir_current != leveldir_last_valid)
807 levelset_has_changed = TRUE;
809 /* store valid level series information */
810 leveldir_last_valid = leveldir_current;
812 /* needed if last screen (level choice) changed graphics, sounds or music */
813 ReloadCustomArtwork(0);
815 #if defined(TARGET_SDL)
816 SetDrawtoField(DRAW_BACKBUFFER);
819 if (setup.show_titlescreen &&
820 ((levelset_has_changed &&
821 (graphic_info[IMG_TITLESCREEN_1].bitmap != NULL ||
822 getLevelSetMessageFilename() != NULL)) ||
823 (show_titlescreen_initial &&
824 graphic_info[IMG_TITLESCREEN_INITIAL_1].bitmap != NULL)))
826 game_status = GAME_MODE_TITLE;
833 /* level_nr may have been set to value over handicap with level editor */
834 if (setup.handicap && level_nr > leveldir_current->handicap_level)
835 level_nr = leveldir_current->handicap_level;
839 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
843 InitializeMainControls();
846 DrawCursorAndText_Main(-1, FALSE);
848 for (i = 0; main_controls[i].nr != -1; i++)
850 struct MenuPosInfo *pos_button = main_controls[i].pos_button;
851 struct MenuPosInfo *pos_text = main_controls[i].pos_text;
852 struct MenuPosInfo *pos_input = main_controls[i].pos_input;
853 char *text = main_controls[i].text;
854 char *input = main_controls[i].input;
855 int button_graphic = main_controls[i].button_graphic;
856 int font_text = main_controls[i].font_text;
857 int font_input = main_controls[i].font_input;
859 if (pos_button != NULL)
860 DrawGraphicThruMaskExt(drawto, mSX + pos_button->x, mSY + pos_button->y,
863 if (pos_text != NULL && text != NULL)
864 DrawText(mSX + pos_text->x, mSY + pos_text->y, text, font_text);
866 if (pos_input != NULL && input != NULL)
867 DrawText(mSX + pos_input->x, mSY + pos_input->y, input, font_input);
875 DrawText(mSX + 32, mSY + 2 * 32, name_text, FONT_MENU_1);
876 DrawText(mSX + 32, mSY + 3 * 32, "Levelset", FONT_MENU_1);
877 DrawText(mSX + 32, mSY + 4 * 32, "Hall Of Fame", FONT_MENU_1);
878 DrawText(mSX + 32, mSY + 5 * 32, "Level Creator", FONT_MENU_1);
879 DrawText(mSX + 32, mSY + 6 * 32, "Info Screen", FONT_MENU_1);
880 DrawText(mSX + 32, mSY + 7 * 32, "Start Game", FONT_MENU_1);
881 DrawText(mSX + 32, mSY + 8 * 32, "Setup", FONT_MENU_1);
882 DrawText(mSX + 32, mSY + 9 * 32, "Quit", FONT_MENU_1);
884 /* calculated after (possible) reload of custom artwork */
885 name_width = getTextWidth(name_text, FONT_MENU_1);
886 level_width = 9 * 32;
888 DrawText(mSX + 32 + name_width, mSY + 2 * 32, setup.player_name,
891 DrawText(mSX + getCurrentLevelTextPos() * 32, mSY + 3 * 32,
892 int2str(level_nr, 3), FONT_VALUE_1);
895 int text_height = getFontHeight(FONT_TEXT_3);
896 int xpos = getLevelRangeTextPos() * 32 + 8;
897 int ypos2 = 3 * 32 + 16;
898 int ypos1 = ypos2 - text_height;
900 DrawTextF(mSX - SX + xpos, mSY - SY + ypos1, FONT_TEXT_3,
901 "%03d", leveldir_current->first_level);
902 DrawTextF(mSX - SX + xpos, mSY - SY + ypos2, FONT_TEXT_3,
903 "%03d", leveldir_current->last_level);
906 for (i = 0; i < 8; i++)
907 initCursor(i, (i == 1 || i == 4 || i == 6 ? IMG_MENU_BUTTON_ENTER_MENU :
910 DrawTextSCentered(326, FONT_TITLE_2, PROGRAM_GAME_BY_STRING);
913 DrawPreviewLevel(TRUE);
915 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
918 if (TAPE_IS_EMPTY(tape))
920 DrawCompleteVideoDisplay();
925 /* create gadgets for main menu screen */
927 CreateScreenGadgets();
929 /* map gadgets for main menu screen */
931 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
933 DrawMaskedBorder(REDRAW_ALL);
942 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
945 void DrawAndFadeInMainMenu(int redraw_mask)
947 DrawMainMenuExt(redraw_mask, TRUE);
952 DrawMainMenuExt(REDRAW_ALL, FALSE);
956 static void gotoTopLevelDir()
958 /* move upwards to top level directory */
959 while (leveldir_current->node_parent)
961 /* write a "path" into level tree for easy navigation to last level */
962 if (leveldir_current->node_parent->node_group->cl_first == -1)
964 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
965 int leveldir_pos = posTreeInfo(leveldir_current);
966 int num_page_entries;
967 int cl_first, cl_cursor;
969 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
970 num_page_entries = num_leveldirs;
972 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
974 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
975 cl_cursor = leveldir_pos - cl_first;
977 leveldir_current->node_parent->node_group->cl_first = cl_first;
978 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
981 leveldir_current = leveldir_current->node_parent;
986 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
988 static unsigned long title_delay = 0;
989 static int title_nr = 0;
990 static boolean showing_message = FALSE;
991 char *filename = getLevelSetMessageFilename();
992 boolean return_to_main_menu = FALSE;
993 boolean use_fading_main_menu = TRUE;
994 boolean use_cross_fading = !show_titlescreen_initial; /* default */
995 boolean no_title_info = (graphic_info[IMG_TITLESCREEN_1].bitmap == NULL &&
998 if (button == MB_MENU_INITIALIZE)
1000 int last_game_status = game_status; /* save current game status */
1004 showing_message = FALSE;
1006 if (show_titlescreen_initial &&
1007 graphic_info[IMG_TITLESCREEN_INITIAL_1].bitmap == NULL)
1008 show_titlescreen_initial = FALSE;
1010 if (game_status == GAME_MODE_INFO)
1014 DrawInfoScreen_NotAvailable("Title screen information:",
1015 "No title screen for this level set.");
1017 title.auto_delay_final = -1;
1022 FadeSoundsAndMusic();
1024 FadeOut(REDRAW_ALL);
1027 /* force TITLE music on title info screen */
1028 game_status = GAME_MODE_TITLE;
1033 game_status = last_game_status; /* restore current game status */
1035 if (graphic_info[getTitleScreenGraphic()].bitmap != NULL)
1037 DrawTitleScreenImage(title_nr);
1041 DrawTitleScreenMessage(filename);
1043 showing_message = TRUE;
1045 title.fade_delay_final = title.fade_delay;
1046 title.post_delay_final = title.post_delay;
1047 title.auto_delay_final = -1;
1052 DelayReached(&title_delay, 0); /* reset delay counter */
1057 if (title.auto_delay_final > -1 &&
1058 DelayReached(&title_delay, title.auto_delay_final))
1059 button = MB_MENU_CHOICE;
1061 if (button == MB_MENU_LEAVE)
1063 return_to_main_menu = TRUE;
1064 use_fading_main_menu = FALSE;
1066 else if (button == MB_MENU_CHOICE)
1070 if (game_status == GAME_MODE_INFO && no_title_info)
1072 FadeOut(REDRAW_FIELD);
1074 info_mode = INFO_MODE_MAIN;
1075 DrawAndFadeInInfoScreen(REDRAW_FIELD);
1082 if (show_titlescreen_initial &&
1083 (title_nr >= MAX_NUM_TITLE_SCREENS ||
1084 graphic_info[IMG_TITLESCREEN_INITIAL_1 + title_nr].bitmap == NULL))
1086 show_titlescreen_initial = FALSE;
1088 title_nr = 0; /* restart with title screens for current level set */
1091 anim_mode = graphic_info[getTitleScreenGraphic() + title_nr].anim_mode;
1093 use_cross_fading = (anim_mode == ANIM_FADE ? FALSE :
1094 anim_mode == ANIM_CROSSFADE ? TRUE :
1097 if (!use_cross_fading)
1098 FadeOut(REDRAW_ALL);
1100 if (title_nr < MAX_NUM_TITLE_SCREENS &&
1101 graphic_info[getTitleScreenGraphic() + title_nr].bitmap != NULL)
1103 if (use_cross_fading)
1104 FadeCrossSaveBackbuffer();
1106 DrawTitleScreenImage(title_nr);
1108 if (use_cross_fading)
1109 FadeCross(REDRAW_ALL);
1113 DelayReached(&title_delay, 0); /* reset delay counter */
1115 else if (!showing_message && filename != NULL)
1117 if (use_cross_fading)
1118 FadeCrossSaveBackbuffer();
1120 DrawTitleScreenMessage(filename);
1122 if (use_cross_fading)
1123 FadeCross(REDRAW_ALL);
1127 DelayReached(&title_delay, 0); /* reset delay counter */
1129 showing_message = TRUE;
1133 FadeSoundsAndMusic();
1135 FadeOut(REDRAW_ALL);
1137 return_to_main_menu = TRUE;
1141 if (return_to_main_menu)
1143 show_titlescreen_initial = FALSE;
1147 if (game_status == GAME_MODE_INFO)
1149 OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1151 info_mode = INFO_MODE_MAIN;
1152 DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu);
1154 else /* default: return to main menu */
1156 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1158 game_status = GAME_MODE_MAIN;
1159 DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu);
1164 void HandleMainMenu_SelectLevel(int step, int direction)
1166 int old_level_nr = level_nr;
1169 new_level_nr = old_level_nr + step * direction;
1170 if (new_level_nr < leveldir_current->first_level)
1171 new_level_nr = leveldir_current->first_level;
1172 if (new_level_nr > leveldir_current->last_level)
1173 new_level_nr = leveldir_current->last_level;
1175 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1177 /* skipping levels is only allowed when trying to skip single level */
1178 if (setup.skip_levels && step == 1 &&
1179 Request("Level still unsolved ! Skip despite handicap ?", REQ_ASK))
1181 leveldir_current->handicap_level++;
1182 SaveLevelSetup_SeriesInfo();
1185 new_level_nr = leveldir_current->handicap_level;
1188 if (new_level_nr != old_level_nr)
1190 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_CURRENT_LEVEL);
1192 PlaySound(SND_MENU_ITEM_SELECTING);
1194 level_nr = new_level_nr;
1197 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1198 int2str(level_nr, 3), mci->font_text);
1200 DrawText(mSX + 11 * 32, mSY + 3 * 32, int2str(level_nr, 3), FONT_VALUE_1);
1203 LoadLevel(level_nr);
1204 DrawPreviewLevel(TRUE);
1208 DrawCompleteVideoDisplay();
1210 /* needed because DrawPreviewLevel() takes some time */
1218 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1220 static int choice = MAIN_CONTROL_GAME;
1224 if (button == MB_MENU_INITIALIZE)
1226 DrawCursorAndText_Main(choice, TRUE);
1231 if (mx || my) /* mouse input */
1235 for (i = 0; main_controls[i].nr != -1; i++)
1237 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1238 insideMenuPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1239 insideMenuPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1241 pos = main_controls[i].nr;
1247 else if (dx || dy) /* keyboard input */
1249 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1250 choice == MAIN_CONTROL_SETUP))
1251 button = MB_MENU_CHOICE;
1256 if (pos == MAIN_CONTROL_LEVELS && dx != 0 && button)
1258 HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1260 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
1266 PlaySound(SND_MENU_ITEM_ACTIVATING);
1268 DrawCursorAndText_Main(choice, FALSE);
1269 DrawCursorAndText_Main(pos, TRUE);
1276 PlaySound(SND_MENU_ITEM_SELECTING);
1278 if (pos == MAIN_CONTROL_NAME)
1280 game_status = GAME_MODE_PSEUDO_TYPENAME;
1282 HandleTypeName(strlen(setup.player_name), 0);
1284 else if (pos == MAIN_CONTROL_LEVELS)
1288 game_status = GAME_MODE_LEVELS;
1290 SaveLevelSetup_LastSeries();
1291 SaveLevelSetup_SeriesInfo();
1300 else if (pos == MAIN_CONTROL_SCORES)
1302 game_status = GAME_MODE_SCORES;
1306 else if (pos == MAIN_CONTROL_EDITOR)
1308 if (leveldir_current->readonly &&
1309 !strEqual(setup.player_name, "Artsoft"))
1310 Request("This level is read only !", REQ_CONFIRM);
1312 game_status = GAME_MODE_EDITOR;
1316 else if (pos == MAIN_CONTROL_INFO)
1318 game_status = GAME_MODE_INFO;
1319 info_mode = INFO_MODE_MAIN;
1323 else if (pos == MAIN_CONTROL_GAME)
1325 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
1327 else if (pos == MAIN_CONTROL_SETUP)
1329 game_status = GAME_MODE_SETUP;
1330 setup_mode = SETUP_MODE_MAIN;
1334 else if (pos == MAIN_CONTROL_QUIT)
1336 SaveLevelSetup_LastSeries();
1337 SaveLevelSetup_SeriesInfo();
1339 if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
1340 game_status = GAME_MODE_QUIT;
1345 if (game_status == GAME_MODE_MAIN)
1347 DrawPreviewLevel(FALSE);
1354 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1356 static int choice = 5;
1360 if (button == MB_MENU_INITIALIZE)
1362 drawCursor(choice, TRUE);
1367 if (mx || my) /* mouse input */
1369 x = (mx - mSX) / 32;
1370 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
1372 else if (dx || dy) /* keyboard input */
1374 if (dx && choice == 1)
1375 x = (dx < 0 ? 10 : 14);
1378 if (choice == 4 || choice == 6)
1379 button = MB_MENU_CHOICE;
1385 if (y == 1 && dx != 0 && button)
1387 HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1389 else if (IN_VIS_FIELD(x, y) &&
1390 y >= 0 && y <= 7 && (y != 1 || x < 10))
1396 drawCursor(choice, FALSE);
1397 drawCursor(y, TRUE);
1406 game_status = GAME_MODE_PSEUDO_TYPENAME;
1407 HandleTypeName(strlen(setup.player_name), 0);
1413 game_status = GAME_MODE_LEVELS;
1414 SaveLevelSetup_LastSeries();
1415 SaveLevelSetup_SeriesInfo();
1426 game_status = GAME_MODE_SCORES;
1431 if (leveldir_current->readonly &&
1432 !strEqual(setup.player_name, "Artsoft"))
1433 Request("This level is read only !", REQ_CONFIRM);
1434 game_status = GAME_MODE_EDITOR;
1439 game_status = GAME_MODE_INFO;
1440 info_mode = INFO_MODE_MAIN;
1445 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
1449 game_status = GAME_MODE_SETUP;
1450 setup_mode = SETUP_MODE_MAIN;
1456 SaveLevelSetup_LastSeries();
1457 SaveLevelSetup_SeriesInfo();
1459 if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
1460 game_status = GAME_MODE_QUIT;
1465 if (game_status == GAME_MODE_MAIN)
1467 DrawPreviewLevel(FALSE);
1475 /* ========================================================================= */
1476 /* info screen functions */
1477 /* ========================================================================= */
1479 static struct TokenInfo *info_info;
1480 static int num_info_info;
1482 static void execInfoTitleScreen()
1484 info_mode = INFO_MODE_TITLE;
1488 static void execInfoElements()
1490 info_mode = INFO_MODE_ELEMENTS;
1494 static void execInfoMusic()
1496 info_mode = INFO_MODE_MUSIC;
1500 static void execInfoCredits()
1502 info_mode = INFO_MODE_CREDITS;
1506 static void execInfoProgram()
1508 info_mode = INFO_MODE_PROGRAM;
1512 static void execInfoVersion()
1514 info_mode = INFO_MODE_VERSION;
1518 static void execInfoLevelSet()
1520 info_mode = INFO_MODE_LEVELSET;
1524 static void execExitInfo()
1526 game_status = GAME_MODE_MAIN;
1530 static struct TokenInfo info_info_main[] =
1532 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
1533 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
1534 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
1535 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
1536 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
1537 { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" },
1538 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
1539 { TYPE_EMPTY, NULL, "" },
1540 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
1545 static void DrawCursorAndText_Info(int pos, boolean active)
1547 int xpos = MENU_SCREEN_START_XPOS;
1548 int ypos = MENU_SCREEN_START_YPOS + pos;
1549 int font_nr = FONT_MENU_1;
1552 font_nr = FONT_ACTIVE(font_nr);
1554 DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[pos].text, font_nr);
1556 if (info_info[pos].type & ~TYPE_SKIP_ENTRY)
1557 drawCursor(pos, active);
1560 static void DrawInfoScreen_Main(int redraw_mask, boolean do_fading)
1565 CloseDoor(DOOR_CLOSE_2);
1569 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
1571 info_info = info_info_main;
1574 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
1577 int xpos = MENU_SCREEN_START_XPOS;
1578 int ypos = MENU_SCREEN_START_YPOS + i;
1579 int font_nr = FONT_MENU_1;
1582 if (info_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
1583 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
1584 else if (info_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
1585 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
1586 else if (info_info[i].type & ~TYPE_SKIP_ENTRY)
1587 initCursor(i, IMG_MENU_BUTTON);
1590 DrawCursorAndText_Info(i, FALSE);
1592 DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[i].text, font_nr);
1598 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
1603 DrawMaskedBorder(REDRAW_ALL);
1606 FadeIn(redraw_mask);
1613 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
1615 static int choice_store[MAX_INFO_MODES];
1616 int choice = choice_store[info_mode]; /* always starts with 0 */
1620 if (button == MB_MENU_INITIALIZE)
1622 /* advance to first valid menu entry */
1623 while (choice < num_info_info &&
1624 info_info[choice].type & TYPE_SKIP_ENTRY)
1626 choice_store[info_mode] = choice;
1629 DrawCursorAndText_Info(choice, TRUE);
1631 drawCursor(choice, TRUE);
1636 else if (button == MB_MENU_LEAVE)
1638 for (y = 0; y < num_info_info; y++)
1640 if (info_info[y].type & TYPE_LEAVE_MENU)
1642 void (*menu_callback_function)(void) = info_info[y].value;
1644 menu_callback_function();
1646 break; /* absolutely needed because function changes 'info_info'! */
1653 if (mx || my) /* mouse input */
1655 x = (mx - mSX) / 32;
1656 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
1658 else if (dx || dy) /* keyboard input */
1662 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
1664 if (info_info[choice].type & menu_navigation_type ||
1665 info_info[choice].type & TYPE_ENTER_SCREEN ||
1666 info_info[choice].type & TYPE_BOOLEAN_STYLE)
1667 button = MB_MENU_CHOICE;
1672 /* jump to next non-empty menu entry (up or down) */
1673 while (y > 0 && y < num_info_info - 1 &&
1674 info_info[y].type & TYPE_SKIP_ENTRY)
1678 if (IN_VIS_FIELD(x, y) &&
1679 y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY)
1685 PlaySound(SND_MENU_ITEM_ACTIVATING);
1688 DrawCursorAndText_Info(choice, FALSE);
1689 DrawCursorAndText_Info(y, TRUE);
1691 drawCursor(choice, FALSE);
1692 drawCursor(y, TRUE);
1695 choice = choice_store[info_mode] = y;
1698 else if (!(info_info[y].type & TYPE_GHOSTED))
1700 PlaySound(SND_MENU_ITEM_SELECTING);
1702 if (info_info[y].type & TYPE_ENTER_OR_LEAVE)
1704 void (*menu_callback_function)(void) = info_info[choice].value;
1706 menu_callback_function();
1712 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
1716 int ybottom = SYSIZE - 20;
1718 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
1720 FadeOut(REDRAW_FIELD);
1725 DrawTextSCentered(ystart1, FONT_TEXT_1, text_title);
1726 DrawTextSCentered(ystart2, FONT_TEXT_2, text_error);
1728 DrawTextSCentered(ybottom, FONT_TEXT_4,
1729 "Press any key or button for info menu");
1731 FadeIn(REDRAW_FIELD);
1734 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
1736 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
1737 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
1738 int xstart = mSX + 16;
1739 int ystart = mSY + 64 + 2 * 32;
1740 int ystep = TILEY + 4;
1741 int element, action, direction;
1749 for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
1750 infoscreen_step[i] = infoscreen_frame[i] = 0;
1755 DrawTextSCentered(100, FONT_TEXT_1, "The Game Elements:");
1757 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
1758 "Press any key or button for next page");
1764 while (helpanim_info[j].element != HELPANIM_LIST_END)
1766 if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN ||
1771 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
1780 j += infoscreen_step[i - start];
1782 element = helpanim_info[j].element;
1783 action = helpanim_info[j].action;
1784 direction = helpanim_info[j].direction;
1787 element = EL_UNKNOWN;
1789 if (action != -1 && direction != -1)
1790 graphic = el_act_dir2img(element, action, direction);
1791 else if (action != -1)
1792 graphic = el_act2img(element, action);
1793 else if (direction != -1)
1794 graphic = el_dir2img(element, direction);
1796 graphic = el2img(element);
1798 delay = helpanim_info[j++].delay;
1803 if (infoscreen_frame[i - start] == 0)
1806 infoscreen_frame[i - start] = delay - 1;
1810 sync_frame = delay - infoscreen_frame[i - start];
1811 infoscreen_frame[i - start]--;
1814 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
1816 if (!infoscreen_frame[i - start])
1817 infoscreen_step[i - start] = 0;
1821 if (!infoscreen_frame[i - start])
1822 infoscreen_step[i - start]++;
1823 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
1829 ClearRectangleOnBackground(drawto, xstart, ystart + (i - start) * ystep,
1831 DrawGraphicAnimationExt(drawto, xstart, ystart + (i - start) * ystep,
1832 graphic, sync_frame, USE_MASKING);
1835 DrawInfoScreen_HelpText(element, action, direction, i - start);
1840 redraw_mask |= REDRAW_FIELD;
1845 static char *getHelpText(int element, int action, int direction)
1847 char token[MAX_LINE_LEN];
1849 strcpy(token, element_info[element].token_name);
1852 strcat(token, element_action_info[action].suffix);
1854 if (direction != -1)
1855 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
1857 return getHashEntry(helptext_info, token);
1860 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
1863 int font_nr = FONT_INFO_ELEMENTS;
1865 int font_nr = FONT_LEVEL_NUMBER;
1867 int font_width = getFontWidth(font_nr);
1868 int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX;
1869 int sy = mSY + 65 + 2 * 32 + 1;
1870 int ystep = TILEY + 4;
1871 int pad_x = sx - SX;
1872 int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width;
1873 int max_lines_per_text = 2;
1876 if (action != -1 && direction != -1) /* element.action.direction */
1877 text = getHelpText(element, action, direction);
1879 if (text == NULL && action != -1) /* element.action */
1880 text = getHelpText(element, action, -1);
1882 if (text == NULL && direction != -1) /* element.direction */
1883 text = getHelpText(element, -1, direction);
1885 if (text == NULL) /* base element */
1886 text = getHelpText(element, -1, -1);
1888 if (text == NULL) /* not found */
1889 text = "No description available";
1891 if (strlen(text) <= max_chars_per_line) /* only one line of text */
1892 sy += getFontHeight(font_nr) / 2;
1894 DrawTextWrapped(sx, sy + ypos * ystep, text, font_nr,
1895 max_chars_per_line, max_lines_per_text);
1898 void DrawInfoScreen_TitleScreen()
1903 void HandleInfoScreen_TitleScreen(int button)
1905 HandleTitleScreen(0, 0, 0, 0, button);
1908 void DrawInfoScreen_Elements()
1910 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
1912 FadeOut(REDRAW_FIELD);
1917 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
1919 FadeIn(REDRAW_FIELD);
1924 void HandleInfoScreen_Elements(int button)
1926 static unsigned long info_delay = 0;
1927 static int num_anims;
1928 static int num_pages;
1930 int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN;
1933 if (button == MB_MENU_INITIALIZE)
1935 boolean new_element = TRUE;
1939 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
1941 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
1943 else if (new_element)
1946 new_element = FALSE;
1950 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
1954 if (button == MB_MENU_LEAVE)
1956 PlaySound(SND_MENU_ITEM_SELECTING);
1958 info_mode = INFO_MODE_MAIN;
1963 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
1965 if (button != MB_MENU_INITIALIZE)
1967 PlaySound(SND_MENU_ITEM_SELECTING);
1972 if (page >= num_pages)
1974 FadeSoundsAndMusic();
1975 FadeOut(REDRAW_FIELD);
1977 info_mode = INFO_MODE_MAIN;
1978 DrawAndFadeInInfoScreen(REDRAW_FIELD);
1983 if (button != MB_MENU_INITIALIZE)
1984 FadeCrossSaveBackbuffer();
1986 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
1988 if (button != MB_MENU_INITIALIZE)
1989 FadeCross(REDRAW_FIELD);
1993 if (DelayReached(&info_delay, GameFrameDelay))
1994 if (page < num_pages)
1995 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
1997 PlayMenuSoundIfLoop();
2001 void DrawInfoScreen_Music()
2003 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
2005 FadeOut(REDRAW_FIELD);
2012 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
2014 FadeIn(REDRAW_FIELD);
2017 void HandleInfoScreen_Music(int button)
2019 static struct MusicFileInfo *list = NULL;
2020 int ystart = 150, dy = 30;
2021 int ybottom = SYSIZE - 20;
2023 if (button == MB_MENU_INITIALIZE)
2025 list = music_file_info;
2029 FadeSoundsAndMusic();
2034 DrawTextSCentered(100, FONT_TEXT_1, "No music info for this level set.");
2036 DrawTextSCentered(ybottom, FONT_TEXT_4,
2037 "Press any key or button for info menu");
2043 if (button == MB_MENU_LEAVE)
2045 PlaySound(SND_MENU_ITEM_SELECTING);
2047 FadeSoundsAndMusic();
2049 info_mode = INFO_MODE_MAIN;
2054 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2058 if (button != MB_MENU_INITIALIZE)
2060 PlaySound(SND_MENU_ITEM_SELECTING);
2068 FadeSoundsAndMusic();
2069 FadeOut(REDRAW_FIELD);
2071 info_mode = INFO_MODE_MAIN;
2072 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2077 FadeSoundsAndMusic();
2079 if (button != MB_MENU_INITIALIZE)
2080 FadeCrossSaveBackbuffer();
2087 int sound = list->music;
2089 if (sound_info[sound].loop)
2090 PlaySoundLoop(sound);
2094 DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Sounds:");
2098 PlayMusic(list->music);
2100 DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Music:");
2103 if (!strEqual(list->title, UNKNOWN_NAME))
2105 if (!strEqual(list->title_header, UNKNOWN_NAME))
2106 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->title_header);
2108 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
2111 if (!strEqual(list->artist, UNKNOWN_NAME))
2113 if (!strEqual(list->artist_header, UNKNOWN_NAME))
2114 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->artist_header);
2116 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "by");
2118 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->artist);
2121 if (!strEqual(list->album, UNKNOWN_NAME))
2123 if (!strEqual(list->album_header, UNKNOWN_NAME))
2124 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->album_header);
2126 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the album");
2128 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album);
2131 if (!strEqual(list->year, UNKNOWN_NAME))
2133 if (!strEqual(list->year_header, UNKNOWN_NAME))
2134 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->year_header);
2136 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the year");
2138 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->year);
2141 DrawTextSCentered(ybottom, FONT_TEXT_4,
2142 "Press any key or button for next page");
2144 if (button != MB_MENU_INITIALIZE)
2145 FadeCross(REDRAW_FIELD);
2148 if (list != NULL && list->is_sound && sound_info[list->music].loop)
2149 PlaySoundLoop(list->music);
2152 static boolean DrawInfoScreen_CreditsScreen(int screen_nr)
2154 int ystart = 150, ystep = 30;
2155 int ybottom = SYSIZE - 20;
2163 DrawTextSCentered(100, FONT_TEXT_1, "Credits:");
2167 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2168 "Special thanks to");
2169 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2171 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2173 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2174 "\"Boulder Dash\"");
2175 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2177 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2179 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2181 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2182 "First Star Software");
2184 else if (screen_nr == 1)
2186 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2187 "Special thanks to");
2188 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2189 "Klaus Heinz & Volker Wertich");
2190 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2192 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2193 "\"Emerald Mine\"");
2194 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2196 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2198 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2200 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2203 else if (screen_nr == 2)
2205 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2206 "Special thanks to");
2207 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2208 "Michael Stopp & Philip Jespersen");
2209 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2211 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2213 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2215 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2217 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2219 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2220 "Digital Integration");
2222 else if (screen_nr == 3)
2224 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2225 "Special thanks to");
2226 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2227 "Hiroyuki Imabayashi");
2228 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2230 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2232 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2234 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2236 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2238 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2241 else if (screen_nr == 4)
2243 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2244 "Special thanks to");
2245 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2247 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2249 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2250 "Jürgen Bonhagen");
2251 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2252 "for the continuous creation");
2253 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
2254 "of outstanding level sets");
2256 else if (screen_nr == 5)
2258 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2260 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2262 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2263 "for ideas and inspiration by");
2264 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2267 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
2269 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_3,
2271 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2,
2272 "for ideas and inspiration by");
2273 DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_3,
2276 else if (screen_nr == 6)
2278 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2280 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2282 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2283 "for the new Emerald Mine engine");
2285 else if (screen_nr == 7)
2287 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2289 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2291 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2292 "for the initial DOS port");
2294 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2296 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2298 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2299 "for some additional toons");
2301 else if (screen_nr == 8)
2303 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2304 "And not to forget:");
2305 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2,
2307 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3,
2308 "All those who contributed");
2309 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2310 "levels to this game");
2311 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_3,
2321 DrawTextSCentered(ybottom, FONT_TEXT_4,
2322 "Press any key or button for next page");
2327 void DrawInfoScreen_Credits()
2329 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
2331 FadeSoundsAndMusic();
2333 FadeOut(REDRAW_FIELD);
2335 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
2337 FadeIn(REDRAW_FIELD);
2340 void HandleInfoScreen_Credits(int button)
2342 static int screen_nr = 0;
2344 if (button == MB_MENU_INITIALIZE)
2348 DrawInfoScreen_CreditsScreen(screen_nr);
2350 else if (button == MB_MENU_LEAVE)
2352 PlaySound(SND_MENU_ITEM_SELECTING);
2354 info_mode = INFO_MODE_MAIN;
2359 else if (button == MB_MENU_CHOICE)
2361 boolean show_screen;
2363 PlaySound(SND_MENU_ITEM_SELECTING);
2367 FadeCrossSaveBackbuffer();
2369 show_screen = DrawInfoScreen_CreditsScreen(screen_nr);
2373 FadeCross(REDRAW_FIELD);
2377 FadeSoundsAndMusic();
2378 FadeOut(REDRAW_FIELD);
2380 info_mode = INFO_MODE_MAIN;
2381 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2386 PlayMenuSoundIfLoop();
2390 void DrawInfoScreen_Program()
2392 int ystart = 150, ystep = 30;
2393 int ybottom = SYSIZE - 20;
2395 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
2397 FadeOut(REDRAW_FIELD);
2402 DrawTextSCentered(100, FONT_TEXT_1, "Program Information:");
2404 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2405 "This game is Freeware!");
2406 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2,
2407 "If you like it, send e-mail to:");
2408 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3,
2409 PROGRAM_EMAIL_STRING);
2410 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_2,
2411 "or SnailMail to:");
2412 DrawTextSCentered(ystart + 4 * ystep + 0, FONT_TEXT_3,
2414 DrawTextSCentered(ystart + 4 * ystep + 20, FONT_TEXT_3,
2415 "Detmolder Strasse 189");
2416 DrawTextSCentered(ystart + 4 * ystep + 40, FONT_TEXT_3,
2418 DrawTextSCentered(ystart + 4 * ystep + 60, FONT_TEXT_3,
2420 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2,
2421 "More information and levels:");
2422 DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_3,
2423 PROGRAM_WEBSITE_STRING);
2424 DrawTextSCentered(ystart + 9 * ystep, FONT_TEXT_2,
2425 "If you have created new levels,");
2426 DrawTextSCentered(ystart + 10 * ystep, FONT_TEXT_2,
2427 "send them to me to include them!");
2428 DrawTextSCentered(ystart + 11 * ystep, FONT_TEXT_2,
2431 DrawTextSCentered(ybottom, FONT_TEXT_4,
2432 "Press any key or button for info menu");
2434 FadeIn(REDRAW_FIELD);
2437 void HandleInfoScreen_Program(int button)
2439 if (button == MB_MENU_LEAVE)
2441 PlaySound(SND_MENU_ITEM_SELECTING);
2443 info_mode = INFO_MODE_MAIN;
2448 else if (button == MB_MENU_CHOICE)
2450 PlaySound(SND_MENU_ITEM_SELECTING);
2452 FadeSoundsAndMusic();
2453 FadeOut(REDRAW_FIELD);
2455 info_mode = INFO_MODE_MAIN;
2456 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2460 PlayMenuSoundIfLoop();
2464 void DrawInfoScreen_Version()
2466 int font_header = FONT_TEXT_3;
2467 int font_text = FONT_TEXT_2;
2468 int xstep = getFontWidth(font_text);
2469 int ystep = getFontHeight(font_text);
2470 int xstart1 = SX + 2 * xstep;
2471 int xstart2 = SX + 18 * xstep;
2472 int xstart3 = SX + 28 * xstep;
2474 int ybottom = SYSIZE - 20;
2475 #if defined(TARGET_SDL)
2476 SDL_version sdl_version_compiled;
2477 const SDL_version *sdl_version_linked;
2480 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
2482 FadeOut(REDRAW_FIELD);
2487 DrawTextSCentered(100, FONT_TEXT_1, "Version Information:");
2489 DrawTextF(xstart1, ystart, font_header, "Name");
2490 DrawTextF(xstart2, ystart, font_text, PROGRAM_TITLE_STRING);
2493 DrawTextF(xstart1, ystart, font_header, "Version");
2494 DrawTextF(xstart2, ystart, font_text, getProgramFullVersionString());
2497 DrawTextF(xstart1, ystart, font_header, "Platform");
2498 DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING);
2501 DrawTextF(xstart1, ystart, font_header, "Target");
2502 DrawTextF(xstart2, ystart, font_text, TARGET_STRING);
2505 DrawTextF(xstart1, ystart, font_header, "Compile time");
2506 DrawTextF(xstart2, ystart, font_text, getCompileDateString());
2508 #if defined(TARGET_SDL)
2509 ystart += 3 * ystep;
2510 DrawTextF(xstart1, ystart, font_header, "Library");
2511 DrawTextF(xstart2, ystart, font_header, "compiled");
2512 DrawTextF(xstart3, ystart, font_header, "linked");
2514 SDL_VERSION(&sdl_version_compiled);
2515 sdl_version_linked = SDL_Linked_Version();
2517 ystart += 2 * ystep;
2518 DrawTextF(xstart1, ystart, font_text, "SDL");
2519 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
2520 sdl_version_compiled.major,
2521 sdl_version_compiled.minor,
2522 sdl_version_compiled.patch);
2523 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
2524 sdl_version_linked->major,
2525 sdl_version_linked->minor,
2526 sdl_version_linked->patch);
2528 SDL_IMAGE_VERSION(&sdl_version_compiled);
2530 sdl_version_linked = IMG_Linked_Version();
2535 DrawTextF(xstart1, ystart, font_text, "SDL_image");
2536 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
2537 sdl_version_compiled.major,
2538 sdl_version_compiled.minor,
2539 sdl_version_compiled.patch);
2541 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
2542 sdl_version_linked->major,
2543 sdl_version_linked->minor,
2544 sdl_version_linked->patch);
2546 DrawTextF(xstart3, ystart, font_text, "?.?.?");
2549 SDL_MIXER_VERSION(&sdl_version_compiled);
2550 sdl_version_linked = Mix_Linked_Version();
2553 DrawTextF(xstart1, ystart, font_text, "SDL_mixer");
2554 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
2555 sdl_version_compiled.major,
2556 sdl_version_compiled.minor,
2557 sdl_version_compiled.patch);
2558 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
2559 sdl_version_linked->major,
2560 sdl_version_linked->minor,
2561 sdl_version_linked->patch);
2564 DrawTextF(xstart1, ystart, font_text, "SDL_net");
2565 DrawTextF(xstart2, ystart, font_text, "?.?.?");
2566 DrawTextF(xstart3, ystart, font_text, "?.?.?");
2569 DrawTextSCentered(ybottom, FONT_TEXT_4,
2570 "Press any key or button for info menu");
2572 FadeIn(REDRAW_FIELD);
2575 void HandleInfoScreen_Version(int button)
2577 if (button == MB_MENU_LEAVE)
2579 PlaySound(SND_MENU_ITEM_SELECTING);
2581 info_mode = INFO_MODE_MAIN;
2586 else if (button == MB_MENU_CHOICE)
2588 PlaySound(SND_MENU_ITEM_SELECTING);
2590 FadeSoundsAndMusic();
2591 FadeOut(REDRAW_FIELD);
2593 info_mode = INFO_MODE_MAIN;
2594 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2598 PlayMenuSoundIfLoop();
2602 void DrawInfoScreen_LevelSet()
2605 int ybottom = SYSIZE - 20;
2606 char *filename = getLevelSetInfoFilename();
2608 int font_nr = FONT_INFO_LEVELSET;
2610 int font_nr = FONT_LEVEL_NUMBER;
2612 int font_width = getFontWidth(font_nr);
2613 int font_height = getFontHeight(font_nr);
2616 int sx = SX + pad_x;
2617 int sy = SY + pad_y;
2618 int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
2619 int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
2621 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
2623 FadeOut(REDRAW_FIELD);
2628 DrawTextSCentered(100, FONT_TEXT_1, "Level Set Information:");
2630 DrawTextSCentered(ybottom, FONT_TEXT_4,
2631 "Press any key or button for info menu");
2633 if (filename != NULL)
2634 DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line,
2635 max_lines_per_screen, TRUE);
2637 DrawTextSCentered(ystart, FONT_TEXT_2,
2638 "No information for this level set.");
2640 FadeIn(REDRAW_FIELD);
2643 void HandleInfoScreen_LevelSet(int button)
2645 if (button == MB_MENU_LEAVE)
2647 PlaySound(SND_MENU_ITEM_SELECTING);
2649 info_mode = INFO_MODE_MAIN;
2654 else if (button == MB_MENU_CHOICE)
2656 PlaySound(SND_MENU_ITEM_SELECTING);
2658 FadeSoundsAndMusic();
2659 FadeOut(REDRAW_FIELD);
2661 info_mode = INFO_MODE_MAIN;
2662 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2666 PlayMenuSoundIfLoop();
2670 static void DrawInfoScreenExt(int redraw_mask, boolean do_fading)
2672 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
2674 if (info_mode == INFO_MODE_TITLE)
2675 DrawInfoScreen_TitleScreen();
2676 else if (info_mode == INFO_MODE_ELEMENTS)
2677 DrawInfoScreen_Elements();
2678 else if (info_mode == INFO_MODE_MUSIC)
2679 DrawInfoScreen_Music();
2680 else if (info_mode == INFO_MODE_CREDITS)
2681 DrawInfoScreen_Credits();
2682 else if (info_mode == INFO_MODE_PROGRAM)
2683 DrawInfoScreen_Program();
2684 else if (info_mode == INFO_MODE_VERSION)
2685 DrawInfoScreen_Version();
2686 else if (info_mode == INFO_MODE_LEVELSET)
2687 DrawInfoScreen_LevelSet();
2689 DrawInfoScreen_Main(redraw_mask, do_fading);
2691 if (info_mode != INFO_MODE_MAIN &&
2692 info_mode != INFO_MODE_TITLE &&
2693 info_mode != INFO_MODE_MUSIC)
2700 void DrawAndFadeInInfoScreen(int redraw_mask)
2702 DrawInfoScreenExt(redraw_mask, TRUE);
2705 void DrawInfoScreen()
2707 DrawInfoScreenExt(REDRAW_ALL, FALSE);
2710 void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
2712 if (info_mode == INFO_MODE_TITLE)
2713 HandleInfoScreen_TitleScreen(button);
2714 else if (info_mode == INFO_MODE_ELEMENTS)
2715 HandleInfoScreen_Elements(button);
2716 else if (info_mode == INFO_MODE_MUSIC)
2717 HandleInfoScreen_Music(button);
2718 else if (info_mode == INFO_MODE_CREDITS)
2719 HandleInfoScreen_Credits(button);
2720 else if (info_mode == INFO_MODE_PROGRAM)
2721 HandleInfoScreen_Program(button);
2722 else if (info_mode == INFO_MODE_VERSION)
2723 HandleInfoScreen_Version(button);
2724 else if (info_mode == INFO_MODE_LEVELSET)
2725 HandleInfoScreen_LevelSet(button);
2727 HandleInfoScreen_Main(mx, my, dx, dy, button);
2733 /* ========================================================================= */
2734 /* type name functions */
2735 /* ========================================================================= */
2737 void HandleTypeName(int newxpos, Key key)
2739 struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME);
2741 struct MenuPosInfo *pos = mci->pos_input;
2742 int startx = mSX + ALIGNED_MENU_XPOS(pos);
2743 int starty = mSY + ALIGNED_MENU_YPOS(pos);
2746 static int xpos = 0;
2748 static int xpos = 0, ypos = 2;
2750 int font_nr = mci->font_input;
2751 int font_active_nr = FONT_ACTIVE(font_nr);
2752 int font_width = getFontWidth(font_active_nr);
2755 int startx = mSX + mci->pos_input->x;
2756 int starty = mSY + mci->pos_input->y;
2759 int name_width = getFontWidth(FONT_MENU_1) * strlen("Name:");
2760 int startx = mSX + 32 + name_width;
2761 int starty = mSY + ypos * 32;
2768 DrawText(startx, starty, setup.player_name, font_active_nr);
2769 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
2774 if (((key >= KSYM_A && key <= KSYM_Z) ||
2775 (key >= KSYM_a && key <= KSYM_z)) &&
2776 xpos < MAX_PLAYER_NAME_LEN)
2780 if (key >= KSYM_A && key <= KSYM_Z)
2781 ascii = 'A' + (char)(key - KSYM_A);
2783 ascii = 'a' + (char)(key - KSYM_a);
2785 setup.player_name[xpos] = ascii;
2786 setup.player_name[xpos + 1] = 0;
2790 DrawText(startx, starty, setup.player_name, font_active_nr);
2791 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
2793 else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
2797 setup.player_name[xpos] = 0;
2799 DrawText(startx + xpos * font_width, starty, "_ ", font_active_nr);
2801 else if (key == KSYM_Return && xpos > 0)
2803 DrawText(startx, starty, setup.player_name, font_nr);
2804 DrawText(startx + xpos * font_width, starty, " ", font_active_nr);
2808 game_status = GAME_MODE_MAIN;
2813 /* ========================================================================= */
2814 /* tree menu functions */
2815 /* ========================================================================= */
2817 static void DrawChooseTree(TreeInfo **ti_ptr)
2821 FreeScreenGadgets();
2822 CreateScreenGadgets();
2824 CloseDoor(DOOR_CLOSE_2);
2828 HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
2829 MapScreenTreeGadgets(*ti_ptr);
2835 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
2837 struct GadgetInfo *gi = screen_gadget[id];
2838 int items_max, items_visible, item_position;
2840 items_max = numTreeInfoInGroup(ti);
2841 items_visible = NUM_MENU_ENTRIES_ON_SCREEN;
2842 item_position = first_entry;
2844 if (item_position > items_max - items_visible)
2845 item_position = items_max - items_visible;
2847 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
2848 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
2849 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
2852 static void drawChooseTreeList(int first_entry, int num_page_entries,
2856 char *title_string = NULL;
2857 int yoffset_sets = MENU_TITLE1_YPOS;
2858 int yoffset_setup = 16;
2859 int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? yoffset_sets :
2861 int last_game_status = game_status; /* save current game status */
2863 title_string = ti->infotext;
2865 DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
2867 /* force LEVELS font on artwork setup screen */
2868 game_status = GAME_MODE_LEVELS;
2871 /* clear tree list area, but not title or scrollbar */
2872 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
2873 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
2874 NUM_MENU_ENTRIES_ON_SCREEN * 32);
2876 /* clear tree list area, but not title or scrollbar */
2877 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
2878 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
2879 MAX_MENU_ENTRIES_ON_SCREEN * 32);
2882 for (i = 0; i < num_page_entries; i++)
2884 TreeInfo *node, *node_first;
2885 int entry_pos = first_entry + i;
2886 int xpos = MENU_SCREEN_START_XPOS;
2887 int ypos = MENU_SCREEN_START_YPOS + i;
2888 int startx = mSX + xpos * 32;
2889 int starty = mSY + ypos * 32;
2890 int font_nr = FONT_TEXT_1;
2891 int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
2892 int startx_text = startx + font_xoffset;
2893 int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
2894 int text_size = startx_scrollbar - startx_text;
2895 int max_buffer_len = text_size / getFontWidth(font_nr);
2896 char buffer[max_buffer_len + 1];
2898 node_first = getTreeInfoFirstGroupEntry(ti);
2899 node = getTreeInfoFromPos(node_first, entry_pos);
2901 strncpy(buffer, node->name, max_buffer_len);
2902 buffer[max_buffer_len] = '\0';
2904 DrawText(startx, starty, buffer, font_nr + node->color);
2906 if (node->parent_link)
2907 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
2908 else if (node->level_group)
2909 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
2911 initCursor(i, IMG_MENU_BUTTON);
2914 game_status = last_game_status; /* restore current game status */
2916 redraw_mask |= REDRAW_FIELD;
2919 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
2921 TreeInfo *node, *node_first;
2922 int x, last_redraw_mask = redraw_mask;
2923 int ypos = MENU_TITLE2_YPOS;
2924 int font_nr = FONT_TITLE_2;
2926 if (ti->type != TREE_TYPE_LEVEL_DIR)
2929 node_first = getTreeInfoFirstGroupEntry(ti);
2930 node = getTreeInfoFromPos(node_first, entry_pos);
2932 DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr);
2934 if (node->parent_link)
2935 DrawTextFCentered(ypos, font_nr, "leave group \"%s\"",
2937 else if (node->level_group)
2938 DrawTextFCentered(ypos, font_nr, "enter group \"%s\"",
2940 else if (ti->type == TREE_TYPE_LEVEL_DIR)
2941 DrawTextFCentered(ypos, font_nr, "%3d levels (%s)",
2942 node->levels, node->class_desc);
2944 /* let BackToFront() redraw only what is needed */
2945 redraw_mask = last_redraw_mask | REDRAW_TILES;
2946 for (x = 0; x < SCR_FIELDX; x++)
2947 MarkTileDirty(x, 1);
2950 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
2953 TreeInfo *ti = *ti_ptr;
2955 int y = ti->cl_cursor;
2956 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2957 int num_entries = numTreeInfoInGroup(ti);
2958 int num_page_entries;
2959 int last_game_status = game_status; /* save current game status */
2960 boolean position_set_by_scrollbar = (dx == 999);
2962 /* force LEVELS draw offset on choose level and artwork setup screen */
2963 game_status = GAME_MODE_LEVELS;
2965 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
2966 num_page_entries = num_entries;
2968 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
2970 game_status = last_game_status; /* restore current game status */
2972 if (button == MB_MENU_INITIALIZE)
2974 int num_entries = numTreeInfoInGroup(ti);
2975 int entry_pos = posTreeInfo(ti);
2977 if (ti->cl_first == -1)
2979 /* only on initialization */
2980 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
2981 ti->cl_cursor = entry_pos - ti->cl_first;
2983 else if (ti->cl_cursor >= num_page_entries ||
2984 (num_entries > num_page_entries &&
2985 num_entries - ti->cl_first < num_page_entries))
2987 /* only after change of list size (by custom graphic configuration) */
2988 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
2989 ti->cl_cursor = entry_pos - ti->cl_first;
2992 if (position_set_by_scrollbar)
2995 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
2998 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
2999 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3000 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3004 else if (button == MB_MENU_LEAVE)
3006 PlaySound(SND_MENU_ITEM_SELECTING);
3008 if (ti->node_parent)
3010 *ti_ptr = ti->node_parent;
3011 DrawChooseTree(ti_ptr);
3013 else if (game_status == GAME_MODE_SETUP)
3015 if (game_status == GAME_MODE_SETUP)
3017 if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
3018 execSetupGraphics();
3025 game_status = GAME_MODE_MAIN;
3032 if (mx || my) /* mouse input */
3034 int last_game_status = game_status; /* save current game status */
3036 /* force LEVELS draw offset on artwork setup screen */
3037 game_status = GAME_MODE_LEVELS;
3039 x = (mx - mSX) / 32;
3040 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
3042 game_status = last_game_status; /* restore current game status */
3044 else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */
3046 /* move cursor instead of scrolling when already at start/end of list */
3047 if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
3049 else if (dy == +1 * SCROLL_LINE &&
3050 ti->cl_first + num_page_entries == num_entries)
3053 /* handle scrolling screen one line or page */
3054 if (ti->cl_cursor + dy < 0 ||
3055 ti->cl_cursor + dy > num_page_entries - 1)
3057 if (ABS(dy) == SCROLL_PAGE)
3058 step = num_page_entries - 1;
3060 if (dy < 0 && ti->cl_first > 0)
3062 /* scroll page/line up */
3064 ti->cl_first -= step;
3065 if (ti->cl_first < 0)
3068 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3069 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3070 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3072 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3075 else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
3077 /* scroll page/line down */
3079 ti->cl_first += step;
3080 if (ti->cl_first + num_page_entries > num_entries)
3081 ti->cl_first = MAX(0, num_entries - num_page_entries);
3083 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3084 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3085 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3087 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3094 /* handle moving cursor one line */
3095 y = ti->cl_cursor + dy;
3100 TreeInfo *node_first, *node_cursor;
3101 int entry_pos = ti->cl_first + y;
3103 node_first = getTreeInfoFirstGroupEntry(ti);
3104 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3106 if (node_cursor->node_group)
3108 PlaySound(SND_MENU_ITEM_SELECTING);
3110 node_cursor->cl_first = ti->cl_first;
3111 node_cursor->cl_cursor = ti->cl_cursor;
3112 *ti_ptr = node_cursor->node_group;
3113 DrawChooseTree(ti_ptr);
3118 else if (dx == -1 && ti->node_parent)
3120 PlaySound(SND_MENU_ITEM_SELECTING);
3122 *ti_ptr = ti->node_parent;
3123 DrawChooseTree(ti_ptr);
3128 if (!anyScrollbarGadgetActive() &&
3129 IN_VIS_FIELD(x, y) &&
3130 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
3131 y >= 0 && y < num_page_entries)
3135 if (y != ti->cl_cursor)
3137 PlaySound(SND_MENU_ITEM_ACTIVATING);
3139 drawChooseTreeCursor(ti->cl_cursor, FALSE);
3140 drawChooseTreeCursor(y, TRUE);
3141 drawChooseTreeInfo(ti->cl_first + y, ti);
3148 TreeInfo *node_first, *node_cursor;
3149 int entry_pos = ti->cl_first + y;
3151 PlaySound(SND_MENU_ITEM_SELECTING);
3153 node_first = getTreeInfoFirstGroupEntry(ti);
3154 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3156 if (node_cursor->node_group)
3158 node_cursor->cl_first = ti->cl_first;
3159 node_cursor->cl_cursor = ti->cl_cursor;
3160 *ti_ptr = node_cursor->node_group;
3161 DrawChooseTree(ti_ptr);
3163 else if (node_cursor->parent_link)
3165 *ti_ptr = node_cursor->node_parent;
3166 DrawChooseTree(ti_ptr);
3170 node_cursor->cl_first = ti->cl_first;
3171 node_cursor->cl_cursor = ti->cl_cursor;
3172 *ti_ptr = node_cursor;
3174 if (ti->type == TREE_TYPE_LEVEL_DIR)
3176 LoadLevelSetup_SeriesInfo();
3178 SaveLevelSetup_LastSeries();
3179 SaveLevelSetup_SeriesInfo();
3183 if (game_status == GAME_MODE_SETUP)
3185 if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
3186 execSetupGraphics();
3192 game_status = GAME_MODE_MAIN;
3200 void DrawChooseLevel()
3202 SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
3204 DrawChooseTree(&leveldir_current);
3210 void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
3212 HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
3217 void DrawHallOfFame(int highlight_position)
3220 FadeSoundsAndMusic();
3222 /* (this is needed when called from GameEnd() after winning a game) */
3223 KeyboardAutoRepeatOn();
3226 /* (this is needed when called from GameEnd() after winning a game) */
3227 SetDrawDeactivationMask(REDRAW_NONE);
3228 SetDrawBackgroundMask(REDRAW_FIELD);
3230 CloseDoor(DOOR_CLOSE_2);
3232 if (highlight_position < 0)
3233 LoadScore(level_nr);
3235 FadeOut(REDRAW_FIELD);
3242 HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
3244 FadeIn(REDRAW_FIELD);
3247 static void drawHallOfFameList(int first_entry, int highlight_position)
3251 SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
3254 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
3255 DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
3256 "HighScores of Level %d", level_nr);
3258 for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
3260 int entry = first_entry + i;
3261 boolean active = (entry == highlight_position);
3262 int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
3263 int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
3264 int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
3265 int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
3266 int dx1 = 3 * getFontWidth(font_nr1);
3267 int dx2 = dx1 + getFontWidth(font_nr1);
3268 int dx3 = dx2 + 25 * getFontWidth(font_nr3);
3269 int sy = mSY + 64 + i * 32;
3271 DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
3272 DrawText(mSX + dx1, sy, ".", font_nr1);
3273 DrawText(mSX + dx2, sy, ".........................", font_nr3);
3275 if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
3276 DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
3278 DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
3281 redraw_mask |= REDRAW_FIELD;
3284 void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
3286 static int first_entry = 0;
3287 static int highlight_position = 0;
3288 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3290 if (button == MB_MENU_INITIALIZE)
3293 highlight_position = mx;
3294 drawHallOfFameList(first_entry, highlight_position);
3299 if (ABS(dy) == SCROLL_PAGE) /* handle scrolling one page */
3300 step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
3304 if (first_entry > 0)
3306 first_entry -= step;
3307 if (first_entry < 0)
3310 drawHallOfFameList(first_entry, highlight_position);
3315 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
3317 first_entry += step;
3318 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
3319 first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
3321 drawHallOfFameList(first_entry, highlight_position);
3324 else if (button == MB_MENU_LEAVE)
3326 PlaySound(SND_MENU_ITEM_SELECTING);
3328 FadeSound(SND_BACKGROUND_SCORES);
3330 game_status = GAME_MODE_MAIN;
3334 else if (button == MB_MENU_CHOICE)
3336 PlaySound(SND_MENU_ITEM_SELECTING);
3338 FadeSound(SND_BACKGROUND_SCORES);
3339 FadeOut(REDRAW_FIELD);
3341 game_status = GAME_MODE_MAIN;
3343 DrawAndFadeInMainMenu(REDRAW_FIELD);
3346 if (game_status == GAME_MODE_SCORES)
3347 PlayMenuSoundIfLoop();
3353 /* ========================================================================= */
3354 /* setup screen functions */
3355 /* ========================================================================= */
3357 static struct TokenInfo *setup_info;
3358 static int num_setup_info;
3360 static char *screen_mode_text;
3361 static char *graphics_set_name;
3362 static char *sounds_set_name;
3363 static char *music_set_name;
3365 static void execSetupMain()
3367 setup_mode = SETUP_MODE_MAIN;
3371 static void execSetupGame()
3373 setup_mode = SETUP_MODE_GAME;
3377 static void execSetupEditor()
3379 setup_mode = SETUP_MODE_EDITOR;
3383 static void execSetupGraphics()
3385 if (video.fullscreen_available && screen_modes == NULL)
3389 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
3391 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
3392 char identifier[32], name[32];
3393 int x = video.fullscreen_modes[i].width;
3394 int y = video.fullscreen_modes[i].height;
3397 get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy);
3399 ti->node_top = &screen_modes;
3400 ti->sort_priority = x * 10000 + y;
3402 sprintf(identifier, "%dx%d", x, y);
3403 sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy);
3405 setString(&ti->identifier, identifier);
3406 setString(&ti->name, name);
3407 setString(&ti->name_sorting, name);
3408 setString(&ti->infotext, "Fullscreen Mode");
3410 pushTreeInfo(&screen_modes, ti);
3413 /* sort fullscreen modes to start with lowest available screen resolution */
3414 sortTreeInfo(&screen_modes);
3416 /* set current screen mode for fullscreen mode to configured setup value */
3417 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3418 setup.fullscreen_mode);
3420 /* if that fails, set current screen mode to reliable default value */
3421 if (screen_mode_current == NULL)
3422 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3423 DEFAULT_FULLSCREEN_MODE);
3425 /* if that also fails, set current screen mode to first available mode */
3426 if (screen_mode_current == NULL)
3427 screen_mode_current = screen_modes;
3429 if (screen_mode_current == NULL)
3430 video.fullscreen_available = FALSE;
3433 if (video.fullscreen_available)
3435 setup.fullscreen_mode = screen_mode_current->identifier;
3437 /* needed for displaying screen mode name instead of identifier */
3438 screen_mode_text = screen_mode_current->name;
3441 setup_mode = SETUP_MODE_GRAPHICS;
3445 static void execSetupChooseScreenMode()
3447 if (!video.fullscreen_available)
3450 setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE;
3454 static void execSetupSound()
3456 setup_mode = SETUP_MODE_SOUND;
3460 static void execSetupArtwork()
3462 setup.graphics_set = artwork.gfx_current->identifier;
3463 setup.sounds_set = artwork.snd_current->identifier;
3464 setup.music_set = artwork.mus_current->identifier;
3466 /* needed if last screen (setup choice) changed graphics, sounds or music */
3467 ReloadCustomArtwork(0);
3469 /* needed for displaying artwork name instead of artwork identifier */
3470 graphics_set_name = artwork.gfx_current->name;
3471 sounds_set_name = artwork.snd_current->name;
3472 music_set_name = artwork.mus_current->name;
3474 setup_mode = SETUP_MODE_ARTWORK;
3478 static void execSetupChooseGraphics()
3480 setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
3484 static void execSetupChooseSounds()
3486 setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
3490 static void execSetupChooseMusic()
3492 setup_mode = SETUP_MODE_CHOOSE_MUSIC;
3496 static void execSetupInput()
3498 setup_mode = SETUP_MODE_INPUT;
3502 static void execSetupShortcut1()
3504 setup_mode = SETUP_MODE_SHORTCUT_1;
3508 static void execSetupShortcut2()
3510 setup_mode = SETUP_MODE_SHORTCUT_2;
3514 static void execExitSetup()
3516 game_status = GAME_MODE_MAIN;
3520 static void execSaveAndExitSetup()
3526 static struct TokenInfo setup_info_main[] =
3528 { TYPE_ENTER_MENU, execSetupGame, "Game & Menu" },
3529 { TYPE_ENTER_MENU, execSetupEditor, "Editor" },
3530 { TYPE_ENTER_MENU, execSetupGraphics, "Graphics" },
3531 { TYPE_ENTER_MENU, execSetupSound, "Sound & Music" },
3532 { TYPE_ENTER_MENU, execSetupArtwork, "Custom Artwork" },
3533 { TYPE_ENTER_MENU, execSetupInput, "Input Devices" },
3534 { TYPE_ENTER_MENU, execSetupShortcut1, "Key Shortcuts 1" },
3535 { TYPE_ENTER_MENU, execSetupShortcut2, "Key Shortcuts 2" },
3536 { TYPE_EMPTY, NULL, "" },
3537 { TYPE_LEAVE_MENU, execExitSetup, "Exit" },
3538 { TYPE_LEAVE_MENU, execSaveAndExitSetup, "Save and Exit" },
3543 static struct TokenInfo setup_info_game[] =
3545 { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" },
3546 { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" },
3547 { TYPE_SWITCH, &setup.handicap, "Handicap:" },
3548 { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" },
3549 { TYPE_SWITCH, &setup.time_limit, "Time Limit:" },
3550 { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" },
3551 { TYPE_EMPTY, NULL, "" },
3552 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3557 static struct TokenInfo setup_info_editor[] =
3560 { TYPE_SWITCH, &setup.editor.el_boulderdash, "Boulder Dash:" },
3561 { TYPE_SWITCH, &setup.editor.el_emerald_mine, "Emerald Mine:" },
3562 { TYPE_SWITCH, &setup.editor.el_emerald_mine_club, "Emerald Mine Club:" },
3563 { TYPE_SWITCH, &setup.editor.el_more, "Rocks'n'Diamonds:" },
3564 { TYPE_SWITCH, &setup.editor.el_sokoban, "Sokoban:" },
3565 { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" },
3566 { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" },
3567 { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
3569 { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" },
3570 { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" },
3571 { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" },
3573 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" },
3575 { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
3576 { TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" },
3577 { TYPE_EMPTY, NULL, "" },
3579 { TYPE_SWITCH, &setup.editor.el_by_game, "Show elements by game:" },
3580 { TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" },
3581 { TYPE_EMPTY, NULL, "" },
3583 { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" },
3584 { TYPE_EMPTY, NULL, "" },
3585 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3590 static struct TokenInfo setup_info_graphics[] =
3592 { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" },
3593 { TYPE_ENTER_LIST, execSetupChooseScreenMode, "Fullscreen Mode:" },
3594 { TYPE_STRING, &screen_mode_text, "" },
3595 { TYPE_SWITCH, &setup.scroll_delay, "Delayed Scrolling:" },
3597 { TYPE_SWITCH, &setup.soft_scrolling, "Soft Scrolling:" },
3598 { TYPE_SWITCH, &setup.double_buffering,"Double-Buffering:" },
3600 { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" },
3601 { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" },
3602 { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" },
3603 { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" },
3604 { TYPE_SWITCH, &setup.toons, "Show Toons:" },
3605 { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" },
3606 { TYPE_EMPTY, NULL, "" },
3607 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3612 static struct TokenInfo setup_info_sound[] =
3614 { TYPE_SWITCH, &setup.sound_simple, "Sound Effects (Normal):" },
3615 { TYPE_SWITCH, &setup.sound_loops, "Sound Effects (Looping):" },
3616 { TYPE_SWITCH, &setup.sound_music, "Music:" },
3617 { TYPE_EMPTY, NULL, "" },
3618 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3623 static struct TokenInfo setup_info_artwork[] =
3625 { TYPE_ENTER_LIST, execSetupChooseGraphics,"Custom Graphics:" },
3626 { TYPE_STRING, &graphics_set_name, "" },
3627 { TYPE_ENTER_LIST, execSetupChooseSounds, "Custom Sounds:" },
3628 { TYPE_STRING, &sounds_set_name, "" },
3629 { TYPE_ENTER_LIST, execSetupChooseMusic, "Custom Music:" },
3630 { TYPE_STRING, &music_set_name, "" },
3631 { TYPE_EMPTY, NULL, "" },
3633 { TYPE_YES_NO, &setup.override_level_graphics,"Override Level Graphics:" },
3634 { TYPE_YES_NO, &setup.override_level_sounds, "Override Level Sounds:" },
3635 { TYPE_YES_NO, &setup.override_level_music, "Override Level Music:" },
3637 { TYPE_STRING, NULL, "Override Level Artwork:"},
3638 { TYPE_YES_NO, &setup.override_level_graphics, "Graphics:" },
3639 { TYPE_YES_NO, &setup.override_level_sounds, "Sounds:" },
3640 { TYPE_YES_NO, &setup.override_level_music, "Music:" },
3642 { TYPE_EMPTY, NULL, "" },
3643 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3648 static struct TokenInfo setup_info_input[] =
3650 { TYPE_SWITCH, NULL, "Player:" },
3651 { TYPE_SWITCH, NULL, "Device:" },
3652 { TYPE_ENTER_MENU, NULL, "" },
3653 { TYPE_EMPTY, NULL, "" },
3654 { TYPE_EMPTY, NULL, "" },
3655 { TYPE_EMPTY, NULL, "" },
3656 { TYPE_EMPTY, NULL, "" },
3657 { TYPE_EMPTY, NULL, "" },
3658 { TYPE_EMPTY, NULL, "" },
3659 { TYPE_EMPTY, NULL, "" },
3660 { TYPE_EMPTY, NULL, "" },
3661 { TYPE_EMPTY, NULL, "" },
3662 { TYPE_EMPTY, NULL, "" },
3663 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3668 static struct TokenInfo setup_info_shortcut_1[] =
3670 { TYPE_KEYTEXT, NULL, "Quick Save Game to Tape:", },
3671 { TYPE_KEY, &setup.shortcut.save_game, "" },
3672 { TYPE_KEYTEXT, NULL, "Quick Load Game from Tape:", },
3673 { TYPE_KEY, &setup.shortcut.load_game, "" },
3674 { TYPE_KEYTEXT, NULL, "Start Game & Toggle Pause:", },
3675 { TYPE_KEY, &setup.shortcut.toggle_pause, "" },
3676 { TYPE_EMPTY, NULL, "" },
3677 { TYPE_YES_NO, &setup.ask_on_escape, "Ask on 'Esc' Key:" },
3678 { TYPE_YES_NO, &setup.ask_on_escape_editor, "Ask on 'Esc' Key (Editor):" },
3679 { TYPE_EMPTY, NULL, "" },
3680 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3685 static struct TokenInfo setup_info_shortcut_2[] =
3687 { TYPE_KEYTEXT, NULL, "Set Focus to Player 1:", },
3688 { TYPE_KEY, &setup.shortcut.focus_player[0], "" },
3689 { TYPE_KEYTEXT, NULL, "Set Focus to Player 2:", },
3690 { TYPE_KEY, &setup.shortcut.focus_player[1], "" },
3691 { TYPE_KEYTEXT, NULL, "Set Focus to Player 3:", },
3692 { TYPE_KEY, &setup.shortcut.focus_player[2], "" },
3693 { TYPE_KEYTEXT, NULL, "Set Focus to Player 4:", },
3694 { TYPE_KEY, &setup.shortcut.focus_player[3], "" },
3695 { TYPE_KEYTEXT, NULL, "Set Focus to All Players:", },
3696 { TYPE_KEY, &setup.shortcut.focus_player_all, "" },
3697 { TYPE_EMPTY, NULL, "" },
3698 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3703 static Key getSetupKey()
3705 Key key = KSYM_UNDEFINED;
3706 boolean got_key_event = FALSE;
3708 while (!got_key_event)
3710 if (PendingEvent()) /* got event */
3718 case EVENT_KEYPRESS:
3720 key = GetEventKey((KeyEvent *)&event, TRUE);
3722 /* press 'Escape' or 'Enter' to keep the existing key binding */
3723 if (key == KSYM_Escape || key == KSYM_Return)
3724 key = KSYM_UNDEFINED; /* keep old value */
3726 got_key_event = TRUE;
3730 case EVENT_KEYRELEASE:
3731 key_joystick_mapping = 0;
3735 HandleOtherEvents(&event);
3743 /* don't eat all CPU time */
3750 static int getSetupTextFont(int type)
3752 if (type & (TYPE_SWITCH |
3763 static int getSetupValueFont(int type, void *value)
3765 if (type & TYPE_KEY)
3766 return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1);
3767 else if (type & TYPE_STRING)
3768 return FONT_VALUE_2;
3769 else if (type & TYPE_ECS_AGA)
3770 return FONT_VALUE_1;
3771 else if (type & TYPE_BOOLEAN_STYLE)
3772 return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
3774 return FONT_VALUE_1;
3777 static void drawSetupValue(int pos)
3779 boolean font_draw_xoffset_modified = FALSE;
3780 int font_draw_xoffset_old = -1;
3781 int xpos = MENU_SCREEN_VALUE_XPOS;
3782 int ypos = MENU_SCREEN_START_YPOS + pos;
3783 int startx = mSX + xpos * 32;
3784 int starty = mSY + ypos * 32;
3785 int font_nr, font_width;
3786 int type = setup_info[pos].type;
3787 void *value = setup_info[pos].value;
3788 char *value_string = getSetupValue(type, value);
3791 if (value_string == NULL)
3794 if (type & TYPE_KEY)
3796 xpos = MENU_SCREEN_START_XPOS;
3798 if (type & TYPE_QUERY)
3800 value_string = "<press key>";
3803 else if (type & TYPE_STRING)
3805 int max_value_len = (SCR_FIELDX - 2) * 2;
3807 xpos = MENU_SCREEN_START_XPOS;
3809 if (strlen(value_string) > max_value_len)
3810 value_string[max_value_len] = '\0';
3813 startx = mSX + xpos * 32;
3814 starty = mSY + ypos * 32;
3815 font_nr = getSetupValueFont(type, value);
3816 font_width = getFontWidth(font_nr);
3818 /* downward compatibility correction for Juergen Bonhagen's menu settings */
3819 if (setup_mode != SETUP_MODE_INPUT)
3821 int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
3822 int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
3823 int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
3824 int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
3825 int text_font_nr = getSetupTextFont(FONT_MENU_2);
3826 int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
3827 int text_width = MAX_MENU_TEXT_LENGTH_MEDIUM * getFontWidth(text_font_nr);
3828 boolean correct_font_draw_xoffset = FALSE;
3830 if (xpos == MENU_SCREEN_START_XPOS &&
3831 startx + font1_xoffset < text_startx + text_font_xoffset)
3832 correct_font_draw_xoffset = TRUE;
3834 if (xpos == MENU_SCREEN_VALUE_XPOS &&
3835 startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
3836 correct_font_draw_xoffset = TRUE;
3838 /* check if setup value would overlap with setup text when printed */
3839 /* (this can happen for extreme/wrong values for font draw offset) */
3840 if (correct_font_draw_xoffset)
3842 font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
3843 font_draw_xoffset_modified = TRUE;
3845 if (type & TYPE_KEY)
3846 getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
3847 else if (!(type & TYPE_STRING))
3848 getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
3849 MAX_MENU_TEXT_LENGTH_MEDIUM * (16 - getFontWidth(text_font_nr));
3853 for (i = 0; i <= MENU_SCREEN_MAX_XPOS - xpos; i++)
3854 DrawText(startx + i * font_width, starty, " ", font_nr);
3856 DrawText(startx, starty, value_string, font_nr);
3858 if (font_draw_xoffset_modified)
3859 getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
3862 static void changeSetupValue(int pos)
3864 if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
3866 *(boolean *)setup_info[pos].value ^= TRUE;
3868 else if (setup_info[pos].type & TYPE_KEY)
3872 setup_info[pos].type |= TYPE_QUERY;
3873 drawSetupValue(pos);
3874 setup_info[pos].type &= ~TYPE_QUERY;
3876 key = getSetupKey();
3877 if (key != KSYM_UNDEFINED)
3878 *(Key *)setup_info[pos].value = key;
3881 drawSetupValue(pos);
3884 static void DrawCursorAndText_Setup(int pos, boolean active)
3886 int xpos = MENU_SCREEN_START_XPOS;
3887 int ypos = MENU_SCREEN_START_YPOS + pos;
3888 int font_nr = getSetupTextFont(setup_info[pos].type);
3890 if (setup_info == setup_info_input)
3891 font_nr = FONT_MENU_1;
3894 font_nr = FONT_ACTIVE(font_nr);
3896 DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[pos].text, font_nr);
3898 if (setup_info[pos].type & ~TYPE_SKIP_ENTRY)
3899 drawCursor(pos, active);
3902 static void DrawSetupScreen_Generic()
3904 char *title_string = NULL;
3908 CloseDoor(DOOR_CLOSE_2);
3912 if (setup_mode == SETUP_MODE_MAIN)
3914 setup_info = setup_info_main;
3915 title_string = "Setup";
3917 else if (setup_mode == SETUP_MODE_GAME)
3919 setup_info = setup_info_game;
3920 title_string = "Setup Game";
3922 else if (setup_mode == SETUP_MODE_EDITOR)
3924 setup_info = setup_info_editor;
3925 title_string = "Setup Editor";
3927 else if (setup_mode == SETUP_MODE_GRAPHICS)
3929 setup_info = setup_info_graphics;
3930 title_string = "Setup Graphics";
3932 else if (setup_mode == SETUP_MODE_SOUND)
3934 setup_info = setup_info_sound;
3935 title_string = "Setup Sound";
3937 else if (setup_mode == SETUP_MODE_ARTWORK)
3939 setup_info = setup_info_artwork;
3940 title_string = "Custom Artwork";
3942 else if (setup_mode == SETUP_MODE_SHORTCUT_1)
3944 setup_info = setup_info_shortcut_1;
3945 title_string = "Setup Shortcuts";
3947 else if (setup_mode == SETUP_MODE_SHORTCUT_2)
3949 setup_info = setup_info_shortcut_2;
3950 title_string = "Setup Shortcuts";
3953 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
3956 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
3958 void *value_ptr = setup_info[i].value;
3961 int xpos = MENU_SCREEN_START_XPOS;
3962 int ypos = MENU_SCREEN_START_YPOS + i;
3966 /* set some entries to "unchangeable" according to other variables */
3967 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
3968 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
3969 (value_ptr == &setup.sound_music && !audio.music_available) ||
3970 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
3971 (value_ptr == &screen_mode_text && !video.fullscreen_available))
3972 setup_info[i].type |= TYPE_GHOSTED;
3974 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
3975 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
3976 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
3977 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
3978 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
3979 initCursor(i, IMG_MENU_BUTTON);
3982 DrawCursorAndText_Setup(i, FALSE);
3984 font_nr = getSetupTextFont(setup_info[i].type);
3986 DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[i].text, font_nr);
3989 if (setup_info[i].type & TYPE_VALUE)
3996 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
3997 "Joysticks deactivated in setup menu");
4002 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
4005 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
4007 static int choice_store[MAX_SETUP_MODES];
4008 int choice = choice_store[setup_mode]; /* always starts with 0 */
4012 if (button == MB_MENU_INITIALIZE)
4014 /* advance to first valid menu entry */
4015 while (choice < num_setup_info &&
4016 setup_info[choice].type & TYPE_SKIP_ENTRY)
4018 choice_store[setup_mode] = choice;
4021 DrawCursorAndText_Setup(choice, TRUE);
4023 drawCursor(choice, TRUE);
4028 else if (button == MB_MENU_LEAVE)
4030 PlaySound(SND_MENU_ITEM_SELECTING);
4032 for (y = 0; y < num_setup_info; y++)
4034 if (setup_info[y].type & TYPE_LEAVE_MENU)
4036 void (*menu_callback_function)(void) = setup_info[y].value;
4038 menu_callback_function();
4040 break; /* absolutely needed because function changes 'setup_info'! */
4047 if (mx || my) /* mouse input */
4049 x = (mx - mSX) / 32;
4050 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
4052 else if (dx || dy) /* keyboard input */
4056 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
4058 if (setup_info[choice].type & menu_navigation_type ||
4059 setup_info[choice].type & TYPE_BOOLEAN_STYLE)
4060 button = MB_MENU_CHOICE;
4065 /* jump to next non-empty menu entry (up or down) */
4066 while (y > 0 && y < num_setup_info - 1 &&
4067 setup_info[y].type & TYPE_SKIP_ENTRY)
4071 if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_setup_info)
4075 if (y != choice && setup_info[y].type & ~TYPE_SKIP_ENTRY)
4077 PlaySound(SND_MENU_ITEM_ACTIVATING);
4080 DrawCursorAndText_Setup(choice, FALSE);
4081 DrawCursorAndText_Setup(y, TRUE);
4083 drawCursor(choice, FALSE);
4084 drawCursor(y, TRUE);
4087 choice = choice_store[setup_mode] = y;
4090 else if (!(setup_info[y].type & TYPE_GHOSTED))
4092 PlaySound(SND_MENU_ITEM_SELECTING);
4094 /* when selecting key headline, execute function for key value change */
4095 if (setup_info[y].type & TYPE_KEYTEXT &&
4096 setup_info[y + 1].type & TYPE_KEY)
4099 /* when selecting string value, execute function for list selection */
4100 if (setup_info[y].type & TYPE_STRING && y > 0 &&
4101 setup_info[y - 1].type & TYPE_ENTER_LIST)
4104 if (setup_info[y].type & TYPE_ENTER_OR_LEAVE)
4106 void (*menu_callback_function)(void) = setup_info[y].value;
4108 menu_callback_function();
4112 if (setup_info[y].type & TYPE_VALUE)
4113 changeSetupValue(y);
4119 void DrawSetupScreen_Input()
4128 setup_info = setup_info_input;
4131 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input");
4134 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
4136 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
4137 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
4138 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
4139 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
4140 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
4141 initCursor(i, IMG_MENU_BUTTON);
4143 DrawCursorAndText_Setup(i, FALSE);
4146 initCursor(0, IMG_MENU_BUTTON);
4147 initCursor(1, IMG_MENU_BUTTON);
4148 initCursor(2, IMG_MENU_BUTTON_ENTER_MENU);
4149 initCursor(13, IMG_MENU_BUTTON_LEAVE_MENU);
4151 DrawText(mSX + 32, mSY + 2 * 32, "Player:", FONT_MENU_1);
4152 DrawText(mSX + 32, mSY + 3 * 32, "Device:", FONT_MENU_1);
4153 DrawText(mSX + 32, mSY + 15 * 32, "Back", FONT_MENU_1);
4157 DeactivateJoystickForCalibration();
4160 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
4161 "Joysticks deactivated on this screen");
4164 /* create gadgets for setup input menu screen */
4165 FreeScreenGadgets();
4166 CreateScreenGadgets();
4168 /* map gadgets for setup input menu screen */
4169 MapScreenMenuGadgets(SCREEN_MASK_INPUT);
4171 HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE);
4176 static void setJoystickDeviceToNr(char *device_name, int device_nr)
4178 if (device_name == NULL)
4181 if (device_nr < 0 || device_nr >= MAX_PLAYERS)
4184 if (strlen(device_name) > 1)
4186 char c1 = device_name[strlen(device_name) - 1];
4187 char c2 = device_name[strlen(device_name) - 2];
4189 if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9'))
4190 device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
4193 strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
4194 strlen(device_name));
4197 static void drawPlayerSetupInputInfo(int player_nr, boolean active)
4200 static struct SetupKeyboardInfo custom_key;
4207 { &custom_key.left, "Joystick Left" },
4208 { &custom_key.right, "Joystick Right" },
4209 { &custom_key.up, "Joystick Up" },
4210 { &custom_key.down, "Joystick Down" },
4211 { &custom_key.snap, "Button 1" },
4212 { &custom_key.drop, "Button 2" }
4214 static char *joystick_name[MAX_PLAYERS] =
4221 int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1);
4225 custom_key = setup.input[player_nr].key;
4227 DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
4228 FONT_INPUT_1_ACTIVE);
4230 ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
4232 DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
4233 PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
4235 if (setup.input[player_nr].use_joystick)
4237 char *device_name = setup.input[player_nr].joy.device_name;
4238 char *text = joystick_name[getJoystickNrFromDeviceName(device_name)];
4239 int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1);
4241 DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
4242 DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr);
4246 DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1);
4247 DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr);
4250 DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1);
4252 drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
4253 drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
4254 drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
4255 drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
4257 DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD);
4258 DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD);
4259 DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD);
4260 DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD);
4261 DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD);
4262 DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD);
4264 for (i = 0; i < 6; i++)
4266 int ypos = 6 + i + (i > 3 ? i-3 : 0);
4268 DrawText(mSX + 3 * 32, mSY + ypos * 32,
4270 DrawText(mSX + 3 * 32, mSY + ypos * 32,
4271 (setup.input[player_nr].use_joystick ?
4273 getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
4277 static int input_player_nr = 0;
4279 void HandleSetupScreen_Input_Player(int step, int direction)
4281 int old_player_nr = input_player_nr;
4284 new_player_nr = old_player_nr + step * direction;
4285 if (new_player_nr < 0)
4287 if (new_player_nr > MAX_PLAYERS - 1)
4288 new_player_nr = MAX_PLAYERS - 1;
4290 if (new_player_nr != old_player_nr)
4292 input_player_nr = new_player_nr;
4294 drawPlayerSetupInputInfo(input_player_nr, FALSE);
4298 void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
4300 static int choice = 0;
4303 int pos_start = SETUPINPUT_SCREEN_POS_START;
4304 int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1;
4305 int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2;
4306 int pos_end = SETUPINPUT_SCREEN_POS_END;
4308 if (button == MB_MENU_INITIALIZE)
4310 drawPlayerSetupInputInfo(input_player_nr, (choice == 2));
4313 DrawCursorAndText_Setup(choice, TRUE);
4315 drawCursor(choice, TRUE);
4320 else if (button == MB_MENU_LEAVE)
4322 setup_mode = SETUP_MODE_MAIN;
4329 if (mx || my) /* mouse input */
4331 x = (mx - mSX) / 32;
4332 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
4334 else if (dx || dy) /* keyboard input */
4336 if (dx && choice == 0)
4337 x = (dx < 0 ? 10 : 12);
4338 else if ((dx && choice == 1) ||
4339 (dx == +1 && choice == 2) ||
4340 (dx == -1 && choice == pos_end))
4341 button = MB_MENU_CHOICE;
4345 if (y >= pos_empty1 && y <= pos_empty2)
4346 y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
4349 if (y == 0 && dx != 0 && button)
4351 HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1);
4353 else if (IN_VIS_FIELD(x, y) &&
4354 y >= pos_start && y <= pos_end &&
4355 !(y >= pos_empty1 && y <= pos_empty2))
4362 DrawCursorAndText_Setup(choice, FALSE);
4363 DrawCursorAndText_Setup(y, TRUE);
4365 drawPlayerSetupInputInfo(input_player_nr, (y == 2));
4367 drawCursor(choice, FALSE);
4368 drawCursor(y, TRUE);
4378 char *device_name = setup.input[input_player_nr].joy.device_name;
4380 if (!setup.input[input_player_nr].use_joystick)
4382 int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1);
4384 setJoystickDeviceToNr(device_name, new_device_nr);
4385 setup.input[input_player_nr].use_joystick = TRUE;
4389 int device_nr = getJoystickNrFromDeviceName(device_name);
4390 int new_device_nr = device_nr + (dx >= 0 ? +1 : -1);
4392 if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS)
4393 setup.input[input_player_nr].use_joystick = FALSE;
4395 setJoystickDeviceToNr(device_name, new_device_nr);
4398 drawPlayerSetupInputInfo(input_player_nr, FALSE);
4402 if (setup.input[input_player_nr].use_joystick)
4405 CalibrateJoystick(input_player_nr);
4408 CustomizeKeyboard(input_player_nr);
4410 else if (y == pos_end)
4414 setup_mode = SETUP_MODE_MAIN;
4421 void CustomizeKeyboard(int player_nr)
4425 boolean finished = FALSE;
4426 static struct SetupKeyboardInfo custom_key;
4431 } customize_step[] =
4433 { &custom_key.left, "Move Left" },
4434 { &custom_key.right, "Move Right" },
4435 { &custom_key.up, "Move Up" },
4436 { &custom_key.down, "Move Down" },
4437 { &custom_key.snap, "Snap Field" },
4438 { &custom_key.drop, "Drop Element" }
4441 /* read existing key bindings from player setup */
4442 custom_key = setup.input[player_nr].key;
4446 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input");
4452 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
4453 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
4454 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
4455 "Key:", FONT_INPUT_1_ACTIVE);
4456 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4457 getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
4461 if (PendingEvent()) /* got event */
4469 case EVENT_KEYPRESS:
4471 Key key = GetEventKey((KeyEvent *)&event, FALSE);
4473 if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
4479 /* all keys configured -- wait for "Escape" or "Return" key */
4483 /* press 'Enter' to keep the existing key binding */
4484 if (key == KSYM_Return)
4485 key = *customize_step[step_nr].key;
4487 /* check if key already used */
4488 for (i = 0; i < step_nr; i++)
4489 if (*customize_step[i].key == key)
4494 /* got new key binding */
4495 *customize_step[step_nr].key = key;
4496 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4498 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4499 getKeyNameFromKey(key), FONT_VALUE_1);
4502 /* un-highlight last query */
4503 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32,
4504 customize_step[step_nr - 1].text, FONT_MENU_1);
4505 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32,
4506 "Key:", FONT_MENU_1);
4508 /* press 'Enter' to leave */
4511 DrawText(mSX + 16, mSY + 15 * 32 + 16,
4512 "Press Enter", FONT_TITLE_1);
4516 /* query next key binding */
4517 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
4518 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
4519 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
4520 "Key:", FONT_INPUT_1_ACTIVE);
4521 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4522 getKeyNameFromKey(*customize_step[step_nr].key),
4527 case EVENT_KEYRELEASE:
4528 key_joystick_mapping = 0;
4532 HandleOtherEvents(&event);
4540 /* don't eat all CPU time */
4544 /* write new key bindings back to player setup */
4545 setup.input[player_nr].key = custom_key;
4548 DrawSetupScreen_Input();
4551 static boolean CalibrateJoystickMain(int player_nr)
4553 int new_joystick_xleft = JOYSTICK_XMIDDLE;
4554 int new_joystick_xright = JOYSTICK_XMIDDLE;
4555 int new_joystick_yupper = JOYSTICK_YMIDDLE;
4556 int new_joystick_ylower = JOYSTICK_YMIDDLE;
4557 int new_joystick_xmiddle, new_joystick_ymiddle;
4559 int joystick_fd = joystick.fd[player_nr];
4560 int x, y, last_x, last_y, xpos = 8, ypos = 3;
4561 boolean check[3][3];
4562 int check_remaining = 3 * 3;
4567 if (joystick.status == JOYSTICK_NOT_AVAILABLE)
4570 if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
4575 for (y = 0; y < 3; y++)
4577 for (x = 0; x < 3; x++)
4579 DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
4580 check[x][y] = FALSE;
4584 DrawTextSCentered(mSY - SY + 6 * 32, FONT_TITLE_1, "Rotate joystick");
4585 DrawTextSCentered(mSY - SY + 7 * 32, FONT_TITLE_1, "in all directions");
4586 DrawTextSCentered(mSY - SY + 9 * 32, FONT_TITLE_1, "if all balls");
4587 DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,");
4588 DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick");
4589 DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and");
4590 DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!");
4592 joy_value = Joystick(player_nr);
4593 last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
4594 last_y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
4596 /* eventually uncalibrated center position (joystick could be uncentered) */
4597 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
4600 new_joystick_xmiddle = joy_x;
4601 new_joystick_ymiddle = joy_y;
4603 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
4606 while (Joystick(player_nr) & JOY_BUTTON); /* wait for released button */
4611 if (PendingEvent()) /* got event */
4619 case EVENT_KEYPRESS:
4620 switch (GetEventKey((KeyEvent *)&event, TRUE))
4623 if (check_remaining == 0)
4636 case EVENT_KEYRELEASE:
4637 key_joystick_mapping = 0;
4641 HandleOtherEvents(&event);
4646 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
4649 new_joystick_xleft = MIN(new_joystick_xleft, joy_x);
4650 new_joystick_xright = MAX(new_joystick_xright, joy_x);
4651 new_joystick_yupper = MIN(new_joystick_yupper, joy_y);
4652 new_joystick_ylower = MAX(new_joystick_ylower, joy_y);
4654 setup.input[player_nr].joy.xleft = new_joystick_xleft;
4655 setup.input[player_nr].joy.yupper = new_joystick_yupper;
4656 setup.input[player_nr].joy.xright = new_joystick_xright;
4657 setup.input[player_nr].joy.ylower = new_joystick_ylower;
4658 setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle;
4659 setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle;
4661 CheckJoystickData();
4663 joy_value = Joystick(player_nr);
4665 if (joy_value & JOY_BUTTON && check_remaining == 0)
4668 x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
4669 y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
4671 if (x != last_x || y != last_y)
4673 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0);
4674 DrawGraphic(xpos + x, ypos + y, IMG_MENU_CALIBRATE_RED, 0);
4679 if (check_remaining > 0 && !check[x+1][y+1])
4681 check[x+1][y+1] = TRUE;
4687 printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
4688 setup.input[player_nr].joy.xleft,
4689 setup.input[player_nr].joy.xmiddle,
4690 setup.input[player_nr].joy.xright);
4691 printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
4692 setup.input[player_nr].joy.yupper,
4693 setup.input[player_nr].joy.ymiddle,
4694 setup.input[player_nr].joy.ylower);
4703 /* don't eat all CPU time */
4707 /* calibrated center position (joystick should now be centered) */
4708 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
4711 new_joystick_xmiddle = joy_x;
4712 new_joystick_ymiddle = joy_y;
4717 DrawSetupScreen_Input();
4720 /* wait until the last pressed button was released */
4721 while (Joystick(player_nr) & JOY_BUTTON)
4723 if (PendingEvent()) /* got event */
4728 HandleOtherEvents(&event);
4737 void CalibrateJoystick(int player_nr)
4739 if (!CalibrateJoystickMain(player_nr))
4741 char *device_name = setup.input[player_nr].joy.device_name;
4742 int nr = getJoystickNrFromDeviceName(device_name) + 1;
4743 int xpos = mSX - SX;
4744 int ypos = mSY - SY;
4748 DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr);
4749 DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! ");
4752 Delay(2000); /* show error message for a short time */
4758 DrawSetupScreen_Input();
4762 void DrawSetupScreen()
4764 DeactivateJoystick();
4766 SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
4768 if (setup_mode == SETUP_MODE_INPUT)
4769 DrawSetupScreen_Input();
4770 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
4771 DrawChooseTree(&screen_mode_current);
4772 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
4773 DrawChooseTree(&artwork.gfx_current);
4774 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
4775 DrawChooseTree(&artwork.snd_current);
4776 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
4777 DrawChooseTree(&artwork.mus_current);
4779 DrawSetupScreen_Generic();
4785 void RedrawSetupScreenAfterFullscreenToggle()
4787 if (setup_mode == SETUP_MODE_GRAPHICS)
4791 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
4793 if (setup_mode == SETUP_MODE_INPUT)
4794 HandleSetupScreen_Input(mx, my, dx, dy, button);
4795 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
4796 HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
4797 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
4798 HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
4799 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
4800 HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
4801 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
4802 HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
4804 HandleSetupScreen_Generic(mx, my, dx, dy, button);
4809 void HandleGameActions()
4811 if (game_status != GAME_MODE_PLAYING)
4814 GameActions(); /* main game loop */
4816 if (tape.auto_play && !tape.playing)
4817 AutoPlayTape(); /* continue automatically playing next tape */
4821 /* ---------- new screen button stuff -------------------------------------- */
4823 static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
4828 case SCREEN_CTRL_ID_PREV_LEVEL:
4829 *x = mSX + menu.main.button.prev_level.x;
4830 *y = mSY + menu.main.button.prev_level.y;
4833 case SCREEN_CTRL_ID_NEXT_LEVEL:
4834 *x = mSX + menu.main.button.next_level.x;
4835 *y = mSY + menu.main.button.next_level.y;
4838 case SCREEN_CTRL_ID_PREV_LEVEL:
4839 *x = mSX + TILEX * getPrevlevelButtonPos();
4840 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
4843 case SCREEN_CTRL_ID_NEXT_LEVEL:
4844 *x = mSX + TILEX * getNextLevelButtonPos();
4845 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
4849 case SCREEN_CTRL_ID_PREV_PLAYER:
4850 *x = mSX + TILEX * 10;
4851 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
4854 case SCREEN_CTRL_ID_NEXT_PLAYER:
4855 *x = mSX + TILEX * 12;
4856 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
4860 Error(ERR_EXIT, "unknown gadget ID %d", gadget_id);
4866 int gfx_unpressed, gfx_pressed;
4867 void (*get_gadget_position)(int *, int *, int);
4871 } menubutton_info[NUM_SCREEN_MENUBUTTONS] =
4874 IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE,
4875 getScreenMenuButtonPos,
4876 SCREEN_CTRL_ID_PREV_LEVEL,
4881 IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE,
4882 getScreenMenuButtonPos,
4883 SCREEN_CTRL_ID_NEXT_LEVEL,
4888 IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE,
4889 getScreenMenuButtonPos,
4890 SCREEN_CTRL_ID_PREV_PLAYER,
4895 IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE,
4896 getScreenMenuButtonPos,
4897 SCREEN_CTRL_ID_NEXT_PLAYER,
4905 int gfx_unpressed, gfx_pressed;
4909 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
4912 IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
4913 SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
4914 SCREEN_CTRL_ID_SCROLL_UP,
4918 IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
4919 SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
4920 SCREEN_CTRL_ID_SCROLL_DOWN,
4927 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4928 Bitmap **gfx_unpressed, **gfx_pressed;
4930 int gfx_unpressed, gfx_pressed;
4937 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
4940 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4941 &scrollbar_bitmap[0], &scrollbar_bitmap[1],
4943 IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
4945 SC_SCROLL_VERTICAL_XPOS, SC_SCROLL_VERTICAL_YPOS,
4946 SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
4947 GD_TYPE_SCROLLBAR_VERTICAL,
4948 SCREEN_CTRL_ID_SCROLL_VERTICAL,
4949 "scroll level series vertically"
4953 static void CreateScreenMenubuttons()
4955 struct GadgetInfo *gi;
4956 unsigned long event_mask;
4959 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
4961 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
4962 int gfx_unpressed, gfx_pressed;
4963 int x, y, width, height;
4964 int gd_x1, gd_x2, gd_y1, gd_y2;
4965 int id = menubutton_info[i].gadget_id;
4967 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
4969 menubutton_info[i].get_gadget_position(&x, &y, id);
4971 width = SC_MENUBUTTON_XSIZE;
4972 height = SC_MENUBUTTON_YSIZE;
4974 gfx_unpressed = menubutton_info[i].gfx_unpressed;
4975 gfx_pressed = menubutton_info[i].gfx_pressed;
4976 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
4977 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
4978 gd_x1 = graphic_info[gfx_unpressed].src_x;
4979 gd_y1 = graphic_info[gfx_unpressed].src_y;
4980 gd_x2 = graphic_info[gfx_pressed].src_x;
4981 gd_y2 = graphic_info[gfx_pressed].src_y;
4983 gi = CreateGadget(GDI_CUSTOM_ID, id,
4984 GDI_CUSTOM_TYPE_ID, i,
4985 GDI_INFO_TEXT, menubutton_info[i].infotext,
4990 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4991 GDI_STATE, GD_BUTTON_UNPRESSED,
4992 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
4993 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
4994 GDI_DIRECT_DRAW, FALSE,
4995 GDI_EVENT_MASK, event_mask,
4996 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5000 Error(ERR_EXIT, "cannot create gadget");
5002 screen_gadget[id] = gi;
5006 static void CreateScreenScrollbuttons()
5008 struct GadgetInfo *gi;
5009 unsigned long event_mask;
5012 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
5014 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5015 int gfx_unpressed, gfx_pressed;
5016 int x, y, width, height;
5017 int gd_x1, gd_x2, gd_y1, gd_y2;
5018 int id = scrollbutton_info[i].gadget_id;
5020 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5022 x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset;
5023 y = mSY + scrollbutton_info[i].y;
5024 width = SC_SCROLLBUTTON_XSIZE;
5025 height = SC_SCROLLBUTTON_YSIZE;
5027 if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
5028 y = mSY + (SC_SCROLL_VERTICAL_YPOS +
5029 (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE);
5031 gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
5032 gfx_pressed = scrollbutton_info[i].gfx_pressed;
5033 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5034 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5035 gd_x1 = graphic_info[gfx_unpressed].src_x;
5036 gd_y1 = graphic_info[gfx_unpressed].src_y;
5037 gd_x2 = graphic_info[gfx_pressed].src_x;
5038 gd_y2 = graphic_info[gfx_pressed].src_y;
5040 gi = CreateGadget(GDI_CUSTOM_ID, id,
5041 GDI_CUSTOM_TYPE_ID, i,
5042 GDI_INFO_TEXT, scrollbutton_info[i].infotext,
5047 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5048 GDI_STATE, GD_BUTTON_UNPRESSED,
5049 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5050 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5051 GDI_DIRECT_DRAW, FALSE,
5052 GDI_EVENT_MASK, event_mask,
5053 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5057 Error(ERR_EXIT, "cannot create gadget");
5059 screen_gadget[id] = gi;
5063 static void CreateScreenScrollbars()
5067 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
5069 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5070 #if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5071 int gfx_unpressed, gfx_pressed;
5073 int x, y, width, height;
5074 int gd_x1, gd_x2, gd_y1, gd_y2;
5075 struct GadgetInfo *gi;
5076 int items_max, items_visible, item_position;
5077 unsigned long event_mask;
5078 int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
5079 int id = scrollbar_info[i].gadget_id;
5081 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
5083 x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset;
5084 y = mSY + scrollbar_info[i].y;
5085 width = scrollbar_info[i].width;
5086 height = scrollbar_info[i].height;
5088 if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
5089 height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;
5091 items_max = num_page_entries;
5092 items_visible = num_page_entries;
5095 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5096 gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
5097 gd_bitmap_pressed = *scrollbar_info[i].gfx_pressed;
5103 gfx_unpressed = scrollbar_info[i].gfx_unpressed;
5104 gfx_pressed = scrollbar_info[i].gfx_pressed;
5105 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5106 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5107 gd_x1 = graphic_info[gfx_unpressed].src_x;
5108 gd_y1 = graphic_info[gfx_unpressed].src_y;
5109 gd_x2 = graphic_info[gfx_pressed].src_x;
5110 gd_y2 = graphic_info[gfx_pressed].src_y;
5113 gi = CreateGadget(GDI_CUSTOM_ID, id,
5114 GDI_CUSTOM_TYPE_ID, i,
5115 GDI_INFO_TEXT, scrollbar_info[i].infotext,
5120 GDI_TYPE, scrollbar_info[i].type,
5121 GDI_SCROLLBAR_ITEMS_MAX, items_max,
5122 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
5123 GDI_SCROLLBAR_ITEM_POSITION, item_position,
5125 GDI_WHEEL_AREA_X, SX,
5126 GDI_WHEEL_AREA_Y, SY,
5127 GDI_WHEEL_AREA_WIDTH, SXSIZE,
5128 GDI_WHEEL_AREA_HEIGHT, SYSIZE,
5130 GDI_WHEEL_AREA_X, 0,
5131 GDI_WHEEL_AREA_Y, 0,
5132 GDI_WHEEL_AREA_WIDTH, WIN_XSIZE,
5133 GDI_WHEEL_AREA_HEIGHT, WIN_YSIZE,
5135 GDI_STATE, GD_BUTTON_UNPRESSED,
5136 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5137 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5138 GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
5139 GDI_DIRECT_DRAW, FALSE,
5140 GDI_EVENT_MASK, event_mask,
5141 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5145 Error(ERR_EXIT, "cannot create gadget");
5147 screen_gadget[id] = gi;
5151 void CreateScreenGadgets()
5153 int last_game_status = game_status; /* save current game status */
5155 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5158 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
5160 scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
5162 /* copy pointers to clip mask and GC */
5163 scrollbar_bitmap[i]->clip_mask =
5164 graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
5165 scrollbar_bitmap[i]->stored_clip_gc =
5166 graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
5168 BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
5169 scrollbar_bitmap[i],
5170 graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
5171 graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
5172 TILEX, TILEY, 0, 0);
5176 CreateScreenMenubuttons();
5178 /* force LEVELS draw offset for scrollbar / scrollbutton gadgets */
5179 game_status = GAME_MODE_LEVELS;
5181 CreateScreenScrollbuttons();
5182 CreateScreenScrollbars();
5184 game_status = last_game_status; /* restore current game status */
5187 void FreeScreenGadgets()
5191 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5192 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
5194 /* prevent freeing clip mask and GC twice */
5195 scrollbar_bitmap[i]->clip_mask = None;
5196 scrollbar_bitmap[i]->stored_clip_gc = None;
5198 FreeBitmap(scrollbar_bitmap[i]);
5202 for (i = 0; i < NUM_SCREEN_GADGETS; i++)
5203 FreeGadget(screen_gadget[i]);
5206 void MapScreenMenuGadgets(int screen_mask)
5210 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
5211 if (screen_mask & menubutton_info[i].screen_mask)
5212 MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
5215 void MapScreenTreeGadgets(TreeInfo *ti)
5217 int num_entries = numTreeInfoInGroup(ti);
5220 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
5223 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
5224 MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
5226 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
5227 MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
5230 static void HandleScreenGadgets(struct GadgetInfo *gi)
5232 int id = gi->custom_id;
5233 int button = gi->event.button;
5234 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
5238 case SCREEN_CTRL_ID_PREV_LEVEL:
5239 HandleMainMenu_SelectLevel(step, -1);
5242 case SCREEN_CTRL_ID_NEXT_LEVEL:
5243 HandleMainMenu_SelectLevel(step, +1);
5246 case SCREEN_CTRL_ID_PREV_PLAYER:
5247 HandleSetupScreen_Input_Player(step, -1);
5250 case SCREEN_CTRL_ID_NEXT_PLAYER:
5251 HandleSetupScreen_Input_Player(step, +1);
5254 case SCREEN_CTRL_ID_SCROLL_UP:
5255 if (game_status == GAME_MODE_LEVELS)
5256 HandleChooseLevel(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
5257 else if (game_status == GAME_MODE_SETUP)
5258 HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
5261 case SCREEN_CTRL_ID_SCROLL_DOWN:
5262 if (game_status == GAME_MODE_LEVELS)
5263 HandleChooseLevel(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
5264 else if (game_status == GAME_MODE_SETUP)
5265 HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
5268 case SCREEN_CTRL_ID_SCROLL_VERTICAL:
5269 if (game_status == GAME_MODE_LEVELS)
5270 HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
5271 else if (game_status == GAME_MODE_SETUP)
5272 HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);