X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ftools.c;h=627c77c61f842840eefe6ca162e4482776df9728;hb=9e5b242142cda73a8b1ae8ae52aa927999b5481d;hp=a3e5306835f7082e83a21f22c3dc053f13f5257d;hpb=1e23125074b86c5eb1254037a81a3e9062152b7f;p=rocksndiamonds.git diff --git a/src/tools.c b/src/tools.c index a3e53068..627c77c6 100644 --- a/src/tools.c +++ b/src/tools.c @@ -165,6 +165,14 @@ static struct DoorPartControlInfo door_part_controls[] = } }; +static struct XY xy_topdown[] = +{ + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } +}; + // forward declaration for internal use static void UnmapToolButtons(void); @@ -512,6 +520,10 @@ static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height, Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status); Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr; + // may happen for "border.draw_masked.*" with undefined "global.border.*" + if (src_bitmap == NULL) + return; + if (x == -1 && y == -1) return; @@ -763,7 +775,7 @@ void BackToFront(void) DrawFramesPerSecond(); // remove playfield redraw before potentially merging with doors redraw - if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE)) + if (DrawingDeactivated(REAL_SX, REAL_SY)) redraw_mask &= ~REDRAW_FIELD; // redraw complete window if both playfield and (some) doors need redraw @@ -1091,7 +1103,14 @@ void FadeSkipNextFadeOut(void) FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP); } -static Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic) +static int getGlobalGameStatus(int status) +{ + return (status == GAME_MODE_PSEUDO_TYPENAME ? GAME_MODE_MAIN : + status == GAME_MODE_SCOREINFO ? GAME_MODE_SCORES : + status); +} + +Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic) { if (graphic == IMG_UNDEFINED) return NULL; @@ -1113,14 +1132,14 @@ static Bitmap *getGlobalBorderBitmap(int graphic) return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER); } -Bitmap *getGlobalBorderBitmapFromStatus(int status) +Bitmap *getGlobalBorderBitmapFromStatus(int status_raw) { + int status = getGlobalGameStatus(status_raw); int graphic = - (status == GAME_MODE_MAIN || - status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN : - status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES : - status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR : - status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING : + (status == GAME_MODE_MAIN ? IMG_GLOBAL_BORDER_MAIN : + status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES : + status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR : + status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING : IMG_GLOBAL_BORDER); return getGlobalBorderBitmap(graphic); @@ -1422,7 +1441,7 @@ void FloodFillLevelExt(int start_x, int start_y, int fill_element, int max_fieldx, int max_fieldy) { static struct XY stack_buffer[MAX_LEV_FIELDX * MAX_LEV_FIELDY]; - static struct XY check[4] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } }; + struct XY *check = xy_topdown; int old_element = field[start_x][start_y]; int stack_pos = 0; @@ -1490,8 +1509,9 @@ int getGraphicAnimationFrameXY(int graphic, int lx, int ly) int ysize = MAX(1, g->anim_frames / xsize); int xoffset = g->anim_start_frame % xsize; int yoffset = g->anim_start_frame % ysize; - int x = (lx + xoffset + xsize) % xsize; - int y = (ly + yoffset + ysize) % ysize; + // may be needed if screen field is significantly larger than playfield + int x = (lx + xoffset + SCR_FIELDX * xsize) % xsize; + int y = (ly + yoffset + SCR_FIELDY * ysize) % ysize; int sync_frame = y * xsize + x; return sync_frame % g->anim_frames; @@ -1499,14 +1519,19 @@ int getGraphicAnimationFrameXY(int graphic, int lx, int ly) else if (graphic_info[graphic].anim_mode & ANIM_RANDOM_STATIC) { struct GraphicInfo *g = &graphic_info[graphic]; - int x = (lx + lev_fieldx) % lev_fieldx; - int y = (ly + lev_fieldy) % lev_fieldy; + // may be needed if screen field is significantly larger than playfield + int x = (lx + SCR_FIELDX * lev_fieldx) % lev_fieldx; + int y = (ly + SCR_FIELDY * lev_fieldy) % lev_fieldy; int sync_frame = GfxRandomStatic[x][y]; return sync_frame % g->anim_frames; } + else + { + int sync_frame = (IN_LEV_FIELD(lx, ly) ? GfxFrame[lx][ly] : -1); - return getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]); + return getGraphicAnimationFrame(graphic, sync_frame); + } } void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap) @@ -1996,11 +2021,11 @@ void DrawScreenElementExt(int x, int y, int dx, int dy, int element, int graphic; int frame; - if (element == EL_EMPTY) - element = GfxElementEmpty[lx][ly]; - if (IN_LEV_FIELD(lx, ly)) { + if (element == EL_EMPTY) + element = GfxElementEmpty[lx][ly]; + SetRandomAnimationValue(lx, ly); graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]); @@ -2276,13 +2301,7 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) int sx = SCREENX(x), sy = SCREENY(y); int element; int i; - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; + struct XY *xy = xy_topdown; if (!IN_LEV_FIELD(x, y)) return; @@ -2297,8 +2316,8 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) // crumble field borders towards direct neighbour fields for (i = 0; i < 4; i++) { - int xx = x + xy[i][0]; - int yy = y + xy[i][1]; + int xx = x + xy[i].x; + int yy = y + xy[i].y; element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); @@ -2332,10 +2351,10 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) // crumble field borders of direct neighbour fields for (i = 0; i < 4; i++) { - int xx = x + xy[i][0]; - int yy = y + xy[i][1]; - int sxx = sx + xy[i][0]; - int syy = sy + xy[i][1]; + int xx = x + xy[i].x; + int yy = y + xy[i].y; + int sxx = sx + xy[i].x; + int syy = sy + xy[i].y; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy)) @@ -2428,22 +2447,16 @@ void DrawLevelFieldCrumbledDigging(int x, int y, int direction, void DrawLevelFieldCrumbledNeighbours(int x, int y) { int sx = SCREENX(x), sy = SCREENY(y); - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; + struct XY *xy = xy_topdown; int i; // crumble direct neighbour fields (required for field borders) for (i = 0; i < 4; i++) { - int xx = x + xy[i][0]; - int yy = y + xy[i][1]; - int sxx = sx + xy[i][0]; - int syy = sy + xy[i][1]; + int xx = x + xy[i].x; + int yy = y + xy[i].y; + int sxx = sx + xy[i].x; + int syy = sy + xy[i].y; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy) || @@ -2517,6 +2530,11 @@ void DrawScreenGraphic(int x, int y, int graphic, int frame) } } +void DrawLevelGraphic(int x, int y, int graphic, int frame) +{ + DrawScreenGraphic(SCREENX(x), SCREENY(y), graphic, frame); +} + void DrawScreenElement(int x, int y, int element) { int mask_mode = NO_MASKING; @@ -2864,9 +2882,9 @@ static void AnimateEnvelope(int envelope_nr, int anim_mode, int action) int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND); boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); - unsigned int anim_delay = 0; int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2); + DelayCounter anim_delay = { anim_delay_value }; int font_nr = FONT_ENVELOPE_1 + envelope_nr; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); @@ -2903,16 +2921,16 @@ static void AnimateEnvelope(int envelope_nr, int anim_mode, int action) for (xx = 0; xx < xsize; xx++) DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr); - DrawTextBuffer(sx + font_width, sy + font_height, - level.envelope[envelope_nr].text, font_nr, max_xsize, - xsize - 2, ysize - 2, 0, mask_mode, - level.envelope[envelope_nr].autowrap, - level.envelope[envelope_nr].centered, FALSE); + DrawTextArea(sx + font_width, sy + font_height, + level.envelope[envelope_nr].text, font_nr, max_xsize, + xsize - 2, ysize - 2, 0, mask_mode, + level.envelope[envelope_nr].autowrap, + level.envelope[envelope_nr].centered, FALSE); redraw_mask |= REDRAW_FIELD; BackToFront(); - SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame); + SkipUntilDelayReached(&anim_delay, &i, last_frame); } ClearAutoRepeatKeyEvents(); @@ -3182,7 +3200,7 @@ static void AnimateEnvelopeRequest(int anim_mode, int action) boolean no_delay = (tape.warp_forward); int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal); int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2); - unsigned int anim_delay = 0; + DelayCounter anim_delay = { anim_delay_value }; int tile_size = MAX(request.step_offset, 1); int max_xsize = request.width / tile_size; @@ -3255,7 +3273,7 @@ static void AnimateEnvelopeRequest(int anim_mode, int action) BackToFront(); - SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame); + SkipUntilDelayReached(&anim_delay, &i, last_frame); } ClearAutoRepeatKeyEvents(); @@ -3526,15 +3544,17 @@ static void DrawPreviewLevelInfo(int mode) static void DrawPreviewLevelExt(boolean restart) { - static unsigned int scroll_delay = 0; - static unsigned int label_delay = 0; + static DelayCounter scroll_delay = { 0 }; + static DelayCounter label_delay = { 0 }; static int from_x, from_y, scroll_direction; static int label_state, label_counter; - unsigned int scroll_delay_value = preview.step_delay; boolean show_level_border = (BorderElement != EL_EMPTY); int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); int level_ysize = lev_fieldy + (show_level_border ? 2 : 0); + scroll_delay.value = preview.step_delay; + label_delay.value = MICROLEVEL_LABEL_DELAY; + if (restart) { from_x = 0; @@ -3588,7 +3608,7 @@ static void DrawPreviewLevelExt(boolean restart) // scroll preview level, if needed if (preview.anim_mode != ANIM_NONE && (level_xsize > preview.xsize || level_ysize > preview.ysize) && - DelayReached(&scroll_delay, scroll_delay_value)) + DelayReached(&scroll_delay)) { switch (scroll_direction) { @@ -3646,7 +3666,7 @@ static void DrawPreviewLevelExt(boolean restart) if (!strEqual(level.name, NAMELESS_LEVEL_NAME) && !strEqual(level.author, ANONYMOUS_NAME) && !strEqual(level.author, leveldir_current->name) && - DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY)) + DelayReached(&label_delay)) { int max_label_counter = 23; @@ -3960,6 +3980,9 @@ void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic) if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy)) return; + if (Tile[x][y] == EL_EMPTY) + graphic = el2img(GfxElementEmpty[x][y]); + if (!IS_NEW_FRAME(GfxFrame[x][y], graphic)) return; @@ -4580,7 +4603,7 @@ static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game) case EVENT_KEYPRESS: { - Key key = GetEventKey((KeyEvent *)&event, TRUE); + Key key = GetEventKey((KeyEvent *)&event); switch (key) { @@ -5327,8 +5350,7 @@ unsigned int MoveDoor(unsigned int door_state) }; static int door1 = DOOR_CLOSE_1; static int door2 = DOOR_CLOSE_2; - unsigned int door_delay = 0; - unsigned int door_delay_value; + DelayCounter door_delay = { 0 }; int i; if (door_state == DOOR_GET_STATE) @@ -5378,7 +5400,6 @@ unsigned int MoveDoor(unsigned int door_state) int num_move_steps = 0; // number of animation steps for all doors int max_move_delay_doors_only = 0; // delay for doors only (no panel) int num_move_steps_doors_only = 0; // steps for doors only (no panel) - int current_move_delay = 0; int start = 0; int k; @@ -5444,7 +5465,7 @@ unsigned int MoveDoor(unsigned int door_state) num_move_steps = max_move_delay / max_step_delay; num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay; - door_delay_value = max_step_delay; + door_delay.value = max_step_delay; if ((door_state & DOOR_NO_DELAY) || setup.quick_doors) { @@ -5527,7 +5548,7 @@ unsigned int MoveDoor(unsigned int door_state) { int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1); int kk_door = MAX(0, k2_door); - int sync_frame = kk_door * door_delay_value; + int sync_frame = kk_door * door_delay.value; int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame); getFixedGraphicSource(dpc->graphic, frame, &bitmap, @@ -5636,9 +5657,7 @@ unsigned int MoveDoor(unsigned int door_state) { BackToFront(); - SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame); - - current_move_delay += max_step_delay; + SkipUntilDelayReached(&door_delay, &k, last_frame); // prevent OS (Windows) from complaining about program not responding CheckQuitEvent(); @@ -5652,13 +5671,13 @@ unsigned int MoveDoor(unsigned int door_state) { // wait for specified door action post delay if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2) - door_delay_value = MAX(door_1.post_delay, door_2.post_delay); + door_delay.value = MAX(door_1.post_delay, door_2.post_delay); else if (door_state & DOOR_ACTION_1) - door_delay_value = door_1.post_delay; + door_delay.value = door_1.post_delay; else if (door_state & DOOR_ACTION_2) - door_delay_value = door_2.post_delay; + door_delay.value = door_2.post_delay; - while (!DelayReached(&door_delay, door_delay_value)) + while (!DelayReached(&door_delay)) BackToFront(); } } @@ -5835,6 +5854,10 @@ void CreateToolButtons(void) int y = pos->y; int id = i; + // do not use touch buttons if overlay touch buttons are disabled + if (is_touch_button && !setup.touch.overlay_buttons) + continue; + if (global.use_envelope_request && !is_touch_button) { setRequestPosition(&base_x, &base_y, TRUE); @@ -9724,9 +9747,9 @@ void ChangeViewportPropertiesIfNeeded(void) { boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? FALSE : setup.small_game_graphics); - int gfx_game_mode = game_status; - int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT : - game_status); + int gfx_game_mode = getGlobalGameStatus(game_status); + int gfx_game_mode2 = (gfx_game_mode == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT : + gfx_game_mode); struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode]; struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode]; struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode]; @@ -9939,12 +9962,28 @@ void ChangeViewportPropertiesIfNeeded(void) } } +void OpenURL(char *url) +{ +#if SDL_VERSION_ATLEAST(2,0,14) + SDL_OpenURL(url); +#else + Warn("SDL_OpenURL(\"%s\") not supported by SDL %d.%d.%d!", + url, SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL); + Warn("Please upgrade to at least SDL 2.0.14 for URL support!"); +#endif +} + +void OpenURLFromHash(SetupFileHash *hash, int hash_key) +{ + OpenURL(getHashEntry(hash, int2str(hash_key, 0))); +} + // ============================================================================ // tests // ============================================================================ -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) /* FILETIME of Jan 1 1970 00:00:00. */ static const unsigned __int64 epoch = ((unsigned __int64) 116444736000000000ULL); @@ -9954,7 +9993,7 @@ static const unsigned __int64 epoch = ((unsigned __int64) 116444736000000000ULL) * Note: this function is not for Win32 high precision timing purpose. See * elapsed_time(). */ -int gettimeofday_windows(struct timeval * tp, struct timezone * tzp) +static int gettimeofday_windows(struct timeval * tp, struct timezone * tzp) { FILETIME file_time; SYSTEMTIME system_time; @@ -9998,7 +10037,7 @@ static char *test_init_uuid_random_function_better(void) return seed_text; } -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) static char *test_init_uuid_random_function_better_windows(void) { static char seed_text[100]; @@ -10026,7 +10065,7 @@ static unsigned int test_uuid_random_function_better(int max) return (max > 0 ? prng_get_uint() % max : 0); } -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) #define NUM_UUID_TESTS 3 #else #define NUM_UUID_TESTS 2 @@ -10053,7 +10092,7 @@ static void TestGeneratingUUIDs_RunTest(int nr, int always_seed, int num_uuids) test_uuid_random_function_better); int xpos = 40; -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) if (nr == 2) { random_name = "windows";