X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Ftools.c;h=e1ff8140e3d56fbc44f8e30f050024072961a5d2;hp=fe14158f0c5904849b4bc9acf7b400cf728a046d;hb=457e98ec0803cd9005a522018e7c255454d1e915;hpb=37dc6b231b7e6cd2aeab259ebe52be365b7f3c17 diff --git a/src/tools.c b/src/tools.c index fe14158f..e1ff8140 100644 --- a/src/tools.c +++ b/src/tools.c @@ -192,17 +192,232 @@ static char *print_if_not_empty(int element) return s; } -void DumpTile(int x, int y) +int correctLevelPosX_EM(int lx) { - int sx = SCREENX(x); - int sy = SCREENY(y); + lx -= 1; + lx -= (BorderElement != EL_EMPTY ? 1 : 0); - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + return lx; +} + +int correctLevelPosY_EM(int ly) +{ + ly -= 1; + ly -= (BorderElement != EL_EMPTY ? 1 : 0); + + return ly; +} + +static int getFieldbufferOffsetX_RND() +{ + int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); + int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0); + int dx_var = dx * TILESIZE_VAR / TILESIZE; + int fx = FX; + + if (EVEN(SCR_FIELDX)) + { + int ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var; + + if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR) + fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR; + else + fx += (dx_var > 0 ? TILEX_VAR : 0); + } + else + { + fx += dx_var; + } + + if (full_lev_fieldx <= SCR_FIELDX) + { + if (EVEN(SCR_FIELDX)) + fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0); + else + fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0); + } + + return fx; +} + +static int getFieldbufferOffsetY_RND() +{ + int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0); + int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0); + int dy_var = dy * TILESIZE_VAR / TILESIZE; + int fy = FY; + + if (EVEN(SCR_FIELDY)) + { + int ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var; + + if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR) + fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR; + else + fy += (dy_var > 0 ? TILEY_VAR : 0); + } + else { - x--; - y--; + fy += dy_var; } + if (full_lev_fieldy <= SCR_FIELDY) + { + if (EVEN(SCR_FIELDY)) + fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0); + else + fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0); + } + + return fy; +} + +static int getLevelFromScreenX_RND(int sx) +{ + int fx = getFieldbufferOffsetX_RND(); + int dx = fx - FX; + int px = sx - SX; + int lx = LEVELX((px + dx) / TILESIZE_VAR); + + return lx; +} + +static int getLevelFromScreenY_RND(int sy) +{ + int fy = getFieldbufferOffsetY_RND(); + int dy = fy - FY; + int py = sy - SY; + int ly = LEVELY((py + dy) / TILESIZE_VAR); + + return ly; +} + +static int getLevelFromScreenX_EM(int sx) +{ + int level_xsize = level.native_em_level->lev->width; + int full_xsize = level_xsize * TILESIZE_VAR; + + sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0); + + int fx = getFieldbufferOffsetX_EM(); + int dx = fx; + int px = sx - SX; + int lx = LEVELX((px + dx) / TILESIZE_VAR); + + lx = correctLevelPosX_EM(lx); + + return lx; +} + +static int getLevelFromScreenY_EM(int sy) +{ + int level_ysize = level.native_em_level->lev->height; + int full_ysize = level_ysize * TILESIZE_VAR; + + sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0); + + int fy = getFieldbufferOffsetY_EM(); + int dy = fy; + int py = sy - SY; + int ly = LEVELY((py + dy) / TILESIZE_VAR); + + ly = correctLevelPosY_EM(ly); + + return ly; +} + +static int getLevelFromScreenX_SP(int sx) +{ + int menBorder = setup.sp_show_border_elements; + int level_xsize = level.native_sp_level->width; + int full_xsize = (level_xsize - (menBorder ? 0 : 1)) * TILESIZE_VAR; + + sx += (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0); + + int fx = getFieldbufferOffsetX_SP(); + int dx = fx - FX; + int px = sx - SX; + int lx = LEVELX((px + dx) / TILESIZE_VAR); + + return lx; +} + +static int getLevelFromScreenY_SP(int sy) +{ + int menBorder = setup.sp_show_border_elements; + int level_ysize = level.native_sp_level->height; + int full_ysize = (level_ysize - (menBorder ? 0 : 1)) * TILESIZE_VAR; + + sy += (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0); + + int fy = getFieldbufferOffsetY_SP(); + int dy = fy - FY; + int py = sy - SY; + int ly = LEVELY((py + dy) / TILESIZE_VAR); + + return ly; +} + +static int getLevelFromScreenX_MM(int sx) +{ +#if 0 + int level_xsize = level.native_mm_level->fieldx; + int full_xsize = level_xsize * TILESIZE_VAR; + + sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0); +#endif + + int px = sx - SX; + int lx = px / TILESIZE_VAR; + + return lx; +} + +static int getLevelFromScreenY_MM(int sy) +{ +#if 0 + int level_ysize = level.native_mm_level->fieldy; + int full_ysize = level_ysize * TILESIZE_VAR; + + sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0); +#endif + + int py = sy - SY; + int ly = py / TILESIZE_VAR; + + return ly; +} + +int getLevelFromScreenX(int x) +{ + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + return getLevelFromScreenX_EM(x); + if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + return getLevelFromScreenX_SP(x); + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + return getLevelFromScreenX_MM(x); + else + return getLevelFromScreenX_RND(x); +} + +int getLevelFromScreenY(int y) +{ + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + return getLevelFromScreenY_EM(y); + if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + return getLevelFromScreenY_SP(y); + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + return getLevelFromScreenY_MM(y); + else + return getLevelFromScreenY_RND(y); +} + +void DumpTile(int x, int y) +{ + int sx = SCREENX(x); + int sy = SCREENY(y); + char *token_name; + printf_line("-", 79); printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y); printf_line("-", 79); @@ -215,8 +430,9 @@ void DumpTile(int x, int y) return; } - printf(" Feld: %d\t['%s']\n", Feld[x][y], - element_info[Feld[x][y]].token_name); + token_name = element_info[Feld[x][y]].token_name; + + printf(" Feld: %d\t['%s']\n", Feld[x][y], token_name); printf(" Back: %s\n", print_if_not_empty(Back[x][y])); printf(" Store: %s\n", print_if_not_empty(Store[x][y])); printf(" Store2: %s\n", print_if_not_empty(Store2[x][y])); @@ -229,9 +445,18 @@ void DumpTile(int x, int y) printf(" GfxElement: %d\n", GfxElement[x][y]); printf(" GfxAction: %d\n", GfxAction[x][y]); printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter); + printf(" Player x/y: %d, %d\n", local_player->jx, local_player->jy); printf("\n"); } +void DumpTileFromScreen(int sx, int sy) +{ + int lx = getLevelFromScreenX(sx); + int ly = getLevelFromScreenY(sy); + + DumpTile(lx, ly); +} + void SetDrawtoField(int mode) { if (mode == DRAW_TO_FIELDBUFFER) @@ -276,6 +501,8 @@ void RedrawPlayfield() RedrawPlayfield_EM(TRUE); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) RedrawPlayfield_SP(TRUE); + else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + RedrawPlayfield_MM(); else if (level.game_engine_type == GAME_ENGINE_TYPE_RND) RedrawPlayfield_RND(); @@ -410,58 +637,8 @@ void DrawMaskedBorderToTarget(int draw_target) void BlitScreenToBitmap_RND(Bitmap *target_bitmap) { - int fx = FX, fy = FY; - int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); - int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0); - - int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0); - int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0); - int dx_var = dx * TILESIZE_VAR / TILESIZE; - int dy_var = dy * TILESIZE_VAR / TILESIZE; - int ffx, ffy; - - ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var; - ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var; - - if (EVEN(SCR_FIELDX)) - { - if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR) - fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR; - else - fx += (dx_var > 0 ? TILEX_VAR : 0); - } - else - { - fx += dx_var; - } - - if (EVEN(SCR_FIELDY)) - { - if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR) - fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR; - else - fy += (dy_var > 0 ? TILEY_VAR : 0); - } - else - { - fy += dy_var; - } - - if (full_lev_fieldx <= SCR_FIELDX) - { - if (EVEN(SCR_FIELDX)) - fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0); - else - fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0); - } - - if (full_lev_fieldy <= SCR_FIELDY) - { - if (EVEN(SCR_FIELDY)) - fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0); - else - fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0); - } + int fx = getFieldbufferOffsetX_RND(); + int fy = getFieldbufferOffsetY_RND(); BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY); } @@ -472,6 +649,8 @@ void BlitScreenToBitmap(Bitmap *target_bitmap) BlitScreenToBitmap_EM(target_bitmap); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) BlitScreenToBitmap_SP(target_bitmap); + else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + BlitScreenToBitmap_MM(target_bitmap); else if (level.game_engine_type == GAME_ENGINE_TYPE_RND) BlitScreenToBitmap_RND(target_bitmap); @@ -483,11 +662,24 @@ void DrawFramesPerSecond() char text[100]; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); + int draw_deactivation_mask = GetDrawDeactivationMask(); + boolean draw_masked = (draw_deactivation_mask == REDRAW_NONE); + + /* draw FPS with leading space (needed if field buffer deactivated) */ + sprintf(text, " %04.1f fps", global.frames_per_second); + + /* override draw deactivation mask (required for invisible warp mode) */ + SetDrawDeactivationMask(REDRAW_NONE); - sprintf(text, "%04.1f fps", global.frames_per_second); + /* draw opaque FPS if field buffer deactivated, else draw masked FPS */ + DrawTextExt(backbuffer, SX + SXSIZE - font_width * strlen(text), SY, text, + font_nr, (draw_masked ? BLIT_MASKED : BLIT_OPAQUE)); - DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text, - font_nr, BLIT_OPAQUE); + /* set draw deactivation mask to previous value */ + SetDrawDeactivationMask(draw_deactivation_mask); + + /* force full-screen redraw in this frame */ + redraw_mask = REDRAW_ALL; } #if DEBUG_FRAME_TIME @@ -620,6 +812,13 @@ void BackToFront() y2 = MAX(y2, EY + EYSIZE); } + // make sure that at least one pixel is blitted, and inside the screen + // (else nothing is blitted, causing the animations not to be updated) + x1 = MIN(MAX(0, x1), WIN_XSIZE - 1); + y1 = MIN(MAX(0, y1), WIN_YSIZE - 1); + x2 = MIN(MAX(1, x2), WIN_XSIZE); + y2 = MIN(MAX(1, y2), WIN_YSIZE); + BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1); } @@ -787,6 +986,10 @@ void FadeIn(int fade_mask) FADE_SXSIZE = FULL_SXSIZE; FADE_SYSIZE = FULL_SYSIZE; + if (game_status == GAME_MODE_PLAYING && + strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS)) + SetOverlayActive(TRUE); + SetScreenStates_AfterFadingIn(); // force update of global animation status in case of rapid screen changes @@ -802,6 +1005,8 @@ void FadeOut(int fade_mask) SetScreenStates_BeforeFadingOut(); + SetOverlayActive(FALSE); + #if 0 DrawMaskedBorder(REDRAW_ALL); #endif @@ -1155,6 +1360,10 @@ void SetBorderElement() BorderElement = EL_EMPTY; + /* the MM game engine does not use a visible border element */ + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + return; + for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++) { for (x = 0; x < lev_fieldx; x++) @@ -1168,9 +1377,10 @@ void SetBorderElement() } } -void FloodFillLevel(int from_x, int from_y, int fill_element, - short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY], - int max_fieldx, int max_fieldy) +void FloodFillLevelExt(int from_x, int from_y, int fill_element, + int max_array_fieldx, int max_array_fieldy, + short field[max_array_fieldx][max_array_fieldy], + int max_fieldx, int max_fieldy) { int i,x,y; int old_element; @@ -1195,12 +1405,22 @@ void FloodFillLevel(int from_x, int from_y, int fill_element, y = from_y + check[i][1]; if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element) - FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy); + FloodFillLevelExt(x, y, fill_element, max_array_fieldx, max_array_fieldy, + field, max_fieldx, max_fieldy); } safety--; } +void FloodFillLevel(int from_x, int from_y, int fill_element, + short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY], + int max_fieldx, int max_fieldy) +{ + FloodFillLevelExt(from_x, from_y, fill_element, + MAX_LEV_FIELDX, MAX_LEV_FIELDY, field, + max_fieldx, max_fieldy); +} + void SetRandomAnimationValue(int x, int y) { gfx.anim_random_frame = GfxRandom[x][y]; @@ -1279,13 +1499,6 @@ void getSizedGraphicSourceExt(int graphic, int frame, int tilesize, *y = *y * tilesize / g->tile_size; } -void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap, - int *x, int *y, boolean get_backside) -{ - getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, - get_backside); -} - void getSizedGraphicSource(int graphic, int frame, int tilesize, Bitmap **bitmap, int *x, int *y) { @@ -1433,6 +1646,14 @@ void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize) MarkTileDirty(x / tilesize, y / tilesize); } +void DrawSizedGraphicThruMask(int x, int y, int graphic, int frame, + int tilesize) +{ + DrawSizedGraphicThruMaskExt(drawto, SX + x * tilesize, SY + y * tilesize, + graphic, frame, tilesize); + MarkTileDirty(x / tilesize, y / tilesize); +} + void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame, int tilesize) { @@ -1443,6 +1664,16 @@ void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame, BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y); } +void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic, + int frame, int tilesize) +{ + Bitmap *src_bitmap; + int src_x, src_y; + + getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y); + BlitBitmapMasked(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y); +} + void DrawMiniGraphic(int x, int y, int graphic) { DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic); @@ -1760,6 +1991,9 @@ static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy, int width, height, cx, cy; int sx = SCREENX(x), sy = SCREENY(y); int crumbled_border_size = graphic_info[graphic].border_size; + int crumbled_tile_size = graphic_info[graphic].tile_size; + int crumbled_border_size_var = + crumbled_border_size * TILESIZE_VAR / crumbled_tile_size; int i; getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); @@ -1787,8 +2021,8 @@ static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy, getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y); - width = crumbled_border_size * TILESIZE_VAR / TILESIZE; - height = crumbled_border_size * TILESIZE_VAR / TILESIZE; + width = crumbled_border_size_var; + height = crumbled_border_size_var; cx = (dx > 0 ? TILESIZE_VAR - width : 0); cy = (dy > 0 ? TILESIZE_VAR - height : 0); @@ -1804,7 +2038,9 @@ static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame, int width, height, bx, by, cx, cy; int sx = SCREENX(x), sy = SCREENY(y); int crumbled_border_size = graphic_info[graphic].border_size; - int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE; + int crumbled_tile_size = graphic_info[graphic].tile_size; + int crumbled_border_size_var = + crumbled_border_size * TILESIZE_VAR / crumbled_tile_size; int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var; int i; @@ -1823,7 +2059,7 @@ static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame, /* (remaining middle border part must be at least as big as corner part) */ if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) || - crumbled_border_size >= TILESIZE / 3) + crumbled_border_size_var >= TILESIZE_VAR / 3) return; /* correct corners of crumbled border, if needed */ @@ -1891,12 +2127,12 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) element = TILE_GFX_ELEMENT(x, y); - /* crumble field itself */ - if (IS_CRUMBLED_TILE(x, y, element)) + if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */ { if (!IN_SCR_FIELD(sx, sy)) return; + /* crumble field borders towards direct neighbour fields */ for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; @@ -1914,6 +2150,7 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i); } + /* crumble inner field corners towards corner neighbour fields */ if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) && graphic_info[graphic].anim_frames == 2) { @@ -1928,8 +2165,9 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) MarkTileDirty(sx, sy); } - else /* center field not crumbled -- crumble neighbour fields */ + else /* center field is not crumbled -- crumble neighbour fields */ { + /* crumble field borders of direct neighbour fields */ for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; @@ -1955,6 +2193,37 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) MarkTileDirty(sxx, syy); } + + /* crumble inner field corners of corner neighbour fields */ + for (i = 0; i < 4; i++) + { + int dx = (i & 1 ? +1 : -1); + int dy = (i & 2 ? +1 : -1); + int xx = x + dx; + int yy = y + dy; + int sxx = sx + dx; + int syy = sy + dy; + + if (!IN_LEV_FIELD(xx, yy) || + !IN_SCR_FIELD(sxx, syy)) + continue; + + if (Feld[xx][yy] == EL_ELEMENT_SNAPPING) + continue; + + element = TILE_GFX_ELEMENT(xx, yy); + + if (!IS_CRUMBLED_TILE(xx, yy, element)) + continue; + + graphic = el_act2crm(element, ACTION_DEFAULT); + + if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) && + graphic_info[graphic].anim_frames == 2) + DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic); + + MarkTileDirty(sxx, syy); + } } } @@ -2004,6 +2273,7 @@ void DrawLevelFieldCrumbledNeighbours(int x, int y) }; int i; + /* crumble direct neighbour fields (required for field borders) */ for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; @@ -2019,6 +2289,30 @@ void DrawLevelFieldCrumbledNeighbours(int x, int y) DrawLevelField(xx, yy); } + + /* crumble corner neighbour fields (required for inner field corners) */ + for (i = 0; i < 4; i++) + { + int dx = (i & 1 ? +1 : -1); + int dy = (i & 2 ? +1 : -1); + int xx = x + dx; + int yy = y + dy; + int sxx = sx + dx; + int syy = sy + dy; + + if (!IN_LEV_FIELD(xx, yy) || + !IN_SCR_FIELD(sxx, syy) || + !GFX_CRUMBLED(Feld[xx][yy]) || + IS_MOVING(xx, yy)) + continue; + + int element = TILE_GFX_ELEMENT(xx, yy); + int graphic = el_act2crm(element, ACTION_DEFAULT); + + if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) && + graphic_info[graphic].anim_frames == 2) + DrawLevelField(xx, yy); + } } static int getBorderElement(int x, int y) @@ -2120,6 +2414,10 @@ void DrawScreenField(int x, int y) int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0); DrawLevelElementThruMask(newlx, newly, EL_ACID); + + // prevent target field from being drawn again (but without masking) + // (this would happen if target field is scanned after moving element) + Stop[newlx][newly] = TRUE; } } else if (IS_BLOCKED(lx, ly)) @@ -2187,12 +2485,77 @@ void DrawLevelField(int x, int y) } } +static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize, + int (*el2img_function)(int), boolean masked) +{ + int element_base = map_mm_wall_element(element); + int element_bits = (IS_DF_WALL(element) ? + element - EL_DF_WALL_START : + element - EL_MM_WALL_START) & 0x000f; + int graphic = el2img_function(element_base); + int tilesize_draw = tilesize / 2; + Bitmap *src_bitmap; + int src_x, src_y; + int i; + + getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y); + + for (i = 0; i < 4; i++) + { + int dst_draw_x = dst_x + (i % 2) * tilesize_draw; + int dst_draw_y = dst_y + (i / 2) * tilesize_draw; + + if (element_bits & (1 << i)) + { + if (masked) + BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, + tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y); + else + BlitBitmap(src_bitmap, drawto, src_x, src_y, + tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y); + } + else + { + if (!masked) + ClearRectangle(drawto, dst_draw_x, dst_draw_y, + tilesize_draw, tilesize_draw); + } + } +} + +void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize, + int (*el2img_function)(int)) +{ + DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE); +} + +void DrawSizedElementExt(int x, int y, int element, int tilesize, + boolean masked) +{ + if (IS_MM_WALL(element)) + { + DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize, + element, tilesize, el2edimg, masked); + } + else + { + int graphic = el2edimg(element); + + if (masked) + DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize); + else + DrawSizedGraphic(x, y, graphic, 0, tilesize); + } +} + void DrawSizedElement(int x, int y, int element, int tilesize) { - int graphic; + DrawSizedElementExt(x, y, element, tilesize, FALSE); +} - graphic = el2edimg(element); - DrawSizedGraphic(x, y, graphic, 0, tilesize); +void DrawSizedElementThruMask(int x, int y, int element, int tilesize) +{ + DrawSizedElementExt(x, y, element, tilesize, TRUE); } void DrawMiniElement(int x, int y, int element) @@ -2286,7 +2649,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action) boolean no_delay = (tape.warp_forward); unsigned int anim_delay = 0; int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); - int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2; + int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2); int font_nr = FONT_ENVELOPE_1 + envelope_nr; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); @@ -2543,7 +2906,7 @@ void AnimateEnvelopeRequest(int anim_mode, int action) boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal); - int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2; + int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2); unsigned int anim_delay = 0; int tile_size = MAX(request.step_offset, 1); @@ -2702,12 +3065,20 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action) void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize) { - Bitmap *src_bitmap; - int src_x, src_y; - int graphic = el2preimg(element); + if (IS_MM_WALL(element)) + { + DrawSizedWall_MM(dst_x, dst_y, element, tilesize, el2preimg); + } + else + { + Bitmap *src_bitmap; + int src_x, src_y; + int graphic = el2preimg(element); - getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y); - BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y); + getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y); + BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, + dst_x, dst_y); + } } void DrawLevel(int draw_background_mask) @@ -2749,7 +3120,7 @@ void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y) redraw_mask |= REDRAW_FIELD; } -static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y) +static void DrawPreviewLevelPlayfield(int from_x, int from_y) { boolean show_level_border = (BorderElement != EL_EMPTY); int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); @@ -2814,9 +3185,8 @@ static int getMaxTextLength(struct TextPosInfo *pos, int font_nr) return max_text_width / font_width; } -static void DrawPreviewLevelLabelExt(int mode) +static void DrawPreviewLevelLabelExt(int mode, struct TextPosInfo *pos) { - struct TextPosInfo *pos = &menu.main.text.level_info_2; char label_text[MAX_OUTPUT_LINESIZE + 1]; int max_len_label_text; int font_nr = pos->font; @@ -2859,6 +3229,19 @@ static void DrawPreviewLevelLabelExt(int mode) redraw_mask |= REDRAW_FIELD; } +static void DrawPreviewLevelLabel(int mode) +{ + DrawPreviewLevelLabelExt(mode, &menu.main.text.level_info_2); +} + +static void DrawPreviewLevelInfo(int mode) +{ + if (mode == MICROLABEL_LEVEL_NAME) + DrawPreviewLevelLabelExt(mode, &menu.main.text.level_name); + else if (mode == MICROLABEL_LEVEL_AUTHOR) + DrawPreviewLevelLabelExt(mode, &menu.main.text.level_author); +} + static void DrawPreviewLevelExt(boolean restart) { static unsigned int scroll_delay = 0; @@ -2890,8 +3273,11 @@ static void DrawPreviewLevelExt(boolean restart) label_state = 1; label_counter = 0; - DrawPreviewLevelPlayfieldExt(from_x, from_y); - DrawPreviewLevelLabelExt(label_state); + DrawPreviewLevelPlayfield(from_x, from_y); + DrawPreviewLevelLabel(label_state); + + DrawPreviewLevelInfo(MICROLABEL_LEVEL_NAME); + DrawPreviewLevelInfo(MICROLABEL_LEVEL_AUTHOR); /* initialize delay counters */ DelayReached(&scroll_delay, 0); @@ -2970,7 +3356,7 @@ static void DrawPreviewLevelExt(boolean restart) break; } - DrawPreviewLevelPlayfieldExt(from_x, from_y); + DrawPreviewLevelPlayfield(from_x, from_y); } /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */ @@ -3011,7 +3397,7 @@ static void DrawPreviewLevelExt(boolean restart) label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ? MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY); - DrawPreviewLevelLabelExt(label_state); + DrawPreviewLevelLabel(label_state); } } @@ -3517,6 +3903,9 @@ void WaitForEventToContinue() { boolean still_wait = TRUE; + if (program.headless) + return; + /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); @@ -3527,16 +3916,18 @@ void WaitForEventToContinue() while (still_wait) { - if (PendingEvent()) - { - Event event; - - NextEvent(&event); + Event event; + if (NextValidEvent(&event)) + { switch (event.type) { case EVENT_BUTTONPRESS: case EVENT_KEYPRESS: +#if defined(TARGET_SDL2) + case SDL_CONTROLLERBUTTONDOWN: +#endif + case SDL_JOYBUTTONDOWN: still_wait = FALSE; break; @@ -3582,7 +3973,9 @@ static int RequestHandleEvents(unsigned int req_state) { if (level_solved) { - SetDrawtoField(DRAW_TO_FIELDBUFFER); + /* the MM game engine does not use a special (scrollable) field buffer */ + if (level.game_engine_type != GAME_ENGINE_TYPE_MM) + SetDrawtoField(DRAW_TO_FIELDBUFFER); HandleGameActions(); @@ -3664,6 +4057,19 @@ static int RequestHandleEvents(unsigned int req_state) break; } +#if defined(TARGET_SDL2) + case SDL_WINDOWEVENT: + HandleWindowEvent((WindowEvent *) &event); + break; + + case SDL_APP_WILLENTERBACKGROUND: + case SDL_APP_DIDENTERBACKGROUND: + case SDL_APP_WILLENTERFOREGROUND: + case SDL_APP_DIDENTERFOREGROUND: + HandlePauseResumeEvent((PauseResumeEvent *) &event); + break; +#endif + case EVENT_KEYPRESS: { Key key = GetEventKey((KeyEvent *)&event, TRUE); @@ -3677,7 +4083,11 @@ static int RequestHandleEvents(unsigned int req_state) case KSYM_Return: #if defined(TARGET_SDL2) + case KSYM_Select: case KSYM_Menu: +#if defined(KSYM_Rewind) + case KSYM_Rewind: /* for Amazon Fire TV remote */ +#endif #endif result = 1; break; @@ -3685,6 +4095,9 @@ static int RequestHandleEvents(unsigned int req_state) case KSYM_Escape: #if defined(TARGET_SDL2) case KSYM_Back: +#if defined(KSYM_FastForward) + case KSYM_FastForward: /* for Amazon Fire TV remote */ +#endif #endif result = 0; break; @@ -3704,6 +4117,35 @@ static int RequestHandleEvents(unsigned int req_state) ClearPlayerAction(); break; +#if defined(TARGET_SDL2) + case SDL_CONTROLLERBUTTONDOWN: + switch (event.cbutton.button) + { + case SDL_CONTROLLER_BUTTON_A: + case SDL_CONTROLLER_BUTTON_X: + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + result = 1; + break; + + case SDL_CONTROLLER_BUTTON_B: + case SDL_CONTROLLER_BUTTON_Y: + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + case SDL_CONTROLLER_BUTTON_BACK: + result = 0; + break; + } + + if (req_state & REQ_PLAYER) + result = 0; + + break; + + case SDL_CONTROLLERBUTTONUP: + HandleJoystickEvent(&event); + ClearPlayerAction(); + break; +#endif + default: HandleOtherEvents(&event); break; @@ -4005,10 +4447,19 @@ static boolean RequestEnvelope(char *text, unsigned int req_state) boolean Request(char *text, unsigned int req_state) { + boolean overlay_active = GetOverlayActive(); + boolean result; + + SetOverlayActive(FALSE); + if (global.use_envelope_request) - return RequestEnvelope(text, req_state); + result = RequestEnvelope(text, req_state); else - return RequestDoor(text, req_state); + result = RequestDoor(text, req_state); + + SetOverlayActive(overlay_active); + + return result; } static int compareDoorPartOrderInfo(const void *object1, const void *object2) @@ -4569,6 +5020,9 @@ unsigned int MoveDoor(unsigned int door_state) SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame); current_move_delay += max_step_delay; + + /* prevent OS (Windows) from complaining about program not responding */ + CheckQuitEvent(); } if (door_part_done_all) @@ -6888,6 +7342,122 @@ int map_action_SP_to_RND(int action_sp) } } +int map_element_RND_to_MM(int element_rnd) +{ + return (element_rnd >= EL_MM_START_1 && + element_rnd <= EL_MM_END_1 ? + EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 : + + element_rnd >= EL_MM_START_2 && + element_rnd <= EL_MM_END_2 ? + EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 : + + element_rnd >= EL_CHAR_START && + element_rnd <= EL_CHAR_END ? + EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START : + + element_rnd >= EL_MM_RUNTIME_START && + element_rnd <= EL_MM_RUNTIME_END ? + EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START : + + element_rnd >= EL_MM_DUMMY_START && + element_rnd <= EL_MM_DUMMY_END ? + EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START : + + EL_MM_EMPTY_NATIVE); +} + +int map_element_MM_to_RND(int element_mm) +{ + return (element_mm == EL_MM_EMPTY_NATIVE || + element_mm == EL_DF_EMPTY_NATIVE ? + EL_EMPTY : + + element_mm >= EL_MM_START_1_NATIVE && + element_mm <= EL_MM_END_1_NATIVE ? + EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE : + + element_mm >= EL_MM_START_2_NATIVE && + element_mm <= EL_MM_END_2_NATIVE ? + EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE : + + element_mm >= EL_MM_CHAR_START_NATIVE && + element_mm <= EL_MM_CHAR_END_NATIVE ? + EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE : + + element_mm >= EL_MM_RUNTIME_START_NATIVE && + element_mm <= EL_MM_RUNTIME_END_NATIVE ? + EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE : + + element_mm >= EL_MM_DUMMY_START_NATIVE && + element_mm <= EL_MM_DUMMY_END_NATIVE ? + EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE : + + EL_EMPTY); +} + +int map_action_MM_to_RND(int action_mm) +{ + /* all MM actions are defined to exactly match their RND counterparts */ + return action_mm; +} + +int map_sound_MM_to_RND(int sound_mm) +{ + switch (sound_mm) + { + case SND_MM_GAME_LEVELTIME_CHARGING: + return SND_GAME_LEVELTIME_CHARGING; + + default: + return SND_UNDEFINED; + } +} + +int map_mm_wall_element(int element) +{ + return (element >= EL_MM_STEEL_WALL_START && + element <= EL_MM_STEEL_WALL_END ? + EL_MM_STEEL_WALL : + + element >= EL_MM_WOODEN_WALL_START && + element <= EL_MM_WOODEN_WALL_END ? + EL_MM_WOODEN_WALL : + + element >= EL_MM_ICE_WALL_START && + element <= EL_MM_ICE_WALL_END ? + EL_MM_ICE_WALL : + + element >= EL_MM_AMOEBA_WALL_START && + element <= EL_MM_AMOEBA_WALL_END ? + EL_MM_AMOEBA_WALL : + + element >= EL_DF_STEEL_WALL_START && + element <= EL_DF_STEEL_WALL_END ? + EL_DF_STEEL_WALL : + + element >= EL_DF_WOODEN_WALL_START && + element <= EL_DF_WOODEN_WALL_END ? + EL_DF_WOODEN_WALL : + + element); +} + +int map_mm_wall_element_editor(int element) +{ + switch (element) + { + case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START; + case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START; + case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START; + case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START; + case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START; + case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START; + + default: return element; + } +} + int get_next_element(int element) { switch (element) @@ -6908,6 +7478,11 @@ int get_next_element(int element) } } +int el2img_mm(int element_mm) +{ + return el2img(map_element_MM_to_RND(element_mm)); +} + int el_act_dir2img(int element, int action, int direction) { element = GFX_ELEMENT(element); @@ -7132,6 +7707,8 @@ unsigned int InitRND(int seed) return InitEngineRandom_EM(seed); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) return InitEngineRandom_SP(seed); + else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + return InitEngineRandom_MM(seed); else return InitEngineRandom_RND(seed); } @@ -7265,6 +7842,7 @@ inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em, &g_em->crumbled_src_x, &g_em->crumbled_src_y); g_em->crumbled_border_size = graphic_info[crumbled].border_size; + g_em->crumbled_tile_size = graphic_info[crumbled].tile_size; g_em->has_crumbled_graphics = TRUE; } @@ -7274,6 +7852,7 @@ inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em, g_em->crumbled_src_x = 0; g_em->crumbled_src_y = 0; g_em->crumbled_border_size = 0; + g_em->crumbled_tile_size = 0; g_em->has_crumbled_graphics = FALSE; } @@ -8037,7 +8616,7 @@ void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame, { if (!local_player->was_waiting) { - if (!SaveEngineSnapshotToList()) + if (!CheckSaveEngineSnapshotToList()) return; local_player->was_waiting = TRUE; @@ -8056,7 +8635,7 @@ void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting, { if (!local_player->was_waiting) { - if (!SaveEngineSnapshotToList()) + if (!CheckSaveEngineSnapshotToList()) return; local_player->was_waiting = TRUE; @@ -8084,8 +8663,15 @@ void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame, void CheckSingleStepMode_SP(boolean murphy_is_waiting, boolean murphy_is_dropping) { + boolean murphy_starts_dropping = FALSE; + int i; + + for (i = 0; i < MAX_PLAYERS; i++) + if (stored_player[i].force_dropping) + murphy_starts_dropping = TRUE; + if (tape.single_step && tape.recording && !tape.pausing) - if (murphy_is_waiting) + if (murphy_is_waiting && !murphy_starts_dropping) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping); @@ -8175,7 +8761,37 @@ void PlayMenuMusicExt(int music) void PlayMenuMusic() { - PlayMenuMusicExt(menu.music[game_status]); + char *curr_music = getCurrentlyPlayingMusicFilename(); + char *next_music = getMusicInfoEntryFilename(menu.music[game_status]); + + if (!strEqual(curr_music, next_music)) + PlayMenuMusicExt(menu.music[game_status]); +} + +void PlayMenuSoundsAndMusic() +{ + PlayMenuSound(); + PlayMenuMusic(); +} + +static void FadeMenuSounds() +{ + FadeSounds(); +} + +static void FadeMenuMusic() +{ + char *curr_music = getCurrentlyPlayingMusicFilename(); + char *next_music = getMusicInfoEntryFilename(menu.music[game_status]); + + if (!strEqual(curr_music, next_music)) + FadeMusic(); +} + +void FadeMenuSoundsAndMusic() +{ + FadeMenuSounds(); + FadeMenuMusic(); } void PlaySoundActivating() @@ -8271,6 +8887,8 @@ void SetAnimStatus(int anim_status_new) { if (anim_status_new == GAME_MODE_MAIN) anim_status_new = GAME_MODE_PSEUDO_MAINONLY; + else if (anim_status_new == GAME_MODE_SCORES) + anim_status_new = GAME_MODE_PSEUDO_SCORESOLD; global.anim_status_next = anim_status_new; @@ -8284,6 +8902,9 @@ void SetAnimStatus(int anim_status_new) void SetGameStatus(int game_status_new) { + if (game_status_new != game_status) + game_status_last_screen = game_status; + game_status = game_status_new; SetAnimStatus(game_status_new); @@ -8313,6 +8934,8 @@ void ResetFontStatus() void ChangeViewportPropertiesIfNeeded() { + 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); @@ -8344,9 +8967,7 @@ void ChangeViewportPropertiesIfNeeded() int new_ey = vp_door_3->y; int new_exsize = vp_door_3->width; int new_eysize = vp_door_3->height; - int new_tilesize_var = - (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size); - + int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size); int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var : gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE); int new_scr_fieldx = new_sxsize / tilesize;