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"
27 /* screens in the setup menu */
28 #define SETUP_MODE_MAIN 0
29 #define SETUP_MODE_GAME 1
30 #define SETUP_MODE_EDITOR 2
31 #define SETUP_MODE_INPUT 3
32 #define SETUP_MODE_SHORTCUT_1 4
33 #define SETUP_MODE_SHORTCUT_2 5
34 #define SETUP_MODE_GRAPHICS 6
35 #define SETUP_MODE_CHOOSE_SCREEN_MODE 7
36 #define SETUP_MODE_SOUND 8
37 #define SETUP_MODE_ARTWORK 9
38 #define SETUP_MODE_CHOOSE_GRAPHICS 10
39 #define SETUP_MODE_CHOOSE_SOUNDS 11
40 #define SETUP_MODE_CHOOSE_MUSIC 12
42 #define MAX_SETUP_MODES 13
44 /* for input setup functions */
45 #define SETUPINPUT_SCREEN_POS_START 0
46 #define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4)
47 #define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3)
48 #define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1)
50 /* screens on the info screen */
51 #define INFO_MODE_MAIN 0
52 #define INFO_MODE_TITLE 1
53 #define INFO_MODE_ELEMENTS 2
54 #define INFO_MODE_MUSIC 3
55 #define INFO_MODE_CREDITS 4
56 #define INFO_MODE_PROGRAM 5
57 #define INFO_MODE_LEVELSET 6
59 #define MAX_INFO_MODES 7
61 /* for various menu stuff */
62 #define MENU_SCREEN_START_XPOS 1
63 #define MENU_SCREEN_START_YPOS 2
64 #define MENU_SCREEN_VALUE_XPOS 14
65 #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1)
66 #define MENU_TITLE1_YPOS 8
67 #define MENU_TITLE2_YPOS 46
68 #define MAX_INFO_ELEMENTS_ON_SCREEN 10
69 #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS)
70 #define MAX_MENU_TEXT_LENGTH_BIG (MENU_SCREEN_VALUE_XPOS - \
71 MENU_SCREEN_START_XPOS)
72 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2)
74 /* buttons and scrollbars identifiers */
75 #define SCREEN_CTRL_ID_PREV_LEVEL 0
76 #define SCREEN_CTRL_ID_NEXT_LEVEL 1
77 #define SCREEN_CTRL_ID_PREV_PLAYER 2
78 #define SCREEN_CTRL_ID_NEXT_PLAYER 3
79 #define SCREEN_CTRL_ID_SCROLL_UP 4
80 #define SCREEN_CTRL_ID_SCROLL_DOWN 5
81 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 6
83 #define NUM_SCREEN_GADGETS 7
85 #define NUM_SCREEN_MENUBUTTONS 4
86 #define NUM_SCREEN_SCROLLBUTTONS 2
87 #define NUM_SCREEN_SCROLLBARS 1
89 #define SCREEN_MASK_MAIN (1 << 0)
90 #define SCREEN_MASK_INPUT (1 << 1)
92 /* graphic position and size values for buttons and scrollbars */
93 #define SC_MENUBUTTON_XSIZE TILEX
94 #define SC_MENUBUTTON_YSIZE TILEY
96 #define SC_SCROLLBUTTON_XSIZE TILEX
97 #define SC_SCROLLBUTTON_YSIZE TILEY
99 #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
101 #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
102 #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
103 SC_SCROLLBUTTON_YSIZE)
105 #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS
106 #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE)
108 #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS
109 #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \
110 SC_SCROLLBUTTON_YSIZE)
112 #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS
113 #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \
114 SC_SCROLL_VERTICAL_YSIZE)
116 #define SC_BORDER_SIZE 14
118 /* other useful macro definitions */
119 #define BUTTON_GRAPHIC_ACTIVE(g) \
120 (g == IMG_MENU_BUTTON_LEFT ? IMG_MENU_BUTTON_LEFT_ACTIVE : \
121 g == IMG_MENU_BUTTON_RIGHT ? IMG_MENU_BUTTON_RIGHT_ACTIVE : \
122 g == IMG_MENU_BUTTON_UP ? IMG_MENU_BUTTON_UP_ACTIVE : \
123 g == IMG_MENU_BUTTON_DOWN ? IMG_MENU_BUTTON_DOWN_ACTIVE : \
124 g == IMG_MENU_BUTTON_LEAVE_MENU ? IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE : \
125 g == IMG_MENU_BUTTON_ENTER_MENU ? IMG_MENU_BUTTON_ENTER_MENU_ACTIVE : \
126 g == IMG_MENU_BUTTON_PREV_LEVEL ? IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE : \
127 g == IMG_MENU_BUTTON_NEXT_LEVEL ? IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE : \
128 IMG_MENU_BUTTON_ACTIVE)
131 /* forward declarations of internal functions */
132 static void HandleScreenGadgets(struct GadgetInfo *);
133 static void HandleSetupScreen_Generic(int, int, int, int, int);
134 static void HandleSetupScreen_Input(int, int, int, int, int);
135 static void CustomizeKeyboard(int);
136 static void CalibrateJoystick(int);
137 static void execSetupGraphics(void);
138 static void execSetupArtwork(void);
139 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
141 static void DrawChooseLevel(void);
142 static void DrawInfoScreen(void);
143 static void DrawAndFadeInInfoScreen(int);
144 static void DrawSetupScreen(void);
146 static void DrawInfoScreenExt(int, int);
147 static void DrawInfoScreen_NotAvailable(char *, char *);
148 static void DrawInfoScreen_HelpAnim(int, int, boolean);
149 static void DrawInfoScreen_HelpText(int, int, int, int);
150 static void HandleInfoScreen_Main(int, int, int, int, int);
151 static void HandleInfoScreen_TitleScreen(int);
152 static void HandleInfoScreen_Elements(int);
153 static void HandleInfoScreen_Music(int);
154 static void HandleInfoScreen_Credits(int);
155 static void HandleInfoScreen_Program(int);
157 static void MapScreenMenuGadgets(int);
158 static void MapScreenTreeGadgets(TreeInfo *);
160 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
162 static boolean show_titlescreen_initial = TRUE;
164 static int setup_mode = SETUP_MODE_MAIN;
165 static int info_mode = INFO_MODE_MAIN;
167 static TreeInfo *screen_modes = NULL;
168 static TreeInfo *screen_mode_current = NULL;
170 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
171 (s) <= GAME_MODE_SETUP ? (s) : \
172 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
173 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
175 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_ELEMENTS && \
176 (i) <= INFO_MODE_LEVELSET ? (i) : \
179 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
180 menu.draw_xoffset[GAME_MODE_INFO] : \
181 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
182 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
183 menu.draw_yoffset[GAME_MODE_INFO] : \
184 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
186 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
187 DRAW_XOFFSET_INFO(info_mode) : \
188 menu.draw_xoffset[DRAW_MODE(s)])
189 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
190 DRAW_YOFFSET_INFO(info_mode) : \
191 menu.draw_yoffset[DRAW_MODE(s)])
193 #define mSX (SX + DRAW_XOFFSET(game_status))
194 #define mSY (SY + DRAW_YOFFSET(game_status))
196 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
197 menu.list_size[game_status] : \
198 MAX_MENU_ENTRIES_ON_SCREEN)
200 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
201 #define NUM_SCROLLBAR_BITMAPS 2
202 static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
206 #define MAIN_CONTROL_NAME 0
207 #define MAIN_CONTROL_LEVELS 1
208 #define MAIN_CONTROL_SCORES 2
209 #define MAIN_CONTROL_EDITOR 3
210 #define MAIN_CONTROL_INFO 4
211 #define MAIN_CONTROL_GAME 5
212 #define MAIN_CONTROL_SETUP 6
213 #define MAIN_CONTROL_QUIT 7
214 #define MAIN_CONTROL_PREV_LEVEL 8
215 #define MAIN_CONTROL_NEXT_LEVEL 9
216 #define MAIN_CONTROL_CURRENT_LEVEL 10
217 #define MAIN_CONTROL_FIRST_LEVEL 11
218 #define MAIN_CONTROL_LAST_LEVEL 12
219 #define MAIN_CONTROL_LEVEL_INFO_1 13
220 #define MAIN_CONTROL_LEVEL_INFO_2 14
221 #define MAIN_CONTROL_TITLE_1 15
222 #define MAIN_CONTROL_TITLE_2 16
223 #define MAIN_CONTROL_TITLE_3 17
225 static char main_text_name[10];
226 static char main_text_current_level[10];
227 static char main_text_first_level[10];
228 static char main_text_last_level[10];
229 static char main_input_name[MAX_PLAYER_NAME_LEN + 1];
231 struct MainControlInfo
235 struct MenuPosInfo *pos_button;
238 struct MenuPosInfo *pos_text;
242 struct MenuPosInfo *pos_input;
247 static struct MainControlInfo main_controls[] =
251 &menu.main.button.name, IMG_MENU_BUTTON,
252 &menu.main.text.name, main_text_name, FONT_MENU_1,
253 &menu.main.input.name, main_input_name, FONT_INPUT_1,
257 &menu.main.button.levels, IMG_MENU_BUTTON_ENTER_MENU,
258 &menu.main.text.levels, "Levelset", FONT_MENU_1,
263 &menu.main.button.scores, IMG_MENU_BUTTON,
264 &menu.main.text.scores, "Hall Of Fame", FONT_MENU_1,
269 &menu.main.button.editor, IMG_MENU_BUTTON,
270 &menu.main.text.editor, "Level Creator", FONT_MENU_1,
275 &menu.main.button.info, IMG_MENU_BUTTON_ENTER_MENU,
276 &menu.main.text.info, "Info Screen", FONT_MENU_1,
281 &menu.main.button.game, IMG_MENU_BUTTON,
282 &menu.main.text.game, "Start Game", FONT_MENU_1,
287 &menu.main.button.setup, IMG_MENU_BUTTON_ENTER_MENU,
288 &menu.main.text.setup, "Setup", FONT_MENU_1,
293 &menu.main.button.quit, IMG_MENU_BUTTON,
294 &menu.main.text.quit, "Quit", FONT_MENU_1,
298 /* (these two buttons are real gadgets) */
300 MAIN_CONTROL_PREV_LEVEL,
301 &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL,
306 MAIN_CONTROL_NEXT_LEVEL,
307 &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL,
313 MAIN_CONTROL_CURRENT_LEVEL,
315 &menu.main.text.current_level, main_text_current_level,FONT_VALUE_1,
319 MAIN_CONTROL_FIRST_LEVEL,
321 &menu.main.text.first_level, main_text_first_level, FONT_TEXT_3,
325 MAIN_CONTROL_LAST_LEVEL,
327 &menu.main.text.last_level, main_text_last_level, FONT_TEXT_3,
331 MAIN_CONTROL_LEVEL_INFO_1,
333 &menu.main.text.level_info_1, NULL, -1,
337 MAIN_CONTROL_LEVEL_INFO_2,
339 &menu.main.text.level_info_2, NULL, -1,
343 MAIN_CONTROL_TITLE_1,
345 &menu.main.text.title_1, PROGRAM_TITLE_STRING, FONT_TITLE_1,
349 MAIN_CONTROL_TITLE_2,
351 &menu.main.text.title_2, PROGRAM_COPYRIGHT_STRING, FONT_TITLE_2,
355 MAIN_CONTROL_TITLE_3,
357 &menu.main.text.title_3, PROGRAM_GAME_BY_STRING, FONT_TITLE_2,
370 static void InitializeMainControls()
372 boolean local_team_mode = (!options.network && setup.team_mode);
375 /* set main control text values to dynamically determined values */
376 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
377 sprintf(main_text_current_level, "%s", int2str(level_nr, 3));
378 sprintf(main_text_first_level, "%03d", leveldir_current->first_level);
379 sprintf(main_text_last_level, "%03d", leveldir_current->last_level);
380 sprintf(main_input_name, "%s", setup.player_name);
382 /* set main control screen positions to dynamically determined values */
383 for (i = 0; main_controls[i].nr != -1; i++)
385 struct MainControlInfo *mci = &main_controls[i];
387 struct MenuPosInfo *pos_button = mci->pos_button;
388 struct MenuPosInfo *pos_text = mci->pos_text;
389 struct MenuPosInfo *pos_input = mci->pos_input;
390 char *text = mci->text;
391 char *input = mci->input;
392 int button_graphic = mci->button_graphic;
393 int font_text = mci->font_text;
394 int font_input = mci->font_input;
396 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
397 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
398 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
399 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
400 int text_chars = (text != NULL ? strlen(text) : 0);
401 int input_chars = (input != NULL ? strlen(input) : 0);
404 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
406 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
407 int text_width = font_text_width * text_chars;
408 int text_height = font_text_height;
409 int input_width = font_input_width * input_chars;
410 int input_height = font_input_height;
412 if (nr == MAIN_CONTROL_NAME)
415 if (menu.main.input.name.x == -1)
416 menu.main.input.name.x = menu.main.text.name.x + text_width;
417 if (menu.main.input.name.y == -1)
418 menu.main.input.name.y = menu.main.text.name.y;
421 menu.main.input.name.width = font_input_width * MAX_PLAYER_NAME_LEN;
422 menu.main.input.name.height = font_input_height;
425 if (pos_button != NULL)
427 if (pos_button->width == 0)
428 pos_button->width = button_width;
429 if (pos_button->height == 0)
430 pos_button->height = button_height;
433 if (pos_text != NULL)
435 /* calculate width for non-clickable text -- needed for text alignment */
436 boolean calculate_text_width = (pos_button == NULL && text != NULL);
438 if (pos_text->x == -1 && pos_button != NULL)
439 pos_text->x = pos_button->x + pos_button->width;
440 if (pos_text->y == -1 && pos_button != NULL)
441 pos_text->y = pos_button->y;
443 if (pos_text->width == -1 || calculate_text_width)
444 pos_text->width = text_width;
445 if (pos_text->height == -1)
446 pos_text->height = text_height;
449 if (pos_input != NULL)
451 if (pos_input->x == -1 && pos_text != NULL)
452 pos_input->x = pos_text->x + pos_text->width;
453 if (pos_input->y == -1 && pos_text != NULL)
454 pos_input->y = pos_text->y;
456 if (pos_input->width == -1)
457 pos_input->width = input_width;
458 if (pos_input->height == -1)
459 pos_input->height = input_height;
464 static void DrawCursorAndText_Main(int nr, boolean active)
468 for (i = 0; main_controls[i].nr != -1; i++)
470 struct MainControlInfo *mci = &main_controls[i];
472 if (mci->nr == nr || nr == -1)
474 struct MenuPosInfo *pos_button = mci->pos_button;
475 struct MenuPosInfo *pos_text = mci->pos_text;
476 struct MenuPosInfo *pos_input = mci->pos_input;
477 char *text = mci->text;
478 char *input = mci->input;
479 int button_graphic = mci->button_graphic;
480 int font_text = mci->font_text;
481 int font_input = mci->font_input;
485 button_graphic = BUTTON_GRAPHIC_ACTIVE(button_graphic);
486 font_text = FONT_ACTIVE(font_text);
489 if (pos_button != NULL)
491 int button_x = mSX + pos_button->x;
492 int button_y = mSY + pos_button->y;
494 DrawBackground(button_x,button_y, pos_button->width,pos_button->height);
495 DrawGraphicThruMaskExt(drawto, button_x, button_y, button_graphic, 0);
498 if (pos_text != NULL && text != NULL)
500 int text_x = mSX + ALIGNED_XPOS(pos_text->x, pos_text->width,
502 int text_y = mSY + pos_text->y;
504 DrawBackground(text_x, text_y, pos_text->width, pos_text->height);
505 DrawText(text_x, text_y, text, font_text);
508 if (pos_input != NULL && input != NULL)
510 int input_x = mSX + ALIGNED_XPOS(pos_input->x, pos_input->width,
512 int input_y = mSY + pos_input->y;
514 DrawBackground(input_x, input_y, pos_input->width, pos_input->height);
515 DrawText(input_x, input_y, input, font_input);
521 static struct MainControlInfo *getMainControlInfo(int nr)
525 for (i = 0; main_controls[i].nr != -1; i++)
526 if (main_controls[i].nr == nr)
527 return &main_controls[i];
532 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
537 int rect_x = ALIGNED_XPOS(rect->x, rect->width, rect->align);
538 int rect_y = rect->y;
540 return (x >= rect_x && x < rect_x + rect->width &&
541 y >= rect_y && y < rect_y + rect->height);
544 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
546 static int cursor_array[SCR_FIELDY];
547 int x = mSX + TILEX * xpos;
548 int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
553 cursor_array[ypos] = graphic;
555 graphic = cursor_array[ypos];
559 graphic = BUTTON_GRAPHIC_ACTIVE(graphic);
561 DrawBackground(x, y, TILEX, TILEY);
562 DrawGraphicThruMaskExt(drawto, x, y, graphic, 0);
565 static void initCursor(int ypos, int graphic)
567 drawCursorExt(0, ypos, FALSE, graphic);
570 static void drawCursor(int ypos, boolean active)
572 drawCursorExt(0, ypos, active, -1);
575 static void drawCursorXY(int xpos, int ypos, int graphic)
577 drawCursorExt(xpos, ypos, FALSE, graphic);
580 static void drawChooseTreeCursor(int ypos, boolean active)
582 int last_game_status = game_status; /* save current game status */
584 /* force LEVELS draw offset on artwork setup screen */
585 game_status = GAME_MODE_LEVELS;
587 drawCursorExt(0, ypos, active, -1);
589 game_status = last_game_status; /* restore current game status */
594 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
595 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
599 static int getPrevlevelButtonPos()
604 static int getCurrentLevelTextPos()
606 return (getPrevlevelButtonPos() + 1);
609 static int getNextLevelButtonPos()
611 return getPrevlevelButtonPos() + 3 + 1;
614 static int getLevelRangeTextPos()
616 return getNextLevelButtonPos() + 1;
620 static int getTitleScreenGraphic()
622 return (show_titlescreen_initial ? IMG_TITLESCREEN_INITIAL_1 :
626 void DrawTitleScreenImage(int nr)
628 int graphic = getTitleScreenGraphic() + nr;
629 Bitmap *bitmap = graphic_info[graphic].bitmap;
630 int width = graphic_info[graphic].src_image_width;
631 int height = graphic_info[graphic].src_image_height;
632 int src_x = 0, src_y = 0;
638 if (width > WIN_XSIZE)
640 /* image width too large for window => center image horizontally */
641 src_x = (width - WIN_XSIZE) / 2;
645 if (height > WIN_YSIZE)
647 /* image height too large for window => center image vertically */
648 src_y = (height - WIN_YSIZE) / 2;
652 dst_x = (WIN_XSIZE - width) / 2;
653 dst_y = (WIN_YSIZE - height) / 2;
655 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
657 if (DrawingOnBackground(dst_x, dst_y))
658 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
660 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
662 redraw_mask = REDRAW_ALL;
664 /* reset fading control values to default config settings */
665 title.fade_delay_final = title.fade_delay;
666 title.post_delay_final = title.post_delay;
667 title.auto_delay_final = title.auto_delay;
669 /* override default settings with image config settings, if defined */
670 if (graphic_info[graphic].fade_delay > -1)
671 title.fade_delay_final = graphic_info[graphic].fade_delay;
672 if (graphic_info[graphic].post_delay > -1)
673 title.post_delay_final = graphic_info[graphic].post_delay;
674 if (graphic_info[graphic].auto_delay > -1)
675 title.auto_delay_final = graphic_info[graphic].auto_delay;
678 void DrawTitleScreen()
680 KeyboardAutoRepeatOff();
682 SetMainBackgroundImage(IMG_BACKGROUND_TITLE);
684 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
689 void DrawMainMenuExt(int redraw_mask, boolean do_fading)
691 static LevelDirTree *leveldir_last_valid = NULL;
692 boolean levelset_has_changed = FALSE;
694 boolean local_team_mode = (!options.network && setup.team_mode);
695 char *name_text = (local_team_mode ? "Team:" : "Name:");
696 int name_width, level_width;
703 FadeSoundsAndMusic();
705 KeyboardAutoRepeatOn();
708 SetDrawDeactivationMask(REDRAW_NONE);
709 SetDrawBackgroundMask(REDRAW_FIELD);
711 audio.sound_deactivated = FALSE;
715 /* needed if last screen was the playing screen, invoked from level editor */
716 if (level_editor_test_game)
718 game_status = GAME_MODE_EDITOR;
724 /* needed if last screen was the editor screen */
725 UndrawSpecialEditorDoor();
727 /* needed if last screen was the setup screen and fullscreen state changed */
728 ToggleFullscreenIfNeeded();
730 /* leveldir_current may be invalid (level group, parent link) */
731 if (!validLevelSeries(leveldir_current))
732 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
734 if (leveldir_current != leveldir_last_valid)
735 levelset_has_changed = TRUE;
737 /* store valid level series information */
738 leveldir_last_valid = leveldir_current;
740 /* needed if last screen (level choice) changed graphics, sounds or music */
741 ReloadCustomArtwork(0);
744 SetDrawtoField(DRAW_BACKBUFFER);
747 if (setup.show_titlescreen &&
748 ((levelset_has_changed &&
749 graphic_info[IMG_TITLESCREEN_1].bitmap != NULL) ||
750 (show_titlescreen_initial &&
751 graphic_info[IMG_TITLESCREEN_INITIAL_1].bitmap != NULL)))
753 game_status = GAME_MODE_TITLE;
760 /* level_nr may have been set to value over handicap with level editor */
761 if (setup.handicap && level_nr > leveldir_current->handicap_level)
762 level_nr = leveldir_current->handicap_level;
766 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
770 InitializeMainControls();
773 DrawCursorAndText_Main(-1, FALSE);
775 for (i = 0; main_controls[i].nr != -1; i++)
777 struct MenuPosInfo *pos_button = main_controls[i].pos_button;
778 struct MenuPosInfo *pos_text = main_controls[i].pos_text;
779 struct MenuPosInfo *pos_input = main_controls[i].pos_input;
780 char *text = main_controls[i].text;
781 char *input = main_controls[i].input;
782 int button_graphic = main_controls[i].button_graphic;
783 int font_text = main_controls[i].font_text;
784 int font_input = main_controls[i].font_input;
786 if (pos_button != NULL)
787 DrawGraphicThruMaskExt(drawto, mSX + pos_button->x, mSY + pos_button->y,
790 if (pos_text != NULL && text != NULL)
791 DrawText(mSX + pos_text->x, mSY + pos_text->y, text, font_text);
793 if (pos_input != NULL && input != NULL)
794 DrawText(mSX + pos_input->x, mSY + pos_input->y, input, font_input);
802 DrawText(mSX + 32, mSY + 2 * 32, name_text, FONT_MENU_1);
803 DrawText(mSX + 32, mSY + 3 * 32, "Levelset", FONT_MENU_1);
804 DrawText(mSX + 32, mSY + 4 * 32, "Hall Of Fame", FONT_MENU_1);
805 DrawText(mSX + 32, mSY + 5 * 32, "Level Creator", FONT_MENU_1);
806 DrawText(mSX + 32, mSY + 6 * 32, "Info Screen", FONT_MENU_1);
807 DrawText(mSX + 32, mSY + 7 * 32, "Start Game", FONT_MENU_1);
808 DrawText(mSX + 32, mSY + 8 * 32, "Setup", FONT_MENU_1);
809 DrawText(mSX + 32, mSY + 9 * 32, "Quit", FONT_MENU_1);
811 /* calculated after (possible) reload of custom artwork */
812 name_width = getTextWidth(name_text, FONT_MENU_1);
813 level_width = 9 * 32;
815 DrawText(mSX + 32 + name_width, mSY + 2 * 32, setup.player_name,
818 DrawText(mSX + getCurrentLevelTextPos() * 32, mSY + 3 * 32,
819 int2str(level_nr, 3), FONT_VALUE_1);
822 int text_height = getFontHeight(FONT_TEXT_3);
823 int xpos = getLevelRangeTextPos() * 32 + 8;
824 int ypos2 = 3 * 32 + 16;
825 int ypos1 = ypos2 - text_height;
827 DrawTextF(mSX - SX + xpos, mSY - SY + ypos1, FONT_TEXT_3,
828 "%03d", leveldir_current->first_level);
829 DrawTextF(mSX - SX + xpos, mSY - SY + ypos2, FONT_TEXT_3,
830 "%03d", leveldir_current->last_level);
833 for (i = 0; i < 8; i++)
834 initCursor(i, (i == 1 || i == 4 || i == 6 ? IMG_MENU_BUTTON_ENTER_MENU :
837 DrawTextSCentered(326, FONT_TITLE_2, PROGRAM_GAME_BY_STRING);
840 DrawPreviewLevel(TRUE);
842 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
845 if (TAPE_IS_EMPTY(tape))
847 DrawCompleteVideoDisplay();
852 /* create gadgets for main menu screen */
854 CreateScreenGadgets();
856 /* map gadgets for main menu screen */
858 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
860 DrawMaskedBorder(REDRAW_ALL);
869 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
872 void DrawAndFadeInMainMenu(int redraw_mask)
874 DrawMainMenuExt(redraw_mask, TRUE);
879 DrawMainMenuExt(REDRAW_ALL, FALSE);
883 static void gotoTopLevelDir()
885 /* move upwards to top level directory */
886 while (leveldir_current->node_parent)
888 /* write a "path" into level tree for easy navigation to last level */
889 if (leveldir_current->node_parent->node_group->cl_first == -1)
891 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
892 int leveldir_pos = posTreeInfo(leveldir_current);
893 int num_page_entries;
894 int cl_first, cl_cursor;
896 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
897 num_page_entries = num_leveldirs;
899 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
901 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
902 cl_cursor = leveldir_pos - cl_first;
904 leveldir_current->node_parent->node_group->cl_first = cl_first;
905 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
908 leveldir_current = leveldir_current->node_parent;
913 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
915 static unsigned long title_delay = 0;
916 static int title_nr = 0;
917 boolean return_to_main_menu = FALSE;
918 boolean use_fading_main_menu = TRUE;
919 boolean use_cross_fading = !show_titlescreen_initial; /* default */
921 if (button == MB_MENU_INITIALIZE)
923 int last_game_status = game_status; /* save current game status */
928 if (show_titlescreen_initial &&
929 graphic_info[IMG_TITLESCREEN_INITIAL_1].bitmap == NULL)
930 show_titlescreen_initial = FALSE;
932 if (game_status == GAME_MODE_INFO)
934 if (graphic_info[IMG_TITLESCREEN_1].bitmap == NULL)
936 DrawInfoScreen_NotAvailable("Title screen information:",
937 "No title screen for this level set.");
942 FadeSoundsAndMusic();
947 /* force TITLE music on title info screen */
948 game_status = GAME_MODE_TITLE;
953 game_status = last_game_status; /* restore current game status */
955 DrawTitleScreenImage(title_nr);
959 DelayReached(&title_delay, 0); /* reset delay counter */
964 if (title.auto_delay_final > -1 &&
965 DelayReached(&title_delay, title.auto_delay_final))
966 button = MB_MENU_CHOICE;
968 if (button == MB_MENU_LEAVE)
970 return_to_main_menu = TRUE;
971 use_fading_main_menu = FALSE;
973 else if (button == MB_MENU_CHOICE)
977 if (game_status == GAME_MODE_INFO &&
978 graphic_info[IMG_TITLESCREEN_1].bitmap == NULL)
980 info_mode = INFO_MODE_MAIN;
988 if (show_titlescreen_initial &&
989 (title_nr >= MAX_NUM_TITLE_SCREENS ||
990 graphic_info[IMG_TITLESCREEN_INITIAL_1 + title_nr].bitmap == NULL))
992 show_titlescreen_initial = FALSE;
994 title_nr = 0; /* restart with title screens for current level set */
997 anim_mode = graphic_info[getTitleScreenGraphic() + title_nr].anim_mode;
999 use_cross_fading = (anim_mode == ANIM_FADE ? FALSE :
1000 anim_mode == ANIM_CROSSFADE ? TRUE :
1003 if (!use_cross_fading)
1004 FadeOut(REDRAW_ALL);
1006 if (title_nr < MAX_NUM_TITLE_SCREENS &&
1007 graphic_info[getTitleScreenGraphic() + title_nr].bitmap != NULL)
1009 if (use_cross_fading)
1010 FadeCrossSaveBackbuffer();
1012 DrawTitleScreenImage(title_nr);
1014 if (use_cross_fading)
1015 FadeCross(REDRAW_ALL);
1019 DelayReached(&title_delay, 0); /* reset delay counter */
1023 FadeSoundsAndMusic();
1025 FadeOut(REDRAW_ALL);
1027 return_to_main_menu = TRUE;
1031 if (return_to_main_menu)
1033 show_titlescreen_initial = FALSE;
1037 if (game_status == GAME_MODE_INFO)
1039 OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1041 info_mode = INFO_MODE_MAIN;
1042 DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu);
1044 else /* default: return to main menu */
1046 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1048 game_status = GAME_MODE_MAIN;
1049 DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu);
1054 void HandleMainMenu_SelectLevel(int step, int direction)
1056 int old_level_nr = level_nr;
1059 new_level_nr = old_level_nr + step * direction;
1060 if (new_level_nr < leveldir_current->first_level)
1061 new_level_nr = leveldir_current->first_level;
1062 if (new_level_nr > leveldir_current->last_level)
1063 new_level_nr = leveldir_current->last_level;
1065 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1067 /* skipping levels is only allowed when trying to skip single level */
1068 if (setup.skip_levels && step == 1 &&
1069 Request("Level still unsolved ! Skip despite handicap ?", REQ_ASK))
1071 leveldir_current->handicap_level++;
1072 SaveLevelSetup_SeriesInfo();
1075 new_level_nr = leveldir_current->handicap_level;
1078 if (new_level_nr != old_level_nr)
1080 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_CURRENT_LEVEL);
1082 level_nr = new_level_nr;
1085 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1086 int2str(level_nr, 3), mci->font_text);
1088 DrawText(mSX + 11 * 32, mSY + 3 * 32, int2str(level_nr, 3), FONT_VALUE_1);
1091 LoadLevel(level_nr);
1092 DrawPreviewLevel(TRUE);
1096 DrawCompleteVideoDisplay();
1098 /* needed because DrawPreviewLevel() takes some time */
1106 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1108 static int choice = MAIN_CONTROL_GAME;
1112 if (button == MB_MENU_INITIALIZE)
1114 DrawCursorAndText_Main(choice, TRUE);
1119 if (mx || my) /* mouse input */
1123 for (i = 0; main_controls[i].nr != -1; i++)
1125 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1126 insideMenuPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1127 insideMenuPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1129 pos = main_controls[i].nr;
1135 else if (dx || dy) /* keyboard input */
1137 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1138 choice == MAIN_CONTROL_SETUP))
1139 button = MB_MENU_CHOICE;
1144 if (pos == MAIN_CONTROL_LEVELS && dx != 0 && button)
1146 HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1148 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
1154 DrawCursorAndText_Main(choice, FALSE);
1155 DrawCursorAndText_Main(pos, TRUE);
1162 if (pos == MAIN_CONTROL_NAME)
1164 game_status = GAME_MODE_PSEUDO_TYPENAME;
1166 HandleTypeName(strlen(setup.player_name), 0);
1168 else if (pos == MAIN_CONTROL_LEVELS)
1172 game_status = GAME_MODE_LEVELS;
1174 SaveLevelSetup_LastSeries();
1175 SaveLevelSetup_SeriesInfo();
1184 else if (pos == MAIN_CONTROL_SCORES)
1186 game_status = GAME_MODE_SCORES;
1190 else if (pos == MAIN_CONTROL_EDITOR)
1192 if (leveldir_current->readonly &&
1193 !strEqual(setup.player_name, "Artsoft"))
1194 Request("This level is read only !", REQ_CONFIRM);
1196 game_status = GAME_MODE_EDITOR;
1200 else if (pos == MAIN_CONTROL_INFO)
1202 game_status = GAME_MODE_INFO;
1203 info_mode = INFO_MODE_MAIN;
1207 else if (pos == MAIN_CONTROL_GAME)
1209 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
1211 else if (pos == MAIN_CONTROL_SETUP)
1213 game_status = GAME_MODE_SETUP;
1214 setup_mode = SETUP_MODE_MAIN;
1218 else if (pos == MAIN_CONTROL_QUIT)
1220 SaveLevelSetup_LastSeries();
1221 SaveLevelSetup_SeriesInfo();
1223 if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
1224 game_status = GAME_MODE_QUIT;
1229 if (game_status == GAME_MODE_MAIN)
1231 DrawPreviewLevel(FALSE);
1238 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1240 static int choice = 5;
1244 if (button == MB_MENU_INITIALIZE)
1246 drawCursor(choice, TRUE);
1251 if (mx || my) /* mouse input */
1253 x = (mx - mSX) / 32;
1254 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
1256 else if (dx || dy) /* keyboard input */
1258 if (dx && choice == 1)
1259 x = (dx < 0 ? 10 : 14);
1262 if (choice == 4 || choice == 6)
1263 button = MB_MENU_CHOICE;
1269 if (y == 1 && dx != 0 && button)
1271 HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1273 else if (IN_VIS_FIELD(x, y) &&
1274 y >= 0 && y <= 7 && (y != 1 || x < 10))
1280 drawCursor(choice, FALSE);
1281 drawCursor(y, TRUE);
1290 game_status = GAME_MODE_PSEUDO_TYPENAME;
1291 HandleTypeName(strlen(setup.player_name), 0);
1297 game_status = GAME_MODE_LEVELS;
1298 SaveLevelSetup_LastSeries();
1299 SaveLevelSetup_SeriesInfo();
1310 game_status = GAME_MODE_SCORES;
1315 if (leveldir_current->readonly &&
1316 !strEqual(setup.player_name, "Artsoft"))
1317 Request("This level is read only !", REQ_CONFIRM);
1318 game_status = GAME_MODE_EDITOR;
1323 game_status = GAME_MODE_INFO;
1324 info_mode = INFO_MODE_MAIN;
1329 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
1333 game_status = GAME_MODE_SETUP;
1334 setup_mode = SETUP_MODE_MAIN;
1340 SaveLevelSetup_LastSeries();
1341 SaveLevelSetup_SeriesInfo();
1343 if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
1344 game_status = GAME_MODE_QUIT;
1349 if (game_status == GAME_MODE_MAIN)
1351 DrawPreviewLevel(FALSE);
1359 /* ========================================================================= */
1360 /* info screen functions */
1361 /* ========================================================================= */
1363 static struct TokenInfo *info_info;
1364 static int num_info_info;
1366 static void execInfoTitleScreen()
1368 info_mode = INFO_MODE_TITLE;
1372 static void execInfoElements()
1374 info_mode = INFO_MODE_ELEMENTS;
1378 static void execInfoMusic()
1380 info_mode = INFO_MODE_MUSIC;
1384 static void execInfoCredits()
1386 info_mode = INFO_MODE_CREDITS;
1390 static void execInfoProgram()
1392 info_mode = INFO_MODE_PROGRAM;
1396 static void execInfoLevelSet()
1398 info_mode = INFO_MODE_LEVELSET;
1402 static void execExitInfo()
1404 game_status = GAME_MODE_MAIN;
1408 static struct TokenInfo info_info_main[] =
1410 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
1411 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
1412 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
1413 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
1414 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
1415 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
1416 { TYPE_EMPTY, NULL, "" },
1417 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
1422 static void DrawCursorAndText_Info(int pos, boolean active)
1424 int xpos = MENU_SCREEN_START_XPOS;
1425 int ypos = MENU_SCREEN_START_YPOS + pos;
1426 int font_nr = FONT_MENU_1;
1429 font_nr = FONT_ACTIVE(font_nr);
1431 DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[pos].text, font_nr);
1433 if (info_info[pos].type & ~TYPE_SKIP_ENTRY)
1434 drawCursor(pos, active);
1437 static void DrawInfoScreen_Main(int redraw_mask, boolean do_fading)
1442 CloseDoor(DOOR_CLOSE_2);
1446 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
1448 info_info = info_info_main;
1451 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
1454 int xpos = MENU_SCREEN_START_XPOS;
1455 int ypos = MENU_SCREEN_START_YPOS + i;
1456 int font_nr = FONT_MENU_1;
1459 if (info_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
1460 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
1461 else if (info_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
1462 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
1463 else if (info_info[i].type & ~TYPE_SKIP_ENTRY)
1464 initCursor(i, IMG_MENU_BUTTON);
1467 DrawCursorAndText_Info(i, FALSE);
1469 DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[i].text, font_nr);
1475 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
1480 DrawMaskedBorder(REDRAW_ALL);
1483 FadeIn(redraw_mask);
1490 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
1492 static int choice_store[MAX_INFO_MODES];
1493 int choice = choice_store[info_mode]; /* always starts with 0 */
1497 if (button == MB_MENU_INITIALIZE)
1499 /* advance to first valid menu entry */
1500 while (choice < num_info_info &&
1501 info_info[choice].type & TYPE_SKIP_ENTRY)
1503 choice_store[info_mode] = choice;
1506 DrawCursorAndText_Info(choice, TRUE);
1508 drawCursor(choice, TRUE);
1513 else if (button == MB_MENU_LEAVE)
1515 for (y = 0; y < num_info_info; y++)
1517 if (info_info[y].type & TYPE_LEAVE_MENU)
1519 void (*menu_callback_function)(void) = info_info[y].value;
1521 menu_callback_function();
1523 break; /* absolutely needed because function changes 'info_info'! */
1530 if (mx || my) /* mouse input */
1532 x = (mx - mSX) / 32;
1533 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
1535 else if (dx || dy) /* keyboard input */
1539 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
1541 if (info_info[choice].type & menu_navigation_type ||
1542 info_info[choice].type & TYPE_ENTER_SCREEN ||
1543 info_info[choice].type & TYPE_BOOLEAN_STYLE)
1544 button = MB_MENU_CHOICE;
1549 /* jump to next non-empty menu entry (up or down) */
1550 while (y > 0 && y < num_info_info - 1 &&
1551 info_info[y].type & TYPE_SKIP_ENTRY)
1555 if (IN_VIS_FIELD(x, y) &&
1556 y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY)
1563 DrawCursorAndText_Info(choice, FALSE);
1564 DrawCursorAndText_Info(y, TRUE);
1566 drawCursor(choice, FALSE);
1567 drawCursor(y, TRUE);
1570 choice = choice_store[info_mode] = y;
1573 else if (!(info_info[y].type & TYPE_GHOSTED))
1575 if (info_info[y].type & TYPE_ENTER_OR_LEAVE)
1577 void (*menu_callback_function)(void) = info_info[choice].value;
1579 menu_callback_function();
1585 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
1588 int ybottom = SYSIZE - 20;
1590 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
1595 DrawTextSCentered(100, FONT_TEXT_1, text_title);
1597 DrawTextSCentered(ybottom, FONT_TEXT_4,
1598 "Press any key or button for info menu");
1600 DrawTextSCentered(ystart, FONT_TEXT_2, text_error);
1603 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
1605 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
1606 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
1607 int xstart = mSX + 16;
1608 int ystart = mSY + 64 + 2 * 32;
1609 int ystep = TILEY + 4;
1610 int element, action, direction;
1618 for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
1619 infoscreen_step[i] = infoscreen_frame[i] = 0;
1624 DrawTextSCentered(100, FONT_TEXT_1, "The Game Elements:");
1626 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
1627 "Press any key or button for next page");
1633 while (helpanim_info[j].element != HELPANIM_LIST_END)
1635 if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN ||
1640 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
1649 j += infoscreen_step[i - start];
1651 element = helpanim_info[j].element;
1652 action = helpanim_info[j].action;
1653 direction = helpanim_info[j].direction;
1656 element = EL_UNKNOWN;
1658 if (action != -1 && direction != -1)
1659 graphic = el_act_dir2img(element, action, direction);
1660 else if (action != -1)
1661 graphic = el_act2img(element, action);
1662 else if (direction != -1)
1663 graphic = el_dir2img(element, direction);
1665 graphic = el2img(element);
1667 delay = helpanim_info[j++].delay;
1672 if (infoscreen_frame[i - start] == 0)
1675 infoscreen_frame[i - start] = delay - 1;
1679 sync_frame = delay - infoscreen_frame[i - start];
1680 infoscreen_frame[i - start]--;
1683 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
1685 if (!infoscreen_frame[i - start])
1686 infoscreen_step[i - start] = 0;
1690 if (!infoscreen_frame[i - start])
1691 infoscreen_step[i - start]++;
1692 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
1698 ClearRectangleOnBackground(drawto, xstart, ystart + (i - start) * ystep,
1700 DrawGraphicAnimationExt(drawto, xstart, ystart + (i - start) * ystep,
1701 graphic, sync_frame, USE_MASKING);
1704 DrawInfoScreen_HelpText(element, action, direction, i - start);
1709 redraw_mask |= REDRAW_FIELD;
1714 static char *getHelpText(int element, int action, int direction)
1716 char token[MAX_LINE_LEN];
1718 strcpy(token, element_info[element].token_name);
1721 strcat(token, element_action_info[action].suffix);
1723 if (direction != -1)
1724 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
1726 return getHashEntry(helptext_info, token);
1729 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
1731 int font_nr = FONT_LEVEL_NUMBER;
1732 int font_width = getFontWidth(font_nr);
1733 int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX;
1734 int sy = mSY + 65 + 2 * 32 + 1;
1735 int ystep = TILEY + 4;
1736 int pad_x = sx - SX;
1737 int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width;
1738 int max_lines_per_text = 2;
1741 if (action != -1 && direction != -1) /* element.action.direction */
1742 text = getHelpText(element, action, direction);
1744 if (text == NULL && action != -1) /* element.action */
1745 text = getHelpText(element, action, -1);
1747 if (text == NULL && direction != -1) /* element.direction */
1748 text = getHelpText(element, -1, direction);
1750 if (text == NULL) /* base element */
1751 text = getHelpText(element, -1, -1);
1753 if (text == NULL) /* not found */
1754 text = "No description available";
1756 if (strlen(text) <= max_chars_per_line) /* only one line of text */
1757 sy += getFontHeight(font_nr) / 2;
1759 DrawTextWrapped(sx, sy + ypos * ystep, text, font_nr,
1760 max_chars_per_line, max_lines_per_text);
1763 void DrawInfoScreen_TitleScreen()
1768 void HandleInfoScreen_TitleScreen(int button)
1770 HandleTitleScreen(0, 0, 0, 0, button);
1773 void DrawInfoScreen_Elements()
1775 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
1777 FadeOut(REDRAW_FIELD);
1782 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
1784 FadeIn(REDRAW_FIELD);
1789 void HandleInfoScreen_Elements(int button)
1791 static unsigned long info_delay = 0;
1792 static int num_anims;
1793 static int num_pages;
1795 int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN;
1798 if (button == MB_MENU_INITIALIZE)
1800 boolean new_element = TRUE;
1804 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
1806 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
1808 else if (new_element)
1811 new_element = FALSE;
1815 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
1819 if (button == MB_MENU_LEAVE)
1821 info_mode = INFO_MODE_MAIN;
1826 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
1828 if (button != MB_MENU_INITIALIZE)
1831 if (page >= num_pages)
1833 FadeSoundsAndMusic();
1834 FadeOut(REDRAW_FIELD);
1836 info_mode = INFO_MODE_MAIN;
1837 DrawAndFadeInInfoScreen(REDRAW_FIELD);
1842 if (button != MB_MENU_INITIALIZE)
1843 FadeCrossSaveBackbuffer();
1845 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
1847 if (button != MB_MENU_INITIALIZE)
1848 FadeCross(REDRAW_FIELD);
1852 if (DelayReached(&info_delay, GameFrameDelay))
1853 if (page < num_pages)
1854 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
1856 PlayMenuSoundIfLoop();
1860 void DrawInfoScreen_Music()
1862 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
1864 FadeOut(REDRAW_FIELD);
1871 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
1873 FadeIn(REDRAW_FIELD);
1876 void HandleInfoScreen_Music(int button)
1878 static struct MusicFileInfo *list = NULL;
1879 int ystart = 150, dy = 30;
1880 int ybottom = SYSIZE - 20;
1882 if (button == MB_MENU_INITIALIZE)
1884 list = music_file_info;
1888 FadeSoundsAndMusic();
1893 DrawTextSCentered(100, FONT_TEXT_1, "No music info for this level set.");
1895 DrawTextSCentered(ybottom, FONT_TEXT_4,
1896 "Press any key or button for info menu");
1902 if (button == MB_MENU_LEAVE)
1904 info_mode = INFO_MODE_MAIN;
1909 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
1913 if (button != MB_MENU_INITIALIZE)
1919 FadeSoundsAndMusic();
1920 FadeOut(REDRAW_FIELD);
1922 info_mode = INFO_MODE_MAIN;
1923 DrawAndFadeInInfoScreen(REDRAW_FIELD);
1928 FadeSoundsAndMusic();
1930 if (button != MB_MENU_INITIALIZE)
1931 FadeCrossSaveBackbuffer();
1938 int sound = list->music;
1940 if (sound_info[sound].loop)
1941 PlaySoundLoop(sound);
1945 DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Sounds:");
1949 PlayMusic(list->music);
1951 DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Music:");
1954 if (!strEqual(list->title, UNKNOWN_NAME))
1956 if (!strEqual(list->title_header, UNKNOWN_NAME))
1957 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->title_header);
1959 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
1962 if (!strEqual(list->artist, UNKNOWN_NAME))
1964 if (!strEqual(list->artist_header, UNKNOWN_NAME))
1965 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->artist_header);
1967 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "by");
1969 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->artist);
1972 if (!strEqual(list->album, UNKNOWN_NAME))
1974 if (!strEqual(list->album_header, UNKNOWN_NAME))
1975 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->album_header);
1977 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the album");
1979 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album);
1982 if (!strEqual(list->year, UNKNOWN_NAME))
1984 if (!strEqual(list->year_header, UNKNOWN_NAME))
1985 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->year_header);
1987 DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the year");
1989 DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->year);
1992 DrawTextSCentered(ybottom, FONT_TEXT_4,
1993 "Press any key or button for next page");
1995 if (button != MB_MENU_INITIALIZE)
1996 FadeCross(REDRAW_FIELD);
1999 if (list != NULL && list->is_sound && sound_info[list->music].loop)
2000 PlaySoundLoop(list->music);
2003 static boolean DrawInfoScreen_CreditsScreen(int screen_nr)
2005 int ystart = 150, ystep = 30;
2006 int ybottom = SYSIZE - 20;
2014 DrawTextSCentered(100, FONT_TEXT_1, "Credits:");
2018 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2019 "Special thanks to");
2020 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2022 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2024 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2025 "\"Boulder Dash\"");
2026 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2028 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2030 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2032 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2033 "First Star Software");
2035 else if (screen_nr == 1)
2037 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2038 "Special thanks to");
2039 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2040 "Klaus Heinz & Volker Wertich");
2041 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2043 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2044 "\"Emerald Mine\"");
2045 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2047 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2049 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2051 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2054 else if (screen_nr == 2)
2056 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2057 "Special thanks to");
2058 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2059 "Michael Stopp & Philip Jespersen");
2060 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2062 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2064 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2066 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2068 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2070 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2071 "Digital Integration");
2073 else if (screen_nr == 3)
2075 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2076 "Special thanks to");
2077 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2078 "Hiroyuki Imabayashi");
2079 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2081 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2083 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2085 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2087 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2089 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
2092 else if (screen_nr == 4)
2094 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2095 "Special thanks to");
2096 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2098 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2100 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2101 "Jürgen Bonhagen");
2102 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2103 "for the continuous creation");
2104 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
2105 "of outstanding level sets");
2107 else if (screen_nr == 5)
2109 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2111 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2113 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2114 "for ideas and inspiration by");
2115 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2118 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
2120 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_3,
2122 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2,
2123 "for ideas and inspiration by");
2124 DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_3,
2127 else if (screen_nr == 6)
2129 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2131 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2133 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2134 "for the new Emerald Mine engine");
2136 else if (screen_nr == 7)
2138 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2140 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
2142 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
2143 "for the initial DOS port");
2145 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
2147 DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
2149 DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
2150 "for some additional toons");
2152 else if (screen_nr == 8)
2154 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2155 "And not to forget:");
2156 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2,
2158 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3,
2159 "All those who contributed");
2160 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
2161 "levels to this game");
2162 DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_3,
2172 DrawTextSCentered(ybottom, FONT_TEXT_4,
2173 "Press any key or button for next page");
2178 void DrawInfoScreen_Credits()
2180 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
2182 FadeSoundsAndMusic();
2184 FadeOut(REDRAW_FIELD);
2186 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
2188 FadeIn(REDRAW_FIELD);
2191 void HandleInfoScreen_Credits(int button)
2193 static int screen_nr = 0;
2195 if (button == MB_MENU_INITIALIZE)
2199 DrawInfoScreen_CreditsScreen(screen_nr);
2201 else if (button == MB_MENU_LEAVE)
2203 info_mode = INFO_MODE_MAIN;
2208 else if (button == MB_MENU_CHOICE)
2210 boolean show_screen;
2214 FadeCrossSaveBackbuffer();
2216 show_screen = DrawInfoScreen_CreditsScreen(screen_nr);
2220 FadeCross(REDRAW_FIELD);
2224 FadeSoundsAndMusic();
2225 FadeOut(REDRAW_FIELD);
2227 info_mode = INFO_MODE_MAIN;
2228 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2233 PlayMenuSoundIfLoop();
2237 void DrawInfoScreen_Program()
2239 int ystart = 150, ystep = 30;
2240 int ybottom = SYSIZE - 20;
2242 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
2244 FadeOut(REDRAW_FIELD);
2249 DrawTextSCentered(100, FONT_TEXT_1, "Program Information:");
2251 DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
2252 "This game is Freeware!");
2253 DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2,
2254 "If you like it, send e-mail to:");
2255 DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3,
2256 PROGRAM_EMAIL_STRING);
2257 DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_2,
2258 "or SnailMail to:");
2259 DrawTextSCentered(ystart + 4 * ystep + 0, FONT_TEXT_3,
2261 DrawTextSCentered(ystart + 4 * ystep + 20, FONT_TEXT_3,
2262 "Detmolder Strasse 189");
2263 DrawTextSCentered(ystart + 4 * ystep + 40, FONT_TEXT_3,
2265 DrawTextSCentered(ystart + 4 * ystep + 60, FONT_TEXT_3,
2267 DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2,
2268 "More information and levels:");
2269 DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_3,
2270 PROGRAM_WEBSITE_STRING);
2271 DrawTextSCentered(ystart + 9 * ystep, FONT_TEXT_2,
2272 "If you have created new levels,");
2273 DrawTextSCentered(ystart + 10 * ystep, FONT_TEXT_2,
2274 "send them to me to include them!");
2275 DrawTextSCentered(ystart + 11 * ystep, FONT_TEXT_2,
2278 DrawTextSCentered(ybottom, FONT_TEXT_4,
2279 "Press any key or button for info menu");
2281 FadeIn(REDRAW_FIELD);
2284 void HandleInfoScreen_Program(int button)
2286 if (button == MB_MENU_LEAVE)
2288 info_mode = INFO_MODE_MAIN;
2293 else if (button == MB_MENU_CHOICE)
2295 FadeSoundsAndMusic();
2296 FadeOut(REDRAW_FIELD);
2298 info_mode = INFO_MODE_MAIN;
2299 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2303 PlayMenuSoundIfLoop();
2307 void DrawInfoScreen_LevelSet()
2310 int ybottom = SYSIZE - 20;
2311 char *filename = getLevelSetInfoFilename();
2312 int font_nr = FONT_LEVEL_NUMBER;
2313 int font_width = getFontWidth(font_nr);
2314 int font_height = getFontHeight(font_nr);
2317 int sx = SX + pad_x;
2318 int sy = SY + pad_y;
2319 int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
2320 int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
2322 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
2324 FadeOut(REDRAW_FIELD);
2329 DrawTextSCentered(100, FONT_TEXT_1, "Level Set Information:");
2331 DrawTextSCentered(ybottom, FONT_TEXT_4,
2332 "Press any key or button for info menu");
2334 if (filename != NULL)
2335 DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line,
2336 max_lines_per_screen);
2338 DrawTextSCentered(ystart, FONT_TEXT_2,
2339 "No information for this level set.");
2341 FadeIn(REDRAW_FIELD);
2344 void HandleInfoScreen_LevelSet(int button)
2346 if (button == MB_MENU_LEAVE)
2348 info_mode = INFO_MODE_MAIN;
2353 else if (button == MB_MENU_CHOICE)
2355 FadeSoundsAndMusic();
2356 FadeOut(REDRAW_FIELD);
2358 info_mode = INFO_MODE_MAIN;
2359 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2363 PlayMenuSoundIfLoop();
2367 static void DrawInfoScreenExt(int redraw_mask, boolean do_fading)
2369 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
2371 if (info_mode == INFO_MODE_TITLE)
2372 DrawInfoScreen_TitleScreen();
2373 else if (info_mode == INFO_MODE_ELEMENTS)
2374 DrawInfoScreen_Elements();
2375 else if (info_mode == INFO_MODE_MUSIC)
2376 DrawInfoScreen_Music();
2377 else if (info_mode == INFO_MODE_CREDITS)
2378 DrawInfoScreen_Credits();
2379 else if (info_mode == INFO_MODE_PROGRAM)
2380 DrawInfoScreen_Program();
2381 else if (info_mode == INFO_MODE_LEVELSET)
2382 DrawInfoScreen_LevelSet();
2384 DrawInfoScreen_Main(redraw_mask, do_fading);
2386 if (info_mode != INFO_MODE_MAIN &&
2387 info_mode != INFO_MODE_TITLE &&
2388 info_mode != INFO_MODE_MUSIC)
2395 void DrawAndFadeInInfoScreen(int redraw_mask)
2397 DrawInfoScreenExt(redraw_mask, TRUE);
2400 void DrawInfoScreen()
2402 DrawInfoScreenExt(REDRAW_ALL, FALSE);
2405 void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
2407 if (info_mode == INFO_MODE_TITLE)
2408 HandleInfoScreen_TitleScreen(button);
2409 else if (info_mode == INFO_MODE_ELEMENTS)
2410 HandleInfoScreen_Elements(button);
2411 else if (info_mode == INFO_MODE_MUSIC)
2412 HandleInfoScreen_Music(button);
2413 else if (info_mode == INFO_MODE_CREDITS)
2414 HandleInfoScreen_Credits(button);
2415 else if (info_mode == INFO_MODE_PROGRAM)
2416 HandleInfoScreen_Program(button);
2417 else if (info_mode == INFO_MODE_LEVELSET)
2418 HandleInfoScreen_LevelSet(button);
2420 HandleInfoScreen_Main(mx, my, dx, dy, button);
2426 /* ========================================================================= */
2427 /* type name functions */
2428 /* ========================================================================= */
2430 void HandleTypeName(int newxpos, Key key)
2432 struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME);
2434 static int xpos = 0;
2436 static int xpos = 0, ypos = 2;
2438 int font_nr = mci->font_input;
2439 int font_active_nr = FONT_ACTIVE(font_nr);
2440 int font_width = getFontWidth(font_active_nr);
2442 int startx = mSX + mci->pos_input->x;
2443 int starty = mSY + mci->pos_input->y;
2445 int name_width = getFontWidth(FONT_MENU_1) * strlen("Name:");
2446 int startx = mSX + 32 + name_width;
2447 int starty = mSY + ypos * 32;
2454 DrawText(startx, starty, setup.player_name, font_active_nr);
2455 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
2460 if (((key >= KSYM_A && key <= KSYM_Z) ||
2461 (key >= KSYM_a && key <= KSYM_z)) &&
2462 xpos < MAX_PLAYER_NAME_LEN)
2466 if (key >= KSYM_A && key <= KSYM_Z)
2467 ascii = 'A' + (char)(key - KSYM_A);
2469 ascii = 'a' + (char)(key - KSYM_a);
2471 setup.player_name[xpos] = ascii;
2472 setup.player_name[xpos + 1] = 0;
2476 DrawText(startx, starty, setup.player_name, font_active_nr);
2477 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
2479 else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
2483 setup.player_name[xpos] = 0;
2485 DrawText(startx + xpos * font_width, starty, "_ ", font_active_nr);
2487 else if (key == KSYM_Return && xpos > 0)
2489 DrawText(startx, starty, setup.player_name, font_nr);
2490 DrawText(startx + xpos * font_width, starty, " ", font_active_nr);
2494 game_status = GAME_MODE_MAIN;
2499 /* ========================================================================= */
2500 /* tree menu functions */
2501 /* ========================================================================= */
2503 static void DrawChooseTree(TreeInfo **ti_ptr)
2507 FreeScreenGadgets();
2508 CreateScreenGadgets();
2510 CloseDoor(DOOR_CLOSE_2);
2514 HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
2515 MapScreenTreeGadgets(*ti_ptr);
2521 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
2523 struct GadgetInfo *gi = screen_gadget[id];
2524 int items_max, items_visible, item_position;
2526 items_max = numTreeInfoInGroup(ti);
2527 items_visible = NUM_MENU_ENTRIES_ON_SCREEN;
2528 item_position = first_entry;
2530 if (item_position > items_max - items_visible)
2531 item_position = items_max - items_visible;
2533 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
2534 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
2535 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
2538 static void drawChooseTreeList(int first_entry, int num_page_entries,
2542 char *title_string = NULL;
2543 int yoffset_sets = MENU_TITLE1_YPOS;
2544 int yoffset_setup = 16;
2545 int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? yoffset_sets :
2547 int last_game_status = game_status; /* save current game status */
2549 title_string = ti->infotext;
2551 DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
2553 /* force LEVELS font on artwork setup screen */
2554 game_status = GAME_MODE_LEVELS;
2556 /* clear tree list area, but not title or scrollbar */
2557 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
2558 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
2559 MAX_MENU_ENTRIES_ON_SCREEN * 32);
2561 for (i = 0; i < num_page_entries; i++)
2563 TreeInfo *node, *node_first;
2564 int entry_pos = first_entry + i;
2565 int xpos = MENU_SCREEN_START_XPOS;
2566 int ypos = MENU_SCREEN_START_YPOS + i;
2567 int startx = mSX + xpos * 32;
2568 int starty = mSY + ypos * 32;
2569 int font_nr = FONT_TEXT_1;
2570 int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
2571 int startx_text = startx + font_xoffset;
2572 int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
2573 int text_size = startx_scrollbar - startx_text;
2574 int max_buffer_len = text_size / getFontWidth(font_nr);
2575 char buffer[max_buffer_len + 1];
2577 node_first = getTreeInfoFirstGroupEntry(ti);
2578 node = getTreeInfoFromPos(node_first, entry_pos);
2580 strncpy(buffer, node->name, max_buffer_len);
2581 buffer[max_buffer_len] = '\0';
2583 DrawText(startx, starty, buffer, font_nr + node->color);
2585 if (node->parent_link)
2586 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
2587 else if (node->level_group)
2588 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
2590 initCursor(i, IMG_MENU_BUTTON);
2593 game_status = last_game_status; /* restore current game status */
2595 redraw_mask |= REDRAW_FIELD;
2598 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
2600 TreeInfo *node, *node_first;
2601 int x, last_redraw_mask = redraw_mask;
2602 int ypos = MENU_TITLE2_YPOS;
2604 if (ti->type != TREE_TYPE_LEVEL_DIR)
2607 node_first = getTreeInfoFirstGroupEntry(ti);
2608 node = getTreeInfoFromPos(node_first, entry_pos);
2610 DrawBackground(SX, SY + ypos, SXSIZE, getFontHeight(FONT_TITLE_2));
2612 if (node->parent_link)
2613 DrawTextFCentered(ypos, FONT_TITLE_2, "leave group \"%s\"",
2615 else if (node->level_group)
2616 DrawTextFCentered(ypos, FONT_TITLE_2, "enter group \"%s\"",
2618 else if (ti->type == TREE_TYPE_LEVEL_DIR)
2619 DrawTextFCentered(ypos, FONT_TITLE_2, "%3d levels (%s)",
2620 node->levels, node->class_desc);
2622 /* let BackToFront() redraw only what is needed */
2623 redraw_mask = last_redraw_mask | REDRAW_TILES;
2624 for (x = 0; x < SCR_FIELDX; x++)
2625 MarkTileDirty(x, 1);
2628 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
2631 TreeInfo *ti = *ti_ptr;
2633 int y = ti->cl_cursor;
2634 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2635 int num_entries = numTreeInfoInGroup(ti);
2636 int num_page_entries;
2637 int last_game_status = game_status; /* save current game status */
2638 boolean position_set_by_scrollbar = (dx == 999);
2640 /* force LEVELS draw offset on choose level and artwork setup screen */
2641 game_status = GAME_MODE_LEVELS;
2643 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
2644 num_page_entries = num_entries;
2646 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
2648 game_status = last_game_status; /* restore current game status */
2650 if (button == MB_MENU_INITIALIZE)
2652 int num_entries = numTreeInfoInGroup(ti);
2653 int entry_pos = posTreeInfo(ti);
2655 if (ti->cl_first == -1)
2657 /* only on initialization */
2658 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
2659 ti->cl_cursor = entry_pos - ti->cl_first;
2661 else if (ti->cl_cursor >= num_page_entries ||
2662 (num_entries > num_page_entries &&
2663 num_entries - ti->cl_first < num_page_entries))
2665 /* only after change of list size (by custom graphic configuration) */
2666 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
2667 ti->cl_cursor = entry_pos - ti->cl_first;
2670 if (position_set_by_scrollbar)
2673 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
2676 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
2677 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
2678 drawChooseTreeCursor(ti->cl_cursor, TRUE);
2682 else if (button == MB_MENU_LEAVE)
2684 if (ti->node_parent)
2686 *ti_ptr = ti->node_parent;
2687 DrawChooseTree(ti_ptr);
2689 else if (game_status == GAME_MODE_SETUP)
2691 if (game_status == GAME_MODE_SETUP)
2693 if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
2694 execSetupGraphics();
2701 game_status = GAME_MODE_MAIN;
2708 if (mx || my) /* mouse input */
2710 int last_game_status = game_status; /* save current game status */
2712 /* force LEVELS draw offset on artwork setup screen */
2713 game_status = GAME_MODE_LEVELS;
2715 x = (mx - mSX) / 32;
2716 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2718 game_status = last_game_status; /* restore current game status */
2720 else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */
2722 /* move cursor instead of scrolling when already at start/end of list */
2723 if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
2725 else if (dy == +1 * SCROLL_LINE &&
2726 ti->cl_first + num_page_entries == num_entries)
2729 /* handle scrolling screen one line or page */
2730 if (ti->cl_cursor + dy < 0 ||
2731 ti->cl_cursor + dy > num_page_entries - 1)
2733 if (ABS(dy) == SCROLL_PAGE)
2734 step = num_page_entries - 1;
2736 if (dy < 0 && ti->cl_first > 0)
2738 /* scroll page/line up */
2740 ti->cl_first -= step;
2741 if (ti->cl_first < 0)
2744 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
2745 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
2746 drawChooseTreeCursor(ti->cl_cursor, TRUE);
2748 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
2751 else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
2753 /* scroll page/line down */
2755 ti->cl_first += step;
2756 if (ti->cl_first + num_page_entries > num_entries)
2757 ti->cl_first = MAX(0, num_entries - num_page_entries);
2759 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
2760 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
2761 drawChooseTreeCursor(ti->cl_cursor, TRUE);
2763 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
2770 /* handle moving cursor one line */
2771 y = ti->cl_cursor + dy;
2776 TreeInfo *node_first, *node_cursor;
2777 int entry_pos = ti->cl_first + y;
2779 node_first = getTreeInfoFirstGroupEntry(ti);
2780 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
2782 if (node_cursor->node_group)
2784 node_cursor->cl_first = ti->cl_first;
2785 node_cursor->cl_cursor = ti->cl_cursor;
2786 *ti_ptr = node_cursor->node_group;
2787 DrawChooseTree(ti_ptr);
2792 else if (dx == -1 && ti->node_parent)
2794 *ti_ptr = ti->node_parent;
2795 DrawChooseTree(ti_ptr);
2800 if (!anyScrollbarGadgetActive() &&
2801 IN_VIS_FIELD(x, y) &&
2802 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
2803 y >= 0 && y < num_page_entries)
2807 if (y != ti->cl_cursor)
2809 drawChooseTreeCursor(ti->cl_cursor, FALSE);
2810 drawChooseTreeCursor(y, TRUE);
2811 drawChooseTreeInfo(ti->cl_first + y, ti);
2818 TreeInfo *node_first, *node_cursor;
2819 int entry_pos = ti->cl_first + y;
2821 node_first = getTreeInfoFirstGroupEntry(ti);
2822 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
2824 if (node_cursor->node_group)
2826 node_cursor->cl_first = ti->cl_first;
2827 node_cursor->cl_cursor = ti->cl_cursor;
2828 *ti_ptr = node_cursor->node_group;
2829 DrawChooseTree(ti_ptr);
2831 else if (node_cursor->parent_link)
2833 *ti_ptr = node_cursor->node_parent;
2834 DrawChooseTree(ti_ptr);
2838 node_cursor->cl_first = ti->cl_first;
2839 node_cursor->cl_cursor = ti->cl_cursor;
2840 *ti_ptr = node_cursor;
2842 if (ti->type == TREE_TYPE_LEVEL_DIR)
2844 LoadLevelSetup_SeriesInfo();
2846 SaveLevelSetup_LastSeries();
2847 SaveLevelSetup_SeriesInfo();
2851 if (game_status == GAME_MODE_SETUP)
2853 if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
2854 execSetupGraphics();
2860 game_status = GAME_MODE_MAIN;
2868 void DrawChooseLevel()
2870 SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
2872 DrawChooseTree(&leveldir_current);
2878 void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
2880 HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
2885 void DrawHallOfFame(int highlight_position)
2888 FadeSoundsAndMusic();
2890 /* (this is needed when called from GameEnd() after winning a game) */
2891 KeyboardAutoRepeatOn();
2894 /* (this is needed when called from GameEnd() after winning a game) */
2895 SetDrawDeactivationMask(REDRAW_NONE);
2896 SetDrawBackgroundMask(REDRAW_FIELD);
2898 CloseDoor(DOOR_CLOSE_2);
2900 if (highlight_position < 0)
2901 LoadScore(level_nr);
2903 FadeOut(REDRAW_FIELD);
2910 HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
2912 FadeIn(REDRAW_FIELD);
2915 static void drawHallOfFameList(int first_entry, int highlight_position)
2919 SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
2922 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
2923 DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
2924 "HighScores of Level %d", level_nr);
2926 for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
2928 int entry = first_entry + i;
2929 boolean active = (entry == highlight_position);
2930 int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
2931 int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
2932 int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
2933 int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
2934 int dx1 = 3 * getFontWidth(font_nr1);
2935 int dx2 = dx1 + getFontWidth(font_nr1);
2936 int dx3 = dx2 + 25 * getFontWidth(font_nr3);
2937 int sy = mSY + 64 + i * 32;
2939 DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
2940 DrawText(mSX + dx1, sy, ".", font_nr1);
2941 DrawText(mSX + dx2, sy, ".........................", font_nr3);
2943 if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
2944 DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
2946 DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
2949 redraw_mask |= REDRAW_FIELD;
2952 void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
2954 static int first_entry = 0;
2955 static int highlight_position = 0;
2956 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2958 if (button == MB_MENU_INITIALIZE)
2961 highlight_position = mx;
2962 drawHallOfFameList(first_entry, highlight_position);
2967 if (ABS(dy) == SCROLL_PAGE) /* handle scrolling one page */
2968 step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
2972 if (first_entry > 0)
2974 first_entry -= step;
2975 if (first_entry < 0)
2978 drawHallOfFameList(first_entry, highlight_position);
2983 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
2985 first_entry += step;
2986 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
2987 first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
2989 drawHallOfFameList(first_entry, highlight_position);
2992 else if (button == MB_MENU_LEAVE)
2994 FadeSound(SND_BACKGROUND_SCORES);
2996 game_status = GAME_MODE_MAIN;
3000 else if (button == MB_MENU_CHOICE)
3002 FadeSound(SND_BACKGROUND_SCORES);
3003 FadeOut(REDRAW_FIELD);
3005 game_status = GAME_MODE_MAIN;
3007 DrawAndFadeInMainMenu(REDRAW_FIELD);
3010 if (game_status == GAME_MODE_SCORES)
3011 PlayMenuSoundIfLoop();
3017 /* ========================================================================= */
3018 /* setup screen functions */
3019 /* ========================================================================= */
3021 static struct TokenInfo *setup_info;
3022 static int num_setup_info;
3024 static char *screen_mode_text;
3025 static char *graphics_set_name;
3026 static char *sounds_set_name;
3027 static char *music_set_name;
3029 static void execSetupMain()
3031 setup_mode = SETUP_MODE_MAIN;
3035 static void execSetupGame()
3037 setup_mode = SETUP_MODE_GAME;
3041 static void execSetupEditor()
3043 setup_mode = SETUP_MODE_EDITOR;
3047 static void execSetupGraphics()
3049 if (video.fullscreen_available && screen_modes == NULL)
3053 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
3055 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
3056 char identifier[32], name[32];
3057 int x = video.fullscreen_modes[i].width;
3058 int y = video.fullscreen_modes[i].height;
3061 get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy);
3063 ti->node_top = &screen_modes;
3064 ti->sort_priority = x * 10000 + y;
3066 sprintf(identifier, "%dx%d", x, y);
3067 sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy);
3069 setString(&ti->identifier, identifier);
3070 setString(&ti->name, name);
3071 setString(&ti->name_sorting, name);
3072 setString(&ti->infotext, "Fullscreen Mode");
3074 pushTreeInfo(&screen_modes, ti);
3077 /* sort fullscreen modes to start with lowest available screen resolution */
3078 sortTreeInfo(&screen_modes);
3080 /* set current screen mode for fullscreen mode to configured setup value */
3081 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3082 setup.fullscreen_mode);
3084 /* if that fails, set current screen mode to reliable default value */
3085 if (screen_mode_current == NULL)
3086 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3087 DEFAULT_FULLSCREEN_MODE);
3089 /* if that also fails, set current screen mode to first available mode */
3090 if (screen_mode_current == NULL)
3091 screen_mode_current = screen_modes;
3093 if (screen_mode_current == NULL)
3094 video.fullscreen_available = FALSE;
3097 if (video.fullscreen_available)
3099 setup.fullscreen_mode = screen_mode_current->identifier;
3101 /* needed for displaying screen mode name instead of identifier */
3102 screen_mode_text = screen_mode_current->name;
3105 setup_mode = SETUP_MODE_GRAPHICS;
3109 static void execSetupChooseScreenMode()
3111 if (!video.fullscreen_available)
3114 setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE;
3118 static void execSetupSound()
3120 setup_mode = SETUP_MODE_SOUND;
3124 static void execSetupArtwork()
3126 setup.graphics_set = artwork.gfx_current->identifier;
3127 setup.sounds_set = artwork.snd_current->identifier;
3128 setup.music_set = artwork.mus_current->identifier;
3130 /* needed if last screen (setup choice) changed graphics, sounds or music */
3131 ReloadCustomArtwork(0);
3133 /* needed for displaying artwork name instead of artwork identifier */
3134 graphics_set_name = artwork.gfx_current->name;
3135 sounds_set_name = artwork.snd_current->name;
3136 music_set_name = artwork.mus_current->name;
3138 setup_mode = SETUP_MODE_ARTWORK;
3142 static void execSetupChooseGraphics()
3144 setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
3148 static void execSetupChooseSounds()
3150 setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
3154 static void execSetupChooseMusic()
3156 setup_mode = SETUP_MODE_CHOOSE_MUSIC;
3160 static void execSetupInput()
3162 setup_mode = SETUP_MODE_INPUT;
3166 static void execSetupShortcut1()
3168 setup_mode = SETUP_MODE_SHORTCUT_1;
3172 static void execSetupShortcut2()
3174 setup_mode = SETUP_MODE_SHORTCUT_2;
3178 static void execExitSetup()
3180 game_status = GAME_MODE_MAIN;
3184 static void execSaveAndExitSetup()
3190 static struct TokenInfo setup_info_main[] =
3192 { TYPE_ENTER_MENU, execSetupGame, "Game & Menu" },
3193 { TYPE_ENTER_MENU, execSetupEditor, "Editor" },
3194 { TYPE_ENTER_MENU, execSetupGraphics, "Graphics" },
3195 { TYPE_ENTER_MENU, execSetupSound, "Sound & Music" },
3196 { TYPE_ENTER_MENU, execSetupArtwork, "Custom Artwork" },
3197 { TYPE_ENTER_MENU, execSetupInput, "Input Devices" },
3198 { TYPE_ENTER_MENU, execSetupShortcut1, "Key Shortcuts 1" },
3199 { TYPE_ENTER_MENU, execSetupShortcut2, "Key Shortcuts 2" },
3200 { TYPE_EMPTY, NULL, "" },
3201 { TYPE_LEAVE_MENU, execExitSetup, "Exit" },
3202 { TYPE_LEAVE_MENU, execSaveAndExitSetup, "Save and Exit" },
3207 static struct TokenInfo setup_info_game[] =
3209 { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" },
3210 { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" },
3211 { TYPE_SWITCH, &setup.handicap, "Handicap:" },
3212 { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" },
3213 { TYPE_SWITCH, &setup.time_limit, "Time Limit:" },
3214 { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" },
3215 { TYPE_EMPTY, NULL, "" },
3216 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3221 static struct TokenInfo setup_info_editor[] =
3224 { TYPE_SWITCH, &setup.editor.el_boulderdash, "Boulder Dash:" },
3225 { TYPE_SWITCH, &setup.editor.el_emerald_mine, "Emerald Mine:" },
3226 { TYPE_SWITCH, &setup.editor.el_emerald_mine_club, "Emerald Mine Club:" },
3227 { TYPE_SWITCH, &setup.editor.el_more, "Rocks'n'Diamonds:" },
3228 { TYPE_SWITCH, &setup.editor.el_sokoban, "Sokoban:" },
3229 { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" },
3230 { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" },
3231 { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
3233 { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" },
3234 { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" },
3236 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" },
3238 { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
3239 { TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" },
3240 { TYPE_EMPTY, NULL, "" },
3242 { TYPE_SWITCH, &setup.editor.el_by_game, "Show elements by game:" },
3243 { TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" },
3244 { TYPE_EMPTY, NULL, "" },
3246 { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" },
3247 { TYPE_EMPTY, NULL, "" },
3248 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3253 static struct TokenInfo setup_info_graphics[] =
3255 { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" },
3256 { TYPE_ENTER_LIST, execSetupChooseScreenMode, "Fullscreen Mode:" },
3257 { TYPE_STRING, &screen_mode_text, "" },
3258 { TYPE_SWITCH, &setup.scroll_delay, "Delayed Scrolling:" },
3260 { TYPE_SWITCH, &setup.soft_scrolling, "Soft Scrolling:" },
3261 { TYPE_SWITCH, &setup.double_buffering,"Double-Buffering:" },
3263 { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" },
3264 { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" },
3265 { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" },
3266 { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" },
3267 { TYPE_SWITCH, &setup.toons, "Show Toons:" },
3268 { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" },
3269 { TYPE_EMPTY, NULL, "" },
3270 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3275 static struct TokenInfo setup_info_sound[] =
3277 { TYPE_SWITCH, &setup.sound_simple, "Sound Effects (Normal):" },
3278 { TYPE_SWITCH, &setup.sound_loops, "Sound Effects (Looping):" },
3279 { TYPE_SWITCH, &setup.sound_music, "Music:" },
3280 { TYPE_EMPTY, NULL, "" },
3281 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3286 static struct TokenInfo setup_info_artwork[] =
3288 { TYPE_ENTER_LIST, execSetupChooseGraphics,"Custom Graphics:" },
3289 { TYPE_STRING, &graphics_set_name, "" },
3290 { TYPE_ENTER_LIST, execSetupChooseSounds, "Custom Sounds:" },
3291 { TYPE_STRING, &sounds_set_name, "" },
3292 { TYPE_ENTER_LIST, execSetupChooseMusic, "Custom Music:" },
3293 { TYPE_STRING, &music_set_name, "" },
3294 { TYPE_EMPTY, NULL, "" },
3296 { TYPE_YES_NO, &setup.override_level_graphics,"Override Level Graphics:" },
3297 { TYPE_YES_NO, &setup.override_level_sounds, "Override Level Sounds:" },
3298 { TYPE_YES_NO, &setup.override_level_music, "Override Level Music:" },
3300 { TYPE_STRING, NULL, "Override Level Artwork:"},
3301 { TYPE_YES_NO, &setup.override_level_graphics, "Graphics:" },
3302 { TYPE_YES_NO, &setup.override_level_sounds, "Sounds:" },
3303 { TYPE_YES_NO, &setup.override_level_music, "Music:" },
3305 { TYPE_EMPTY, NULL, "" },
3306 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3311 static struct TokenInfo setup_info_input[] =
3313 { TYPE_SWITCH, NULL, "Player:" },
3314 { TYPE_SWITCH, NULL, "Device:" },
3315 { TYPE_ENTER_MENU, NULL, "" },
3316 { TYPE_EMPTY, NULL, "" },
3317 { TYPE_EMPTY, NULL, "" },
3318 { TYPE_EMPTY, NULL, "" },
3319 { TYPE_EMPTY, NULL, "" },
3320 { TYPE_EMPTY, NULL, "" },
3321 { TYPE_EMPTY, NULL, "" },
3322 { TYPE_EMPTY, NULL, "" },
3323 { TYPE_EMPTY, NULL, "" },
3324 { TYPE_EMPTY, NULL, "" },
3325 { TYPE_EMPTY, NULL, "" },
3326 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3331 static struct TokenInfo setup_info_shortcut_1[] =
3333 { TYPE_KEYTEXT, NULL, "Quick Save Game to Tape:", },
3334 { TYPE_KEY, &setup.shortcut.save_game, "" },
3335 { TYPE_KEYTEXT, NULL, "Quick Load Game from Tape:", },
3336 { TYPE_KEY, &setup.shortcut.load_game, "" },
3337 { TYPE_KEYTEXT, NULL, "Start Game & Toggle Pause:", },
3338 { TYPE_KEY, &setup.shortcut.toggle_pause, "" },
3339 { TYPE_EMPTY, NULL, "" },
3340 { TYPE_YES_NO, &setup.ask_on_escape, "Ask on 'Esc' Key:" },
3341 { TYPE_YES_NO, &setup.ask_on_escape_editor, "Ask on 'Esc' Key (Editor):" },
3342 { TYPE_EMPTY, NULL, "" },
3343 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3348 static struct TokenInfo setup_info_shortcut_2[] =
3350 { TYPE_KEYTEXT, NULL, "Set Focus to Player 1:", },
3351 { TYPE_KEY, &setup.shortcut.focus_player[0], "" },
3352 { TYPE_KEYTEXT, NULL, "Set Focus to Player 2:", },
3353 { TYPE_KEY, &setup.shortcut.focus_player[1], "" },
3354 { TYPE_KEYTEXT, NULL, "Set Focus to Player 3:", },
3355 { TYPE_KEY, &setup.shortcut.focus_player[2], "" },
3356 { TYPE_KEYTEXT, NULL, "Set Focus to Player 4:", },
3357 { TYPE_KEY, &setup.shortcut.focus_player[3], "" },
3358 { TYPE_KEYTEXT, NULL, "Set Focus to All Players:", },
3359 { TYPE_KEY, &setup.shortcut.focus_player_all, "" },
3360 { TYPE_EMPTY, NULL, "" },
3361 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
3366 static Key getSetupKey()
3368 Key key = KSYM_UNDEFINED;
3369 boolean got_key_event = FALSE;
3371 while (!got_key_event)
3373 if (PendingEvent()) /* got event */
3381 case EVENT_KEYPRESS:
3383 key = GetEventKey((KeyEvent *)&event, TRUE);
3385 /* press 'Escape' or 'Enter' to keep the existing key binding */
3386 if (key == KSYM_Escape || key == KSYM_Return)
3387 key = KSYM_UNDEFINED; /* keep old value */
3389 got_key_event = TRUE;
3393 case EVENT_KEYRELEASE:
3394 key_joystick_mapping = 0;
3398 HandleOtherEvents(&event);
3406 /* don't eat all CPU time */
3413 static int getSetupTextFont(int type)
3415 if (type & (TYPE_SWITCH |
3426 static int getSetupValueFont(int type, void *value)
3428 if (type & TYPE_KEY)
3429 return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1);
3430 else if (type & TYPE_STRING)
3431 return FONT_VALUE_2;
3432 else if (type & TYPE_ECS_AGA)
3433 return FONT_VALUE_1;
3434 else if (type & TYPE_BOOLEAN_STYLE)
3435 return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
3437 return FONT_VALUE_1;
3440 static void drawSetupValue(int pos)
3442 boolean font_draw_xoffset_modified = FALSE;
3443 int font_draw_xoffset_old = -1;
3444 int xpos = MENU_SCREEN_VALUE_XPOS;
3445 int ypos = MENU_SCREEN_START_YPOS + pos;
3446 int startx = mSX + xpos * 32;
3447 int starty = mSY + ypos * 32;
3448 int font_nr, font_width;
3449 int type = setup_info[pos].type;
3450 void *value = setup_info[pos].value;
3451 char *value_string = getSetupValue(type, value);
3454 if (value_string == NULL)
3457 if (type & TYPE_KEY)
3459 xpos = MENU_SCREEN_START_XPOS;
3461 if (type & TYPE_QUERY)
3463 value_string = "<press key>";
3466 else if (type & TYPE_STRING)
3468 int max_value_len = (SCR_FIELDX - 2) * 2;
3470 xpos = MENU_SCREEN_START_XPOS;
3472 if (strlen(value_string) > max_value_len)
3473 value_string[max_value_len] = '\0';
3476 startx = mSX + xpos * 32;
3477 starty = mSY + ypos * 32;
3478 font_nr = getSetupValueFont(type, value);
3479 font_width = getFontWidth(font_nr);
3481 /* downward compatibility correction for Juergen Bonhagen's menu settings */
3482 if (setup_mode != SETUP_MODE_INPUT)
3484 int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
3485 int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
3486 int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
3487 int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
3488 int text_font_nr = getSetupTextFont(FONT_MENU_2);
3489 int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
3490 int text_width = MAX_MENU_TEXT_LENGTH_MEDIUM * getFontWidth(text_font_nr);
3491 boolean correct_font_draw_xoffset = FALSE;
3493 if (xpos == MENU_SCREEN_START_XPOS &&
3494 startx + font1_xoffset < text_startx + text_font_xoffset)
3495 correct_font_draw_xoffset = TRUE;
3497 if (xpos == MENU_SCREEN_VALUE_XPOS &&
3498 startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
3499 correct_font_draw_xoffset = TRUE;
3501 /* check if setup value would overlap with setup text when printed */
3502 /* (this can happen for extreme/wrong values for font draw offset) */
3503 if (correct_font_draw_xoffset)
3505 font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
3506 font_draw_xoffset_modified = TRUE;
3508 if (type & TYPE_KEY)
3509 getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
3510 else if (!(type & TYPE_STRING))
3511 getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
3512 MAX_MENU_TEXT_LENGTH_MEDIUM * (16 - getFontWidth(text_font_nr));
3516 for (i = 0; i <= MENU_SCREEN_MAX_XPOS - xpos; i++)
3517 DrawText(startx + i * font_width, starty, " ", font_nr);
3519 DrawText(startx, starty, value_string, font_nr);
3521 if (font_draw_xoffset_modified)
3522 getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
3525 static void changeSetupValue(int pos)
3527 if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
3529 *(boolean *)setup_info[pos].value ^= TRUE;
3531 else if (setup_info[pos].type & TYPE_KEY)
3535 setup_info[pos].type |= TYPE_QUERY;
3536 drawSetupValue(pos);
3537 setup_info[pos].type &= ~TYPE_QUERY;
3539 key = getSetupKey();
3540 if (key != KSYM_UNDEFINED)
3541 *(Key *)setup_info[pos].value = key;
3544 drawSetupValue(pos);
3547 static void DrawCursorAndText_Setup(int pos, boolean active)
3549 int xpos = MENU_SCREEN_START_XPOS;
3550 int ypos = MENU_SCREEN_START_YPOS + pos;
3551 int font_nr = getSetupTextFont(setup_info[pos].type);
3553 if (setup_info == setup_info_input)
3554 font_nr = FONT_MENU_1;
3557 font_nr = FONT_ACTIVE(font_nr);
3559 DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[pos].text, font_nr);
3561 if (setup_info[pos].type & ~TYPE_SKIP_ENTRY)
3562 drawCursor(pos, active);
3565 static void DrawSetupScreen_Generic()
3567 char *title_string = NULL;
3571 CloseDoor(DOOR_CLOSE_2);
3575 if (setup_mode == SETUP_MODE_MAIN)
3577 setup_info = setup_info_main;
3578 title_string = "Setup";
3580 else if (setup_mode == SETUP_MODE_GAME)
3582 setup_info = setup_info_game;
3583 title_string = "Setup Game";
3585 else if (setup_mode == SETUP_MODE_EDITOR)
3587 setup_info = setup_info_editor;
3588 title_string = "Setup Editor";
3590 else if (setup_mode == SETUP_MODE_GRAPHICS)
3592 setup_info = setup_info_graphics;
3593 title_string = "Setup Graphics";
3595 else if (setup_mode == SETUP_MODE_SOUND)
3597 setup_info = setup_info_sound;
3598 title_string = "Setup Sound";
3600 else if (setup_mode == SETUP_MODE_ARTWORK)
3602 setup_info = setup_info_artwork;
3603 title_string = "Custom Artwork";
3605 else if (setup_mode == SETUP_MODE_SHORTCUT_1)
3607 setup_info = setup_info_shortcut_1;
3608 title_string = "Setup Shortcuts";
3610 else if (setup_mode == SETUP_MODE_SHORTCUT_2)
3612 setup_info = setup_info_shortcut_2;
3613 title_string = "Setup Shortcuts";
3616 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
3619 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
3621 void *value_ptr = setup_info[i].value;
3624 int xpos = MENU_SCREEN_START_XPOS;
3625 int ypos = MENU_SCREEN_START_YPOS + i;
3629 /* set some entries to "unchangeable" according to other variables */
3630 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
3631 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
3632 (value_ptr == &setup.sound_music && !audio.music_available) ||
3633 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
3634 (value_ptr == &screen_mode_text && !video.fullscreen_available))
3635 setup_info[i].type |= TYPE_GHOSTED;
3637 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
3638 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
3639 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
3640 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
3641 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
3642 initCursor(i, IMG_MENU_BUTTON);
3645 DrawCursorAndText_Setup(i, FALSE);
3647 font_nr = getSetupTextFont(setup_info[i].type);
3649 DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[i].text, font_nr);
3652 if (setup_info[i].type & TYPE_VALUE)
3659 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
3660 "Joysticks deactivated in setup menu");
3665 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
3668 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
3670 static int choice_store[MAX_SETUP_MODES];
3671 int choice = choice_store[setup_mode]; /* always starts with 0 */
3675 if (button == MB_MENU_INITIALIZE)
3677 /* advance to first valid menu entry */
3678 while (choice < num_setup_info &&
3679 setup_info[choice].type & TYPE_SKIP_ENTRY)
3681 choice_store[setup_mode] = choice;
3684 DrawCursorAndText_Setup(choice, TRUE);
3686 drawCursor(choice, TRUE);
3691 else if (button == MB_MENU_LEAVE)
3693 for (y = 0; y < num_setup_info; y++)
3695 if (setup_info[y].type & TYPE_LEAVE_MENU)
3697 void (*menu_callback_function)(void) = setup_info[y].value;
3699 menu_callback_function();
3701 break; /* absolutely needed because function changes 'setup_info'! */
3708 if (mx || my) /* mouse input */
3710 x = (mx - mSX) / 32;
3711 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
3713 else if (dx || dy) /* keyboard input */
3717 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
3719 if (setup_info[choice].type & menu_navigation_type ||
3720 setup_info[choice].type & TYPE_BOOLEAN_STYLE)
3721 button = MB_MENU_CHOICE;
3726 /* jump to next non-empty menu entry (up or down) */
3727 while (y > 0 && y < num_setup_info - 1 &&
3728 setup_info[y].type & TYPE_SKIP_ENTRY)
3732 if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_setup_info)
3736 if (y != choice && setup_info[y].type & ~TYPE_SKIP_ENTRY)
3739 DrawCursorAndText_Setup(choice, FALSE);
3740 DrawCursorAndText_Setup(y, TRUE);
3742 drawCursor(choice, FALSE);
3743 drawCursor(y, TRUE);
3746 choice = choice_store[setup_mode] = y;
3749 else if (!(setup_info[y].type & TYPE_GHOSTED))
3751 /* when selecting key headline, execute function for key value change */
3752 if (setup_info[y].type & TYPE_KEYTEXT &&
3753 setup_info[y + 1].type & TYPE_KEY)
3756 /* when selecting string value, execute function for list selection */
3757 if (setup_info[y].type & TYPE_STRING && y > 0 &&
3758 setup_info[y - 1].type & TYPE_ENTER_LIST)
3761 if (setup_info[y].type & TYPE_ENTER_OR_LEAVE)
3763 void (*menu_callback_function)(void) = setup_info[y].value;
3765 menu_callback_function();
3769 if (setup_info[y].type & TYPE_VALUE)
3770 changeSetupValue(y);
3776 void DrawSetupScreen_Input()
3785 setup_info = setup_info_input;
3788 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input");
3791 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
3793 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
3794 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
3795 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
3796 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
3797 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
3798 initCursor(i, IMG_MENU_BUTTON);
3800 DrawCursorAndText_Setup(i, FALSE);
3803 initCursor(0, IMG_MENU_BUTTON);
3804 initCursor(1, IMG_MENU_BUTTON);
3805 initCursor(2, IMG_MENU_BUTTON_ENTER_MENU);
3806 initCursor(13, IMG_MENU_BUTTON_LEAVE_MENU);
3808 DrawText(mSX + 32, mSY + 2 * 32, "Player:", FONT_MENU_1);
3809 DrawText(mSX + 32, mSY + 3 * 32, "Device:", FONT_MENU_1);
3810 DrawText(mSX + 32, mSY + 15 * 32, "Back", FONT_MENU_1);
3814 DeactivateJoystickForCalibration();
3817 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
3818 "Joysticks deactivated on this screen");
3821 /* create gadgets for setup input menu screen */
3822 FreeScreenGadgets();
3823 CreateScreenGadgets();
3825 /* map gadgets for setup input menu screen */
3826 MapScreenMenuGadgets(SCREEN_MASK_INPUT);
3828 HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE);
3833 static void setJoystickDeviceToNr(char *device_name, int device_nr)
3835 if (device_name == NULL)
3838 if (device_nr < 0 || device_nr >= MAX_PLAYERS)
3841 if (strlen(device_name) > 1)
3843 char c1 = device_name[strlen(device_name) - 1];
3844 char c2 = device_name[strlen(device_name) - 2];
3846 if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9'))
3847 device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
3850 strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
3851 strlen(device_name));
3854 static void drawPlayerSetupInputInfo(int player_nr, boolean active)
3857 static struct SetupKeyboardInfo custom_key;
3864 { &custom_key.left, "Joystick Left" },
3865 { &custom_key.right, "Joystick Right" },
3866 { &custom_key.up, "Joystick Up" },
3867 { &custom_key.down, "Joystick Down" },
3868 { &custom_key.snap, "Button 1" },
3869 { &custom_key.drop, "Button 2" }
3871 static char *joystick_name[MAX_PLAYERS] =
3878 int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1);
3882 custom_key = setup.input[player_nr].key;
3884 DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
3885 FONT_INPUT_1_ACTIVE);
3887 ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
3889 DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
3890 PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
3892 if (setup.input[player_nr].use_joystick)
3894 char *device_name = setup.input[player_nr].joy.device_name;
3895 char *text = joystick_name[getJoystickNrFromDeviceName(device_name)];
3896 int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1);
3898 DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
3899 DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr);
3903 DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1);
3904 DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr);
3907 DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1);
3909 drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
3910 drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
3911 drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
3912 drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
3914 DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD);
3915 DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD);
3916 DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD);
3917 DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD);
3918 DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD);
3919 DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD);
3921 for (i = 0; i < 6; i++)
3923 int ypos = 6 + i + (i > 3 ? i-3 : 0);
3925 DrawText(mSX + 3 * 32, mSY + ypos * 32,
3927 DrawText(mSX + 3 * 32, mSY + ypos * 32,
3928 (setup.input[player_nr].use_joystick ?
3930 getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
3934 static int input_player_nr = 0;
3936 void HandleSetupScreen_Input_Player(int step, int direction)
3938 int old_player_nr = input_player_nr;
3941 new_player_nr = old_player_nr + step * direction;
3942 if (new_player_nr < 0)
3944 if (new_player_nr > MAX_PLAYERS - 1)
3945 new_player_nr = MAX_PLAYERS - 1;
3947 if (new_player_nr != old_player_nr)
3949 input_player_nr = new_player_nr;
3951 drawPlayerSetupInputInfo(input_player_nr, FALSE);
3955 void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
3957 static int choice = 0;
3960 int pos_start = SETUPINPUT_SCREEN_POS_START;
3961 int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1;
3962 int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2;
3963 int pos_end = SETUPINPUT_SCREEN_POS_END;
3965 if (button == MB_MENU_INITIALIZE)
3967 drawPlayerSetupInputInfo(input_player_nr, (choice == 2));
3970 DrawCursorAndText_Setup(choice, TRUE);
3972 drawCursor(choice, TRUE);
3977 else if (button == MB_MENU_LEAVE)
3979 setup_mode = SETUP_MODE_MAIN;
3986 if (mx || my) /* mouse input */
3988 x = (mx - mSX) / 32;
3989 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
3991 else if (dx || dy) /* keyboard input */
3993 if (dx && choice == 0)
3994 x = (dx < 0 ? 10 : 12);
3995 else if ((dx && choice == 1) ||
3996 (dx == +1 && choice == 2) ||
3997 (dx == -1 && choice == pos_end))
3998 button = MB_MENU_CHOICE;
4002 if (y >= pos_empty1 && y <= pos_empty2)
4003 y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
4006 if (y == 0 && dx != 0 && button)
4008 HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1);
4010 else if (IN_VIS_FIELD(x, y) &&
4011 y >= pos_start && y <= pos_end &&
4012 !(y >= pos_empty1 && y <= pos_empty2))
4019 DrawCursorAndText_Setup(choice, FALSE);
4020 DrawCursorAndText_Setup(y, TRUE);
4022 drawPlayerSetupInputInfo(input_player_nr, (y == 2));
4024 drawCursor(choice, FALSE);
4025 drawCursor(y, TRUE);
4035 char *device_name = setup.input[input_player_nr].joy.device_name;
4037 if (!setup.input[input_player_nr].use_joystick)
4039 int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1);
4041 setJoystickDeviceToNr(device_name, new_device_nr);
4042 setup.input[input_player_nr].use_joystick = TRUE;
4046 int device_nr = getJoystickNrFromDeviceName(device_name);
4047 int new_device_nr = device_nr + (dx >= 0 ? +1 : -1);
4049 if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS)
4050 setup.input[input_player_nr].use_joystick = FALSE;
4052 setJoystickDeviceToNr(device_name, new_device_nr);
4055 drawPlayerSetupInputInfo(input_player_nr, FALSE);
4059 if (setup.input[input_player_nr].use_joystick)
4062 CalibrateJoystick(input_player_nr);
4065 CustomizeKeyboard(input_player_nr);
4067 else if (y == pos_end)
4071 setup_mode = SETUP_MODE_MAIN;
4078 void CustomizeKeyboard(int player_nr)
4082 boolean finished = FALSE;
4083 static struct SetupKeyboardInfo custom_key;
4088 } customize_step[] =
4090 { &custom_key.left, "Move Left" },
4091 { &custom_key.right, "Move Right" },
4092 { &custom_key.up, "Move Up" },
4093 { &custom_key.down, "Move Down" },
4094 { &custom_key.snap, "Snap Field" },
4095 { &custom_key.drop, "Drop Element" }
4098 /* read existing key bindings from player setup */
4099 custom_key = setup.input[player_nr].key;
4103 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input");
4109 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
4110 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
4111 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
4112 "Key:", FONT_INPUT_1_ACTIVE);
4113 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4114 getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
4118 if (PendingEvent()) /* got event */
4126 case EVENT_KEYPRESS:
4128 Key key = GetEventKey((KeyEvent *)&event, FALSE);
4130 if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
4136 /* all keys configured -- wait for "Escape" or "Return" key */
4140 /* press 'Enter' to keep the existing key binding */
4141 if (key == KSYM_Return)
4142 key = *customize_step[step_nr].key;
4144 /* check if key already used */
4145 for (i = 0; i < step_nr; i++)
4146 if (*customize_step[i].key == key)
4151 /* got new key binding */
4152 *customize_step[step_nr].key = key;
4153 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4155 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4156 getKeyNameFromKey(key), FONT_VALUE_1);
4159 /* un-highlight last query */
4160 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32,
4161 customize_step[step_nr - 1].text, FONT_MENU_1);
4162 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32,
4163 "Key:", FONT_MENU_1);
4165 /* press 'Enter' to leave */
4168 DrawText(mSX + 16, mSY + 15 * 32 + 16,
4169 "Press Enter", FONT_TITLE_1);
4173 /* query next key binding */
4174 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
4175 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
4176 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
4177 "Key:", FONT_INPUT_1_ACTIVE);
4178 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
4179 getKeyNameFromKey(*customize_step[step_nr].key),
4184 case EVENT_KEYRELEASE:
4185 key_joystick_mapping = 0;
4189 HandleOtherEvents(&event);
4197 /* don't eat all CPU time */
4201 /* write new key bindings back to player setup */
4202 setup.input[player_nr].key = custom_key;
4205 DrawSetupScreen_Input();
4208 static boolean CalibrateJoystickMain(int player_nr)
4210 int new_joystick_xleft = JOYSTICK_XMIDDLE;
4211 int new_joystick_xright = JOYSTICK_XMIDDLE;
4212 int new_joystick_yupper = JOYSTICK_YMIDDLE;
4213 int new_joystick_ylower = JOYSTICK_YMIDDLE;
4214 int new_joystick_xmiddle, new_joystick_ymiddle;
4216 int joystick_fd = joystick.fd[player_nr];
4217 int x, y, last_x, last_y, xpos = 8, ypos = 3;
4218 boolean check[3][3];
4219 int check_remaining = 3 * 3;
4224 if (joystick.status == JOYSTICK_NOT_AVAILABLE)
4227 if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
4232 for (y = 0; y < 3; y++)
4234 for (x = 0; x < 3; x++)
4236 DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
4237 check[x][y] = FALSE;
4241 DrawTextSCentered(mSY - SY + 6 * 32, FONT_TITLE_1, "Rotate joystick");
4242 DrawTextSCentered(mSY - SY + 7 * 32, FONT_TITLE_1, "in all directions");
4243 DrawTextSCentered(mSY - SY + 9 * 32, FONT_TITLE_1, "if all balls");
4244 DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,");
4245 DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick");
4246 DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and");
4247 DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!");
4249 joy_value = Joystick(player_nr);
4250 last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
4251 last_y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
4253 /* eventually uncalibrated center position (joystick could be uncentered) */
4254 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
4257 new_joystick_xmiddle = joy_x;
4258 new_joystick_ymiddle = joy_y;
4260 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
4263 while (Joystick(player_nr) & JOY_BUTTON); /* wait for released button */
4268 if (PendingEvent()) /* got event */
4276 case EVENT_KEYPRESS:
4277 switch (GetEventKey((KeyEvent *)&event, TRUE))
4280 if (check_remaining == 0)
4293 case EVENT_KEYRELEASE:
4294 key_joystick_mapping = 0;
4298 HandleOtherEvents(&event);
4303 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
4306 new_joystick_xleft = MIN(new_joystick_xleft, joy_x);
4307 new_joystick_xright = MAX(new_joystick_xright, joy_x);
4308 new_joystick_yupper = MIN(new_joystick_yupper, joy_y);
4309 new_joystick_ylower = MAX(new_joystick_ylower, joy_y);
4311 setup.input[player_nr].joy.xleft = new_joystick_xleft;
4312 setup.input[player_nr].joy.yupper = new_joystick_yupper;
4313 setup.input[player_nr].joy.xright = new_joystick_xright;
4314 setup.input[player_nr].joy.ylower = new_joystick_ylower;
4315 setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle;
4316 setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle;
4318 CheckJoystickData();
4320 joy_value = Joystick(player_nr);
4322 if (joy_value & JOY_BUTTON && check_remaining == 0)
4325 x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
4326 y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
4328 if (x != last_x || y != last_y)
4330 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0);
4331 DrawGraphic(xpos + x, ypos + y, IMG_MENU_CALIBRATE_RED, 0);
4336 if (check_remaining > 0 && !check[x+1][y+1])
4338 check[x+1][y+1] = TRUE;
4344 printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
4345 setup.input[player_nr].joy.xleft,
4346 setup.input[player_nr].joy.xmiddle,
4347 setup.input[player_nr].joy.xright);
4348 printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
4349 setup.input[player_nr].joy.yupper,
4350 setup.input[player_nr].joy.ymiddle,
4351 setup.input[player_nr].joy.ylower);
4360 /* don't eat all CPU time */
4364 /* calibrated center position (joystick should now be centered) */
4365 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
4368 new_joystick_xmiddle = joy_x;
4369 new_joystick_ymiddle = joy_y;
4374 DrawSetupScreen_Input();
4377 /* wait until the last pressed button was released */
4378 while (Joystick(player_nr) & JOY_BUTTON)
4380 if (PendingEvent()) /* got event */
4385 HandleOtherEvents(&event);
4394 void CalibrateJoystick(int player_nr)
4396 if (!CalibrateJoystickMain(player_nr))
4398 char *device_name = setup.input[player_nr].joy.device_name;
4399 int nr = getJoystickNrFromDeviceName(device_name) + 1;
4400 int xpos = mSX - SX;
4401 int ypos = mSY - SY;
4405 DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr);
4406 DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! ");
4409 Delay(2000); /* show error message for a short time */
4415 DrawSetupScreen_Input();
4419 void DrawSetupScreen()
4421 DeactivateJoystick();
4423 SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
4425 if (setup_mode == SETUP_MODE_INPUT)
4426 DrawSetupScreen_Input();
4427 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
4428 DrawChooseTree(&screen_mode_current);
4429 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
4430 DrawChooseTree(&artwork.gfx_current);
4431 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
4432 DrawChooseTree(&artwork.snd_current);
4433 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
4434 DrawChooseTree(&artwork.mus_current);
4436 DrawSetupScreen_Generic();
4442 void RedrawSetupScreenAfterFullscreenToggle()
4444 if (setup_mode == SETUP_MODE_GRAPHICS)
4448 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
4450 if (setup_mode == SETUP_MODE_INPUT)
4451 HandleSetupScreen_Input(mx, my, dx, dy, button);
4452 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
4453 HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
4454 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
4455 HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
4456 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
4457 HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
4458 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
4459 HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
4461 HandleSetupScreen_Generic(mx, my, dx, dy, button);
4466 void HandleGameActions()
4468 if (game_status != GAME_MODE_PLAYING)
4471 GameActions(); /* main game loop */
4473 if (tape.auto_play && !tape.playing)
4474 AutoPlayTape(); /* continue automatically playing next tape */
4478 /* ---------- new screen button stuff -------------------------------------- */
4480 static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
4485 case SCREEN_CTRL_ID_PREV_LEVEL:
4486 *x = mSX + menu.main.button.prev_level.x;
4487 *y = mSY + menu.main.button.prev_level.y;
4490 case SCREEN_CTRL_ID_NEXT_LEVEL:
4491 *x = mSX + menu.main.button.next_level.x;
4492 *y = mSY + menu.main.button.next_level.y;
4495 case SCREEN_CTRL_ID_PREV_LEVEL:
4496 *x = mSX + TILEX * getPrevlevelButtonPos();
4497 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
4500 case SCREEN_CTRL_ID_NEXT_LEVEL:
4501 *x = mSX + TILEX * getNextLevelButtonPos();
4502 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
4506 case SCREEN_CTRL_ID_PREV_PLAYER:
4507 *x = mSX + TILEX * 10;
4508 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
4511 case SCREEN_CTRL_ID_NEXT_PLAYER:
4512 *x = mSX + TILEX * 12;
4513 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
4517 Error(ERR_EXIT, "unknown gadget ID %d", gadget_id);
4523 int gfx_unpressed, gfx_pressed;
4524 void (*get_gadget_position)(int *, int *, int);
4528 } menubutton_info[NUM_SCREEN_MENUBUTTONS] =
4531 IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE,
4532 getScreenMenuButtonPos,
4533 SCREEN_CTRL_ID_PREV_LEVEL,
4538 IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE,
4539 getScreenMenuButtonPos,
4540 SCREEN_CTRL_ID_NEXT_LEVEL,
4545 IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE,
4546 getScreenMenuButtonPos,
4547 SCREEN_CTRL_ID_PREV_PLAYER,
4552 IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE,
4553 getScreenMenuButtonPos,
4554 SCREEN_CTRL_ID_NEXT_PLAYER,
4562 int gfx_unpressed, gfx_pressed;
4566 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
4569 IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
4570 SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
4571 SCREEN_CTRL_ID_SCROLL_UP,
4575 IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
4576 SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
4577 SCREEN_CTRL_ID_SCROLL_DOWN,
4584 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4585 Bitmap **gfx_unpressed, **gfx_pressed;
4587 int gfx_unpressed, gfx_pressed;
4594 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
4597 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4598 &scrollbar_bitmap[0], &scrollbar_bitmap[1],
4600 IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
4602 SC_SCROLL_VERTICAL_XPOS, SC_SCROLL_VERTICAL_YPOS,
4603 SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
4604 GD_TYPE_SCROLLBAR_VERTICAL,
4605 SCREEN_CTRL_ID_SCROLL_VERTICAL,
4606 "scroll level series vertically"
4610 static void CreateScreenMenubuttons()
4612 struct GadgetInfo *gi;
4613 unsigned long event_mask;
4616 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
4618 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
4619 int gfx_unpressed, gfx_pressed;
4620 int x, y, width, height;
4621 int gd_x1, gd_x2, gd_y1, gd_y2;
4622 int id = menubutton_info[i].gadget_id;
4624 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
4626 menubutton_info[i].get_gadget_position(&x, &y, id);
4628 width = SC_MENUBUTTON_XSIZE;
4629 height = SC_MENUBUTTON_YSIZE;
4631 gfx_unpressed = menubutton_info[i].gfx_unpressed;
4632 gfx_pressed = menubutton_info[i].gfx_pressed;
4633 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
4634 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
4635 gd_x1 = graphic_info[gfx_unpressed].src_x;
4636 gd_y1 = graphic_info[gfx_unpressed].src_y;
4637 gd_x2 = graphic_info[gfx_pressed].src_x;
4638 gd_y2 = graphic_info[gfx_pressed].src_y;
4640 gi = CreateGadget(GDI_CUSTOM_ID, id,
4641 GDI_CUSTOM_TYPE_ID, i,
4642 GDI_INFO_TEXT, menubutton_info[i].infotext,
4647 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4648 GDI_STATE, GD_BUTTON_UNPRESSED,
4649 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
4650 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
4651 GDI_DIRECT_DRAW, FALSE,
4652 GDI_EVENT_MASK, event_mask,
4653 GDI_CALLBACK_ACTION, HandleScreenGadgets,
4657 Error(ERR_EXIT, "cannot create gadget");
4659 screen_gadget[id] = gi;
4663 static void CreateScreenScrollbuttons()
4665 struct GadgetInfo *gi;
4666 unsigned long event_mask;
4669 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
4671 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
4672 int gfx_unpressed, gfx_pressed;
4673 int x, y, width, height;
4674 int gd_x1, gd_x2, gd_y1, gd_y2;
4675 int id = scrollbutton_info[i].gadget_id;
4677 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
4679 x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset;
4680 y = mSY + scrollbutton_info[i].y;
4681 width = SC_SCROLLBUTTON_XSIZE;
4682 height = SC_SCROLLBUTTON_YSIZE;
4684 if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
4685 y = mSY + (SC_SCROLL_VERTICAL_YPOS +
4686 (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE);
4688 gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
4689 gfx_pressed = scrollbutton_info[i].gfx_pressed;
4690 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
4691 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
4692 gd_x1 = graphic_info[gfx_unpressed].src_x;
4693 gd_y1 = graphic_info[gfx_unpressed].src_y;
4694 gd_x2 = graphic_info[gfx_pressed].src_x;
4695 gd_y2 = graphic_info[gfx_pressed].src_y;
4697 gi = CreateGadget(GDI_CUSTOM_ID, id,
4698 GDI_CUSTOM_TYPE_ID, i,
4699 GDI_INFO_TEXT, scrollbutton_info[i].infotext,
4704 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4705 GDI_STATE, GD_BUTTON_UNPRESSED,
4706 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
4707 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
4708 GDI_DIRECT_DRAW, FALSE,
4709 GDI_EVENT_MASK, event_mask,
4710 GDI_CALLBACK_ACTION, HandleScreenGadgets,
4714 Error(ERR_EXIT, "cannot create gadget");
4716 screen_gadget[id] = gi;
4720 static void CreateScreenScrollbars()
4724 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
4726 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
4727 #if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4728 int gfx_unpressed, gfx_pressed;
4730 int x, y, width, height;
4731 int gd_x1, gd_x2, gd_y1, gd_y2;
4732 struct GadgetInfo *gi;
4733 int items_max, items_visible, item_position;
4734 unsigned long event_mask;
4735 int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
4736 int id = scrollbar_info[i].gadget_id;
4738 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
4740 x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset;
4741 y = mSY + scrollbar_info[i].y;
4742 width = scrollbar_info[i].width;
4743 height = scrollbar_info[i].height;
4745 if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
4746 height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;
4748 items_max = num_page_entries;
4749 items_visible = num_page_entries;
4752 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4753 gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
4754 gd_bitmap_pressed = *scrollbar_info[i].gfx_pressed;
4760 gfx_unpressed = scrollbar_info[i].gfx_unpressed;
4761 gfx_pressed = scrollbar_info[i].gfx_pressed;
4762 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
4763 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
4764 gd_x1 = graphic_info[gfx_unpressed].src_x;
4765 gd_y1 = graphic_info[gfx_unpressed].src_y;
4766 gd_x2 = graphic_info[gfx_pressed].src_x;
4767 gd_y2 = graphic_info[gfx_pressed].src_y;
4770 gi = CreateGadget(GDI_CUSTOM_ID, id,
4771 GDI_CUSTOM_TYPE_ID, i,
4772 GDI_INFO_TEXT, scrollbar_info[i].infotext,
4777 GDI_TYPE, scrollbar_info[i].type,
4778 GDI_SCROLLBAR_ITEMS_MAX, items_max,
4779 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
4780 GDI_SCROLLBAR_ITEM_POSITION, item_position,
4782 GDI_WHEEL_AREA_X, SX,
4783 GDI_WHEEL_AREA_Y, SY,
4784 GDI_WHEEL_AREA_WIDTH, SXSIZE,
4785 GDI_WHEEL_AREA_HEIGHT, SYSIZE,
4787 GDI_WHEEL_AREA_X, 0,
4788 GDI_WHEEL_AREA_Y, 0,
4789 GDI_WHEEL_AREA_WIDTH, WIN_XSIZE,
4790 GDI_WHEEL_AREA_HEIGHT, WIN_YSIZE,
4792 GDI_STATE, GD_BUTTON_UNPRESSED,
4793 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
4794 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
4795 GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
4796 GDI_DIRECT_DRAW, FALSE,
4797 GDI_EVENT_MASK, event_mask,
4798 GDI_CALLBACK_ACTION, HandleScreenGadgets,
4802 Error(ERR_EXIT, "cannot create gadget");
4804 screen_gadget[id] = gi;
4808 void CreateScreenGadgets()
4810 int last_game_status = game_status; /* save current game status */
4812 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4815 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
4817 scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
4819 /* copy pointers to clip mask and GC */
4820 scrollbar_bitmap[i]->clip_mask =
4821 graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
4822 scrollbar_bitmap[i]->stored_clip_gc =
4823 graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
4825 BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
4826 scrollbar_bitmap[i],
4827 graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
4828 graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
4829 TILEX, TILEY, 0, 0);
4833 CreateScreenMenubuttons();
4835 /* force LEVELS draw offset for scrollbar / scrollbutton gadgets */
4836 game_status = GAME_MODE_LEVELS;
4838 CreateScreenScrollbuttons();
4839 CreateScreenScrollbars();
4841 game_status = last_game_status; /* restore current game status */
4844 void FreeScreenGadgets()
4848 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
4849 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
4851 /* prevent freeing clip mask and GC twice */
4852 scrollbar_bitmap[i]->clip_mask = None;
4853 scrollbar_bitmap[i]->stored_clip_gc = None;
4855 FreeBitmap(scrollbar_bitmap[i]);
4859 for (i = 0; i < NUM_SCREEN_GADGETS; i++)
4860 FreeGadget(screen_gadget[i]);
4863 void MapScreenMenuGadgets(int screen_mask)
4867 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
4868 if (screen_mask & menubutton_info[i].screen_mask)
4869 MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
4872 void MapScreenTreeGadgets(TreeInfo *ti)
4874 int num_entries = numTreeInfoInGroup(ti);
4877 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
4880 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
4881 MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
4883 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
4884 MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
4887 static void HandleScreenGadgets(struct GadgetInfo *gi)
4889 int id = gi->custom_id;
4890 int button = gi->event.button;
4891 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
4895 case SCREEN_CTRL_ID_PREV_LEVEL:
4896 HandleMainMenu_SelectLevel(step, -1);
4899 case SCREEN_CTRL_ID_NEXT_LEVEL:
4900 HandleMainMenu_SelectLevel(step, +1);
4903 case SCREEN_CTRL_ID_PREV_PLAYER:
4904 HandleSetupScreen_Input_Player(step, -1);
4907 case SCREEN_CTRL_ID_NEXT_PLAYER:
4908 HandleSetupScreen_Input_Player(step, +1);
4911 case SCREEN_CTRL_ID_SCROLL_UP:
4912 if (game_status == GAME_MODE_LEVELS)
4913 HandleChooseLevel(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
4914 else if (game_status == GAME_MODE_SETUP)
4915 HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
4918 case SCREEN_CTRL_ID_SCROLL_DOWN:
4919 if (game_status == GAME_MODE_LEVELS)
4920 HandleChooseLevel(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
4921 else if (game_status == GAME_MODE_SETUP)
4922 HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
4925 case SCREEN_CTRL_ID_SCROLL_VERTICAL:
4926 if (game_status == GAME_MODE_LEVELS)
4927 HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
4928 else if (game_status == GAME_MODE_SETUP)
4929 HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);