X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fscreens.c;h=031d37dda6f90fc1cc8f715372213860726aef4e;hp=fe5f60a04a29df808fc535fc34f73f77fd6191d3;hb=17c7213a32d3a0e4c84727937f2ed79028461798;hpb=3e6bcc5592d355bc582383b36566d08dd451aba9 diff --git a/src/screens.c b/src/screens.c index fe5f60a0..3c12d6b5 100644 --- a/src/screens.c +++ b/src/screens.c @@ -18,11 +18,15 @@ #include "editor.h" #include "files.h" #include "tape.h" -#include "cartoons.h" +#include "anim.h" #include "network.h" #include "init.h" #include "config.h" + +#define DEBUG_JOYSTICKS 0 + + /* screens on the info screen */ #define INFO_MODE_MAIN 0 #define INFO_MODE_TITLE 1 @@ -60,26 +64,73 @@ /* sub-screens on the setup screen (specific) */ #define SETUP_MODE_CHOOSE_GAME_SPEED 16 #define SETUP_MODE_CHOOSE_SCROLL_DELAY 17 -#define SETUP_MODE_CHOOSE_SCREEN_MODE 18 +#define SETUP_MODE_CHOOSE_SNAPSHOT_MODE 18 #define SETUP_MODE_CHOOSE_WINDOW_SIZE 19 #define SETUP_MODE_CHOOSE_SCALING_TYPE 20 -#define SETUP_MODE_CHOOSE_GRAPHICS 21 -#define SETUP_MODE_CHOOSE_SOUNDS 22 -#define SETUP_MODE_CHOOSE_MUSIC 23 -#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE 24 -#define SETUP_MODE_CHOOSE_VOLUME_LOOPS 25 -#define SETUP_MODE_CHOOSE_VOLUME_MUSIC 26 -#define SETUP_MODE_CHOOSE_TOUCH_CONTROL 27 -#define SETUP_MODE_CHOOSE_MOVE_DISTANCE 28 -#define SETUP_MODE_CHOOSE_DROP_DISTANCE 29 - -#define MAX_SETUP_MODES 30 +#define SETUP_MODE_CHOOSE_RENDERING 21 +#define SETUP_MODE_CHOOSE_VSYNC 22 +#define SETUP_MODE_CHOOSE_GRAPHICS 23 +#define SETUP_MODE_CHOOSE_SOUNDS 24 +#define SETUP_MODE_CHOOSE_MUSIC 25 +#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE 26 +#define SETUP_MODE_CHOOSE_VOLUME_LOOPS 27 +#define SETUP_MODE_CHOOSE_VOLUME_MUSIC 28 +#define SETUP_MODE_CHOOSE_TOUCH_CONTROL 29 +#define SETUP_MODE_CHOOSE_MOVE_DISTANCE 30 +#define SETUP_MODE_CHOOSE_DROP_DISTANCE 31 +#define SETUP_MODE_CHOOSE_TRANSPARENCY 32 +#define SETUP_MODE_CHOOSE_GRID_XSIZE_0 33 +#define SETUP_MODE_CHOOSE_GRID_YSIZE_0 34 +#define SETUP_MODE_CHOOSE_GRID_XSIZE_1 35 +#define SETUP_MODE_CHOOSE_GRID_YSIZE_1 36 +#define SETUP_MODE_CONFIG_VIRT_BUTTONS 37 + +#define MAX_SETUP_MODES 38 + +#define MAX_MENU_MODES MAX(MAX_INFO_MODES, MAX_SETUP_MODES) + +/* setup screen titles */ +#define STR_SETUP_MAIN "Setup" +#define STR_SETUP_GAME "Game & Menu" +#define STR_SETUP_EDITOR "Editor" +#define STR_SETUP_GRAPHICS "Graphics" +#define STR_SETUP_SOUND "Sound & Music" +#define STR_SETUP_ARTWORK "Custom Artwork" +#define STR_SETUP_INPUT "Input Devices" +#define STR_SETUP_TOUCH "Touch Controls" +#define STR_SETUP_SHORTCUTS "Key Shortcuts" +#define STR_SETUP_EXIT "Exit" +#define STR_SETUP_SAVE_AND_EXIT "Save and Exit" + +#define STR_SETUP_CHOOSE_GAME_SPEED "Game Speed" +#define STR_SETUP_CHOOSE_SCROLL_DELAY "Scroll Delay" +#define STR_SETUP_CHOOSE_SNAPSHOT_MODE "Snapshot Mode" +#define STR_SETUP_CHOOSE_WINDOW_SIZE "Window Scaling" +#define STR_SETUP_CHOOSE_SCALING_TYPE "Anti-Aliasing" +#define STR_SETUP_CHOOSE_RENDERING "Rendering Mode" +#define STR_SETUP_CHOOSE_VSYNC "VSync Mode" +#define STR_SETUP_CHOOSE_VOLUME_SIMPLE "Sound Volume" +#define STR_SETUP_CHOOSE_VOLUME_LOOPS "Loops Volume" +#define STR_SETUP_CHOOSE_VOLUME_MUSIC "Music Volume" +#define STR_SETUP_CHOOSE_TOUCH_CONTROL "Control Type" +#define STR_SETUP_CHOOSE_MOVE_DISTANCE "Move Distance" +#define STR_SETUP_CHOOSE_DROP_DISTANCE "Drop Distance" +#define STR_SETUP_CHOOSE_TRANSPARENCY "Transparency" +#define STR_SETUP_CHOOSE_GRID_XSIZE_0 "Horiz. Buttons" +#define STR_SETUP_CHOOSE_GRID_YSIZE_0 "Vert. Buttons" +#define STR_SETUP_CHOOSE_GRID_XSIZE_1 "Horiz. Buttons" +#define STR_SETUP_CHOOSE_GRID_YSIZE_1 "Vert. Buttons" /* for input setup functions */ #define SETUPINPUT_SCREEN_POS_START 0 -#define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4) -#define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3) -#define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1) +#define SETUPINPUT_SCREEN_POS_EMPTY1 3 +#define SETUPINPUT_SCREEN_POS_EMPTY2 12 +#define SETUPINPUT_SCREEN_POS_END 13 + +#define MENU_SETUP_FONT_TITLE FONT_TEXT_1 +#define MENU_SETUP_FONT_TEXT FONT_TITLE_2 + +#define MAX_SETUP_TEXT_INPUT_LEN 28 /* for various menu stuff */ #define MENU_SCREEN_START_XPOS 1 @@ -88,39 +139,60 @@ #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1) #define MENU_TITLE1_YPOS 8 #define MENU_TITLE2_YPOS 46 -#define MENU_SCREEN_INFO_XSTART 16 -#define MENU_SCREEN_INFO_YSTART1 100 -#define MENU_SCREEN_INFO_YSTART2 128 +#define MENU_INFO_FONT_TITLE FONT_TEXT_1 +#define MENU_INFO_FONT_HEAD FONT_TEXT_2 +#define MENU_INFO_FONT_TEXT FONT_TEXT_3 +#define MENU_INFO_FONT_FOOT FONT_TEXT_4 +#define MENU_INFO_SPACE_HEAD (menu.headline2_spacing_info[info_mode]) +#define MENU_SCREEN_INFO_SPACE_LEFT (menu.left_spacing_info[info_mode]) +#define MENU_SCREEN_INFO_SPACE_RIGHT (menu.right_spacing_info[info_mode]) +#define MENU_SCREEN_INFO_SPACE_TOP (menu.top_spacing_info[info_mode]) +#define MENU_SCREEN_INFO_SPACE_BOTTOM (menu.bottom_spacing_info[info_mode]) +#define MENU_SCREEN_INFO_YSTART1 MENU_SCREEN_INFO_SPACE_TOP +#define MENU_SCREEN_INFO_YSTART2 (MENU_SCREEN_INFO_YSTART1 + \ + getMenuTextStep(MENU_INFO_SPACE_HEAD, \ + MENU_INFO_FONT_TITLE)) #define MENU_SCREEN_INFO_YSTEP (TILEY + 4) -#define MENU_SCREEN_INFO_YBOTTOM (SYSIZE - 20) +#define MENU_SCREEN_INFO_YBOTTOM (SYSIZE - MENU_SCREEN_INFO_SPACE_BOTTOM) #define MENU_SCREEN_INFO_YSIZE (MENU_SCREEN_INFO_YBOTTOM - \ MENU_SCREEN_INFO_YSTART2 - \ TILEY / 2) #define MAX_INFO_ELEMENTS_ON_SCREEN 128 -#define NUM_INFO_ELEMENTS_ON_SCREEN MIN(MENU_SCREEN_INFO_YSIZE / \ - MENU_SCREEN_INFO_YSTEP, \ - MAX_INFO_ELEMENTS_ON_SCREEN) +#define STD_INFO_ELEMENTS_ON_SCREEN (MENU_SCREEN_INFO_YSIZE / \ + MENU_SCREEN_INFO_YSTEP) +#define NUM_INFO_ELEMENTS_FROM_CONF \ + (menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] > 0 ? \ + menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] : \ + MAX_MENU_ENTRIES_ON_SCREEN) +#define NUM_INFO_ELEMENTS_ON_SCREEN MIN(MIN(STD_INFO_ELEMENTS_ON_SCREEN, \ + MAX_INFO_ELEMENTS_ON_SCREEN), \ + NUM_INFO_ELEMENTS_FROM_CONF) #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS) #define MAX_MENU_TEXT_LENGTH_BIG 13 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2) -/* buttons and scrollbars identifiers */ +/* screen gadget identifiers */ #define SCREEN_CTRL_ID_PREV_LEVEL 0 #define SCREEN_CTRL_ID_NEXT_LEVEL 1 #define SCREEN_CTRL_ID_PREV_PLAYER 2 #define SCREEN_CTRL_ID_NEXT_PLAYER 3 -#define SCREEN_CTRL_ID_SCROLL_UP 4 -#define SCREEN_CTRL_ID_SCROLL_DOWN 5 -#define SCREEN_CTRL_ID_SCROLL_VERTICAL 6 +#define SCREEN_CTRL_ID_INSERT_SOLUTION 4 +#define SCREEN_CTRL_ID_PLAY_SOLUTION 5 +#define SCREEN_CTRL_ID_SCROLL_UP 6 +#define SCREEN_CTRL_ID_SCROLL_DOWN 7 +#define SCREEN_CTRL_ID_SCROLL_VERTICAL 8 +#define SCREEN_CTRL_ID_NETWORK_SERVER 9 -#define NUM_SCREEN_GADGETS 7 +#define NUM_SCREEN_GADGETS 10 -#define NUM_SCREEN_MENUBUTTONS 4 +#define NUM_SCREEN_MENUBUTTONS 6 #define NUM_SCREEN_SCROLLBUTTONS 2 #define NUM_SCREEN_SCROLLBARS 1 +#define NUM_SCREEN_TEXTINPUT 1 #define SCREEN_MASK_MAIN (1 << 0) -#define SCREEN_MASK_INPUT (1 << 1) +#define SCREEN_MASK_MAIN_HAS_SOLUTION (1 << 1) +#define SCREEN_MASK_INPUT (1 << 2) /* graphic position and size values for buttons and scrollbars */ #define SC_MENUBUTTON_XSIZE TILEX @@ -154,7 +226,8 @@ static void HandleScreenGadgets(struct GadgetInfo *); static void HandleSetupScreen_Generic(int, int, int, int, int); static void HandleSetupScreen_Input(int, int, int, int, int); static void CustomizeKeyboard(int); -static void CalibrateJoystick(int); +static void ConfigureJoystick(int); +static void ConfigureVirtualButtons(void); static void execSetupGame(void); static void execSetupGraphics(void); static void execSetupSound(void); @@ -165,10 +238,8 @@ static void HandleChooseTree(int, int, int, int, int, TreeInfo **); static void DrawChooseLevelSet(void); static void DrawChooseLevelNr(void); static void DrawInfoScreen(void); -static void DrawAndFadeInInfoScreen(int); static void DrawSetupScreen(void); -static void DrawInfoScreenExt(int, int); static void DrawInfoScreen_NotAvailable(char *, char *); static void DrawInfoScreen_HelpAnim(int, int, boolean); static void DrawInfoScreen_HelpText(int, int, int, int); @@ -180,27 +251,40 @@ static void HandleInfoScreen_Credits(int); static void HandleInfoScreen_Program(int); static void HandleInfoScreen_Version(int); +static void ModifyGameSpeedIfNeeded(void); +static void DisableVsyncIfNeeded(void); + static void MapScreenMenuGadgets(int); static void MapScreenGadgets(int); static void MapScreenTreeGadgets(TreeInfo *); +static void UpdateScreenMenuGadgets(int, boolean); + static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS]; static int info_mode = INFO_MODE_MAIN; static int setup_mode = SETUP_MODE_MAIN; -static TreeInfo *screen_modes = NULL; -static TreeInfo *screen_mode_current = NULL; - static TreeInfo *window_sizes = NULL; static TreeInfo *window_size_current = NULL; static TreeInfo *scaling_types = NULL; static TreeInfo *scaling_type_current = NULL; +static TreeInfo *rendering_modes = NULL; +static TreeInfo *rendering_mode_current = NULL; + +static TreeInfo *vsync_modes = NULL; +static TreeInfo *vsync_mode_current = NULL; + static TreeInfo *scroll_delays = NULL; static TreeInfo *scroll_delay_current = NULL; +static TreeInfo *snapshot_modes = NULL; +static TreeInfo *snapshot_mode_current = NULL; + +static TreeInfo *game_speeds_normal = NULL; +static TreeInfo *game_speeds_extended = NULL; static TreeInfo *game_speeds = NULL; static TreeInfo *game_speed_current = NULL; @@ -222,14 +306,16 @@ static TreeInfo *move_distance_current = NULL; static TreeInfo *drop_distances = NULL; static TreeInfo *drop_distance_current = NULL; +static TreeInfo *transparencies = NULL; +static TreeInfo *transparency_current = NULL; + +static TreeInfo *grid_sizes[2][2] = { { NULL, NULL }, { NULL, NULL } }; +static TreeInfo *grid_size_current[2][2] = { { NULL, NULL }, { NULL, NULL } }; + static TreeInfo *level_number = NULL; static TreeInfo *level_number_current = NULL; -static struct -{ - int value; - char *text; -} window_sizes_list[] = +static struct ValueTextInfo window_sizes_list[] = { { 50, "50 %" }, { 80, "80 %" }, @@ -247,55 +333,71 @@ static struct { -1, NULL }, }; -static struct +static struct StringValueTextInfo scaling_types_list[] = { - char *value; - char *text; -} scaling_types_list[] = -{ - { SCALING_QUALITY_NEAREST, "None" }, + { SCALING_QUALITY_NEAREST, "Off" }, { SCALING_QUALITY_LINEAR, "Linear" }, { SCALING_QUALITY_BEST, "Anisotropic" }, { NULL, NULL }, }; -static struct +static struct StringValueTextInfo rendering_modes_list[] = { - int value; - char *text; -} game_speeds_list[] = + { STR_SPECIAL_RENDERING_OFF, "Off (May show artifacts, fast)" }, + { STR_SPECIAL_RENDERING_BITMAP, "Bitmap/Texture mode (slower)" }, +#if DEBUG + // this mode may work under certain conditions, but does not work on Windows + { STR_SPECIAL_RENDERING_TARGET, "Target Texture mode (slower)" }, +#endif + { STR_SPECIAL_RENDERING_DOUBLE, "Double Texture mode (slower)" }, + + { NULL, NULL }, +}; + +static struct StringValueTextInfo vsync_modes_list[] = +{ + { STR_VSYNC_MODE_OFF, "Off" }, + { STR_VSYNC_MODE_NORMAL, "Normal" }, + { STR_VSYNC_MODE_ADAPTIVE, "Adaptive" }, + + { NULL, NULL }, +}; + +static struct ValueTextInfo game_speeds_list_normal[] = { -#if 1 { 30, "Very Slow" }, { 25, "Slow" }, { 20, "Normal" }, { 15, "Fast" }, { 10, "Very Fast" }, -#else - { 1000, "1/1s (Extremely Slow)" }, - { 500, "1/2s" }, - { 200, "1/5s" }, - { 100, "1/10s" }, - { 50, "1/20s" }, - { 29, "1/35s (Original Supaplex)" }, - { 25, "1/40s" }, - { 20, "1/50s (Normal Speed)" }, - { 14, "1/70s (Maximum Supaplex)" }, - { 10, "1/100s" }, - { 5, "1/200s" }, - { 2, "1/500s" }, - { 1, "1/1000s (Extremely Fast)" }, -#endif { -1, NULL }, }; -static struct -{ - int value; - char *text; -} scroll_delays_list[] = +static struct ValueTextInfo game_speeds_list_extended[] = +{ + { 1000, "1 fps (Extremely Slow)" }, + { 500, "2 fps" }, + { 200, "5 fps" }, + { 100, "10 fps" }, + { 50, "20 fps" }, + { 29, "35 fps (Original Supaplex)" }, + { 25, "40 fps" }, + { 20, "50 fps (=== Normal Speed ===)" }, + { 16, "60 fps (60 Hz VSync Speed)" }, + { 14, "70 fps (Maximum Supaplex)" }, + { 10, "100 fps" }, + { 5, "200 fps" }, + { 2, "500 fps" }, + { 1, "1000 fps (Extremely Fast)" }, + + { -1, NULL }, +}; + +static struct ValueTextInfo *game_speeds_list; + +static struct ValueTextInfo scroll_delays_list[] = { { 0, "0 Tiles (No Scroll Delay)" }, { 1, "1 Tile" }, @@ -310,11 +412,17 @@ static struct { -1, NULL }, }; -static struct +static struct StringValueTextInfo snapshot_modes_list[] = { - int value; - char *text; -} volumes_list[] = + { STR_SNAPSHOT_MODE_OFF, "Off" }, + { STR_SNAPSHOT_MODE_EVERY_STEP, "Every Step" }, + { STR_SNAPSHOT_MODE_EVERY_MOVE, "Every Move" }, + { STR_SNAPSHOT_MODE_EVERY_COLLECT, "Every Collect" }, + + { NULL, NULL }, +}; + +static struct ValueTextInfo volumes_list[] = { { 0, "0 %" }, { 1, "1 %" }, @@ -334,23 +442,17 @@ static struct { -1, NULL }, }; -static struct -{ - char *value; - char *text; -} touch_controls_list[] = +static struct StringValueTextInfo touch_controls_list[] = { + { TOUCH_CONTROL_OFF, "Off" }, { TOUCH_CONTROL_VIRTUAL_BUTTONS, "Virtual Buttons" }, { TOUCH_CONTROL_WIPE_GESTURES, "Wipe Gestures" }, + { TOUCH_CONTROL_FOLLOW_FINGER, "Follow Finger" }, { NULL, NULL }, }; -static struct -{ - int value; - char *text; -} distances_list[] = +static struct ValueTextInfo distances_list[] = { { 1, "1 %" }, { 2, "2 %" }, @@ -365,13 +467,66 @@ static struct { -1, NULL }, }; +static struct ValueTextInfo transparencies_list[] = +{ + { 0, "0 % (Opaque)" }, + { 10, "10 %" }, + { 20, "20 %" }, + { 30, "30 %" }, + { 40, "40 %" }, + { 50, "50 %" }, + { 60, "60 %" }, + { 70, "70 %" }, + { 80, "80 %" }, + { 90, "90 %" }, + { 100, "100 % (Invisible)" }, + + { -1, NULL }, +}; + +static struct ValueTextInfo grid_sizes_list[] = +{ + { 3, "3" }, + { 4, "4" }, + { 5, "5" }, + { 6, "6" }, + { 7, "7" }, + { 8, "8" }, + { 9, "9" }, + { 10, "10" }, + { 11, "11" }, + { 12, "12" }, + { 13, "13" }, + { 14, "14" }, + { 15, "15" }, + { 16, "16" }, + { 17, "17" }, + { 18, "18" }, + { 19, "19" }, + { 20, "20" }, + { 21, "21" }, + { 22, "22" }, + { 23, "23" }, + { 24, "24" }, + { 25, "25" }, + { 26, "26" }, + { 27, "27" }, + { 28, "28" }, + { 29, "29" }, + { 30, "30" }, + { 31, "31" }, + { 32, "32" }, + + { -1, NULL }, +}; + #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \ (s) <= GAME_MODE_SETUP ? (s) : \ (s) == GAME_MODE_PSEUDO_TYPENAME ? \ GAME_MODE_MAIN : GAME_MODE_DEFAULT) /* (there are no draw offset definitions needed for INFO_MODE_TITLE) */ -#define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_ELEMENTS && \ +#define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_TITLE && \ (i) <= INFO_MODE_LEVELSET ? (i) : \ INFO_MODE_MAIN) @@ -388,6 +543,9 @@ static struct #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \ menu.draw_yoffset[GAME_MODE_INFO] : \ menu.draw_yoffset_info[DRAW_MODE_INFO(i)]) +#define EXTRA_SPACING_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \ + menu.extra_spacing[GAME_MODE_INFO] : \ + menu.extra_spacing_info[DRAW_MODE_INFO(i)]) #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ menu.draw_xoffset[GAME_MODE_SETUP] : \ @@ -395,6 +553,9 @@ static struct #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ menu.draw_yoffset[GAME_MODE_SETUP] : \ menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)]) +#define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ + menu.extra_spacing[GAME_MODE_SETUP] : \ + menu.extra_spacing_setup[DRAW_MODE_SETUP(i)]) #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \ DRAW_XOFFSET_INFO(info_mode) : \ @@ -406,6 +567,11 @@ static struct (s) == GAME_MODE_SETUP ? \ DRAW_YOFFSET_SETUP(setup_mode) : \ menu.draw_yoffset[DRAW_MODE(s)]) +#define EXTRA_SPACING(s) ((s) == GAME_MODE_INFO ? \ + EXTRA_SPACING_INFO(info_mode) : \ + (s) == GAME_MODE_SETUP ? \ + EXTRA_SPACING_SETUP(setup_mode) : \ + menu.extra_spacing[DRAW_MODE(s)]) #define mSX (SX + DRAW_XOFFSET(game_status)) #define mSY (SY + DRAW_YOFFSET(game_status)) @@ -432,6 +598,7 @@ struct TitleControlInfo { boolean is_image; boolean initial; + boolean first; int local_nr; int sort_priority; }; @@ -470,6 +637,8 @@ static char str_main_text_first_level[10]; static char str_main_text_last_level[10]; static char str_main_text_level_number[10]; +static char network_server_hostname[MAX_SETUP_TEXT_INPUT_LEN + 1]; + static char *main_text_name = str_main_text_name; static char *main_text_first_level = str_main_text_first_level; static char *main_text_last_level = str_main_text_last_level; @@ -487,9 +656,9 @@ static char *main_text_level_year = NULL; static char *main_text_level_imported_from = NULL; static char *main_text_level_imported_by = NULL; static char *main_text_level_tested_by = NULL; -static char *main_text_title_1 = PROGRAM_TITLE_STRING; -static char *main_text_title_2 = PROGRAM_COPYRIGHT_STRING; -static char *main_text_title_3 = PROGRAM_GAME_BY_STRING; +static char *main_text_title_1 = NULL; +static char *main_text_title_2 = NULL; +static char *main_text_title_3 = NULL; struct MainControlInfo { @@ -572,19 +741,19 @@ static struct MainControlInfo main_controls[] = #endif { MAIN_CONTROL_FIRST_LEVEL, - NULL, -1, + &menu.main.button.first_level, IMG_MENU_BUTTON_FIRST_LEVEL, &menu.main.text.first_level, &main_text_first_level, NULL, NULL, }, { MAIN_CONTROL_LAST_LEVEL, - NULL, -1, + &menu.main.button.last_level, IMG_MENU_BUTTON_LAST_LEVEL, &menu.main.text.last_level, &main_text_last_level, NULL, NULL, }, { MAIN_CONTROL_LEVEL_NUMBER, - NULL, -1, + &menu.main.button.level_number, IMG_MENU_BUTTON_LEVEL_NUMBER, &menu.main.text.level_number, &main_text_level_number, NULL, NULL, }, @@ -686,6 +855,13 @@ static int getTitleMessageGameMode(boolean initial) return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); } +static int getTitleAnimMode(struct TitleControlInfo *tci) +{ + int base = (tci->initial ? GAME_MODE_TITLE_INITIAL_1 : GAME_MODE_TITLE_1); + + return base + tci->local_nr; +} + #if 0 static int getTitleScreenBackground(boolean initial) { @@ -783,44 +959,29 @@ static int getTitleMusic(struct TitleControlInfo *tci) static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci) { boolean is_image = tci->is_image; - int initial = tci->initial; + boolean initial = tci->initial; + boolean first = tci->first; int nr = tci->local_nr; + struct TitleMessageInfo tmi; struct TitleFadingInfo ti; - if (is_image) - { - int graphic = getTitleScreenGraphic(nr, initial); - - /* initialize fading control values to default title config settings */ - ti = (initial ? title_initial_default : title_default); - - /* override default settings with image config settings, if defined */ - if (graphic_info[graphic].fade_mode != FADE_MODE_DEFAULT) - ti.fade_mode = graphic_info[graphic].fade_mode; - if (graphic_info[graphic].fade_delay > -1) - ti.fade_delay = graphic_info[graphic].fade_delay; - if (graphic_info[graphic].post_delay > -1) - ti.post_delay = graphic_info[graphic].post_delay; - if (graphic_info[graphic].auto_delay > -1) - ti.auto_delay = graphic_info[graphic].auto_delay; - } - else - { - if (initial) - { - ti.fade_mode = titlemessage_initial[nr].fade_mode; - ti.fade_delay = titlemessage_initial[nr].fade_delay; - ti.post_delay = titlemessage_initial[nr].post_delay; - ti.auto_delay = titlemessage_initial[nr].auto_delay; - } - else - { - ti.fade_mode = titlemessage[nr].fade_mode; - ti.fade_delay = titlemessage[nr].fade_delay; - ti.post_delay = titlemessage[nr].post_delay; - ti.auto_delay = titlemessage[nr].auto_delay; - } - } + tmi = (is_image ? (initial ? (first ? + titlescreen_initial_first[nr] : + titlescreen_initial[nr]) + : (first ? + titlescreen_first[nr] : + titlescreen[nr])) + : (initial ? (first ? + titlemessage_initial_first[nr] : + titlemessage_initial[nr]) + : (first ? + titlemessage_first[nr] : + titlemessage[nr]))); + + ti.fade_mode = tmi.fade_mode; + ti.fade_delay = tmi.fade_delay; + ti.post_delay = tmi.post_delay; + ti.auto_delay = tmi.auto_delay; return ti; } @@ -852,6 +1013,8 @@ static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image, title_controls[num_title_screens].local_nr = nr; title_controls[num_title_screens].sort_priority = sort_priority; + title_controls[num_title_screens].first = FALSE; /* will be set later */ + num_title_screens++; } @@ -894,6 +1057,9 @@ static void InitializeTitleControls(boolean show_title_initial) /* sort title screens according to sort_priority and title number */ qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo), compareTitleControlInfo); + + /* mark first title screen */ + title_controls[0].first = TRUE; } static boolean visibleMenuPos(struct MenuPosInfo *pos) @@ -906,9 +1072,9 @@ static boolean visibleTextPos(struct TextPosInfo *pos) return (pos != NULL && pos->x != -1 && pos->y != -1); } -static void InitializeMainControls() +static void InitializeMainControls(void) { - boolean local_team_mode = (!options.network && setup.team_mode); + boolean local_team_mode = (!network.enabled && setup.team_mode); int i; /* set main control text values to dynamically determined values */ @@ -926,6 +1092,10 @@ static void InitializeMainControls() main_text_level_imported_by = leveldir_current->imported_by; main_text_level_tested_by = leveldir_current->tested_by; + main_text_title_1 = getConfigProgramTitleString(); + main_text_title_2 = getConfigProgramCopyrightString(); + main_text_title_3 = getConfigProgramCompanyString(); + /* set main control screen positions to dynamically determined values */ for (i = 0; main_controls[i].nr != -1; i++) { @@ -970,8 +1140,8 @@ static void InitializeMainControls() if (pos_text != NULL) /* (x/y may be -1/-1 here) */ { - /* calculate size for non-clickable text -- needed for text alignment */ - boolean calculate_text_size = (pos_button == NULL && text != NULL); + /* calculate text size -- needed for text alignment */ + boolean calculate_text_size = (text != NULL); if (pos_text->width == -1 || calculate_text_size) pos_text->width = text_width; @@ -1006,8 +1176,24 @@ static void InitializeMainControls() } } +static void DrawPressedGraphicThruMask(int dst_x, int dst_y, + int graphic, boolean pressed) +{ + struct GraphicInfo *g = &graphic_info[graphic]; + Bitmap *src_bitmap; + int src_x, src_y; + int xoffset = (pressed ? g->pressed_xoffset : 0); + int yoffset = (pressed ? g->pressed_yoffset : 0); + + getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); + + BlitBitmapMasked(src_bitmap, drawto, src_x + xoffset, src_y + yoffset, + g->width, g->height, dst_x, dst_y); +} + static void DrawCursorAndText_Main_Ext(int nr, boolean active_text, - boolean active_input) + boolean active_input, + boolean pressed_button) { int i; @@ -1044,7 +1230,7 @@ static void DrawCursorAndText_Main_Ext(int nr, boolean active_text, int y = mSY + pos->y; DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic); - DrawFixedGraphicThruMaskExt(drawto, x, y, button_graphic, 0); + DrawPressedGraphicThruMask(x, y, button_graphic, pressed_button); } if (visibleTextPos(pos_text) && text != NULL) @@ -1076,15 +1262,17 @@ static void DrawCursorAndText_Main_Ext(int nr, boolean active_text, } } -static void DrawCursorAndText_Main(int nr, boolean active_text) +static void DrawCursorAndText_Main(int nr, boolean active_text, + boolean pressed_button) { - DrawCursorAndText_Main_Ext(nr, active_text, FALSE); + DrawCursorAndText_Main_Ext(nr, active_text, FALSE, pressed_button); } #if 0 -static void DrawCursorAndText_Main_Input(int nr, boolean active_text) +static void DrawCursorAndText_Main_Input(int nr, boolean active_text, + boolean pressed_button) { - DrawCursorAndText_Main_Ext(nr, active_text, TRUE); + DrawCursorAndText_Main_Ext(nr, active_text, TRUE, pressed_button); } #endif @@ -1130,6 +1318,49 @@ static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y) y >= rect_y && y < rect_y + rect->height); } +static boolean insidePreviewRect(struct PreviewInfo *preview, int x, int y) +{ + int rect_width = preview->xsize * preview->tile_size; + int rect_height = preview->ysize * preview->tile_size; + int rect_x = ALIGNED_XPOS(preview->x, rect_width, preview->align); + int rect_y = ALIGNED_YPOS(preview->y, rect_height, preview->valign); + + return (x >= rect_x && x < rect_x + rect_width && + y >= rect_y && y < rect_y + rect_height); +} + +static void AdjustScrollbar(int id, int items_max, int items_visible, + int item_position) +{ + struct GadgetInfo *gi = screen_gadget[id]; + + if (item_position > items_max - items_visible) + item_position = items_max - items_visible; + + ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, + GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, + GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); +} + +static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti) +{ + AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN, + first_entry); +} + +static void clearMenuListArea(void) +{ + int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset; + + /* correct scrollbar position if placed outside menu (playfield) area */ + if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS) + scrollbar_xpos = SX + SC_SCROLLBAR_XPOS; + + /* clear menu list area, but not title or scrollbar */ + DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32, + scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32); +} + static void drawCursorExt(int xpos, int ypos, boolean active, int graphic) { static int cursor_array[MAX_LEV_FIELDY]; @@ -1168,28 +1399,16 @@ static void drawCursorXY(int xpos, int ypos, int graphic) static void drawChooseTreeCursor(int ypos, boolean active) { - int last_game_status = game_status; /* save current game status */ - 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); } -int effectiveGameStatus() +static void DrawHeadline(void) { - if (game_status == GAME_MODE_INFO && info_mode == INFO_MODE_TITLE) - return GAME_MODE_TITLE; - - return game_status; + DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, main_text_title_1); + DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, main_text_title_2); } -void DrawTitleScreenImage(int nr, boolean initial) +static void DrawTitleScreenImage(int nr, boolean initial) { int graphic = getTitleScreenGraphic(nr, initial); Bitmap *bitmap = graphic_info[graphic].bitmap; @@ -1233,17 +1452,24 @@ void DrawTitleScreenImage(int nr, boolean initial) redraw_mask = REDRAW_ALL; } -void DrawTitleScreenMessage(int nr, boolean initial) +static 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); + SetFontStatus(getTitleMessageGameMode(initial)); + + /* if chars *and* width set to "-1", automatically determine width */ + if (tmi->chars == -1 && tmi->width == -1) + tmi->width = viewport.window[game_status].width; + + /* if lines *and* height set to "-1", automatically determine height */ + if (tmi->lines == -1 && tmi->height == -1) + tmi->height = viewport.window[game_status].height; /* if chars set to "-1", automatically determine by text and font width */ if (tmi->chars == -1) @@ -1257,6 +1483,14 @@ void DrawTitleScreenMessage(int nr, boolean initial) else tmi->height = tmi->lines * getFontHeight(tmi->font); + /* if x set to "-1", automatically determine by width and alignment */ + if (tmi->x == -1) + tmi->x = -1 * ALIGNED_XPOS(0, tmi->width, tmi->align); + + /* if y set to "-1", automatically determine by height and alignment */ + if (tmi->y == -1) + tmi->y = -1 * ALIGNED_YPOS(0, tmi->height, tmi->valign); + SetDrawBackgroundMask(REDRAW_ALL); SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE)); @@ -1266,19 +1500,17 @@ void DrawTitleScreenMessage(int nr, boolean initial) 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 */ + ResetFontStatus(); } -void DrawTitleScreen() +static void DrawTitleScreen(void) { KeyboardAutoRepeatOff(); HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE); - - StopAnimation(); } -boolean CheckTitleScreen(boolean levelset_has_changed) +static boolean CheckTitleScreen(boolean levelset_has_changed) { static boolean show_title_initial = TRUE; boolean show_titlescreen = FALSE; @@ -1295,10 +1527,11 @@ boolean CheckTitleScreen(boolean levelset_has_changed) return (show_titlescreen && num_title_screens > 0); } -void DrawMainMenuExt(int fade_mask, boolean do_fading) +void DrawMainMenu(void) { static LevelDirTree *leveldir_last_valid = NULL; boolean levelset_has_changed = FALSE; + int fade_mask = REDRAW_FIELD; LimitScreenUpdates(FALSE); @@ -1307,10 +1540,11 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading) /* do not fade out here -- function may continue and fade on editor screen */ UnmapAllGadgets(); - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); + + ExpireSoundLoops(FALSE); KeyboardAutoRepeatOn(); - ActivateJoystick(); audio.sound_deactivated = FALSE; @@ -1319,7 +1553,10 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading) /* needed if last screen was the playing screen, invoked from level editor */ if (level_editor_test_game) { - game_status = GAME_MODE_EDITOR; + CloseDoor(DOOR_CLOSE_ALL); + + SetGameStatus(GAME_MODE_EDITOR); + DrawLevelEd(); return; @@ -1344,27 +1581,27 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading) /* needed if last screen (level choice) changed graphics, sounds or music */ ReloadCustomArtwork(0); + if (CheckTitleScreen(levelset_has_changed)) + { + SetGameStatus(GAME_MODE_TITLE); + + DrawTitleScreen(); + + return; + } + if (redraw_mask & REDRAW_ALL) fade_mask = REDRAW_ALL; + if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) + fade_mask = REDRAW_ALL; + FadeOut(fade_mask); /* needed if different viewport properties defined for menues */ ChangeViewportPropertiesIfNeeded(); - /* needed if last screen was the editor screen */ - UndrawSpecialEditorDoor(); - - SetDrawtoField(DRAW_BACKBUFFER); - - if (CheckTitleScreen(levelset_has_changed)) - { - game_status = GAME_MODE_TITLE; - - DrawTitleScreen(); - - return; - } + SetDrawtoField(DRAW_TO_BACKBUFFER); /* level_nr may have been set to value over handicap with level editor */ if (setup.handicap && level_nr > leveldir_current->handicap_level) @@ -1373,21 +1610,26 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading) LoadLevel(level_nr); LoadScore(level_nr); + SaveLevelSetup_SeriesInfo(); + // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it) SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); SetMainBackgroundImage(IMG_BACKGROUND_MAIN); +#if 0 if (fade_mask == REDRAW_ALL) - RedrawBackground(); + RedrawGlobalBorder(); +#endif ClearField(); InitializeMainControls(); - DrawCursorAndText_Main(-1, FALSE); + DrawCursorAndText_Main(-1, FALSE, FALSE); DrawPreviewLevelInitial(); + DrawNetworkPlayers(); HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE); @@ -1396,23 +1638,28 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading) LoadTape(level_nr); DrawCompleteVideoDisplay(); - PlayMenuSound(); - PlayMenuMusic(); + PlayMenuSoundsAndMusic(); /* create gadgets for main menu screen */ FreeScreenGadgets(); CreateScreenGadgets(); + /* may be required if audio buttons shown on tape and changed in setup menu */ + FreeGameButtons(); + CreateGameButtons(); + /* map gadgets for main menu screen */ MapTapeButtons(); MapScreenMenuGadgets(SCREEN_MASK_MAIN); + UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape()); /* copy actual game door content to door double buffer for OpenDoor() */ + BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); BlitBitmap(drawto, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0); OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); - DrawMaskedBorder(REDRAW_ALL); + DrawMaskedBorder(fade_mask); FadeIn(fade_mask); FadeSetEnterMenu(); @@ -1423,26 +1670,14 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading) 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() +static void gotoTopLevelDir(void) { - /* move upwards to top level directory */ - while (leveldir_current->node_parent) + /* move upwards until inside (but not above) top level directory */ + while (leveldir_current->node_parent && + !strEqual(leveldir_current->node_parent->subdir, STRING_TOP_DIRECTORY)) { /* write a "path" into level tree for easy navigation to last level */ if (leveldir_current->node_parent->node_group->cl_first == -1) @@ -1467,7 +1702,6 @@ static void gotoTopLevelDir() leveldir_current = leveldir_current->node_parent; } } -#endif void HandleTitleScreen(int mx, int my, int dx, int dy, int button) { @@ -1475,11 +1709,7 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) 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) @@ -1488,40 +1718,50 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) title_screen_nr = 0; tci = &title_controls[title_screen_nr]; + SetAnimStatus(getTitleAnimMode(tci)); + last_sound = SND_UNDEFINED; last_music = MUS_UNDEFINED; - if (game_status == GAME_MODE_INFO) + if (num_title_screens != 0) + { + FadeSetEnterScreen(); + + /* use individual title fading instead of global "enter screen" fading */ + fading = getTitleFading(tci); + } + + if (game_status_last_screen == GAME_MODE_INFO) { if (num_title_screens == 0) { + /* switch game mode from title screen mode back to info screen mode */ + SetGameStatus(GAME_MODE_INFO); + + /* store that last screen was info screen, not main menu screen */ + game_status_last_screen = GAME_MODE_INFO; + DrawInfoScreen_NotAvailable("Title screen information:", "No title screen for this level set."); - return; } - FadeSoundsAndMusic(); - - FadeOut(REDRAW_ALL); + FadeMenuSoundsAndMusic(); } + FadeOut(REDRAW_ALL); + + /* title screens may have different window size */ + ChangeViewportPropertiesIfNeeded(); + + /* only required to update logic for redrawing global border */ + ClearField(); + if (tci->is_image) DrawTitleScreenImage(tci->local_nr, tci->initial); else DrawTitleScreenMessage(tci->local_nr, tci->initial); - fading_default = (tci->initial ? title_initial_default : title_default); - - fading = fading_next = getTitleFading(tci); - - if (!(fading_last.fade_mode & FADE_TYPE_TRANSFORM) && - fading_next.fade_mode & FADE_TYPE_TRANSFORM) - { - fading.fade_mode = FADE_MODE_FADE; - fading.fade_delay = fading_default.fade_delay; - } - sound = getTitleSound(tci); music = getTitleMusic(tci); @@ -1537,8 +1777,6 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) FadeIn(REDRAW_ALL); - fading = fading_next; - DelayReached(&title_delay, 0); /* reset delay counter */ return; @@ -1550,33 +1788,38 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) if (button == MB_MENU_LEAVE) { return_to_main_menu = TRUE; - use_fading_main_menu = FALSE; } else if (button == MB_MENU_CHOICE) { - if (game_status == GAME_MODE_INFO && num_title_screens == 0) + if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0) { - FadeSetEnterScreen(); + SetGameStatus(GAME_MODE_INFO); info_mode = INFO_MODE_MAIN; - DrawAndFadeInInfoScreen(REDRAW_FIELD); + + DrawInfoScreen(); return; } title_screen_nr++; - tci = &title_controls[title_screen_nr]; if (title_screen_nr < num_title_screens) { + tci = &title_controls[title_screen_nr]; + + SetAnimStatus(getTitleAnimMode(tci)); + sound = getTitleSound(tci); music = getTitleMusic(tci); - if (sound == SND_UNDEFINED || sound != last_sound) - FadeSounds(); - if (music == MUS_UNDEFINED || music != last_music) + if (last_sound != SND_UNDEFINED && sound != last_sound) + FadeSound(last_sound); + if (last_music != MUS_UNDEFINED && music != last_music) FadeMusic(); + fading = getTitleFading(tci); + FadeOut(REDRAW_ALL); if (tci->is_image) @@ -1584,8 +1827,6 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) else DrawTitleScreenMessage(tci->local_nr, tci->initial); - fading_next = getTitleFading(tci); - sound = getTitleSound(tci); music = getTitleMusic(tci); @@ -1597,20 +1838,13 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) last_sound = sound; last_music = music; - /* last screen already faded out, next screen has no animation */ - if (!(fading.fade_mode & FADE_TYPE_TRANSFORM) && - fading_next.fade_mode == FADE_MODE_NONE) - fading = fading_next; - FadeIn(REDRAW_ALL); - fading = fading_next; - DelayReached(&title_delay, 0); /* reset delay counter */ } else { - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); return_to_main_menu = TRUE; } @@ -1620,24 +1854,28 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) { SetMouseCursor(CURSOR_DEFAULT); - if (game_status == GAME_MODE_INFO) + /* force full menu screen redraw after displaying title screens */ + redraw_mask = REDRAW_ALL; + + if (game_status_last_screen == GAME_MODE_INFO) { - int fade_mask = (num_title_screens == 0 ? REDRAW_FIELD : REDRAW_ALL); + SetGameStatus(GAME_MODE_INFO); info_mode = INFO_MODE_MAIN; - DrawInfoScreenExt(fade_mask, use_fading_main_menu); + DrawInfoScreen(); } else /* default: return to main menu */ { - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); - DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu); + DrawMainMenu(); } } } -void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr) +static void HandleMainMenu_SelectLevel(int step, int direction, + int selected_level_nr) { int old_level_nr = level_nr; int new_level_nr; @@ -1684,6 +1922,10 @@ void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr) LoadTape(level_nr); DrawCompleteVideoDisplay(); + SaveLevelSetup_SeriesInfo(); + + UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape()); + /* needed because DrawPreviewLevelInitial() takes some time */ BackToFront(); /* SyncDisplay(); */ @@ -1693,12 +1935,14 @@ void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr) void HandleMainMenu(int mx, int my, int dx, int dy, int button) { static int choice = MAIN_CONTROL_GAME; + static boolean button_pressed_last = FALSE; + boolean button_pressed = FALSE; int pos = choice; int i; if (button == MB_MENU_INITIALIZE) { - DrawCursorAndText_Main(choice, TRUE); + DrawCursorAndText_Main(choice, TRUE, FALSE); return; } @@ -1718,6 +1962,27 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) break; } } + + /* check if level preview was clicked */ + if (insidePreviewRect(&preview, mx - SX, my - SY)) + pos = MAIN_CONTROL_GAME; + + // handle pressed/unpressed state for active/inactive menu buttons + // (if pos != -1, "i" contains index position corresponding to "pos") + if (button && + pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT && + insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY)) + button_pressed = TRUE; + + if (button_pressed != button_pressed_last) + { + DrawCursorAndText_Main(choice, TRUE, button_pressed); + + if (button_pressed) + PlaySound(SND_MENU_BUTTON_PRESSING); + else + PlaySound(SND_MENU_BUTTON_RELEASING); + } } else if (dx || dy) /* keyboard input */ { @@ -1728,11 +1993,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) pos = choice + dy; } - if (pos == MAIN_CONTROL_LEVELS && dx != 0 && button) - { - HandleMainMenu_SelectLevel(1, (dx < 0 ? -1 : +1), NO_DIRECT_LEVEL_SELECT); - } - else if (pos == MAIN_CONTROL_FIRST_LEVEL && !button) + if (pos == MAIN_CONTROL_FIRST_LEVEL && !button) { HandleMainMenu_SelectLevel(MAX_LEVELS, -1, NO_DIRECT_LEVEL_SELECT); } @@ -1742,9 +2003,9 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) } else if (pos == MAIN_CONTROL_LEVEL_NUMBER && !button) { - game_status = GAME_MODE_LEVELNR; + CloseDoor(DOOR_CLOSE_2); - ChangeViewportPropertiesIfNeeded(); + SetGameStatus(GAME_MODE_LEVELNR); DrawChooseLevelNr(); } @@ -1756,11 +2017,17 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) { PlaySound(SND_MENU_ITEM_ACTIVATING); - DrawCursorAndText_Main(choice, FALSE); - DrawCursorAndText_Main(pos, TRUE); + DrawCursorAndText_Main(choice, FALSE, FALSE); + DrawCursorAndText_Main(pos, TRUE, button_pressed); choice = pos; } + else if (dx != 0) + { + if (choice != MAIN_CONTROL_INFO && + choice != MAIN_CONTROL_SETUP) + HandleMainMenu_SelectLevel(1, dx, NO_DIRECT_LEVEL_SELECT); + } } else { @@ -1768,7 +2035,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) if (pos == MAIN_CONTROL_NAME) { - game_status = GAME_MODE_PSEUDO_TYPENAME; + SetGameStatus(GAME_MODE_PSEUDO_TYPENAME); HandleTypeName(strlen(setup.player_name), 0); } @@ -1776,27 +2043,26 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) { if (leveldir_first) { - game_status = GAME_MODE_LEVELS; + CloseDoor(DOOR_CLOSE_2); + + SetGameStatus(GAME_MODE_LEVELS); SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); -#if defined(CREATE_SPECIAL_EDITION_RND_JUE) - gotoTopLevelDir(); -#endif - - ChangeViewportPropertiesIfNeeded(); + if (setup.internal.choose_from_top_leveldir) + gotoTopLevelDir(); DrawChooseLevelSet(); } } else if (pos == MAIN_CONTROL_SCORES) { - game_status = GAME_MODE_SCORES; + CloseDoor(DOOR_CLOSE_2); - ChangeViewportPropertiesIfNeeded(); + SetGameStatus(GAME_MODE_SCORES); - DrawHallOfFame(-1); + DrawHallOfFame(level_nr, -1); } else if (pos == MAIN_CONTROL_EDITOR) { @@ -1806,7 +2072,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) CloseDoor(DOOR_CLOSE_2); - game_status = GAME_MODE_EDITOR; + SetGameStatus(GAME_MODE_EDITOR); FadeSetEnterScreen(); @@ -1814,23 +2080,25 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) } else if (pos == MAIN_CONTROL_INFO) { - game_status = GAME_MODE_INFO; - info_mode = INFO_MODE_MAIN; + CloseDoor(DOOR_CLOSE_2); + + SetGameStatus(GAME_MODE_INFO); - ChangeViewportPropertiesIfNeeded(); + info_mode = INFO_MODE_MAIN; DrawInfoScreen(); } else if (pos == MAIN_CONTROL_GAME) { - StartGameActions(options.network, setup.autorecord, level.random_seed); + StartGameActions(network.enabled, setup.autorecord, level.random_seed); } else if (pos == MAIN_CONTROL_SETUP) { - game_status = GAME_MODE_SETUP; - setup_mode = SETUP_MODE_MAIN; + CloseDoor(DOOR_CLOSE_2); + + SetGameStatus(GAME_MODE_SETUP); - ChangeViewportPropertiesIfNeeded(); + setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } @@ -1840,10 +2108,12 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) SaveLevelSetup_SeriesInfo(); if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED)) - game_status = GAME_MODE_QUIT; + SetGameStatus(GAME_MODE_QUIT); } } } + + button_pressed_last = button_pressed; } @@ -1852,62 +2122,63 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) /* ========================================================================= */ static struct TokenInfo *info_info; -static int num_info_info; +static int num_info_info; /* number of info entries shown on screen */ +static int max_info_info; /* total number of info entries in list */ -static void execInfoTitleScreen() +static void execInfoTitleScreen(void) { info_mode = INFO_MODE_TITLE; DrawInfoScreen(); } -static void execInfoElements() +static void execInfoElements(void) { info_mode = INFO_MODE_ELEMENTS; DrawInfoScreen(); } -static void execInfoMusic() +static void execInfoMusic(void) { info_mode = INFO_MODE_MUSIC; DrawInfoScreen(); } -static void execInfoCredits() +static void execInfoCredits(void) { info_mode = INFO_MODE_CREDITS; DrawInfoScreen(); } -static void execInfoProgram() +static void execInfoProgram(void) { info_mode = INFO_MODE_PROGRAM; DrawInfoScreen(); } -static void execInfoVersion() +static void execInfoVersion(void) { info_mode = INFO_MODE_VERSION; DrawInfoScreen(); } -static void execInfoLevelSet() +static void execInfoLevelSet(void) { info_mode = INFO_MODE_LEVELSET; DrawInfoScreen(); } -static void execExitInfo() +static void execExitInfo(void) { - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); - DrawMainMenuExt(REDRAW_FIELD, FALSE); + DrawMainMenu(); } static struct TokenInfo info_info_main[] = @@ -1925,27 +2196,142 @@ static struct TokenInfo info_info_main[] = { 0, NULL, NULL } }; -static void DrawCursorAndText_Info(int pos, boolean active) +static int getMenuTextFont(int type) +{ + if (type & (TYPE_SWITCH | + TYPE_YES_NO | + TYPE_YES_NO_AUTO | + TYPE_STRING | + TYPE_PLAYER | + TYPE_ECS_AGA | + TYPE_KEYTEXT | + TYPE_ENTER_LIST | + TYPE_TEXT_INPUT)) + return FONT_MENU_2; + else + return FONT_MENU_1; +} + +static struct TokenInfo *setup_info; +static struct TokenInfo setup_info_input[]; + +static struct TokenInfo *menu_info; + +static void DrawCursorAndText_Menu_Ext(struct TokenInfo *token_info, + int screen_pos, int menu_info_pos_raw, + boolean active) { + int pos = (menu_info_pos_raw < 0 ? screen_pos : menu_info_pos_raw); + struct TokenInfo *ti = &token_info[pos]; int xpos = MENU_SCREEN_START_XPOS; - int ypos = MENU_SCREEN_START_YPOS + pos; - int font_nr = FONT_MENU_1; + int ypos = MENU_SCREEN_START_YPOS + screen_pos; + int font_nr = getMenuTextFont(ti->type); + + if (setup_mode == SETUP_MODE_INPUT) + font_nr = FONT_MENU_1; if (active) font_nr = FONT_ACTIVE(font_nr); - DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[pos].text, font_nr); + DrawText(mSX + xpos * 32, mSY + ypos * 32, ti->text, font_nr); - if (info_info[pos].type & ~TYPE_SKIP_ENTRY) - drawCursor(pos, active); + if (ti->type & ~TYPE_SKIP_ENTRY) + drawCursor(screen_pos, active); } -static void DrawInfoScreen_Main(int fade_mask, boolean do_fading) +static void DrawCursorAndText_Menu(int screen_pos, int menu_info_pos_raw, + boolean active) { + DrawCursorAndText_Menu_Ext(menu_info, screen_pos, menu_info_pos_raw, active); +} + +static void DrawCursorAndText_Setup(int screen_pos, int menu_info_pos_raw, + boolean active) +{ + DrawCursorAndText_Menu_Ext(setup_info, screen_pos, menu_info_pos_raw, active); +} + +static char *window_size_text; +static char *scaling_type_text; +static char *network_server_text; + +static void drawSetupValue(int, int); + +static void drawMenuInfoList(int first_entry, int num_page_entries, + int max_page_entries) +{ + int i; + + if (first_entry + num_page_entries > max_page_entries) + first_entry = 0; + + clearMenuListArea(); + + for (i = 0; i < num_page_entries; i++) + { + int menu_info_pos = first_entry + i; + struct TokenInfo *si = &menu_info[menu_info_pos]; + void *value_ptr = si->value; + + /* set some entries to "unchangeable" according to other variables */ + if ((value_ptr == &setup.sound_simple && !audio.sound_available) || + (value_ptr == &setup.sound_loops && !audio.loops_available) || + (value_ptr == &setup.sound_music && !audio.music_available) || + (value_ptr == &setup.fullscreen && !video.fullscreen_available) || + (value_ptr == &window_size_text && !video.window_scaling_available) || + (value_ptr == &scaling_type_text && !video.window_scaling_available)) + si->type |= TYPE_GHOSTED; + + if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) + initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); + else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) + initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); + else if (si->type & ~TYPE_SKIP_ENTRY) + initCursor(i, IMG_MENU_BUTTON); + + DrawCursorAndText_Menu(i, menu_info_pos, FALSE); + + if (si->type & TYPE_STRING) + { + int gadget_id = -1; + + if (value_ptr == &network_server_text) + gadget_id = SCREEN_CTRL_ID_NETWORK_SERVER; + + if (gadget_id != -1) + { + struct GadgetInfo *gi = screen_gadget[gadget_id]; + int xpos = MENU_SCREEN_START_XPOS; + int ypos = MENU_SCREEN_START_YPOS + i; + int x = mSX + xpos * 32; + int y = mSY + ypos * 32; + + ModifyGadget(gi, GDI_X, x, GDI_Y, y, GDI_END); + } + } + + if (si->type & TYPE_VALUE && + menu_info == setup_info) + drawSetupValue(i, menu_info_pos); + } +} + +static void DrawInfoScreen_Main(void) +{ + int fade_mask = REDRAW_FIELD; int i; + if (redraw_mask & REDRAW_ALL) + fade_mask = REDRAW_ALL; + + if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) + fade_mask = REDRAW_ALL; + UnmapAllGadgets(); - CloseDoor(DOOR_CLOSE_2); + FadeMenuSoundsAndMusic(); + + FreeScreenGadgets(); + CreateScreenGadgets(); /* (needed after displaying title screens which disable auto repeat) */ KeyboardAutoRepeatOn(); @@ -1954,78 +2340,125 @@ static void DrawInfoScreen_Main(int fade_mask, boolean do_fading) FadeOut(fade_mask); - if (fade_mask == REDRAW_ALL) - { - RedrawBackground(); + /* needed if different viewport properties defined for info screen */ + ChangeViewportPropertiesIfNeeded(); - OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); - } + SetMainBackgroundImage(IMG_BACKGROUND_INFO); ClearField(); + OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); + DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen"); info_info = info_info_main; - num_info_info = 0; - - for (i = 0; info_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++) - { - if (info_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) - initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); - else if (info_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) - initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); - else if (info_info[i].type & ~TYPE_SKIP_ENTRY) - initCursor(i, IMG_MENU_BUTTON); - - DrawCursorAndText_Info(i, FALSE); + // determine maximal number of info entries that can be displayed on screen + num_info_info = 0; + for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) num_info_info++; - } + + // determine maximal number of info entries available for menu of info screen + max_info_info = 0; + for (i = 0; info_info[i].type != 0; i++) + max_info_info++; HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE); - PlayMenuSound(); - PlayMenuMusic(); + MapScreenGadgets(max_info_info); + + PlayMenuSoundsAndMusic(); DrawMaskedBorder(fade_mask); FadeIn(fade_mask); - - InitAnimation(); } -void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button) +static void changeSetupValue(int, int, int); + +static void HandleMenuScreen(int mx, int my, int dx, int dy, int button, + int mode, int num_page_entries, + int max_page_entries) { - static int choice_store[MAX_INFO_MODES]; - int choice = choice_store[info_mode]; /* always starts with 0 */ + static int num_page_entries_all_last[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES]; + static int choice_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES]; + static int first_entry_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES]; + int *num_page_entries_last = num_page_entries_all_last[game_status]; + int *choice_store = choice_stores[game_status]; + int *first_entry_store = first_entry_stores[game_status]; + int choice = choice_store[mode]; /* starts with 0 */ + int first_entry = first_entry_store[mode]; /* starts with 0 */ int x = 0; - int y = choice; + int y = choice - first_entry; + int y_old = y; + boolean position_set_by_scrollbar = (dx == 999); + int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + int i; if (button == MB_MENU_INITIALIZE) { + // check if number of menu page entries has changed (may happen by change + // of custom artwork definition value for 'list_size' for this menu screen) + // (in this case, the last menu position most probably has to be corrected) + if (num_page_entries != num_page_entries_last[mode]) + { + choice_store[mode] = first_entry_store[mode] = 0; + + choice = first_entry = 0; + y = y_old = 0; + + num_page_entries_last[mode] = num_page_entries; + } + /* advance to first valid menu entry */ - while (choice < num_info_info && - info_info[choice].type & TYPE_SKIP_ENTRY) + while (choice < num_page_entries && + menu_info[choice].type & TYPE_SKIP_ENTRY) choice++; - choice_store[info_mode] = choice; - DrawCursorAndText_Info(choice, TRUE); + if (position_set_by_scrollbar) + first_entry = first_entry_store[mode] = dy; + else + AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries, + NUM_MENU_ENTRIES_ON_SCREEN, first_entry); + + drawMenuInfoList(first_entry, num_page_entries, max_page_entries); + + if (choice < first_entry) + { + choice = first_entry; + + if (menu_info[choice].type & TYPE_SKIP_ENTRY) + choice++; + } + else if (choice > first_entry + num_page_entries - 1) + { + choice = first_entry + num_page_entries - 1; + + if (menu_info[choice].type & TYPE_SKIP_ENTRY) + choice--; + } + + choice_store[mode] = choice; + + DrawCursorAndText_Menu(choice - first_entry, choice, TRUE); return; } else if (button == MB_MENU_LEAVE) { - for (y = 0; y < num_info_info; y++) + PlaySound(SND_MENU_ITEM_SELECTING); + + for (i = 0; i < max_page_entries; i++) { - if (info_info[y].type & TYPE_LEAVE_MENU) + if (menu_info[i].type & TYPE_LEAVE_MENU) { - void (*menu_callback_function)(void) = info_info[y].value; + void (*menu_callback_function)(void) = menu_info[i].value; FadeSetLeaveMenu(); menu_callback_function(); - break; /* absolutely needed because function changes 'info_info'! */ + break; /* absolutely needed because function changes 'menu_info'! */ } } @@ -2037,63 +2470,258 @@ void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button) x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; } - else if (dx || dy) /* keyboard input */ + else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */ { + /* move cursor instead of scrolling when already at start/end of list */ + if (dy == -1 * SCROLL_LINE && first_entry == 0) + dy = -1; + else if (dy == +1 * SCROLL_LINE && + first_entry + num_page_entries == max_page_entries) + dy = 1; + + /* handle scrolling screen one line or page */ + if (y + dy < 0 || + y + dy > num_page_entries - 1) + { + boolean redraw = FALSE; + + if (ABS(dy) == SCROLL_PAGE) + step = num_page_entries - 1; + + if (dy < 0 && first_entry > 0) + { + /* scroll page/line up */ + + first_entry -= step; + if (first_entry < 0) + first_entry = 0; + + redraw = TRUE; + } + else if (dy > 0 && first_entry + num_page_entries < max_page_entries) + { + /* scroll page/line down */ + + first_entry += step; + if (first_entry + num_page_entries > max_page_entries) + first_entry = MAX(0, max_page_entries - num_page_entries); + + redraw = TRUE; + } + + if (redraw) + { + choice += first_entry - first_entry_store[mode]; + + if (choice < first_entry) + { + choice = first_entry; + + if (menu_info[choice].type & TYPE_SKIP_ENTRY) + choice++; + } + else if (choice > first_entry + num_page_entries - 1) + { + choice = first_entry + num_page_entries - 1; + + if (menu_info[choice].type & TYPE_SKIP_ENTRY) + choice--; + } + else if (menu_info[choice].type & TYPE_SKIP_ENTRY) + { + choice += SIGN(dy); + + if (choice < first_entry || + choice > first_entry + num_page_entries - 1) + first_entry += SIGN(dy); + } + + first_entry_store[mode] = first_entry; + choice_store[mode] = choice; + + drawMenuInfoList(first_entry, num_page_entries, max_page_entries); + + DrawCursorAndText_Menu(choice - first_entry, choice, TRUE); + + AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries, + NUM_MENU_ENTRIES_ON_SCREEN, first_entry); + } + + return; + } + if (dx) { int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER); - if (info_info[choice].type & menu_navigation_type || - info_info[choice].type & TYPE_ENTER_SCREEN || - info_info[choice].type & TYPE_BOOLEAN_STYLE || - info_info[choice].type & TYPE_YES_NO_AUTO) + if (menu_info[choice].type & menu_navigation_type || + menu_info[choice].type & TYPE_BOOLEAN_STYLE || + menu_info[choice].type & TYPE_YES_NO_AUTO || + menu_info[choice].type & TYPE_PLAYER) button = MB_MENU_CHOICE; } else if (dy) - y = choice + dy; + y += dy; /* jump to next non-empty menu entry (up or down) */ - while (y > 0 && y < num_info_info - 1 && - info_info[y].type & TYPE_SKIP_ENTRY) + while (first_entry + y > 0 && + first_entry + y < max_page_entries - 1 && + menu_info[first_entry + y].type & TYPE_SKIP_ENTRY) y += dy; + + if (!IN_VIS_MENU(x, y)) + { + choice += y - y_old; + + if (choice < first_entry) + first_entry = choice; + else if (choice > first_entry + num_page_entries - 1) + first_entry = choice - num_page_entries + 1; + + if (first_entry >= 0 && + first_entry + num_page_entries <= max_page_entries) + { + first_entry_store[mode] = first_entry; + + if (choice < first_entry) + choice = first_entry; + else if (choice > first_entry + num_page_entries - 1) + choice = first_entry + num_page_entries - 1; + + choice_store[mode] = choice; + + drawMenuInfoList(first_entry, num_page_entries, max_page_entries); + + DrawCursorAndText_Menu(choice - first_entry, choice, TRUE); + + AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries, + NUM_MENU_ENTRIES_ON_SCREEN, first_entry); + } + + return; + } } - if (IN_VIS_MENU(x, y) && - y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY) + if (!anyScrollbarGadgetActive() && + IN_VIS_MENU(x, y) && + mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x && + y >= 0 && y < num_page_entries) { if (button) { - if (y != choice) + if (first_entry + y != choice && + menu_info[first_entry + y].type & ~TYPE_SKIP_ENTRY) { PlaySound(SND_MENU_ITEM_ACTIVATING); - DrawCursorAndText_Info(choice, FALSE); - DrawCursorAndText_Info(y, TRUE); + DrawCursorAndText_Menu(choice - first_entry, choice, FALSE); + DrawCursorAndText_Menu(y, first_entry + y, TRUE); + + choice = choice_store[mode] = first_entry + y; + } + else if (dx < 0) + { + PlaySound(SND_MENU_ITEM_SELECTING); + + for (i = 0; menu_info[i].type != 0; i++) + { + if (menu_info[i].type & TYPE_LEAVE_MENU) + { + void (*menu_callback_function)(void) = menu_info[i].value; + + FadeSetLeaveMenu(); + + menu_callback_function(); + + /* absolutely needed because function changes 'menu_info'! */ + break; + } + } - choice = choice_store[info_mode] = y; + return; } } - else if (!(info_info[y].type & TYPE_GHOSTED)) + else if (!(menu_info[first_entry + y].type & TYPE_GHOSTED)) { PlaySound(SND_MENU_ITEM_SELECTING); - if (info_info[y].type & TYPE_ENTER_OR_LEAVE) + /* when selecting key headline, execute function for key value change */ + if (menu_info[first_entry + y].type & TYPE_KEYTEXT && + menu_info[first_entry + y + 1].type & TYPE_KEY) + y++; + + /* when selecting string value, execute function for list selection */ + if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 && + menu_info[first_entry + y - 1].type & TYPE_ENTER_LIST) + y--; + + /* when selecting string value, execute function for text input gadget */ + if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 && + menu_info[first_entry + y - 1].type & TYPE_TEXT_INPUT) + y--; + + if (menu_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE) { - void (*menu_callback_function)(void) = info_info[choice].value; + void (*menu_callback_function)(void) = + menu_info[first_entry + y].value; - FadeSetFromType(info_info[y].type); + FadeSetFromType(menu_info[first_entry + y].type); menu_callback_function(); } + else if (menu_info[first_entry + y].type & TYPE_TEXT_INPUT) + { + void (*gadget_callback_function)(void) = + menu_info[first_entry + y].value; + + gadget_callback_function(); + } + else if (menu_info[first_entry + y].type & TYPE_VALUE && + menu_info == setup_info) + { + changeSetupValue(y, first_entry + y, dx); + } } } } +void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button) +{ + menu_info = info_info; + + HandleMenuScreen(mx, my, dx, dy, button, + info_mode, num_info_info, max_info_info); +} + +static int getMenuFontSpacing(int spacing_height, int font_nr) +{ + int font_spacing = getFontHeight(font_nr) + EXTRA_SPACING(game_status); + + return (spacing_height < 0 ? ABS(spacing_height) * font_spacing : + spacing_height); +} + +static int getMenuTextSpacing(int spacing_height, int font_nr) +{ + return (getMenuFontSpacing(spacing_height, font_nr) + + EXTRA_SPACING(game_status)); +} + +static int getMenuTextStep(int spacing_height, int font_nr) +{ + return getFontHeight(font_nr) + getMenuTextSpacing(spacing_height, font_nr); +} + void DrawInfoScreen_NotAvailable(char *text_title, char *text_error) { - int ystart1 = mSY - SY + 100; - int ystart2 = mSY - SY + 150; - int ybottom = mSY - SY + SYSIZE - 20; + int font_title = MENU_INFO_FONT_TITLE; + int font_error = FONT_TEXT_2; + int font_foot = MENU_INFO_FONT_FOOT; + int spacing_title = menu.headline1_spacing_info[info_mode]; + int ystep_title = getMenuTextStep(spacing_title, font_title); + int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1; + int ystart2 = ystart1 + ystep_title; + int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO); @@ -2102,10 +2730,10 @@ void DrawInfoScreen_NotAvailable(char *text_title, char *text_error) ClearField(); DrawHeadline(); - DrawTextSCentered(ystart1, FONT_TEXT_1, text_title); - DrawTextSCentered(ystart2, FONT_TEXT_2, text_error); + DrawTextSCentered(ystart1, font_title, text_title); + DrawTextSCentered(ystart2, font_error, text_error); - DrawTextSCentered(ybottom, FONT_TEXT_4, + DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); @@ -2115,7 +2743,9 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init) { static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN]; static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN]; - int xstart = mSX + MENU_SCREEN_INFO_XSTART; + int font_title = MENU_INFO_FONT_TITLE; + int font_foot = MENU_INFO_FONT_FOOT; + int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT; int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; @@ -2134,9 +2764,9 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init) ClearField(); DrawHeadline(); - DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Elements:"); + DrawTextSCentered(ystart1, font_title, "The Game Elements:"); - DrawTextSCentered(ybottom, FONT_TEXT_4, + DrawTextSCentered(ybottom, font_foot, "Press any key or button for next page"); FrameCounter = 0; @@ -2243,11 +2873,14 @@ void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos) { int font_nr = FONT_INFO_ELEMENTS; int font_width = getFontWidth(font_nr); - int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX; - int sy = mSY + 65 + 2 * 32 + 1; + int font_height = getFontHeight(font_nr); + int yoffset = (TILEX - 2 * font_height) / 2; + int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT + TILEX + MINI_TILEX; + int ystart = mSY + MENU_SCREEN_INFO_YSTART2 + yoffset; int ystep = TILEY + 4; - int pad_x = sx - SX; - int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width; + int pad_left = xstart - SX; + int pad_right = MENU_SCREEN_INFO_SPACE_RIGHT; + int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width; int max_lines_per_text = 2; char *text = NULL; @@ -2267,15 +2900,17 @@ void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos) text = "No description available"; if (strlen(text) <= max_chars_per_line) /* only one line of text */ - sy += getFontHeight(font_nr) / 2; + ystart += getFontHeight(font_nr) / 2; - DrawTextBuffer(sx, sy + ypos * ystep, text, font_nr, + DrawTextBuffer(xstart, ystart + ypos * ystep, text, font_nr, max_chars_per_line, -1, max_lines_per_text, 0, -1, TRUE, FALSE, FALSE); } -void DrawInfoScreen_TitleScreen() +static void DrawInfoScreen_TitleScreen(void) { + SetGameStatus(GAME_MODE_TITLE); + DrawTitleScreen(); } @@ -2284,7 +2919,7 @@ void HandleInfoScreen_TitleScreen(int button) HandleTitleScreen(0, 0, 0, 0, button); } -void DrawInfoScreen_Elements() +static void DrawInfoScreen_Elements(void) { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS); @@ -2296,8 +2931,6 @@ void DrawInfoScreen_Elements() HandleInfoScreen_Elements(MB_MENU_INITIALIZE); FadeIn(REDRAW_FIELD); - - InitAnimation(); } void HandleInfoScreen_Elements(int button) @@ -2350,10 +2983,10 @@ void HandleInfoScreen_Elements(int button) if (page >= num_pages) { - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; - DrawAndFadeInInfoScreen(REDRAW_FIELD); + DrawInfoScreen(); return; } @@ -2379,7 +3012,7 @@ void HandleInfoScreen_Elements(int button) } } -void DrawInfoScreen_Music() +static void DrawInfoScreen_Music(void) { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC); @@ -2398,10 +3031,16 @@ void DrawInfoScreen_Music() void HandleInfoScreen_Music(int button) { static struct MusicFileInfo *list = NULL; - int ystart1 = mSY - SY + 100; - int ystart2 = mSY - SY + 150; - int ybottom = mSY - SY + SYSIZE - 20; - int dy = 30; + int font_title = MENU_INFO_FONT_TITLE; + int font_head = MENU_INFO_FONT_HEAD; + int font_text = MENU_INFO_FONT_TEXT; + int font_foot = MENU_INFO_FONT_FOOT; + int spacing_title = menu.headline1_spacing_info[info_mode]; + int spacing_head = menu.headline2_spacing_info[info_mode]; + int ystep_title = getMenuTextStep(spacing_title, font_title); + int ystep_head = getMenuTextStep(spacing_head, font_head); + int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; + int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; if (button == MB_MENU_INITIALIZE) { @@ -2409,15 +3048,15 @@ void HandleInfoScreen_Music(int button) if (list == NULL) { - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); ClearField(); DrawHeadline(); - DrawTextSCentered(ystart1, FONT_TEXT_1, + DrawTextSCentered(ystart, font_title, "No music info for this level set."); - DrawTextSCentered(ybottom, FONT_TEXT_4, + DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); return; @@ -2428,7 +3067,7 @@ void HandleInfoScreen_Music(int button) { PlaySound(SND_MENU_ITEM_SELECTING); - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); @@ -2437,8 +3076,6 @@ void HandleInfoScreen_Music(int button) } else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE) { - int y = 0; - if (button != MB_MENU_INITIALIZE) { PlaySound(SND_MENU_ITEM_SELECTING); @@ -2449,15 +3086,15 @@ void HandleInfoScreen_Music(int button) if (list == NULL) { - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; - DrawAndFadeInInfoScreen(REDRAW_FIELD); + DrawInfoScreen(); return; } - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); if (list != music_file_info) FadeSetNextScreen(); @@ -2477,51 +3114,71 @@ void HandleInfoScreen_Music(int button) else PlaySound(sound); - DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Sounds:"); + DrawTextSCentered(ystart, font_title, "The Game Background Sounds:"); } else { - PlayMusic(list->music); + int music = list->music; - DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Music:"); + if (music_info[music].loop) + PlayMusicLoop(music); + else + PlayMusic(music); + + DrawTextSCentered(ystart, font_title, "The Game Background Music:"); } + ystart += ystep_title; + if (!strEqual(list->title, UNKNOWN_NAME)) { if (!strEqual(list->title_header, UNKNOWN_NAME)) - DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->title_header); + { + DrawTextSCentered(ystart, font_head, list->title_header); + ystart += ystep_head; + } - DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title); + DrawTextFCentered(ystart, font_text, "\"%s\"", list->title); + ystart += ystep_head; } if (!strEqual(list->artist, UNKNOWN_NAME)) { if (!strEqual(list->artist_header, UNKNOWN_NAME)) - DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->artist_header); + DrawTextSCentered(ystart, font_head, list->artist_header); else - DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "by"); + DrawTextSCentered(ystart, font_head, "by"); + + ystart += ystep_head; - DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->artist); + DrawTextFCentered(ystart, font_text, "%s", list->artist); + ystart += ystep_head; } if (!strEqual(list->album, UNKNOWN_NAME)) { if (!strEqual(list->album_header, UNKNOWN_NAME)) - DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->album_header); + DrawTextSCentered(ystart, font_head, list->album_header); else - DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the album"); + DrawTextSCentered(ystart, font_head, "from the album"); - DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album); + ystart += ystep_head; + + DrawTextFCentered(ystart, font_text, "\"%s\"", list->album); + ystart += ystep_head; } if (!strEqual(list->year, UNKNOWN_NAME)) { if (!strEqual(list->year_header, UNKNOWN_NAME)) - DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->year_header); + DrawTextSCentered(ystart, font_head, list->year_header); else - DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the year"); + DrawTextSCentered(ystart, font_head, "from the year"); + + ystart += ystep_head; - DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->year); + DrawTextFCentered(ystart, font_text, "%s", list->year); + ystart += ystep_head; } DrawTextSCentered(ybottom, FONT_TEXT_4, @@ -2537,182 +3194,240 @@ void HandleInfoScreen_Music(int button) static void DrawInfoScreen_CreditsScreen(int screen_nr) { - int ystart1 = mSY - SY + 100; - int ystart2 = mSY - SY + 150; - int ybottom = mSY - SY + SYSIZE - 20; - int ystep = 30; + int font_title = MENU_INFO_FONT_TITLE; + int font_head = MENU_INFO_FONT_HEAD; + int font_text = MENU_INFO_FONT_TEXT; + int font_foot = MENU_INFO_FONT_FOOT; + int spacing_title = menu.headline1_spacing_info[info_mode]; + int spacing_head = menu.headline2_spacing_info[info_mode]; + int spacing_para = menu.paragraph_spacing_info[info_mode]; + int spacing_line = menu.line_spacing_info[info_mode]; + int ystep_title = getMenuTextStep(spacing_title, font_title); + int ystep_head = getMenuTextStep(spacing_head, font_head); + int ystep_para = getMenuTextStep(spacing_para, font_text); + int ystep_line = getMenuTextStep(spacing_line, font_text); + int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; + int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; ClearField(); DrawHeadline(); - DrawTextSCentered(ystart1, FONT_TEXT_1, "Credits:"); + DrawTextSCentered(ystart, font_title, "Credits:"); + ystart += ystep_title; if (screen_nr == 0) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Special thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Peter Liepa"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for creating"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "\"Boulder Dash\""); - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "in the year"); - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "1984"); - DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "published by"); - DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "First Star Software"); } else if (screen_nr == 1) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Special thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Klaus Heinz & Volker Wertich"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for creating"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "\"Emerald Mine\""); - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "in the year"); - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "1987"); - DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "published by"); - DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Kingsoft"); } else if (screen_nr == 2) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Special thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Michael Stopp & Philip Jespersen"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for creating"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "\"Supaplex\""); - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "in the year"); - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "1991"); - DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "published by"); - DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Digital Integration"); } else if (screen_nr == 3) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Special thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Hiroyuki Imabayashi"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for creating"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "\"Sokoban\""); - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "in the year"); - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "1982"); - DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "published by"); - DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Thinking Rabbit"); } else if (screen_nr == 4) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Special thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Alan Bond"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "and"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "J\xfcrgen Bonhagen"); - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for the continuous creation"); - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2, + ystart += ystep_line; + DrawTextSCentered(ystart, font_head, "of outstanding level sets"); } else if (screen_nr == 5) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Peter Elzner"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for ideas and inspiration by"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Diamond Caves"); + ystart += ystep_para; - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Thanks to"); - DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Steffest"); - DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for ideas and inspiration by"); - DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "DX-Boulderdash"); } else if (screen_nr == 6) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "David Tritscher"); -#if 1 - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for the code base used for the"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_2, + ystart += ystep_line; + DrawTextSCentered(ystart, font_head, "native Emerald Mine engine"); -#else - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, - "for the new Emerald Mine engine"); -#endif } else if (screen_nr == 7) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Thanks to"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Guido Schulz"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for the initial DOS port"); + ystart += ystep_para; - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "Thanks to"); - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "Karl H\xf6rnell"); - DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "for some additional toons"); } else if (screen_nr == 8) { - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "And not to forget:"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "Many thanks to"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, "All those who contributed"); - DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3, + ystart += ystep_line; + DrawTextSCentered(ystart, font_text, "levels to this game"); - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_3, + ystart += ystep_line; + DrawTextSCentered(ystart, font_text, "since 1995"); } - DrawTextSCentered(ybottom, FONT_TEXT_4, + DrawTextSCentered(ybottom, font_foot, "Press any key or button for next page"); } -void DrawInfoScreen_Credits() +static void DrawInfoScreen_Credits(void) { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS); - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); FadeOut(REDRAW_FIELD); @@ -2753,10 +3468,10 @@ void HandleInfoScreen_Credits(int button) if (screen_nr >= num_screens) { - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; - DrawAndFadeInInfoScreen(REDRAW_FIELD); + DrawInfoScreen(); return; } @@ -2778,12 +3493,22 @@ void HandleInfoScreen_Credits(int button) } } -void DrawInfoScreen_Program() +static void DrawInfoScreen_Program(void) { - int ystart1 = mSY - SY + 100; - int ystart2 = mSY - SY + 150; - int ybottom = mSY - SY + SYSIZE - 20; - int ystep = 30; + int font_title = MENU_INFO_FONT_TITLE; + int font_head = MENU_INFO_FONT_HEAD; + int font_text = MENU_INFO_FONT_TEXT; + int font_foot = MENU_INFO_FONT_FOOT; + int spacing_title = menu.headline1_spacing_info[info_mode]; + int spacing_head = menu.headline2_spacing_info[info_mode]; + int spacing_para = menu.paragraph_spacing_info[info_mode]; + int spacing_line = menu.line_spacing_info[info_mode]; + int ystep_title = getMenuTextStep(spacing_title, font_title); + int ystep_head = getMenuTextStep(spacing_head, font_head); + int ystep_para = getMenuTextStep(spacing_para, font_text); + int ystep_line = getMenuTextStep(spacing_line, font_text); + int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; + int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM); @@ -2792,26 +3517,36 @@ void DrawInfoScreen_Program() ClearField(); DrawHeadline(); - DrawTextSCentered(ystart1, FONT_TEXT_1, "Program Information:"); + DrawTextSCentered(ystart, font_title, "Program Information:"); + ystart += ystep_title; - DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart, font_head, "This game is Freeware!"); - DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, "If you like it, send e-mail to:"); - DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3, - PROGRAM_EMAIL_STRING); - DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, + setup.internal.program_email); + ystart += ystep_para; + + DrawTextSCentered(ystart, font_head, "More information and levels:"); - DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3, - PROGRAM_WEBSITE_STRING); - DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_text, + setup.internal.program_website); + ystart += ystep_para; + + DrawTextSCentered(ystart, font_head, "If you have created new levels,"); - DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_2, + ystart += ystep_line; + DrawTextSCentered(ystart, font_head, "send them to me to include them!"); - DrawTextSCentered(ystart2 + 9 * ystep, FONT_TEXT_2, + ystart += ystep_head; + DrawTextSCentered(ystart, font_head, ":-)"); - DrawTextSCentered(ybottom, FONT_TEXT_4, + DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); @@ -2832,10 +3567,10 @@ void HandleInfoScreen_Program(int button) { PlaySound(SND_MENU_ITEM_SELECTING); - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; - DrawAndFadeInInfoScreen(REDRAW_FIELD); + DrawInfoScreen(); } else { @@ -2843,15 +3578,23 @@ void HandleInfoScreen_Program(int button) } } -void DrawInfoScreen_Version() +static void DrawInfoScreen_Version(void) { - int font_header = FONT_TEXT_3; - int font_text = FONT_TEXT_2; + int font_title = MENU_INFO_FONT_TITLE; + int font_head = MENU_INFO_FONT_HEAD; + int font_text = MENU_INFO_FONT_TEXT; + int font_foot = MENU_INFO_FONT_FOOT; + int spacing_title = menu.headline1_spacing_info[info_mode]; + int spacing_head = menu.headline2_spacing_info[info_mode]; + int spacing_para = menu.paragraph_spacing_info[info_mode]; + int spacing_line = menu.line_spacing_info[info_mode]; int xstep = getFontWidth(font_text); - int ystep = getFontHeight(font_text); - int ystart1 = mSY - SY + 100; - int ystart2 = mSY - SY + 150; - int ybottom = mSY - SY + SYSIZE - 20; + int ystep_title = getMenuTextStep(spacing_title, font_title); + int ystep_head = getMenuTextStep(spacing_head, font_head); + int ystep_para = getMenuTextStep(spacing_para, font_text); + int ystep_line = getMenuTextStep(spacing_line, font_text); + int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; + int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; int xstart1 = mSX - SX + 2 * xstep; int xstart2 = mSX - SX + 18 * xstep; int xstart3 = mSX - SX + 28 * xstep; @@ -2872,31 +3615,46 @@ void DrawInfoScreen_Version() ClearField(); DrawHeadline(); - DrawTextSCentered(ystart1, FONT_TEXT_1, "Version Information:"); + DrawTextSCentered(ystart, font_title, "Version Information:"); + ystart += ystep_title; - DrawTextF(xstart1, ystart2, font_header, "Name"); - DrawTextF(xstart2, ystart2, font_text, PROGRAM_TITLE_STRING); + DrawTextF(xstart1, ystart, font_head, "Name"); + DrawTextF(xstart2, ystart, font_text, getProgramTitleString()); + ystart += ystep_line; + + if (!strEqual(getProgramVersionString(), getProgramRealVersionString())) + { + DrawTextF(xstart1, ystart, font_head, "Version (fake)"); + DrawTextF(xstart2, ystart, font_text, getProgramVersionString()); + ystart += ystep_line; - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_header, "Version"); - DrawTextF(xstart2, ystart2, font_text, getProgramVersionString()); + DrawTextF(xstart1, ystart, font_head, "Version (real)"); + DrawTextF(xstart2, ystart, font_text, getProgramRealVersionString()); + ystart += ystep_line; + } + else + { + DrawTextF(xstart1, ystart, font_head, "Version"); + DrawTextF(xstart2, ystart, font_text, getProgramVersionString()); + ystart += ystep_line; + } - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_header, "Platform"); - DrawTextF(xstart2, ystart2, font_text, PLATFORM_STRING); + DrawTextF(xstart1, ystart, font_head, "Platform"); + DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING); + ystart += ystep_line; - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_header, "Target"); - DrawTextF(xstart2, ystart2, font_text, TARGET_STRING); + DrawTextF(xstart1, ystart, font_head, "Target"); + DrawTextF(xstart2, ystart, font_text, TARGET_STRING); + ystart += ystep_line; - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_header, "Compile time"); - DrawTextF(xstart2, ystart2, font_text, getCompileDateString()); + DrawTextF(xstart1, ystart, font_head, "Source date"); + DrawTextF(xstart2, ystart, font_text, getSourceDateString()); + ystart += ystep_para; - ystart2 += 3 * ystep; - DrawTextF(xstart1, ystart2, font_header, "Library"); - DrawTextF(xstart2, ystart2, font_header, "compiled"); - DrawTextF(xstart3, ystart2, font_header, "linked"); + DrawTextF(xstart1, ystart, font_head, "Library"); + DrawTextF(xstart2, ystart, font_head, "compiled"); + DrawTextF(xstart3, ystart, font_head, "linked"); + ystart += ystep_head; SDL_VERSION(&sdl_version_compiled); #if defined(TARGET_SDL2) @@ -2906,63 +3664,63 @@ void DrawInfoScreen_Version() sdl_version_linked = SDL_Linked_Version(); #endif - ystart2 += 2 * ystep; - DrawTextF(xstart1, ystart2, font_text, "SDL"); - DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart1, ystart, font_text, "SDL"); + DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); - DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); + ystart += ystep_line; SDL_IMAGE_VERSION(&sdl_version_compiled); sdl_version_linked = IMG_Linked_Version(); - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_text, "SDL_image"); - DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart1, ystart, font_text, "SDL_image"); + DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); - DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); + ystart += ystep_line; SDL_MIXER_VERSION(&sdl_version_compiled); sdl_version_linked = Mix_Linked_Version(); - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_text, "SDL_mixer"); - DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart1, ystart, font_text, "SDL_mixer"); + DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); - DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); + ystart += ystep_line; SDL_NET_VERSION(&sdl_version_compiled); sdl_version_linked = SDLNet_Linked_Version(); - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_text, "SDL_net"); - DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart1, ystart, font_text, "SDL_net"); + DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); - DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d", + DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); + ystart += ystep_para; - ystart2 += 3 * ystep; - DrawTextF(xstart1, ystart2, font_header, "Driver"); - DrawTextF(xstart2, ystart2, font_header, "Requested"); - DrawTextF(xstart3, ystart2, font_header, "Used"); + DrawTextF(xstart1, ystart, font_head, "Driver"); + DrawTextF(xstart2, ystart, font_head, "Requested"); + DrawTextF(xstart3, ystart, font_head, "Used"); + ystart += ystep_head; #if defined(TARGET_SDL2) driver_name = getStringCopyNStatic(SDL_GetVideoDriver(0), driver_name_len); @@ -2970,10 +3728,10 @@ void DrawInfoScreen_Version() SDL_VideoDriverName(driver_name, driver_name_len); #endif - ystart2 += 2 * ystep; - DrawTextF(xstart1, ystart2, font_text, "SDL_VideoDriver"); - DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_videodriver); - DrawTextF(xstart3, ystart2, font_text, "%s", driver_name); + DrawTextF(xstart1, ystart, font_text, "SDL_VideoDriver"); + DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_videodriver); + DrawTextF(xstart3, ystart, font_text, "%s", driver_name); + ystart += ystep_line; #if defined(TARGET_SDL2) driver_name = getStringCopyNStatic(SDL_GetAudioDriver(0), driver_name_len); @@ -2981,12 +3739,11 @@ void DrawInfoScreen_Version() SDL_AudioDriverName(driver_name, driver_name_len); #endif - ystart2 += ystep; - DrawTextF(xstart1, ystart2, font_text, "SDL_AudioDriver"); - DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_audiodriver); - DrawTextF(xstart3, ystart2, font_text, "%s", driver_name); + DrawTextF(xstart1, ystart, font_text, "SDL_AudioDriver"); + DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_audiodriver); + DrawTextF(xstart3, ystart, font_text, "%s", driver_name); - DrawTextSCentered(ybottom, FONT_TEXT_4, + DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); @@ -3007,10 +3764,10 @@ void HandleInfoScreen_Version(int button) { PlaySound(SND_MENU_ITEM_SELECTING); - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; - DrawAndFadeInInfoScreen(REDRAW_FIELD); + DrawInfoScreen(); } else { @@ -3018,13 +3775,13 @@ void HandleInfoScreen_Version(int button) } } -void DrawInfoScreen_LevelSet() +static void DrawInfoScreen_LevelSet(void) { struct TitleMessageInfo *tmi = &readme; char *filename = getLevelSetInfoFilename(); char *title = "Level Set Information:"; - int ystart1 = mSY - SY + 100; - int ybottom = mSY - SY + SYSIZE - 20; + int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; + int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; if (filename == NULL) { @@ -3040,7 +3797,7 @@ void DrawInfoScreen_LevelSet() ClearField(); DrawHeadline(); - DrawTextSCentered(ystart1, FONT_TEXT_1, title); + DrawTextSCentered(ystart, FONT_TEXT_1, title); /* if x position set to "-1", automatically determine by playfield width */ if (tmi->x == -1) @@ -3056,7 +3813,7 @@ void DrawInfoScreen_LevelSet() /* if height set to "-1", automatically determine by playfield height */ if (tmi->height == -1) - tmi->height = SYSIZE - 20 - tmi->y - 10; + tmi->height = MENU_SCREEN_INFO_YBOTTOM - tmi->y - 10; /* if chars set to "-1", automatically determine by text and font width */ if (tmi->chars == -1) @@ -3080,7 +3837,7 @@ void DrawInfoScreen_LevelSet() FadeIn(REDRAW_FIELD); } -void HandleInfoScreen_LevelSet(int button) +static void HandleInfoScreen_LevelSet(int button) { if (button == MB_MENU_LEAVE) { @@ -3095,10 +3852,10 @@ void HandleInfoScreen_LevelSet(int button) { PlaySound(SND_MENU_ITEM_SELECTING); - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; - DrawAndFadeInInfoScreen(REDRAW_FIELD); + DrawInfoScreen(); } else { @@ -3106,10 +3863,8 @@ void HandleInfoScreen_LevelSet(int button) } } -static void DrawInfoScreenExt(int fade_mask, boolean do_fading) +static void DrawInfoScreen(void) { - SetMainBackgroundImage(IMG_BACKGROUND_INFO); - if (info_mode == INFO_MODE_TITLE) DrawInfoScreen_TitleScreen(); else if (info_mode == INFO_MODE_ELEMENTS) @@ -3125,25 +3880,12 @@ static void DrawInfoScreenExt(int fade_mask, boolean do_fading) else if (info_mode == INFO_MODE_LEVELSET) DrawInfoScreen_LevelSet(); else - DrawInfoScreen_Main(fade_mask, do_fading); + DrawInfoScreen_Main(); if (info_mode != INFO_MODE_MAIN && info_mode != INFO_MODE_TITLE && info_mode != INFO_MODE_MUSIC) - { - PlayMenuSound(); - PlayMenuMusic(); - } -} - -void DrawAndFadeInInfoScreen(int fade_mask) -{ - DrawInfoScreenExt(fade_mask, TRUE); -} - -void DrawInfoScreen() -{ - DrawInfoScreenExt(REDRAW_FIELD, FALSE); + PlayMenuSoundsAndMusic(); } void HandleInfoScreen(int mx, int my, int dx, int dy, int button) @@ -3194,9 +3936,7 @@ void HandleTypeName(int newxpos, Key key) xpos = newxpos; -#if defined(TARGET_SDL2) - SDL_StartTextInput(); -#endif + StartTextInput(startx, starty, pos->width, pos->height); } else if (is_valid_key_char && xpos < MAX_PLAYER_NAME_LEN) { @@ -3217,7 +3957,7 @@ void HandleTypeName(int newxpos, Key key) is_active = FALSE; - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); } else if (key == KSYM_Escape) { @@ -3225,7 +3965,7 @@ void HandleTypeName(int newxpos, Key key) is_active = FALSE; - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); } if (is_active) @@ -3243,9 +3983,7 @@ void HandleTypeName(int newxpos, Key key) DrawText(startx, starty, setup.player_name, font_nr); -#if defined(TARGET_SDL2) - SDL_StopTextInput(); -#endif + StopTextInput(); } } @@ -3256,57 +3994,45 @@ void HandleTypeName(int newxpos, Key key) static void DrawChooseTree(TreeInfo **ti_ptr) { - int fade_mask = (DrawingAreaChanged() ? REDRAW_ALL : REDRAW_FIELD); - - UnmapAllGadgets(); + int fade_mask = REDRAW_FIELD; - FreeScreenGadgets(); - CreateScreenGadgets(); + if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) + fade_mask = REDRAW_ALL; - CloseDoor(DOOR_CLOSE_2); + if (strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY)) + { + SetGameStatus(GAME_MODE_MAIN); - FadeOut(fade_mask); + DrawMainMenu(); - ClearField(); + return; + } - HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr); - MapScreenTreeGadgets(*ti_ptr); + UnmapAllGadgets(); - FadeIn(fade_mask); + FreeScreenGadgets(); + CreateScreenGadgets(); - InitAnimation(); -} + FadeOut(fade_mask); -static void AdjustScrollbar(int id, int items_max, int items_visible, - int item_position) -{ - struct GadgetInfo *gi = screen_gadget[id]; + /* needed if different viewport properties defined for choosing level (set) */ + ChangeViewportPropertiesIfNeeded(); - if (item_position > items_max - items_visible) - item_position = items_max - items_visible; + if (game_status == GAME_MODE_LEVELNR) + SetMainBackgroundImage(IMG_BACKGROUND_LEVELNR); + else if (game_status == GAME_MODE_LEVELS) + SetMainBackgroundImage(IMG_BACKGROUND_LEVELS); - ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, - GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, - GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); -} + ClearField(); -static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti) -{ - AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN, - first_entry); -} + OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); -static void clearMenuListArea() -{ - int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset; + HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr); + MapScreenTreeGadgets(*ti_ptr); - /* correct scrollbar position if placed outside menu (playfield) area */ - if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS) - scrollbar_xpos = SX + SC_SCROLLBAR_XPOS; + DrawMaskedBorder(fade_mask); - /* clear menu list area, but not title or scrollbar */ - DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32, - scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32); + FadeIn(fade_mask); } static void drawChooseTreeList(int first_entry, int num_page_entries, @@ -3318,7 +4044,6 @@ static void drawChooseTreeList(int first_entry, int num_page_entries, int yoffset_setup = 16; int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR || ti->type == TREE_TYPE_LEVEL_NR ? yoffset_sets : yoffset_setup); - int last_game_status = game_status; /* save current game status */ title_string = ti->infotext; @@ -3358,8 +4083,6 @@ static void drawChooseTreeList(int first_entry, int num_page_entries, initCursor(i, IMG_MENU_BUTTON); } - game_status = last_game_status; /* restore current game status */ - redraw_mask |= REDRAW_FIELD; } @@ -3393,7 +4116,7 @@ static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti) node->class_desc); /* let BackToFront() redraw only what is needed */ - redraw_mask = last_redraw_mask | REDRAW_TILES; + redraw_mask = last_redraw_mask; for (x = 0; x < SCR_FIELDX; x++) MarkTileDirty(x, 1); } @@ -3407,7 +4130,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, int step = (button == 1 ? 1 : button == 2 ? 5 : 10); int num_entries = numTreeInfoInGroup(ti); int num_page_entries; - int last_game_status = game_status; /* save current game status */ boolean position_set_by_scrollbar = (dx == 999); if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN) @@ -3415,8 +4137,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, else num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; - game_status = last_game_status; /* restore current game status */ - if (button == MB_MENU_INITIALIZE) { int num_entries = numTreeInfoInGroup(ti); @@ -3463,11 +4183,13 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, else if (game_status == GAME_MODE_SETUP) { if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED || - setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) + setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY || + setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) execSetupGame(); - else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE || - setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || - setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE) + else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || + setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE || + setup_mode == SETUP_MODE_CHOOSE_RENDERING || + setup_mode == SETUP_MODE_CHOOSE_VSYNC) execSetupGraphics(); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE || setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS || @@ -3475,7 +4197,12 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, execSetupSound(); else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL || setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE || - setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) + setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE || + setup_mode == SETUP_MODE_CHOOSE_TRANSPARENCY || + setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_0 || + setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_0 || + setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_1 || + setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_1) execSetupTouch(); else execSetupArtwork(); @@ -3489,9 +4216,9 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, HandleMainMenu_SelectLevel(0, 0, new_level_nr); } - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); - DrawMainMenuExt(REDRAW_FIELD, FALSE); + DrawMainMenu(); } return; @@ -3499,12 +4226,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, if (mx || my) /* mouse input */ { - int last_game_status = game_status; /* save current game status */ - x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; - - game_status = last_game_status; /* restore current game status */ } else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */ { @@ -3555,7 +4278,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, ti->cl_first, ti); } - return; } @@ -3614,6 +4336,36 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, ti->cl_cursor = y; } + else if (dx < 0) + { + if (game_status == GAME_MODE_SETUP) + { + if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED || + setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY || + setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) + execSetupGame(); + else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || + setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE || + setup_mode == SETUP_MODE_CHOOSE_RENDERING || + setup_mode == SETUP_MODE_CHOOSE_VSYNC) + execSetupGraphics(); + else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE || + setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS || + setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC) + execSetupSound(); + else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL || + setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE || + setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE || + setup_mode == SETUP_MODE_CHOOSE_TRANSPARENCY || + setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_0 || + setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_0 || + setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_1 || + setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_1) + execSetupTouch(); + else + execSetupArtwork(); + } + } } else { @@ -3661,11 +4413,13 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, if (game_status == GAME_MODE_SETUP) { if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED || - setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) + setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY || + setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) execSetupGame(); - else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE || - setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || - setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE) + else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || + setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE || + setup_mode == SETUP_MODE_CHOOSE_RENDERING || + setup_mode == SETUP_MODE_CHOOSE_VSYNC) execSetupGraphics(); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE || setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS || @@ -3673,7 +4427,12 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, execSetupSound(); else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL || setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE || - setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) + setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE || + setup_mode == SETUP_MODE_CHOOSE_TRANSPARENCY || + setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_0 || + setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_0 || + setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_1 || + setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_1) execSetupTouch(); else execSetupArtwork(); @@ -3687,7 +4446,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, HandleMainMenu_SelectLevel(0, 0, new_level_nr); } - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } @@ -3696,14 +4455,13 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, } } -void DrawChooseLevelSet() +void DrawChooseLevelSet(void) { - SetMainBackgroundImage(IMG_BACKGROUND_LEVELS); + FadeMenuSoundsAndMusic(); DrawChooseTree(&leveldir_current); - PlayMenuSound(); - PlayMenuMusic(); + PlayMenuSoundsAndMusic(); } void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button) @@ -3711,10 +4469,12 @@ void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button) HandleChooseTree(mx, my, dx, dy, button, &leveldir_current); } -void DrawChooseLevelNr() +void DrawChooseLevelNr(void) { int i; + FadeMenuSoundsAndMusic(); + if (level_number != NULL) { freeTreeInfo(level_number); @@ -3733,13 +4493,13 @@ void DrawChooseLevelNr() ti->node_top = &level_number; ti->sort_priority = 10000 + value; - ti->color = (level.no_valid_file ? FC_BLUE : + ti->color = (level.no_level_file ? FC_BLUE : LevelStats_getSolved(i) ? FC_GREEN : LevelStats_getPlayed(i) ? FC_YELLOW : FC_RED); - sprintf(identifier, "%d", value); - sprintf(name, "%03d: %s", value, - (level.no_valid_file ? "(no file)" : level.name)); + snprintf(identifier, sizeof(identifier), "%d", value); + snprintf(name, sizeof(name), "%03d: %s", value, + (level.no_level_file ? "(no file)" : level.name)); setString(&ti->identifier, identifier); setString(&ti->name, name); @@ -3759,12 +4519,9 @@ void DrawChooseLevelNr() if (level_number_current == NULL) level_number_current = level_number; - SetMainBackgroundImage(IMG_BACKGROUND_LEVELNR); - DrawChooseTree(&level_number_current); - PlayMenuSound(); - PlayMenuMusic(); + PlayMenuSoundsAndMusic(); } void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button) @@ -3772,41 +4529,48 @@ void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button) HandleChooseTree(mx, my, dx, dy, button, &level_number_current); } -void DrawHallOfFame(int highlight_position) +void DrawHallOfFame(int level_nr, int highlight_position) { - int fade_mask = (DrawingAreaChanged() ? REDRAW_ALL : REDRAW_FIELD); + int fade_mask = REDRAW_FIELD; + + if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) + fade_mask = REDRAW_ALL; UnmapAllGadgets(); - FadeSoundsAndMusic(); + FadeMenuSoundsAndMusic(); /* (this is needed when called from GameEnd() after winning a game) */ KeyboardAutoRepeatOn(); - ActivateJoystick(); /* (this is needed when called from GameEnd() after winning a game) */ SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); - CloseDoor(DOOR_CLOSE_2); - if (highlight_position < 0) LoadScore(level_nr); + else + SetAnimStatus(GAME_MODE_PSEUDO_SCORESNEW); FadeSetEnterScreen(); FadeOut(fade_mask); - InitAnimation(); + /* needed if different viewport properties defined for scores */ + ChangeViewportPropertiesIfNeeded(); + + PlayMenuSoundsAndMusic(); + + OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); - PlayMenuSound(); - PlayMenuMusic(); + HandleHallOfFame(level_nr, highlight_position, 0, 0, MB_MENU_INITIALIZE); - HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE); + DrawMaskedBorder(fade_mask); FadeIn(fade_mask); } -static void drawHallOfFameList(int first_entry, int highlight_position) +static void drawHallOfFameList(int level_nr, int first_entry, + int highlight_position) { int i, j; @@ -3825,9 +4589,10 @@ static void drawHallOfFameList(int first_entry, int highlight_position) int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2); int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3); int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4); + int dxoff = getFontDrawOffsetX(font_nr1); int dx1 = 3 * getFontWidth(font_nr1); int dx2 = dx1 + getFontWidth(font_nr1); - int dx3 = SXSIZE - 2 * (mSX - SX) - 5 * getFontWidth(font_nr4); + int dx3 = SXSIZE - 2 * (mSX - SX + dxoff) - 5 * getFontWidth(font_nr4); int num_dots = (dx3 - dx2) / getFontWidth(font_nr3); int sy = mSY + 64 + i * 32; @@ -3848,15 +4613,18 @@ static void drawHallOfFameList(int first_entry, int highlight_position) void HandleHallOfFame(int mx, int my, int dx, int dy, int button) { + static int level_nr = 0; static int first_entry = 0; static int highlight_position = 0; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); if (button == MB_MENU_INITIALIZE) { + level_nr = mx; first_entry = 0; - highlight_position = mx; - drawHallOfFameList(first_entry, highlight_position); + highlight_position = my; + + drawHallOfFameList(level_nr, first_entry, highlight_position); return; } @@ -3872,7 +4640,7 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button) if (first_entry < 0) first_entry = 0; - drawHallOfFameList(first_entry, highlight_position); + drawHallOfFameList(level_nr, first_entry, highlight_position); } } else if (dy > 0) @@ -3883,28 +4651,28 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button) if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES) first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN); - drawHallOfFameList(first_entry, highlight_position); + drawHallOfFameList(level_nr, first_entry, highlight_position); } } - else if (button == MB_MENU_LEAVE) - { - PlaySound(SND_MENU_ITEM_SELECTING); - - FadeSound(SND_BACKGROUND_SCORES); - - game_status = GAME_MODE_MAIN; - - DrawMainMenu(); - } - else if (button == MB_MENU_CHOICE) + else if (button == MB_MENU_LEAVE || button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSound(SND_BACKGROUND_SCORES); - game_status = GAME_MODE_MAIN; + if (game_status_last_screen == GAME_MODE_PLAYING && + setup.auto_play_next_level && setup.increment_levels && + level_nr < leveldir_current->last_level && + !network_playing) + { + StartGameActions(network.enabled, setup.autorecord, level.random_seed); + } + else + { + SetGameStatus(GAME_MODE_MAIN); - DrawAndFadeInMainMenu(REDRAW_FIELD); + DrawMainMenu(); + } } if (game_status == GAME_MODE_SCORES) @@ -3920,11 +4688,14 @@ static struct TokenInfo *setup_info; static int num_setup_info; /* number of setup entries shown on screen */ static int max_setup_info; /* total number of setup entries in list */ -static char *screen_mode_text; static char *window_size_text; static char *scaling_type_text; +static char *rendering_mode_text; +static char *vsync_mode_text; static char *scroll_delay_text; +static char *snapshot_mode_text; static char *game_speed_text; +static char *network_server_text; static char *graphics_set_name; static char *sounds_set_name; static char *music_set_name; @@ -3934,16 +4705,29 @@ static char *volume_music_text; static char *touch_controls_text; static char *move_distance_text; static char *drop_distance_text; +static char *transparency_text; +static char *grid_size_text[2][2]; -static void execSetupMain() +static void execSetupMain(void) { setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } -static void execSetupGame_setGameSpeeds() +static void execSetupGame_setGameSpeeds(boolean update_value) { + if (setup.game_speed_extended) + { + game_speeds_list = game_speeds_list_extended; + game_speeds = game_speeds_extended; + } + else + { + game_speeds_list = game_speeds_list_normal; + game_speeds = game_speeds_normal; + } + if (game_speeds == NULL) { int i; @@ -3964,7 +4748,7 @@ static void execSetupGame_setGameSpeeds() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Game Speed"); + setString(&ti->infotext, STR_SETUP_CHOOSE_GAME_SPEED); pushTreeInfo(&game_speeds, ti); } @@ -3972,6 +4756,11 @@ static void execSetupGame_setGameSpeeds() /* sort game speed values to start with slowest game speed */ sortTreeInfo(&game_speeds); + update_value = TRUE; + } + + if (update_value) + { /* set current game speed to configured game speed value */ game_speed_current = getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay)); @@ -3984,6 +4773,11 @@ static void execSetupGame_setGameSpeeds() /* if that also fails, set current game speed to first available speed */ if (game_speed_current == NULL) game_speed_current = game_speeds; + + if (setup.game_speed_extended) + game_speeds_extended = game_speeds; + else + game_speeds_normal = game_speeds; } setup.game_frame_delay = atoi(game_speed_current->identifier); @@ -3992,7 +4786,7 @@ static void execSetupGame_setGameSpeeds() game_speed_text = game_speed_current->name; } -static void execSetupGame_setScrollDelays() +static void execSetupGame_setScrollDelays(void) { if (scroll_delays == NULL) { @@ -4014,59 +4808,142 @@ static void execSetupGame_setScrollDelays() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Scaling Type"); + setString(&ti->infotext, STR_SETUP_CHOOSE_SCROLL_DELAY); pushTreeInfo(&scroll_delays, ti); } - /* sort scaling type values to start with lowest scaling type value */ + /* sort scroll delay values to start with lowest scroll delay value */ sortTreeInfo(&scroll_delays); - /* set current scaling type value to configured scaling type value */ + /* set current scroll delay value to configured scroll delay value */ scroll_delay_current = getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value)); - /* if that fails, set current scaling type to reliable default value */ + /* if that fails, set current scroll delay to reliable default value */ if (scroll_delay_current == NULL) scroll_delay_current = getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY)); - /* if that also fails, set current scaling type to first available value */ + /* if that also fails, set current scroll delay to first available value */ if (scroll_delay_current == NULL) scroll_delay_current = scroll_delays; } setup.scroll_delay_value = atoi(scroll_delay_current->identifier); - /* needed for displaying scaling type text instead of identifier */ + /* needed for displaying scroll delay text instead of identifier */ scroll_delay_text = scroll_delay_current->name; } -static void execSetupGame() +static void execSetupGame_setSnapshotModes(void) { - execSetupGame_setGameSpeeds(); + if (snapshot_modes == NULL) + { + int i; + + for (i = 0; snapshot_modes_list[i].value != NULL; i++) + { + TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); + char identifier[32], name[32]; + char *value = snapshot_modes_list[i].value; + char *text = snapshot_modes_list[i].text; + + ti->node_top = &snapshot_modes; + ti->sort_priority = i; + + sprintf(identifier, "%s", value); + sprintf(name, "%s", text); + + setString(&ti->identifier, identifier); + setString(&ti->name, name); + setString(&ti->name_sorting, name); + setString(&ti->infotext, STR_SETUP_CHOOSE_SNAPSHOT_MODE); + + pushTreeInfo(&snapshot_modes, ti); + } + + /* sort snapshot mode values to start with lowest snapshot mode value */ + sortTreeInfo(&snapshot_modes); + + /* set current snapshot mode value to configured snapshot mode value */ + snapshot_mode_current = + getTreeInfoFromIdentifier(snapshot_modes, setup.engine_snapshot_mode); + + /* if that fails, set current snapshot mode to reliable default value */ + if (snapshot_mode_current == NULL) + snapshot_mode_current = + getTreeInfoFromIdentifier(snapshot_modes, STR_SNAPSHOT_MODE_DEFAULT); + + /* if that also fails, set current snapshot mode to first available value */ + if (snapshot_mode_current == NULL) + snapshot_mode_current = snapshot_modes; + } + + setup.engine_snapshot_mode = snapshot_mode_current->identifier; + + /* needed for displaying snapshot mode text instead of identifier */ + snapshot_mode_text = snapshot_mode_current->name; +} + +static void execSetupGame_setNetworkServerText(void) +{ + if (strEqual(setup.network_server_hostname, STR_NETWORK_AUTO_DETECT)) + { + strcpy(network_server_hostname, STR_NETWORK_AUTO_DETECT_SETUP); + } + else + { + strncpy(network_server_hostname, setup.network_server_hostname, + MAX_SETUP_TEXT_INPUT_LEN); + network_server_hostname[MAX_SETUP_TEXT_INPUT_LEN] = '\0'; + } + + /* needed for displaying network server text instead of identifier */ + network_server_text = network_server_hostname; +} + +static void execSetupGame(void) +{ + boolean check_vsync_mode = (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED); + + execSetupGame_setGameSpeeds(FALSE); execSetupGame_setScrollDelays(); + execSetupGame_setSnapshotModes(); + + execSetupGame_setNetworkServerText(); setup_mode = SETUP_MODE_GAME; DrawSetupScreen(); + + // check if vsync needs to be disabled for this game speed to work + if (check_vsync_mode) + DisableVsyncIfNeeded(); } -static void execSetupChooseGameSpeed() +static void execSetupChooseGameSpeed(void) { setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED; DrawSetupScreen(); } -static void execSetupChooseScrollDelay() +static void execSetupChooseScrollDelay(void) { setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY; DrawSetupScreen(); } -static void execSetupEditor() +static void execSetupChooseSnapshotMode(void) +{ + setup_mode = SETUP_MODE_CHOOSE_SNAPSHOT_MODE; + + DrawSetupScreen(); +} + +static void execSetupEditor(void) { setup_mode = SETUP_MODE_EDITOR; @@ -4103,7 +4980,7 @@ static void execSetupGraphics_setWindowSizes(boolean update_list) setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Window Scaling"); + setString(&ti->infotext, STR_SETUP_CHOOSE_WINDOW_SIZE); pushTreeInfo(&window_sizes, ti); @@ -4128,7 +5005,7 @@ static void execSetupGraphics_setWindowSizes(boolean update_list) setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Window Scaling"); + setString(&ti->infotext, STR_SETUP_CHOOSE_WINDOW_SIZE); pushTreeInfo(&window_sizes, ti); } @@ -4158,7 +5035,7 @@ static void execSetupGraphics_setWindowSizes(boolean update_list) window_size_text = window_size_current->name; } -static void execSetupGraphics_setScalingTypes() +static void execSetupGraphics_setScalingTypes(void) { if (scaling_types == NULL) { @@ -4180,7 +5057,7 @@ static void execSetupGraphics_setScalingTypes() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Anti-Aliasing"); + setString(&ti->infotext, STR_SETUP_CHOOSE_SCALING_TYPE); pushTreeInfo(&scaling_types, ti); } @@ -4208,87 +5085,137 @@ static void execSetupGraphics_setScalingTypes() scaling_type_text = scaling_type_current->name; } -static void execSetupGraphics_setScreenModes() +static void execSetupGraphics_setRenderingModes(void) { - // if (screen_modes == NULL && video.fullscreen_available) - if (screen_modes == NULL && video.fullscreen_modes != NULL) + if (rendering_modes == NULL) { int i; - for (i = 0; video.fullscreen_modes[i].width != -1; i++) + for (i = 0; rendering_modes_list[i].value != NULL; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; - int x = video.fullscreen_modes[i].width; - int y = video.fullscreen_modes[i].height; - int xx, yy; - - get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy); + char *value = rendering_modes_list[i].value; + char *text = rendering_modes_list[i].text; - ti->node_top = &screen_modes; - ti->sort_priority = x * 10000 + y; + ti->node_top = &rendering_modes; + ti->sort_priority = i; - sprintf(identifier, "%dx%d", x, y); - sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy); + sprintf(identifier, "%s", value); + sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Fullscreen Mode"); + setString(&ti->infotext, STR_SETUP_CHOOSE_RENDERING); - pushTreeInfo(&screen_modes, ti); + pushTreeInfo(&rendering_modes, ti); } - /* sort fullscreen modes to start with lowest available screen resolution */ - sortTreeInfo(&screen_modes); + /* sort rendering mode values to start with lowest rendering mode value */ + sortTreeInfo(&rendering_modes); + + /* set current rendering mode value to configured rendering mode value */ + rendering_mode_current = + getTreeInfoFromIdentifier(rendering_modes, setup.screen_rendering_mode); - /* set current screen mode for fullscreen mode to configured setup value */ - screen_mode_current = getTreeInfoFromIdentifier(screen_modes, - setup.fullscreen_mode); + /* if that fails, set current rendering mode to reliable default value */ + if (rendering_mode_current == NULL) + rendering_mode_current = + getTreeInfoFromIdentifier(rendering_modes, + STR_SPECIAL_RENDERING_DEFAULT); + + /* if that also fails, set current rendering mode to first available one */ + if (rendering_mode_current == NULL) + rendering_mode_current = rendering_modes; + } - /* if that fails, set current screen mode to reliable default value */ - if (screen_mode_current == NULL) - screen_mode_current = getTreeInfoFromIdentifier(screen_modes, - DEFAULT_FULLSCREEN_MODE); + setup.screen_rendering_mode = rendering_mode_current->identifier; - /* if that also fails, set current screen mode to first available mode */ - if (screen_mode_current == NULL) - screen_mode_current = screen_modes; + /* needed for displaying rendering mode text instead of identifier */ + rendering_mode_text = rendering_mode_current->name; +} - if (screen_mode_current == NULL) - video.fullscreen_available = FALSE; +static void execSetupGraphics_setVsyncModes(boolean update_value) +{ + if (vsync_modes == NULL) + { + int i; + + for (i = 0; vsync_modes_list[i].value != NULL; i++) + { + TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); + char identifier[32], name[32]; + char *value = vsync_modes_list[i].value; + char *text = vsync_modes_list[i].text; + + ti->node_top = &vsync_modes; + ti->sort_priority = i; + + sprintf(identifier, "%s", value); + sprintf(name, "%s", text); + + setString(&ti->identifier, identifier); + setString(&ti->name, name); + setString(&ti->name_sorting, name); + setString(&ti->infotext, STR_SETUP_CHOOSE_VSYNC); + + pushTreeInfo(&vsync_modes, ti); + } + + /* sort vsync mode values to start with lowest vsync mode value */ + sortTreeInfo(&vsync_modes); + + update_value = TRUE; } - // if (video.fullscreen_available) - if (screen_mode_current != NULL) + if (update_value) { - setup.fullscreen_mode = screen_mode_current->identifier; + /* set current vsync mode value to configured vsync mode value */ + vsync_mode_current = + getTreeInfoFromIdentifier(vsync_modes, setup.vsync_mode); + + /* if that fails, set current vsync mode to reliable default value */ + if (vsync_mode_current == NULL) + vsync_mode_current = + getTreeInfoFromIdentifier(vsync_modes, STR_VSYNC_MODE_DEFAULT); - /* needed for displaying screen mode name instead of identifier */ - screen_mode_text = screen_mode_current->name; + /* if that also fails, set current vsync mode to first available one */ + if (vsync_mode_current == NULL) + vsync_mode_current = vsync_modes; } + + setup.vsync_mode = vsync_mode_current->identifier; + + /* needed for displaying vsync mode text instead of identifier */ + vsync_mode_text = vsync_mode_current->name; } -static void execSetupGraphics() +static void execSetupGraphics(void) { + boolean check_game_speed = (setup_mode == SETUP_MODE_CHOOSE_VSYNC); + + // update "setup.window_scaling_percent" from list selection + // (in this case, window scaling was changed on setup screen) if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) - { - // update "setup.window_scaling_percent" from list selection execSetupGraphics_setWindowSizes(FALSE); - } - else - { - // update list selection from "setup.window_scaling_percent" - execSetupGraphics_setWindowSizes(TRUE); - } + + // update list selection from "setup.window_scaling_percent" + // (window scaling may have changed by resizing the window) + execSetupGraphics_setWindowSizes(TRUE); execSetupGraphics_setScalingTypes(); - execSetupGraphics_setScreenModes(); + execSetupGraphics_setRenderingModes(); + execSetupGraphics_setVsyncModes(FALSE); setup_mode = SETUP_MODE_GRAPHICS; DrawSetupScreen(); + // check if game speed is high enough for 60 Hz vsync to work + if (check_game_speed) + ModifyGameSpeedIfNeeded(); + #if defined(TARGET_SDL2) // window scaling may have changed at this point ToggleFullscreenOrChangeWindowScalingIfNeeded(); @@ -4296,59 +5223,65 @@ static void execSetupGraphics() // window scaling quality may have changed at this point if (!strEqual(setup.window_scaling_quality, video.window_scaling_quality)) SDLSetWindowScalingQuality(setup.window_scaling_quality); + + // screen rendering mode may have changed at this point + SDLSetScreenRenderingMode(setup.screen_rendering_mode); + + // screen vsync mode may have changed at this point + SDLSetScreenVsyncMode(setup.vsync_mode); #endif } -#if !defined(PLATFORM_ANDROID) -#if defined(TARGET_SDL2) -static void execSetupChooseWindowSize() +static void execSetupChooseWindowSize(void) { setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE; DrawSetupScreen(); } -static void execSetupChooseScalingType() +static void execSetupChooseScalingType(void) { setup_mode = SETUP_MODE_CHOOSE_SCALING_TYPE; DrawSetupScreen(); } -#else -static void execSetupChooseScreenMode() + +static void execSetupChooseRenderingMode(void) { - if (!video.fullscreen_available) - return; + setup_mode = SETUP_MODE_CHOOSE_RENDERING; + + DrawSetupScreen(); +} - setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE; +static void execSetupChooseVsyncMode(void) +{ + setup_mode = SETUP_MODE_CHOOSE_VSYNC; DrawSetupScreen(); } -#endif -#endif -static void execSetupChooseVolumeSimple() +static void execSetupChooseVolumeSimple(void) { setup_mode = SETUP_MODE_CHOOSE_VOLUME_SIMPLE; DrawSetupScreen(); } -static void execSetupChooseVolumeLoops() +static void execSetupChooseVolumeLoops(void) { setup_mode = SETUP_MODE_CHOOSE_VOLUME_LOOPS; DrawSetupScreen(); } -static void execSetupChooseVolumeMusic() +static void execSetupChooseVolumeMusic(void) { setup_mode = SETUP_MODE_CHOOSE_VOLUME_MUSIC; DrawSetupScreen(); } -static void execSetupSound() +static void execSetupSound(void) { if (volumes_simple == NULL) { @@ -4371,7 +5304,7 @@ static void execSetupSound() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Sound Volume"); + setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_SIMPLE); pushTreeInfo(&volumes_simple, ti); @@ -4396,7 +5329,7 @@ static void execSetupSound() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Sound Volume"); + setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_SIMPLE); pushTreeInfo(&volumes_simple, ti); } @@ -4439,7 +5372,7 @@ static void execSetupSound() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Loops Volume"); + setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_LOOPS); pushTreeInfo(&volumes_loops, ti); @@ -4464,7 +5397,7 @@ static void execSetupSound() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Loops Volume"); + setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_LOOPS); pushTreeInfo(&volumes_loops, ti); } @@ -4507,7 +5440,7 @@ static void execSetupSound() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Music Volume"); + setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_MUSIC); pushTreeInfo(&volumes_music, ti); @@ -4532,7 +5465,7 @@ static void execSetupSound() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Music Volume"); + setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_MUSIC); pushTreeInfo(&volumes_music, ti); } @@ -4568,33 +5501,79 @@ static void execSetupSound() DrawSetupScreen(); } -static void execSetupChooseTouchControls() +static void execSetupChooseTouchControls(void) { setup_mode = SETUP_MODE_CHOOSE_TOUCH_CONTROL; DrawSetupScreen(); } -static void execSetupChooseMoveDistance() +static void execSetupChooseMoveDistance(void) { setup_mode = SETUP_MODE_CHOOSE_MOVE_DISTANCE; DrawSetupScreen(); } -static void execSetupChooseDropDistance() +static void execSetupChooseDropDistance(void) { setup_mode = SETUP_MODE_CHOOSE_DROP_DISTANCE; DrawSetupScreen(); } -static void execSetupTouch() +static void execSetupChooseTransparency(void) +{ + setup_mode = SETUP_MODE_CHOOSE_TRANSPARENCY; + + DrawSetupScreen(); +} + +static void execSetupChooseGridXSize_0(void) +{ + setup_mode = SETUP_MODE_CHOOSE_GRID_XSIZE_0; + + DrawSetupScreen(); +} + +static void execSetupChooseGridYSize_0(void) +{ + setup_mode = SETUP_MODE_CHOOSE_GRID_YSIZE_0; + + DrawSetupScreen(); +} + +static void execSetupChooseGridXSize_1(void) +{ + setup_mode = SETUP_MODE_CHOOSE_GRID_XSIZE_1; + + DrawSetupScreen(); +} + +static void execSetupChooseGridYSize_1(void) +{ + setup_mode = SETUP_MODE_CHOOSE_GRID_YSIZE_1; + + DrawSetupScreen(); +} + +static void execSetupConfigureVirtualButtons(void) +{ + setup_mode = SETUP_MODE_CONFIG_VIRT_BUTTONS; + + ConfigureVirtualButtons(); + + setup_mode = SETUP_MODE_TOUCH; + + DrawSetupScreen(); +} + +static void execSetupTouch(void) { + int i, j, k; + if (touch_controls == NULL) { - int i; - for (i = 0; touch_controls_list[i].value != NULL; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); @@ -4611,7 +5590,7 @@ static void execSetupTouch() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Control Type"); + setString(&ti->infotext, STR_SETUP_CHOOSE_TOUCH_CONTROL); pushTreeInfo(&touch_controls, ti); } @@ -4635,8 +5614,6 @@ static void execSetupTouch() if (move_distances == NULL) { - int i; - for (i = 0; distances_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); @@ -4653,7 +5630,7 @@ static void execSetupTouch() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Move Distance"); + setString(&ti->infotext, STR_SETUP_CHOOSE_MOVE_DISTANCE); pushTreeInfo(&move_distances, ti); } @@ -4669,7 +5646,8 @@ static void execSetupTouch() /* if that fails, set current distance to reliable default value */ if (move_distance_current == NULL) move_distance_current = - getTreeInfoFromIdentifier(move_distances, i_to_a(1)); + getTreeInfoFromIdentifier(move_distances, + i_to_a(TOUCH_MOVE_DISTANCE_DEFAULT)); /* if that also fails, set current distance to first available value */ if (move_distance_current == NULL) @@ -4678,8 +5656,6 @@ static void execSetupTouch() if (drop_distances == NULL) { - int i; - for (i = 0; distances_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); @@ -4696,7 +5672,7 @@ static void execSetupTouch() setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); - setString(&ti->infotext, "Drop Distance"); + setString(&ti->infotext, STR_SETUP_CHOOSE_DROP_DISTANCE); pushTreeInfo(&drop_distances, ti); } @@ -4712,28 +5688,148 @@ static void execSetupTouch() /* if that fails, set current distance to reliable default value */ if (drop_distance_current == NULL) drop_distance_current = - getTreeInfoFromIdentifier(drop_distances, i_to_a(1)); + getTreeInfoFromIdentifier(drop_distances, + i_to_a(TOUCH_DROP_DISTANCE_DEFAULT)); /* if that also fails, set current distance to first available value */ if (drop_distance_current == NULL) drop_distance_current = drop_distances; } + if (transparencies == NULL) + { + for (i = 0; transparencies_list[i].value != -1; i++) + { + TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); + char identifier[32], name[32]; + int value = transparencies_list[i].value; + char *text = transparencies_list[i].text; + + ti->node_top = &transparencies; + ti->sort_priority = value; + + sprintf(identifier, "%d", value); + sprintf(name, "%s", text); + + setString(&ti->identifier, identifier); + setString(&ti->name, name); + setString(&ti->name_sorting, name); + setString(&ti->infotext, STR_SETUP_CHOOSE_TRANSPARENCY); + + pushTreeInfo(&transparencies, ti); + } + + /* sort transparency values to start with lowest transparency value */ + sortTreeInfo(&transparencies); + + /* set current transparency value to configured transparency value */ + transparency_current = + getTreeInfoFromIdentifier(transparencies, + i_to_a(setup.touch.transparency)); + + /* if that fails, set current transparency to reliable default value */ + if (transparency_current == NULL) + transparency_current = + getTreeInfoFromIdentifier(transparencies, + i_to_a(TOUCH_TRANSPARENCY_DEFAULT)); + + /* if that also fails, set current transparency to first available value */ + if (transparency_current == NULL) + transparency_current = transparencies; + } + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (grid_sizes[i][j] == NULL) + { + for (k = 0; grid_sizes_list[k].value != -1; k++) + { + TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); + char identifier[32], name[32]; + int value = grid_sizes_list[k].value; + char *text = grid_sizes_list[k].text; + + ti->node_top = &grid_sizes[i][j]; + ti->sort_priority = value; + + sprintf(identifier, "%d", value); + sprintf(name, "%s", text); + + setString(&ti->identifier, identifier); + setString(&ti->name, name); + setString(&ti->name_sorting, name); + setString(&ti->infotext, + (i == 0 ? + (j == 0 ? + STR_SETUP_CHOOSE_GRID_XSIZE_0 : + STR_SETUP_CHOOSE_GRID_YSIZE_0) : + (j == 0 ? + STR_SETUP_CHOOSE_GRID_XSIZE_1 : + STR_SETUP_CHOOSE_GRID_YSIZE_1))); + + pushTreeInfo(&grid_sizes[i][j], ti); + } + + /* sort grid size values to start with lowest grid size value */ + sortTreeInfo(&grid_sizes[i][j]); + + /* set current grid size value to configured grid size value */ + grid_size_current[i][j] = + getTreeInfoFromIdentifier(grid_sizes[i][j], + i_to_a(j == 0 ? + setup.touch.grid_xsize[i] : + setup.touch.grid_ysize[i])); + + /* if that fails, set current grid size to reliable default value */ + if (grid_size_current[i][j] == NULL) + grid_size_current[i][j] = + getTreeInfoFromIdentifier(grid_sizes[i][j], + i_to_a(j == 0 ? + DEFAULT_GRID_XSIZE(i) : + DEFAULT_GRID_YSIZE(i))); + + /* if that also fails, set current grid size to first available value */ + if (grid_size_current[i][j] == NULL) + grid_size_current[i][j] = grid_sizes[i][j]; + } + } + } + setup.touch.control_type = touch_control_current->identifier; setup.touch.move_distance = atoi(move_distance_current->identifier); setup.touch.drop_distance = atoi(drop_distance_current->identifier); + setup.touch.transparency = atoi(transparency_current->identifier); - /* needed for displaying volume text instead of identifier */ + for (i = 0; i < 2; i++) + { + setup.touch.grid_xsize[i] = atoi(grid_size_current[i][0]->identifier); + setup.touch.grid_ysize[i] = atoi(grid_size_current[i][1]->identifier); + + if (i == GRID_ACTIVE_NR()) + { + overlay.grid_xsize = setup.touch.grid_xsize[i]; + overlay.grid_ysize = setup.touch.grid_ysize[i]; + } + } + + /* needed for displaying value text instead of identifier */ touch_controls_text = touch_control_current->name; move_distance_text = move_distance_current->name; drop_distance_text = drop_distance_current->name; + transparency_text = transparency_current->name; + + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) + grid_size_text[i][j] = grid_size_current[i][j]->name; setup_mode = SETUP_MODE_TOUCH; DrawSetupScreen(); } -static void execSetupArtwork() +static void execSetupArtwork(void) { #if 0 printf("::: '%s', '%s', '%s'\n", @@ -4759,108 +5855,297 @@ static void execSetupArtwork() DrawSetupScreen(); } -static void execSetupChooseGraphics() +static void execSetupChooseGraphics(void) { setup_mode = SETUP_MODE_CHOOSE_GRAPHICS; DrawSetupScreen(); } -static void execSetupChooseSounds() +static void execSetupChooseSounds(void) { setup_mode = SETUP_MODE_CHOOSE_SOUNDS; DrawSetupScreen(); } -static void execSetupChooseMusic() +static void execSetupChooseMusic(void) { setup_mode = SETUP_MODE_CHOOSE_MUSIC; DrawSetupScreen(); } -#if !defined(PLATFORM_ANDROID) -static void execSetupInput() +static void execSetupInput(void) { setup_mode = SETUP_MODE_INPUT; DrawSetupScreen(); } -#endif -static void execSetupShortcuts() +static void execSetupShortcuts(void) { setup_mode = SETUP_MODE_SHORTCUTS; DrawSetupScreen(); } -static void execSetupShortcuts1() +static void execSetupShortcuts1(void) { setup_mode = SETUP_MODE_SHORTCUTS_1; DrawSetupScreen(); } -static void execSetupShortcuts2() +static void execSetupShortcuts2(void) { setup_mode = SETUP_MODE_SHORTCUTS_2; DrawSetupScreen(); } -static void execSetupShortcuts3() +static void execSetupShortcuts3(void) { setup_mode = SETUP_MODE_SHORTCUTS_3; DrawSetupScreen(); } -static void execSetupShortcuts4() +static void execSetupShortcuts4(void) { setup_mode = SETUP_MODE_SHORTCUTS_4; DrawSetupScreen(); } -static void execSetupShortcuts5() +static void execSetupShortcuts5(void) { setup_mode = SETUP_MODE_SHORTCUTS_5; DrawSetupScreen(); } -static void execExitSetup() +static void execExitSetup(void) { - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); - DrawMainMenuExt(REDRAW_FIELD, FALSE); + DrawMainMenu(); } -static void execSaveAndExitSetup() +static void execSaveAndExitSetup(void) { SaveSetup(); execExitSetup(); } +static void execGadgetNetworkServer(void) +{ + int gadget_id = SCREEN_CTRL_ID_NETWORK_SERVER; + struct GadgetInfo *gi = screen_gadget[gadget_id]; + + if (strEqual(setup.network_server_hostname, STR_NETWORK_AUTO_DETECT)) + network_server_hostname[0] = '\0'; + + ModifyGadget(gi, GDI_TEXT_VALUE, network_server_hostname, GDI_END); + + MapGadget(gi); + + ClickOnGadget(gi, MB_LEFTBUTTON); +} + +static void ToggleNetworkModeIfNeeded(void) +{ + int font_title = FONT_TITLE_1; + int font_foot = FC_BLUE; + int ystart = mSY - SY + 16; + int ybottom = mSY - SY + SYSIZE - 20; + char *text = (setup.network_mode ? "Start Network" : "Stop Network"); + + if (setup.network_mode == network.enabled) + return; + + network.enabled = setup.network_mode; + + FadeOut(REDRAW_ALL); + + ClearField(); + + DrawTextSCentered(ystart, font_title, text); + + FadeIn(REDRAW_ALL); + + if (network.enabled) + InitNetworkServer(); + else + DisconnectFromNetworkServer(); + + DrawTextSCentered(ybottom, font_foot, + "Press any key or button for setup menu"); + + WaitForEventToContinue(); + + DrawSetupScreen(); +} + +static void ToggleGameSpeedsListIfNeeded(void) +{ + boolean using_game_speeds_extended = (game_speeds == game_speeds_extended); + + if (setup.game_speed_extended == using_game_speeds_extended) + return; + + /* try to match similar values when changing game speeds list */ + if (setup.game_speed_extended) + setup.game_frame_delay = (setup.game_frame_delay == 15 ? 16 : + setup.game_frame_delay == 30 ? 29 : + setup.game_frame_delay); + else + setup.game_frame_delay = (setup.game_frame_delay == 14 ? 15 : + setup.game_frame_delay == 16 ? 15 : + setup.game_frame_delay >= 29 ? 30 : + setup.game_frame_delay <= 10 ? 10 : + setup.game_frame_delay); + + execSetupGame_setGameSpeeds(TRUE); + + DrawSetupScreen(); +} + +static void ModifyGameSpeedIfNeeded(void) +{ + if (strEqual(setup.vsync_mode, STR_VSYNC_MODE_OFF) || + setup.game_frame_delay <= MAX_VSYNC_FRAME_DELAY) + return; + + char message[100]; + char *game_speed_text = "Fast"; + int game_speed_value = 15; + + if (setup.game_speed_extended) + { + game_speed_text = "60 fps"; + game_speed_value = 16; + } + + sprintf(message, "Game speed set to %s for VSync to work!", game_speed_text); + + /* set game speed to existing list value that is fast enough for vsync */ + setup.game_frame_delay = game_speed_value; + + execSetupGame_setGameSpeeds(TRUE); + + Request(message, REQ_CONFIRM); +} + +static void DisableVsyncIfNeeded(void) +{ + if (strEqual(setup.vsync_mode, STR_VSYNC_MODE_OFF) || + (setup.game_frame_delay >= MIN_VSYNC_FRAME_DELAY && + setup.game_frame_delay <= MAX_VSYNC_FRAME_DELAY)) + return; + + /* disable vsync for the selected game speed to work */ + setup.vsync_mode = STR_VSYNC_MODE_OFF; + + execSetupGraphics_setVsyncModes(TRUE); + + Request("VSync disabled for this game speed to work!", REQ_CONFIRM); +} + +static struct +{ + void *value; + void *related_value; +} hide_related_entry_list[] = +{ + { &setup.game_frame_delay, execSetupChooseGameSpeed }, + { &setup.game_frame_delay, &game_speed_text }, + + { &setup.scroll_delay_value, execSetupChooseScrollDelay }, + { &setup.scroll_delay_value, &scroll_delay_text }, + + { &setup.engine_snapshot_mode, execSetupChooseSnapshotMode }, + { &setup.engine_snapshot_mode, &snapshot_mode_text }, + + { &setup.window_scaling_percent, execSetupChooseWindowSize }, + { &setup.window_scaling_percent, &window_size_text }, + + { &setup.window_scaling_quality, execSetupChooseScalingType }, + { &setup.window_scaling_quality, &scaling_type_text }, + + { &setup.screen_rendering_mode, execSetupChooseRenderingMode }, + { &setup.screen_rendering_mode, &rendering_mode_text }, + + { &setup.vsync_mode, execSetupChooseVsyncMode }, + { &setup.vsync_mode, &vsync_mode_text }, + + { &setup.graphics_set, execSetupChooseGraphics }, + { &setup.graphics_set, &graphics_set_name }, + + { &setup.sounds_set, execSetupChooseSounds }, + { &setup.sounds_set, &sounds_set_name }, + + { &setup.music_set, execSetupChooseMusic }, + { &setup.music_set, &music_set_name }, + + { &setup.volume_simple, execSetupChooseVolumeSimple }, + { &setup.volume_simple, &volume_simple_text }, + + { &setup.volume_loops, execSetupChooseVolumeLoops }, + { &setup.volume_loops, &volume_loops_text }, + + { &setup.volume_music, execSetupChooseVolumeMusic }, + { &setup.volume_music, &volume_music_text }, + + { &setup.touch.control_type, execSetupChooseTouchControls }, + { &setup.touch.control_type, &touch_controls_text }, + + { &setup.touch.move_distance, execSetupChooseMoveDistance }, + { &setup.touch.move_distance, &move_distance_text }, + + { &setup.touch.drop_distance, execSetupChooseDropDistance }, + { &setup.touch.drop_distance, &drop_distance_text }, + + { &setup.touch.transparency, execSetupChooseTransparency }, + { &setup.touch.transparency, &transparency_text }, + + { &setup.touch.grid_xsize[0], execSetupChooseGridXSize_0 }, + { &setup.touch.grid_xsize[0], &grid_size_text[0][0] }, + + { &setup.touch.grid_ysize[0], execSetupChooseGridYSize_0 }, + { &setup.touch.grid_ysize[0], &grid_size_text[0][1] }, + + { &setup.touch.grid_xsize[1], execSetupChooseGridXSize_1 }, + { &setup.touch.grid_xsize[1], &grid_size_text[1][0] }, + + { &setup.touch.grid_ysize[1], execSetupChooseGridYSize_1 }, + { &setup.touch.grid_ysize[1], &grid_size_text[1][1] }, + + { NULL, NULL } +}; + +void setHideRelatedSetupEntries(void) +{ + int i; + + for (i = 0; hide_related_entry_list[i].value != NULL; i++) + if (hideSetupEntry(hide_related_entry_list[i].value)) + setHideSetupEntry(hide_related_entry_list[i].related_value); +} + static struct TokenInfo setup_info_main[] = { - { TYPE_ENTER_MENU, execSetupGame, "Game & Menu" }, - { TYPE_ENTER_MENU, execSetupEditor, "Editor" }, - { TYPE_ENTER_MENU, execSetupGraphics, "Graphics" }, - { TYPE_ENTER_MENU, execSetupSound, "Sound & Music" }, - { TYPE_ENTER_MENU, execSetupArtwork, "Custom Artwork" }, -#if !defined(PLATFORM_ANDROID) - { TYPE_ENTER_MENU, execSetupInput, "Input Devices" }, - { TYPE_ENTER_MENU, execSetupTouch, "Touch Controls" }, -#else - { TYPE_ENTER_MENU, execSetupTouch, "Touch Controls" }, -#endif - { TYPE_ENTER_MENU, execSetupShortcuts, "Key Shortcuts" }, + { TYPE_ENTER_MENU, execSetupGame, STR_SETUP_GAME }, + { TYPE_ENTER_MENU, execSetupEditor, STR_SETUP_EDITOR }, + { TYPE_ENTER_MENU, execSetupGraphics, STR_SETUP_GRAPHICS }, + { TYPE_ENTER_MENU, execSetupSound, STR_SETUP_SOUND }, + { TYPE_ENTER_MENU, execSetupArtwork, STR_SETUP_ARTWORK }, + { TYPE_ENTER_MENU, execSetupInput, STR_SETUP_INPUT }, + { TYPE_ENTER_MENU, execSetupTouch, STR_SETUP_TOUCH }, + { TYPE_ENTER_MENU, execSetupShortcuts, STR_SETUP_SHORTCUTS }, { TYPE_EMPTY, NULL, "" }, - { TYPE_LEAVE_MENU, execExitSetup, "Exit" }, - { TYPE_LEAVE_MENU, execSaveAndExitSetup, "Save and Exit" }, + { TYPE_LEAVE_MENU, execExitSetup, STR_SETUP_EXIT }, + { TYPE_LEAVE_MENU, execSaveAndExitSetup, STR_SETUP_SAVE_AND_EXIT }, { 0, NULL, NULL } }; @@ -4868,17 +6153,29 @@ static struct TokenInfo setup_info_main[] = static struct TokenInfo setup_info_game[] = { { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" }, + { TYPE_SWITCH, &setup.network_mode, "Network Multi-Player Mode:" }, + { TYPE_PLAYER, &setup.network_player_nr,"Preferred Network Player:" }, + { TYPE_TEXT_INPUT, execGadgetNetworkServer, "Network Server Hostname:" }, + { TYPE_STRING, &network_server_text, "" }, { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" }, + { TYPE_SWITCH, &setup.time_limit, "Time Limit:" }, { TYPE_SWITCH, &setup.handicap, "Handicap:" }, { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" }, - { TYPE_SWITCH, &setup.time_limit, "Time Limit:" }, + { TYPE_SWITCH, &setup.increment_levels,"Increment Solved Levels:" }, + { TYPE_SWITCH, &setup.auto_play_next_level,"Auto-play Next Level:" }, + { TYPE_SWITCH, &setup.skip_scores_after_game,"Skip Scores After Game:" }, + { TYPE_YES_NO, &setup.ask_on_game_over, "Ask on Game Over:" }, { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" }, { TYPE_ENTER_LIST, execSetupChooseGameSpeed, "Game Speed:" }, { TYPE_STRING, &game_speed_text, "" }, + { TYPE_SWITCH, &setup.game_speed_extended, "Game Speed Extended List:" }, #if 1 { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay:" }, { TYPE_STRING, &scroll_delay_text, "" }, #endif + { TYPE_ENTER_LIST, execSetupChooseSnapshotMode,"Game Engine Snapshot Mode:" }, + { TYPE_STRING, &snapshot_mode_text, "" }, + { TYPE_SWITCH, &setup.show_snapshot_buttons,"Show Snapshot Buttons:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, @@ -4896,9 +6193,10 @@ static struct TokenInfo setup_info_editor[] = { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" }, { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" }, { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" }, -#endif { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" }, { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" }, +#endif + { TYPE_SWITCH, &setup.editor.el_classic, "Classic Elements:" }, { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" }, #if 0 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" }, @@ -4920,27 +6218,26 @@ static struct TokenInfo setup_info_editor[] = static struct TokenInfo setup_info_graphics[] = { -#if !defined(PLATFORM_ANDROID) +#if defined(TARGET_SDL2) && !defined(PLATFORM_ANDROID) { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" }, -#if defined(TARGET_SDL2) { TYPE_ENTER_LIST, execSetupChooseWindowSize, "Window Scaling:" }, { TYPE_STRING, &window_size_text, "" }, { TYPE_ENTER_LIST, execSetupChooseScalingType, "Anti-Aliasing:" }, { TYPE_STRING, &scaling_type_text, "" }, -#else - { TYPE_ENTER_LIST, execSetupChooseScreenMode, "Fullscreen Mode:" }, - { TYPE_STRING, &screen_mode_text, "" }, -#endif + { TYPE_ENTER_LIST, execSetupChooseRenderingMode, "Special Rendering:" }, + { TYPE_STRING, &rendering_mode_text, "" }, #endif #if 0 { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay:" }, { TYPE_STRING, &scroll_delay_text, "" }, #endif + { TYPE_ENTER_LIST, execSetupChooseVsyncMode, "Vertical Sync (VSync):" }, + { TYPE_STRING, &vsync_mode_text, "" }, { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" }, { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" }, { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" }, { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" }, - { TYPE_SWITCH, &setup.toons, "Show Toons:" }, + { TYPE_SWITCH, &setup.toons, "Show Menu Animations:" }, { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" }, { TYPE_SWITCH, &setup.sp_show_border_elements,"Supaplex Border Elements:" }, { TYPE_SWITCH, &setup.small_game_graphics, "Small Game Graphics:" }, @@ -4990,23 +6287,81 @@ static struct TokenInfo setup_info_input[] = { { TYPE_SWITCH, NULL, "Player:" }, { TYPE_SWITCH, NULL, "Device:" }, - { TYPE_ENTER_MENU, NULL, "" }, + { TYPE_SWITCH, NULL, "" }, + { TYPE_SKIPPABLE, NULL, "" }, + { TYPE_EMPTY, NULL, "" }, + { TYPE_EMPTY, NULL, "" }, + { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, + { TYPE_SKIPPABLE, NULL, "" }, + { TYPE_LEAVE_MENU, execSetupMain, "Back" }, + + { 0, NULL, NULL } +}; + +static struct TokenInfo setup_info_touch[] = +{ + { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" }, + { TYPE_STRING, &touch_controls_text, "" }, + { TYPE_EMPTY, NULL, "" }, + { TYPE_LEAVE_MENU, execSetupMain, "Back" }, + + { 0, NULL, NULL } +}; + +static struct TokenInfo setup_info_touch_virtual_buttons_0[] = +{ + { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" }, + { TYPE_STRING, &touch_controls_text, "" }, + { TYPE_EMPTY, NULL, "" }, + { TYPE_ENTER_LIST, execSetupChooseGridXSize_0, "Horizontal Buttons (Landscape):" }, + { TYPE_STRING, &grid_size_text[0][0], "" }, + { TYPE_ENTER_LIST, execSetupChooseGridYSize_0, "Vertical Buttons (Landscape):" }, + { TYPE_STRING, &grid_size_text[0][1], "" }, + { TYPE_ENTER_LIST, execSetupChooseTransparency, "Button Transparency:" }, + { TYPE_STRING, &transparency_text, "" }, + { TYPE_SWITCH, &setup.touch.draw_outlined, "Draw Buttons Outlined:" }, + { TYPE_SWITCH, &setup.touch.draw_pressed, "Highlight Pressed Buttons:" }, { TYPE_EMPTY, NULL, "" }, + { TYPE_ENTER_LIST, execSetupConfigureVirtualButtons, "Configure Virtual Buttons" }, { TYPE_EMPTY, NULL, "" }, + { TYPE_LEAVE_MENU, execSetupMain, "Back" }, + + { 0, NULL, NULL } +}; + +static struct TokenInfo setup_info_touch_virtual_buttons_1[] = +{ + { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" }, + { TYPE_STRING, &touch_controls_text, "" }, { TYPE_EMPTY, NULL, "" }, + { TYPE_ENTER_LIST, execSetupChooseGridXSize_1, "Horizontal Buttons (Portrait):" }, + { TYPE_STRING, &grid_size_text[1][0], "" }, + { TYPE_ENTER_LIST, execSetupChooseGridYSize_1, "Vertical Buttons (Portrait):" }, + { TYPE_STRING, &grid_size_text[1][1], "" }, + { TYPE_ENTER_LIST, execSetupChooseTransparency, "Button Transparency:" }, + { TYPE_STRING, &transparency_text, "" }, + { TYPE_SWITCH, &setup.touch.draw_outlined, "Draw Buttons Outlined:" }, + { TYPE_SWITCH, &setup.touch.draw_pressed, "Highlight Pressed Buttons:" }, { TYPE_EMPTY, NULL, "" }, + { TYPE_ENTER_LIST, execSetupConfigureVirtualButtons, "Configure Virtual Buttons" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; -static struct TokenInfo setup_info_touch[] = +static struct TokenInfo *setup_info_touch_virtual_buttons[] = +{ + setup_info_touch_virtual_buttons_0, + setup_info_touch_virtual_buttons_1 +}; + +static struct TokenInfo setup_info_touch_wipe_gestures[] = { { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" }, { TYPE_STRING, &touch_controls_text, "" }, @@ -5119,19 +6474,17 @@ static struct TokenInfo setup_info_shortcuts_5[] = { 0, NULL, NULL } }; -static Key getSetupKey() +static Key getSetupKey(void) { Key key = KSYM_UNDEFINED; boolean got_key_event = FALSE; while (!got_key_event) { - if (PendingEvent()) /* got event */ - { - Event event; - - NextEvent(&event); + Event event; + if (NextValidEvent(&event)) + { switch (event.type) { case EVENT_KEYPRESS: @@ -5156,33 +6509,17 @@ static Key getSetupKey() } } - DoAnimation(); BackToFront(); - - /* don't eat all CPU time */ - Delay(10); } return key; } -static int getSetupTextFont(int type) -{ - if (type & (TYPE_SWITCH | - TYPE_YES_NO | - TYPE_YES_NO_AUTO | - TYPE_STRING | - TYPE_ECS_AGA | - TYPE_KEYTEXT | - TYPE_ENTER_LIST)) - return FONT_MENU_2; - else - return FONT_MENU_1; -} - static int getSetupValueFont(int type, void *value) { - if (type & TYPE_KEY) + if (type & TYPE_GHOSTED) + return FONT_OPTION_OFF; + else if (type & TYPE_KEY) return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1); else if (type & TYPE_STRING) return FONT_VALUE_2; @@ -5193,27 +6530,40 @@ static int getSetupValueFont(int type, void *value) else if (type & TYPE_YES_NO_AUTO) return (*(int *)value == AUTO ? FONT_OPTION_ON : *(int *)value == FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON); + else if (type & TYPE_PLAYER) + return FONT_VALUE_1; else return FONT_VALUE_1; } +static int getSetupValueFontNarrow(int type, int font_nr) +{ + return (font_nr == FONT_VALUE_1 ? FONT_VALUE_NARROW : + font_nr == FONT_OPTION_ON ? FONT_OPTION_ON_NARROW : + font_nr == FONT_OPTION_OFF ? FONT_OPTION_OFF_NARROW : + font_nr); +} + static void drawSetupValue(int screen_pos, int setup_info_pos_raw) { int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw); struct TokenInfo *si = &setup_info[si_pos]; boolean font_draw_xoffset_modified = FALSE; + boolean scrollbar_needed = (num_setup_info < max_setup_info); int font_draw_xoffset_old = -1; - int xoffset = (num_setup_info < max_setup_info ? -1 : 0); + int xoffset = (scrollbar_needed ? -1 : 0); int menu_screen_value_xpos = MENU_SCREEN_VALUE_XPOS + xoffset; int menu_screen_max_xpos = MENU_SCREEN_MAX_XPOS + xoffset; int xpos = menu_screen_value_xpos; int ypos = MENU_SCREEN_START_YPOS + screen_pos; int startx = mSX + xpos * 32; int starty = mSY + ypos * 32; - int font_nr, font_width; int type = si->type; void *value = si->value; char *value_string = getSetupValue(type, value); + int font_nr_default = getSetupValueFont(type, value); + int font_width_default = getFontWidth(font_nr_default); + int font_nr = font_nr_default; int i; if (value_string == NULL) @@ -5228,7 +6578,7 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw) } else if (type & TYPE_STRING) { - int max_value_len = (SCR_FIELDX - 2) * 2; + int max_value_len = (SXSIZE - 2 * TILEX) / font_width_default; xpos = MENU_SCREEN_START_XPOS; @@ -5239,12 +6589,35 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw) { xpos = menu_screen_value_xpos - 1; } + else if (type & TYPE_PLAYER) + { + int displayed_player_nr = *(int *)value + 1; + + value_string = getSetupValue(TYPE_INTEGER, (void *)&displayed_player_nr); + } + + startx = mSX + xpos * 32; + starty = mSY + ypos * 32; + + // special check if right-side setup values moved left due to scrollbar + if (scrollbar_needed && xpos > MENU_SCREEN_START_XPOS) + { + int max_menu_text_length = 26; // maximum text length for classic menu + int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; + int text_startx = mSX + MENU_SCREEN_START_XPOS * 32; + int text_font_nr = getMenuTextFont(FONT_MENU_2); + int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset; + int text_width = max_menu_text_length * getFontWidth(text_font_nr); + + if (startx + font_xoffset < text_startx + text_width + text_font_xoffset) + { + xpos += 1; + startx = mSX + xpos * 32; + + font_nr = getSetupValueFontNarrow(type, font_nr); + } + } - startx = mSX + xpos * 32; - starty = mSY + ypos * 32; - font_nr = getSetupValueFont(type, value); - font_width = getFontWidth(font_nr); - /* downward compatibility correction for Juergen Bonhagen's menu settings */ if (setup_mode != SETUP_MODE_INPUT) { @@ -5255,7 +6628,7 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw) int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset; int text_startx = mSX + MENU_SCREEN_START_XPOS * 32; - int text_font_nr = getSetupTextFont(FONT_MENU_2); + int text_font_nr = getMenuTextFont(FONT_MENU_2); int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset; int text_width = max_menu_text_length_medium * getFontWidth(text_font_nr); boolean correct_font_draw_xoffset = FALSE; @@ -5284,10 +6657,26 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw) } for (i = 0; i <= menu_screen_max_xpos - xpos; i++) - DrawText(startx + i * font_width, starty, " ", font_nr); + DrawText(startx + i * font_width_default, starty, " ", font_nr_default); DrawText(startx, starty, value_string, font_nr); + if (type & TYPE_PLAYER) + { + struct FontBitmapInfo *font = getFontBitmapInfo(font_nr); + int player_nr = *(int *)value; + int xoff = font->draw_xoffset + getFontWidth(font_nr); + int yoff = font->draw_yoffset + (getFontHeight(font_nr) - TILEY) / 2; + int startx2 = startx + xoff; + int starty2 = starty + yoff; + + if (DrawingOnBackground(startx2, starty2)) + ClearRectangleOnBackground(drawto, startx2, starty2, TILEX, TILEY); + + DrawFixedGraphicThruMaskExt(drawto, startx2, starty2, + PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0); + } + if (font_draw_xoffset_modified) getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old; } @@ -5322,453 +6711,202 @@ static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx) if (key != KSYM_UNDEFINED) *(Key *)si->value = key; } + else if (si->type & TYPE_PLAYER) + { + int player_nr = *(int *)si->value; + + if (dx) + player_nr += dx; + else + player_nr = Request("Choose player", REQ_PLAYER) - 1; + + *(int *)si->value = MIN(MAX(0, player_nr), MAX_PLAYERS - 1); + } drawSetupValue(screen_pos, setup_info_pos_raw); // fullscreen state may have changed at this point if (si->value == &setup.fullscreen) ToggleFullscreenOrChangeWindowScalingIfNeeded(); -} - -static void DrawCursorAndText_Setup(int screen_pos, int setup_info_pos_raw, - boolean active) -{ - int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw); - struct TokenInfo *si = &setup_info[si_pos]; - int xpos = MENU_SCREEN_START_XPOS; - int ypos = MENU_SCREEN_START_YPOS + screen_pos; - int font_nr = getSetupTextFont(si->type); - - if (setup_info == setup_info_input) - font_nr = FONT_MENU_1; - if (active) - font_nr = FONT_ACTIVE(font_nr); + // network mode may have changed at this point + if (si->value == &setup.network_mode) + ToggleNetworkModeIfNeeded(); - DrawText(mSX + xpos * 32, mSY + ypos * 32, si->text, font_nr); - - if (si->type & ~TYPE_SKIP_ENTRY) - drawCursor(screen_pos, active); + // game speed list may have changed at this point + if (si->value == &setup.game_speed_extended) + ToggleGameSpeedsListIfNeeded(); } -static void drawSetupInfoList(struct TokenInfo *setup_info, - int first_entry, int num_page_entries) +static struct TokenInfo *getSetupInfoFinal(struct TokenInfo *setup_info_orig) { + static struct TokenInfo *setup_info_final = NULL; + int list_size = 0; + int list_pos = 0; int i; - if (num_page_entries > NUM_MENU_ENTRIES_ON_SCREEN) - num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; - - if (num_page_entries > max_setup_info) - num_page_entries = max_setup_info; - - if (first_entry + num_page_entries > max_setup_info) - first_entry = 0; + /* determine maximum list size of target list */ + while (setup_info_orig[list_size++].type != 0); - clearMenuListArea(); + /* free, allocate and clear memory for target list */ + checked_free(setup_info_final); + setup_info_final = checked_calloc(list_size * sizeof(struct TokenInfo)); - for (i = 0; i < num_page_entries; i++) + /* copy setup info list without setup entries marked as hidden */ + for (i = 0; setup_info_orig[i].type != 0; i++) { - int setup_info_pos = first_entry + i; - struct TokenInfo *si = &setup_info[setup_info_pos]; - void *value_ptr = si->value; - - /* set some entries to "unchangeable" according to other variables */ - if ((value_ptr == &setup.sound_simple && !audio.sound_available) || - (value_ptr == &setup.sound_loops && !audio.loops_available) || - (value_ptr == &setup.sound_music && !audio.music_available) || - (value_ptr == &setup.fullscreen && !video.fullscreen_available) || - (value_ptr == &screen_mode_text && !video.fullscreen_available) || - (value_ptr == &window_size_text && !video.window_scaling_available) || - (value_ptr == &scaling_type_text && !video.window_scaling_available)) - si->type |= TYPE_GHOSTED; - - if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) - initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); - else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) - initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); - else if (si->type & ~TYPE_SKIP_ENTRY) - initCursor(i, IMG_MENU_BUTTON); + /* skip setup entries configured to be hidden */ + if (hideSetupEntry(setup_info_orig[i].value)) + continue; - DrawCursorAndText_Setup(i, setup_info_pos, FALSE); + /* skip skippable setup entries if screen is lower than usual */ + if (SCR_FIELDY < SCR_FIELDY_DEFAULT && + setup_info_orig[i].type == TYPE_SKIPPABLE) + continue; - if (si->type & TYPE_VALUE) - drawSetupValue(i, setup_info_pos); + setup_info_final[list_pos++] = setup_info_orig[i]; } + + return setup_info_final; } -static void DrawSetupScreen_Generic() +static void DrawSetupScreen_Generic(void) { - int fade_mask = (DrawingAreaChanged() ? REDRAW_ALL : REDRAW_FIELD); + int fade_mask = REDRAW_FIELD; boolean redraw_all = FALSE; char *title_string = NULL; int i; + if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) + fade_mask = REDRAW_ALL; + UnmapAllGadgets(); + FadeMenuSoundsAndMusic(); FreeScreenGadgets(); CreateScreenGadgets(); - CloseDoor(DOOR_CLOSE_2); - if (redraw_mask & REDRAW_ALL) redraw_all = TRUE; FadeOut(fade_mask); + /* needed if different viewport properties defined for setup screen */ + ChangeViewportPropertiesIfNeeded(); + + SetMainBackgroundImage(IMG_BACKGROUND_SETUP); + ClearField(); + OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); + if (setup_mode == SETUP_MODE_MAIN) { setup_info = setup_info_main; - title_string = "Setup"; + title_string = STR_SETUP_MAIN; } else if (setup_mode == SETUP_MODE_GAME) { setup_info = setup_info_game; - title_string = "Setup Game"; + title_string = STR_SETUP_GAME; } else if (setup_mode == SETUP_MODE_EDITOR) { setup_info = setup_info_editor; - title_string = "Setup Editor"; + title_string = STR_SETUP_EDITOR; } else if (setup_mode == SETUP_MODE_GRAPHICS) { setup_info = setup_info_graphics; - title_string = "Setup Graphics"; + title_string = STR_SETUP_GRAPHICS; } else if (setup_mode == SETUP_MODE_SOUND) { setup_info = setup_info_sound; - title_string = "Setup Sound"; + title_string = STR_SETUP_SOUND; } else if (setup_mode == SETUP_MODE_ARTWORK) { setup_info = setup_info_artwork; - title_string = "Custom Artwork"; + title_string = STR_SETUP_ARTWORK; } else if (setup_mode == SETUP_MODE_TOUCH) { setup_info = setup_info_touch; - title_string = "Setup Touch Ctrls"; + title_string = STR_SETUP_TOUCH; + + if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS)) + setup_info = setup_info_touch_virtual_buttons[GRID_ACTIVE_NR()]; + else if (strEqual(setup.touch.control_type, TOUCH_CONTROL_WIPE_GESTURES)) + setup_info = setup_info_touch_wipe_gestures; } else if (setup_mode == SETUP_MODE_SHORTCUTS) { setup_info = setup_info_shortcuts; - title_string = "Setup Shortcuts"; + title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_1) { setup_info = setup_info_shortcuts_1; - title_string = "Setup Shortcuts"; + title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_2) { setup_info = setup_info_shortcuts_2; - title_string = "Setup Shortcuts"; + title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_3) { setup_info = setup_info_shortcuts_3; - title_string = "Setup Shortcuts"; - } - else if (setup_mode == SETUP_MODE_SHORTCUTS_4) - { - setup_info = setup_info_shortcuts_4; - title_string = "Setup Shortcuts"; - } - else if (setup_mode == SETUP_MODE_SHORTCUTS_5) - { - setup_info = setup_info_shortcuts_5; - title_string = "Setup Shortcuts"; - } - - DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string); - - // determine maximal number of setup entries that can be displayed on screen - num_setup_info = 0; - for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) - num_setup_info++; - - // determine maximal number of setup entries available for this setup screen - max_setup_info = 0; - for (i = 0; setup_info[i].type != 0; i++) - max_setup_info++; - - HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE); - - MapScreenGadgets(max_setup_info); - - if (redraw_all) - redraw_mask = fade_mask = REDRAW_ALL; - - FadeIn(fade_mask); - - InitAnimation(); -} - -void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button) -{ - static int choice_store[MAX_SETUP_MODES]; - static int first_entry_store[MAX_SETUP_MODES]; - int choice = choice_store[setup_mode]; /* starts with 0 */ - int first_entry = first_entry_store[setup_mode]; /* starts with 0 */ - int x = 0; - int y = choice - first_entry; - int y_old = y; - boolean position_set_by_scrollbar = (dx == 999); - int step = (button == 1 ? 1 : button == 2 ? 5 : 10); - int num_page_entries; - - num_page_entries = MIN(max_setup_info, NUM_MENU_ENTRIES_ON_SCREEN); - - if (button == MB_MENU_INITIALIZE) - { - /* advance to first valid menu entry */ - while (choice < num_setup_info && - setup_info[choice].type & TYPE_SKIP_ENTRY) - choice++; - - if (position_set_by_scrollbar) - first_entry = first_entry_store[setup_mode] = dy; - else - AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_setup_info, - NUM_MENU_ENTRIES_ON_SCREEN, first_entry); - - drawSetupInfoList(setup_info, first_entry, NUM_MENU_ENTRIES_ON_SCREEN); - - if (choice < first_entry) - { - choice = first_entry; - - if (setup_info[choice].type & TYPE_SKIP_ENTRY) - choice++; - } - else if (choice > first_entry + num_page_entries - 1) - { - choice = first_entry + num_page_entries - 1; - - if (setup_info[choice].type & TYPE_SKIP_ENTRY) - choice--; - } - - choice_store[setup_mode] = choice; - - DrawCursorAndText_Setup(choice - first_entry, choice, TRUE); - - return; - } - else if (button == MB_MENU_LEAVE) - { - int i; - - PlaySound(SND_MENU_ITEM_SELECTING); - - for (i = 0; setup_info[i].type != 0; i++) - { - if (setup_info[i].type & TYPE_LEAVE_MENU) - { - void (*menu_callback_function)(void) = setup_info[i].value; - - FadeSetLeaveMenu(); - - menu_callback_function(); - - break; /* absolutely needed because function changes 'setup_info'! */ - } - } - - return; - } - - if (mx || my) /* mouse input */ - { - x = (mx - mSX) / 32; - y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; - } - else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */ - { - /* move cursor instead of scrolling when already at start/end of list */ - if (dy == -1 * SCROLL_LINE && first_entry == 0) - dy = -1; - else if (dy == +1 * SCROLL_LINE && - first_entry + num_page_entries == max_setup_info) - dy = 1; - - /* handle scrolling screen one line or page */ - if (y + dy < 0 || - y + dy > num_page_entries - 1) - { - boolean redraw = FALSE; - - if (ABS(dy) == SCROLL_PAGE) - step = num_page_entries - 1; - - if (dy < 0 && first_entry > 0) - { - /* scroll page/line up */ - - first_entry -= step; - if (first_entry < 0) - first_entry = 0; - - redraw = TRUE; - } - else if (dy > 0 && first_entry + num_page_entries < max_setup_info) - { - /* scroll page/line down */ - - first_entry += step; - if (first_entry + num_page_entries > max_setup_info) - first_entry = MAX(0, max_setup_info - num_page_entries); - - redraw = TRUE; - } - - if (redraw) - { - choice += first_entry - first_entry_store[setup_mode]; - - if (choice < first_entry) - { - choice = first_entry; - - if (setup_info[choice].type & TYPE_SKIP_ENTRY) - choice++; - } - else if (choice > first_entry + num_page_entries - 1) - { - choice = first_entry + num_page_entries - 1; - - if (setup_info[choice].type & TYPE_SKIP_ENTRY) - choice--; - } - else if (setup_info[choice].type & TYPE_SKIP_ENTRY) - { - choice += SIGN(dy); - - if (choice < first_entry || - choice > first_entry + num_page_entries - 1) - first_entry += SIGN(dy); - } - - first_entry_store[setup_mode] = first_entry; - choice_store[setup_mode] = choice; - - drawSetupInfoList(setup_info, first_entry, NUM_MENU_ENTRIES_ON_SCREEN); - - DrawCursorAndText_Setup(choice - first_entry, choice, TRUE); - - AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_setup_info, - NUM_MENU_ENTRIES_ON_SCREEN, first_entry); - } - - return; - } - - if (dx) - { - int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER); - - if (setup_info[choice].type & menu_navigation_type || - setup_info[choice].type & TYPE_BOOLEAN_STYLE || - setup_info[choice].type & TYPE_YES_NO_AUTO) - button = MB_MENU_CHOICE; - } - else if (dy) - y += dy; - - /* jump to next non-empty menu entry (up or down) */ - while (first_entry + y > 0 && - first_entry + y < max_setup_info - 1 && - setup_info[first_entry + y].type & TYPE_SKIP_ENTRY) - y += dy; - - if (!IN_VIS_MENU(x, y)) - { - choice += y - y_old; - - if (choice < first_entry) - first_entry = choice; - else if (choice > first_entry + num_page_entries - 1) - first_entry = choice - num_page_entries + 1; - - if (first_entry >= 0 && - first_entry + num_page_entries <= max_setup_info) - { - first_entry_store[setup_mode] = first_entry; - - if (choice < first_entry) - choice = first_entry; - else if (choice > first_entry + num_page_entries - 1) - choice = first_entry + num_page_entries - 1; - - choice_store[setup_mode] = choice; - - drawSetupInfoList(setup_info, first_entry, NUM_MENU_ENTRIES_ON_SCREEN); + title_string = STR_SETUP_SHORTCUTS; + } + else if (setup_mode == SETUP_MODE_SHORTCUTS_4) + { + setup_info = setup_info_shortcuts_4; + title_string = STR_SETUP_SHORTCUTS; + } + else if (setup_mode == SETUP_MODE_SHORTCUTS_5) + { + setup_info = setup_info_shortcuts_5; + title_string = STR_SETUP_SHORTCUTS; + } - DrawCursorAndText_Setup(choice - first_entry, choice, TRUE); + /* use modified setup info without setup entries marked as hidden */ + setup_info = getSetupInfoFinal(setup_info); - AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_setup_info, - NUM_MENU_ENTRIES_ON_SCREEN, first_entry); - } + DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string); - return; - } - } + // determine maximal number of setup entries that can be displayed on screen + num_setup_info = 0; + for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) + num_setup_info++; - if (!anyScrollbarGadgetActive() && - IN_VIS_MENU(x, y) && - mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x && - y >= 0 && y < num_page_entries) - { - if (button) - { - if (first_entry + y != choice && - setup_info[first_entry + y].type & ~TYPE_SKIP_ENTRY) - { - PlaySound(SND_MENU_ITEM_ACTIVATING); + // determine maximal number of setup entries available for this setup screen + max_setup_info = 0; + for (i = 0; setup_info[i].type != 0; i++) + max_setup_info++; - DrawCursorAndText_Setup(choice - first_entry, choice, FALSE); - DrawCursorAndText_Setup(y, first_entry + y, TRUE); + HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE); - choice = choice_store[setup_mode] = first_entry + y; - } - } - else if (!(setup_info[first_entry + y].type & TYPE_GHOSTED)) - { - PlaySound(SND_MENU_ITEM_SELECTING); + MapScreenGadgets(max_setup_info); - /* when selecting key headline, execute function for key value change */ - if (setup_info[first_entry + y].type & TYPE_KEYTEXT && - setup_info[first_entry + y + 1].type & TYPE_KEY) - y++; + if (redraw_all) + redraw_mask = fade_mask = REDRAW_ALL; - /* when selecting string value, execute function for list selection */ - if (setup_info[first_entry + y].type & TYPE_STRING && y > 0 && - setup_info[first_entry + y - 1].type & TYPE_ENTER_LIST) - y--; + DrawMaskedBorder(fade_mask); - if (setup_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE) - { - void (*menu_callback_function)(void) = - setup_info[first_entry + y].value; + FadeIn(fade_mask); +} - FadeSetFromType(setup_info[first_entry + y].type); +void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button) +{ + menu_info = setup_info; - menu_callback_function(); - } - else - { - if (setup_info[first_entry + y].type & TYPE_VALUE) - changeSetupValue(y, first_entry + y, dx); - } - } - } + HandleMenuScreen(mx, my, dx, dy, button, + setup_mode, num_setup_info, max_setup_info); } -void DrawSetupScreen_Input() +static void DrawSetupScreen_Input(void) { int i; @@ -5776,14 +6914,11 @@ void DrawSetupScreen_Input() ClearField(); - setup_info = setup_info_input; - - DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input"); + setup_info = getSetupInfoFinal(setup_info_input); - DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2, - "Joysticks deactivated on this screen"); + DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, STR_SETUP_INPUT); - for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++) + for (i = 0; setup_info[i].type != 0; i++) { if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); @@ -5805,8 +6940,6 @@ void DrawSetupScreen_Input() HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE); FadeIn(REDRAW_FIELD); - - InitAnimation(); } static void setJoystickDeviceToNr(char *device_name, int device_nr) @@ -5840,12 +6973,12 @@ static void drawPlayerSetupInputInfo(int player_nr, boolean active) char *text; } custom[] = { - { &custom_key.left, "Joystick Left" }, - { &custom_key.right, "Joystick Right" }, - { &custom_key.up, "Joystick Up" }, - { &custom_key.down, "Joystick Down" }, - { &custom_key.snap, "Button 1" }, - { &custom_key.drop, "Button 2" } + { &custom_key.left, "Axis/Pad Left" }, + { &custom_key.right, "Axis/Pad Right" }, + { &custom_key.up, "Axis/Pad Up" }, + { &custom_key.down, "Axis/Pad Down" }, + { &custom_key.snap, "Button 1/A/X" }, + { &custom_key.drop, "Button 2/B/Y" } }; static char *joystick_name[MAX_PLAYERS] = { @@ -5854,9 +6987,19 @@ static void drawPlayerSetupInputInfo(int player_nr, boolean active) "Joystick3", "Joystick4" }; - int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1); + int font_nr_menu = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1); + int font_nr_info = FONT_MENU_1; + int font_nr_name = FONT_VALUE_OLD; + int font_nr_on = FONT_VALUE_1; + int font_nr_off = FONT_VALUE_OLD; + int pos = 4; - InitJoysticks(); + if (SCR_FIELDX < SCR_FIELDX_DEFAULT) + { + font_nr_info = FONT_MENU_2; + font_nr_on = FONT_VALUE_NARROW; + font_nr_off = FONT_VALUE_OLD_NARROW; + } custom_key = setup.input[player_nr].key; @@ -5871,48 +7014,53 @@ static void drawPlayerSetupInputInfo(int player_nr, boolean active) if (setup.input[player_nr].use_joystick) { char *device_name = setup.input[player_nr].joy.device_name; - char *text = joystick_name[getJoystickNrFromDeviceName(device_name)]; - int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1); + int joystick_nr = getJoystickNrFromDeviceName(device_name); + boolean joystick_active = CheckJoystickOpened(joystick_nr); + char *text = joystick_name[joystick_nr]; + int font_nr = (joystick_active ? font_nr_on : font_nr_off); DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr); - DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr); + DrawText(mSX + 32, mSY + 4 * 32, "Configure", font_nr_menu); } else { - DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1); - DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr); + DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", font_nr_on); + DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", font_nr_menu); } - DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1); + if (SCR_FIELDY >= SCR_FIELDY_DEFAULT) + DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", font_nr_info); + else + pos = 3; - drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT); - drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT); - drawCursorXY(1, 6, IMG_MENU_BUTTON_UP); - drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN); + drawCursorXY(1, pos + 0, IMG_MENU_BUTTON_LEFT); + drawCursorXY(1, pos + 1, IMG_MENU_BUTTON_RIGHT); + drawCursorXY(1, pos + 2, IMG_MENU_BUTTON_UP); + drawCursorXY(1, pos + 3, IMG_MENU_BUTTON_DOWN); - DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD); - DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD); - DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD); - DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD); - DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD); - DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD); + DrawText(mSX + 2 * 32, mSY + (pos + 2) * 32, ":", font_nr_name); + DrawText(mSX + 2 * 32, mSY + (pos + 3) * 32, ":", font_nr_name); + DrawText(mSX + 2 * 32, mSY + (pos + 4) * 32, ":", font_nr_name); + DrawText(mSX + 2 * 32, mSY + (pos + 5) * 32, ":", font_nr_name); + DrawText(mSX + 1 * 32, mSY + (pos + 6) * 32, "Snap Field:", font_nr_name); + DrawText(mSX + 1 * 32, mSY + (pos + 8) * 32, "Drop Element:", font_nr_name); for (i = 0; i < 6; i++) { - int ypos = 6 + i + (i > 3 ? i-3 : 0); + int ypos = (pos + 2) + i + (i > 3 ? i - 3 : 0); DrawText(mSX + 3 * 32, mSY + ypos * 32, - " ", FONT_VALUE_1); + " ", font_nr_on); DrawText(mSX + 3 * 32, mSY + ypos * 32, (setup.input[player_nr].use_joystick ? custom[i].text : - getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1); + getKeyNameFromKey(*custom[i].key)), font_nr_on); } } static int input_player_nr = 0; -void HandleSetupScreen_Input_Player(int step, int direction) +static void HandleSetupScreen_Input_Player(int step, int direction) { int old_player_nr = input_player_nr; int new_player_nr; @@ -5941,8 +7089,27 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2; int pos_end = SETUPINPUT_SCREEN_POS_END; + if (SCR_FIELDY < SCR_FIELDY_DEFAULT) + { + int i; + + for (i = 0; setup_info_input[i].type != 0; i++) + { + /* adjust menu structure according to skipped setup entries */ + if (setup_info_input[i].type == TYPE_SKIPPABLE) + { + pos_empty2--; + pos_end--; + } + } + } + if (button == MB_MENU_INITIALIZE) { + /* input setup menu may have changed size due to graphics configuration */ + if (choice >= pos_empty1) + choice = pos_end; + drawPlayerSetupInputInfo(input_player_nr, (choice == 2)); DrawCursorAndText_Setup(choice, -1, TRUE); @@ -5968,7 +7135,6 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) if (dx && choice == 0) x = (dx < 0 ? 10 : 12); else if ((dx && choice == 1) || - (dx == +1 && choice == 2) || (dx == -1 && choice == pos_end)) button = MB_MENU_CHOICE; else if (dy) @@ -6027,10 +7193,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) else if (y == 2) { if (setup.input[input_player_nr].use_joystick) - { - InitJoysticks(); - CalibrateJoystick(input_player_nr); - } + ConfigureJoystick(input_player_nr); else CustomizeKeyboard(input_player_nr); } @@ -6047,7 +7210,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) } } -void CustomizeKeyboard(int player_nr) +static boolean CustomizeKeyboardMain(int player_nr) { int i; int step_nr; @@ -6066,6 +7229,15 @@ void CustomizeKeyboard(int player_nr) { &custom_key.snap, "Snap Field" }, { &custom_key.drop, "Drop Element" } }; + int font_nr_old = FONT_VALUE_OLD; + int font_nr_new = FONT_VALUE_1; + boolean success = FALSE; + + if (SCR_FIELDX < SCR_FIELDX_DEFAULT) + { + font_nr_old = FONT_VALUE_OLD_NARROW; + font_nr_new = FONT_VALUE_NARROW; + } /* read existing key bindings from player setup */ custom_key = setup.input[player_nr].key; @@ -6083,38 +7255,31 @@ void CustomizeKeyboard(int player_nr) DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32, "Key:", FONT_INPUT_1_ACTIVE); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, - getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD); + getKeyNameFromKey(*customize_step[step_nr].key), font_nr_old); FadeIn(REDRAW_FIELD); - InitAnimation(); - while (!finished) { - if (PendingEvent()) /* got event */ - { - Event event; - - NextEvent(&event); + Event event; + if (NextValidEvent(&event)) + { switch (event.type) { case EVENT_KEYPRESS: { Key key = GetEventKey((KeyEvent *)&event, FALSE); - if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6)) + /* press 'Escape' to abort and keep the old key bindings */ + if (key == KSYM_Escape) { - if (key == KSYM_Escape) - FadeSkipNextFadeIn(); + FadeSkipNextFadeIn(); finished = TRUE; - break; - } - /* all keys configured -- wait for "Escape" or "Return" key */ - if (step_nr == 6) break; + } /* press 'Enter' to keep the existing key binding */ if (key == KSYM_Return) @@ -6130,9 +7295,9 @@ void CustomizeKeyboard(int player_nr) /* got new key binding */ *customize_step[step_nr].key = key; DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, - " ", FONT_VALUE_1); + " ", font_nr_new); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, - getKeyNameFromKey(key), FONT_VALUE_1); + getKeyNameFromKey(key), font_nr_new); step_nr++; /* un-highlight last query */ @@ -6141,11 +7306,12 @@ void CustomizeKeyboard(int player_nr) DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32, "Key:", FONT_MENU_1); - /* press 'Enter' to leave */ + /* all keys configured */ if (step_nr == 6) { - DrawText(mSX + 16, mSY + 15 * 32 + 16, - "Press Enter", FONT_TITLE_1); + finished = TRUE; + success = TRUE; + break; } @@ -6156,250 +7322,780 @@ void CustomizeKeyboard(int player_nr) "Key:", FONT_INPUT_1_ACTIVE); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, getKeyNameFromKey(*customize_step[step_nr].key), - FONT_VALUE_OLD); + font_nr_old); } break; - case EVENT_KEYRELEASE: - key_joystick_mapping = 0; - break; + case EVENT_KEYRELEASE: + key_joystick_mapping = 0; + break; + + default: + HandleOtherEvents(&event); + break; + } + } + + BackToFront(); + } + + /* write new key bindings back to player setup, if successfully finished */ + if (success) + setup.input[player_nr].key = custom_key; + + return success; +} + +void CustomizeKeyboard(int player_nr) +{ + boolean success = CustomizeKeyboardMain(player_nr); + + if (success) + { + int font_nr = FONT_TITLE_1; + int font_height = getFontHeight(font_nr); + int ypos1 = SYSIZE / 2 - font_height * 2; + int ypos2 = SYSIZE / 2 - font_height * 1; + unsigned int wait_frame_delay = 0; + unsigned int wait_frame_delay_value = 2000; + + ResetDelayCounter(&wait_frame_delay); + + ClearField(); + + DrawTextSCentered(ypos1, font_nr, "Keyboard"); + DrawTextSCentered(ypos2, font_nr, "configured!"); + + while (!DelayReached(&wait_frame_delay, wait_frame_delay_value)) + BackToFront(); + + ClearEventQueue(); + } + + DrawSetupScreen_Input(); +} + +/* game controller mapping generator by Gabriel Jacobo */ + +#define MARKER_BUTTON 1 +#define MARKER_AXIS_X 2 +#define MARKER_AXIS_Y 3 + +static boolean ConfigureJoystickMapButtonsAndAxes(SDL_Joystick *joystick) +{ +#if defined(TARGET_SDL2) + static boolean bitmaps_initialized = FALSE; + boolean screen_initialized = FALSE; + static Bitmap *controller, *button, *axis_x, *axis_y; + char *name; + boolean success = TRUE; + boolean done = FALSE, next = FALSE; + Event event; + int alpha = 200, alpha_step = -1; + int alpha_ticks = 0; + char mapping[4096], temp[4096]; + int font_name = MENU_SETUP_FONT_TITLE; + int font_info = MENU_SETUP_FONT_TEXT; + int spacing_name = menu.line_spacing_setup[SETUP_MODE_INPUT]; + int spacing_line = menu.line_spacing_setup[SETUP_MODE_INPUT]; + int spacing_para = menu.paragraph_spacing_setup[SETUP_MODE_INPUT]; + int ystep_name = getMenuTextStep(spacing_name, font_name); + int ystep_line = getMenuTextStep(spacing_line, font_info); + int ystep_para = getMenuTextStep(spacing_para, font_info); + int i, j; + + struct + { + int x, y; + int marker; + char *field; + int axis, button, hat, hat_value; + char mapping[4096]; + } + *step, *prev_step, steps[] = + { + { 356, 155, MARKER_BUTTON, "a", }, + { 396, 122, MARKER_BUTTON, "b", }, + { 320, 125, MARKER_BUTTON, "x", }, + { 358, 95, MARKER_BUTTON, "y", }, + { 162, 125, MARKER_BUTTON, "back", }, + { 216, 125, MARKER_BUTTON, "guide", }, + { 271, 125, MARKER_BUTTON, "start", }, + { 110, 200, MARKER_BUTTON, "dpleft", }, + { 146, 228, MARKER_BUTTON, "dpdown", }, + { 178, 200, MARKER_BUTTON, "dpright", }, + { 146, 172, MARKER_BUTTON, "dpup", }, + { 50, 40, MARKER_BUTTON, "leftshoulder", }, + { 88, -10, MARKER_AXIS_Y, "lefttrigger", }, + { 382, 40, MARKER_BUTTON, "rightshoulder", }, + { 346, -10, MARKER_AXIS_Y, "righttrigger", }, + { 73, 141, MARKER_BUTTON, "leftstick", }, + { 282, 210, MARKER_BUTTON, "rightstick", }, + { 73, 141, MARKER_AXIS_X, "leftx", }, + { 73, 141, MARKER_AXIS_Y, "lefty", }, + { 282, 210, MARKER_AXIS_X, "rightx", }, + { 282, 210, MARKER_AXIS_Y, "righty", }, + }; + + unsigned int event_frame_delay = 0; + unsigned int event_frame_delay_value = GAME_FRAME_DELAY; + + ResetDelayCounter(&event_frame_delay); + + if (!bitmaps_initialized) + { + controller = LoadCustomImage("joystick/controller.png"); + button = LoadCustomImage("joystick/button.png"); + axis_x = LoadCustomImage("joystick/axis_x.png"); + axis_y = LoadCustomImage("joystick/axis_y.png"); + + bitmaps_initialized = TRUE; + } + + name = getFormattedJoystickName(SDL_JoystickName(joystick)); + +#if DEBUG_JOYSTICKS + /* print info about the joystick we are watching */ + Error(ERR_DEBUG, "watching joystick %d: (%s)\n", + SDL_JoystickInstanceID(joystick), name); + Error(ERR_DEBUG, "joystick has %d axes, %d hats, %d balls, and %d buttons\n", + SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick), + SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick)); +#endif + + /* initialize mapping with GUID and name */ + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), temp, sizeof(temp)); + + snprintf(mapping, sizeof(mapping), "%s,%s,platform:%s,", + temp, name, SDL_GetPlatform()); + + /* loop through all steps (buttons and axes), getting joystick events */ + for (i = 0; i < SDL_arraysize(steps) && !done;) + { + Bitmap *marker = button; /* initialize with reliable default value */ + + step = &steps[i]; + strcpy(step->mapping, mapping); + step->axis = -1; + step->button = -1; + step->hat = -1; + step->hat_value = -1; + + marker = (step->marker == MARKER_BUTTON ? button : + step->marker == MARKER_AXIS_X ? axis_x : + step->marker == MARKER_AXIS_Y ? axis_y : marker); + + next = FALSE; + + while (!done && !next) + { + alpha += alpha_step * (int)(SDL_GetTicks() - alpha_ticks) / 5; + alpha_ticks = SDL_GetTicks(); + + if (alpha >= 255) + { + alpha = 255; + alpha_step = -1; + } + else if (alpha < 128) + { + alpha = 127; + alpha_step = 1; + } + + int controller_x = SX + (SXSIZE - controller->width) / 2; + int controller_y = SY + ystep_line; + + int marker_x = controller_x + step->x; + int marker_y = controller_y + step->y; + + int ystart1 = mSY - 2 * SY + controller_y + controller->height; + int ystart2 = ystart1 + ystep_name + ystep_line; + + ClearField(); + + DrawTextSCentered(ystart1, font_name, name); + + DrawTextSCentered(ystart2, font_info, + "Press buttons and move axes on"); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "your controller when indicated."); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "(Your controller may look different.)"); + ystart2 += ystep_para; + +#if defined(PLATFORM_ANDROID) + DrawTextSCentered(ystart2, font_info, + "To correct a mistake,"); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "press the 'back' button."); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "To skip a button or axis,"); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "press the 'menu' button."); +#else + DrawTextSCentered(ystart2, font_info, + "To correct a mistake,"); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "press the 'backspace' key."); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "To skip a button or axis,"); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "press the 'return' key."); + ystart2 += ystep_line; + DrawTextSCentered(ystart2, font_info, + "To exit, press the 'escape' key."); +#endif + + BlitBitmapMasked(controller, drawto, 0, 0, + controller->width, controller->height, + controller_x, controller_y); + + SDL_SetSurfaceBlendMode(marker->surface_masked, SDL_BLENDMODE_BLEND); + SDL_SetSurfaceAlphaMod(marker->surface_masked, alpha); + + BlitBitmapMasked(marker, drawto, 0, 0, + marker->width, marker->height, + marker_x, marker_y); + + if (!screen_initialized) + FadeIn(REDRAW_FIELD); + else + BackToFront(); + + screen_initialized = TRUE; + + while (NextValidEvent(&event)) + { + switch (event.type) + { + case SDL_JOYAXISMOTION: + if (event.jaxis.value > 20000 || + event.jaxis.value < -20000) + { + for (j = 0; j < i; j++) + if (steps[j].axis == event.jaxis.axis) + break; + + if (j == i) + { + if (step->marker != MARKER_AXIS_X && + step->marker != MARKER_AXIS_Y) + break; + + step->axis = event.jaxis.axis; + strcat(mapping, step->field); + snprintf(temp, sizeof(temp), ":a%u,", event.jaxis.axis); + strcat(mapping, temp); + i++; + next = TRUE; + } + } + + break; + + case SDL_JOYHATMOTION: + /* ignore centering; we're probably just coming back + to the center from the previous item we set */ + if (event.jhat.value == SDL_HAT_CENTERED) + break; + + for (j = 0; j < i; j++) + if (steps[j].hat == event.jhat.hat && + steps[j].hat_value == event.jhat.value) + break; + + if (j == i) + { + step->hat = event.jhat.hat; + step->hat_value = event.jhat.value; + strcat(mapping, step->field); + snprintf(temp, sizeof(temp), ":h%u.%u,", + event.jhat.hat, event.jhat.value ); + strcat(mapping, temp); + i++; + next = TRUE; + } + + break; + + case SDL_JOYBALLMOTION: + break; + + case SDL_JOYBUTTONUP: + for (j = 0; j < i; j++) + if (steps[j].button == event.jbutton.button) + break; + + if (j == i) + { + step->button = event.jbutton.button; + strcat(mapping, step->field); + snprintf(temp, sizeof(temp), ":b%u,", event.jbutton.button); + strcat(mapping, temp); + i++; + next = TRUE; + } + + break; + + case SDL_FINGERDOWN: + case SDL_MOUSEBUTTONDOWN: + /* skip this step */ + i++; + next = TRUE; + + break; + + case SDL_KEYDOWN: + if (event.key.keysym.sym == KSYM_BackSpace || + event.key.keysym.sym == KSYM_Back) + { + if (i == 0) + { + /* leave screen */ + success = FALSE; + done = TRUE; + + break; + } + + /* undo this step */ + prev_step = &steps[i - 1]; + strcpy(mapping, prev_step->mapping); + i--; + next = TRUE; + + break; + } + + if (event.key.keysym.sym == KSYM_space || + event.key.keysym.sym == KSYM_Return || + event.key.keysym.sym == KSYM_Menu) + { + /* skip this step */ + i++; + next = TRUE; + + break; + } + + if (event.key.keysym.sym == KSYM_Escape) + { + /* leave screen */ + success = FALSE; + done = TRUE; + } + + break; + + case SDL_QUIT: + program.exit_function(0); + break; + + default: + break; + } + + // do not handle events for longer than standard frame delay period + if (DelayReached(&event_frame_delay, event_frame_delay_value)) + break; + } + } + } + + if (success) + { +#if DEBUG_JOYSTICKS + Error(ERR_DEBUG, "New game controller mapping:\n\n%s\n\n", mapping); +#endif + + // activate mapping for this game + SDL_GameControllerAddMapping(mapping); + + // save mapping to personal mappings + SaveSetup_AddGameControllerMapping(mapping); + } + + /* wait until the last pending event was removed from event queue */ + while (NextValidEvent(&event)); + + return success; +#else + return TRUE; +#endif +} + +static int ConfigureJoystickMain(int player_nr) +{ + char *device_name = setup.input[player_nr].joy.device_name; + int joystick_nr = getJoystickNrFromDeviceName(device_name); + boolean joystick_active = CheckJoystickOpened(joystick_nr); + int success = FALSE; + int i; + + if (joystick.status == JOYSTICK_NOT_AVAILABLE) + return JOYSTICK_NOT_AVAILABLE; + + if (!joystick_active || !setup.input[player_nr].use_joystick) + return JOYSTICK_NOT_AVAILABLE; + + FadeSetEnterMenu(); + FadeOut(REDRAW_FIELD); + + // close all joystick devices (potentially opened as game controllers) + for (i = 0; i < SDL_NumJoysticks(); i++) + SDLCloseJoystick(i); + + // open joystick device as plain joystick to configure as game controller + SDL_Joystick *joystick = SDL_JoystickOpen(joystick_nr); + + // as the joystick was successfully opened before, this should not happen + if (joystick == NULL) + return FALSE; + + // create new game controller mapping (buttons and axes) for joystick device + success = ConfigureJoystickMapButtonsAndAxes(joystick); + + // close joystick (and maybe re-open as configured game controller later) + SDL_JoystickClose(joystick); + + // re-open all joystick devices (potentially as game controllers) + for (i = 0; i < SDL_NumJoysticks(); i++) + SDLOpenJoystick(i); + + // clear all joystick input actions for all joystick devices + SDLClearJoystickState(); + + return (success ? JOYSTICK_CONFIGURED : JOYSTICK_NOT_CONFIGURED); +} + +void ConfigureJoystick(int player_nr) +{ + boolean state = ConfigureJoystickMain(player_nr); + + if (state != JOYSTICK_NOT_CONFIGURED) + { + boolean success = (state == JOYSTICK_CONFIGURED); + char message1[MAX_OUTPUT_LINESIZE + 1]; + char *message2 = (success ? "configured!" : "not available!"); + char *device_name = setup.input[player_nr].joy.device_name; + int nr = getJoystickNrFromDeviceName(device_name) + 1; + int font_nr = FONT_TITLE_1; + int font_height = getFontHeight(font_nr); + int ypos1 = SYSIZE / 2 - font_height * 2; + int ypos2 = SYSIZE / 2 - font_height * 1; + unsigned int wait_frame_delay = 0; + unsigned int wait_frame_delay_value = 2000; + + ResetDelayCounter(&wait_frame_delay); + + ClearField(); - default: - HandleOtherEvents(&event); - break; - } - } + sprintf(message1, "Joystick %d", nr); - DoAnimation(); - BackToFront(); + DrawTextSCentered(ypos1, font_nr, message1); + DrawTextSCentered(ypos2, font_nr, message2); - /* don't eat all CPU time */ - Delay(10); - } + while (!DelayReached(&wait_frame_delay, wait_frame_delay_value)) + BackToFront(); - /* write new key bindings back to player setup */ - setup.input[player_nr].key = custom_key; + ClearEventQueue(); + } - StopAnimation(); DrawSetupScreen_Input(); } -static boolean CalibrateJoystickMain(int player_nr) +static boolean ConfigureVirtualButtonsMain(void) { - int new_joystick_xleft = JOYSTICK_XMIDDLE; - int new_joystick_xright = JOYSTICK_XMIDDLE; - int new_joystick_yupper = JOYSTICK_YMIDDLE; - int new_joystick_ylower = JOYSTICK_YMIDDLE; - int new_joystick_xmiddle, new_joystick_ymiddle; - - int joystick_fd = joystick.fd[player_nr]; - int x, y, last_x, last_y, xpos = 8, ypos = 3; - boolean check[3][3]; - int check_remaining = 3 * 3; - int joy_x, joy_y; - int joy_value; - int result = -1; + static char *customize_step_text[] = + { + "Move Left", + "Move Right", + "Move Up", + "Move Down", + "Snap Field", + "Drop Element" + }; + char grid_button[] = + { + CHAR_GRID_BUTTON_LEFT, + CHAR_GRID_BUTTON_RIGHT, + CHAR_GRID_BUTTON_UP, + CHAR_GRID_BUTTON_DOWN, + CHAR_GRID_BUTTON_SNAP, + CHAR_GRID_BUTTON_DROP + }; + int font_nr = FONT_INPUT_1_ACTIVE; + int font_height = getFontHeight(font_nr); + int ypos1 = SYSIZE / 2 - font_height * 2; + int ypos2 = SYSIZE / 2 - font_height * 1; + boolean success = FALSE; + boolean finished = FALSE; + int step_nr = 0; + char grid_button_draw = CHAR_GRID_BUTTON_NONE; + char grid_button_old[MAX_GRID_XSIZE][MAX_GRID_YSIZE]; + char grid_button_tmp[MAX_GRID_XSIZE][MAX_GRID_YSIZE]; + boolean set_grid_button = FALSE; + int nr = GRID_ACTIVE_NR(); + int x, y; - if (joystick.status == JOYSTICK_NOT_AVAILABLE) - return FALSE; + for (x = 0; x < MAX_GRID_XSIZE; x++) + for (y = 0; y < MAX_GRID_YSIZE; y++) + grid_button_old[x][y] = grid_button_tmp[x][y] = overlay.grid_button[x][y]; - if (joystick_fd < 0 || !setup.input[player_nr].use_joystick) - return FALSE; + overlay.grid_button_highlight = grid_button[step_nr]; FadeSetEnterMenu(); FadeOut(REDRAW_FIELD); ClearField(); - for (y = 0; y < 3; y++) + DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Virtual Buttons"); + DrawTextSCentered(ypos1, font_nr, "Select tiles to"); + DrawTextSCentered(ypos2, font_nr, customize_step_text[step_nr]); + + FadeIn(REDRAW_FIELD); + + SetOverlayShowGrid(TRUE); + + while (!finished) { - for (x = 0; x < 3; x++) + Event event; + + while (NextValidEvent(&event)) { - DrawFixedGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0); - check[x][y] = FALSE; - } - } + switch (event.type) + { + case EVENT_KEYPRESS: + { + Key key = GetEventKey((KeyEvent *)&event, FALSE); - DrawTextSCentered(mSY - SY + 6 * 32, FONT_TITLE_1, "Rotate joystick"); - DrawTextSCentered(mSY - SY + 7 * 32, FONT_TITLE_1, "in all directions"); - DrawTextSCentered(mSY - SY + 9 * 32, FONT_TITLE_1, "if all balls"); - DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,"); - DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick"); - DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and"); - DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!"); + /* press 'Escape' to abort and keep the old key bindings */ + if (key == KSYM_Escape) + { + for (x = 0; x < MAX_GRID_XSIZE; x++) + for (y = 0; y < MAX_GRID_YSIZE; y++) + overlay.grid_button[x][y] = grid_button_old[x][y]; - joy_value = Joystick(player_nr); - last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0); - last_y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0); + FadeSkipNextFadeIn(); - /* eventually uncalibrated center position (joystick could be uncentered) */ - if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL)) - return FALSE; + finished = TRUE; - new_joystick_xmiddle = joy_x; - new_joystick_ymiddle = joy_y; + break; + } - DrawFixedGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0); + /* press 'Enter' to keep the existing key binding */ + if (key == KSYM_Return || +#if defined(TARGET_SDL2) + key == KSYM_Menu || +#endif + key == KSYM_space) + { + step_nr++; + } + else if (key == KSYM_BackSpace +#if defined(TARGET_SDL2) + || + key == KSYM_Back +#endif + ) + { + if (step_nr == 0) + { + FadeSkipNextFadeIn(); - FadeIn(REDRAW_FIELD); + finished = TRUE; - while (Joystick(player_nr) & JOY_BUTTON); /* wait for released button */ - InitAnimation(); + break; + } - while (result < 0) - { - if (PendingEvent()) /* got event */ - { - Event event; + step_nr--; + } + else + { + break; + } - NextEvent(&event); + /* all virtual buttons configured */ + if (step_nr == 6) + { + finished = TRUE; + success = TRUE; - switch (event.type) - { - case EVENT_KEYPRESS: - switch (GetEventKey((KeyEvent *)&event, TRUE)) - { - case KSYM_Return: - if (check_remaining == 0) - result = 1; break; + } - case KSYM_Escape: - FadeSkipNextFadeIn(); - result = 0; - break; + for (x = 0; x < MAX_GRID_XSIZE; x++) + for (y = 0; y < MAX_GRID_YSIZE; y++) + grid_button_tmp[x][y] = overlay.grid_button[x][y]; - default: - break; + overlay.grid_button_highlight = grid_button[step_nr]; + + /* query next virtual button */ + + ClearField(); + + DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Virtual Buttons"); + DrawTextSCentered(ypos1, font_nr, "Select tiles to"); + DrawTextSCentered(ypos2, font_nr, customize_step_text[step_nr]); } break; - case EVENT_KEYRELEASE: + case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; - default: - HandleOtherEvents(&event); + case EVENT_BUTTONPRESS: + case EVENT_BUTTONRELEASE: + { + ButtonEvent *button = (ButtonEvent *)&event; + + button->x += video.screen_xoffset; + button->y += video.screen_yoffset; + + x = button->x * overlay.grid_xsize / video.screen_width; + y = button->y * overlay.grid_ysize / video.screen_height; + + if (button->type == EVENT_BUTTONPRESS) + { + button_status = button->button; + + grid_button_draw = + (overlay.grid_button[x][y] != grid_button[step_nr] ? + grid_button[step_nr] : CHAR_GRID_BUTTON_NONE); + + set_grid_button = TRUE; + } + else + { + button_status = MB_RELEASED; + } + } break; - } - } - if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL)) - return FALSE; + case EVENT_MOTIONNOTIFY: + { + MotionEvent *motion = (MotionEvent *)&event; + + motion->x += video.screen_xoffset; + motion->y += video.screen_yoffset; - new_joystick_xleft = MIN(new_joystick_xleft, joy_x); - new_joystick_xright = MAX(new_joystick_xright, joy_x); - new_joystick_yupper = MIN(new_joystick_yupper, joy_y); - new_joystick_ylower = MAX(new_joystick_ylower, joy_y); + x = motion->x * overlay.grid_xsize / video.screen_width; + y = motion->y * overlay.grid_ysize / video.screen_height; - setup.input[player_nr].joy.xleft = new_joystick_xleft; - setup.input[player_nr].joy.yupper = new_joystick_yupper; - setup.input[player_nr].joy.xright = new_joystick_xright; - setup.input[player_nr].joy.ylower = new_joystick_ylower; - setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle; - setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle; + set_grid_button = TRUE; + } + break; - CheckJoystickData(); +#if defined(TARGET_SDL2) + case SDL_WINDOWEVENT: + HandleWindowEvent((WindowEvent *) &event); - joy_value = Joystick(player_nr); + // check if device has been rotated + if (nr != GRID_ACTIVE_NR()) + { + nr = GRID_ACTIVE_NR(); - if (joy_value & JOY_BUTTON && check_remaining == 0) - result = 1; + for (x = 0; x < MAX_GRID_XSIZE; x++) + for (y = 0; y < MAX_GRID_YSIZE; y++) + grid_button_old[x][y] = grid_button_tmp[x][y] = + overlay.grid_button[x][y]; + } - x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0); - y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0); + break; - if (x != last_x || y != last_y) - { - DrawFixedGraphic(xpos + last_x, ypos + last_y, - IMG_MENU_CALIBRATE_YELLOW, 0); - DrawFixedGraphic(xpos + x, ypos + y, - IMG_MENU_CALIBRATE_RED, 0); + case SDL_APP_WILLENTERBACKGROUND: + case SDL_APP_DIDENTERBACKGROUND: + case SDL_APP_WILLENTERFOREGROUND: + case SDL_APP_DIDENTERFOREGROUND: + HandlePauseResumeEvent((PauseResumeEvent *) &event); + break; +#endif - last_x = x; - last_y = y; + default: + HandleOtherEvents(&event); + break; + } - if (check_remaining > 0 && !check[x+1][y+1]) + if (set_grid_button) { - check[x+1][y+1] = TRUE; - check_remaining--; + overlay.grid_button[x][y] = + (grid_button_draw != CHAR_GRID_BUTTON_NONE ? grid_button_draw : + grid_button_tmp[x][y] == grid_button[step_nr] ? CHAR_GRID_BUTTON_NONE : + grid_button_tmp[x][y]); + + set_grid_button = FALSE; } } - DoAnimation(); BackToFront(); - - /* don't eat all CPU time */ - Delay(10); } - /* calibrated center position (joystick should now be centered) */ - if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL)) - return FALSE; - - new_joystick_xmiddle = joy_x; - new_joystick_ymiddle = joy_y; - - StopAnimation(); - - /* wait until the last pressed button was released */ - while (Joystick(player_nr) & JOY_BUTTON) - { - if (PendingEvent()) /* got event */ - { - Event event; + for (x = 0; x < MAX_GRID_XSIZE; x++) + for (y = 0; y < MAX_GRID_YSIZE; y++) + setup.touch.grid_button[nr][x][y] = overlay.grid_button[x][y]; - NextEvent(&event); - HandleOtherEvents(&event); + overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE; - Delay(10); - } - } + SetOverlayShowGrid(FALSE); - return TRUE; + return success; } -void CalibrateJoystick(int player_nr) +void ConfigureVirtualButtons(void) { - if (!CalibrateJoystickMain(player_nr)) + boolean success = ConfigureVirtualButtonsMain(); + + if (success) { - char *device_name = setup.input[player_nr].joy.device_name; - int nr = getJoystickNrFromDeviceName(device_name) + 1; - int xpos = mSX - SX; - int ypos = mSY - SY; + int font_nr = FONT_TITLE_1; + int font_height = getFontHeight(font_nr); + int ypos1 = SYSIZE / 2 - font_height * 2; + int ypos2 = SYSIZE / 2 - font_height * 1; + unsigned int wait_frame_delay = 0; + unsigned int wait_frame_delay_value = 2000; + + ResetDelayCounter(&wait_frame_delay); ClearField(); - DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr); - DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! "); - BackToFront(); + DrawTextSCentered(ypos1, font_nr, "Virtual buttons"); + DrawTextSCentered(ypos2, font_nr, "configured!"); - Delay(2000); /* show error message for a short time */ + while (!DelayReached(&wait_frame_delay, wait_frame_delay_value)) + BackToFront(); ClearEventQueue(); } - - DrawSetupScreen_Input(); } -void DrawSetupScreen() +void DrawSetupScreen(void) { - DeactivateJoystick(); - - SetMainBackgroundImage(IMG_BACKGROUND_SETUP); - if (setup_mode == SETUP_MODE_INPUT) DrawSetupScreen_Input(); else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED) DrawChooseTree(&game_speed_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) DrawChooseTree(&scroll_delay_current); - else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE) - DrawChooseTree(&screen_mode_current); + else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) + DrawChooseTree(&snapshot_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) DrawChooseTree(&window_size_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE) DrawChooseTree(&scaling_type_current); + else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING) + DrawChooseTree(&rendering_mode_current); + else if (setup_mode == SETUP_MODE_CHOOSE_VSYNC) + DrawChooseTree(&vsync_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS) DrawChooseTree(&artwork.gfx_current); else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS) @@ -6418,14 +8114,23 @@ void DrawSetupScreen() DrawChooseTree(&move_distance_current); else if (setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) DrawChooseTree(&drop_distance_current); + else if (setup_mode == SETUP_MODE_CHOOSE_TRANSPARENCY) + DrawChooseTree(&transparency_current); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_0) + DrawChooseTree(&grid_size_current[0][0]); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_0) + DrawChooseTree(&grid_size_current[0][1]); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_1) + DrawChooseTree(&grid_size_current[1][0]); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_1) + DrawChooseTree(&grid_size_current[1][1]); else DrawSetupScreen_Generic(); - PlayMenuSound(); - PlayMenuMusic(); + PlayMenuSoundsAndMusic(); } -void RedrawSetupScreenAfterFullscreenToggle() +void RedrawSetupScreenAfterFullscreenToggle(void) { if (setup_mode == SETUP_MODE_GRAPHICS || setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) @@ -6437,6 +8142,24 @@ void RedrawSetupScreenAfterFullscreenToggle() } } +void RedrawSetupScreenAfterScreenRotation(int nr) +{ + int x, y; + + if (setup_mode == SETUP_MODE_TOUCH) + { + // update virtual button settings (depending on screen orientation) + DrawSetupScreen(); + } + else if (setup_mode == SETUP_MODE_CONFIG_VIRT_BUTTONS) + { + // save already configured virtual buttons + for (x = 0; x < MAX_GRID_XSIZE; x++) + for (y = 0; y < MAX_GRID_YSIZE; y++) + setup.touch.grid_button[nr][x][y] = overlay.grid_button[x][y]; + } +} + void HandleSetupScreen(int mx, int my, int dx, int dy, int button) { if (setup_mode == SETUP_MODE_INPUT) @@ -6445,12 +8168,16 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) HandleChooseTree(mx, my, dx, dy, button, &game_speed_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current); - else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE) - HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current); + else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) + HandleChooseTree(mx, my, dx, dy, button, &snapshot_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) HandleChooseTree(mx, my, dx, dy, button, &window_size_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE) HandleChooseTree(mx, my, dx, dy, button, &scaling_type_current); + else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING) + HandleChooseTree(mx, my, dx, dy, button, &rendering_mode_current); + else if (setup_mode == SETUP_MODE_CHOOSE_VSYNC) + HandleChooseTree(mx, my, dx, dy, button, &vsync_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS) HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current); else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS) @@ -6469,12 +8196,32 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) HandleChooseTree(mx, my, dx, dy, button, &move_distance_current); else if (setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) HandleChooseTree(mx, my, dx, dy, button, &drop_distance_current); + else if (setup_mode == SETUP_MODE_CHOOSE_TRANSPARENCY) + HandleChooseTree(mx, my, dx, dy, button, &transparency_current); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_0) + HandleChooseTree(mx, my, dx, dy, button, &grid_size_current[0][0]); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_0) + HandleChooseTree(mx, my, dx, dy, button, &grid_size_current[0][1]); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_XSIZE_1) + HandleChooseTree(mx, my, dx, dy, button, &grid_size_current[1][0]); + else if (setup_mode == SETUP_MODE_CHOOSE_GRID_YSIZE_1) + HandleChooseTree(mx, my, dx, dy, button, &grid_size_current[1][1]); else HandleSetupScreen_Generic(mx, my, dx, dy, button); } -void HandleGameActions() +void HandleGameActions(void) { + if (setup.ask_on_game_over) + CheckGameOver(); + + if (game.restart_game_message != NULL) + { + RequestRestartGame(game.restart_game_message); + + return; + } + if (game_status != GAME_MODE_PLAYING) return; @@ -6511,6 +8258,16 @@ static void getScreenMenuButtonPos(int *x, int *y, int gadget_id) *y = mSY + TILEY * MENU_SCREEN_START_YPOS; break; + case SCREEN_CTRL_ID_INSERT_SOLUTION: + *x = mSX + GDI_ACTIVE_POS(menu.main.button.insert_solution.x); + *y = mSY + GDI_ACTIVE_POS(menu.main.button.insert_solution.y); + break; + + case SCREEN_CTRL_ID_PLAY_SOLUTION: + *x = mSX + GDI_ACTIVE_POS(menu.main.button.play_solution.x); + *y = mSY + GDI_ACTIVE_POS(menu.main.button.play_solution.y); + break; + default: Error(ERR_EXIT, "unknown gadget ID %d", gadget_id); } @@ -6553,6 +8310,20 @@ static struct SCREEN_MASK_INPUT, "next player" }, + { + IMG_MENU_BUTTON_INSERT_SOLUTION, IMG_MENU_BUTTON_INSERT_SOLUTION_ACTIVE, + getScreenMenuButtonPos, + SCREEN_CTRL_ID_INSERT_SOLUTION, + SCREEN_MASK_MAIN_HAS_SOLUTION, + "insert solution tape" + }, + { + IMG_MENU_BUTTON_PLAY_SOLUTION, IMG_MENU_BUTTON_PLAY_SOLUTION_ACTIVE, + getScreenMenuButtonPos, + SCREEN_CTRL_ID_PLAY_SOLUTION, + SCREEN_MASK_MAIN_HAS_SOLUTION, + "play solution tape" + }, }; static struct @@ -6597,7 +8368,27 @@ static struct } }; -static void CreateScreenMenubuttons() +static struct +{ + int graphic; + int gadget_id; + int x, y; + int size; + char *value; + char *infotext; +} textinput_info[NUM_SCREEN_TEXTINPUT] = +{ + { + IMG_SETUP_INPUT_TEXT, + SCREEN_CTRL_ID_NETWORK_SERVER, + -1, -1, /* these values are not constant, but can change at runtime */ + MAX_SETUP_TEXT_INPUT_LEN, + network_server_hostname, + "Network Server Hostname / IP" + }, +}; + +static void CreateScreenMenubuttons(void) { struct GadgetInfo *gi; unsigned int event_mask; @@ -6611,12 +8402,23 @@ static void CreateScreenMenubuttons() int gd_x1, gd_x2, gd_y1, gd_y2; int id = menubutton_info[i].gadget_id; - event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; + if (menubutton_info[i].screen_mask == SCREEN_MASK_MAIN_HAS_SOLUTION) + event_mask = GD_EVENT_RELEASED; + else + event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; menubutton_info[i].get_gadget_position(&x, &y, id); - width = SC_MENUBUTTON_XSIZE; - height = SC_MENUBUTTON_YSIZE; + if (menubutton_info[i].screen_mask == SCREEN_MASK_MAIN_HAS_SOLUTION) + { + width = graphic_info[menubutton_info[i].gfx_pressed].width; + height = graphic_info[menubutton_info[i].gfx_pressed].height; + } + else + { + width = SC_MENUBUTTON_XSIZE; + height = SC_MENUBUTTON_YSIZE; + } gfx_unpressed = menubutton_info[i].gfx_unpressed; gfx_pressed = menubutton_info[i].gfx_pressed; @@ -6629,6 +8431,7 @@ static void CreateScreenMenubuttons() gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, + GDI_IMAGE_ID, gfx_unpressed, GDI_INFO_TEXT, menubutton_info[i].infotext, GDI_X, x, GDI_Y, y, @@ -6650,7 +8453,7 @@ static void CreateScreenMenubuttons() } } -static void CreateScreenScrollbuttons() +static void CreateScreenScrollbuttons(void) { struct GadgetInfo *gi; unsigned int event_mask; @@ -6696,6 +8499,7 @@ static void CreateScreenScrollbuttons() gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, + GDI_IMAGE_ID, gfx_unpressed, GDI_INFO_TEXT, scrollbutton_info[i].infotext, GDI_X, x, GDI_Y, y, @@ -6717,7 +8521,7 @@ static void CreateScreenScrollbuttons() } } -static void CreateScreenScrollbars() +static void CreateScreenScrollbars(void) { int i; @@ -6768,6 +8572,7 @@ static void CreateScreenScrollbars() gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, + GDI_IMAGE_ID, gfx_unpressed, GDI_INFO_TEXT, scrollbar_info[i].infotext, GDI_X, x, GDI_Y, y, @@ -6797,19 +8602,63 @@ static void CreateScreenScrollbars() } } -void CreateScreenGadgets() +static void CreateScreenTextInputGadgets(void) { - int last_game_status = game_status; /* save current game status */ + int i; + + for (i = 0; i < NUM_SCREEN_TEXTINPUT; i++) + { + int graphic = textinput_info[i].graphic; + struct GraphicInfo *gd = &graphic_info[graphic]; + int gd_x1 = gd->src_x; + int gd_y1 = gd->src_y; + int gd_x2 = gd->src_x + gd->active_xoffset; + int gd_y2 = gd->src_y + gd->active_yoffset; + struct GadgetInfo *gi; + unsigned int event_mask; + int id = textinput_info[i].gadget_id; + int x = textinput_info[i].x; + int y = textinput_info[i].y; + + event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING; + + gi = CreateGadget(GDI_CUSTOM_ID, id, + GDI_CUSTOM_TYPE_ID, i, + GDI_INFO_TEXT, textinput_info[i].infotext, + GDI_X, SX + x, + GDI_Y, SY + y, + GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC, + GDI_TEXT_VALUE, textinput_info[i].value, + GDI_TEXT_SIZE, textinput_info[i].size, + GDI_TEXT_FONT, getSetupValueFont(TYPE_STRING, NULL), + GDI_TEXT_FONT_ACTIVE, FONT_TEXT_1, + GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, + GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, + GDI_BORDER_SIZE, gd->border_size, gd->border_size, + GDI_DESIGN_WIDTH, gd->width, + GDI_EVENT_MASK, event_mask, + GDI_CALLBACK_ACTION, HandleScreenGadgets, + GDI_CALLBACK_ACTION_ALWAYS, TRUE, + GDI_END); + + if (gi == NULL) + Error(ERR_EXIT, "cannot create gadget"); + + screen_gadget[id] = gi; + } +} +void CreateScreenGadgets(void) +{ CreateScreenMenubuttons(); CreateScreenScrollbuttons(); CreateScreenScrollbars(); - game_status = last_game_status; /* restore current game status */ + CreateScreenTextInputGadgets(); } -void FreeScreenGadgets() +void FreeScreenGadgets(void) { int i; @@ -6826,6 +8675,33 @@ void MapScreenMenuGadgets(int screen_mask) MapGadget(screen_gadget[menubutton_info[i].gadget_id]); } +static void UnmapScreenMenuGadgets(int screen_mask) +{ + int i; + + for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++) + { + if (screen_mask & menubutton_info[i].screen_mask) + { + UnmapGadget(screen_gadget[menubutton_info[i].gadget_id]); + + if (screen_mask & SCREEN_MASK_MAIN_HAS_SOLUTION) + DrawBackground(screen_gadget[menubutton_info[i].gadget_id]->x, + screen_gadget[menubutton_info[i].gadget_id]->y, + screen_gadget[menubutton_info[i].gadget_id]->width, + screen_gadget[menubutton_info[i].gadget_id]->height); + } + } +} + +void UpdateScreenMenuGadgets(int screen_mask, boolean map_gadgets) +{ + if (map_gadgets) + MapScreenMenuGadgets(screen_mask); + else + UnmapScreenMenuGadgets(screen_mask); +} + void MapScreenGadgets(int num_entries) { int i; @@ -6849,7 +8725,9 @@ static void HandleScreenGadgets(struct GadgetInfo *gi) { int id = gi->custom_id; int button = gi->event.button; - int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + int step = (button == MB_LEFTBUTTON ? 1 : + button == MB_MIDDLEBUTTON ? 5 : + button == MB_RIGHTBUTTON ? 10 : 1); switch (id) { @@ -6869,6 +8747,14 @@ static void HandleScreenGadgets(struct GadgetInfo *gi) HandleSetupScreen_Input_Player(step, +1); break; + case SCREEN_CTRL_ID_INSERT_SOLUTION: + InsertSolutionTape(); + break; + + case SCREEN_CTRL_ID_PLAY_SOLUTION: + PlaySolutionTape(); + break; + case SCREEN_CTRL_ID_SCROLL_UP: if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); @@ -6876,6 +8762,8 @@ static void HandleScreenGadgets(struct GadgetInfo *gi) HandleChooseLevelNr(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); + else if (game_status == GAME_MODE_INFO) + HandleInfoScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); break; case SCREEN_CTRL_ID_SCROLL_DOWN: @@ -6885,6 +8773,8 @@ static void HandleScreenGadgets(struct GadgetInfo *gi) HandleChooseLevelNr(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); + else if (game_status == GAME_MODE_INFO) + HandleInfoScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); break; case SCREEN_CTRL_ID_SCROLL_VERTICAL: @@ -6894,9 +8784,83 @@ static void HandleScreenGadgets(struct GadgetInfo *gi) HandleChooseLevelNr(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE); + else if (game_status == GAME_MODE_INFO) + HandleInfoScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE); + break; + + case SCREEN_CTRL_ID_NETWORK_SERVER: + { + if (!strEqual(gi->textinput.value, "")) + { + setString(&setup.network_server_hostname, gi->textinput.value); + + network.server_host = setup.network_server_hostname; + } + else + { + setString(&setup.network_server_hostname, STR_NETWORK_AUTO_DETECT); + + network.server_host = NULL; + } + + if (strEqual(network.server_host, STR_NETWORK_AUTO_DETECT)) + network.server_host = NULL; + + execSetupGame_setNetworkServerText(); + + DrawSetupScreen(); + break; + } default: break; } } + +void DumpScreenIdentifiers(void) +{ + int i; + + Print("Active screen elements on current screen:\n"); + + for (i = 0; main_controls[i].nr != -1; i++) + { + struct MainControlInfo *mci = &main_controls[i]; + + if (mci->button_graphic != -1) + { + char *token = getTokenFromImageID(mci->button_graphic); + + Print("- '%s'\n", token); + } + } + + Print("Done.\n"); +} + +boolean DoScreenAction(int image_id) +{ + int i; + + if (game_status != GAME_MODE_MAIN) + return FALSE; + + for (i = 0; main_controls[i].nr != -1; i++) + { + struct MainControlInfo *mci = &main_controls[i]; + struct MenuPosInfo *pos = mci->pos_button; + + if (mci->button_graphic == image_id) + { + int x = mSX + pos->x; + int y = mSY + pos->y; + + HandleMainMenu(x, y, 0, 0, MB_MENU_CHOICE); + + return TRUE; + } + } + + return FALSE; +}