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_CHOOSE_GAME_SPEED 2
32 #define SETUP_MODE_EDITOR 3
33 #define SETUP_MODE_INPUT 4
34 #define SETUP_MODE_SHORTCUT_1 5
35 #define SETUP_MODE_SHORTCUT_2 6
36 #define SETUP_MODE_GRAPHICS 7
37 #define SETUP_MODE_CHOOSE_SCREEN_MODE 8
38 #define SETUP_MODE_SOUND 9
39 #define SETUP_MODE_ARTWORK 10
40 #define SETUP_MODE_CHOOSE_GRAPHICS 11
41 #define SETUP_MODE_CHOOSE_SOUNDS 12
42 #define SETUP_MODE_CHOOSE_MUSIC 13
44 #define MAX_SETUP_MODES 14
46 /* for input setup functions */
47 #define SETUPINPUT_SCREEN_POS_START 0
48 #define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4)
49 #define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3)
50 #define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1)
52 /* screens on the info screen */
53 #define INFO_MODE_MAIN 0
54 #define INFO_MODE_TITLE 1
55 #define INFO_MODE_ELEMENTS 2
56 #define INFO_MODE_MUSIC 3
57 #define INFO_MODE_CREDITS 4
58 #define INFO_MODE_PROGRAM 5
59 #define INFO_MODE_VERSION 6
60 #define INFO_MODE_LEVELSET 7
62 #define MAX_INFO_MODES 8
64 /* for various menu stuff */
65 #define MENU_SCREEN_START_XPOS 1
66 #define MENU_SCREEN_START_YPOS 2
67 #define MENU_SCREEN_VALUE_XPOS 14
68 #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1)
69 #define MENU_TITLE1_YPOS 8
70 #define MENU_TITLE2_YPOS 46
71 #define MAX_INFO_ELEMENTS_ON_SCREEN 10
72 #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS)
73 #define MAX_MENU_TEXT_LENGTH_BIG (MENU_SCREEN_VALUE_XPOS - \
74 MENU_SCREEN_START_XPOS)
75 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2)
77 /* buttons and scrollbars identifiers */
78 #define SCREEN_CTRL_ID_PREV_LEVEL 0
79 #define SCREEN_CTRL_ID_NEXT_LEVEL 1
80 #define SCREEN_CTRL_ID_PREV_PLAYER 2
81 #define SCREEN_CTRL_ID_NEXT_PLAYER 3
82 #define SCREEN_CTRL_ID_SCROLL_UP 4
83 #define SCREEN_CTRL_ID_SCROLL_DOWN 5
84 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 6
86 #define NUM_SCREEN_GADGETS 7
88 #define NUM_SCREEN_MENUBUTTONS 4
89 #define NUM_SCREEN_SCROLLBUTTONS 2
90 #define NUM_SCREEN_SCROLLBARS 1
92 #define SCREEN_MASK_MAIN (1 << 0)
93 #define SCREEN_MASK_INPUT (1 << 1)
95 /* graphic position and size values for buttons and scrollbars */
96 #define SC_MENUBUTTON_XSIZE TILEX
97 #define SC_MENUBUTTON_YSIZE TILEY
99 #define SC_SCROLLBUTTON_XSIZE TILEX
100 #define SC_SCROLLBUTTON_YSIZE TILEY
102 #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
104 #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
105 #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
106 SC_SCROLLBUTTON_YSIZE)
108 #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS
109 #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE)
111 #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS
112 #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \
113 SC_SCROLLBUTTON_YSIZE)
115 #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS
116 #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \
117 SC_SCROLL_VERTICAL_YSIZE)
119 #define SC_BORDER_SIZE 14
121 /* other useful macro definitions */
122 #define BUTTON_GRAPHIC_ACTIVE(g) \
123 (g == IMG_MENU_BUTTON_LEFT ? IMG_MENU_BUTTON_LEFT_ACTIVE : \
124 g == IMG_MENU_BUTTON_RIGHT ? IMG_MENU_BUTTON_RIGHT_ACTIVE : \
125 g == IMG_MENU_BUTTON_UP ? IMG_MENU_BUTTON_UP_ACTIVE : \
126 g == IMG_MENU_BUTTON_DOWN ? IMG_MENU_BUTTON_DOWN_ACTIVE : \
127 g == IMG_MENU_BUTTON_LEAVE_MENU ? IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE : \
128 g == IMG_MENU_BUTTON_ENTER_MENU ? IMG_MENU_BUTTON_ENTER_MENU_ACTIVE : \
129 g == IMG_MENU_BUTTON_PREV_LEVEL ? IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE : \
130 g == IMG_MENU_BUTTON_NEXT_LEVEL ? IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE : \
131 IMG_MENU_BUTTON_ACTIVE)
134 /* forward declarations of internal functions */
135 static void HandleScreenGadgets(struct GadgetInfo *);
136 static void HandleSetupScreen_Generic(int, int, int, int, int);
137 static void HandleSetupScreen_Input(int, int, int, int, int);
138 static void CustomizeKeyboard(int);
139 static void CalibrateJoystick(int);
140 static void execSetupGame(void);
141 static void execSetupGraphics(void);
142 static void execSetupArtwork(void);
143 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
145 static void DrawChooseLevel(void);
146 static void DrawInfoScreen(void);
147 static void DrawAndFadeInInfoScreen(int);
148 static void DrawSetupScreen(void);
150 static void DrawInfoScreenExt(int, int);
151 static void DrawInfoScreen_NotAvailable(char *, char *);
152 static void DrawInfoScreen_HelpAnim(int, int, boolean);
153 static void DrawInfoScreen_HelpText(int, int, int, int);
154 static void HandleInfoScreen_Main(int, int, int, int, int);
155 static void HandleInfoScreen_TitleScreen(int);
156 static void HandleInfoScreen_Elements(int);
157 static void HandleInfoScreen_Music(int);
158 static void HandleInfoScreen_Credits(int);
159 static void HandleInfoScreen_Program(int);
160 static void HandleInfoScreen_Version(int);
162 static void MapScreenMenuGadgets(int);
163 static void MapScreenTreeGadgets(TreeInfo *);
165 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
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 static TreeInfo *game_speeds = NULL;
174 static TreeInfo *game_speed_current = NULL;
180 } game_speeds_list[] =
189 { 1000, "1/1s (Extremely Slow)" },
194 { 29, "1/35s (Original Supaplex)" },
196 { 20, "1/50s (Normal Speed)" },
197 { 14, "1/70s (Maximum Supaplex)" },
201 { 1, "1/1000s (Extremely Fast)" },
207 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
208 (s) <= GAME_MODE_SETUP ? (s) : \
209 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
210 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
212 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_ELEMENTS && \
213 (i) <= INFO_MODE_LEVELSET ? (i) : \
216 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
217 menu.draw_xoffset[GAME_MODE_INFO] : \
218 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
219 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
220 menu.draw_yoffset[GAME_MODE_INFO] : \
221 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
223 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
224 DRAW_XOFFSET_INFO(info_mode) : \
225 menu.draw_xoffset[DRAW_MODE(s)])
226 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
227 DRAW_YOFFSET_INFO(info_mode) : \
228 menu.draw_yoffset[DRAW_MODE(s)])
230 #define mSX (SX + DRAW_XOFFSET(game_status))
231 #define mSY (SY + DRAW_YOFFSET(game_status))
233 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
234 menu.list_size[game_status] : \
235 MAX_MENU_ENTRIES_ON_SCREEN)
237 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
238 #define NUM_SCROLLBAR_BITMAPS 2
239 static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
243 /* title display and control definitions */
245 #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \
246 2 * MAX_NUM_TITLE_MESSAGES)
248 static boolean show_title_initial = TRUE;
249 static int num_title_screens = 0;
251 struct TitleControlInfo
258 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
261 /* main menu display and control definitions */
263 #define MAIN_CONTROL_NAME 0
264 #define MAIN_CONTROL_LEVELS 1
265 #define MAIN_CONTROL_SCORES 2
266 #define MAIN_CONTROL_EDITOR 3
267 #define MAIN_CONTROL_INFO 4
268 #define MAIN_CONTROL_GAME 5
269 #define MAIN_CONTROL_SETUP 6
270 #define MAIN_CONTROL_QUIT 7
271 #define MAIN_CONTROL_PREV_LEVEL 8
272 #define MAIN_CONTROL_NEXT_LEVEL 9
273 #define MAIN_CONTROL_CURRENT_LEVEL 10
274 #define MAIN_CONTROL_FIRST_LEVEL 11
275 #define MAIN_CONTROL_LAST_LEVEL 12
276 #define MAIN_CONTROL_LEVEL_INFO_1 13
277 #define MAIN_CONTROL_LEVEL_INFO_2 14
278 #define MAIN_CONTROL_TITLE_1 15
279 #define MAIN_CONTROL_TITLE_2 16
280 #define MAIN_CONTROL_TITLE_3 17
282 static char main_text_name[10];
283 static char main_text_current_level[10];
284 static char main_text_first_level[10];
285 static char main_text_last_level[10];
286 static char main_input_name[MAX_PLAYER_NAME_LEN + 1];
288 struct MainControlInfo
292 struct MenuPosInfo *pos_button;
295 struct TextPosInfo *pos_text;
299 struct MenuPosInfo *pos_input;
304 static struct MainControlInfo main_controls[] =
308 &menu.main.button.name, IMG_MENU_BUTTON,
309 &menu.main.text.name, main_text_name, FONT_MENU_1,
310 &menu.main.input.name, main_input_name, FONT_INPUT_1,
314 &menu.main.button.levels, IMG_MENU_BUTTON_ENTER_MENU,
315 &menu.main.text.levels, "Levelset", FONT_MENU_1,
320 &menu.main.button.scores, IMG_MENU_BUTTON,
321 &menu.main.text.scores, "Hall Of Fame", FONT_MENU_1,
326 &menu.main.button.editor, IMG_MENU_BUTTON,
327 &menu.main.text.editor, "Level Creator", FONT_MENU_1,
332 &menu.main.button.info, IMG_MENU_BUTTON_ENTER_MENU,
333 &menu.main.text.info, "Info Screen", FONT_MENU_1,
338 &menu.main.button.game, IMG_MENU_BUTTON,
339 &menu.main.text.game, "Start Game", FONT_MENU_1,
344 &menu.main.button.setup, IMG_MENU_BUTTON_ENTER_MENU,
345 &menu.main.text.setup, "Setup", FONT_MENU_1,
350 &menu.main.button.quit, IMG_MENU_BUTTON,
351 &menu.main.text.quit, "Quit", FONT_MENU_1,
355 /* (these two buttons are real gadgets) */
357 MAIN_CONTROL_PREV_LEVEL,
358 &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL,
363 MAIN_CONTROL_NEXT_LEVEL,
364 &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL,
370 MAIN_CONTROL_CURRENT_LEVEL,
372 &menu.main.text.current_level, main_text_current_level,FONT_VALUE_1,
376 MAIN_CONTROL_FIRST_LEVEL,
378 &menu.main.text.first_level, main_text_first_level, FONT_TEXT_3,
382 MAIN_CONTROL_LAST_LEVEL,
384 &menu.main.text.last_level, main_text_last_level, FONT_TEXT_3,
388 MAIN_CONTROL_LEVEL_INFO_1,
390 &menu.main.text.level_info_1, NULL, -1,
394 MAIN_CONTROL_LEVEL_INFO_2,
396 &menu.main.text.level_info_2, NULL, -1,
400 MAIN_CONTROL_TITLE_1,
402 &menu.main.text.title_1, PROGRAM_TITLE_STRING, FONT_TITLE_1,
406 MAIN_CONTROL_TITLE_2,
408 &menu.main.text.title_2, PROGRAM_COPYRIGHT_STRING, FONT_TITLE_2,
412 MAIN_CONTROL_TITLE_3,
414 &menu.main.text.title_3, PROGRAM_GAME_BY_STRING, FONT_TITLE_2,
427 static int getTitleScreenGraphic(int nr, boolean initial)
429 return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
432 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
433 boolean initial, int nr)
435 title_controls[num_title_screens].is_image = is_image;
436 title_controls[num_title_screens].initial = initial;
437 title_controls[num_title_screens].local_nr = nr;
442 static void InitializeTitleControls_CheckTitleInfo(boolean initial)
446 for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++)
447 if (graphic_info[getTitleScreenGraphic(i, initial)].bitmap != NULL)
448 InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i);
450 for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
451 if (getLevelSetTitleMessageFilename(i, initial) != NULL)
452 InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i);
455 static void InitializeTitleControls()
457 num_title_screens = 0;
459 if (show_title_initial)
460 InitializeTitleControls_CheckTitleInfo(TRUE);
462 InitializeTitleControls_CheckTitleInfo(FALSE);
465 static void InitializeMainControls()
467 boolean local_team_mode = (!options.network && setup.team_mode);
470 /* set main control text values to dynamically determined values */
471 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
472 sprintf(main_text_current_level, "%s", int2str(level_nr, 3));
473 sprintf(main_text_first_level, "%03d", leveldir_current->first_level);
474 sprintf(main_text_last_level, "%03d", leveldir_current->last_level);
475 sprintf(main_input_name, "%s", setup.player_name);
477 /* set main control screen positions to dynamically determined values */
478 for (i = 0; main_controls[i].nr != -1; i++)
480 struct MainControlInfo *mci = &main_controls[i];
482 struct MenuPosInfo *pos_button = mci->pos_button;
483 struct TextPosInfo *pos_text = mci->pos_text;
484 struct MenuPosInfo *pos_input = mci->pos_input;
485 char *text = mci->text;
486 char *input = mci->input;
487 int button_graphic = mci->button_graphic;
488 int font_text = mci->font_text;
489 int font_input = mci->font_input;
491 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
492 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
493 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
494 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
495 int text_chars = (text != NULL ? strlen(text) : 0);
496 int input_chars = (input != NULL ? strlen(input) : 0);
499 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
501 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
502 int text_width = font_text_width * text_chars;
503 int text_height = font_text_height;
504 int input_width = font_input_width * input_chars;
505 int input_height = font_input_height;
507 if (nr == MAIN_CONTROL_NAME)
510 if (menu.main.input.name.x == -1)
511 menu.main.input.name.x = menu.main.text.name.x + text_width;
512 if (menu.main.input.name.y == -1)
513 menu.main.input.name.y = menu.main.text.name.y;
517 menu.main.input.name.width = input_width;
518 menu.main.input.name.height = input_height;
520 menu.main.input.name.width = font_input_width * MAX_PLAYER_NAME_LEN;
521 menu.main.input.name.height = font_input_height;
525 if (pos_button != NULL)
527 if (pos_button->width == 0)
528 pos_button->width = button_width;
529 if (pos_button->height == 0)
530 pos_button->height = button_height;
533 if (pos_text != NULL)
535 /* calculate width for non-clickable text -- needed for text alignment */
536 boolean calculate_text_width = (pos_button == NULL && text != NULL);
538 if (pos_text->x == -1 && pos_button != NULL)
539 pos_text->x = pos_button->x + pos_button->width;
540 if (pos_text->y == -1 && pos_button != NULL)
541 pos_text->y = pos_button->y;
543 if (pos_text->width == -1 || calculate_text_width)
544 pos_text->width = text_width;
545 if (pos_text->height == -1)
546 pos_text->height = text_height;
549 if (pos_input != NULL)
551 if (pos_input->x == -1 && pos_text != NULL)
552 pos_input->x = pos_text->x + pos_text->width;
553 if (pos_input->y == -1 && pos_text != NULL)
554 pos_input->y = pos_text->y;
556 if (pos_input->width == -1)
557 pos_input->width = input_width;
558 if (pos_input->height == -1)
559 pos_input->height = input_height;
564 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
565 boolean active_input)
569 for (i = 0; main_controls[i].nr != -1; i++)
571 struct MainControlInfo *mci = &main_controls[i];
573 if (mci->nr == nr || nr == -1)
575 struct MenuPosInfo *pos_button = mci->pos_button;
576 struct TextPosInfo *pos_text = mci->pos_text;
577 struct MenuPosInfo *pos_input = mci->pos_input;
578 char *text = mci->text;
579 char *input = mci->input;
580 int button_graphic = mci->button_graphic;
581 int font_text = mci->font_text;
582 int font_input = mci->font_input;
586 button_graphic = BUTTON_GRAPHIC_ACTIVE(button_graphic);
587 font_text = FONT_ACTIVE(font_text);
592 font_input = FONT_ACTIVE(font_input);
595 if (pos_button != NULL)
597 struct MenuPosInfo *pos = pos_button;
598 int x = mSX + pos->x;
599 int y = mSY + pos->y;
601 DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
602 DrawGraphicThruMaskExt(drawto, x, y, button_graphic, 0);
605 if (pos_text != NULL && text != NULL)
607 struct TextPosInfo *pos = pos_text;
608 int x = mSX + ALIGNED_MENU_XPOS(pos);
609 int y = mSY + ALIGNED_MENU_YPOS(pos);
611 DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
612 DrawText(x, y, text, font_text);
615 if (pos_input != NULL && input != NULL)
617 struct MenuPosInfo *pos = pos_input;
618 int x = mSX + ALIGNED_MENU_XPOS(pos);
619 int y = mSY + ALIGNED_MENU_YPOS(pos);
621 DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
622 DrawText(x, y, input, font_input);
628 static void DrawCursorAndText_Main(int nr, boolean active_text)
630 DrawCursorAndText_Main_Ext(nr, active_text, FALSE);
634 static void DrawCursorAndText_Main_Input(int nr, boolean active_text)
636 DrawCursorAndText_Main_Ext(nr, active_text, TRUE);
640 static struct MainControlInfo *getMainControlInfo(int nr)
644 for (i = 0; main_controls[i].nr != -1; i++)
645 if (main_controls[i].nr == nr)
646 return &main_controls[i];
651 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
656 int rect_x = ALIGNED_MENU_XPOS(rect);
657 int rect_y = ALIGNED_MENU_YPOS(rect);
659 return (x >= rect_x && x < rect_x + rect->width &&
660 y >= rect_y && y < rect_y + rect->height);
663 static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
668 int rect_x = ALIGNED_MENU_XPOS(rect);
669 int rect_y = ALIGNED_MENU_YPOS(rect);
671 return (x >= rect_x && x < rect_x + rect->width &&
672 y >= rect_y && y < rect_y + rect->height);
675 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
677 static int cursor_array[SCR_FIELDY];
678 int x = mSX + TILEX * xpos;
679 int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
684 cursor_array[ypos] = graphic;
686 graphic = cursor_array[ypos];
690 graphic = BUTTON_GRAPHIC_ACTIVE(graphic);
692 DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
693 DrawGraphicThruMaskExt(drawto, x, y, graphic, 0);
696 static void initCursor(int ypos, int graphic)
698 drawCursorExt(0, ypos, FALSE, graphic);
701 static void drawCursor(int ypos, boolean active)
703 drawCursorExt(0, ypos, active, -1);
706 static void drawCursorXY(int xpos, int ypos, int graphic)
708 drawCursorExt(xpos, ypos, FALSE, graphic);
711 static void drawChooseTreeCursor(int ypos, boolean active)
713 int last_game_status = game_status; /* save current game status */
715 /* force LEVELS draw offset on artwork setup screen */
716 game_status = GAME_MODE_LEVELS;
718 drawCursorExt(0, ypos, active, -1);
720 game_status = last_game_status; /* restore current game status */
725 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
726 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
730 static int getPrevlevelButtonPos()
735 static int getCurrentLevelTextPos()
737 return (getPrevlevelButtonPos() + 1);
740 static int getNextLevelButtonPos()
742 return getPrevlevelButtonPos() + 3 + 1;
745 static int getLevelRangeTextPos()
747 return getNextLevelButtonPos() + 1;
751 int effectiveGameStatus()
753 if (game_status == GAME_MODE_INFO && info_mode == INFO_MODE_TITLE)
754 return GAME_MODE_TITLE;
759 void DrawTitleScreenImage(int nr, boolean initial)
761 int graphic = getTitleScreenGraphic(nr, initial);
762 Bitmap *bitmap = graphic_info[graphic].bitmap;
764 int width = graphic_info[graphic].width;
765 int height = graphic_info[graphic].height;
766 int src_x = graphic_info[graphic].src_x;
767 int src_y = graphic_info[graphic].src_y;
769 int width = graphic_info[graphic].src_image_width;
770 int height = graphic_info[graphic].src_image_height;
771 int src_x = 0, src_y = 0;
778 if (width > WIN_XSIZE)
780 /* image width too large for window => center image horizontally */
781 src_x = (width - WIN_XSIZE) / 2;
785 if (height > WIN_YSIZE)
787 /* image height too large for window => center image vertically */
788 src_y = (height - WIN_YSIZE) / 2;
792 dst_x = (WIN_XSIZE - width) / 2;
793 dst_y = (WIN_YSIZE - height) / 2;
795 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
797 if (DrawingOnBackground(dst_x, dst_y))
798 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
800 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
802 redraw_mask = REDRAW_ALL;
804 /* reset fading control values to default config settings */
805 title.fade_delay_final = title.fade_delay;
806 title.post_delay_final = title.post_delay;
807 title.auto_delay_final = title.auto_delay;
809 /* override default settings with image config settings, if defined */
810 if (graphic_info[graphic].fade_delay > -1)
811 title.fade_delay_final = graphic_info[graphic].fade_delay;
812 if (graphic_info[graphic].post_delay > -1)
813 title.post_delay_final = graphic_info[graphic].post_delay;
814 if (graphic_info[graphic].auto_delay > -1)
815 title.auto_delay_final = graphic_info[graphic].auto_delay;
818 void DrawTitleScreenMessage(int nr, boolean initial)
820 char *filename = getLevelSetTitleMessageFilename(nr, initial);
821 int font_nr = FONT_TEXT_1;
828 int max_chars_per_line;
829 int max_lines_per_screen;
830 int last_game_status = game_status; /* save current game status */
832 if (filename == NULL)
835 SetDrawBackgroundMask(REDRAW_ALL);
836 SetWindowBackgroundImageIfDefined(IMG_BACKGROUND_MESSAGE);
838 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
840 /* force MESSAGE font on title message screen */
841 game_status = GAME_MODE_MESSAGE;
843 font_width = getFontWidth(font_nr);
844 font_height = getFontHeight(font_nr);
845 max_chars_per_line = (WIN_XSIZE - 2 * pad_x) / font_width;
846 max_lines_per_screen = (WIN_YSIZE - pad_y) / font_height - 1;
848 DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line,
849 max_lines_per_screen, FALSE);
851 game_status = last_game_status; /* restore current game status */
854 void DrawTitleScreen()
856 KeyboardAutoRepeatOff();
858 SetMainBackgroundImage(IMG_BACKGROUND_TITLE);
860 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
865 void DrawMainMenuExt(int redraw_mask, boolean do_fading)
867 static LevelDirTree *leveldir_last_valid = NULL;
868 boolean levelset_has_changed = FALSE;
870 boolean local_team_mode = (!options.network && setup.team_mode);
871 char *name_text = (local_team_mode ? "Team:" : "Name:");
872 int name_width, level_width;
879 FadeSoundsAndMusic();
881 KeyboardAutoRepeatOn();
884 SetDrawDeactivationMask(REDRAW_NONE);
885 SetDrawBackgroundMask(REDRAW_FIELD);
887 audio.sound_deactivated = FALSE;
891 /* needed if last screen was the playing screen, invoked from level editor */
892 if (level_editor_test_game)
894 game_status = GAME_MODE_EDITOR;
900 /* needed if last screen was the editor screen */
901 UndrawSpecialEditorDoor();
903 /* needed if last screen was the setup screen and fullscreen state changed */
904 ToggleFullscreenIfNeeded();
906 /* leveldir_current may be invalid (level group, parent link) */
907 if (!validLevelSeries(leveldir_current))
908 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
910 if (leveldir_current != leveldir_last_valid)
911 levelset_has_changed = TRUE;
913 /* store valid level series information */
914 leveldir_last_valid = leveldir_current;
916 /* needed if last screen (level choice) changed graphics, sounds or music */
917 ReloadCustomArtwork(0);
919 #if defined(TARGET_SDL)
920 SetDrawtoField(DRAW_BACKBUFFER);
924 if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
926 /* needed to be able to skip title screen, if no image or message defined */
927 InitializeTitleControls();
929 if (num_title_screens > 0)
931 game_status = GAME_MODE_TITLE;
939 if (setup.show_titlescreen &&
940 ((levelset_has_changed &&
941 (graphic_info[IMG_TITLESCREEN_1].bitmap != NULL ||
942 getLevelSetMessageFilename(1, FALSE) != NULL)) ||
943 (show_title_initial &&
944 (graphic_info[IMG_TITLESCREEN_INITIAL_1].bitmap != NULL ||
945 getLevelSetMessageFilename(1, TRUE) != NULL))))
947 game_status = GAME_MODE_TITLE;
955 /* level_nr may have been set to value over handicap with level editor */
956 if (setup.handicap && level_nr > leveldir_current->handicap_level)
957 level_nr = leveldir_current->handicap_level;
961 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
965 InitializeMainControls();
968 DrawCursorAndText_Main(-1, FALSE);
970 for (i = 0; main_controls[i].nr != -1; i++)
972 struct MenuPosInfo *pos_button = main_controls[i].pos_button;
973 struct MenuPosInfo *pos_text = main_controls[i].pos_text;
974 struct MenuPosInfo *pos_input = main_controls[i].pos_input;
975 char *text = main_controls[i].text;
976 char *input = main_controls[i].input;
977 int button_graphic = main_controls[i].button_graphic;
978 int font_text = main_controls[i].font_text;
979 int font_input = main_controls[i].font_input;
981 if (pos_button != NULL)
982 DrawGraphicThruMaskExt(drawto, mSX + pos_button->x, mSY + pos_button->y,
985 if (pos_text != NULL && text != NULL)
986 DrawText(mSX + pos_text->x, mSY + pos_text->y, text, font_text);
988 if (pos_input != NULL && input != NULL)
989 DrawText(mSX + pos_input->x, mSY + pos_input->y, input, font_input);
997 DrawText(mSX + 32, mSY + 2 * 32, name_text, FONT_MENU_1);
998 DrawText(mSX + 32, mSY + 3 * 32, "Levelset", FONT_MENU_1);
999 DrawText(mSX + 32, mSY + 4 * 32, "Hall Of Fame", FONT_MENU_1);
1000 DrawText(mSX + 32, mSY + 5 * 32, "Level Creator", FONT_MENU_1);
1001 DrawText(mSX + 32, mSY + 6 * 32, "Info Screen", FONT_MENU_1);
1002 DrawText(mSX + 32, mSY + 7 * 32, "Start Game", FONT_MENU_1);
1003 DrawText(mSX + 32, mSY + 8 * 32, "Setup", FONT_MENU_1);
1004 DrawText(mSX + 32, mSY + 9 * 32, "Quit", FONT_MENU_1);
1006 /* calculated after (possible) reload of custom artwork */
1007 name_width = getTextWidth(name_text, FONT_MENU_1);
1008 level_width = 9 * 32;
1010 DrawText(mSX + 32 + name_width, mSY + 2 * 32, setup.player_name,
1013 DrawText(mSX + getCurrentLevelTextPos() * 32, mSY + 3 * 32,
1014 int2str(level_nr, 3), FONT_VALUE_1);
1017 int text_height = getFontHeight(FONT_TEXT_3);
1018 int xpos = getLevelRangeTextPos() * 32 + 8;
1019 int ypos2 = 3 * 32 + 16;
1020 int ypos1 = ypos2 - text_height;
1022 DrawTextF(mSX - SX + xpos, mSY - SY + ypos1, FONT_TEXT_3,
1023 "%03d", leveldir_current->first_level);
1024 DrawTextF(mSX - SX + xpos, mSY - SY + ypos2, FONT_TEXT_3,
1025 "%03d", leveldir_current->last_level);
1028 for (i = 0; i < 8; i++)
1029 initCursor(i, (i == 1 || i == 4 || i == 6 ? IMG_MENU_BUTTON_ENTER_MENU :
1032 DrawTextSCentered(326, FONT_TITLE_2, PROGRAM_GAME_BY_STRING);
1035 DrawPreviewLevel(TRUE);
1037 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
1040 if (TAPE_IS_EMPTY(tape))
1042 DrawCompleteVideoDisplay();
1047 /* create gadgets for main menu screen */
1048 FreeScreenGadgets();
1049 CreateScreenGadgets();
1051 /* map gadgets for main menu screen */
1053 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
1055 DrawMaskedBorder(REDRAW_ALL);
1058 FadeIn(redraw_mask);
1064 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
1067 void DrawAndFadeInMainMenu(int redraw_mask)
1069 DrawMainMenuExt(redraw_mask, TRUE);
1074 DrawMainMenuExt(REDRAW_ALL, FALSE);
1078 static void gotoTopLevelDir()
1080 /* move upwards to top level directory */
1081 while (leveldir_current->node_parent)
1083 /* write a "path" into level tree for easy navigation to last level */
1084 if (leveldir_current->node_parent->node_group->cl_first == -1)
1086 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
1087 int leveldir_pos = posTreeInfo(leveldir_current);
1088 int num_page_entries;
1089 int cl_first, cl_cursor;
1091 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
1092 num_page_entries = num_leveldirs;
1094 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1096 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
1097 cl_cursor = leveldir_pos - cl_first;
1099 leveldir_current->node_parent->node_group->cl_first = cl_first;
1100 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
1103 leveldir_current = leveldir_current->node_parent;
1109 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1111 static unsigned long title_delay = 0;
1112 static int title_screen_nr = 0;
1113 boolean return_to_main_menu = FALSE;
1114 boolean use_fading_main_menu = TRUE;
1115 boolean use_cross_fading = !show_title_initial; /* default */
1116 struct TitleControlInfo *tci;
1118 if (button == MB_MENU_INITIALIZE)
1120 int last_game_status = game_status; /* save current game status */
1123 title_screen_nr = 0;
1124 tci = &title_controls[title_screen_nr];
1126 /* determine number of title screens to display (images and messages) */
1127 InitializeTitleControls();
1129 if (game_status == GAME_MODE_INFO)
1131 if (num_title_screens == 0)
1133 DrawInfoScreen_NotAvailable("Title screen information:",
1134 "No title screen for this level set.");
1136 title.auto_delay_final = -1;
1141 FadeSoundsAndMusic();
1143 FadeOut(REDRAW_ALL);
1146 /* force TITLE music on title info screen */
1147 game_status = GAME_MODE_TITLE;
1152 game_status = last_game_status; /* restore current game status */
1156 DrawTitleScreenImage(tci->local_nr, tci->initial);
1160 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1162 title.fade_delay_final = title.fade_delay;
1163 title.post_delay_final = title.post_delay;
1164 title.auto_delay_final = -1;
1169 DelayReached(&title_delay, 0); /* reset delay counter */
1174 if (title.auto_delay_final > -1 &&
1175 DelayReached(&title_delay, title.auto_delay_final))
1176 button = MB_MENU_CHOICE;
1178 if (button == MB_MENU_LEAVE)
1180 return_to_main_menu = TRUE;
1181 use_fading_main_menu = FALSE;
1183 else if (button == MB_MENU_CHOICE)
1187 if (game_status == GAME_MODE_INFO && num_title_screens == 0)
1189 FadeOut(REDRAW_FIELD);
1191 info_mode = INFO_MODE_MAIN;
1192 DrawAndFadeInInfoScreen(REDRAW_FIELD);
1198 tci = &title_controls[title_screen_nr];
1202 graphic_info[getTitleScreenGraphic(tci->local_nr,
1203 tci->initial)].anim_mode;
1205 anim_mode = ANIM_FADE; /* ??? */
1207 use_cross_fading = (anim_mode == ANIM_FADE ? FALSE :
1208 anim_mode == ANIM_CROSSFADE ? TRUE :
1211 if (title_screen_nr < num_title_screens)
1213 if (!use_cross_fading)
1214 FadeOut(REDRAW_ALL);
1216 if (use_cross_fading)
1217 FadeCrossSaveBackbuffer();
1220 DrawTitleScreenImage(tci->local_nr, tci->initial);
1222 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1224 if (use_cross_fading)
1225 FadeCross(REDRAW_ALL);
1229 DelayReached(&title_delay, 0); /* reset delay counter */
1233 FadeSoundsAndMusic();
1235 FadeOut(REDRAW_ALL);
1237 return_to_main_menu = TRUE;
1241 if (return_to_main_menu)
1243 /* show initial title images and messages only once at program start */
1244 show_title_initial = FALSE;
1248 if (game_status == GAME_MODE_INFO)
1250 OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1252 info_mode = INFO_MODE_MAIN;
1253 DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu);
1255 else /* default: return to main menu */
1257 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1259 game_status = GAME_MODE_MAIN;
1260 DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu);
1267 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1269 static unsigned long title_delay = 0;
1270 static int title_nr = 0;
1271 static boolean showing_message = FALSE;
1272 char *filename = getLevelSetMessageFilename();
1273 boolean return_to_main_menu = FALSE;
1274 boolean use_fading_main_menu = TRUE;
1275 boolean use_cross_fading = !show_title_initial; /* default */
1276 boolean no_title_info = (graphic_info[IMG_TITLESCREEN_1].bitmap == NULL &&
1277 getLevelSetMessageFilename(1, FALSE) == NULL);
1279 if (button == MB_MENU_INITIALIZE)
1281 int last_game_status = game_status; /* save current game status */
1285 showing_message = FALSE;
1287 if (show_title_initial &&
1288 graphic_info[IMG_TITLESCREEN_INITIAL_1].bitmap == NULL &&
1289 getLevelSetMessageFilename(1, TRUE) == NULL)
1290 show_title_initial = FALSE;
1292 if (game_status == GAME_MODE_INFO)
1296 DrawInfoScreen_NotAvailable("Title screen information:",
1297 "No title screen for this level set.");
1299 title.auto_delay_final = -1;
1304 FadeSoundsAndMusic();
1306 FadeOut(REDRAW_ALL);
1309 /* force TITLE music on title info screen */
1310 game_status = GAME_MODE_TITLE;
1315 game_status = last_game_status; /* restore current game status */
1317 if (graphic_info[getTitleScreenGraphic(0, show_title_initial)].bitmap != NULL)
1319 DrawTitleScreenImage(title_nr, show_title_initial);
1323 DrawTitleScreenMessage(filename);
1325 showing_message = TRUE;
1327 title.fade_delay_final = title.fade_delay;
1328 title.post_delay_final = title.post_delay;
1329 title.auto_delay_final = -1;
1334 DelayReached(&title_delay, 0); /* reset delay counter */
1339 if (title.auto_delay_final > -1 &&
1340 DelayReached(&title_delay, title.auto_delay_final))
1341 button = MB_MENU_CHOICE;
1343 if (button == MB_MENU_LEAVE)
1345 return_to_main_menu = TRUE;
1346 use_fading_main_menu = FALSE;
1348 else if (button == MB_MENU_CHOICE)
1352 if (game_status == GAME_MODE_INFO && no_title_info)
1354 FadeOut(REDRAW_FIELD);
1356 info_mode = INFO_MODE_MAIN;
1357 DrawAndFadeInInfoScreen(REDRAW_FIELD);
1364 if (show_title_initial &&
1365 (title_nr >= MAX_NUM_TITLE_IMAGES ||
1366 graphic_info[IMG_TITLESCREEN_INITIAL_1 + title_nr].bitmap == NULL))
1368 show_title_initial = FALSE;
1370 title_nr = 0; /* restart with title screens for current level set */
1373 anim_mode = graphic_info[getTitleScreenGraphic(title_nr, show_title_initial)].anim_mode;
1375 use_cross_fading = (anim_mode == ANIM_FADE ? FALSE :
1376 anim_mode == ANIM_CROSSFADE ? TRUE :
1379 if (!use_cross_fading)
1380 FadeOut(REDRAW_ALL);
1382 if (title_nr < MAX_NUM_TITLE_IMAGES &&
1383 graphic_info[getTitleScreenGraphic(title_nr, show_title_initial)].bitmap != NULL)
1385 if (use_cross_fading)
1386 FadeCrossSaveBackbuffer();
1388 DrawTitleScreenImage(title_nr, show_title_initial);
1390 if (use_cross_fading)
1391 FadeCross(REDRAW_ALL);
1395 DelayReached(&title_delay, 0); /* reset delay counter */
1397 else if (!showing_message && filename != NULL)
1399 if (use_cross_fading)
1400 FadeCrossSaveBackbuffer();
1402 DrawTitleScreenMessage(filename);
1404 if (use_cross_fading)
1405 FadeCross(REDRAW_ALL);
1409 DelayReached(&title_delay, 0); /* reset delay counter */
1411 showing_message = TRUE;
1415 FadeSoundsAndMusic();
1417 FadeOut(REDRAW_ALL);
1419 return_to_main_menu = TRUE;
1423 if (return_to_main_menu)
1425 show_title_initial = FALSE;
1429 if (game_status == GAME_MODE_INFO)
1431 OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1433 info_mode = INFO_MODE_MAIN;
1434 DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu);
1436 else /* default: return to main menu */
1438 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1440 game_status = GAME_MODE_MAIN;
1441 DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu);
1447 void HandleMainMenu_SelectLevel(int step, int direction)
1449 int old_level_nr = level_nr;
1452 new_level_nr = old_level_nr + step * direction;
1453 if (new_level_nr < leveldir_current->first_level)
1454 new_level_nr = leveldir_current->first_level;
1455 if (new_level_nr > leveldir_current->last_level)
1456 new_level_nr = leveldir_current->last_level;
1458 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1460 /* skipping levels is only allowed when trying to skip single level */
1461 if (setup.skip_levels && step == 1 &&
1462 Request("Level still unsolved ! Skip despite handicap ?", REQ_ASK))
1464 leveldir_current->handicap_level++;
1465 SaveLevelSetup_SeriesInfo();
1468 new_level_nr = leveldir_current->handicap_level;
1471 if (new_level_nr != old_level_nr)
1473 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_CURRENT_LEVEL);
1475 PlaySound(SND_MENU_ITEM_SELECTING);
1477 level_nr = new_level_nr;
1480 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1481 int2str(level_nr, 3), mci->font_text);
1483 DrawText(mSX + 11 * 32, mSY + 3 * 32, int2str(level_nr, 3), FONT_VALUE_1);
1486 LoadLevel(level_nr);
1487 DrawPreviewLevel(TRUE);
1491 DrawCompleteVideoDisplay();
1493 /* needed because DrawPreviewLevel() takes some time */
1501 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1503 static int choice = MAIN_CONTROL_GAME;
1507 if (button == MB_MENU_INITIALIZE)
1509 DrawCursorAndText_Main(choice, TRUE);
1514 if (mx || my) /* mouse input */
1518 for (i = 0; main_controls[i].nr != -1; i++)
1520 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1521 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1522 insideMenuPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1524 pos = main_controls[i].nr;
1530 else if (dx || dy) /* keyboard input */
1532 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1533 choice == MAIN_CONTROL_SETUP))
1534 button = MB_MENU_CHOICE;
1539 if (pos == MAIN_CONTROL_LEVELS && dx != 0 && button)
1541 HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1543 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
1549 PlaySound(SND_MENU_ITEM_ACTIVATING);
1551 DrawCursorAndText_Main(choice, FALSE);
1552 DrawCursorAndText_Main(pos, TRUE);
1559 PlaySound(SND_MENU_ITEM_SELECTING);
1561 if (pos == MAIN_CONTROL_NAME)
1563 game_status = GAME_MODE_PSEUDO_TYPENAME;
1565 HandleTypeName(strlen(setup.player_name), 0);
1567 else if (pos == MAIN_CONTROL_LEVELS)
1571 game_status = GAME_MODE_LEVELS;
1573 SaveLevelSetup_LastSeries();
1574 SaveLevelSetup_SeriesInfo();
1583 else if (pos == MAIN_CONTROL_SCORES)
1585 game_status = GAME_MODE_SCORES;
1589 else if (pos == MAIN_CONTROL_EDITOR)
1591 if (leveldir_current->readonly &&
1592 !strEqual(setup.player_name, "Artsoft"))
1593 Request("This level is read only !", REQ_CONFIRM);
1595 game_status = GAME_MODE_EDITOR;
1599 else if (pos == MAIN_CONTROL_INFO)
1601 game_status = GAME_MODE_INFO;
1602 info_mode = INFO_MODE_MAIN;
1606 else if (pos == MAIN_CONTROL_GAME)
1608 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
1610 else if (pos == MAIN_CONTROL_SETUP)
1612 game_status = GAME_MODE_SETUP;
1613 setup_mode = SETUP_MODE_MAIN;
1617 else if (pos == MAIN_CONTROL_QUIT)
1619 SaveLevelSetup_LastSeries();
1620 SaveLevelSetup_SeriesInfo();
1622 if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
1623 game_status = GAME_MODE_QUIT;
1628 if (game_status == GAME_MODE_MAIN)
1630 DrawPreviewLevel(FALSE);
1637 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1639 static int choice = 5;
1643 if (button == MB_MENU_INITIALIZE)
1645 drawCursor(choice, TRUE);
1650 if (mx || my) /* mouse input */
1652 x = (mx - mSX) / 32;
1653 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
1655 else if (dx || dy) /* keyboard input */
1657 if (dx && choice == 1)
1658 x = (dx < 0 ? 10 : 14);
1661 if (choice == 4 || choice == 6)
1662 button = MB_MENU_CHOICE;
1668 if (y == 1 && dx != 0 && button)
1670 HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1672 else if (IN_VIS_FIELD(x, y) &&
1673 y >= 0 && y <= 7 && (y != 1 || x < 10))
1679 drawCursor(choice, FALSE);
1680 drawCursor(y, TRUE);
1689 game_status = GAME_MODE_PSEUDO_TYPENAME;
1690 HandleTypeName(strlen(setup.player_name), 0);
1696 game_status = GAME_MODE_LEVELS;
1697 SaveLevelSetup_LastSeries();
1698 SaveLevelSetup_SeriesInfo();
1709 game_status = GAME_MODE_SCORES;
1714 if (leveldir_current->readonly &&
1715 !strEqual(setup.player_name, "Artsoft"))
1716 Request("This level is read only !", REQ_CONFIRM);
1717 game_status = GAME_MODE_EDITOR;
1722 game_status = GAME_MODE_INFO;
1723 info_mode = INFO_MODE_MAIN;
1728 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
1732 game_status = GAME_MODE_SETUP;
1733 setup_mode = SETUP_MODE_MAIN;
1739 SaveLevelSetup_LastSeries();
1740 SaveLevelSetup_SeriesInfo();
1742 if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
1743 game_status = GAME_MODE_QUIT;
1748 if (game_status == GAME_MODE_MAIN)
1750 DrawPreviewLevel(FALSE);
1758 /* ========================================================================= */
1759 /* info screen functions */
1760 /* ========================================================================= */
1762 static struct TokenInfo *info_info;
1763 static int num_info_info;
1765 static void execInfoTitleScreen()
1767 info_mode = INFO_MODE_TITLE;
1771 static void execInfoElements()
1773 info_mode = INFO_MODE_ELEMENTS;
1777 static void execInfoMusic()
1779 info_mode = INFO_MODE_MUSIC;
1783 static void execInfoCredits()
1785 info_mode = INFO_MODE_CREDITS;
1789 static void execInfoProgram()
1791 info_mode = INFO_MODE_PROGRAM;
1795 static void execInfoVersion()
1797 info_mode = INFO_MODE_VERSION;
1801 static void execInfoLevelSet()
1803 info_mode = INFO_MODE_LEVELSET;
1807 static void execExitInfo()
1809 game_status = GAME_MODE_MAIN;
1813 static struct TokenInfo info_info_main[] =
1815 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
1816 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
1817 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
1818 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
1819 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
1820 { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" },
1821 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
1822 { TYPE_EMPTY, NULL, "" },
1823 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
1828 static void DrawCursorAndText_Info(int pos, boolean active)
1830 int xpos = MENU_SCREEN_START_XPOS;
1831 int ypos = MENU_SCREEN_START_YPOS + pos;
1832 int font_nr = FONT_MENU_1;
1835 font_nr = FONT_ACTIVE(font_nr);
1837 DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[pos].text, font_nr);
1839 if (info_info[pos].type & ~TYPE_SKIP_ENTRY)
1840 drawCursor(pos, active);
1843 static void DrawInfoScreen_Main(int redraw_mask, boolean do_fading)
1848 CloseDoor(DOOR_CLOSE_2);
1852 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
1854 info_info = info_info_main;
1857 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
1860 int xpos = MENU_SCREEN_START_XPOS;
1861 int ypos = MENU_SCREEN_START_YPOS + i;
1862 int font_nr = FONT_MENU_1;
1865 if (info_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
1866 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
1867 else if (info_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
1868 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
1869 else if (info_info[i].type & ~TYPE_SKIP_ENTRY)
1870 initCursor(i, IMG_MENU_BUTTON);
1873 DrawCursorAndText_Info(i, FALSE);
1875 DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[i].text, font_nr);
1881 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
1886 DrawMaskedBorder(REDRAW_ALL);
1889 FadeIn(redraw_mask);
1896 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
1898 static int choice_store[MAX_INFO_MODES];
1899 int choice = choice_store[info_mode]; /* always starts with 0 */
1903 if (button == MB_MENU_INITIALIZE)
1905 /* advance to first valid menu entry */
1906 while (choice < num_info_info &&
1907 info_info[choice].type & TYPE_SKIP_ENTRY)
1909 choice_store[info_mode] = choice;
1912 DrawCursorAndText_Info(choice, TRUE);
1914 drawCursor(choice, TRUE);
1919 else if (button == MB_MENU_LEAVE)
1921 for (y = 0; y < num_info_info; y++)
1923 if (info_info[y].type & TYPE_LEAVE_MENU)
1925 void (*menu_callback_function)(void) = info_info[y].value;
1927 menu_callback_function();
1929 break; /* absolutely needed because function changes 'info_info'! */
1936 if (mx || my) /* mouse input */
1938 x = (mx - mSX) / 32;
1939 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
1941 else if (dx || dy) /* keyboard input */
1945 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
1947 if (info_info[choice].type & menu_navigation_type ||
1948 info_info[choice].type & TYPE_ENTER_SCREEN ||
1949 info_info[choice].type & TYPE_BOOLEAN_STYLE)
1950 button = MB_MENU_CHOICE;
1955 /* jump to next non-empty menu entry (up or down) */
1956 while (y > 0 && y < num_info_info - 1 &&
1957 info_info[y].type & TYPE_SKIP_ENTRY)
1961 if (IN_VIS_FIELD(x, y) &&
1962 y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY)
1968 PlaySound(SND_MENU_ITEM_ACTIVATING);
1971 DrawCursorAndText_Info(choice, FALSE);
1972 DrawCursorAndText_Info(y, TRUE);
1974 drawCursor(choice, FALSE);
1975 drawCursor(y, TRUE);
1978 choice = choice_store[info_mode] = y;
1981 else if (!(info_info[y].type & TYPE_GHOSTED))
1983 PlaySound(SND_MENU_ITEM_SELECTING);
1985 if (info_info[y].type & TYPE_ENTER_OR_LEAVE)
1987 void (*menu_callback_function)(void) = info_info[choice].value;
1989 menu_callback_function();
1995 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
1999 int ybottom = SYSIZE - 20;
2001 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
2003 FadeOut(REDRAW_FIELD);
2008 DrawTextSCentered(ystart1, FONT_TEXT_1, text_title);
2009 DrawTextSCentered(ystart2, FONT_TEXT_2, text_error);
2011 DrawTextSCentered(ybottom, FONT_TEXT_4,
2012 "Press any key or button for info menu");
2014 FadeIn(REDRAW_FIELD);
2017 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
2019 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
2020 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
2021 int xstart = mSX + 16;
2022 int ystart = mSY + 64 + 2 * 32;
2023 int ystep = TILEY + 4;
2024 int element, action, direction;
2032 for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
2033 infoscreen_step[i] = infoscreen_frame[i] = 0;
2038 DrawTextSCentered(100, FONT_TEXT_1, "The Game Elements:");
2040 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
2041 "Press any key or button for next page");
2047 while (helpanim_info[j].element != HELPANIM_LIST_END)
2049 if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN ||
2054 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2063 j += infoscreen_step[i - start];
2065 element = helpanim_info[j].element;
2066 action = helpanim_info[j].action;
2067 direction = helpanim_info[j].direction;
2070 element = EL_UNKNOWN;
2072 if (action != -1 && direction != -1)
2073 graphic = el_act_dir2img(element, action, direction);
2074 else if (action != -1)
2075 graphic = el_act2img(element, action);
2076 else if (direction != -1)
2077 graphic = el_dir2img(element, direction);
2079 graphic = el2img(element);
2081 delay = helpanim_info[j++].delay;
2086 if (infoscreen_frame[i - start] == 0)
2089 infoscreen_frame[i - start] = delay - 1;
2093 sync_frame = delay - infoscreen_frame[i - start];
2094 infoscreen_frame[i - start]--;
2097 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
2099 if (!infoscreen_frame[i - start])
2100 infoscreen_step[i - start] = 0;
2104 if (!infoscreen_frame[i - start])
2105 infoscreen_step[i - start]++;
2106 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2112 ClearRectangleOnBackground(drawto, xstart, ystart + (i - start) * ystep,
2114 DrawGraphicAnimationExt(drawto, xstart, ystart + (i - start) * ystep,
2115 graphic, sync_frame, USE_MASKING);
2118 DrawInfoScreen_HelpText(element, action, direction, i - start);
2123 redraw_mask |= REDRAW_FIELD;
2128 static char *getHelpText(int element, int action, int direction)
2130 char token[MAX_LINE_LEN];
2132 strcpy(token, element_info[element].token_name);
2135 strcat(token, element_action_info[action].suffix);
2137 if (direction != -1)
2138 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
2140 return getHashEntry(helptext_info, token);
2143 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
2146 int font_nr = FONT_INFO_ELEMENTS;
2148 int font_nr = FONT_LEVEL_NUMBER;
2150 int font_width = getFontWidth(font_nr);
2151 int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX;
2152 int sy = mSY + 65 + 2 * 32 + 1;
2153 int ystep = TILEY + 4;
2154 int pad_x = sx - SX;
2155 int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width;
2156 int max_lines_per_text = 2;
2159 if (action != -1 && direction != -1) /* element.action.direction */
2160 text = getHelpText(element, action, direction);
2162 if (text == NULL && action != -1) /* element.action */
2163 text = getHelpText(element, action, -1);
2165 if (text == NULL && direction != -1) /* element.direction */
2166 text = getHelpText(element, -1, direction);
2168 if (text == NULL) /* base element */
2169 text = getHelpText(element, -1, -1);
2171 if (text == NULL) /* not found */
2172 text = "No description available";
2174 if (strlen(text) <= max_chars_per_line) /* only one line of text */
2175 sy += getFontHeight(font_nr) / 2;
2177 DrawTextWrapped(sx, sy + ypos * ystep, text, font_nr,
2178 max_chars_per_line, max_lines_per_text);
2181 void DrawInfoScreen_TitleScreen()
2186 void HandleInfoScreen_TitleScreen(int button)
2188 HandleTitleScreen(0, 0, 0, 0, button);
2191 void DrawInfoScreen_Elements()
2193 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
2195 FadeOut(REDRAW_FIELD);
2200 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
2202 FadeIn(REDRAW_FIELD);
2207 void HandleInfoScreen_Elements(int button)
2209 static unsigned long info_delay = 0;
2210 static int num_anims;
2211 static int num_pages;
2213 int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN;
2216 if (button == MB_MENU_INITIALIZE)
2218 boolean new_element = TRUE;
2222 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
2224 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
2226 else if (new_element)
2229 new_element = FALSE;
2233 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
2237 if (button == MB_MENU_LEAVE)
2239 PlaySound(SND_MENU_ITEM_SELECTING);
2241 info_mode = INFO_MODE_MAIN;
2246 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2248 if (button != MB_MENU_INITIALIZE)
2250 PlaySound(SND_MENU_ITEM_SELECTING);
2255 if (page >= num_pages)
2257 FadeSoundsAndMusic();
2258 FadeOut(REDRAW_FIELD);
2260 info_mode = INFO_MODE_MAIN;
2261 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2266 if (button != MB_MENU_INITIALIZE)
2267 FadeCrossSaveBackbuffer();
2269 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
2271 if (button != MB_MENU_INITIALIZE)
2272 FadeCross(REDRAW_FIELD);
2276 if (DelayReached(&info_delay, GameFrameDelay))
2277 if (page < num_pages)
2278 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
2280 PlayMenuSoundIfLoop();
2284 void DrawInfoScreen_Music()
2286 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
2288 FadeOut(REDRAW_FIELD);
2295 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
2297 FadeIn(REDRAW_FIELD);
2300 void HandleInfoScreen_Music(int button)
2302 static struct MusicFileInfo *list = NULL;
2303 int ystart = 150, dy = 30;
2304 int ybottom = SYSIZE - 20;
2306 if (button == MB_MENU_INITIALIZE)
2308 list = music_file_info;
2312 FadeSoundsAndMusic();
2317 DrawTextSCentered(100, FONT_TEXT_1, "No music info for this level set.");
2319 DrawTextSCentered(ybottom, FONT_TEXT_4,
2320 "Press any key or button for info menu");
2326 if (button == MB_MENU_LEAVE)
2328 PlaySound(SND_MENU_ITEM_SELECTING);
2330 FadeSoundsAndMusic();
2332 info_mode = INFO_MODE_MAIN;
2337 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2341 if (button != MB_MENU_INITIALIZE)
2343 PlaySound(SND_MENU_ITEM_SELECTING);
2351 FadeSoundsAndMusic();
2352 FadeOut(REDRAW_FIELD);
2354 info_mode = INFO_MODE_MAIN;
2355 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2360 FadeSoundsAndMusic();
2362 if (button != MB_MENU_INITIALIZE)
2363 FadeCrossSaveBackbuffer();
2370 int sound = list->music;
2372 if (sound_info[sound].loop)
2373 PlaySoundLoop(sound);
2377 DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Sounds:");
2381 PlayMusic(list->music);
2383 DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Music:");
2386 if (!strEqual(list->title, UNKNOWN_NAME))
2388 if (!strEqual(list->title_header, UNKNOWN_NAME))
2389 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->title_header);
2391 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
2394 if (!strEqual(list->artist, UNKNOWN_NAME))
2396 if (!strEqual(list->artist_header, UNKNOWN_NAME))
2397 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->artist_header);
2399 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "by");
2401 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->artist);
2404 if (!strEqual(list->album, UNKNOWN_NAME))
2406 if (!strEqual(list->album_header, UNKNOWN_NAME))
2407 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->album_header);
2409 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the album");
2411 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album);
2414 if (!strEqual(list->year, UNKNOWN_NAME))
2416 if (!strEqual(list->year_header, UNKNOWN_NAME))
2417 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->year_header);
2419 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the year");
2421 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->year);
2424 DrawTextSCentered(ybottom, FONT_TEXT_4,
2425 "Press any key or button for next page");
2427 if (button != MB_MENU_INITIALIZE)
2428 FadeCross(REDRAW_FIELD);
2431 if (list != NULL && list->is_sound && sound_info[list->music].loop)
2432 PlaySoundLoop(list->music);
2435 static boolean DrawInfoScreen_CreditsScreen(int screen_nr)
2437 int ystart = 150, ystep = 30;
2438 int ybottom = SYSIZE - 20;
2446 DrawTextSCentered(100, FONT_TEXT_1, "Credits:");
2450 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2451 "Special thanks to");
2452 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2454 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2456 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2457 "\"Boulder Dash\"");
2458 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2460 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2462 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2464 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2465 "First Star Software");
2467 else if (screen_nr == 1)
2469 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2470 "Special thanks to");
2471 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2472 "Klaus Heinz & Volker Wertich");
2473 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2475 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2476 "\"Emerald Mine\"");
2477 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2479 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2481 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2483 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2486 else if (screen_nr == 2)
2488 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2489 "Special thanks to");
2490 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2491 "Michael Stopp & Philip Jespersen");
2492 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2494 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2496 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2498 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2500 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2502 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2503 "Digital Integration");
2505 else if (screen_nr == 3)
2507 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2508 "Special thanks to");
2509 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2510 "Hiroyuki Imabayashi");
2511 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2513 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2515 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2517 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2519 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2521 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2524 else if (screen_nr == 4)
2526 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2527 "Special thanks to");
2528 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2530 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2532 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2533 "Jürgen Bonhagen");
2534 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2535 "for the continuous creation");
2536 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
2537 "of outstanding level sets");
2539 else if (screen_nr == 5)
2541 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2543 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2545 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2546 "for ideas and inspiration by");
2547 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2550 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
2552 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_3,
2554 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2,
2555 "for ideas and inspiration by");
2556 DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_3,
2559 else if (screen_nr == 6)
2561 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2563 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2565 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2566 "for the new Emerald Mine engine");
2568 else if (screen_nr == 7)
2570 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2572 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2574 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2575 "for the initial DOS port");
2577 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2579 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2581 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2582 "for some additional toons");
2584 else if (screen_nr == 8)
2586 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2587 "And not to forget:");
2588 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2,
2590 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3,
2591 "All those who contributed");
2592 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2593 "levels to this game");
2594 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_3,
2604 DrawTextSCentered(ybottom, FONT_TEXT_4,
2605 "Press any key or button for next page");
2610 void DrawInfoScreen_Credits()
2612 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
2614 FadeSoundsAndMusic();
2616 FadeOut(REDRAW_FIELD);
2618 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
2620 FadeIn(REDRAW_FIELD);
2623 void HandleInfoScreen_Credits(int button)
2625 static int screen_nr = 0;
2627 if (button == MB_MENU_INITIALIZE)
2631 DrawInfoScreen_CreditsScreen(screen_nr);
2633 else if (button == MB_MENU_LEAVE)
2635 PlaySound(SND_MENU_ITEM_SELECTING);
2637 info_mode = INFO_MODE_MAIN;
2642 else if (button == MB_MENU_CHOICE)
2644 boolean show_screen;
2646 PlaySound(SND_MENU_ITEM_SELECTING);
2650 FadeCrossSaveBackbuffer();
2652 show_screen = DrawInfoScreen_CreditsScreen(screen_nr);
2656 FadeCross(REDRAW_FIELD);
2660 FadeSoundsAndMusic();
2661 FadeOut(REDRAW_FIELD);
2663 info_mode = INFO_MODE_MAIN;
2664 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2669 PlayMenuSoundIfLoop();
2673 void DrawInfoScreen_Program()
2675 int ystart = 150, ystep = 30;
2676 int ybottom = SYSIZE - 20;
2678 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
2680 FadeOut(REDRAW_FIELD);
2685 DrawTextSCentered(100, FONT_TEXT_1, "Program Information:");
2687 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2688 "This game is Freeware!");
2689 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2,
2690 "If you like it, send e-mail to:");
2691 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3,
2692 PROGRAM_EMAIL_STRING);
2693 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_2,
2694 "or SnailMail to:");
2695 DrawTextSCentered(ystart + 4 * ystep + 0, FONT_TEXT_3,
2697 DrawTextSCentered(ystart + 4 * ystep + 20, FONT_TEXT_3,
2698 "Detmolder Strasse 189");
2699 DrawTextSCentered(ystart + 4 * ystep + 40, FONT_TEXT_3,
2701 DrawTextSCentered(ystart + 4 * ystep + 60, FONT_TEXT_3,
2703 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2,
2704 "More information and levels:");
2705 DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_3,
2706 PROGRAM_WEBSITE_STRING);
2707 DrawTextSCentered(ystart + 9 * ystep, FONT_TEXT_2,
2708 "If you have created new levels,");
2709 DrawTextSCentered(ystart + 10 * ystep, FONT_TEXT_2,
2710 "send them to me to include them!");
2711 DrawTextSCentered(ystart + 11 * ystep, FONT_TEXT_2,
2714 DrawTextSCentered(ybottom, FONT_TEXT_4,
2715 "Press any key or button for info menu");
2717 FadeIn(REDRAW_FIELD);
2720 void HandleInfoScreen_Program(int button)
2722 if (button == MB_MENU_LEAVE)
2724 PlaySound(SND_MENU_ITEM_SELECTING);
2726 info_mode = INFO_MODE_MAIN;
2731 else if (button == MB_MENU_CHOICE)
2733 PlaySound(SND_MENU_ITEM_SELECTING);
2735 FadeSoundsAndMusic();
2736 FadeOut(REDRAW_FIELD);
2738 info_mode = INFO_MODE_MAIN;
2739 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2743 PlayMenuSoundIfLoop();
2747 void DrawInfoScreen_Version()
2749 int font_header = FONT_TEXT_3;
2750 int font_text = FONT_TEXT_2;
2751 int xstep = getFontWidth(font_text);
2752 int ystep = getFontHeight(font_text);
2754 int ybottom = SYSIZE - 20;
2755 int xstart1 = SX + 2 * xstep;
2756 int xstart2 = SX + 18 * xstep;
2757 #if defined(TARGET_SDL)
2758 int xstart3 = SX + 28 * xstep;
2759 SDL_version sdl_version_compiled;
2760 const SDL_version *sdl_version_linked;
2763 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
2765 FadeOut(REDRAW_FIELD);
2770 DrawTextSCentered(100, FONT_TEXT_1, "Version Information:");
2772 DrawTextF(xstart1, ystart, font_header, "Name");
2773 DrawTextF(xstart2, ystart, font_text, PROGRAM_TITLE_STRING);
2776 DrawTextF(xstart1, ystart, font_header, "Version");
2777 DrawTextF(xstart2, ystart, font_text, getProgramFullVersionString());
2780 DrawTextF(xstart1, ystart, font_header, "Platform");
2781 DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING);
2784 DrawTextF(xstart1, ystart, font_header, "Target");
2785 DrawTextF(xstart2, ystart, font_text, TARGET_STRING);
2788 DrawTextF(xstart1, ystart, font_header, "Compile time");
2789 DrawTextF(xstart2, ystart, font_text, getCompileDateString());
2791 #if defined(TARGET_SDL)
2792 ystart += 3 * ystep;
2793 DrawTextF(xstart1, ystart, font_header, "Library");
2794 DrawTextF(xstart2, ystart, font_header, "compiled");
2795 DrawTextF(xstart3, ystart, font_header, "linked");
2797 SDL_VERSION(&sdl_version_compiled);
2798 sdl_version_linked = SDL_Linked_Version();
2800 ystart += 2 * ystep;
2801 DrawTextF(xstart1, ystart, font_text, "SDL");
2802 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
2803 sdl_version_compiled.major,
2804 sdl_version_compiled.minor,
2805 sdl_version_compiled.patch);
2806 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
2807 sdl_version_linked->major,
2808 sdl_version_linked->minor,
2809 sdl_version_linked->patch);
2811 SDL_IMAGE_VERSION(&sdl_version_compiled);
2812 sdl_version_linked = IMG_Linked_Version();
2815 DrawTextF(xstart1, ystart, font_text, "SDL_image");
2816 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
2817 sdl_version_compiled.major,
2818 sdl_version_compiled.minor,
2819 sdl_version_compiled.patch);
2820 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
2821 sdl_version_linked->major,
2822 sdl_version_linked->minor,
2823 sdl_version_linked->patch);
2825 SDL_MIXER_VERSION(&sdl_version_compiled);
2826 sdl_version_linked = Mix_Linked_Version();
2829 DrawTextF(xstart1, ystart, font_text, "SDL_mixer");
2830 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
2831 sdl_version_compiled.major,
2832 sdl_version_compiled.minor,
2833 sdl_version_compiled.patch);
2834 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
2835 sdl_version_linked->major,
2836 sdl_version_linked->minor,
2837 sdl_version_linked->patch);
2839 SDL_NET_VERSION(&sdl_version_compiled);
2840 sdl_version_linked = SDLNet_Linked_Version();
2843 DrawTextF(xstart1, ystart, font_text, "SDL_net");
2844 DrawTextF(xstart2, ystart, font_text, "%d.%d.%d",
2845 sdl_version_compiled.major,
2846 sdl_version_compiled.minor,
2847 sdl_version_compiled.patch);
2848 DrawTextF(xstart3, ystart, font_text, "%d.%d.%d",
2849 sdl_version_linked->major,
2850 sdl_version_linked->minor,
2851 sdl_version_linked->patch);
2854 DrawTextSCentered(ybottom, FONT_TEXT_4,
2855 "Press any key or button for info menu");
2857 FadeIn(REDRAW_FIELD);
2860 void HandleInfoScreen_Version(int button)
2862 if (button == MB_MENU_LEAVE)
2864 PlaySound(SND_MENU_ITEM_SELECTING);
2866 info_mode = INFO_MODE_MAIN;
2871 else if (button == MB_MENU_CHOICE)
2873 PlaySound(SND_MENU_ITEM_SELECTING);
2875 FadeSoundsAndMusic();
2876 FadeOut(REDRAW_FIELD);
2878 info_mode = INFO_MODE_MAIN;
2879 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2883 PlayMenuSoundIfLoop();
2887 void DrawInfoScreen_LevelSet()
2890 int ybottom = SYSIZE - 20;
2891 char *filename = getLevelSetInfoFilename();
2893 int font_nr = FONT_INFO_LEVELSET;
2895 int font_nr = FONT_LEVEL_NUMBER;
2897 int font_width = getFontWidth(font_nr);
2898 int font_height = getFontHeight(font_nr);
2901 int sx = SX + pad_x;
2902 int sy = SY + pad_y;
2903 int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
2904 int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
2906 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
2908 FadeOut(REDRAW_FIELD);
2913 DrawTextSCentered(100, FONT_TEXT_1, "Level Set Information:");
2915 DrawTextSCentered(ybottom, FONT_TEXT_4,
2916 "Press any key or button for info menu");
2918 if (filename != NULL)
2919 DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line,
2920 max_lines_per_screen, TRUE);
2922 DrawTextSCentered(ystart, FONT_TEXT_2,
2923 "No information for this level set.");
2925 FadeIn(REDRAW_FIELD);
2928 void HandleInfoScreen_LevelSet(int button)
2930 if (button == MB_MENU_LEAVE)
2932 PlaySound(SND_MENU_ITEM_SELECTING);
2934 info_mode = INFO_MODE_MAIN;
2939 else if (button == MB_MENU_CHOICE)
2941 PlaySound(SND_MENU_ITEM_SELECTING);
2943 FadeSoundsAndMusic();
2944 FadeOut(REDRAW_FIELD);
2946 info_mode = INFO_MODE_MAIN;
2947 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2951 PlayMenuSoundIfLoop();
2955 static void DrawInfoScreenExt(int redraw_mask, boolean do_fading)
2957 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
2959 if (info_mode == INFO_MODE_TITLE)
2960 DrawInfoScreen_TitleScreen();
2961 else if (info_mode == INFO_MODE_ELEMENTS)
2962 DrawInfoScreen_Elements();
2963 else if (info_mode == INFO_MODE_MUSIC)
2964 DrawInfoScreen_Music();
2965 else if (info_mode == INFO_MODE_CREDITS)
2966 DrawInfoScreen_Credits();
2967 else if (info_mode == INFO_MODE_PROGRAM)
2968 DrawInfoScreen_Program();
2969 else if (info_mode == INFO_MODE_VERSION)
2970 DrawInfoScreen_Version();
2971 else if (info_mode == INFO_MODE_LEVELSET)
2972 DrawInfoScreen_LevelSet();
2974 DrawInfoScreen_Main(redraw_mask, do_fading);
2976 if (info_mode != INFO_MODE_MAIN &&
2977 info_mode != INFO_MODE_TITLE &&
2978 info_mode != INFO_MODE_MUSIC)
2985 void DrawAndFadeInInfoScreen(int redraw_mask)
2987 DrawInfoScreenExt(redraw_mask, TRUE);
2990 void DrawInfoScreen()
2992 DrawInfoScreenExt(REDRAW_ALL, FALSE);
2995 void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
2997 if (info_mode == INFO_MODE_TITLE)
2998 HandleInfoScreen_TitleScreen(button);
2999 else if (info_mode == INFO_MODE_ELEMENTS)
3000 HandleInfoScreen_Elements(button);
3001 else if (info_mode == INFO_MODE_MUSIC)
3002 HandleInfoScreen_Music(button);
3003 else if (info_mode == INFO_MODE_CREDITS)
3004 HandleInfoScreen_Credits(button);
3005 else if (info_mode == INFO_MODE_PROGRAM)
3006 HandleInfoScreen_Program(button);
3007 else if (info_mode == INFO_MODE_VERSION)
3008 HandleInfoScreen_Version(button);
3009 else if (info_mode == INFO_MODE_LEVELSET)
3010 HandleInfoScreen_LevelSet(button);
3012 HandleInfoScreen_Main(mx, my, dx, dy, button);
3018 /* ========================================================================= */
3019 /* type name functions */
3020 /* ========================================================================= */
3022 void HandleTypeName(int newxpos, Key key)
3024 static char last_player_name[MAX_PLAYER_NAME_LEN + 1];
3025 struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME);
3027 struct MenuPosInfo *pos = mci->pos_input;
3028 int startx = mSX + ALIGNED_MENU_XPOS(pos);
3029 int starty = mSY + ALIGNED_MENU_YPOS(pos);
3032 static int xpos = 0;
3034 static int xpos = 0, ypos = 2;
3036 int font_nr = mci->font_input;
3037 int font_active_nr = FONT_ACTIVE(font_nr);
3038 int font_width = getFontWidth(font_active_nr);
3041 int startx = mSX + mci->pos_input->x;
3042 int starty = mSY + mci->pos_input->y;
3045 int name_width = getFontWidth(FONT_MENU_1) * strlen("Name:");
3046 int startx = mSX + 32 + name_width;
3047 int starty = mSY + ypos * 32;
3049 char key_char = getValidConfigValueChar(getCharFromKey(key));
3050 boolean is_valid_key_char = (key_char != 0 && (key_char != ' ' || xpos > 0));
3051 boolean is_active = TRUE;
3053 DrawBackgroundForFont(startx,starty, pos->width, pos->height, font_active_nr);
3057 strcpy(last_player_name, setup.player_name);
3062 /* add one character width for added cursor character */
3063 pos->width += font_width;
3064 startx = mSX + ALIGNED_MENU_XPOS(pos);
3066 DrawText(startx, starty, setup.player_name, font_active_nr);
3067 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
3070 else if (is_valid_key_char && xpos < MAX_PLAYER_NAME_LEN)
3072 setup.player_name[xpos] = key_char;
3073 setup.player_name[xpos + 1] = 0;
3078 /* add one character width for added name text character */
3079 pos->width += font_width;
3080 startx = mSX + ALIGNED_MENU_XPOS(pos);
3082 DrawText(startx, starty, setup.player_name, font_active_nr);
3083 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
3086 else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
3090 setup.player_name[xpos] = 0;
3093 /* remove one character width for removed name text character */
3094 pos->width -= font_width;
3095 startx = mSX + ALIGNED_MENU_XPOS(pos);
3097 DrawText(startx, starty, setup.player_name, font_active_nr);
3098 DrawText(startx + xpos * font_width, starty, "_ ", font_active_nr);
3101 else if (key == KSYM_Return && xpos > 0)
3104 /* remove one character width for removed cursor text character */
3105 pos->width -= font_width;
3106 startx = mSX + ALIGNED_MENU_XPOS(pos);
3108 DrawText(startx, starty, setup.player_name, font_nr);
3109 DrawText(startx + xpos * font_width, starty, " ", font_active_nr);
3116 game_status = GAME_MODE_MAIN;
3118 else if (key == KSYM_Escape)
3120 strcpy(setup.player_name, last_player_name);
3124 game_status = GAME_MODE_MAIN;
3129 pos->width = (strlen(setup.player_name) + 1) * font_width;
3130 startx = mSX + ALIGNED_MENU_XPOS(pos);
3132 DrawText(startx, starty, setup.player_name, font_active_nr);
3133 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
3137 pos->width = strlen(setup.player_name) * font_width;
3138 startx = mSX + ALIGNED_MENU_XPOS(pos);
3140 DrawText(startx, starty, setup.player_name, font_nr);
3143 sprintf(main_input_name, "%s", setup.player_name);
3147 /* ========================================================================= */
3148 /* tree menu functions */
3149 /* ========================================================================= */
3151 static void DrawChooseTree(TreeInfo **ti_ptr)
3155 FreeScreenGadgets();
3156 CreateScreenGadgets();
3158 CloseDoor(DOOR_CLOSE_2);
3162 HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
3163 MapScreenTreeGadgets(*ti_ptr);
3169 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
3171 struct GadgetInfo *gi = screen_gadget[id];
3172 int items_max, items_visible, item_position;
3174 items_max = numTreeInfoInGroup(ti);
3175 items_visible = NUM_MENU_ENTRIES_ON_SCREEN;
3176 item_position = first_entry;
3178 if (item_position > items_max - items_visible)
3179 item_position = items_max - items_visible;
3181 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
3182 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
3183 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
3186 static void drawChooseTreeList(int first_entry, int num_page_entries,
3190 char *title_string = NULL;
3191 int yoffset_sets = MENU_TITLE1_YPOS;
3192 int yoffset_setup = 16;
3193 int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? yoffset_sets :
3195 int last_game_status = game_status; /* save current game status */
3197 title_string = ti->infotext;
3199 DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
3201 /* force LEVELS font on artwork setup screen */
3202 game_status = GAME_MODE_LEVELS;
3205 /* clear tree list area, but not title or scrollbar */
3206 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
3207 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
3208 NUM_MENU_ENTRIES_ON_SCREEN * 32);
3210 /* clear tree list area, but not title or scrollbar */
3211 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
3212 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
3213 MAX_MENU_ENTRIES_ON_SCREEN * 32);
3216 for (i = 0; i < num_page_entries; i++)
3218 TreeInfo *node, *node_first;
3219 int entry_pos = first_entry + i;
3220 int xpos = MENU_SCREEN_START_XPOS;
3221 int ypos = MENU_SCREEN_START_YPOS + i;
3222 int startx = mSX + xpos * 32;
3223 int starty = mSY + ypos * 32;
3224 int font_nr = FONT_TEXT_1;
3225 int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
3226 int startx_text = startx + font_xoffset;
3227 int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
3228 int text_size = startx_scrollbar - startx_text;
3229 int max_buffer_len = text_size / getFontWidth(font_nr);
3230 char buffer[max_buffer_len + 1];
3232 node_first = getTreeInfoFirstGroupEntry(ti);
3233 node = getTreeInfoFromPos(node_first, entry_pos);
3235 strncpy(buffer, node->name, max_buffer_len);
3236 buffer[max_buffer_len] = '\0';
3238 DrawText(startx, starty, buffer, font_nr + node->color);
3240 if (node->parent_link)
3241 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
3242 else if (node->level_group)
3243 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
3245 initCursor(i, IMG_MENU_BUTTON);
3248 game_status = last_game_status; /* restore current game status */
3250 redraw_mask |= REDRAW_FIELD;
3253 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
3255 TreeInfo *node, *node_first;
3256 int x, last_redraw_mask = redraw_mask;
3257 int ypos = MENU_TITLE2_YPOS;
3258 int font_nr = FONT_TITLE_2;
3260 if (ti->type != TREE_TYPE_LEVEL_DIR)
3263 node_first = getTreeInfoFirstGroupEntry(ti);
3264 node = getTreeInfoFromPos(node_first, entry_pos);
3266 DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr);
3268 if (node->parent_link)
3269 DrawTextFCentered(ypos, font_nr, "leave group \"%s\"",
3271 else if (node->level_group)
3272 DrawTextFCentered(ypos, font_nr, "enter group \"%s\"",
3274 else if (ti->type == TREE_TYPE_LEVEL_DIR)
3275 DrawTextFCentered(ypos, font_nr, "%3d levels (%s)",
3276 node->levels, node->class_desc);
3278 /* let BackToFront() redraw only what is needed */
3279 redraw_mask = last_redraw_mask | REDRAW_TILES;
3280 for (x = 0; x < SCR_FIELDX; x++)
3281 MarkTileDirty(x, 1);
3284 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
3287 TreeInfo *ti = *ti_ptr;
3289 int y = ti->cl_cursor;
3290 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3291 int num_entries = numTreeInfoInGroup(ti);
3292 int num_page_entries;
3293 int last_game_status = game_status; /* save current game status */
3294 boolean position_set_by_scrollbar = (dx == 999);
3296 /* force LEVELS draw offset on choose level and artwork setup screen */
3297 game_status = GAME_MODE_LEVELS;
3299 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
3300 num_page_entries = num_entries;
3302 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
3304 game_status = last_game_status; /* restore current game status */
3306 if (button == MB_MENU_INITIALIZE)
3308 int num_entries = numTreeInfoInGroup(ti);
3309 int entry_pos = posTreeInfo(ti);
3311 if (ti->cl_first == -1)
3313 /* only on initialization */
3314 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
3315 ti->cl_cursor = entry_pos - ti->cl_first;
3317 else if (ti->cl_cursor >= num_page_entries ||
3318 (num_entries > num_page_entries &&
3319 num_entries - ti->cl_first < num_page_entries))
3321 /* only after change of list size (by custom graphic configuration) */
3322 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
3323 ti->cl_cursor = entry_pos - ti->cl_first;
3326 if (position_set_by_scrollbar)
3329 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3332 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3333 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3334 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3338 else if (button == MB_MENU_LEAVE)
3340 PlaySound(SND_MENU_ITEM_SELECTING);
3342 if (ti->node_parent)
3344 *ti_ptr = ti->node_parent;
3345 DrawChooseTree(ti_ptr);
3347 else if (game_status == GAME_MODE_SETUP)
3349 if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
3351 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
3352 execSetupGraphics();
3358 game_status = GAME_MODE_MAIN;
3365 if (mx || my) /* mouse input */
3367 int last_game_status = game_status; /* save current game status */
3369 /* force LEVELS draw offset on artwork setup screen */
3370 game_status = GAME_MODE_LEVELS;
3372 x = (mx - mSX) / 32;
3373 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
3375 game_status = last_game_status; /* restore current game status */
3377 else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */
3379 /* move cursor instead of scrolling when already at start/end of list */
3380 if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
3382 else if (dy == +1 * SCROLL_LINE &&
3383 ti->cl_first + num_page_entries == num_entries)
3386 /* handle scrolling screen one line or page */
3387 if (ti->cl_cursor + dy < 0 ||
3388 ti->cl_cursor + dy > num_page_entries - 1)
3390 if (ABS(dy) == SCROLL_PAGE)
3391 step = num_page_entries - 1;
3393 if (dy < 0 && ti->cl_first > 0)
3395 /* scroll page/line up */
3397 ti->cl_first -= step;
3398 if (ti->cl_first < 0)
3401 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3402 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3403 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3405 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3408 else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
3410 /* scroll page/line down */
3412 ti->cl_first += step;
3413 if (ti->cl_first + num_page_entries > num_entries)
3414 ti->cl_first = MAX(0, num_entries - num_page_entries);
3416 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3417 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3418 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3420 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3427 /* handle moving cursor one line */
3428 y = ti->cl_cursor + dy;
3433 TreeInfo *node_first, *node_cursor;
3434 int entry_pos = ti->cl_first + y;
3436 node_first = getTreeInfoFirstGroupEntry(ti);
3437 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3439 if (node_cursor->node_group)
3441 PlaySound(SND_MENU_ITEM_SELECTING);
3443 node_cursor->cl_first = ti->cl_first;
3444 node_cursor->cl_cursor = ti->cl_cursor;
3445 *ti_ptr = node_cursor->node_group;
3446 DrawChooseTree(ti_ptr);
3451 else if (dx == -1 && ti->node_parent)
3453 PlaySound(SND_MENU_ITEM_SELECTING);
3455 *ti_ptr = ti->node_parent;
3456 DrawChooseTree(ti_ptr);
3461 if (!anyScrollbarGadgetActive() &&
3462 IN_VIS_FIELD(x, y) &&
3463 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
3464 y >= 0 && y < num_page_entries)
3468 if (y != ti->cl_cursor)
3470 PlaySound(SND_MENU_ITEM_ACTIVATING);
3472 drawChooseTreeCursor(ti->cl_cursor, FALSE);
3473 drawChooseTreeCursor(y, TRUE);
3474 drawChooseTreeInfo(ti->cl_first + y, ti);
3481 TreeInfo *node_first, *node_cursor;
3482 int entry_pos = ti->cl_first + y;
3484 PlaySound(SND_MENU_ITEM_SELECTING);
3486 node_first = getTreeInfoFirstGroupEntry(ti);
3487 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3489 if (node_cursor->node_group)
3491 node_cursor->cl_first = ti->cl_first;
3492 node_cursor->cl_cursor = ti->cl_cursor;
3493 *ti_ptr = node_cursor->node_group;
3494 DrawChooseTree(ti_ptr);
3496 else if (node_cursor->parent_link)
3498 *ti_ptr = node_cursor->node_parent;
3499 DrawChooseTree(ti_ptr);
3503 node_cursor->cl_first = ti->cl_first;
3504 node_cursor->cl_cursor = ti->cl_cursor;
3505 *ti_ptr = node_cursor;
3507 if (ti->type == TREE_TYPE_LEVEL_DIR)
3509 LoadLevelSetup_SeriesInfo();
3511 SaveLevelSetup_LastSeries();
3512 SaveLevelSetup_SeriesInfo();
3516 if (game_status == GAME_MODE_SETUP)
3518 if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
3520 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
3521 execSetupGraphics();
3527 game_status = GAME_MODE_MAIN;
3535 void DrawChooseLevel()
3537 SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
3539 DrawChooseTree(&leveldir_current);
3545 void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
3547 HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
3552 void DrawHallOfFame(int highlight_position)
3555 FadeSoundsAndMusic();
3557 /* (this is needed when called from GameEnd() after winning a game) */
3558 KeyboardAutoRepeatOn();
3561 /* (this is needed when called from GameEnd() after winning a game) */
3562 SetDrawDeactivationMask(REDRAW_NONE);
3563 SetDrawBackgroundMask(REDRAW_FIELD);
3565 CloseDoor(DOOR_CLOSE_2);
3567 if (highlight_position < 0)
3568 LoadScore(level_nr);
3570 FadeOut(REDRAW_FIELD);
3577 HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
3579 FadeIn(REDRAW_FIELD);
3582 static void drawHallOfFameList(int first_entry, int highlight_position)
3586 SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
3589 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
3590 DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
3591 "HighScores of Level %d", level_nr);
3593 for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
3595 int entry = first_entry + i;
3596 boolean active = (entry == highlight_position);
3597 int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
3598 int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
3599 int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
3600 int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
3601 int dx1 = 3 * getFontWidth(font_nr1);
3602 int dx2 = dx1 + getFontWidth(font_nr1);
3603 int dx3 = dx2 + 25 * getFontWidth(font_nr3);
3604 int sy = mSY + 64 + i * 32;
3606 DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
3607 DrawText(mSX + dx1, sy, ".", font_nr1);
3608 DrawText(mSX + dx2, sy, ".........................", font_nr3);
3610 if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
3611 DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
3613 DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
3616 redraw_mask |= REDRAW_FIELD;
3619 void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
3621 static int first_entry = 0;
3622 static int highlight_position = 0;
3623 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3625 if (button == MB_MENU_INITIALIZE)
3628 highlight_position = mx;
3629 drawHallOfFameList(first_entry, highlight_position);
3634 if (ABS(dy) == SCROLL_PAGE) /* handle scrolling one page */
3635 step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
3639 if (first_entry > 0)
3641 first_entry -= step;
3642 if (first_entry < 0)
3645 drawHallOfFameList(first_entry, highlight_position);
3650 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
3652 first_entry += step;
3653 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
3654 first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
3656 drawHallOfFameList(first_entry, highlight_position);
3659 else if (button == MB_MENU_LEAVE)
3661 PlaySound(SND_MENU_ITEM_SELECTING);
3663 FadeSound(SND_BACKGROUND_SCORES);
3665 game_status = GAME_MODE_MAIN;
3669 else if (button == MB_MENU_CHOICE)
3671 PlaySound(SND_MENU_ITEM_SELECTING);
3673 FadeSound(SND_BACKGROUND_SCORES);
3674 FadeOut(REDRAW_FIELD);
3676 game_status = GAME_MODE_MAIN;
3678 DrawAndFadeInMainMenu(REDRAW_FIELD);
3681 if (game_status == GAME_MODE_SCORES)
3682 PlayMenuSoundIfLoop();
3688 /* ========================================================================= */
3689 /* setup screen functions */
3690 /* ========================================================================= */
3692 static struct TokenInfo *setup_info;
3693 static int num_setup_info;
3695 static char *screen_mode_text;
3696 static char *game_speed_text;
3697 static char *graphics_set_name;
3698 static char *sounds_set_name;
3699 static char *music_set_name;
3701 static void execSetupMain()
3703 setup_mode = SETUP_MODE_MAIN;
3707 static void execSetupGame()
3709 if (game_speeds == NULL)
3713 for (i = 0; game_speeds_list[i].value != -1; i++)
3715 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
3716 char identifier[32], name[32];
3717 int value = game_speeds_list[i].value;
3718 char *text = game_speeds_list[i].text;
3720 ti->node_top = &game_speeds;
3721 ti->sort_priority = 10000 - value;
3723 sprintf(identifier, "%d", value);
3724 sprintf(name, "%s", text);
3726 setString(&ti->identifier, identifier);
3727 setString(&ti->name, name);
3728 setString(&ti->name_sorting, name);
3729 setString(&ti->infotext, "Game Speed");
3731 pushTreeInfo(&game_speeds, ti);
3734 /* sort game speed values to start with slowest game speed */
3735 sortTreeInfo(&game_speeds);
3737 /* set current game speed to configured game speed value */
3738 game_speed_current =
3739 getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay));
3741 /* if that fails, set current game speed to reliable default value */
3742 if (game_speed_current == NULL)
3743 game_speed_current =
3744 getTreeInfoFromIdentifier(game_speeds, i_to_a(GAME_FRAME_DELAY));
3746 /* if that also fails, set current game speed to first available speed */
3747 if (game_speed_current == NULL)
3748 game_speed_current = game_speeds;
3751 setup.game_frame_delay = atoi(game_speed_current->identifier);
3753 /* needed for displaying game speed text instead of identifier */
3754 game_speed_text = game_speed_current->name;
3756 setup_mode = SETUP_MODE_GAME;
3760 static void execSetupChooseGameSpeed()
3762 setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED;
3766 static void execSetupEditor()
3768 setup_mode = SETUP_MODE_EDITOR;
3772 static void execSetupGraphics()
3774 if (video.fullscreen_available && screen_modes == NULL)
3778 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
3780 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
3781 char identifier[32], name[32];
3782 int x = video.fullscreen_modes[i].width;
3783 int y = video.fullscreen_modes[i].height;
3786 get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy);
3788 ti->node_top = &screen_modes;
3789 ti->sort_priority = x * 10000 + y;
3791 sprintf(identifier, "%dx%d", x, y);
3792 sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy);
3794 setString(&ti->identifier, identifier);
3795 setString(&ti->name, name);
3796 setString(&ti->name_sorting, name);
3797 setString(&ti->infotext, "Fullscreen Mode");
3799 pushTreeInfo(&screen_modes, ti);
3802 /* sort fullscreen modes to start with lowest available screen resolution */
3803 sortTreeInfo(&screen_modes);
3805 /* set current screen mode for fullscreen mode to configured setup value */
3806 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3807 setup.fullscreen_mode);
3809 /* if that fails, set current screen mode to reliable default value */
3810 if (screen_mode_current == NULL)
3811 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3812 DEFAULT_FULLSCREEN_MODE);
3814 /* if that also fails, set current screen mode to first available mode */
3815 if (screen_mode_current == NULL)
3816 screen_mode_current = screen_modes;
3818 if (screen_mode_current == NULL)
3819 video.fullscreen_available = FALSE;
3822 if (video.fullscreen_available)
3824 setup.fullscreen_mode = screen_mode_current->identifier;
3826 /* needed for displaying screen mode name instead of identifier */
3827 screen_mode_text = screen_mode_current->name;
3830 setup_mode = SETUP_MODE_GRAPHICS;
3834 static void execSetupChooseScreenMode()
3836 if (!video.fullscreen_available)
3839 setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE;
3843 static void execSetupSound()
3845 setup_mode = SETUP_MODE_SOUND;
3849 static void execSetupArtwork()
3851 setup.graphics_set = artwork.gfx_current->identifier;
3852 setup.sounds_set = artwork.snd_current->identifier;
3853 setup.music_set = artwork.mus_current->identifier;
3855 /* needed if last screen (setup choice) changed graphics, sounds or music */
3856 ReloadCustomArtwork(0);
3858 /* needed for displaying artwork name instead of artwork identifier */
3859 graphics_set_name = artwork.gfx_current->name;
3860 sounds_set_name = artwork.snd_current->name;
3861 music_set_name = artwork.mus_current->name;
3863 setup_mode = SETUP_MODE_ARTWORK;
3867 static void execSetupChooseGraphics()
3869 setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
3873 static void execSetupChooseSounds()
3875 setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
3879 static void execSetupChooseMusic()
3881 setup_mode = SETUP_MODE_CHOOSE_MUSIC;
3885 static void execSetupInput()
3887 setup_mode = SETUP_MODE_INPUT;
3891 static void execSetupShortcut1()
3893 setup_mode = SETUP_MODE_SHORTCUT_1;
3897 static void execSetupShortcut2()
3899 setup_mode = SETUP_MODE_SHORTCUT_2;
3903 static void execExitSetup()
3905 game_status = GAME_MODE_MAIN;
3909 static void execSaveAndExitSetup()
3915 static struct TokenInfo setup_info_main[] =
3917 { TYPE_ENTER_MENU, execSetupGame, "Game & Menu" },
3918 { TYPE_ENTER_MENU, execSetupEditor, "Editor" },
3919 { TYPE_ENTER_MENU, execSetupGraphics, "Graphics" },
3920 { TYPE_ENTER_MENU, execSetupSound, "Sound & Music" },
3921 { TYPE_ENTER_MENU, execSetupArtwork, "Custom Artwork" },
3922 { TYPE_ENTER_MENU, execSetupInput, "Input Devices" },
3923 { TYPE_ENTER_MENU, execSetupShortcut1, "Key Shortcuts 1" },
3924 { TYPE_ENTER_MENU, execSetupShortcut2, "Key Shortcuts 2" },
3925 { TYPE_EMPTY, NULL, "" },
3926 { TYPE_LEAVE_MENU, execExitSetup, "Exit" },
3927 { TYPE_LEAVE_MENU, execSaveAndExitSetup, "Save and Exit" },
3932 static struct TokenInfo setup_info_game[] =
3934 { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" },
3935 { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" },
3936 { TYPE_SWITCH, &setup.handicap, "Handicap:" },
3937 { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" },
3938 { TYPE_SWITCH, &setup.time_limit, "Time Limit:" },
3939 { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" },
3940 { TYPE_ENTER_LIST, execSetupChooseGameSpeed, "Game Speed:" },
3941 { TYPE_STRING, &game_speed_text, "" },
3942 { TYPE_EMPTY, NULL, "" },
3943 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3948 static struct TokenInfo setup_info_editor[] =
3951 { TYPE_SWITCH, &setup.editor.el_boulderdash, "Boulder Dash:" },
3952 { TYPE_SWITCH, &setup.editor.el_emerald_mine, "Emerald Mine:" },
3953 { TYPE_SWITCH, &setup.editor.el_emerald_mine_club, "Emerald Mine Club:" },
3954 { TYPE_SWITCH, &setup.editor.el_more, "Rocks'n'Diamonds:" },
3955 { TYPE_SWITCH, &setup.editor.el_sokoban, "Sokoban:" },
3956 { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" },
3957 { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" },
3958 { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
3960 { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" },
3961 { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" },
3962 { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" },
3964 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" },
3966 { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
3967 { TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" },
3968 { TYPE_EMPTY, NULL, "" },
3970 { TYPE_SWITCH, &setup.editor.el_by_game, "Show elements by game:" },
3971 { TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" },
3972 { TYPE_EMPTY, NULL, "" },
3974 { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" },
3975 { TYPE_EMPTY, NULL, "" },
3976 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3981 static struct TokenInfo setup_info_graphics[] =
3983 { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" },
3984 { TYPE_ENTER_LIST, execSetupChooseScreenMode, "Fullscreen Mode:" },
3985 { TYPE_STRING, &screen_mode_text, "" },
3986 { TYPE_SWITCH, &setup.scroll_delay, "Delayed Scrolling:" },
3988 { TYPE_SWITCH, &setup.soft_scrolling, "Soft Scrolling:" },
3989 { TYPE_SWITCH, &setup.double_buffering,"Double-Buffering:" },
3991 { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" },
3992 { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" },
3993 { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" },
3994 { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" },
3995 { TYPE_SWITCH, &setup.toons, "Show Toons:" },
3996 { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" },
3997 { TYPE_EMPTY, NULL, "" },
3998 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4003 static struct TokenInfo setup_info_sound[] =
4005 { TYPE_SWITCH, &setup.sound_simple, "Sound Effects (Normal):" },
4006 { TYPE_SWITCH, &setup.sound_loops, "Sound Effects (Looping):" },
4007 { TYPE_SWITCH, &setup.sound_music, "Music:" },
4008 { TYPE_EMPTY, NULL, "" },
4009 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4014 static struct TokenInfo setup_info_artwork[] =
4016 { TYPE_ENTER_LIST, execSetupChooseGraphics,"Custom Graphics:" },
4017 { TYPE_STRING, &graphics_set_name, "" },
4018 { TYPE_ENTER_LIST, execSetupChooseSounds, "Custom Sounds:" },
4019 { TYPE_STRING, &sounds_set_name, "" },
4020 { TYPE_ENTER_LIST, execSetupChooseMusic, "Custom Music:" },
4021 { TYPE_STRING, &music_set_name, "" },
4022 { TYPE_EMPTY, NULL, "" },
4024 { TYPE_YES_NO, &setup.override_level_graphics,"Override Level Graphics:" },
4025 { TYPE_YES_NO, &setup.override_level_sounds, "Override Level Sounds:" },
4026 { TYPE_YES_NO, &setup.override_level_music, "Override Level Music:" },
4028 { TYPE_STRING, NULL, "Override Level Artwork:"},
4029 { TYPE_YES_NO, &setup.override_level_graphics, "Graphics:" },
4030 { TYPE_YES_NO, &setup.override_level_sounds, "Sounds:" },
4031 { TYPE_YES_NO, &setup.override_level_music, "Music:" },
4033 { TYPE_EMPTY, NULL, "" },
4034 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4039 static struct TokenInfo setup_info_input[] =
4041 { TYPE_SWITCH, NULL, "Player:" },
4042 { TYPE_SWITCH, NULL, "Device:" },
4043 { TYPE_ENTER_MENU, NULL, "" },
4044 { TYPE_EMPTY, NULL, "" },
4045 { TYPE_EMPTY, NULL, "" },
4046 { TYPE_EMPTY, NULL, "" },
4047 { TYPE_EMPTY, NULL, "" },
4048 { TYPE_EMPTY, NULL, "" },
4049 { TYPE_EMPTY, NULL, "" },
4050 { TYPE_EMPTY, NULL, "" },
4051 { TYPE_EMPTY, NULL, "" },
4052 { TYPE_EMPTY, NULL, "" },
4053 { TYPE_EMPTY, NULL, "" },
4054 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4059 static struct TokenInfo setup_info_shortcut_1[] =
4061 { TYPE_KEYTEXT, NULL, "Quick Save Game to Tape:", },
4062 { TYPE_KEY, &setup.shortcut.save_game, "" },
4063 { TYPE_KEYTEXT, NULL, "Quick Load Game from Tape:", },
4064 { TYPE_KEY, &setup.shortcut.load_game, "" },
4065 { TYPE_KEYTEXT, NULL, "Start Game & Toggle Pause:", },
4066 { TYPE_KEY, &setup.shortcut.toggle_pause, "" },
4067 { TYPE_EMPTY, NULL, "" },
4068 { TYPE_YES_NO, &setup.ask_on_escape, "Ask on 'Esc' Key:" },
4069 { TYPE_YES_NO, &setup.ask_on_escape_editor, "Ask on 'Esc' Key (Editor):" },
4070 { TYPE_EMPTY, NULL, "" },
4071 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4076 static struct TokenInfo setup_info_shortcut_2[] =
4078 { TYPE_KEYTEXT, NULL, "Set Focus to Player 1:", },
4079 { TYPE_KEY, &setup.shortcut.focus_player[0], "" },
4080 { TYPE_KEYTEXT, NULL, "Set Focus to Player 2:", },
4081 { TYPE_KEY, &setup.shortcut.focus_player[1], "" },
4082 { TYPE_KEYTEXT, NULL, "Set Focus to Player 3:", },
4083 { TYPE_KEY, &setup.shortcut.focus_player[2], "" },
4084 { TYPE_KEYTEXT, NULL, "Set Focus to Player 4:", },
4085 { TYPE_KEY, &setup.shortcut.focus_player[3], "" },
4086 { TYPE_KEYTEXT, NULL, "Set Focus to All Players:", },
4087 { TYPE_KEY, &setup.shortcut.focus_player_all, "" },
4088 { TYPE_EMPTY, NULL, "" },
4089 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4094 static Key getSetupKey()
4096 Key key = KSYM_UNDEFINED;
4097 boolean got_key_event = FALSE;
4099 while (!got_key_event)
4101 if (PendingEvent()) /* got event */
4109 case EVENT_KEYPRESS:
4111 key = GetEventKey((KeyEvent *)&event, TRUE);
4113 /* press 'Escape' or 'Enter' to keep the existing key binding */
4114 if (key == KSYM_Escape || key == KSYM_Return)
4115 key = KSYM_UNDEFINED; /* keep old value */
4117 got_key_event = TRUE;
4121 case EVENT_KEYRELEASE:
4122 key_joystick_mapping = 0;
4126 HandleOtherEvents(&event);
4134 /* don't eat all CPU time */
4141 static int getSetupTextFont(int type)
4143 if (type & (TYPE_SWITCH |
4154 static int getSetupValueFont(int type, void *value)
4156 if (type & TYPE_KEY)
4157 return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1);
4158 else if (type & TYPE_STRING)
4159 return FONT_VALUE_2;
4160 else if (type & TYPE_ECS_AGA)
4161 return FONT_VALUE_1;
4162 else if (type & TYPE_BOOLEAN_STYLE)
4163 return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
4165 return FONT_VALUE_1;
4168 static void drawSetupValue(int pos)
4170 boolean font_draw_xoffset_modified = FALSE;
4171 int font_draw_xoffset_old = -1;
4172 int xpos = MENU_SCREEN_VALUE_XPOS;
4173 int ypos = MENU_SCREEN_START_YPOS + pos;
4174 int startx = mSX + xpos * 32;
4175 int starty = mSY + ypos * 32;
4176 int font_nr, font_width;
4177 int type = setup_info[pos].type;
4178 void *value = setup_info[pos].value;
4179 char *value_string = getSetupValue(type, value);
4182 if (value_string == NULL)
4185 if (type & TYPE_KEY)
4187 xpos = MENU_SCREEN_START_XPOS;
4189 if (type & TYPE_QUERY)
4191 value_string = "<press key>";
4194 else if (type & TYPE_STRING)
4196 int max_value_len = (SCR_FIELDX - 2) * 2;
4198 xpos = MENU_SCREEN_START_XPOS;
4200 if (strlen(value_string) > max_value_len)
4201 value_string[max_value_len] = '\0';
4204 startx = mSX + xpos * 32;
4205 starty = mSY + ypos * 32;
4206 font_nr = getSetupValueFont(type, value);
4207 font_width = getFontWidth(font_nr);
4209 /* downward compatibility correction for Juergen Bonhagen's menu settings */
4210 if (setup_mode != SETUP_MODE_INPUT)
4212 int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
4213 int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
4214 int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
4215 int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
4216 int text_font_nr = getSetupTextFont(FONT_MENU_2);
4217 int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
4218 int text_width = MAX_MENU_TEXT_LENGTH_MEDIUM * getFontWidth(text_font_nr);
4219 boolean correct_font_draw_xoffset = FALSE;
4221 if (xpos == MENU_SCREEN_START_XPOS &&
4222 startx + font1_xoffset < text_startx + text_font_xoffset)
4223 correct_font_draw_xoffset = TRUE;
4225 if (xpos == MENU_SCREEN_VALUE_XPOS &&
4226 startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
4227 correct_font_draw_xoffset = TRUE;
4229 /* check if setup value would overlap with setup text when printed */
4230 /* (this can happen for extreme/wrong values for font draw offset) */
4231 if (correct_font_draw_xoffset)
4233 font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
4234 font_draw_xoffset_modified = TRUE;
4236 if (type & TYPE_KEY)
4237 getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
4238 else if (!(type & TYPE_STRING))
4239 getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
4240 MAX_MENU_TEXT_LENGTH_MEDIUM * (16 - getFontWidth(text_font_nr));
4244 for (i = 0; i <= MENU_SCREEN_MAX_XPOS - xpos; i++)
4245 DrawText(startx + i * font_width, starty, " ", font_nr);
4247 DrawText(startx, starty, value_string, font_nr);
4249 if (font_draw_xoffset_modified)
4250 getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
4253 static void changeSetupValue(int pos)
4255 if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
4257 *(boolean *)setup_info[pos].value ^= TRUE;
4259 else if (setup_info[pos].type & TYPE_KEY)
4263 setup_info[pos].type |= TYPE_QUERY;
4264 drawSetupValue(pos);
4265 setup_info[pos].type &= ~TYPE_QUERY;
4267 key = getSetupKey();
4268 if (key != KSYM_UNDEFINED)
4269 *(Key *)setup_info[pos].value = key;
4272 drawSetupValue(pos);
4275 static void DrawCursorAndText_Setup(int pos, boolean active)
4277 int xpos = MENU_SCREEN_START_XPOS;
4278 int ypos = MENU_SCREEN_START_YPOS + pos;
4279 int font_nr = getSetupTextFont(setup_info[pos].type);
4281 if (setup_info == setup_info_input)
4282 font_nr = FONT_MENU_1;
4285 font_nr = FONT_ACTIVE(font_nr);
4287 DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[pos].text, font_nr);
4289 if (setup_info[pos].type & ~TYPE_SKIP_ENTRY)
4290 drawCursor(pos, active);
4293 static void DrawSetupScreen_Generic()
4295 char *title_string = NULL;
4299 CloseDoor(DOOR_CLOSE_2);
4303 if (setup_mode == SETUP_MODE_MAIN)
4305 setup_info = setup_info_main;
4306 title_string = "Setup";
4308 else if (setup_mode == SETUP_MODE_GAME)
4310 setup_info = setup_info_game;
4311 title_string = "Setup Game";
4313 else if (setup_mode == SETUP_MODE_EDITOR)
4315 setup_info = setup_info_editor;
4316 title_string = "Setup Editor";
4318 else if (setup_mode == SETUP_MODE_GRAPHICS)
4320 setup_info = setup_info_graphics;
4321 title_string = "Setup Graphics";
4323 else if (setup_mode == SETUP_MODE_SOUND)
4325 setup_info = setup_info_sound;
4326 title_string = "Setup Sound";
4328 else if (setup_mode == SETUP_MODE_ARTWORK)
4330 setup_info = setup_info_artwork;
4331 title_string = "Custom Artwork";
4333 else if (setup_mode == SETUP_MODE_SHORTCUT_1)
4335 setup_info = setup_info_shortcut_1;
4336 title_string = "Setup Shortcuts";
4338 else if (setup_mode == SETUP_MODE_SHORTCUT_2)
4340 setup_info = setup_info_shortcut_2;
4341 title_string = "Setup Shortcuts";
4344 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
4347 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
4349 void *value_ptr = setup_info[i].value;
4352 int xpos = MENU_SCREEN_START_XPOS;
4353 int ypos = MENU_SCREEN_START_YPOS + i;
4357 /* set some entries to "unchangeable" according to other variables */
4358 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
4359 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
4360 (value_ptr == &setup.sound_music && !audio.music_available) ||
4361 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
4362 (value_ptr == &screen_mode_text && !video.fullscreen_available))
4363 setup_info[i].type |= TYPE_GHOSTED;
4365 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
4366 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
4367 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
4368 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
4369 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
4370 initCursor(i, IMG_MENU_BUTTON);
4373 DrawCursorAndText_Setup(i, FALSE);
4375 font_nr = getSetupTextFont(setup_info[i].type);
4377 DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[i].text, font_nr);
4380 if (setup_info[i].type & TYPE_VALUE)
4387 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
4388 "Joysticks deactivated in setup menu");
4393 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
4396 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
4398 static int choice_store[MAX_SETUP_MODES];
4399 int choice = choice_store[setup_mode]; /* always starts with 0 */
4403 if (button == MB_MENU_INITIALIZE)
4405 /* advance to first valid menu entry */
4406 while (choice < num_setup_info &&
4407 setup_info[choice].type & TYPE_SKIP_ENTRY)
4409 choice_store[setup_mode] = choice;
4412 DrawCursorAndText_Setup(choice, TRUE);
4414 drawCursor(choice, TRUE);
4419 else if (button == MB_MENU_LEAVE)
4421 PlaySound(SND_MENU_ITEM_SELECTING);
4423 for (y = 0; y < num_setup_info; y++)
4425 if (setup_info[y].type & TYPE_LEAVE_MENU)
4427 void (*menu_callback_function)(void) = setup_info[y].value;
4429 menu_callback_function();
4431 break; /* absolutely needed because function changes 'setup_info'! */
4438 if (mx || my) /* mouse input */
4440 x = (mx - mSX) / 32;
4441 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
4443 else if (dx || dy) /* keyboard input */
4447 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
4449 if (setup_info[choice].type & menu_navigation_type ||
4450 setup_info[choice].type & TYPE_BOOLEAN_STYLE)
4451 button = MB_MENU_CHOICE;
4456 /* jump to next non-empty menu entry (up or down) */
4457 while (y > 0 && y < num_setup_info - 1 &&
4458 setup_info[y].type & TYPE_SKIP_ENTRY)
4462 if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_setup_info)
4466 if (y != choice && setup_info[y].type & ~TYPE_SKIP_ENTRY)
4468 PlaySound(SND_MENU_ITEM_ACTIVATING);
4471 DrawCursorAndText_Setup(choice, FALSE);
4472 DrawCursorAndText_Setup(y, TRUE);
4474 drawCursor(choice, FALSE);
4475 drawCursor(y, TRUE);
4478 choice = choice_store[setup_mode] = y;
4481 else if (!(setup_info[y].type & TYPE_GHOSTED))
4483 PlaySound(SND_MENU_ITEM_SELECTING);
4485 /* when selecting key headline, execute function for key value change */
4486 if (setup_info[y].type & TYPE_KEYTEXT &&
4487 setup_info[y + 1].type & TYPE_KEY)
4490 /* when selecting string value, execute function for list selection */
4491 if (setup_info[y].type & TYPE_STRING && y > 0 &&
4492 setup_info[y - 1].type & TYPE_ENTER_LIST)
4495 if (setup_info[y].type & TYPE_ENTER_OR_LEAVE)
4497 void (*menu_callback_function)(void) = setup_info[y].value;
4499 menu_callback_function();
4503 if (setup_info[y].type & TYPE_VALUE)
4504 changeSetupValue(y);
4510 void DrawSetupScreen_Input()
4519 setup_info = setup_info_input;
4522 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input");
4525 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
4527 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
4528 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
4529 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
4530 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
4531 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
4532 initCursor(i, IMG_MENU_BUTTON);
4534 DrawCursorAndText_Setup(i, FALSE);
4537 initCursor(0, IMG_MENU_BUTTON);
4538 initCursor(1, IMG_MENU_BUTTON);
4539 initCursor(2, IMG_MENU_BUTTON_ENTER_MENU);
4540 initCursor(13, IMG_MENU_BUTTON_LEAVE_MENU);
4542 DrawText(mSX + 32, mSY + 2 * 32, "Player:", FONT_MENU_1);
4543 DrawText(mSX + 32, mSY + 3 * 32, "Device:", FONT_MENU_1);
4544 DrawText(mSX + 32, mSY + 15 * 32, "Back", FONT_MENU_1);
4548 DeactivateJoystickForCalibration();
4551 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
4552 "Joysticks deactivated on this screen");
4555 /* create gadgets for setup input menu screen */
4556 FreeScreenGadgets();
4557 CreateScreenGadgets();
4559 /* map gadgets for setup input menu screen */
4560 MapScreenMenuGadgets(SCREEN_MASK_INPUT);
4562 HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE);
4567 static void setJoystickDeviceToNr(char *device_name, int device_nr)
4569 if (device_name == NULL)
4572 if (device_nr < 0 || device_nr >= MAX_PLAYERS)
4575 if (strlen(device_name) > 1)
4577 char c1 = device_name[strlen(device_name) - 1];
4578 char c2 = device_name[strlen(device_name) - 2];
4580 if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9'))
4581 device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
4584 strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
4585 strlen(device_name));
4588 static void drawPlayerSetupInputInfo(int player_nr, boolean active)
4591 static struct SetupKeyboardInfo custom_key;
4598 { &custom_key.left, "Joystick Left" },
4599 { &custom_key.right, "Joystick Right" },
4600 { &custom_key.up, "Joystick Up" },
4601 { &custom_key.down, "Joystick Down" },
4602 { &custom_key.snap, "Button 1" },
4603 { &custom_key.drop, "Button 2" }
4605 static char *joystick_name[MAX_PLAYERS] =
4612 int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1);
4616 custom_key = setup.input[player_nr].key;
4618 DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
4619 FONT_INPUT_1_ACTIVE);
4621 ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
4623 DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
4624 PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
4626 if (setup.input[player_nr].use_joystick)
4628 char *device_name = setup.input[player_nr].joy.device_name;
4629 char *text = joystick_name[getJoystickNrFromDeviceName(device_name)];
4630 int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1);
4632 DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
4633 DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr);
4637 DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1);
4638 DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr);
4641 DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1);
4643 drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
4644 drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
4645 drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
4646 drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
4648 DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD);
4649 DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD);
4650 DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD);
4651 DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD);
4652 DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD);
4653 DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD);
4655 for (i = 0; i < 6; i++)
4657 int ypos = 6 + i + (i > 3 ? i-3 : 0);
4659 DrawText(mSX + 3 * 32, mSY + ypos * 32,
4661 DrawText(mSX + 3 * 32, mSY + ypos * 32,
4662 (setup.input[player_nr].use_joystick ?
4664 getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
4668 static int input_player_nr = 0;
4670 void HandleSetupScreen_Input_Player(int step, int direction)
4672 int old_player_nr = input_player_nr;
4675 new_player_nr = old_player_nr + step * direction;
4676 if (new_player_nr < 0)
4678 if (new_player_nr > MAX_PLAYERS - 1)
4679 new_player_nr = MAX_PLAYERS - 1;
4681 if (new_player_nr != old_player_nr)
4683 input_player_nr = new_player_nr;
4685 drawPlayerSetupInputInfo(input_player_nr, FALSE);
4689 void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
4691 static int choice = 0;
4694 int pos_start = SETUPINPUT_SCREEN_POS_START;
4695 int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1;
4696 int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2;
4697 int pos_end = SETUPINPUT_SCREEN_POS_END;
4699 if (button == MB_MENU_INITIALIZE)
4701 drawPlayerSetupInputInfo(input_player_nr, (choice == 2));
4704 DrawCursorAndText_Setup(choice, TRUE);
4706 drawCursor(choice, TRUE);
4711 else if (button == MB_MENU_LEAVE)
4713 setup_mode = SETUP_MODE_MAIN;
4720 if (mx || my) /* mouse input */
4722 x = (mx - mSX) / 32;
4723 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
4725 else if (dx || dy) /* keyboard input */
4727 if (dx && choice == 0)
4728 x = (dx < 0 ? 10 : 12);
4729 else if ((dx && choice == 1) ||
4730 (dx == +1 && choice == 2) ||
4731 (dx == -1 && choice == pos_end))
4732 button = MB_MENU_CHOICE;
4736 if (y >= pos_empty1 && y <= pos_empty2)
4737 y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
4740 if (y == 0 && dx != 0 && button)
4742 HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1);
4744 else if (IN_VIS_FIELD(x, y) &&
4745 y >= pos_start && y <= pos_end &&
4746 !(y >= pos_empty1 && y <= pos_empty2))
4753 DrawCursorAndText_Setup(choice, FALSE);
4754 DrawCursorAndText_Setup(y, TRUE);
4756 drawPlayerSetupInputInfo(input_player_nr, (y == 2));
4758 drawCursor(choice, FALSE);
4759 drawCursor(y, TRUE);
4769 char *device_name = setup.input[input_player_nr].joy.device_name;
4771 if (!setup.input[input_player_nr].use_joystick)
4773 int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1);
4775 setJoystickDeviceToNr(device_name, new_device_nr);
4776 setup.input[input_player_nr].use_joystick = TRUE;
4780 int device_nr = getJoystickNrFromDeviceName(device_name);
4781 int new_device_nr = device_nr + (dx >= 0 ? +1 : -1);
4783 if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS)
4784 setup.input[input_player_nr].use_joystick = FALSE;
4786 setJoystickDeviceToNr(device_name, new_device_nr);
4789 drawPlayerSetupInputInfo(input_player_nr, FALSE);
4793 if (setup.input[input_player_nr].use_joystick)
4796 CalibrateJoystick(input_player_nr);
4799 CustomizeKeyboard(input_player_nr);
4801 else if (y == pos_end)
4805 setup_mode = SETUP_MODE_MAIN;
4812 void CustomizeKeyboard(int player_nr)
4816 boolean finished = FALSE;
4817 static struct SetupKeyboardInfo custom_key;
4822 } customize_step[] =
4824 { &custom_key.left, "Move Left" },
4825 { &custom_key.right, "Move Right" },
4826 { &custom_key.up, "Move Up" },
4827 { &custom_key.down, "Move Down" },
4828 { &custom_key.snap, "Snap Field" },
4829 { &custom_key.drop, "Drop Element" }
4832 /* read existing key bindings from player setup */
4833 custom_key = setup.input[player_nr].key;
4837 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input");
4843 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
4844 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
4845 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
4846 "Key:", FONT_INPUT_1_ACTIVE);
4847 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4848 getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
4852 if (PendingEvent()) /* got event */
4860 case EVENT_KEYPRESS:
4862 Key key = GetEventKey((KeyEvent *)&event, FALSE);
4864 if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
4870 /* all keys configured -- wait for "Escape" or "Return" key */
4874 /* press 'Enter' to keep the existing key binding */
4875 if (key == KSYM_Return)
4876 key = *customize_step[step_nr].key;
4878 /* check if key already used */
4879 for (i = 0; i < step_nr; i++)
4880 if (*customize_step[i].key == key)
4885 /* got new key binding */
4886 *customize_step[step_nr].key = key;
4887 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4889 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4890 getKeyNameFromKey(key), FONT_VALUE_1);
4893 /* un-highlight last query */
4894 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32,
4895 customize_step[step_nr - 1].text, FONT_MENU_1);
4896 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32,
4897 "Key:", FONT_MENU_1);
4899 /* press 'Enter' to leave */
4902 DrawText(mSX + 16, mSY + 15 * 32 + 16,
4903 "Press Enter", FONT_TITLE_1);
4907 /* query next key binding */
4908 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
4909 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
4910 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
4911 "Key:", FONT_INPUT_1_ACTIVE);
4912 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4913 getKeyNameFromKey(*customize_step[step_nr].key),
4918 case EVENT_KEYRELEASE:
4919 key_joystick_mapping = 0;
4923 HandleOtherEvents(&event);
4931 /* don't eat all CPU time */
4935 /* write new key bindings back to player setup */
4936 setup.input[player_nr].key = custom_key;
4939 DrawSetupScreen_Input();
4942 static boolean CalibrateJoystickMain(int player_nr)
4944 int new_joystick_xleft = JOYSTICK_XMIDDLE;
4945 int new_joystick_xright = JOYSTICK_XMIDDLE;
4946 int new_joystick_yupper = JOYSTICK_YMIDDLE;
4947 int new_joystick_ylower = JOYSTICK_YMIDDLE;
4948 int new_joystick_xmiddle, new_joystick_ymiddle;
4950 int joystick_fd = joystick.fd[player_nr];
4951 int x, y, last_x, last_y, xpos = 8, ypos = 3;
4952 boolean check[3][3];
4953 int check_remaining = 3 * 3;
4958 if (joystick.status == JOYSTICK_NOT_AVAILABLE)
4961 if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
4966 for (y = 0; y < 3; y++)
4968 for (x = 0; x < 3; x++)
4970 DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
4971 check[x][y] = FALSE;
4975 DrawTextSCentered(mSY - SY + 6 * 32, FONT_TITLE_1, "Rotate joystick");
4976 DrawTextSCentered(mSY - SY + 7 * 32, FONT_TITLE_1, "in all directions");
4977 DrawTextSCentered(mSY - SY + 9 * 32, FONT_TITLE_1, "if all balls");
4978 DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,");
4979 DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick");
4980 DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and");
4981 DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!");
4983 joy_value = Joystick(player_nr);
4984 last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
4985 last_y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
4987 /* eventually uncalibrated center position (joystick could be uncentered) */
4988 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
4991 new_joystick_xmiddle = joy_x;
4992 new_joystick_ymiddle = joy_y;
4994 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
4997 while (Joystick(player_nr) & JOY_BUTTON); /* wait for released button */
5002 if (PendingEvent()) /* got event */
5010 case EVENT_KEYPRESS:
5011 switch (GetEventKey((KeyEvent *)&event, TRUE))
5014 if (check_remaining == 0)
5027 case EVENT_KEYRELEASE:
5028 key_joystick_mapping = 0;
5032 HandleOtherEvents(&event);
5037 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
5040 new_joystick_xleft = MIN(new_joystick_xleft, joy_x);
5041 new_joystick_xright = MAX(new_joystick_xright, joy_x);
5042 new_joystick_yupper = MIN(new_joystick_yupper, joy_y);
5043 new_joystick_ylower = MAX(new_joystick_ylower, joy_y);
5045 setup.input[player_nr].joy.xleft = new_joystick_xleft;
5046 setup.input[player_nr].joy.yupper = new_joystick_yupper;
5047 setup.input[player_nr].joy.xright = new_joystick_xright;
5048 setup.input[player_nr].joy.ylower = new_joystick_ylower;
5049 setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle;
5050 setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle;
5052 CheckJoystickData();
5054 joy_value = Joystick(player_nr);
5056 if (joy_value & JOY_BUTTON && check_remaining == 0)
5059 x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
5060 y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
5062 if (x != last_x || y != last_y)
5064 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0);
5065 DrawGraphic(xpos + x, ypos + y, IMG_MENU_CALIBRATE_RED, 0);
5070 if (check_remaining > 0 && !check[x+1][y+1])
5072 check[x+1][y+1] = TRUE;
5078 printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
5079 setup.input[player_nr].joy.xleft,
5080 setup.input[player_nr].joy.xmiddle,
5081 setup.input[player_nr].joy.xright);
5082 printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
5083 setup.input[player_nr].joy.yupper,
5084 setup.input[player_nr].joy.ymiddle,
5085 setup.input[player_nr].joy.ylower);
5094 /* don't eat all CPU time */
5098 /* calibrated center position (joystick should now be centered) */
5099 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
5102 new_joystick_xmiddle = joy_x;
5103 new_joystick_ymiddle = joy_y;
5108 DrawSetupScreen_Input();
5111 /* wait until the last pressed button was released */
5112 while (Joystick(player_nr) & JOY_BUTTON)
5114 if (PendingEvent()) /* got event */
5119 HandleOtherEvents(&event);
5128 void CalibrateJoystick(int player_nr)
5130 if (!CalibrateJoystickMain(player_nr))
5132 char *device_name = setup.input[player_nr].joy.device_name;
5133 int nr = getJoystickNrFromDeviceName(device_name) + 1;
5134 int xpos = mSX - SX;
5135 int ypos = mSY - SY;
5139 DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr);
5140 DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! ");
5143 Delay(2000); /* show error message for a short time */
5149 DrawSetupScreen_Input();
5153 void DrawSetupScreen()
5155 DeactivateJoystick();
5157 SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
5159 if (setup_mode == SETUP_MODE_INPUT)
5160 DrawSetupScreen_Input();
5161 else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
5162 DrawChooseTree(&game_speed_current);
5163 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
5164 DrawChooseTree(&screen_mode_current);
5165 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
5166 DrawChooseTree(&artwork.gfx_current);
5167 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
5168 DrawChooseTree(&artwork.snd_current);
5169 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
5170 DrawChooseTree(&artwork.mus_current);
5172 DrawSetupScreen_Generic();
5178 void RedrawSetupScreenAfterFullscreenToggle()
5180 if (setup_mode == SETUP_MODE_GRAPHICS)
5184 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
5186 if (setup_mode == SETUP_MODE_INPUT)
5187 HandleSetupScreen_Input(mx, my, dx, dy, button);
5188 else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
5189 HandleChooseTree(mx, my, dx, dy, button, &game_speed_current);
5190 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
5191 HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
5192 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
5193 HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
5194 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
5195 HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
5196 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
5197 HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
5199 HandleSetupScreen_Generic(mx, my, dx, dy, button);
5204 void HandleGameActions()
5206 if (game_status != GAME_MODE_PLAYING)
5209 GameActions(); /* main game loop */
5211 if (tape.auto_play && !tape.playing)
5212 AutoPlayTape(); /* continue automatically playing next tape */
5216 /* ---------- new screen button stuff -------------------------------------- */
5218 static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
5223 case SCREEN_CTRL_ID_PREV_LEVEL:
5224 *x = mSX + menu.main.button.prev_level.x;
5225 *y = mSY + menu.main.button.prev_level.y;
5228 case SCREEN_CTRL_ID_NEXT_LEVEL:
5229 *x = mSX + menu.main.button.next_level.x;
5230 *y = mSY + menu.main.button.next_level.y;
5233 case SCREEN_CTRL_ID_PREV_LEVEL:
5234 *x = mSX + TILEX * getPrevlevelButtonPos();
5235 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
5238 case SCREEN_CTRL_ID_NEXT_LEVEL:
5239 *x = mSX + TILEX * getNextLevelButtonPos();
5240 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
5244 case SCREEN_CTRL_ID_PREV_PLAYER:
5245 *x = mSX + TILEX * 10;
5246 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
5249 case SCREEN_CTRL_ID_NEXT_PLAYER:
5250 *x = mSX + TILEX * 12;
5251 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
5255 Error(ERR_EXIT, "unknown gadget ID %d", gadget_id);
5261 int gfx_unpressed, gfx_pressed;
5262 void (*get_gadget_position)(int *, int *, int);
5266 } menubutton_info[NUM_SCREEN_MENUBUTTONS] =
5269 IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE,
5270 getScreenMenuButtonPos,
5271 SCREEN_CTRL_ID_PREV_LEVEL,
5276 IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE,
5277 getScreenMenuButtonPos,
5278 SCREEN_CTRL_ID_NEXT_LEVEL,
5283 IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE,
5284 getScreenMenuButtonPos,
5285 SCREEN_CTRL_ID_PREV_PLAYER,
5290 IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE,
5291 getScreenMenuButtonPos,
5292 SCREEN_CTRL_ID_NEXT_PLAYER,
5300 int gfx_unpressed, gfx_pressed;
5304 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
5307 IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
5308 SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
5309 SCREEN_CTRL_ID_SCROLL_UP,
5313 IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
5314 SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
5315 SCREEN_CTRL_ID_SCROLL_DOWN,
5322 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5323 Bitmap **gfx_unpressed, **gfx_pressed;
5325 int gfx_unpressed, gfx_pressed;
5332 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
5335 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5336 &scrollbar_bitmap[0], &scrollbar_bitmap[1],
5338 IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
5340 SC_SCROLL_VERTICAL_XPOS, SC_SCROLL_VERTICAL_YPOS,
5341 SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
5342 GD_TYPE_SCROLLBAR_VERTICAL,
5343 SCREEN_CTRL_ID_SCROLL_VERTICAL,
5344 "scroll level series vertically"
5348 static void CreateScreenMenubuttons()
5350 struct GadgetInfo *gi;
5351 unsigned long event_mask;
5354 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
5356 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5357 int gfx_unpressed, gfx_pressed;
5358 int x, y, width, height;
5359 int gd_x1, gd_x2, gd_y1, gd_y2;
5360 int id = menubutton_info[i].gadget_id;
5362 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5364 menubutton_info[i].get_gadget_position(&x, &y, id);
5366 width = SC_MENUBUTTON_XSIZE;
5367 height = SC_MENUBUTTON_YSIZE;
5369 gfx_unpressed = menubutton_info[i].gfx_unpressed;
5370 gfx_pressed = menubutton_info[i].gfx_pressed;
5371 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5372 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5373 gd_x1 = graphic_info[gfx_unpressed].src_x;
5374 gd_y1 = graphic_info[gfx_unpressed].src_y;
5375 gd_x2 = graphic_info[gfx_pressed].src_x;
5376 gd_y2 = graphic_info[gfx_pressed].src_y;
5378 gi = CreateGadget(GDI_CUSTOM_ID, id,
5379 GDI_CUSTOM_TYPE_ID, i,
5380 GDI_INFO_TEXT, menubutton_info[i].infotext,
5385 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5386 GDI_STATE, GD_BUTTON_UNPRESSED,
5387 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5388 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5389 GDI_DIRECT_DRAW, FALSE,
5390 GDI_EVENT_MASK, event_mask,
5391 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5395 Error(ERR_EXIT, "cannot create gadget");
5397 screen_gadget[id] = gi;
5401 static void CreateScreenScrollbuttons()
5403 struct GadgetInfo *gi;
5404 unsigned long event_mask;
5407 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
5409 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5410 int gfx_unpressed, gfx_pressed;
5411 int x, y, width, height;
5412 int gd_x1, gd_x2, gd_y1, gd_y2;
5413 int id = scrollbutton_info[i].gadget_id;
5415 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5417 x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset;
5418 y = mSY + scrollbutton_info[i].y;
5419 width = SC_SCROLLBUTTON_XSIZE;
5420 height = SC_SCROLLBUTTON_YSIZE;
5422 if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
5423 y = mSY + (SC_SCROLL_VERTICAL_YPOS +
5424 (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE);
5426 gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
5427 gfx_pressed = scrollbutton_info[i].gfx_pressed;
5428 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5429 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5430 gd_x1 = graphic_info[gfx_unpressed].src_x;
5431 gd_y1 = graphic_info[gfx_unpressed].src_y;
5432 gd_x2 = graphic_info[gfx_pressed].src_x;
5433 gd_y2 = graphic_info[gfx_pressed].src_y;
5435 gi = CreateGadget(GDI_CUSTOM_ID, id,
5436 GDI_CUSTOM_TYPE_ID, i,
5437 GDI_INFO_TEXT, scrollbutton_info[i].infotext,
5442 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5443 GDI_STATE, GD_BUTTON_UNPRESSED,
5444 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5445 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5446 GDI_DIRECT_DRAW, FALSE,
5447 GDI_EVENT_MASK, event_mask,
5448 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5452 Error(ERR_EXIT, "cannot create gadget");
5454 screen_gadget[id] = gi;
5458 static void CreateScreenScrollbars()
5462 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
5464 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5465 #if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5466 int gfx_unpressed, gfx_pressed;
5468 int x, y, width, height;
5469 int gd_x1, gd_x2, gd_y1, gd_y2;
5470 struct GadgetInfo *gi;
5471 int items_max, items_visible, item_position;
5472 unsigned long event_mask;
5473 int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
5474 int id = scrollbar_info[i].gadget_id;
5476 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
5478 x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset;
5479 y = mSY + scrollbar_info[i].y;
5480 width = scrollbar_info[i].width;
5481 height = scrollbar_info[i].height;
5483 if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
5484 height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;
5486 items_max = num_page_entries;
5487 items_visible = num_page_entries;
5490 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5491 gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
5492 gd_bitmap_pressed = *scrollbar_info[i].gfx_pressed;
5498 gfx_unpressed = scrollbar_info[i].gfx_unpressed;
5499 gfx_pressed = scrollbar_info[i].gfx_pressed;
5500 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5501 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5502 gd_x1 = graphic_info[gfx_unpressed].src_x;
5503 gd_y1 = graphic_info[gfx_unpressed].src_y;
5504 gd_x2 = graphic_info[gfx_pressed].src_x;
5505 gd_y2 = graphic_info[gfx_pressed].src_y;
5508 gi = CreateGadget(GDI_CUSTOM_ID, id,
5509 GDI_CUSTOM_TYPE_ID, i,
5510 GDI_INFO_TEXT, scrollbar_info[i].infotext,
5515 GDI_TYPE, scrollbar_info[i].type,
5516 GDI_SCROLLBAR_ITEMS_MAX, items_max,
5517 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
5518 GDI_SCROLLBAR_ITEM_POSITION, item_position,
5520 GDI_WHEEL_AREA_X, SX,
5521 GDI_WHEEL_AREA_Y, SY,
5522 GDI_WHEEL_AREA_WIDTH, SXSIZE,
5523 GDI_WHEEL_AREA_HEIGHT, SYSIZE,
5525 GDI_WHEEL_AREA_X, 0,
5526 GDI_WHEEL_AREA_Y, 0,
5527 GDI_WHEEL_AREA_WIDTH, WIN_XSIZE,
5528 GDI_WHEEL_AREA_HEIGHT, WIN_YSIZE,
5530 GDI_STATE, GD_BUTTON_UNPRESSED,
5531 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5532 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5533 GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
5534 GDI_DIRECT_DRAW, FALSE,
5535 GDI_EVENT_MASK, event_mask,
5536 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5540 Error(ERR_EXIT, "cannot create gadget");
5542 screen_gadget[id] = gi;
5546 void CreateScreenGadgets()
5548 int last_game_status = game_status; /* save current game status */
5550 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5553 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
5555 scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
5557 /* copy pointers to clip mask and GC */
5558 scrollbar_bitmap[i]->clip_mask =
5559 graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
5560 scrollbar_bitmap[i]->stored_clip_gc =
5561 graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
5563 BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
5564 scrollbar_bitmap[i],
5565 graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
5566 graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
5567 TILEX, TILEY, 0, 0);
5571 CreateScreenMenubuttons();
5573 /* force LEVELS draw offset for scrollbar / scrollbutton gadgets */
5574 game_status = GAME_MODE_LEVELS;
5576 CreateScreenScrollbuttons();
5577 CreateScreenScrollbars();
5579 game_status = last_game_status; /* restore current game status */
5582 void FreeScreenGadgets()
5586 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5587 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
5589 /* prevent freeing clip mask and GC twice */
5590 scrollbar_bitmap[i]->clip_mask = None;
5591 scrollbar_bitmap[i]->stored_clip_gc = None;
5593 FreeBitmap(scrollbar_bitmap[i]);
5597 for (i = 0; i < NUM_SCREEN_GADGETS; i++)
5598 FreeGadget(screen_gadget[i]);
5601 void MapScreenMenuGadgets(int screen_mask)
5605 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
5606 if (screen_mask & menubutton_info[i].screen_mask)
5607 MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
5610 void MapScreenTreeGadgets(TreeInfo *ti)
5612 int num_entries = numTreeInfoInGroup(ti);
5615 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
5618 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
5619 MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
5621 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
5622 MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
5625 static void HandleScreenGadgets(struct GadgetInfo *gi)
5627 int id = gi->custom_id;
5628 int button = gi->event.button;
5629 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
5633 case SCREEN_CTRL_ID_PREV_LEVEL:
5634 HandleMainMenu_SelectLevel(step, -1);
5637 case SCREEN_CTRL_ID_NEXT_LEVEL:
5638 HandleMainMenu_SelectLevel(step, +1);
5641 case SCREEN_CTRL_ID_PREV_PLAYER:
5642 HandleSetupScreen_Input_Player(step, -1);
5645 case SCREEN_CTRL_ID_NEXT_PLAYER:
5646 HandleSetupScreen_Input_Player(step, +1);
5649 case SCREEN_CTRL_ID_SCROLL_UP:
5650 if (game_status == GAME_MODE_LEVELS)
5651 HandleChooseLevel(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
5652 else if (game_status == GAME_MODE_SETUP)
5653 HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
5656 case SCREEN_CTRL_ID_SCROLL_DOWN:
5657 if (game_status == GAME_MODE_LEVELS)
5658 HandleChooseLevel(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
5659 else if (game_status == GAME_MODE_SETUP)
5660 HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
5663 case SCREEN_CTRL_ID_SCROLL_VERTICAL:
5664 if (game_status == GAME_MODE_LEVELS)
5665 HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
5666 else if (game_status == GAME_MODE_SETUP)
5667 HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);