+static void InitializeMainControls()
+{
+ boolean local_team_mode = (!options.network && setup.team_mode);
+ int i;
+
+ /* set main control text values to dynamically determined values */
+ sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:");
+
+ strcpy(main_text_first_level, int2str(leveldir_current->first_level,
+ menu.main.text.first_level.size));
+ strcpy(main_text_last_level, int2str(leveldir_current->last_level,
+ menu.main.text.last_level.size));
+ strcpy(main_text_level_number, int2str(level_nr,
+ menu.main.text.level_number.size));
+
+ main_text_level_year = leveldir_current->year;
+ main_text_level_imported_from = leveldir_current->imported_from;
+ main_text_level_imported_by = leveldir_current->imported_by;
+ main_text_level_tested_by = leveldir_current->tested_by;
+
+ /* set main control screen positions to dynamically determined values */
+ for (i = 0; main_controls[i].nr != -1; i++)
+ {
+ struct MainControlInfo *mci = &main_controls[i];
+ int nr = mci->nr;
+ struct MenuPosInfo *pos_button = mci->pos_button;
+ struct TextPosInfo *pos_text = mci->pos_text;
+ struct TextPosInfo *pos_input = mci->pos_input;
+ char *text = (mci->text ? *mci->text : NULL);
+ char *input = (mci->input ? *mci->input : NULL);
+ int button_graphic = mci->button_graphic;
+#if 1
+ int font_text = (pos_text ? pos_text->font : -1);
+ int font_input = (pos_input ? pos_input->font : -1);
+#else
+ int font_text = mci->font_text;
+ int font_input = mci->font_input;
+#endif
+
+ int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0);
+ int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0);
+ int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0);
+ int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
+ int text_chars = (text != NULL ? strlen(text) : 0);
+ int input_chars = (input != NULL ? strlen(input) : 0);
+
+ int button_width =
+ (button_graphic != -1 ? graphic_info[button_graphic].width : 0);
+ int button_height =
+ (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
+ int text_width = font_text_width * text_chars;
+ int text_height = font_text_height;
+ int input_width = font_input_width * input_chars;
+ int input_height = font_input_height;
+
+ if (nr == MAIN_CONTROL_NAME)
+ {
+#if 0
+ if (menu.main.input.name.x == -1)
+ menu.main.input.name.x = menu.main.text.name.x + text_width;
+ if (menu.main.input.name.y == -1)
+ menu.main.input.name.y = menu.main.text.name.y;
+#endif
+
+#if 1
+ menu.main.input.name.width = input_width;
+ menu.main.input.name.height = input_height;
+#else
+ menu.main.input.name.width = font_input_width * MAX_PLAYER_NAME_LEN;
+ menu.main.input.name.height = font_input_height;
+#endif
+ }
+
+ if (pos_button != NULL) /* (x/y may be -1/-1 here) */
+ {
+ if (pos_button->width == 0)
+ pos_button->width = button_width;
+ if (pos_button->height == 0)
+ pos_button->height = button_height;
+ }
+
+ if (pos_text != NULL) /* (x/y may be -1/-1 here) */
+ {
+#if 1
+ /* calculate size for non-clickable text -- needed for text alignment */
+ boolean calculate_text_size = (pos_button == NULL && text != NULL);
+#else
+ /* calculate width for non-clickable text -- needed for text alignment */
+ boolean calculate_text_width = (pos_button == NULL && text != NULL);
+#endif
+
+ if (visibleMenuPos(pos_button))
+ {
+ if (pos_text->x == -1)
+ pos_text->x = pos_button->x + pos_button->width;
+ if (pos_text->y == -1)
+ pos_text->y = pos_button->y;
+ }
+
+#if 1
+ if (pos_text->width == -1 || calculate_text_size)
+ pos_text->width = text_width;
+ if (pos_text->height == -1 || calculate_text_size)
+ pos_text->height = text_height;
+#else
+ if (pos_text->width == -1 || calculate_text_width)
+ pos_text->width = text_width;
+ if (pos_text->height == -1)
+ pos_text->height = text_height;
+#endif
+ }
+
+ if (pos_input != NULL) /* (x/y may be -1/-1 here) */
+ {
+ if (visibleTextPos(pos_text))
+ {
+ if (pos_input->x == -1)
+ pos_input->x = pos_text->x + pos_text->width;
+ if (pos_input->y == -1)
+ pos_input->y = pos_text->y;
+ }
+
+ if (pos_input->width == -1)
+ pos_input->width = input_width;
+ if (pos_input->height == -1)
+ pos_input->height = input_height;
+ }
+ }
+}
+
+static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
+ boolean active_input)
+{
+ int i;
+
+ for (i = 0; main_controls[i].nr != -1; i++)
+ {
+ struct MainControlInfo *mci = &main_controls[i];
+
+ if (mci->nr == nr || nr == -1)
+ {
+ struct MenuPosInfo *pos_button = mci->pos_button;
+ struct TextPosInfo *pos_text = mci->pos_text;
+ struct TextPosInfo *pos_input = mci->pos_input;
+ char *text = (mci->text ? *mci->text : NULL);
+ char *input = (mci->input ? *mci->input : NULL);
+ int button_graphic = mci->button_graphic;
+#if 1
+ int font_text = (pos_text ? pos_text->font : -1);
+ int font_input = (pos_input ? pos_input->font : -1);
+#else
+ int font_text = mci->font_text;
+ int font_input = mci->font_input;
+#endif
+
+ if (active_text)
+ {
+ button_graphic = BUTTON_ACTIVE(button_graphic);
+ font_text = FONT_ACTIVE(font_text);
+ }
+
+ if (active_input)
+ {
+ font_input = FONT_ACTIVE(font_input);
+ }
+
+ if (visibleMenuPos(pos_button))
+ {
+ struct MenuPosInfo *pos = pos_button;
+ int x = mSX + pos->x;
+ int y = mSY + pos->y;
+
+ DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
+ DrawFixedGraphicThruMaskExt(drawto, x, y, button_graphic, 0);
+ }
+
+ if (visibleTextPos(pos_text) && text != NULL)
+ {
+ struct TextPosInfo *pos = pos_text;
+ int x = mSX + ALIGNED_TEXT_XPOS(pos);
+ int y = mSY + ALIGNED_TEXT_YPOS(pos);
+
+#if 1
+ /* (check why/if this is needed) */
+ DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
+#endif
+ DrawText(x, y, text, font_text);
+ }
+
+ if (visibleTextPos(pos_input) && input != NULL)
+ {
+ struct TextPosInfo *pos = pos_input;
+ int x = mSX + ALIGNED_TEXT_XPOS(pos);
+ int y = mSY + ALIGNED_TEXT_YPOS(pos);
+
+#if 1
+ /* (check why/if this is needed) */
+ DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
+#endif
+ DrawText(x, y, input, font_input);
+ }
+ }
+ }
+}
+
+static void DrawCursorAndText_Main(int nr, boolean active_text)
+{
+ DrawCursorAndText_Main_Ext(nr, active_text, FALSE);
+}
+
+#if 0
+static void DrawCursorAndText_Main_Input(int nr, boolean active_text)
+{
+ DrawCursorAndText_Main_Ext(nr, active_text, TRUE);
+}
+#endif
+
+static struct MainControlInfo *getMainControlInfo(int nr)
+{
+ int i;
+
+ for (i = 0; main_controls[i].nr != -1; i++)
+ if (main_controls[i].nr == nr)
+ return &main_controls[i];
+
+ return NULL;
+}
+
+static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
+{
+ if (rect == NULL)
+ return FALSE;
+
+ int rect_x = ALIGNED_TEXT_XPOS(rect);
+ int rect_y = ALIGNED_TEXT_YPOS(rect);
+
+ return (x >= rect_x && x < rect_x + rect->width &&
+ y >= rect_y && y < rect_y + rect->height);
+}
+
+static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
+{
+ if (rect == NULL)
+ return FALSE;
+
+ int rect_x = ALIGNED_TEXT_XPOS(rect);
+ int rect_y = ALIGNED_TEXT_YPOS(rect);
+
+#if 0
+ printf("::: insideTextPosRect: (%d, %d), (%d, %d) [%d, %d] (%d, %d) => %d\n",
+ x, y, rect_x, rect_y, rect->x, rect->y, rect->width, rect->height,
+ (x >= rect_x && x < rect_x + rect->width &&
+ y >= rect_y && y < rect_y + rect->height));
+#endif
+
+ return (x >= rect_x && x < rect_x + rect->width &&
+ y >= rect_y && y < rect_y + rect->height);
+}
+
+static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
+{
+#if 1
+ static int cursor_array[MAX_LEV_FIELDY];
+#else
+ static int cursor_array[SCR_FIELDY];
+#endif
+ int x = mSX + TILEX * xpos;
+ int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
+
+ if (xpos == 0)
+ {
+ if (graphic != -1)
+ cursor_array[ypos] = graphic;
+ else
+ graphic = cursor_array[ypos];
+ }
+
+ if (active)
+ graphic = BUTTON_ACTIVE(graphic);
+
+ DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
+ DrawFixedGraphicThruMaskExt(drawto, x, y, graphic, 0);
+}
+
+static void initCursor(int ypos, int graphic)
+{
+ drawCursorExt(0, ypos, FALSE, graphic);
+}
+
+static void drawCursor(int ypos, boolean active)
+{
+ drawCursorExt(0, ypos, active, -1);
+}
+
+static void drawCursorXY(int xpos, int ypos, int graphic)
+{
+ drawCursorExt(xpos, ypos, FALSE, graphic);
+}
+
+static void drawChooseTreeCursor(int ypos, boolean active)
+{
+ int last_game_status = game_status; /* save current game status */
+
+#if 0
+ /* force LEVELS draw offset on artwork setup screen */
+ game_status = GAME_MODE_LEVELS;
+#endif
+
+ drawCursorExt(0, ypos, active, -1);
+
+ game_status = last_game_status; /* restore current game status */
+}
+
+void DrawHeadline()
+{
+ DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
+ DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
+}
+
+#if 0
+static int getPrevlevelButtonPos()
+{
+ return 10;
+}
+
+static int getCurrentLevelTextPos()
+{
+ return (getPrevlevelButtonPos() + 1);
+}
+
+static int getNextLevelButtonPos()
+{
+ return getPrevlevelButtonPos() + 3 + 1;
+}
+
+static int getLevelRangeTextPos()
+{
+ return getNextLevelButtonPos() + 1;
+}
+#endif
+
+int effectiveGameStatus()
+{
+ if (game_status == GAME_MODE_INFO && info_mode == INFO_MODE_TITLE)
+ return GAME_MODE_TITLE;
+
+ return game_status;
+}
+
+void DrawTitleScreenImage(int nr, boolean initial)
+{
+ int graphic = getTitleScreenGraphic(nr, initial);
+ Bitmap *bitmap = graphic_info[graphic].bitmap;
+ int width = graphic_info[graphic].width;
+ int height = graphic_info[graphic].height;
+ int src_x = graphic_info[graphic].src_x;
+ int src_y = graphic_info[graphic].src_y;
+ int dst_x, dst_y;
+
+ if (bitmap == NULL)
+ return;
+
+ if (width > WIN_XSIZE)
+ {
+ /* image width too large for window => center image horizontally */
+ src_x = (width - WIN_XSIZE) / 2;
+ width = WIN_XSIZE;
+ }
+
+ if (height > WIN_YSIZE)
+ {
+ /* image height too large for window => center image vertically */
+ src_y = (height - WIN_YSIZE) / 2;
+ height = WIN_YSIZE;
+ }
+
+ /* always display title screens centered */
+ dst_x = (WIN_XSIZE - width) / 2;
+ dst_y = (WIN_YSIZE - height) / 2;
+
+ SetDrawBackgroundMask(REDRAW_ALL);
+ SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE));
+
+ ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ if (DrawingOnBackground(dst_x, dst_y))
+ {
+ SetClipOrigin(bitmap, bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y);
+ BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
+ }
+ else
+ BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
+
+ redraw_mask = REDRAW_ALL;
+}
+
+void DrawTitleScreenMessage(int nr, boolean initial)
+{
+ char *filename = getLevelSetTitleMessageFilename(nr, initial);
+ struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
+ int last_game_status = game_status; /* save current game status */
+
+ if (filename == NULL)
+ return;
+
+ /* force TITLE font on title message screen */
+ game_status = getTitleMessageGameMode(initial);
+
+ /* if chars set to "-1", automatically determine by text and font width */
+ if (tmi->chars == -1)
+ tmi->chars = tmi->width / getFontWidth(tmi->font);
+ else
+ tmi->width = tmi->chars * getFontWidth(tmi->font);
+
+ /* if lines set to "-1", automatically determine by text and font height */
+ if (tmi->lines == -1)
+ tmi->lines = tmi->height / getFontHeight(tmi->font);
+ else
+ tmi->height = tmi->lines * getFontHeight(tmi->font);
+
+ SetDrawBackgroundMask(REDRAW_ALL);
+ SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE));
+
+ ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi),
+ filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
+ tmi->autowrap, tmi->centered, tmi->parse_comments);
+
+ game_status = last_game_status; /* restore current game status */
+}
+
+void DrawTitleScreen()
+{
+ KeyboardAutoRepeatOff();
+
+#if 0
+ SetMainBackgroundImage(IMG_BACKGROUND_TITLE);
+#endif
+
+ HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
+
+ StopAnimation();
+}
+
+boolean CheckTitleScreen(boolean levelset_has_changed)
+{
+ static boolean show_title_initial = TRUE;
+ boolean show_titlescreen = FALSE;
+
+ /* needed to be able to skip title screen, if no image or message defined */
+ InitializeTitleControls(show_title_initial);
+
+ if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
+ show_titlescreen = TRUE;
+
+ /* show initial title images and messages only once at program start */
+ show_title_initial = FALSE;
+
+ return (show_titlescreen && num_title_screens > 0);
+}
+
+void DrawMainMenuExt(int fade_mask, boolean do_fading)
+{
+ static LevelDirTree *leveldir_last_valid = NULL;
+ boolean levelset_has_changed = FALSE;
+
+ FadeSetLeaveScreen();
+
+ /* do not fade out here -- function may continue and fade on editor screen */
+
+ UnmapAllGadgets();
+ FadeSoundsAndMusic();
+
+ KeyboardAutoRepeatOn();
+ ActivateJoystick();
+
+ SetDrawDeactivationMask(REDRAW_NONE);
+ SetDrawBackgroundMask(REDRAW_FIELD);
+
+ audio.sound_deactivated = FALSE;
+
+ GetPlayerConfig();
+
+ /* needed if last screen was the playing screen, invoked from level editor */
+ if (level_editor_test_game)
+ {
+ game_status = GAME_MODE_EDITOR;
+ DrawLevelEd();
+
+ return;
+ }
+
+ /* needed if last screen was the setup screen and fullscreen state changed */
+ ToggleFullscreenIfNeeded();
+
+ /* leveldir_current may be invalid (level group, parent link) */
+ if (!validLevelSeries(leveldir_current))
+ leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
+
+ if (leveldir_current != leveldir_last_valid)
+ levelset_has_changed = TRUE;
+
+ /* store valid level series information */
+ leveldir_last_valid = leveldir_current;
+
+ init_last = init; /* switch to new busy animation */
+
+ /* needed if last screen (level choice) changed graphics, sounds or music */
+ ReloadCustomArtwork(0);
+
+ if (redraw_mask & REDRAW_ALL)
+ fade_mask = REDRAW_ALL;
+
+#if 1
+ FadeOut(fade_mask);
+
+ /* needed if last screen was the editor screen */
+ UndrawSpecialEditorDoor();
+#if 0
+ if (fade_mask == REDRAW_FIELD)
+ BackToFront();
+#endif
+#endif
+
+#if 1
+ /* needed if different viewport properties defined for menues */
+ ChangeViewportPropertiesIfNeeded();
+#endif
+
+#if defined(TARGET_SDL)
+ SetDrawtoField(DRAW_BACKBUFFER);
+#endif
+
+ if (CheckTitleScreen(levelset_has_changed))
+ {
+ game_status = GAME_MODE_TITLE;
+
+ DrawTitleScreen();
+
+ return;
+ }
+
+ /* level_nr may have been set to value over handicap with level editor */
+ if (setup.handicap && level_nr > leveldir_current->handicap_level)
+ level_nr = leveldir_current->handicap_level;
+
+ LoadLevel(level_nr);
+ LoadScore(level_nr);
+
+ SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
+
+#if 1
+ if (fade_mask == REDRAW_ALL)
+ {
+ // int door_state = GetDoorState();
+
+ RedrawBackground();
+
+ // OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+ }
+#endif
+
+ ClearField();
+
+ InitializeMainControls();
+
+ DrawCursorAndText_Main(-1, FALSE);
+ DrawPreviewLevel(TRUE);
+
+ HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
+
+ TapeStop();
+ if (TAPE_IS_EMPTY(tape))
+ LoadTape(level_nr);
+ DrawCompleteVideoDisplay();
+
+ PlayMenuSound();
+ PlayMenuMusic();
+
+ /* create gadgets for main menu screen */
+ FreeScreenGadgets();
+ CreateScreenGadgets();
+
+ /* map gadgets for main menu screen */
+ MapTapeButtons();
+ MapScreenMenuGadgets(SCREEN_MASK_MAIN);
+
+#if 1
+ if (fade_mask == REDRAW_ALL)
+ {
+ int door_state = GetDoorState();
+
+ // RedrawBackground();
+
+ OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+ }
+#endif
+
+ DrawMaskedBorder(REDRAW_ALL);
+
+ FadeIn(fade_mask);
+ FadeSetEnterMenu();
+
+#if 1
+ /* update screen area with special editor door */
+ redraw_mask |= REDRAW_ALL;
+ BackToFront();
+#endif
+
+ SetMouseCursor(CURSOR_DEFAULT);
+
+ InitAnimation();
+
+ OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
+}
+
+void DrawAndFadeInMainMenu(int fade_mask)
+{
+ DrawMainMenuExt(fade_mask, TRUE);
+}
+
+void DrawMainMenu()
+{
+ DrawMainMenuExt(REDRAW_ALL, FALSE);
+}
+
+#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
+static void gotoTopLevelDir()
+{
+ /* move upwards to top level directory */
+ while (leveldir_current->node_parent)
+ {
+ /* write a "path" into level tree for easy navigation to last level */
+ if (leveldir_current->node_parent->node_group->cl_first == -1)
+ {
+ int num_leveldirs = numTreeInfoInGroup(leveldir_current);
+ int leveldir_pos = posTreeInfo(leveldir_current);
+ int num_page_entries;
+ int cl_first, cl_cursor;
+
+ if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
+ num_page_entries = num_leveldirs;
+ else
+ num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
+
+ cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
+ cl_cursor = leveldir_pos - cl_first;
+
+ leveldir_current->node_parent->node_group->cl_first = cl_first;
+ leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
+ }
+
+ leveldir_current = leveldir_current->node_parent;
+ }
+}
+#endif
+
+void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
+{
+ static unsigned int title_delay = 0;
+ static int title_screen_nr = 0;
+ static int last_sound = -1, last_music = -1;
+ boolean return_to_main_menu = FALSE;
+ boolean use_fading_main_menu = TRUE;
+ struct TitleControlInfo *tci;
+ struct TitleFadingInfo fading_default;
+ struct TitleFadingInfo fading_last = fading;
+ struct TitleFadingInfo fading_next;
+ int sound, music;
+
+ if (button == MB_MENU_INITIALIZE)
+ {
+ title_delay = 0;
+ title_screen_nr = 0;
+ tci = &title_controls[title_screen_nr];
+
+ last_sound = SND_UNDEFINED;
+ last_music = MUS_UNDEFINED;
+
+ if (game_status == GAME_MODE_INFO)
+ {
+ if (num_title_screens == 0)
+ {
+ DrawInfoScreen_NotAvailable("Title screen information:",
+ "No title screen for this level set.");