1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
28 /* screens on the info screen */
29 #define INFO_MODE_MAIN 0
30 #define INFO_MODE_TITLE 1
31 #define INFO_MODE_ELEMENTS 2
32 #define INFO_MODE_MUSIC 3
33 #define INFO_MODE_CREDITS 4
34 #define INFO_MODE_PROGRAM 5
35 #define INFO_MODE_VERSION 6
36 #define INFO_MODE_LEVELSET 7
38 #define MAX_INFO_MODES 8
40 /* screens on the setup screen */
41 #define SETUP_MODE_MAIN 0
42 #define SETUP_MODE_GAME 1
43 #define SETUP_MODE_EDITOR 2
44 #define SETUP_MODE_GRAPHICS 3
45 #define SETUP_MODE_SOUND 4
46 #define SETUP_MODE_ARTWORK 5
47 #define SETUP_MODE_INPUT 6
48 #define SETUP_MODE_SHORTCUTS_1 7
49 #define SETUP_MODE_SHORTCUTS_2 8
51 /* sub-screens on the setup screen (generic) */
52 #define SETUP_MODE_CHOOSE_ARTWORK 9
53 #define SETUP_MODE_CHOOSE_OTHER 10
55 /* sub-screens on the setup screen (specific) */
56 #define SETUP_MODE_CHOOSE_GAME_SPEED 11
57 #define SETUP_MODE_CHOOSE_SCREEN_MODE 12
58 #define SETUP_MODE_CHOOSE_SCROLL_DELAY 13
59 #define SETUP_MODE_CHOOSE_GRAPHICS 14
60 #define SETUP_MODE_CHOOSE_SOUNDS 15
61 #define SETUP_MODE_CHOOSE_MUSIC 16
63 #define MAX_SETUP_MODES 17
65 /* for input setup functions */
66 #define SETUPINPUT_SCREEN_POS_START 0
67 #define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4)
68 #define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3)
69 #define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1)
71 /* for various menu stuff */
72 #define MENU_SCREEN_START_XPOS 1
73 #define MENU_SCREEN_START_YPOS 2
74 #define MENU_SCREEN_VALUE_XPOS 14
75 #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1)
76 #define MENU_TITLE1_YPOS 8
77 #define MENU_TITLE2_YPOS 46
78 #define MAX_INFO_ELEMENTS_ON_SCREEN 10
79 #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS)
80 #define MAX_MENU_TEXT_LENGTH_BIG (MENU_SCREEN_VALUE_XPOS - \
81 MENU_SCREEN_START_XPOS)
82 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2)
84 /* buttons and scrollbars identifiers */
85 #define SCREEN_CTRL_ID_PREV_LEVEL 0
86 #define SCREEN_CTRL_ID_NEXT_LEVEL 1
87 #define SCREEN_CTRL_ID_PREV_PLAYER 2
88 #define SCREEN_CTRL_ID_NEXT_PLAYER 3
89 #define SCREEN_CTRL_ID_SCROLL_UP 4
90 #define SCREEN_CTRL_ID_SCROLL_DOWN 5
91 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 6
93 #define NUM_SCREEN_GADGETS 7
95 #define NUM_SCREEN_MENUBUTTONS 4
96 #define NUM_SCREEN_SCROLLBUTTONS 2
97 #define NUM_SCREEN_SCROLLBARS 1
99 #define SCREEN_MASK_MAIN (1 << 0)
100 #define SCREEN_MASK_INPUT (1 << 1)
102 /* graphic position and size values for buttons and scrollbars */
103 #define SC_MENUBUTTON_XSIZE TILEX
104 #define SC_MENUBUTTON_YSIZE TILEY
106 #define SC_SCROLLBUTTON_XSIZE TILEX
107 #define SC_SCROLLBUTTON_YSIZE TILEY
109 #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
111 #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
112 #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
113 SC_SCROLLBUTTON_YSIZE)
115 #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS
116 #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE)
118 #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS
119 #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \
120 SC_SCROLLBUTTON_YSIZE)
122 #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS
123 #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \
124 SC_SCROLL_VERTICAL_YSIZE)
126 #define SC_BORDER_SIZE 14
129 /* forward declarations of internal functions */
130 static void HandleScreenGadgets(struct GadgetInfo *);
131 static void HandleSetupScreen_Generic(int, int, int, int, int);
132 static void HandleSetupScreen_Input(int, int, int, int, int);
133 static void CustomizeKeyboard(int);
134 static void CalibrateJoystick(int);
135 static void execSetupGame(void);
136 static void execSetupGraphics(void);
137 static void execSetupArtwork(void);
138 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
140 static void DrawChooseLevel(void);
141 static void DrawInfoScreen(void);
142 static void DrawAndFadeInInfoScreen(int);
143 static void DrawSetupScreen(void);
145 static void DrawInfoScreenExt(int, int);
146 static void DrawInfoScreen_NotAvailable(char *, char *);
147 static void DrawInfoScreen_HelpAnim(int, int, boolean);
148 static void DrawInfoScreen_HelpText(int, int, int, int);
149 static void HandleInfoScreen_Main(int, int, int, int, int);
150 static void HandleInfoScreen_TitleScreen(int);
151 static void HandleInfoScreen_Elements(int);
152 static void HandleInfoScreen_Music(int);
153 static void HandleInfoScreen_Credits(int);
154 static void HandleInfoScreen_Program(int);
155 static void HandleInfoScreen_Version(int);
157 static void MapScreenMenuGadgets(int);
158 static void MapScreenTreeGadgets(TreeInfo *);
160 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
162 static int info_mode = INFO_MODE_MAIN;
163 static int setup_mode = SETUP_MODE_MAIN;
165 static TreeInfo *screen_modes = NULL;
166 static TreeInfo *screen_mode_current = NULL;
168 static TreeInfo *scroll_delays = NULL;
169 static TreeInfo *scroll_delay_current = NULL;
171 static TreeInfo *game_speeds = NULL;
172 static TreeInfo *game_speed_current = NULL;
178 } game_speeds_list[] =
187 { 1000, "1/1s (Extremely Slow)" },
192 { 29, "1/35s (Original Supaplex)" },
194 { 20, "1/50s (Normal Speed)" },
195 { 14, "1/70s (Maximum Supaplex)" },
199 { 1, "1/1000s (Extremely Fast)" },
209 } scroll_delays_list[] =
211 { 0, "0 Tiles (No Scroll Delay)" },
214 { 3, "3 Tiles (Default)" },
219 { 8, "8 Tiles (Maximum Scroll Delay)"},
224 #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \
225 (s) <= GAME_MODE_SETUP ? (s) : \
226 (s) == GAME_MODE_PSEUDO_TYPENAME ? \
227 GAME_MODE_MAIN : GAME_MODE_DEFAULT)
229 /* (there are no draw offset definitions needed for INFO_MODE_TITLE) */
230 #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_ELEMENTS && \
231 (i) <= INFO_MODE_LEVELSET ? (i) : \
234 #define DRAW_MODE_SETUP(i) ((i) >= SETUP_MODE_MAIN && \
235 (i) <= SETUP_MODE_SHORTCUTS_2 ? (i) : \
236 (i) >= SETUP_MODE_CHOOSE_GRAPHICS && \
237 (i) <= SETUP_MODE_CHOOSE_MUSIC ? \
238 SETUP_MODE_CHOOSE_ARTWORK : \
239 SETUP_MODE_CHOOSE_OTHER)
241 #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
242 menu.draw_xoffset[GAME_MODE_INFO] : \
243 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
244 #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
245 menu.draw_yoffset[GAME_MODE_INFO] : \
246 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
248 #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
249 menu.draw_xoffset[GAME_MODE_SETUP] : \
250 menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)])
251 #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
252 menu.draw_yoffset[GAME_MODE_SETUP] : \
253 menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)])
255 #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \
256 DRAW_XOFFSET_INFO(info_mode) : \
257 (s) == GAME_MODE_SETUP ? \
258 DRAW_XOFFSET_SETUP(setup_mode) : \
259 menu.draw_xoffset[DRAW_MODE(s)])
260 #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \
261 DRAW_YOFFSET_INFO(info_mode) : \
262 (s) == GAME_MODE_SETUP ? \
263 DRAW_YOFFSET_SETUP(setup_mode) : \
264 menu.draw_yoffset[DRAW_MODE(s)])
266 #define mSX (SX + DRAW_XOFFSET(game_status))
267 #define mSY (SY + DRAW_YOFFSET(game_status))
269 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \
270 menu.list_size[game_status] : \
271 MAX_MENU_ENTRIES_ON_SCREEN)
273 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
274 #define NUM_SCROLLBAR_BITMAPS 2
275 static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
279 /* title display and control definitions */
281 #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \
282 2 * MAX_NUM_TITLE_MESSAGES)
284 static int num_title_screens = 0;
286 struct TitleControlInfo
294 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
296 /* main menu display and control definitions */
298 #define MAIN_CONTROL_NAME 0
299 #define MAIN_CONTROL_LEVELS 1
300 #define MAIN_CONTROL_SCORES 2
301 #define MAIN_CONTROL_EDITOR 3
302 #define MAIN_CONTROL_INFO 4
303 #define MAIN_CONTROL_GAME 5
304 #define MAIN_CONTROL_SETUP 6
305 #define MAIN_CONTROL_QUIT 7
306 #define MAIN_CONTROL_PREV_LEVEL 8
307 #define MAIN_CONTROL_NEXT_LEVEL 9
308 #define MAIN_CONTROL_FIRST_LEVEL 10
309 #define MAIN_CONTROL_LAST_LEVEL 11
310 #define MAIN_CONTROL_LEVEL_NUMBER 12
311 #define MAIN_CONTROL_LEVEL_INFO_1 13
312 #define MAIN_CONTROL_LEVEL_INFO_2 14
313 #define MAIN_CONTROL_LEVEL_NAME 15
314 #define MAIN_CONTROL_LEVEL_AUTHOR 16
315 #define MAIN_CONTROL_LEVEL_YEAR 17
316 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM 18
317 #define MAIN_CONTROL_LEVEL_IMPORTED_BY 19
318 #define MAIN_CONTROL_LEVEL_TESTED_BY 20
319 #define MAIN_CONTROL_TITLE_1 21
320 #define MAIN_CONTROL_TITLE_2 22
321 #define MAIN_CONTROL_TITLE_3 23
323 static char str_main_text_name[10];
324 static char str_main_text_first_level[10];
325 static char str_main_text_last_level[10];
326 static char str_main_text_level_number[10];
328 static char *main_text_name = str_main_text_name;
329 static char *main_text_first_level = str_main_text_first_level;
330 static char *main_text_last_level = str_main_text_last_level;
331 static char *main_text_level_number = str_main_text_level_number;
332 static char *main_text_levels = "Levelset";
333 static char *main_text_scores = "Hall Of Fame";
334 static char *main_text_editor = "Level Creator";
335 static char *main_text_info = "Info Screen";
336 static char *main_text_game = "Start Game";
337 static char *main_text_setup = "Setup";
338 static char *main_text_quit = "Quit";
339 static char *main_text_level_name = level.name;
340 static char *main_text_level_author = level.author;
341 static char *main_text_level_year = NULL;
342 static char *main_text_level_imported_from = NULL;
343 static char *main_text_level_imported_by = NULL;
344 static char *main_text_level_tested_by = NULL;
345 static char *main_text_title_1 = PROGRAM_TITLE_STRING;
346 static char *main_text_title_2 = PROGRAM_COPYRIGHT_STRING;
347 static char *main_text_title_3 = PROGRAM_GAME_BY_STRING;
349 struct MainControlInfo
353 struct MenuPosInfo *pos_button;
356 struct TextPosInfo *pos_text;
359 struct TextPosInfo *pos_input;
363 static struct MainControlInfo main_controls[] =
367 &menu.main.button.name, IMG_MENU_BUTTON_NAME,
368 &menu.main.text.name, &main_text_name,
369 &menu.main.input.name, &setup.player_name,
373 &menu.main.button.levels, IMG_MENU_BUTTON_LEVELS,
374 &menu.main.text.levels, &main_text_levels,
379 &menu.main.button.scores, IMG_MENU_BUTTON_SCORES,
380 &menu.main.text.scores, &main_text_scores,
385 &menu.main.button.editor, IMG_MENU_BUTTON_EDITOR,
386 &menu.main.text.editor, &main_text_editor,
391 &menu.main.button.info, IMG_MENU_BUTTON_INFO,
392 &menu.main.text.info, &main_text_info,
397 &menu.main.button.game, IMG_MENU_BUTTON_GAME,
398 &menu.main.text.game, &main_text_game,
403 &menu.main.button.setup, IMG_MENU_BUTTON_SETUP,
404 &menu.main.text.setup, &main_text_setup,
409 &menu.main.button.quit, IMG_MENU_BUTTON_QUIT,
410 &menu.main.text.quit, &main_text_quit,
414 /* (these two buttons are real gadgets) */
416 MAIN_CONTROL_PREV_LEVEL,
417 &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL,
422 MAIN_CONTROL_NEXT_LEVEL,
423 &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL,
429 MAIN_CONTROL_FIRST_LEVEL,
431 &menu.main.text.first_level, &main_text_first_level,
435 MAIN_CONTROL_LAST_LEVEL,
437 &menu.main.text.last_level, &main_text_last_level,
441 MAIN_CONTROL_LEVEL_NUMBER,
443 &menu.main.text.level_number, &main_text_level_number,
447 MAIN_CONTROL_LEVEL_INFO_1,
449 &menu.main.text.level_info_1, NULL,
453 MAIN_CONTROL_LEVEL_INFO_2,
455 &menu.main.text.level_info_2, NULL,
459 MAIN_CONTROL_LEVEL_NAME,
461 &menu.main.text.level_name, &main_text_level_name,
465 MAIN_CONTROL_LEVEL_AUTHOR,
467 &menu.main.text.level_author, &main_text_level_author,
471 MAIN_CONTROL_LEVEL_YEAR,
473 &menu.main.text.level_year, &main_text_level_year,
477 MAIN_CONTROL_LEVEL_IMPORTED_FROM,
479 &menu.main.text.level_imported_from, &main_text_level_imported_from,
483 MAIN_CONTROL_LEVEL_IMPORTED_BY,
485 &menu.main.text.level_imported_by, &main_text_level_imported_by,
489 MAIN_CONTROL_LEVEL_TESTED_BY,
491 &menu.main.text.level_tested_by, &main_text_level_tested_by,
495 MAIN_CONTROL_TITLE_1,
497 &menu.main.text.title_1, &main_text_title_1,
501 MAIN_CONTROL_TITLE_2,
503 &menu.main.text.title_2, &main_text_title_2,
507 MAIN_CONTROL_TITLE_3,
509 &menu.main.text.title_3, &main_text_title_3,
522 static int getTitleScreenGraphic(int nr, boolean initial)
524 return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
527 static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial)
529 return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]);
533 static int getTitleScreenGameMode(boolean initial)
535 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
539 static int getTitleMessageGameMode(boolean initial)
541 return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
545 static int getTitleScreenBackground(boolean initial)
547 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
552 static int getTitleMessageBackground(int nr, boolean initial)
554 return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
558 static int getTitleBackground(int nr, boolean initial, boolean is_image)
560 int base = (is_image ?
561 (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 :
562 IMG_BACKGROUND_TITLESCREEN_1) :
563 (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
564 IMG_BACKGROUND_TITLEMESSAGE_1));
565 int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL :
566 IMG_BACKGROUND_TITLE);
567 int graphic_local = base + nr;
569 if (graphic_info[graphic_local].bitmap != NULL)
570 return graphic_local;
572 if (graphic_info[graphic_global].bitmap != NULL)
573 return graphic_global;
575 return IMG_UNDEFINED;
578 static int getTitleSound(struct TitleControlInfo *tci)
580 boolean is_image = tci->is_image;
581 int initial = tci->initial;
582 int nr = tci->local_nr;
583 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
584 int base = (is_image ?
585 (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 :
586 SND_BACKGROUND_TITLESCREEN_1) :
587 (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
588 SND_BACKGROUND_TITLEMESSAGE_1));
589 int sound_global = menu.sound[mode];
590 int sound_local = base + nr;
593 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
594 nr, initial, is_image,
595 sound_global, getSoundListEntry(sound_global)->filename,
596 sound_local, getSoundListEntry(sound_local)->filename);
599 if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME))
602 if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME))
605 return SND_UNDEFINED;
608 static int getTitleMusic(struct TitleControlInfo *tci)
610 boolean is_image = tci->is_image;
611 int initial = tci->initial;
612 int nr = tci->local_nr;
613 int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
614 int base = (is_image ?
615 (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 :
616 MUS_BACKGROUND_TITLESCREEN_1) :
617 (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
618 MUS_BACKGROUND_TITLEMESSAGE_1));
619 int music_global = menu.music[mode];
620 int music_local = base + nr;
623 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
624 nr, initial, is_image,
625 music_global, getMusicListEntry(music_global)->filename,
626 music_local, getMusicListEntry(music_local)->filename);
629 if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME))
632 if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME))
635 return MUS_UNDEFINED;
638 static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci)
640 boolean is_image = tci->is_image;
641 int initial = tci->initial;
642 int nr = tci->local_nr;
643 struct TitleFadingInfo ti;
647 int graphic = getTitleScreenGraphic(nr, initial);
649 /* initialize fading control values to default title config settings */
650 ti = (initial ? title_initial_default : title_default);
652 /* override default settings with image config settings, if defined */
653 if (graphic_info[graphic].fade_mode != FADE_MODE_DEFAULT)
654 ti.fade_mode = graphic_info[graphic].fade_mode;
655 if (graphic_info[graphic].fade_delay > -1)
656 ti.fade_delay = graphic_info[graphic].fade_delay;
657 if (graphic_info[graphic].post_delay > -1)
658 ti.post_delay = graphic_info[graphic].post_delay;
659 if (graphic_info[graphic].auto_delay > -1)
660 ti.auto_delay = graphic_info[graphic].auto_delay;
666 ti.fade_mode = titlemessage_initial[nr].fade_mode;
667 ti.fade_delay = titlemessage_initial[nr].fade_delay;
668 ti.post_delay = titlemessage_initial[nr].post_delay;
669 ti.auto_delay = titlemessage_initial[nr].auto_delay;
673 ti.fade_mode = titlemessage[nr].fade_mode;
674 ti.fade_delay = titlemessage[nr].fade_delay;
675 ti.post_delay = titlemessage[nr].post_delay;
676 ti.auto_delay = titlemessage[nr].auto_delay;
681 if (ti.anim_mode == ANIM_NONE)
682 ti.fade_delay = ti.post_delay = 0;
688 static int compareTitleControlInfo(const void *object1, const void *object2)
690 const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1;
691 const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2;
694 if (tci1->initial != tci2->initial)
695 compare_result = (tci1->initial ? -1 : +1);
696 else if (tci1->sort_priority != tci2->sort_priority)
697 compare_result = tci1->sort_priority - tci2->sort_priority;
698 else if (tci1->is_image != tci2->is_image)
699 compare_result = (tci1->is_image ? -1 : +1);
701 compare_result = tci1->local_nr - tci2->local_nr;
703 return compare_result;
706 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
708 int nr, int sort_priority)
710 title_controls[num_title_screens].is_image = is_image;
711 title_controls[num_title_screens].initial = initial;
712 title_controls[num_title_screens].local_nr = nr;
713 title_controls[num_title_screens].sort_priority = sort_priority;
718 static void InitializeTitleControls_CheckTitleInfo(boolean initial)
722 for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++)
724 int graphic = getTitleScreenGraphic(i, initial);
725 Bitmap *bitmap = graphic_info[graphic].bitmap;
726 int sort_priority = graphic_info[graphic].sort_priority;
729 /* skip images and messages (fonts!) when using forced custom graphics */
730 if (setup.override_level_graphics && !initial)
735 InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority);
738 for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
740 struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial);
741 char *filename = getLevelSetTitleMessageFilename(i, initial);
742 int sort_priority = tmi->sort_priority;
745 /* skip images and messages (fonts!) when using forced custom graphics */
746 if (setup.override_level_graphics)
750 if (filename != NULL)
751 InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority);
755 static void InitializeTitleControls(boolean show_title_initial)
757 num_title_screens = 0;
760 if (show_title_initial)
761 InitializeTitleControls_CheckTitleInfo(TRUE);
764 InitializeTitleControls_CheckTitleInfo(FALSE);
766 /* sort title screens according to sort_priority and title number */
767 qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo),
768 compareTitleControlInfo);
771 static boolean visibleMenuPos(struct MenuPosInfo *pos)
773 return (pos != NULL && pos->x != -1 && pos->y != -1);
776 static boolean visibleTextPos(struct TextPosInfo *pos)
778 return (pos != NULL && pos->x != -1 && pos->y != -1);
781 static void InitializeMainControls()
783 boolean local_team_mode = (!options.network && setup.team_mode);
786 /* set main control text values to dynamically determined values */
787 sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
789 strcpy(main_text_first_level, int2str(leveldir_current->first_level,
790 menu.main.text.first_level.size));
791 strcpy(main_text_last_level, int2str(leveldir_current->last_level,
792 menu.main.text.last_level.size));
793 strcpy(main_text_level_number, int2str(level_nr,
794 menu.main.text.level_number.size));
796 main_text_level_year = leveldir_current->year;
797 main_text_level_imported_from = leveldir_current->imported_from;
798 main_text_level_imported_by = leveldir_current->imported_by;
799 main_text_level_tested_by = leveldir_current->tested_by;
801 /* set main control screen positions to dynamically determined values */
802 for (i = 0; main_controls[i].nr != -1; i++)
804 struct MainControlInfo *mci = &main_controls[i];
806 struct MenuPosInfo *pos_button = mci->pos_button;
807 struct TextPosInfo *pos_text = mci->pos_text;
808 struct TextPosInfo *pos_input = mci->pos_input;
809 char *text = (mci->text ? *mci->text : NULL);
810 char *input = (mci->input ? *mci->input : NULL);
811 int button_graphic = mci->button_graphic;
813 int font_text = (pos_text ? pos_text->font : -1);
814 int font_input = (pos_input ? pos_input->font : -1);
816 int font_text = mci->font_text;
817 int font_input = mci->font_input;
820 int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
821 int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
822 int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
823 int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
824 int text_chars = (text != NULL ? strlen(text) : 0);
825 int input_chars = (input != NULL ? strlen(input) : 0);
828 (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
830 (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
831 int text_width = font_text_width * text_chars;
832 int text_height = font_text_height;
833 int input_width = font_input_width * input_chars;
834 int input_height = font_input_height;
836 if (nr == MAIN_CONTROL_NAME)
839 if (menu.main.input.name.x == -1)
840 menu.main.input.name.x = menu.main.text.name.x + text_width;
841 if (menu.main.input.name.y == -1)
842 menu.main.input.name.y = menu.main.text.name.y;
846 menu.main.input.name.width = input_width;
847 menu.main.input.name.height = input_height;
849 menu.main.input.name.width = font_input_width * MAX_PLAYER_NAME_LEN;
850 menu.main.input.name.height = font_input_height;
854 if (pos_button != NULL) /* (x/y may be -1/-1 here) */
856 if (pos_button->width == 0)
857 pos_button->width = button_width;
858 if (pos_button->height == 0)
859 pos_button->height = button_height;
862 if (pos_text != NULL) /* (x/y may be -1/-1 here) */
864 /* calculate width for non-clickable text -- needed for text alignment */
865 boolean calculate_text_width = (pos_button == NULL && text != NULL);
867 if (visibleMenuPos(pos_button))
869 if (pos_text->x == -1)
870 pos_text->x = pos_button->x + pos_button->width;
871 if (pos_text->y == -1)
872 pos_text->y = pos_button->y;
875 if (pos_text->width == -1 || calculate_text_width)
876 pos_text->width = text_width;
877 if (pos_text->height == -1)
878 pos_text->height = text_height;
881 if (pos_input != NULL) /* (x/y may be -1/-1 here) */
883 if (visibleTextPos(pos_text))
885 if (pos_input->x == -1)
886 pos_input->x = pos_text->x + pos_text->width;
887 if (pos_input->y == -1)
888 pos_input->y = pos_text->y;
891 if (pos_input->width == -1)
892 pos_input->width = input_width;
893 if (pos_input->height == -1)
894 pos_input->height = input_height;
899 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
900 boolean active_input)
904 for (i = 0; main_controls[i].nr != -1; i++)
906 struct MainControlInfo *mci = &main_controls[i];
908 if (mci->nr == nr || nr == -1)
910 struct MenuPosInfo *pos_button = mci->pos_button;
911 struct TextPosInfo *pos_text = mci->pos_text;
912 struct TextPosInfo *pos_input = mci->pos_input;
913 char *text = (mci->text ? *mci->text : NULL);
914 char *input = (mci->input ? *mci->input : NULL);
915 int button_graphic = mci->button_graphic;
917 int font_text = (pos_text ? pos_text->font : -1);
918 int font_input = (pos_input ? pos_input->font : -1);
920 int font_text = mci->font_text;
921 int font_input = mci->font_input;
926 button_graphic = BUTTON_ACTIVE(button_graphic);
927 font_text = FONT_ACTIVE(font_text);
932 font_input = FONT_ACTIVE(font_input);
935 if (visibleMenuPos(pos_button))
937 struct MenuPosInfo *pos = pos_button;
938 int x = mSX + pos->x;
939 int y = mSY + pos->y;
941 DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
942 DrawGraphicThruMaskExt(drawto, x, y, button_graphic, 0);
945 if (visibleTextPos(pos_text) && text != NULL)
947 struct TextPosInfo *pos = pos_text;
948 int x = mSX + ALIGNED_TEXT_XPOS(pos);
949 int y = mSY + ALIGNED_TEXT_YPOS(pos);
952 /* (check why/if this is needed) */
953 DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
955 DrawText(x, y, text, font_text);
958 if (visibleTextPos(pos_input) && input != NULL)
960 struct TextPosInfo *pos = pos_input;
961 int x = mSX + ALIGNED_TEXT_XPOS(pos);
962 int y = mSY + ALIGNED_TEXT_YPOS(pos);
965 /* (check why/if this is needed) */
966 DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
968 DrawText(x, y, input, font_input);
974 static void DrawCursorAndText_Main(int nr, boolean active_text)
976 DrawCursorAndText_Main_Ext(nr, active_text, FALSE);
980 static void DrawCursorAndText_Main_Input(int nr, boolean active_text)
982 DrawCursorAndText_Main_Ext(nr, active_text, TRUE);
986 static struct MainControlInfo *getMainControlInfo(int nr)
990 for (i = 0; main_controls[i].nr != -1; i++)
991 if (main_controls[i].nr == nr)
992 return &main_controls[i];
997 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
1002 int rect_x = ALIGNED_TEXT_XPOS(rect);
1003 int rect_y = ALIGNED_TEXT_YPOS(rect);
1005 return (x >= rect_x && x < rect_x + rect->width &&
1006 y >= rect_y && y < rect_y + rect->height);
1009 static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
1014 int rect_x = ALIGNED_TEXT_XPOS(rect);
1015 int rect_y = ALIGNED_TEXT_YPOS(rect);
1017 return (x >= rect_x && x < rect_x + rect->width &&
1018 y >= rect_y && y < rect_y + rect->height);
1021 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
1023 static int cursor_array[SCR_FIELDY];
1024 int x = mSX + TILEX * xpos;
1025 int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
1030 cursor_array[ypos] = graphic;
1032 graphic = cursor_array[ypos];
1036 graphic = BUTTON_ACTIVE(graphic);
1038 DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
1039 DrawGraphicThruMaskExt(drawto, x, y, graphic, 0);
1042 static void initCursor(int ypos, int graphic)
1044 drawCursorExt(0, ypos, FALSE, graphic);
1047 static void drawCursor(int ypos, boolean active)
1049 drawCursorExt(0, ypos, active, -1);
1052 static void drawCursorXY(int xpos, int ypos, int graphic)
1054 drawCursorExt(xpos, ypos, FALSE, graphic);
1057 static void drawChooseTreeCursor(int ypos, boolean active)
1059 int last_game_status = game_status; /* save current game status */
1062 /* force LEVELS draw offset on artwork setup screen */
1063 game_status = GAME_MODE_LEVELS;
1066 drawCursorExt(0, ypos, active, -1);
1068 game_status = last_game_status; /* restore current game status */
1073 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
1074 DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
1078 static int getPrevlevelButtonPos()
1083 static int getCurrentLevelTextPos()
1085 return (getPrevlevelButtonPos() + 1);
1088 static int getNextLevelButtonPos()
1090 return getPrevlevelButtonPos() + 3 + 1;
1093 static int getLevelRangeTextPos()
1095 return getNextLevelButtonPos() + 1;
1099 int effectiveGameStatus()
1101 if (game_status == GAME_MODE_INFO && info_mode == INFO_MODE_TITLE)
1102 return GAME_MODE_TITLE;
1107 void DrawTitleScreenImage(int nr, boolean initial)
1109 int graphic = getTitleScreenGraphic(nr, initial);
1110 Bitmap *bitmap = graphic_info[graphic].bitmap;
1111 int width = graphic_info[graphic].width;
1112 int height = graphic_info[graphic].height;
1113 int src_x = graphic_info[graphic].src_x;
1114 int src_y = graphic_info[graphic].src_y;
1120 if (width > WIN_XSIZE)
1122 /* image width too large for window => center image horizontally */
1123 src_x = (width - WIN_XSIZE) / 2;
1127 if (height > WIN_YSIZE)
1129 /* image height too large for window => center image vertically */
1130 src_y = (height - WIN_YSIZE) / 2;
1134 /* always display title screens centered */
1135 dst_x = (WIN_XSIZE - width) / 2;
1136 dst_y = (WIN_YSIZE - height) / 2;
1138 SetDrawBackgroundMask(REDRAW_ALL);
1139 SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE));
1141 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1143 if (DrawingOnBackground(dst_x, dst_y))
1144 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1146 BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1148 redraw_mask = REDRAW_ALL;
1151 void DrawTitleScreenMessage(int nr, boolean initial)
1153 char *filename = getLevelSetTitleMessageFilename(nr, initial);
1154 struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
1155 int last_game_status = game_status; /* save current game status */
1157 if (filename == NULL)
1160 /* force TITLE font on title message screen */
1161 game_status = getTitleMessageGameMode(initial);
1163 /* if chars set to "-1", automatically determine by text and font width */
1164 if (tmi->chars == -1)
1165 tmi->chars = tmi->width / getFontWidth(tmi->font);
1167 tmi->width = tmi->chars * getFontWidth(tmi->font);
1169 /* if lines set to "-1", automatically determine by text and font height */
1170 if (tmi->lines == -1)
1171 tmi->lines = tmi->height / getFontHeight(tmi->font);
1173 tmi->height = tmi->lines * getFontHeight(tmi->font);
1175 SetDrawBackgroundMask(REDRAW_ALL);
1176 SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE));
1178 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1180 DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi),
1181 filename, tmi->font, tmi->chars, -1, tmi->lines, -1,
1182 tmi->autowrap, tmi->centered, tmi->parse_comments);
1184 game_status = last_game_status; /* restore current game status */
1187 void DrawTitleScreen()
1189 KeyboardAutoRepeatOff();
1192 SetMainBackgroundImage(IMG_BACKGROUND_TITLE);
1195 HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
1200 boolean CheckTitleScreen(boolean levelset_has_changed)
1202 static boolean show_title_initial = TRUE;
1203 boolean show_titlescreen = FALSE;
1205 /* needed to be able to skip title screen, if no image or message defined */
1206 InitializeTitleControls(show_title_initial);
1208 if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
1209 show_titlescreen = TRUE;
1211 /* show initial title images and messages only once at program start */
1212 show_title_initial = FALSE;
1214 return (show_titlescreen && num_title_screens > 0);
1217 void DrawMainMenuExt(int fade_mask, boolean do_fading)
1219 static LevelDirTree *leveldir_last_valid = NULL;
1220 boolean levelset_has_changed = FALSE;
1222 FadeSetLeaveScreen();
1224 /* do not fade out here -- function may continue and fade on editor screen */
1227 FadeSoundsAndMusic();
1229 KeyboardAutoRepeatOn();
1232 SetDrawDeactivationMask(REDRAW_NONE);
1233 SetDrawBackgroundMask(REDRAW_FIELD);
1235 audio.sound_deactivated = FALSE;
1239 /* needed if last screen was the playing screen, invoked from level editor */
1240 if (level_editor_test_game)
1242 game_status = GAME_MODE_EDITOR;
1248 /* needed if last screen was the setup screen and fullscreen state changed */
1249 ToggleFullscreenIfNeeded();
1251 /* leveldir_current may be invalid (level group, parent link) */
1252 if (!validLevelSeries(leveldir_current))
1253 leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
1255 if (leveldir_current != leveldir_last_valid)
1256 levelset_has_changed = TRUE;
1258 /* store valid level series information */
1259 leveldir_last_valid = leveldir_current;
1261 /* needed if last screen (level choice) changed graphics, sounds or music */
1262 ReloadCustomArtwork(0);
1264 if (redraw_mask & REDRAW_ALL)
1265 fade_mask = REDRAW_ALL;
1270 /* needed if last screen was the editor screen */
1271 UndrawSpecialEditorDoor();
1273 if (fade_mask == REDRAW_FIELD)
1278 #if defined(TARGET_SDL)
1279 SetDrawtoField(DRAW_BACKBUFFER);
1282 if (CheckTitleScreen(levelset_has_changed))
1284 game_status = GAME_MODE_TITLE;
1291 /* level_nr may have been set to value over handicap with level editor */
1292 if (setup.handicap && level_nr > leveldir_current->handicap_level)
1293 level_nr = leveldir_current->handicap_level;
1295 LoadLevel(level_nr);
1296 LoadScore(level_nr);
1298 SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
1301 if (fade_mask == REDRAW_ALL)
1303 // int door_state = GetDoorState();
1307 // OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1313 InitializeMainControls();
1315 DrawCursorAndText_Main(-1, FALSE);
1316 DrawPreviewLevel(TRUE);
1318 HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
1321 if (TAPE_IS_EMPTY(tape))
1323 DrawCompleteVideoDisplay();
1328 /* create gadgets for main menu screen */
1329 FreeScreenGadgets();
1330 CreateScreenGadgets();
1332 /* map gadgets for main menu screen */
1334 MapScreenMenuGadgets(SCREEN_MASK_MAIN);
1337 if (fade_mask == REDRAW_ALL)
1339 int door_state = GetDoorState();
1341 // RedrawBackground();
1343 OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1347 DrawMaskedBorder(REDRAW_ALL);
1353 /* update screen area with special editor door */
1354 redraw_mask |= REDRAW_ALL;
1358 SetMouseCursor(CURSOR_DEFAULT);
1362 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
1365 void DrawAndFadeInMainMenu(int fade_mask)
1367 DrawMainMenuExt(fade_mask, TRUE);
1372 DrawMainMenuExt(REDRAW_ALL, FALSE);
1376 static void gotoTopLevelDir()
1378 /* move upwards to top level directory */
1379 while (leveldir_current->node_parent)
1381 /* write a "path" into level tree for easy navigation to last level */
1382 if (leveldir_current->node_parent->node_group->cl_first == -1)
1384 int num_leveldirs = numTreeInfoInGroup(leveldir_current);
1385 int leveldir_pos = posTreeInfo(leveldir_current);
1386 int num_page_entries;
1387 int cl_first, cl_cursor;
1389 if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
1390 num_page_entries = num_leveldirs;
1392 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1394 cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
1395 cl_cursor = leveldir_pos - cl_first;
1397 leveldir_current->node_parent->node_group->cl_first = cl_first;
1398 leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
1401 leveldir_current = leveldir_current->node_parent;
1406 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1408 static unsigned long title_delay = 0;
1409 static int title_screen_nr = 0;
1410 static int last_sound = -1, last_music = -1;
1411 boolean return_to_main_menu = FALSE;
1412 boolean use_fading_main_menu = TRUE;
1413 struct TitleControlInfo *tci;
1414 struct TitleFadingInfo fading_default;
1415 struct TitleFadingInfo fading_last = fading;
1416 struct TitleFadingInfo fading_next;
1419 if (button == MB_MENU_INITIALIZE)
1422 title_screen_nr = 0;
1423 tci = &title_controls[title_screen_nr];
1425 last_sound = SND_UNDEFINED;
1426 last_music = MUS_UNDEFINED;
1428 if (game_status == GAME_MODE_INFO)
1430 if (num_title_screens == 0)
1432 DrawInfoScreen_NotAvailable("Title screen information:",
1433 "No title screen for this level set.");
1438 FadeSoundsAndMusic();
1441 FadeOut(REDRAW_ALL);
1446 DrawTitleScreenImage(tci->local_nr, tci->initial);
1448 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1450 fading_default = (tci->initial ? title_initial_default : title_default);
1452 fading = fading_next = getTitleFading(tci);
1456 if (!(fading_last.fade_mode & FADE_TYPE_TRANSFORM) &&
1457 fading_next.fade_mode & FADE_TYPE_TRANSFORM)
1459 fading.fade_mode = FADE_MODE_FADE;
1460 fading.fade_delay = fading_default.fade_delay;
1463 if (fading_last.fade_mode != FADE_MODE_CROSSFADE &&
1464 fading_next.fade_mode == FADE_MODE_CROSSFADE)
1465 fading.fade_mode = FADE_MODE_FADE;
1470 sound = getTitleSound(tci);
1471 music = getTitleMusic(tci);
1473 if (sound != last_sound)
1474 PlayMenuSoundExt(sound);
1475 if (music != last_music)
1476 PlayMenuMusicExt(music);
1482 SetMouseCursor(CURSOR_NONE);
1488 fading = fading_next;
1490 DelayReached(&title_delay, 0); /* reset delay counter */
1496 if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay))
1497 button = MB_MENU_CHOICE;
1499 if (fading.auto_delay > -1 && DelayReached(&title_delay, fading.auto_delay))
1500 button = MB_MENU_CHOICE;
1503 if (button == MB_MENU_LEAVE)
1505 return_to_main_menu = TRUE;
1506 use_fading_main_menu = FALSE;
1508 else if (button == MB_MENU_CHOICE)
1510 if (game_status == GAME_MODE_INFO && num_title_screens == 0)
1513 FadeOut(REDRAW_FIELD);
1516 FadeSetEnterScreen();
1518 info_mode = INFO_MODE_MAIN;
1519 DrawAndFadeInInfoScreen(REDRAW_FIELD);
1525 tci = &title_controls[title_screen_nr];
1527 if (title_screen_nr < num_title_screens)
1529 sound = getTitleSound(tci);
1530 music = getTitleMusic(tci);
1532 if (sound == SND_UNDEFINED || sound != last_sound)
1534 if (music == MUS_UNDEFINED || music != last_music)
1538 FadeOut(REDRAW_ALL);
1542 DrawTitleScreenImage(tci->local_nr, tci->initial);
1544 DrawTitleScreenMessage(tci->local_nr, tci->initial);
1546 fading_next = getTitleFading(tci);
1549 sound = getTitleSound(tci);
1550 music = getTitleMusic(tci);
1552 if (sound != last_sound)
1553 PlayMenuSoundExt(sound);
1554 if (music != last_music)
1555 PlayMenuMusicExt(music);
1562 /* last screen already faded out, next screen has no animation */
1563 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM) &&
1564 fading_next.fade_mode == FADE_MODE_NONE)
1565 fading = fading_next;
1567 /* last screen already faded out, next screen has no animation */
1568 if (fading.fade_mode != FADE_MODE_CROSSFADE &&
1569 fading_next.fade_mode == FADE_MODE_NONE)
1570 fading = fading_next;
1577 fading = fading_next;
1579 DelayReached(&title_delay, 0); /* reset delay counter */
1583 FadeSoundsAndMusic();
1585 return_to_main_menu = TRUE;
1589 if (return_to_main_menu)
1595 SetMouseCursor(CURSOR_DEFAULT);
1597 if (game_status == GAME_MODE_INFO)
1600 OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1603 info_mode = INFO_MODE_MAIN;
1604 DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu);
1606 else /* default: return to main menu */
1609 OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1612 game_status = GAME_MODE_MAIN;
1613 DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu);
1618 void HandleMainMenu_SelectLevel(int step, int direction)
1620 int old_level_nr = level_nr;
1623 new_level_nr = old_level_nr + step * direction;
1624 if (new_level_nr < leveldir_current->first_level)
1625 new_level_nr = leveldir_current->first_level;
1626 if (new_level_nr > leveldir_current->last_level)
1627 new_level_nr = leveldir_current->last_level;
1629 if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1631 /* skipping levels is only allowed when trying to skip single level */
1632 if (setup.skip_levels && step == 1 &&
1633 Request("Level still unsolved ! Skip despite handicap ?", REQ_ASK))
1635 leveldir_current->handicap_level++;
1636 SaveLevelSetup_SeriesInfo();
1639 new_level_nr = leveldir_current->handicap_level;
1642 if (new_level_nr != old_level_nr)
1644 struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER);
1646 PlaySound(SND_MENU_ITEM_SELECTING);
1648 level_nr = new_level_nr;
1650 DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1651 int2str(level_nr, menu.main.text.level_number.size),
1652 mci->pos_text->font);
1654 LoadLevel(level_nr);
1655 DrawPreviewLevel(TRUE);
1659 DrawCompleteVideoDisplay();
1661 /* needed because DrawPreviewLevel() takes some time */
1667 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1669 static int choice = MAIN_CONTROL_GAME;
1673 if (button == MB_MENU_INITIALIZE)
1675 DrawCursorAndText_Main(choice, TRUE);
1680 if (mx || my) /* mouse input */
1684 for (i = 0; main_controls[i].nr != -1; i++)
1686 if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1687 insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) ||
1688 insideTextPosRect(main_controls[i].pos_input, mx - mSX, my - mSY))
1690 pos = main_controls[i].nr;
1696 else if (dx || dy) /* keyboard input */
1698 if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1699 choice == MAIN_CONTROL_SETUP))
1700 button = MB_MENU_CHOICE;
1705 if (pos == MAIN_CONTROL_LEVELS && dx != 0 && button)
1707 HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1709 else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
1715 PlaySound(SND_MENU_ITEM_ACTIVATING);
1717 DrawCursorAndText_Main(choice, FALSE);
1718 DrawCursorAndText_Main(pos, TRUE);
1725 PlaySound(SND_MENU_ITEM_SELECTING);
1727 if (pos == MAIN_CONTROL_NAME)
1729 game_status = GAME_MODE_PSEUDO_TYPENAME;
1731 HandleTypeName(strlen(setup.player_name), 0);
1733 else if (pos == MAIN_CONTROL_LEVELS)
1737 game_status = GAME_MODE_LEVELS;
1739 SaveLevelSetup_LastSeries();
1740 SaveLevelSetup_SeriesInfo();
1749 else if (pos == MAIN_CONTROL_SCORES)
1751 game_status = GAME_MODE_SCORES;
1755 else if (pos == MAIN_CONTROL_EDITOR)
1757 if (leveldir_current->readonly &&
1758 !strEqual(setup.player_name, "Artsoft"))
1759 Request("This level is read only !", REQ_CONFIRM);
1761 game_status = GAME_MODE_EDITOR;
1763 FadeSetEnterScreen();
1767 else if (pos == MAIN_CONTROL_INFO)
1769 game_status = GAME_MODE_INFO;
1770 info_mode = INFO_MODE_MAIN;
1774 else if (pos == MAIN_CONTROL_GAME)
1776 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
1778 else if (pos == MAIN_CONTROL_SETUP)
1780 game_status = GAME_MODE_SETUP;
1781 setup_mode = SETUP_MODE_MAIN;
1785 else if (pos == MAIN_CONTROL_QUIT)
1787 SaveLevelSetup_LastSeries();
1788 SaveLevelSetup_SeriesInfo();
1790 if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
1791 game_status = GAME_MODE_QUIT;
1796 if (game_status == GAME_MODE_MAIN)
1798 DrawPreviewLevel(FALSE);
1804 /* ========================================================================= */
1805 /* info screen functions */
1806 /* ========================================================================= */
1808 static struct TokenInfo *info_info;
1809 static int num_info_info;
1811 static void execInfoTitleScreen()
1813 info_mode = INFO_MODE_TITLE;
1818 static void execInfoElements()
1820 info_mode = INFO_MODE_ELEMENTS;
1825 static void execInfoMusic()
1827 info_mode = INFO_MODE_MUSIC;
1832 static void execInfoCredits()
1834 info_mode = INFO_MODE_CREDITS;
1839 static void execInfoProgram()
1841 info_mode = INFO_MODE_PROGRAM;
1846 static void execInfoVersion()
1848 info_mode = INFO_MODE_VERSION;
1853 static void execInfoLevelSet()
1855 info_mode = INFO_MODE_LEVELSET;
1860 static void execExitInfo()
1862 game_status = GAME_MODE_MAIN;
1864 DrawMainMenuExt(REDRAW_FIELD, FALSE);
1867 static struct TokenInfo info_info_main[] =
1869 { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" },
1870 { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" },
1871 { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" },
1872 { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" },
1873 { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" },
1874 { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" },
1875 { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" },
1876 { TYPE_EMPTY, NULL, "" },
1877 { TYPE_LEAVE_MENU, execExitInfo, "Exit" },
1882 static void DrawCursorAndText_Info(int pos, boolean active)
1884 int xpos = MENU_SCREEN_START_XPOS;
1885 int ypos = MENU_SCREEN_START_YPOS + pos;
1886 int font_nr = FONT_MENU_1;
1889 font_nr = FONT_ACTIVE(font_nr);
1891 DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[pos].text, font_nr);
1893 if (info_info[pos].type & ~TYPE_SKIP_ENTRY)
1894 drawCursor(pos, active);
1897 static void DrawInfoScreen_Main(int fade_mask, boolean do_fading)
1902 CloseDoor(DOOR_CLOSE_2);
1904 /* (needed after displaying title screens which disable auto repeat) */
1905 KeyboardAutoRepeatOn();
1907 FadeSetLeaveScreen();
1914 if (fade_mask == REDRAW_ALL)
1918 OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1924 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
1926 info_info = info_info_main;
1930 for (i = 0; info_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
1932 for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
1935 if (info_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
1936 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
1937 else if (info_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
1938 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
1939 else if (info_info[i].type & ~TYPE_SKIP_ENTRY)
1940 initCursor(i, IMG_MENU_BUTTON);
1942 DrawCursorAndText_Info(i, FALSE);
1947 HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
1952 DrawMaskedBorder(fade_mask);
1959 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
1961 static int choice_store[MAX_INFO_MODES];
1962 int choice = choice_store[info_mode]; /* always starts with 0 */
1966 if (button == MB_MENU_INITIALIZE)
1968 /* advance to first valid menu entry */
1969 while (choice < num_info_info &&
1970 info_info[choice].type & TYPE_SKIP_ENTRY)
1972 choice_store[info_mode] = choice;
1974 DrawCursorAndText_Info(choice, TRUE);
1978 else if (button == MB_MENU_LEAVE)
1980 for (y = 0; y < num_info_info; y++)
1982 if (info_info[y].type & TYPE_LEAVE_MENU)
1984 void (*menu_callback_function)(void) = info_info[y].value;
1988 menu_callback_function();
1990 break; /* absolutely needed because function changes 'info_info'! */
1997 if (mx || my) /* mouse input */
1999 x = (mx - mSX) / 32;
2000 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2002 else if (dx || dy) /* keyboard input */
2006 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
2008 if (info_info[choice].type & menu_navigation_type ||
2009 info_info[choice].type & TYPE_ENTER_SCREEN ||
2010 info_info[choice].type & TYPE_BOOLEAN_STYLE)
2011 button = MB_MENU_CHOICE;
2016 /* jump to next non-empty menu entry (up or down) */
2017 while (y > 0 && y < num_info_info - 1 &&
2018 info_info[y].type & TYPE_SKIP_ENTRY)
2022 if (IN_VIS_FIELD(x, y) &&
2023 y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY)
2029 PlaySound(SND_MENU_ITEM_ACTIVATING);
2031 DrawCursorAndText_Info(choice, FALSE);
2032 DrawCursorAndText_Info(y, TRUE);
2034 choice = choice_store[info_mode] = y;
2037 else if (!(info_info[y].type & TYPE_GHOSTED))
2039 PlaySound(SND_MENU_ITEM_SELECTING);
2041 if (info_info[y].type & TYPE_ENTER_OR_LEAVE)
2043 void (*menu_callback_function)(void) = info_info[choice].value;
2045 FadeSetFromType(info_info[y].type);
2047 menu_callback_function();
2053 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
2055 int ystart1 = mSY - SY + 100;
2056 int ystart2 = mSY - SY + 150;
2057 int ybottom = mSY - SY + SYSIZE - 20;
2059 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
2061 FadeOut(REDRAW_FIELD);
2066 DrawTextSCentered(ystart1, FONT_TEXT_1, text_title);
2067 DrawTextSCentered(ystart2, FONT_TEXT_2, text_error);
2069 DrawTextSCentered(ybottom, FONT_TEXT_4,
2070 "Press any key or button for info menu");
2072 FadeIn(REDRAW_FIELD);
2075 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
2077 static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
2078 static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
2079 int xstart = mSX + 16;
2080 int ystart1 = mSY - SY + 100;
2081 int ystart2 = mSY + 64 + 2 * 32;
2082 int ybottom = mSY - SY + SYSIZE - 20;
2083 int ystep = TILEY + 4;
2084 int element, action, direction;
2092 for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
2093 infoscreen_step[i] = infoscreen_frame[i] = 0;
2098 DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Elements:");
2100 DrawTextSCentered(ybottom, FONT_TEXT_4,
2101 "Press any key or button for next page");
2107 while (helpanim_info[j].element != HELPANIM_LIST_END)
2109 if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN ||
2114 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2123 j += infoscreen_step[i - start];
2125 element = helpanim_info[j].element;
2126 action = helpanim_info[j].action;
2127 direction = helpanim_info[j].direction;
2130 element = EL_UNKNOWN;
2132 if (action != -1 && direction != -1)
2133 graphic = el_act_dir2img(element, action, direction);
2134 else if (action != -1)
2135 graphic = el_act2img(element, action);
2136 else if (direction != -1)
2137 graphic = el_dir2img(element, direction);
2139 graphic = el2img(element);
2141 delay = helpanim_info[j++].delay;
2146 if (infoscreen_frame[i - start] == 0)
2149 infoscreen_frame[i - start] = delay - 1;
2153 sync_frame = delay - infoscreen_frame[i - start];
2154 infoscreen_frame[i - start]--;
2157 if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
2159 if (!infoscreen_frame[i - start])
2160 infoscreen_step[i - start] = 0;
2164 if (!infoscreen_frame[i - start])
2165 infoscreen_step[i - start]++;
2166 while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2172 ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep,
2174 DrawGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep,
2175 graphic, sync_frame, USE_MASKING);
2178 DrawInfoScreen_HelpText(element, action, direction, i - start);
2183 redraw_mask |= REDRAW_FIELD;
2188 static char *getHelpText(int element, int action, int direction)
2190 char token[MAX_LINE_LEN];
2192 strcpy(token, element_info[element].token_name);
2195 strcat(token, element_action_info[action].suffix);
2197 if (direction != -1)
2198 strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
2200 return getHashEntry(helptext_info, token);
2203 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
2205 int font_nr = FONT_INFO_ELEMENTS;
2206 int font_width = getFontWidth(font_nr);
2207 int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX;
2208 int sy = mSY + 65 + 2 * 32 + 1;
2209 int ystep = TILEY + 4;
2210 int pad_x = sx - SX;
2211 int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width;
2212 int max_lines_per_text = 2;
2215 if (action != -1 && direction != -1) /* element.action.direction */
2216 text = getHelpText(element, action, direction);
2218 if (text == NULL && action != -1) /* element.action */
2219 text = getHelpText(element, action, -1);
2221 if (text == NULL && direction != -1) /* element.direction */
2222 text = getHelpText(element, -1, direction);
2224 if (text == NULL) /* base element */
2225 text = getHelpText(element, -1, -1);
2227 if (text == NULL) /* not found */
2228 text = "No description available";
2230 if (strlen(text) <= max_chars_per_line) /* only one line of text */
2231 sy += getFontHeight(font_nr) / 2;
2233 DrawTextBuffer(sx, sy + ypos * ystep, text, font_nr,
2234 max_chars_per_line, -1, max_lines_per_text, -1,
2235 TRUE, FALSE, FALSE);
2238 void DrawInfoScreen_TitleScreen()
2243 void HandleInfoScreen_TitleScreen(int button)
2245 HandleTitleScreen(0, 0, 0, 0, button);
2248 void DrawInfoScreen_Elements()
2250 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
2252 FadeOut(REDRAW_FIELD);
2257 HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
2259 FadeIn(REDRAW_FIELD);
2264 void HandleInfoScreen_Elements(int button)
2266 static unsigned long info_delay = 0;
2267 static int num_anims;
2268 static int num_pages;
2270 int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN;
2273 if (button == MB_MENU_INITIALIZE)
2275 boolean new_element = TRUE;
2279 for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
2281 if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
2283 else if (new_element)
2286 new_element = FALSE;
2290 num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
2294 if (button == MB_MENU_LEAVE)
2296 PlaySound(SND_MENU_ITEM_SELECTING);
2298 info_mode = INFO_MODE_MAIN;
2303 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2305 if (button != MB_MENU_INITIALIZE)
2307 PlaySound(SND_MENU_ITEM_SELECTING);
2312 if (page >= num_pages)
2314 FadeSoundsAndMusic();
2316 info_mode = INFO_MODE_MAIN;
2317 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2324 FadeSetNextScreen();
2327 if (button != MB_MENU_INITIALIZE)
2328 FadeOut(REDRAW_FIELD);
2330 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
2332 if (button != MB_MENU_INITIALIZE)
2333 FadeIn(REDRAW_FIELD);
2337 if (DelayReached(&info_delay, GameFrameDelay))
2338 if (page < num_pages)
2339 DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
2341 PlayMenuSoundIfLoop();
2345 void DrawInfoScreen_Music()
2347 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
2350 FadeOut(REDRAW_FIELD);
2358 HandleInfoScreen_Music(MB_MENU_INITIALIZE);
2361 FadeIn(REDRAW_FIELD);
2365 void HandleInfoScreen_Music(int button)
2367 static struct MusicFileInfo *list = NULL;
2368 int ystart1 = mSY - SY + 100;
2369 int ystart2 = mSY - SY + 150;
2370 int ybottom = mSY - SY + SYSIZE - 20;
2373 if (button == MB_MENU_INITIALIZE)
2375 list = music_file_info;
2379 FadeSoundsAndMusic();
2384 DrawTextSCentered(ystart1, FONT_TEXT_1,
2385 "No music info for this level set.");
2387 DrawTextSCentered(ybottom, FONT_TEXT_4,
2388 "Press any key or button for info menu");
2394 if (button == MB_MENU_LEAVE)
2396 PlaySound(SND_MENU_ITEM_SELECTING);
2398 FadeSoundsAndMusic();
2400 info_mode = INFO_MODE_MAIN;
2405 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2409 if (button != MB_MENU_INITIALIZE)
2411 PlaySound(SND_MENU_ITEM_SELECTING);
2419 FadeSoundsAndMusic();
2421 info_mode = INFO_MODE_MAIN;
2422 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2427 FadeSoundsAndMusic();
2430 if (list != music_file_info)
2431 FadeSetNextScreen();
2434 if (button != MB_MENU_INITIALIZE)
2435 FadeOut(REDRAW_FIELD);
2442 int sound = list->music;
2444 if (sound_info[sound].loop)
2445 PlaySoundLoop(sound);
2449 DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Sounds:");
2453 PlayMusic(list->music);
2455 DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Music:");
2458 if (!strEqual(list->title, UNKNOWN_NAME))
2460 if (!strEqual(list->title_header, UNKNOWN_NAME))
2461 DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->title_header);
2463 DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
2466 if (!strEqual(list->artist, UNKNOWN_NAME))
2468 if (!strEqual(list->artist_header, UNKNOWN_NAME))
2469 DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->artist_header);
2471 DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "by");
2473 DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->artist);
2476 if (!strEqual(list->album, UNKNOWN_NAME))
2478 if (!strEqual(list->album_header, UNKNOWN_NAME))
2479 DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->album_header);
2481 DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the album");
2483 DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album);
2486 if (!strEqual(list->year, UNKNOWN_NAME))
2488 if (!strEqual(list->year_header, UNKNOWN_NAME))
2489 DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->year_header);
2491 DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the year");
2493 DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->year);
2496 DrawTextSCentered(ybottom, FONT_TEXT_4,
2497 "Press any key or button for next page");
2499 if (button != MB_MENU_INITIALIZE)
2500 FadeIn(REDRAW_FIELD);
2503 if (list != NULL && list->is_sound && sound_info[list->music].loop)
2504 PlaySoundLoop(list->music);
2507 static void DrawInfoScreen_CreditsScreen(int screen_nr)
2509 int ystart1 = mSY - SY + 100;
2510 int ystart2 = mSY - SY + 150;
2511 int ybottom = mSY - SY + SYSIZE - 20;
2517 DrawTextSCentered(ystart1, FONT_TEXT_1, "Credits:");
2521 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2522 "Special thanks to");
2523 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2525 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2527 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2528 "\"Boulder Dash\"");
2529 DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2531 DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2533 DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2535 DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2536 "First Star Software");
2538 else if (screen_nr == 1)
2540 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2541 "Special thanks to");
2542 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2543 "Klaus Heinz & Volker Wertich");
2544 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2546 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2547 "\"Emerald Mine\"");
2548 DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2550 DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2552 DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2554 DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2557 else if (screen_nr == 2)
2559 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2560 "Special thanks to");
2561 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2562 "Michael Stopp & Philip Jespersen");
2563 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2565 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2567 DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2569 DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2571 DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2573 DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2574 "Digital Integration");
2576 else if (screen_nr == 3)
2578 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2579 "Special thanks to");
2580 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2581 "Hiroyuki Imabayashi");
2582 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2584 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2586 DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2588 DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2590 DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2592 DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2595 else if (screen_nr == 4)
2597 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2598 "Special thanks to");
2599 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2601 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2603 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2604 "Jürgen Bonhagen");
2605 DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2606 "for the continuous creation");
2607 DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2,
2608 "of outstanding level sets");
2610 else if (screen_nr == 5)
2612 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2614 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2616 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2617 "for ideas and inspiration by");
2618 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2621 DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2,
2623 DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_3,
2625 DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2,
2626 "for ideas and inspiration by");
2627 DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_3,
2630 else if (screen_nr == 6)
2632 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2634 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2636 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2637 "for the new Emerald Mine engine");
2639 else if (screen_nr == 7)
2641 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2643 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2645 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2646 "for the initial DOS port");
2648 DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2650 DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2652 DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2653 "for some additional toons");
2655 else if (screen_nr == 8)
2657 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2658 "And not to forget:");
2659 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2,
2661 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3,
2662 "All those who contributed");
2663 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2664 "levels to this game");
2665 DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_3,
2669 DrawTextSCentered(ybottom, FONT_TEXT_4,
2670 "Press any key or button for next page");
2673 void DrawInfoScreen_Credits()
2675 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
2677 FadeSoundsAndMusic();
2680 FadeOut(REDRAW_FIELD);
2683 HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
2686 FadeIn(REDRAW_FIELD);
2690 void HandleInfoScreen_Credits(int button)
2692 static int screen_nr = 0;
2693 int num_screens = 9;
2695 if (button == MB_MENU_INITIALIZE)
2699 // DrawInfoScreen_CreditsScreen(screen_nr);
2702 if (button == MB_MENU_LEAVE)
2704 PlaySound(SND_MENU_ITEM_SELECTING);
2706 info_mode = INFO_MODE_MAIN;
2711 else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2713 if (button != MB_MENU_INITIALIZE)
2715 PlaySound(SND_MENU_ITEM_SELECTING);
2720 if (screen_nr >= num_screens)
2722 FadeSoundsAndMusic();
2724 info_mode = INFO_MODE_MAIN;
2725 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2732 FadeSetNextScreen();
2735 if (button != MB_MENU_INITIALIZE)
2736 FadeOut(REDRAW_FIELD);
2738 DrawInfoScreen_CreditsScreen(screen_nr);
2740 if (button != MB_MENU_INITIALIZE)
2741 FadeIn(REDRAW_FIELD);
2745 PlayMenuSoundIfLoop();
2749 void DrawInfoScreen_Program()
2751 int ystart1 = mSY - SY + 100;
2752 int ystart2 = mSY - SY + 150;
2753 int ybottom = mSY - SY + SYSIZE - 20;
2756 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
2759 FadeOut(REDRAW_FIELD);
2765 DrawTextSCentered(ystart1, FONT_TEXT_1, "Program Information:");
2767 DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2768 "This game is Freeware!");
2769 DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2,
2770 "If you like it, send e-mail to:");
2771 DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3,
2772 PROGRAM_EMAIL_STRING);
2773 DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_2,
2774 "or SnailMail to:");
2775 DrawTextSCentered(ystart2 + 4 * ystep + 0, FONT_TEXT_3,
2777 DrawTextSCentered(ystart2 + 4 * ystep + 20, FONT_TEXT_3,
2778 "Detmolder Strasse 189");
2779 DrawTextSCentered(ystart2 + 4 * ystep + 40, FONT_TEXT_3,
2781 DrawTextSCentered(ystart2 + 4 * ystep + 60, FONT_TEXT_3,
2783 DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2,
2784 "More information and levels:");
2785 DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_3,
2786 PROGRAM_WEBSITE_STRING);
2787 DrawTextSCentered(ystart2 + 9 * ystep, FONT_TEXT_2,
2788 "If you have created new levels,");
2789 DrawTextSCentered(ystart2 + 10 * ystep, FONT_TEXT_2,
2790 "send them to me to include them!");
2791 DrawTextSCentered(ystart2 + 11 * ystep, FONT_TEXT_2,
2794 DrawTextSCentered(ybottom, FONT_TEXT_4,
2795 "Press any key or button for info menu");
2798 FadeIn(REDRAW_FIELD);
2802 void HandleInfoScreen_Program(int button)
2804 if (button == MB_MENU_LEAVE)
2806 PlaySound(SND_MENU_ITEM_SELECTING);
2808 info_mode = INFO_MODE_MAIN;
2813 else if (button == MB_MENU_CHOICE)
2815 PlaySound(SND_MENU_ITEM_SELECTING);
2817 FadeSoundsAndMusic();
2820 FadeOut(REDRAW_FIELD);
2823 info_mode = INFO_MODE_MAIN;
2824 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2828 PlayMenuSoundIfLoop();
2832 void DrawInfoScreen_Version()
2834 int font_header = FONT_TEXT_3;
2835 int font_text = FONT_TEXT_2;
2836 int xstep = getFontWidth(font_text);
2837 int ystep = getFontHeight(font_text);
2838 int ystart1 = mSY - SY + 100;
2839 int ystart2 = mSY - SY + 150;
2840 int ybottom = mSY - SY + SYSIZE - 20;
2841 int xstart1 = mSX + 2 * xstep;
2842 int xstart2 = mSX + 19 * xstep;
2843 #if defined(TARGET_SDL)
2844 int xstart3 = mSX + 29 * xstep;
2845 SDL_version sdl_version_compiled;
2846 const SDL_version *sdl_version_linked;
2847 int driver_name_len = 8;
2848 char driver_name[driver_name_len];
2851 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION);
2854 FadeOut(REDRAW_FIELD);
2860 DrawTextSCentered(ystart1, FONT_TEXT_1, "Version Information:");
2862 DrawTextF(xstart1, ystart2, font_header, "Name");
2863 DrawTextF(xstart2, ystart2, font_text, PROGRAM_TITLE_STRING);
2866 DrawTextF(xstart1, ystart2, font_header, "Version");
2867 DrawTextF(xstart2, ystart2, font_text, getProgramFullVersionString());
2870 DrawTextF(xstart1, ystart2, font_header, "Platform");
2871 DrawTextF(xstart2, ystart2, font_text, PLATFORM_STRING);
2874 DrawTextF(xstart1, ystart2, font_header, "Target");
2875 DrawTextF(xstart2, ystart2, font_text, TARGET_STRING);
2878 DrawTextF(xstart1, ystart2, font_header, "Compile time");
2879 DrawTextF(xstart2, ystart2, font_text, getCompileDateString());
2881 #if defined(TARGET_SDL)
2882 ystart2 += 3 * ystep;
2883 DrawTextF(xstart1, ystart2, font_header, "Library");
2884 DrawTextF(xstart2, ystart2, font_header, "compiled");
2885 DrawTextF(xstart3, ystart2, font_header, "linked");
2887 SDL_VERSION(&sdl_version_compiled);
2888 sdl_version_linked = SDL_Linked_Version();
2890 ystart2 += 2 * ystep;
2891 DrawTextF(xstart1, ystart2, font_text, "SDL");
2892 DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
2893 sdl_version_compiled.major,
2894 sdl_version_compiled.minor,
2895 sdl_version_compiled.patch);
2896 DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
2897 sdl_version_linked->major,
2898 sdl_version_linked->minor,
2899 sdl_version_linked->patch);
2901 SDL_IMAGE_VERSION(&sdl_version_compiled);
2902 sdl_version_linked = IMG_Linked_Version();
2905 DrawTextF(xstart1, ystart2, font_text, "SDL_image");
2906 DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
2907 sdl_version_compiled.major,
2908 sdl_version_compiled.minor,
2909 sdl_version_compiled.patch);
2910 DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
2911 sdl_version_linked->major,
2912 sdl_version_linked->minor,
2913 sdl_version_linked->patch);
2915 SDL_MIXER_VERSION(&sdl_version_compiled);
2916 sdl_version_linked = Mix_Linked_Version();
2919 DrawTextF(xstart1, ystart2, font_text, "SDL_mixer");
2920 DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
2921 sdl_version_compiled.major,
2922 sdl_version_compiled.minor,
2923 sdl_version_compiled.patch);
2924 DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
2925 sdl_version_linked->major,
2926 sdl_version_linked->minor,
2927 sdl_version_linked->patch);
2929 SDL_NET_VERSION(&sdl_version_compiled);
2930 sdl_version_linked = SDLNet_Linked_Version();
2933 DrawTextF(xstart1, ystart2, font_text, "SDL_net");
2934 DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
2935 sdl_version_compiled.major,
2936 sdl_version_compiled.minor,
2937 sdl_version_compiled.patch);
2938 DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
2939 sdl_version_linked->major,
2940 sdl_version_linked->minor,
2941 sdl_version_linked->patch);
2943 ystart2 += 3 * ystep;
2944 DrawTextF(xstart1, ystart2, font_header, "Driver");
2945 DrawTextF(xstart2, ystart2, font_header, "Requested");
2946 DrawTextF(xstart3, ystart2, font_header, "Used");
2948 SDL_VideoDriverName(driver_name, driver_name_len);
2950 ystart2 += 2 * ystep;
2951 DrawTextF(xstart1, ystart2, font_text, "SDL_VideoDriver");
2952 DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_videodriver);
2953 DrawTextF(xstart3, ystart2, font_text, "%s", driver_name);
2955 SDL_AudioDriverName(driver_name, driver_name_len);
2958 DrawTextF(xstart1, ystart2, font_text, "SDL_AudioDriver");
2959 DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_audiodriver);
2960 DrawTextF(xstart3, ystart2, font_text, "%s", driver_name);
2963 DrawTextSCentered(ybottom, FONT_TEXT_4,
2964 "Press any key or button for info menu");
2967 FadeIn(REDRAW_FIELD);
2971 void HandleInfoScreen_Version(int button)
2973 if (button == MB_MENU_LEAVE)
2975 PlaySound(SND_MENU_ITEM_SELECTING);
2977 info_mode = INFO_MODE_MAIN;
2982 else if (button == MB_MENU_CHOICE)
2984 PlaySound(SND_MENU_ITEM_SELECTING);
2986 FadeSoundsAndMusic();
2989 FadeOut(REDRAW_FIELD);
2992 info_mode = INFO_MODE_MAIN;
2993 DrawAndFadeInInfoScreen(REDRAW_FIELD);
2997 PlayMenuSoundIfLoop();
3001 void DrawInfoScreen_LevelSet()
3003 struct TitleMessageInfo *tmi = &readme;
3004 char *filename = getLevelSetInfoFilename();
3006 /* if chars set to "-1", automatically determine by text and font width */
3007 if (tmi->chars == -1)
3008 tmi->chars = tmi->width / getFontWidth(tmi->font);
3010 tmi->width = tmi->chars * getFontWidth(tmi->font);
3012 /* if lines set to "-1", automatically determine by text and font height */
3013 if (tmi->lines == -1)
3014 tmi->lines = tmi->height / getFontHeight(tmi->font);
3016 tmi->height = tmi->lines * getFontHeight(tmi->font);
3018 SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
3021 FadeOut(REDRAW_FIELD);
3027 DrawTextCentered(mSY + 100, FONT_TEXT_1, "Level Set Information:");
3029 if (filename != NULL)
3030 DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi),
3031 filename, tmi->font, tmi->chars, -1, tmi->lines, -1,
3032 tmi->autowrap, tmi->centered, tmi->parse_comments);
3034 DrawTextCentered(mSY + ALIGNED_TEXT_YPOS(tmi), FONT_TEXT_2,
3035 "No information for this level set.");
3037 DrawTextCentered(mSY + SYSIZE - 20, FONT_TEXT_4,
3038 "Press any key or button for info menu");
3041 FadeIn(REDRAW_FIELD);
3045 void HandleInfoScreen_LevelSet(int button)
3047 if (button == MB_MENU_LEAVE)
3049 PlaySound(SND_MENU_ITEM_SELECTING);
3051 info_mode = INFO_MODE_MAIN;
3056 else if (button == MB_MENU_CHOICE)
3058 PlaySound(SND_MENU_ITEM_SELECTING);
3060 FadeSoundsAndMusic();
3063 FadeOut(REDRAW_FIELD);
3066 info_mode = INFO_MODE_MAIN;
3067 DrawAndFadeInInfoScreen(REDRAW_FIELD);
3071 PlayMenuSoundIfLoop();
3075 static void DrawInfoScreenExt(int fade_mask, boolean do_fading)
3077 SetMainBackgroundImage(IMG_BACKGROUND_INFO);
3079 if (info_mode == INFO_MODE_TITLE)
3080 DrawInfoScreen_TitleScreen();
3081 else if (info_mode == INFO_MODE_ELEMENTS)
3082 DrawInfoScreen_Elements();
3083 else if (info_mode == INFO_MODE_MUSIC)
3084 DrawInfoScreen_Music();
3085 else if (info_mode == INFO_MODE_CREDITS)
3086 DrawInfoScreen_Credits();
3087 else if (info_mode == INFO_MODE_PROGRAM)
3088 DrawInfoScreen_Program();
3089 else if (info_mode == INFO_MODE_VERSION)
3090 DrawInfoScreen_Version();
3091 else if (info_mode == INFO_MODE_LEVELSET)
3092 DrawInfoScreen_LevelSet();
3094 DrawInfoScreen_Main(fade_mask, do_fading);
3096 if (info_mode != INFO_MODE_MAIN &&
3097 info_mode != INFO_MODE_TITLE &&
3098 info_mode != INFO_MODE_MUSIC)
3105 void DrawAndFadeInInfoScreen(int fade_mask)
3107 DrawInfoScreenExt(fade_mask, TRUE);
3110 void DrawInfoScreen()
3112 DrawInfoScreenExt(REDRAW_FIELD, FALSE);
3115 void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
3117 if (info_mode == INFO_MODE_TITLE)
3118 HandleInfoScreen_TitleScreen(button);
3119 else if (info_mode == INFO_MODE_ELEMENTS)
3120 HandleInfoScreen_Elements(button);
3121 else if (info_mode == INFO_MODE_MUSIC)
3122 HandleInfoScreen_Music(button);
3123 else if (info_mode == INFO_MODE_CREDITS)
3124 HandleInfoScreen_Credits(button);
3125 else if (info_mode == INFO_MODE_PROGRAM)
3126 HandleInfoScreen_Program(button);
3127 else if (info_mode == INFO_MODE_VERSION)
3128 HandleInfoScreen_Version(button);
3129 else if (info_mode == INFO_MODE_LEVELSET)
3130 HandleInfoScreen_LevelSet(button);
3132 HandleInfoScreen_Main(mx, my, dx, dy, button);
3138 /* ========================================================================= */
3139 /* type name functions */
3140 /* ========================================================================= */
3142 void HandleTypeName(int newxpos, Key key)
3144 static char last_player_name[MAX_PLAYER_NAME_LEN + 1];
3145 struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME);
3146 struct TextPosInfo *pos = mci->pos_input;
3147 int startx = mSX + ALIGNED_TEXT_XPOS(pos);
3148 int starty = mSY + ALIGNED_TEXT_YPOS(pos);
3149 static int xpos = 0;
3150 int font_nr = pos->font;
3151 int font_active_nr = FONT_ACTIVE(font_nr);
3152 int font_width = getFontWidth(font_active_nr);
3153 char key_char = getValidConfigValueChar(getCharFromKey(key));
3154 boolean is_valid_key_char = (key_char != 0 && (key_char != ' ' || xpos > 0));
3155 boolean is_active = TRUE;
3157 DrawBackgroundForFont(startx,starty, pos->width, pos->height, font_active_nr);
3161 strcpy(last_player_name, setup.player_name);
3165 else if (is_valid_key_char && xpos < MAX_PLAYER_NAME_LEN)
3167 setup.player_name[xpos] = key_char;
3168 setup.player_name[xpos + 1] = 0;
3172 else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
3176 setup.player_name[xpos] = 0;
3178 else if (key == KSYM_Return && xpos > 0)
3184 game_status = GAME_MODE_MAIN;
3186 else if (key == KSYM_Escape)
3188 strcpy(setup.player_name, last_player_name);
3192 game_status = GAME_MODE_MAIN;
3197 pos->width = (strlen(setup.player_name) + 1) * font_width;
3198 startx = mSX + ALIGNED_TEXT_XPOS(pos);
3200 DrawText(startx, starty, setup.player_name, font_active_nr);
3201 DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
3205 pos->width = strlen(setup.player_name) * font_width;
3206 startx = mSX + ALIGNED_TEXT_XPOS(pos);
3208 DrawText(startx, starty, setup.player_name, font_nr);
3213 /* ========================================================================= */
3214 /* tree menu functions */
3215 /* ========================================================================= */
3217 static void DrawChooseTree(TreeInfo **ti_ptr)
3221 FreeScreenGadgets();
3222 CreateScreenGadgets();
3224 CloseDoor(DOOR_CLOSE_2);
3227 FadeOut(REDRAW_FIELD);
3232 HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
3233 MapScreenTreeGadgets(*ti_ptr);
3236 FadeIn(REDRAW_FIELD);
3242 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
3244 struct GadgetInfo *gi = screen_gadget[id];
3245 int items_max, items_visible, item_position;
3247 items_max = numTreeInfoInGroup(ti);
3248 items_visible = NUM_MENU_ENTRIES_ON_SCREEN;
3249 item_position = first_entry;
3251 if (item_position > items_max - items_visible)
3252 item_position = items_max - items_visible;
3254 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
3255 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
3256 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
3259 static void drawChooseTreeList(int first_entry, int num_page_entries,
3263 char *title_string = NULL;
3264 int yoffset_sets = MENU_TITLE1_YPOS;
3265 int yoffset_setup = 16;
3266 int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? yoffset_sets :
3268 int last_game_status = game_status; /* save current game status */
3270 title_string = ti->infotext;
3272 DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
3275 /* force LEVELS font on artwork setup screen */
3276 game_status = GAME_MODE_LEVELS;
3280 /* clear tree list area, but not title or scrollbar */
3281 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
3282 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
3283 NUM_MENU_ENTRIES_ON_SCREEN * 32);
3285 /* clear tree list area, but not title or scrollbar */
3286 DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
3287 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
3288 MAX_MENU_ENTRIES_ON_SCREEN * 32);
3291 for (i = 0; i < num_page_entries; i++)
3293 TreeInfo *node, *node_first;
3294 int entry_pos = first_entry + i;
3295 int xpos = MENU_SCREEN_START_XPOS;
3296 int ypos = MENU_SCREEN_START_YPOS + i;
3297 int startx = mSX + xpos * 32;
3298 int starty = mSY + ypos * 32;
3299 int font_nr = FONT_TEXT_1;
3300 int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
3301 int startx_text = startx + font_xoffset;
3302 int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
3303 int text_size = startx_scrollbar - startx_text;
3304 int max_buffer_len = text_size / getFontWidth(font_nr);
3305 char buffer[max_buffer_len + 1];
3307 node_first = getTreeInfoFirstGroupEntry(ti);
3308 node = getTreeInfoFromPos(node_first, entry_pos);
3310 strncpy(buffer, node->name, max_buffer_len);
3311 buffer[max_buffer_len] = '\0';
3313 DrawText(startx, starty, buffer, font_nr + node->color);
3315 if (node->parent_link)
3316 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
3317 else if (node->level_group)
3318 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
3320 initCursor(i, IMG_MENU_BUTTON);
3323 game_status = last_game_status; /* restore current game status */
3325 redraw_mask |= REDRAW_FIELD;
3328 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
3330 TreeInfo *node, *node_first;
3331 int x, last_redraw_mask = redraw_mask;
3332 int ypos = MENU_TITLE2_YPOS;
3333 int font_nr = FONT_TITLE_2;
3335 if (ti->type != TREE_TYPE_LEVEL_DIR)
3338 node_first = getTreeInfoFirstGroupEntry(ti);
3339 node = getTreeInfoFromPos(node_first, entry_pos);
3341 DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr);
3343 if (node->parent_link)
3344 DrawTextFCentered(ypos, font_nr, "leave group \"%s\"",
3346 else if (node->level_group)
3347 DrawTextFCentered(ypos, font_nr, "enter group \"%s\"",
3349 else if (ti->type == TREE_TYPE_LEVEL_DIR)
3350 DrawTextFCentered(ypos, font_nr, "%3d levels (%s)",
3351 node->levels, node->class_desc);
3353 /* let BackToFront() redraw only what is needed */
3354 redraw_mask = last_redraw_mask | REDRAW_TILES;
3355 for (x = 0; x < SCR_FIELDX; x++)
3356 MarkTileDirty(x, 1);
3359 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
3362 TreeInfo *ti = *ti_ptr;
3364 int y = ti->cl_cursor;
3365 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3366 int num_entries = numTreeInfoInGroup(ti);
3367 int num_page_entries;
3368 int last_game_status = game_status; /* save current game status */
3369 boolean position_set_by_scrollbar = (dx == 999);
3372 /* force LEVELS draw offset on choose level and artwork setup screen */
3373 game_status = GAME_MODE_LEVELS;
3376 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
3377 num_page_entries = num_entries;
3379 num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
3381 game_status = last_game_status; /* restore current game status */
3383 if (button == MB_MENU_INITIALIZE)
3385 int num_entries = numTreeInfoInGroup(ti);
3386 int entry_pos = posTreeInfo(ti);
3388 if (ti->cl_first == -1)
3390 /* only on initialization */
3391 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
3392 ti->cl_cursor = entry_pos - ti->cl_first;
3394 else if (ti->cl_cursor >= num_page_entries ||
3395 (num_entries > num_page_entries &&
3396 num_entries - ti->cl_first < num_page_entries))
3398 /* only after change of list size (by custom graphic configuration) */
3399 ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
3400 ti->cl_cursor = entry_pos - ti->cl_first;
3403 if (position_set_by_scrollbar)
3406 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3409 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3410 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3411 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3415 else if (button == MB_MENU_LEAVE)
3419 PlaySound(SND_MENU_ITEM_SELECTING);
3421 if (ti->node_parent)
3423 *ti_ptr = ti->node_parent;
3424 DrawChooseTree(ti_ptr);
3426 else if (game_status == GAME_MODE_SETUP)
3428 if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
3430 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
3431 setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
3432 execSetupGraphics();
3438 game_status = GAME_MODE_MAIN;
3440 DrawMainMenuExt(REDRAW_FIELD, FALSE);
3446 if (mx || my) /* mouse input */
3448 int last_game_status = game_status; /* save current game status */
3451 /* force LEVELS draw offset on artwork setup screen */
3452 game_status = GAME_MODE_LEVELS;
3455 x = (mx - mSX) / 32;
3456 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
3458 game_status = last_game_status; /* restore current game status */
3460 else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */
3462 /* move cursor instead of scrolling when already at start/end of list */
3463 if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
3465 else if (dy == +1 * SCROLL_LINE &&
3466 ti->cl_first + num_page_entries == num_entries)
3469 /* handle scrolling screen one line or page */
3470 if (ti->cl_cursor + dy < 0 ||
3471 ti->cl_cursor + dy > num_page_entries - 1)
3473 if (ABS(dy) == SCROLL_PAGE)
3474 step = num_page_entries - 1;
3476 if (dy < 0 && ti->cl_first > 0)
3478 /* scroll page/line up */
3480 ti->cl_first -= step;
3481 if (ti->cl_first < 0)
3484 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3485 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3486 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3488 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3491 else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
3493 /* scroll page/line down */
3495 ti->cl_first += step;
3496 if (ti->cl_first + num_page_entries > num_entries)
3497 ti->cl_first = MAX(0, num_entries - num_page_entries);
3499 drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3500 drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3501 drawChooseTreeCursor(ti->cl_cursor, TRUE);
3503 AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3510 /* handle moving cursor one line */
3511 y = ti->cl_cursor + dy;
3516 TreeInfo *node_first, *node_cursor;
3517 int entry_pos = ti->cl_first + y;
3519 node_first = getTreeInfoFirstGroupEntry(ti);
3520 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3522 if (node_cursor->node_group)
3526 PlaySound(SND_MENU_ITEM_SELECTING);
3528 node_cursor->cl_first = ti->cl_first;
3529 node_cursor->cl_cursor = ti->cl_cursor;
3530 *ti_ptr = node_cursor->node_group;
3531 DrawChooseTree(ti_ptr);
3536 else if (dx == -1 && ti->node_parent)
3540 PlaySound(SND_MENU_ITEM_SELECTING);
3542 *ti_ptr = ti->node_parent;
3543 DrawChooseTree(ti_ptr);
3548 if (!anyScrollbarGadgetActive() &&
3549 IN_VIS_FIELD(x, y) &&
3550 mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
3551 y >= 0 && y < num_page_entries)
3555 if (y != ti->cl_cursor)
3557 PlaySound(SND_MENU_ITEM_ACTIVATING);
3559 drawChooseTreeCursor(ti->cl_cursor, FALSE);
3560 drawChooseTreeCursor(y, TRUE);
3561 drawChooseTreeInfo(ti->cl_first + y, ti);
3568 TreeInfo *node_first, *node_cursor;
3569 int entry_pos = ti->cl_first + y;
3571 PlaySound(SND_MENU_ITEM_SELECTING);
3573 node_first = getTreeInfoFirstGroupEntry(ti);
3574 node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3576 if (node_cursor->node_group)
3580 node_cursor->cl_first = ti->cl_first;
3581 node_cursor->cl_cursor = ti->cl_cursor;
3582 *ti_ptr = node_cursor->node_group;
3583 DrawChooseTree(ti_ptr);
3585 else if (node_cursor->parent_link)
3589 *ti_ptr = node_cursor->node_parent;
3590 DrawChooseTree(ti_ptr);
3594 FadeSetEnterScreen();
3596 node_cursor->cl_first = ti->cl_first;
3597 node_cursor->cl_cursor = ti->cl_cursor;
3598 *ti_ptr = node_cursor;
3600 if (ti->type == TREE_TYPE_LEVEL_DIR)
3602 LoadLevelSetup_SeriesInfo();
3604 SaveLevelSetup_LastSeries();
3605 SaveLevelSetup_SeriesInfo();
3609 if (game_status == GAME_MODE_SETUP)
3611 if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
3613 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
3614 setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
3615 execSetupGraphics();
3621 game_status = GAME_MODE_MAIN;
3629 void DrawChooseLevel()
3631 SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
3633 DrawChooseTree(&leveldir_current);
3639 void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
3641 HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
3646 void DrawHallOfFame(int highlight_position)
3649 FadeSoundsAndMusic();
3651 /* (this is needed when called from GameEnd() after winning a game) */
3652 KeyboardAutoRepeatOn();
3655 /* (this is needed when called from GameEnd() after winning a game) */
3656 SetDrawDeactivationMask(REDRAW_NONE);
3657 SetDrawBackgroundMask(REDRAW_FIELD);
3659 CloseDoor(DOOR_CLOSE_2);
3661 if (highlight_position < 0)
3662 LoadScore(level_nr);
3664 FadeSetEnterScreen();
3666 // printf("::: %d: %d\n", game_status, menu.enter_screen[game_status]);
3669 FadeOut(REDRAW_FIELD);
3677 HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
3680 FadeIn(REDRAW_FIELD);
3684 static void drawHallOfFameList(int first_entry, int highlight_position)
3688 SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
3691 DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
3692 DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
3693 "HighScores of Level %d", level_nr);
3695 for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
3697 int entry = first_entry + i;
3698 boolean active = (entry == highlight_position);
3699 int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
3700 int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
3701 int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
3702 int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
3703 int dx1 = 3 * getFontWidth(font_nr1);
3704 int dx2 = dx1 + getFontWidth(font_nr1);
3705 int dx3 = dx2 + 25 * getFontWidth(font_nr3);
3706 int sy = mSY + 64 + i * 32;
3708 DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
3709 DrawText(mSX + dx1, sy, ".", font_nr1);
3710 DrawText(mSX + dx2, sy, ".........................", font_nr3);
3712 if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
3713 DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
3715 DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
3718 redraw_mask |= REDRAW_FIELD;
3721 void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
3723 static int first_entry = 0;
3724 static int highlight_position = 0;
3725 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3727 if (button == MB_MENU_INITIALIZE)
3730 highlight_position = mx;
3731 drawHallOfFameList(first_entry, highlight_position);
3736 if (ABS(dy) == SCROLL_PAGE) /* handle scrolling one page */
3737 step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
3741 if (first_entry > 0)
3743 first_entry -= step;
3744 if (first_entry < 0)
3747 drawHallOfFameList(first_entry, highlight_position);
3752 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
3754 first_entry += step;
3755 if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
3756 first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
3758 drawHallOfFameList(first_entry, highlight_position);
3761 else if (button == MB_MENU_LEAVE)
3763 PlaySound(SND_MENU_ITEM_SELECTING);
3765 FadeSound(SND_BACKGROUND_SCORES);
3767 game_status = GAME_MODE_MAIN;
3771 else if (button == MB_MENU_CHOICE)
3773 PlaySound(SND_MENU_ITEM_SELECTING);
3775 FadeSound(SND_BACKGROUND_SCORES);
3778 FadeOut(REDRAW_FIELD);
3781 game_status = GAME_MODE_MAIN;
3783 DrawAndFadeInMainMenu(REDRAW_FIELD);
3786 if (game_status == GAME_MODE_SCORES)
3787 PlayMenuSoundIfLoop();
3793 /* ========================================================================= */
3794 /* setup screen functions */
3795 /* ========================================================================= */
3797 static struct TokenInfo *setup_info;
3798 static int num_setup_info;
3800 static char *screen_mode_text;
3801 static char *scroll_delay_text;
3802 static char *game_speed_text;
3803 static char *graphics_set_name;
3804 static char *sounds_set_name;
3805 static char *music_set_name;
3807 static void execSetupMain()
3809 setup_mode = SETUP_MODE_MAIN;
3814 static void execSetupGame()
3816 if (game_speeds == NULL)
3820 for (i = 0; game_speeds_list[i].value != -1; i++)
3822 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
3823 char identifier[32], name[32];
3824 int value = game_speeds_list[i].value;
3825 char *text = game_speeds_list[i].text;
3827 ti->node_top = &game_speeds;
3828 ti->sort_priority = 10000 - value;
3830 sprintf(identifier, "%d", value);
3831 sprintf(name, "%s", text);
3833 setString(&ti->identifier, identifier);
3834 setString(&ti->name, name);
3835 setString(&ti->name_sorting, name);
3836 setString(&ti->infotext, "Game Speed");
3838 pushTreeInfo(&game_speeds, ti);
3841 /* sort game speed values to start with slowest game speed */
3842 sortTreeInfo(&game_speeds);
3844 /* set current game speed to configured game speed value */
3845 game_speed_current =
3846 getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay));
3848 /* if that fails, set current game speed to reliable default value */
3849 if (game_speed_current == NULL)
3850 game_speed_current =
3851 getTreeInfoFromIdentifier(game_speeds, i_to_a(GAME_FRAME_DELAY));
3853 /* if that also fails, set current game speed to first available speed */
3854 if (game_speed_current == NULL)
3855 game_speed_current = game_speeds;
3858 setup.game_frame_delay = atoi(game_speed_current->identifier);
3860 /* needed for displaying game speed text instead of identifier */
3861 game_speed_text = game_speed_current->name;
3863 setup_mode = SETUP_MODE_GAME;
3868 static void execSetupChooseGameSpeed()
3870 setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED;
3875 static void execSetupEditor()
3877 setup_mode = SETUP_MODE_EDITOR;
3882 static void execSetupGraphics()
3884 if (video.fullscreen_available && screen_modes == NULL)
3888 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
3890 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
3891 char identifier[32], name[32];
3892 int x = video.fullscreen_modes[i].width;
3893 int y = video.fullscreen_modes[i].height;
3896 get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy);
3898 ti->node_top = &screen_modes;
3899 ti->sort_priority = x * 10000 + y;
3901 sprintf(identifier, "%dx%d", x, y);
3902 sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy);
3904 setString(&ti->identifier, identifier);
3905 setString(&ti->name, name);
3906 setString(&ti->name_sorting, name);
3907 setString(&ti->infotext, "Fullscreen Mode");
3909 pushTreeInfo(&screen_modes, ti);
3912 /* sort fullscreen modes to start with lowest available screen resolution */
3913 sortTreeInfo(&screen_modes);
3915 /* set current screen mode for fullscreen mode to configured setup value */
3916 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3917 setup.fullscreen_mode);
3919 /* if that fails, set current screen mode to reliable default value */
3920 if (screen_mode_current == NULL)
3921 screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
3922 DEFAULT_FULLSCREEN_MODE);
3924 /* if that also fails, set current screen mode to first available mode */
3925 if (screen_mode_current == NULL)
3926 screen_mode_current = screen_modes;
3928 if (screen_mode_current == NULL)
3929 video.fullscreen_available = FALSE;
3932 if (video.fullscreen_available)
3934 setup.fullscreen_mode = screen_mode_current->identifier;
3936 /* needed for displaying screen mode name instead of identifier */
3937 screen_mode_text = screen_mode_current->name;
3941 if (scroll_delays == NULL)
3945 for (i = 0; scroll_delays_list[i].value != -1; i++)
3947 TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
3948 char identifier[32], name[32];
3949 int value = scroll_delays_list[i].value;
3950 char *text = scroll_delays_list[i].text;
3952 ti->node_top = &scroll_delays;
3953 ti->sort_priority = value;
3955 sprintf(identifier, "%d", value);
3956 sprintf(name, "%s", text);
3958 setString(&ti->identifier, identifier);
3959 setString(&ti->name, name);
3960 setString(&ti->name_sorting, name);
3961 setString(&ti->infotext, "Scroll Delay");
3963 pushTreeInfo(&scroll_delays, ti);
3966 /* sort scroll delay values to start with lowest scroll delay value */
3967 sortTreeInfo(&scroll_delays);
3969 /* set current scroll delay value to configured scroll delay value */
3970 scroll_delay_current =
3971 getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value));
3973 /* if that fails, set current scroll delay to reliable default value */
3974 if (scroll_delay_current == NULL)
3975 scroll_delay_current =
3976 getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY));
3978 /* if that also fails, set current scroll delay to first available value */
3979 if (scroll_delay_current == NULL)
3980 scroll_delay_current = scroll_delays;
3983 setup.scroll_delay_value = atoi(scroll_delay_current->identifier);
3985 /* needed for displaying scroll delay text instead of identifier */
3986 scroll_delay_text = scroll_delay_current->name;
3989 setup_mode = SETUP_MODE_GRAPHICS;
3993 static void execSetupChooseScreenMode()
3995 if (!video.fullscreen_available)
3998 setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE;
4003 static void execSetupChooseScrollDelay()
4005 setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY;
4010 static void execSetupSound()
4012 setup_mode = SETUP_MODE_SOUND;
4017 static void execSetupArtwork()
4019 setup.graphics_set = artwork.gfx_current->identifier;
4020 setup.sounds_set = artwork.snd_current->identifier;
4021 setup.music_set = artwork.mus_current->identifier;
4023 /* needed if last screen (setup choice) changed graphics, sounds or music */
4024 ReloadCustomArtwork(0);
4026 /* needed for displaying artwork name instead of artwork identifier */
4027 graphics_set_name = artwork.gfx_current->name;
4028 sounds_set_name = artwork.snd_current->name;
4029 music_set_name = artwork.mus_current->name;
4031 setup_mode = SETUP_MODE_ARTWORK;
4036 static void execSetupChooseGraphics()
4038 setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
4043 static void execSetupChooseSounds()
4045 setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
4050 static void execSetupChooseMusic()
4052 setup_mode = SETUP_MODE_CHOOSE_MUSIC;
4057 static void execSetupInput()
4059 setup_mode = SETUP_MODE_INPUT;
4064 static void execSetupShortcuts1()
4066 setup_mode = SETUP_MODE_SHORTCUTS_1;
4071 static void execSetupShortcuts2()
4073 setup_mode = SETUP_MODE_SHORTCUTS_2;
4078 static void execExitSetup()
4080 game_status = GAME_MODE_MAIN;
4082 DrawMainMenuExt(REDRAW_FIELD, FALSE);
4085 static void execSaveAndExitSetup()
4091 static struct TokenInfo setup_info_main[] =
4093 { TYPE_ENTER_MENU, execSetupGame, "Game & Menu" },
4094 { TYPE_ENTER_MENU, execSetupEditor, "Editor" },
4095 { TYPE_ENTER_MENU, execSetupGraphics, "Graphics" },
4096 { TYPE_ENTER_MENU, execSetupSound, "Sound & Music" },
4097 { TYPE_ENTER_MENU, execSetupArtwork, "Custom Artwork" },
4098 { TYPE_ENTER_MENU, execSetupInput, "Input Devices" },
4099 { TYPE_ENTER_MENU, execSetupShortcuts1, "Key Shortcuts 1" },
4100 { TYPE_ENTER_MENU, execSetupShortcuts2, "Key Shortcuts 2" },
4101 { TYPE_EMPTY, NULL, "" },
4102 { TYPE_LEAVE_MENU, execExitSetup, "Exit" },
4103 { TYPE_LEAVE_MENU, execSaveAndExitSetup, "Save and Exit" },
4108 static struct TokenInfo setup_info_game[] =
4110 { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" },
4111 { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" },
4112 { TYPE_SWITCH, &setup.handicap, "Handicap:" },
4113 { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" },
4114 { TYPE_SWITCH, &setup.time_limit, "Time Limit:" },
4115 { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" },
4116 { TYPE_ENTER_LIST, execSetupChooseGameSpeed, "Game Speed:" },
4117 { TYPE_STRING, &game_speed_text, "" },
4118 { TYPE_EMPTY, NULL, "" },
4119 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4124 static struct TokenInfo setup_info_editor[] =
4127 { TYPE_SWITCH, &setup.editor.el_boulderdash, "Boulder Dash:" },
4128 { TYPE_SWITCH, &setup.editor.el_emerald_mine, "Emerald Mine:" },
4129 { TYPE_SWITCH, &setup.editor.el_emerald_mine_club, "Emerald Mine Club:" },
4130 { TYPE_SWITCH, &setup.editor.el_more, "Rocks'n'Diamonds:" },
4131 { TYPE_SWITCH, &setup.editor.el_sokoban, "Sokoban:" },
4132 { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" },
4133 { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" },
4134 { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
4136 { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" },
4137 { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" },
4138 { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" },
4140 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" },
4142 { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
4143 { TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" },
4144 { TYPE_EMPTY, NULL, "" },
4146 { TYPE_SWITCH, &setup.editor.el_by_game, "Show elements by game:" },
4147 { TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" },
4148 { TYPE_EMPTY, NULL, "" },
4150 { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" },
4151 { TYPE_EMPTY, NULL, "" },
4152 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4157 static struct TokenInfo setup_info_graphics[] =
4159 { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" },
4160 { TYPE_ENTER_LIST, execSetupChooseScreenMode, "Fullscreen Mode:" },
4161 { TYPE_STRING, &screen_mode_text, "" },
4163 { TYPE_SWITCH, &setup.scroll_delay, "Scroll Delay:" },
4165 { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay Value:" },
4166 { TYPE_STRING, &scroll_delay_text, "" },
4168 { TYPE_SWITCH, &setup.soft_scrolling, "Soft Scrolling:" },
4170 { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" },
4171 { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" },
4172 { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" },
4173 { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" },
4174 { TYPE_SWITCH, &setup.toons, "Show Toons:" },
4175 { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" },
4176 { TYPE_EMPTY, NULL, "" },
4177 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4182 static struct TokenInfo setup_info_sound[] =
4184 { TYPE_SWITCH, &setup.sound_simple, "Sound Effects (Normal):" },
4185 { TYPE_SWITCH, &setup.sound_loops, "Sound Effects (Looping):" },
4186 { TYPE_SWITCH, &setup.sound_music, "Music:" },
4187 { TYPE_EMPTY, NULL, "" },
4188 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4193 static struct TokenInfo setup_info_artwork[] =
4195 { TYPE_ENTER_LIST, execSetupChooseGraphics,"Custom Graphics:" },
4196 { TYPE_STRING, &graphics_set_name, "" },
4197 { TYPE_ENTER_LIST, execSetupChooseSounds, "Custom Sounds:" },
4198 { TYPE_STRING, &sounds_set_name, "" },
4199 { TYPE_ENTER_LIST, execSetupChooseMusic, "Custom Music:" },
4200 { TYPE_STRING, &music_set_name, "" },
4201 { TYPE_EMPTY, NULL, "" },
4203 { TYPE_YES_NO, &setup.override_level_graphics,"Override Level Graphics:" },
4204 { TYPE_YES_NO, &setup.override_level_sounds, "Override Level Sounds:" },
4205 { TYPE_YES_NO, &setup.override_level_music, "Override Level Music:" },
4206 { TYPE_YES_NO, &setup.auto_override_artwork, "Auto-Override Non-CE Sets:" },
4208 { TYPE_STRING, NULL, "Override Level Artwork:"},
4209 { TYPE_YES_NO, &setup.override_level_graphics, "Graphics:" },
4210 { TYPE_YES_NO, &setup.override_level_sounds, "Sounds:" },
4211 { TYPE_YES_NO, &setup.override_level_music, "Music:" },
4213 { TYPE_EMPTY, NULL, "" },
4214 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4219 static struct TokenInfo setup_info_input[] =
4221 { TYPE_SWITCH, NULL, "Player:" },
4222 { TYPE_SWITCH, NULL, "Device:" },
4223 { TYPE_ENTER_MENU, NULL, "" },
4224 { TYPE_EMPTY, NULL, "" },
4225 { TYPE_EMPTY, NULL, "" },
4226 { TYPE_EMPTY, NULL, "" },
4227 { TYPE_EMPTY, NULL, "" },
4228 { TYPE_EMPTY, NULL, "" },
4229 { TYPE_EMPTY, NULL, "" },
4230 { TYPE_EMPTY, NULL, "" },
4231 { TYPE_EMPTY, NULL, "" },
4232 { TYPE_EMPTY, NULL, "" },
4233 { TYPE_EMPTY, NULL, "" },
4234 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4239 static struct TokenInfo setup_info_shortcuts_1[] =
4241 { TYPE_KEYTEXT, NULL, "Quick Save Game to Tape:", },
4242 { TYPE_KEY, &setup.shortcut.save_game, "" },
4243 { TYPE_KEYTEXT, NULL, "Quick Load Game from Tape:", },
4244 { TYPE_KEY, &setup.shortcut.load_game, "" },
4245 { TYPE_KEYTEXT, NULL, "Start Game & Toggle Pause:", },
4246 { TYPE_KEY, &setup.shortcut.toggle_pause, "" },
4247 { TYPE_EMPTY, NULL, "" },
4248 { TYPE_YES_NO, &setup.ask_on_escape, "Ask on 'Esc' Key:" },
4249 { TYPE_YES_NO, &setup.ask_on_escape_editor, "Ask on 'Esc' Key (Editor):" },
4250 { TYPE_EMPTY, NULL, "" },
4251 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4256 static struct TokenInfo setup_info_shortcuts_2[] =
4258 { TYPE_KEYTEXT, NULL, "Set Focus to Player 1:", },
4259 { TYPE_KEY, &setup.shortcut.focus_player[0], "" },
4260 { TYPE_KEYTEXT, NULL, "Set Focus to Player 2:", },
4261 { TYPE_KEY, &setup.shortcut.focus_player[1], "" },
4262 { TYPE_KEYTEXT, NULL, "Set Focus to Player 3:", },
4263 { TYPE_KEY, &setup.shortcut.focus_player[2], "" },
4264 { TYPE_KEYTEXT, NULL, "Set Focus to Player 4:", },
4265 { TYPE_KEY, &setup.shortcut.focus_player[3], "" },
4266 { TYPE_KEYTEXT, NULL, "Set Focus to All Players:", },
4267 { TYPE_KEY, &setup.shortcut.focus_player_all, "" },
4268 { TYPE_EMPTY, NULL, "" },
4269 { TYPE_LEAVE_MENU, execSetupMain, "Back" },
4274 static Key getSetupKey()
4276 Key key = KSYM_UNDEFINED;
4277 boolean got_key_event = FALSE;
4279 while (!got_key_event)
4281 if (PendingEvent()) /* got event */
4289 case EVENT_KEYPRESS:
4291 key = GetEventKey((KeyEvent *)&event, TRUE);
4293 /* press 'Escape' or 'Enter' to keep the existing key binding */
4294 if (key == KSYM_Escape || key == KSYM_Return)
4295 key = KSYM_UNDEFINED; /* keep old value */
4297 got_key_event = TRUE;
4301 case EVENT_KEYRELEASE:
4302 key_joystick_mapping = 0;
4306 HandleOtherEvents(&event);
4314 /* don't eat all CPU time */
4321 static int getSetupTextFont(int type)
4323 if (type & (TYPE_SWITCH |
4334 static int getSetupValueFont(int type, void *value)
4336 if (type & TYPE_KEY)
4337 return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1);
4338 else if (type & TYPE_STRING)
4339 return FONT_VALUE_2;
4340 else if (type & TYPE_ECS_AGA)
4341 return FONT_VALUE_1;
4342 else if (type & TYPE_BOOLEAN_STYLE)
4343 return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
4345 return FONT_VALUE_1;
4348 static void drawSetupValue(int pos)
4350 boolean font_draw_xoffset_modified = FALSE;
4351 int font_draw_xoffset_old = -1;
4352 int xpos = MENU_SCREEN_VALUE_XPOS;
4353 int ypos = MENU_SCREEN_START_YPOS + pos;
4354 int startx = mSX + xpos * 32;
4355 int starty = mSY + ypos * 32;
4356 int font_nr, font_width;
4357 int type = setup_info[pos].type;
4358 void *value = setup_info[pos].value;
4359 char *value_string = getSetupValue(type, value);
4362 if (value_string == NULL)
4365 if (type & TYPE_KEY)
4367 xpos = MENU_SCREEN_START_XPOS;
4369 if (type & TYPE_QUERY)
4371 value_string = "<press key>";
4374 else if (type & TYPE_STRING)
4376 int max_value_len = (SCR_FIELDX - 2) * 2;
4378 xpos = MENU_SCREEN_START_XPOS;
4380 if (strlen(value_string) > max_value_len)
4381 value_string[max_value_len] = '\0';
4384 startx = mSX + xpos * 32;
4385 starty = mSY + ypos * 32;
4386 font_nr = getSetupValueFont(type, value);
4387 font_width = getFontWidth(font_nr);
4389 /* downward compatibility correction for Juergen Bonhagen's menu settings */
4390 if (setup_mode != SETUP_MODE_INPUT)
4392 int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
4393 int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
4394 int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
4395 int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
4396 int text_font_nr = getSetupTextFont(FONT_MENU_2);
4397 int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
4398 int text_width = MAX_MENU_TEXT_LENGTH_MEDIUM * getFontWidth(text_font_nr);
4399 boolean correct_font_draw_xoffset = FALSE;
4401 if (xpos == MENU_SCREEN_START_XPOS &&
4402 startx + font1_xoffset < text_startx + text_font_xoffset)
4403 correct_font_draw_xoffset = TRUE;
4405 if (xpos == MENU_SCREEN_VALUE_XPOS &&
4406 startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
4407 correct_font_draw_xoffset = TRUE;
4409 /* check if setup value would overlap with setup text when printed */
4410 /* (this can happen for extreme/wrong values for font draw offset) */
4411 if (correct_font_draw_xoffset)
4413 font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
4414 font_draw_xoffset_modified = TRUE;
4416 if (type & TYPE_KEY)
4417 getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
4418 else if (!(type & TYPE_STRING))
4419 getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
4420 MAX_MENU_TEXT_LENGTH_MEDIUM * (16 - getFontWidth(text_font_nr));
4424 for (i = 0; i <= MENU_SCREEN_MAX_XPOS - xpos; i++)
4425 DrawText(startx + i * font_width, starty, " ", font_nr);
4427 DrawText(startx, starty, value_string, font_nr);
4429 if (font_draw_xoffset_modified)
4430 getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
4433 static void changeSetupValue(int pos)
4435 if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
4437 *(boolean *)setup_info[pos].value ^= TRUE;
4439 else if (setup_info[pos].type & TYPE_KEY)
4443 setup_info[pos].type |= TYPE_QUERY;
4444 drawSetupValue(pos);
4445 setup_info[pos].type &= ~TYPE_QUERY;
4447 key = getSetupKey();
4448 if (key != KSYM_UNDEFINED)
4449 *(Key *)setup_info[pos].value = key;
4452 drawSetupValue(pos);
4455 static void DrawCursorAndText_Setup(int pos, boolean active)
4457 int xpos = MENU_SCREEN_START_XPOS;
4458 int ypos = MENU_SCREEN_START_YPOS + pos;
4459 int font_nr = getSetupTextFont(setup_info[pos].type);
4461 if (setup_info == setup_info_input)
4462 font_nr = FONT_MENU_1;
4465 font_nr = FONT_ACTIVE(font_nr);
4467 DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[pos].text, font_nr);
4469 if (setup_info[pos].type & ~TYPE_SKIP_ENTRY)
4470 drawCursor(pos, active);
4473 static void DrawSetupScreen_Generic()
4475 boolean redraw_all = FALSE;
4476 char *title_string = NULL;
4480 CloseDoor(DOOR_CLOSE_2);
4482 if (redraw_mask & REDRAW_ALL)
4486 printf("::: %s\n", (redraw_mask & REDRAW_FIELD ? "REDRAW_FIELD" :
4487 redraw_mask & REDRAW_ALL ? "REDRAW_ALL" :
4488 int2str(0, redraw_mask)));
4492 /* !!! usually REDRAW_NONE => DOES NOT WORK (with fade) => CHECK THIS !!! */
4493 FadeOut(redraw_mask);
4495 FadeOut(REDRAW_FIELD);
4500 if (setup_mode == SETUP_MODE_MAIN)
4502 setup_info = setup_info_main;
4503 title_string = "Setup";
4505 else if (setup_mode == SETUP_MODE_GAME)
4507 setup_info = setup_info_game;
4508 title_string = "Setup Game";
4510 else if (setup_mode == SETUP_MODE_EDITOR)
4512 setup_info = setup_info_editor;
4513 title_string = "Setup Editor";
4515 else if (setup_mode == SETUP_MODE_GRAPHICS)
4517 setup_info = setup_info_graphics;
4518 title_string = "Setup Graphics";
4520 else if (setup_mode == SETUP_MODE_SOUND)
4522 setup_info = setup_info_sound;
4523 title_string = "Setup Sound";
4525 else if (setup_mode == SETUP_MODE_ARTWORK)
4527 setup_info = setup_info_artwork;
4528 title_string = "Custom Artwork";
4530 else if (setup_mode == SETUP_MODE_SHORTCUTS_1)
4532 setup_info = setup_info_shortcuts_1;
4533 title_string = "Setup Shortcuts";
4535 else if (setup_mode == SETUP_MODE_SHORTCUTS_2)
4537 setup_info = setup_info_shortcuts_2;
4538 title_string = "Setup Shortcuts";
4541 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
4545 for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
4547 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
4550 void *value_ptr = setup_info[i].value;
4552 /* set some entries to "unchangeable" according to other variables */
4553 if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
4554 (value_ptr == &setup.sound_loops && !audio.loops_available) ||
4555 (value_ptr == &setup.sound_music && !audio.music_available) ||
4556 (value_ptr == &setup.fullscreen && !video.fullscreen_available) ||
4557 (value_ptr == &screen_mode_text && !video.fullscreen_available))
4558 setup_info[i].type |= TYPE_GHOSTED;
4560 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
4561 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
4562 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
4563 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
4564 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
4565 initCursor(i, IMG_MENU_BUTTON);
4567 DrawCursorAndText_Setup(i, FALSE);
4569 if (setup_info[i].type & TYPE_VALUE)
4576 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
4577 "Joysticks deactivated in setup menu");
4581 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
4585 redraw_mask = REDRAW_ALL;
4588 FadeIn(redraw_mask);
4590 FadeIn(REDRAW_FIELD);
4595 HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
4599 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
4601 static int choice_store[MAX_SETUP_MODES];
4602 int choice = choice_store[setup_mode]; /* always starts with 0 */
4606 if (button == MB_MENU_INITIALIZE)
4608 /* advance to first valid menu entry */
4609 while (choice < num_setup_info &&
4610 setup_info[choice].type & TYPE_SKIP_ENTRY)
4612 choice_store[setup_mode] = choice;
4614 DrawCursorAndText_Setup(choice, TRUE);
4618 else if (button == MB_MENU_LEAVE)
4620 PlaySound(SND_MENU_ITEM_SELECTING);
4622 for (y = 0; y < num_setup_info; y++)
4624 if (setup_info[y].type & TYPE_LEAVE_MENU)
4626 void (*menu_callback_function)(void) = setup_info[y].value;
4630 menu_callback_function();
4632 break; /* absolutely needed because function changes 'setup_info'! */
4639 if (mx || my) /* mouse input */
4641 x = (mx - mSX) / 32;
4642 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
4644 else if (dx || dy) /* keyboard input */
4648 int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
4650 if (setup_info[choice].type & menu_navigation_type ||
4651 setup_info[choice].type & TYPE_BOOLEAN_STYLE)
4652 button = MB_MENU_CHOICE;
4657 /* jump to next non-empty menu entry (up or down) */
4658 while (y > 0 && y < num_setup_info - 1 &&
4659 setup_info[y].type & TYPE_SKIP_ENTRY)
4663 if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_setup_info)
4667 if (y != choice && setup_info[y].type & ~TYPE_SKIP_ENTRY)
4669 PlaySound(SND_MENU_ITEM_ACTIVATING);
4671 DrawCursorAndText_Setup(choice, FALSE);
4672 DrawCursorAndText_Setup(y, TRUE);
4674 choice = choice_store[setup_mode] = y;
4677 else if (!(setup_info[y].type & TYPE_GHOSTED))
4679 PlaySound(SND_MENU_ITEM_SELECTING);
4681 /* when selecting key headline, execute function for key value change */
4682 if (setup_info[y].type & TYPE_KEYTEXT &&
4683 setup_info[y + 1].type & TYPE_KEY)
4686 /* when selecting string value, execute function for list selection */
4687 if (setup_info[y].type & TYPE_STRING && y > 0 &&
4688 setup_info[y - 1].type & TYPE_ENTER_LIST)
4691 if (setup_info[y].type & TYPE_ENTER_OR_LEAVE)
4693 void (*menu_callback_function)(void) = setup_info[y].value;
4695 FadeSetFromType(setup_info[y].type);
4697 menu_callback_function();
4701 if (setup_info[y].type & TYPE_VALUE)
4702 changeSetupValue(y);
4708 void DrawSetupScreen_Input()
4713 FadeOut(REDRAW_FIELD);
4719 setup_info = setup_info_input;
4722 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input");
4726 DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2,
4727 "Joysticks deactivated on this screen");
4729 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
4730 "Joysticks deactivated on this screen");
4735 for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
4737 for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
4740 if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
4741 initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
4742 else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
4743 initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
4744 else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
4745 initCursor(i, IMG_MENU_BUTTON);
4747 DrawCursorAndText_Setup(i, FALSE);
4751 DeactivateJoystickForCalibration();
4756 DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2,
4757 "Joysticks deactivated on this screen");
4759 DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
4760 "Joysticks deactivated on this screen");
4764 /* create gadgets for setup input menu screen */
4765 FreeScreenGadgets();
4766 CreateScreenGadgets();
4768 /* map gadgets for setup input menu screen */
4769 MapScreenMenuGadgets(SCREEN_MASK_INPUT);
4771 HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE);
4774 FadeIn(REDRAW_FIELD);
4780 static void setJoystickDeviceToNr(char *device_name, int device_nr)
4782 if (device_name == NULL)
4785 if (device_nr < 0 || device_nr >= MAX_PLAYERS)
4788 if (strlen(device_name) > 1)
4790 char c1 = device_name[strlen(device_name) - 1];
4791 char c2 = device_name[strlen(device_name) - 2];
4793 if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9'))
4794 device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
4797 strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
4798 strlen(device_name));
4801 static void drawPlayerSetupInputInfo(int player_nr, boolean active)
4804 static struct SetupKeyboardInfo custom_key;
4811 { &custom_key.left, "Joystick Left" },
4812 { &custom_key.right, "Joystick Right" },
4813 { &custom_key.up, "Joystick Up" },
4814 { &custom_key.down, "Joystick Down" },
4815 { &custom_key.snap, "Button 1" },
4816 { &custom_key.drop, "Button 2" }
4818 static char *joystick_name[MAX_PLAYERS] =
4825 int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1);
4829 custom_key = setup.input[player_nr].key;
4831 DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
4832 FONT_INPUT_1_ACTIVE);
4834 ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
4836 DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
4837 PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
4839 if (setup.input[player_nr].use_joystick)
4841 char *device_name = setup.input[player_nr].joy.device_name;
4842 char *text = joystick_name[getJoystickNrFromDeviceName(device_name)];
4843 int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1);
4845 DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
4846 DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr);
4850 DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1);
4851 DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr);
4854 DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1);
4856 drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
4857 drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
4858 drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
4859 drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
4861 DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD);
4862 DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD);
4863 DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD);
4864 DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD);
4865 DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD);
4866 DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD);
4868 for (i = 0; i < 6; i++)
4870 int ypos = 6 + i + (i > 3 ? i-3 : 0);
4872 DrawText(mSX + 3 * 32, mSY + ypos * 32,
4874 DrawText(mSX + 3 * 32, mSY + ypos * 32,
4875 (setup.input[player_nr].use_joystick ?
4877 getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
4881 static int input_player_nr = 0;
4883 void HandleSetupScreen_Input_Player(int step, int direction)
4885 int old_player_nr = input_player_nr;
4888 new_player_nr = old_player_nr + step * direction;
4889 if (new_player_nr < 0)
4891 if (new_player_nr > MAX_PLAYERS - 1)
4892 new_player_nr = MAX_PLAYERS - 1;
4894 if (new_player_nr != old_player_nr)
4896 input_player_nr = new_player_nr;
4898 drawPlayerSetupInputInfo(input_player_nr, FALSE);
4902 void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
4904 static int choice = 0;
4907 int pos_start = SETUPINPUT_SCREEN_POS_START;
4908 int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1;
4909 int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2;
4910 int pos_end = SETUPINPUT_SCREEN_POS_END;
4912 if (button == MB_MENU_INITIALIZE)
4914 drawPlayerSetupInputInfo(input_player_nr, (choice == 2));
4916 DrawCursorAndText_Setup(choice, TRUE);
4920 else if (button == MB_MENU_LEAVE)
4922 setup_mode = SETUP_MODE_MAIN;
4929 if (mx || my) /* mouse input */
4931 x = (mx - mSX) / 32;
4932 y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
4934 else if (dx || dy) /* keyboard input */
4936 if (dx && choice == 0)
4937 x = (dx < 0 ? 10 : 12);
4938 else if ((dx && choice == 1) ||
4939 (dx == +1 && choice == 2) ||
4940 (dx == -1 && choice == pos_end))
4941 button = MB_MENU_CHOICE;
4945 if (y >= pos_empty1 && y <= pos_empty2)
4946 y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
4949 if (y == 0 && dx != 0 && button)
4951 HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1);
4953 else if (IN_VIS_FIELD(x, y) &&
4954 y >= pos_start && y <= pos_end &&
4955 !(y >= pos_empty1 && y <= pos_empty2))
4961 DrawCursorAndText_Setup(choice, FALSE);
4962 DrawCursorAndText_Setup(y, TRUE);
4964 drawPlayerSetupInputInfo(input_player_nr, (y == 2));
4973 char *device_name = setup.input[input_player_nr].joy.device_name;
4975 if (!setup.input[input_player_nr].use_joystick)
4977 int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1);
4979 setJoystickDeviceToNr(device_name, new_device_nr);
4980 setup.input[input_player_nr].use_joystick = TRUE;
4984 int device_nr = getJoystickNrFromDeviceName(device_name);
4985 int new_device_nr = device_nr + (dx >= 0 ? +1 : -1);
4987 if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS)
4988 setup.input[input_player_nr].use_joystick = FALSE;
4990 setJoystickDeviceToNr(device_name, new_device_nr);
4993 drawPlayerSetupInputInfo(input_player_nr, FALSE);
4997 if (setup.input[input_player_nr].use_joystick)
5000 CalibrateJoystick(input_player_nr);
5003 CustomizeKeyboard(input_player_nr);
5005 else if (y == pos_end)
5011 setup_mode = SETUP_MODE_MAIN;
5018 void CustomizeKeyboard(int player_nr)
5022 boolean finished = FALSE;
5023 static struct SetupKeyboardInfo custom_key;
5028 } customize_step[] =
5030 { &custom_key.left, "Move Left" },
5031 { &custom_key.right, "Move Right" },
5032 { &custom_key.up, "Move Up" },
5033 { &custom_key.down, "Move Down" },
5034 { &custom_key.snap, "Snap Field" },
5035 { &custom_key.drop, "Drop Element" }
5038 /* read existing key bindings from player setup */
5039 custom_key = setup.input[player_nr].key;
5042 FadeOut(REDRAW_FIELD);
5046 DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input");
5054 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
5055 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
5056 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
5057 "Key:", FONT_INPUT_1_ACTIVE);
5058 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
5059 getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
5062 FadeIn(REDRAW_FIELD);
5069 if (PendingEvent()) /* got event */
5077 case EVENT_KEYPRESS:
5079 Key key = GetEventKey((KeyEvent *)&event, FALSE);
5081 if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
5083 if (key == KSYM_Escape)
5084 FadeSkipNextFadeIn();
5090 /* all keys configured -- wait for "Escape" or "Return" key */
5094 /* press 'Enter' to keep the existing key binding */
5095 if (key == KSYM_Return)
5096 key = *customize_step[step_nr].key;
5098 /* check if key already used */
5099 for (i = 0; i < step_nr; i++)
5100 if (*customize_step[i].key == key)
5105 /* got new key binding */
5106 *customize_step[step_nr].key = key;
5107 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
5109 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
5110 getKeyNameFromKey(key), FONT_VALUE_1);
5113 /* un-highlight last query */
5114 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32,
5115 customize_step[step_nr - 1].text, FONT_MENU_1);
5116 DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32,
5117 "Key:", FONT_MENU_1);
5119 /* press 'Enter' to leave */
5122 DrawText(mSX + 16, mSY + 15 * 32 + 16,
5123 "Press Enter", FONT_TITLE_1);
5127 /* query next key binding */
5128 DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
5129 customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
5130 DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
5131 "Key:", FONT_INPUT_1_ACTIVE);
5132 DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
5133 getKeyNameFromKey(*customize_step[step_nr].key),
5138 case EVENT_KEYRELEASE:
5139 key_joystick_mapping = 0;
5143 HandleOtherEvents(&event);
5151 /* don't eat all CPU time */
5155 /* write new key bindings back to player setup */
5156 setup.input[player_nr].key = custom_key;
5159 DrawSetupScreen_Input();
5162 static boolean CalibrateJoystickMain(int player_nr)
5164 int new_joystick_xleft = JOYSTICK_XMIDDLE;
5165 int new_joystick_xright = JOYSTICK_XMIDDLE;
5166 int new_joystick_yupper = JOYSTICK_YMIDDLE;
5167 int new_joystick_ylower = JOYSTICK_YMIDDLE;
5168 int new_joystick_xmiddle, new_joystick_ymiddle;
5170 int joystick_fd = joystick.fd[player_nr];
5171 int x, y, last_x, last_y, xpos = 8, ypos = 3;
5172 boolean check[3][3];
5173 int check_remaining = 3 * 3;
5178 if (joystick.status == JOYSTICK_NOT_AVAILABLE)
5181 if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
5185 FadeOut(REDRAW_FIELD);
5189 for (y = 0; y < 3; y++)
5191 for (x = 0; x < 3; x++)
5193 DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
5194 check[x][y] = FALSE;
5198 DrawTextSCentered(mSY - SY + 6 * 32, FONT_TITLE_1, "Rotate joystick");
5199 DrawTextSCentered(mSY - SY + 7 * 32, FONT_TITLE_1, "in all directions");
5200 DrawTextSCentered(mSY - SY + 9 * 32, FONT_TITLE_1, "if all balls");
5201 DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,");
5202 DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick");
5203 DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and");
5204 DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!");
5206 joy_value = Joystick(player_nr);
5207 last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
5208 last_y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
5210 /* eventually uncalibrated center position (joystick could be uncentered) */
5211 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
5214 new_joystick_xmiddle = joy_x;
5215 new_joystick_ymiddle = joy_y;
5217 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
5219 FadeIn(REDRAW_FIELD);
5221 while (Joystick(player_nr) & JOY_BUTTON); /* wait for released button */
5226 if (PendingEvent()) /* got event */
5234 case EVENT_KEYPRESS:
5235 switch (GetEventKey((KeyEvent *)&event, TRUE))
5238 if (check_remaining == 0)
5243 FadeSkipNextFadeIn();
5252 case EVENT_KEYRELEASE:
5253 key_joystick_mapping = 0;
5257 HandleOtherEvents(&event);
5262 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
5265 new_joystick_xleft = MIN(new_joystick_xleft, joy_x);
5266 new_joystick_xright = MAX(new_joystick_xright, joy_x);
5267 new_joystick_yupper = MIN(new_joystick_yupper, joy_y);
5268 new_joystick_ylower = MAX(new_joystick_ylower, joy_y);
5270 setup.input[player_nr].joy.xleft = new_joystick_xleft;
5271 setup.input[player_nr].joy.yupper = new_joystick_yupper;
5272 setup.input[player_nr].joy.xright = new_joystick_xright;
5273 setup.input[player_nr].joy.ylower = new_joystick_ylower;
5274 setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle;
5275 setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle;
5277 CheckJoystickData();
5279 joy_value = Joystick(player_nr);
5281 if (joy_value & JOY_BUTTON && check_remaining == 0)
5284 x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
5285 y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
5287 if (x != last_x || y != last_y)
5289 DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0);
5290 DrawGraphic(xpos + x, ypos + y, IMG_MENU_CALIBRATE_RED, 0);
5295 if (check_remaining > 0 && !check[x+1][y+1])
5297 check[x+1][y+1] = TRUE;
5303 printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
5304 setup.input[player_nr].joy.xleft,
5305 setup.input[player_nr].joy.xmiddle,
5306 setup.input[player_nr].joy.xright);
5307 printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
5308 setup.input[player_nr].joy.yupper,
5309 setup.input[player_nr].joy.ymiddle,
5310 setup.input[player_nr].joy.ylower);
5319 /* don't eat all CPU time */
5323 /* calibrated center position (joystick should now be centered) */
5324 if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
5327 new_joystick_xmiddle = joy_x;
5328 new_joystick_ymiddle = joy_y;
5333 DrawSetupScreen_Input();
5336 /* wait until the last pressed button was released */
5337 while (Joystick(player_nr) & JOY_BUTTON)
5339 if (PendingEvent()) /* got event */
5344 HandleOtherEvents(&event);
5353 void CalibrateJoystick(int player_nr)
5355 if (!CalibrateJoystickMain(player_nr))
5357 char *device_name = setup.input[player_nr].joy.device_name;
5358 int nr = getJoystickNrFromDeviceName(device_name) + 1;
5359 int xpos = mSX - SX;
5360 int ypos = mSY - SY;
5364 DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr);
5365 DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! ");
5368 Delay(2000); /* show error message for a short time */
5374 DrawSetupScreen_Input();
5378 void DrawSetupScreen()
5380 DeactivateJoystick();
5382 SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
5384 if (setup_mode == SETUP_MODE_INPUT)
5385 DrawSetupScreen_Input();
5386 else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
5387 DrawChooseTree(&game_speed_current);
5388 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
5389 DrawChooseTree(&screen_mode_current);
5390 else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
5391 DrawChooseTree(&scroll_delay_current);
5392 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
5393 DrawChooseTree(&artwork.gfx_current);
5394 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
5395 DrawChooseTree(&artwork.snd_current);
5396 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
5397 DrawChooseTree(&artwork.mus_current);
5399 DrawSetupScreen_Generic();
5405 void RedrawSetupScreenAfterFullscreenToggle()
5407 if (setup_mode == SETUP_MODE_GRAPHICS)
5411 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
5413 if (setup_mode == SETUP_MODE_INPUT)
5414 HandleSetupScreen_Input(mx, my, dx, dy, button);
5415 else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
5416 HandleChooseTree(mx, my, dx, dy, button, &game_speed_current);
5417 else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
5418 HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
5419 else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
5420 HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
5421 else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
5422 HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
5423 else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
5424 HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
5425 else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
5426 HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
5428 HandleSetupScreen_Generic(mx, my, dx, dy, button);
5433 void HandleGameActions()
5435 if (game_status != GAME_MODE_PLAYING)
5438 GameActions(); /* main game loop */
5440 if (tape.auto_play && !tape.playing)
5441 AutoPlayTape(); /* continue automatically playing next tape */
5445 /* ---------- new screen button stuff -------------------------------------- */
5447 static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
5452 case SCREEN_CTRL_ID_PREV_LEVEL:
5453 *x = mSX + menu.main.button.prev_level.x;
5454 *y = mSY + menu.main.button.prev_level.y;
5457 case SCREEN_CTRL_ID_NEXT_LEVEL:
5458 *x = mSX + menu.main.button.next_level.x;
5459 *y = mSY + menu.main.button.next_level.y;
5462 case SCREEN_CTRL_ID_PREV_LEVEL:
5463 *x = mSX + TILEX * getPrevlevelButtonPos();
5464 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
5467 case SCREEN_CTRL_ID_NEXT_LEVEL:
5468 *x = mSX + TILEX * getNextLevelButtonPos();
5469 *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
5473 case SCREEN_CTRL_ID_PREV_PLAYER:
5474 *x = mSX + TILEX * 10;
5475 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
5478 case SCREEN_CTRL_ID_NEXT_PLAYER:
5479 *x = mSX + TILEX * 12;
5480 *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
5484 Error(ERR_EXIT, "unknown gadget ID %d", gadget_id);
5490 int gfx_unpressed, gfx_pressed;
5491 void (*get_gadget_position)(int *, int *, int);
5495 } menubutton_info[NUM_SCREEN_MENUBUTTONS] =
5498 IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE,
5499 getScreenMenuButtonPos,
5500 SCREEN_CTRL_ID_PREV_LEVEL,
5505 IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE,
5506 getScreenMenuButtonPos,
5507 SCREEN_CTRL_ID_NEXT_LEVEL,
5512 IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE,
5513 getScreenMenuButtonPos,
5514 SCREEN_CTRL_ID_PREV_PLAYER,
5519 IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE,
5520 getScreenMenuButtonPos,
5521 SCREEN_CTRL_ID_NEXT_PLAYER,
5529 int gfx_unpressed, gfx_pressed;
5533 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
5536 IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
5537 SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
5538 SCREEN_CTRL_ID_SCROLL_UP,
5542 IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
5543 SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
5544 SCREEN_CTRL_ID_SCROLL_DOWN,
5551 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5552 Bitmap **gfx_unpressed, **gfx_pressed;
5554 int gfx_unpressed, gfx_pressed;
5561 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
5564 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5565 &scrollbar_bitmap[0], &scrollbar_bitmap[1],
5567 IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
5569 SC_SCROLL_VERTICAL_XPOS, SC_SCROLL_VERTICAL_YPOS,
5570 SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
5571 GD_TYPE_SCROLLBAR_VERTICAL,
5572 SCREEN_CTRL_ID_SCROLL_VERTICAL,
5573 "scroll level series vertically"
5577 static void CreateScreenMenubuttons()
5579 struct GadgetInfo *gi;
5580 unsigned long event_mask;
5583 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
5585 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5586 int gfx_unpressed, gfx_pressed;
5587 int x, y, width, height;
5588 int gd_x1, gd_x2, gd_y1, gd_y2;
5589 int id = menubutton_info[i].gadget_id;
5591 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5593 menubutton_info[i].get_gadget_position(&x, &y, id);
5595 width = SC_MENUBUTTON_XSIZE;
5596 height = SC_MENUBUTTON_YSIZE;
5598 gfx_unpressed = menubutton_info[i].gfx_unpressed;
5599 gfx_pressed = menubutton_info[i].gfx_pressed;
5600 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5601 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5602 gd_x1 = graphic_info[gfx_unpressed].src_x;
5603 gd_y1 = graphic_info[gfx_unpressed].src_y;
5604 gd_x2 = graphic_info[gfx_pressed].src_x;
5605 gd_y2 = graphic_info[gfx_pressed].src_y;
5607 gi = CreateGadget(GDI_CUSTOM_ID, id,
5608 GDI_CUSTOM_TYPE_ID, i,
5609 GDI_INFO_TEXT, menubutton_info[i].infotext,
5614 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5615 GDI_STATE, GD_BUTTON_UNPRESSED,
5616 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5617 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5618 GDI_DIRECT_DRAW, FALSE,
5619 GDI_EVENT_MASK, event_mask,
5620 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5624 Error(ERR_EXIT, "cannot create gadget");
5626 screen_gadget[id] = gi;
5630 static void CreateScreenScrollbuttons()
5632 struct GadgetInfo *gi;
5633 unsigned long event_mask;
5636 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
5638 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5639 int gfx_unpressed, gfx_pressed;
5640 int x, y, width, height;
5641 int gd_x1, gd_x2, gd_y1, gd_y2;
5642 int id = scrollbutton_info[i].gadget_id;
5644 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5646 x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset;
5647 y = mSY + scrollbutton_info[i].y;
5648 width = SC_SCROLLBUTTON_XSIZE;
5649 height = SC_SCROLLBUTTON_YSIZE;
5651 if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
5652 y = mSY + (SC_SCROLL_VERTICAL_YPOS +
5653 (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE);
5655 gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
5656 gfx_pressed = scrollbutton_info[i].gfx_pressed;
5657 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5658 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5659 gd_x1 = graphic_info[gfx_unpressed].src_x;
5660 gd_y1 = graphic_info[gfx_unpressed].src_y;
5661 gd_x2 = graphic_info[gfx_pressed].src_x;
5662 gd_y2 = graphic_info[gfx_pressed].src_y;
5664 gi = CreateGadget(GDI_CUSTOM_ID, id,
5665 GDI_CUSTOM_TYPE_ID, i,
5666 GDI_INFO_TEXT, scrollbutton_info[i].infotext,
5671 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5672 GDI_STATE, GD_BUTTON_UNPRESSED,
5673 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5674 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5675 GDI_DIRECT_DRAW, FALSE,
5676 GDI_EVENT_MASK, event_mask,
5677 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5681 Error(ERR_EXIT, "cannot create gadget");
5683 screen_gadget[id] = gi;
5687 static void CreateScreenScrollbars()
5691 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
5693 Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
5694 #if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5695 int gfx_unpressed, gfx_pressed;
5697 int x, y, width, height;
5698 int gd_x1, gd_x2, gd_y1, gd_y2;
5699 struct GadgetInfo *gi;
5700 int items_max, items_visible, item_position;
5701 unsigned long event_mask;
5702 int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
5703 int id = scrollbar_info[i].gadget_id;
5705 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
5707 x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset;
5708 y = mSY + scrollbar_info[i].y;
5709 width = scrollbar_info[i].width;
5710 height = scrollbar_info[i].height;
5712 if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
5713 height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;
5715 items_max = num_page_entries;
5716 items_visible = num_page_entries;
5719 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5720 gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
5721 gd_bitmap_pressed = *scrollbar_info[i].gfx_pressed;
5727 gfx_unpressed = scrollbar_info[i].gfx_unpressed;
5728 gfx_pressed = scrollbar_info[i].gfx_pressed;
5729 gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
5730 gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
5731 gd_x1 = graphic_info[gfx_unpressed].src_x;
5732 gd_y1 = graphic_info[gfx_unpressed].src_y;
5733 gd_x2 = graphic_info[gfx_pressed].src_x;
5734 gd_y2 = graphic_info[gfx_pressed].src_y;
5737 gi = CreateGadget(GDI_CUSTOM_ID, id,
5738 GDI_CUSTOM_TYPE_ID, i,
5739 GDI_INFO_TEXT, scrollbar_info[i].infotext,
5744 GDI_TYPE, scrollbar_info[i].type,
5745 GDI_SCROLLBAR_ITEMS_MAX, items_max,
5746 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
5747 GDI_SCROLLBAR_ITEM_POSITION, item_position,
5749 GDI_WHEEL_AREA_X, SX,
5750 GDI_WHEEL_AREA_Y, SY,
5751 GDI_WHEEL_AREA_WIDTH, SXSIZE,
5752 GDI_WHEEL_AREA_HEIGHT, SYSIZE,
5754 GDI_WHEEL_AREA_X, 0,
5755 GDI_WHEEL_AREA_Y, 0,
5756 GDI_WHEEL_AREA_WIDTH, WIN_XSIZE,
5757 GDI_WHEEL_AREA_HEIGHT, WIN_YSIZE,
5759 GDI_STATE, GD_BUTTON_UNPRESSED,
5760 GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
5761 GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
5762 GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
5763 GDI_DIRECT_DRAW, FALSE,
5764 GDI_EVENT_MASK, event_mask,
5765 GDI_CALLBACK_ACTION, HandleScreenGadgets,
5769 Error(ERR_EXIT, "cannot create gadget");
5771 screen_gadget[id] = gi;
5775 void CreateScreenGadgets()
5777 int last_game_status = game_status; /* save current game status */
5779 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5782 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
5784 scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
5786 /* copy pointers to clip mask and GC */
5787 scrollbar_bitmap[i]->clip_mask =
5788 graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
5789 scrollbar_bitmap[i]->stored_clip_gc =
5790 graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
5792 BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
5793 scrollbar_bitmap[i],
5794 graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
5795 graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
5796 TILEX, TILEY, 0, 0);
5800 CreateScreenMenubuttons();
5803 /* force LEVELS draw offset for scrollbar / scrollbutton gadgets */
5804 game_status = GAME_MODE_LEVELS;
5807 CreateScreenScrollbuttons();
5808 CreateScreenScrollbars();
5810 game_status = last_game_status; /* restore current game status */
5813 void FreeScreenGadgets()
5817 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
5818 for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
5820 /* prevent freeing clip mask and GC twice */
5821 scrollbar_bitmap[i]->clip_mask = None;
5822 scrollbar_bitmap[i]->stored_clip_gc = None;
5824 FreeBitmap(scrollbar_bitmap[i]);
5828 for (i = 0; i < NUM_SCREEN_GADGETS; i++)
5829 FreeGadget(screen_gadget[i]);
5832 void MapScreenMenuGadgets(int screen_mask)
5836 for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
5837 if (screen_mask & menubutton_info[i].screen_mask)
5838 MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
5841 void MapScreenTreeGadgets(TreeInfo *ti)
5843 int num_entries = numTreeInfoInGroup(ti);
5846 if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
5849 for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
5850 MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
5852 for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
5853 MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
5856 static void HandleScreenGadgets(struct GadgetInfo *gi)
5858 int id = gi->custom_id;
5859 int button = gi->event.button;
5860 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
5864 case SCREEN_CTRL_ID_PREV_LEVEL:
5865 HandleMainMenu_SelectLevel(step, -1);
5868 case SCREEN_CTRL_ID_NEXT_LEVEL:
5869 HandleMainMenu_SelectLevel(step, +1);
5872 case SCREEN_CTRL_ID_PREV_PLAYER:
5873 HandleSetupScreen_Input_Player(step, -1);
5876 case SCREEN_CTRL_ID_NEXT_PLAYER:
5877 HandleSetupScreen_Input_Player(step, +1);
5880 case SCREEN_CTRL_ID_SCROLL_UP:
5881 if (game_status == GAME_MODE_LEVELS)
5882 HandleChooseLevel(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
5883 else if (game_status == GAME_MODE_SETUP)
5884 HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
5887 case SCREEN_CTRL_ID_SCROLL_DOWN:
5888 if (game_status == GAME_MODE_LEVELS)
5889 HandleChooseLevel(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
5890 else if (game_status == GAME_MODE_SETUP)
5891 HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
5894 case SCREEN_CTRL_ID_SCROLL_VERTICAL:
5895 if (game_status == GAME_MODE_LEVELS)
5896 HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
5897 else if (game_status == GAME_MODE_SETUP)
5898 HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);