#include "init.h"
#include "game.h"
#include "events.h"
-#include "cartoons.h"
+#include "anim.h"
#include "network.h"
#include "tape.h"
#include "screens.h"
/* select level set with EMC X11 graphics before activating EM GFX debugging */
-#define DEBUG_EM_GFX 0
+#define DEBUG_EM_GFX FALSE
+#define DEBUG_FRAME_TIME FALSE
/* tool button identifiers */
#define TOOL_CTRL_ID_YES 0
{
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_1,
+ IMG_GFX_DOOR_1_PART_1,
&door_1.part_1
},
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_2,
+ IMG_GFX_DOOR_1_PART_2,
&door_1.part_2
},
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_3,
+ IMG_GFX_DOOR_1_PART_3,
&door_1.part_3
},
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_4,
+ IMG_GFX_DOOR_1_PART_4,
&door_1.part_4
},
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_5,
+ IMG_GFX_DOOR_1_PART_5,
&door_1.part_5
},
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_6,
+ IMG_GFX_DOOR_1_PART_6,
&door_1.part_6
},
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_7,
+ IMG_GFX_DOOR_1_PART_7,
&door_1.part_7
},
{
DOOR_1,
- IMG_DOOR_1_GFX_PART_8,
+ IMG_GFX_DOOR_1_PART_8,
&door_1.part_8
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_1,
+ IMG_GFX_DOOR_2_PART_1,
&door_2.part_1
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_2,
+ IMG_GFX_DOOR_2_PART_2,
&door_2.part_2
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_3,
+ IMG_GFX_DOOR_2_PART_3,
&door_2.part_3
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_4,
+ IMG_GFX_DOOR_2_PART_4,
&door_2.part_4
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_5,
+ IMG_GFX_DOOR_2_PART_5,
&door_2.part_5
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_6,
+ IMG_GFX_DOOR_2_PART_6,
&door_2.part_6
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_7,
+ IMG_GFX_DOOR_2_PART_7,
&door_2.part_7
},
{
DOOR_2,
- IMG_DOOR_2_GFX_PART_8,
+ IMG_GFX_DOOR_2_PART_8,
&door_2.part_8
},
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;
+}
+
+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);
+ 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);
+ else
+ return getLevelFromScreenY_RND(y);
+}
+
+void DumpTile(int x, int y)
+{
+ int sx = SCREENX(x);
+ int sy = SCREENY(y);
+
printf_line("-", 79);
printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
printf_line("-", 79);
printf(" CustomValue: %d\n", CustomValue[x][y]);
printf(" GfxElement: %d\n", GfxElement[x][y]);
printf(" GfxAction: %d\n", GfxAction[x][y]);
- printf(" GfxFrame: %d\n", GfxFrame[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_BUFFERED && setup.soft_scrolling)
+ if (mode == DRAW_TO_FIELDBUFFER)
{
FX = 2 * TILEX_VAR;
FY = 2 * TILEY_VAR;
BY1 = -2;
BX2 = SCR_FIELDX + 1;
BY2 = SCR_FIELDY + 1;
- redraw_x1 = 2;
- redraw_y1 = 2;
drawto_field = fieldbuffer;
}
- else /* DRAW_BACKBUFFER */
+ else /* DRAW_TO_BACKBUFFER */
{
FX = SX;
FY = SY;
BY1 = 0;
BX2 = SCR_FIELDX - 1;
BY2 = SCR_FIELDY - 1;
- redraw_x1 = 0;
- redraw_y1 = 0;
drawto_field = backbuffer;
}
gfx.sx, gfx.sy);
}
-void DrawMaskedBorder_Rect(int x, int y, int width, int height)
+static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
+ int draw_target)
{
- Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
+ Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
+ Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
- BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
+ if (x == -1 && y == -1)
+ return;
+
+ if (draw_target == DRAW_TO_SCREEN)
+ BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
+ else
+ BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
}
-void DrawMaskedBorder_FIELD()
+static void DrawMaskedBorderExt_FIELD(int draw_target)
{
- if (global.border_status >= GAME_MODE_TITLE &&
+ if (global.border_status >= GAME_MODE_MAIN &&
global.border_status <= GAME_MODE_PLAYING &&
border.draw_masked[global.border_status])
- DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+ DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+ draw_target);
}
-void DrawMaskedBorder_DOOR_1()
+static void DrawMaskedBorderExt_DOOR_1(int draw_target)
{
+ // when drawing to backbuffer, never draw border over open doors
+ if (draw_target == DRAW_TO_BACKBUFFER &&
+ (GetDoorState() & DOOR_OPEN_1))
+ return;
+
if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
(global.border_status != GAME_MODE_EDITOR ||
border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
- DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
+ DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
}
-void DrawMaskedBorder_DOOR_2()
+static void DrawMaskedBorderExt_DOOR_2(int draw_target)
{
+ // when drawing to backbuffer, never draw border over open doors
+ if (draw_target == DRAW_TO_BACKBUFFER &&
+ (GetDoorState() & DOOR_OPEN_2))
+ return;
+
if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
global.border_status != GAME_MODE_EDITOR)
- DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
+ DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
}
-void DrawMaskedBorder_DOOR_3()
+static void DrawMaskedBorderExt_DOOR_3(int draw_target)
{
/* currently not available */
}
-void DrawMaskedBorder_ALL()
+static void DrawMaskedBorderExt_ALL(int draw_target)
{
- DrawMaskedBorder_FIELD();
- DrawMaskedBorder_DOOR_1();
- DrawMaskedBorder_DOOR_2();
- DrawMaskedBorder_DOOR_3();
+ DrawMaskedBorderExt_FIELD(draw_target);
+ DrawMaskedBorderExt_DOOR_1(draw_target);
+ DrawMaskedBorderExt_DOOR_2(draw_target);
+ DrawMaskedBorderExt_DOOR_3(draw_target);
}
-void DrawMaskedBorder(int redraw_mask)
+static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
{
/* never draw masked screen borders on borderless screens */
- if (effectiveGameStatus() == GAME_MODE_LOADING ||
- effectiveGameStatus() == GAME_MODE_TITLE)
- return;
-
- /* never draw masked screen borders when displaying request outside door */
- if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
- global.use_envelope_request)
+ if (global.border_status == GAME_MODE_LOADING ||
+ global.border_status == GAME_MODE_TITLE)
return;
if (redraw_mask & REDRAW_ALL)
- DrawMaskedBorder_ALL();
+ DrawMaskedBorderExt_ALL(draw_target);
else
{
if (redraw_mask & REDRAW_FIELD)
- DrawMaskedBorder_FIELD();
+ DrawMaskedBorderExt_FIELD(draw_target);
if (redraw_mask & REDRAW_DOOR_1)
- DrawMaskedBorder_DOOR_1();
+ DrawMaskedBorderExt_DOOR_1(draw_target);
if (redraw_mask & REDRAW_DOOR_2)
- DrawMaskedBorder_DOOR_2();
+ DrawMaskedBorderExt_DOOR_2(draw_target);
if (redraw_mask & REDRAW_DOOR_3)
- DrawMaskedBorder_DOOR_3();
+ DrawMaskedBorderExt_DOOR_3(draw_target);
}
}
-static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
+void DrawMaskedBorder_FIELD()
{
- DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
- 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;
+ DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
+}
- ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
- ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
+void DrawMaskedBorder(int redraw_mask)
+{
+ DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
+}
- if (EVEN(SCR_FIELDX))
+void DrawMaskedBorderToTarget(int draw_target)
+{
+ if (draw_target == DRAW_TO_BACKBUFFER ||
+ draw_target == DRAW_TO_SCREEN)
{
- 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);
+ DrawMaskedBorderExt(REDRAW_ALL, draw_target);
}
else
{
- fx += dx_var;
- }
+ int last_border_status = global.border_status;
- 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 (draw_target == DRAW_TO_FADE_SOURCE)
+ {
+ global.border_status = gfx.fade_border_source_status;
+ gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
+ }
+ else if (draw_target == DRAW_TO_FADE_TARGET)
+ {
+ global.border_status = gfx.fade_border_target_status;
+ gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
+ }
- 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);
- }
+ DrawMaskedBorderExt(REDRAW_ALL, draw_target);
- 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);
+ global.border_status = last_border_status;
+ gfx.masked_border_bitmap_ptr = backbuffer;
}
+}
- if (border.draw_masked[GAME_MODE_PLAYING])
- {
- if (buffer != backbuffer)
- {
- /* copy playfield buffer to backbuffer to add masked border */
- BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
- DrawMaskedBorder(REDRAW_FIELD);
- }
+void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
+{
+ int fx = getFieldbufferOffsetX_RND();
+ int fy = getFieldbufferOffsetY_RND();
- BlitBitmap(backbuffer, target_bitmap,
- REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
- REAL_SX, REAL_SY);
- }
- else
- {
- BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
- }
+ BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
}
void BlitScreenToBitmap(Bitmap *target_bitmap)
BlitScreenToBitmap_SP(target_bitmap);
else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
BlitScreenToBitmap_RND(target_bitmap);
+
+ redraw_mask |= REDRAW_FIELD;
}
-void BackToFront()
+void DrawFramesPerSecond()
{
- int x, y;
- DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
+ 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);
- if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
- redraw_mask |= REDRAW_FIELD;
+ /* draw FPS with leading space (needed if field buffer deactivated) */
+ sprintf(text, " %04.1f fps", global.frames_per_second);
-#if 0
- // never redraw single tiles, always redraw the whole field
- // (redrawing single tiles up to a certain threshold was faster on old,
- // now legacy graphics, but slows things down on modern graphics now)
- // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
- if (redraw_mask & REDRAW_TILES)
- redraw_mask |= REDRAW_FIELD;
-#endif
+ /* override draw deactivation mask (required for invisible warp mode) */
+ SetDrawDeactivationMask(REDRAW_NONE);
-#if 0
- /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
- /* (force full redraw) */
- if (game_status == GAME_MODE_PLAYING)
- redraw_mask |= REDRAW_FIELD;
-#endif
+ /* 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));
- if (redraw_mask & REDRAW_FIELD)
- redraw_mask &= ~REDRAW_TILES;
+ /* set draw deactivation mask to previous value */
+ SetDrawDeactivationMask(draw_deactivation_mask);
- if (redraw_mask == REDRAW_NONE)
- return;
+ /* force full-screen redraw in this frame */
+ redraw_mask = REDRAW_ALL;
+}
-#if 0
- printf("::: ");
- if (redraw_mask & REDRAW_ALL)
- printf("[REDRAW_ALL]");
- if (redraw_mask & REDRAW_FIELD)
- printf("[REDRAW_FIELD]");
- if (redraw_mask & REDRAW_TILES)
- printf("[REDRAW_TILES]");
- if (redraw_mask & REDRAW_DOOR_1)
- printf("[REDRAW_DOOR_1]");
- if (redraw_mask & REDRAW_DOOR_2)
- printf("[REDRAW_DOOR_2]");
- if (redraw_mask & REDRAW_FROM_BACKBUFFER)
- printf("[REDRAW_FROM_BACKBUFFER]");
- printf(" [%d]\n", FrameCounter);
-#endif
+#if DEBUG_FRAME_TIME
+static void PrintFrameTimeDebugging()
+{
+ static unsigned int last_counter = 0;
+ unsigned int counter = Counter();
+ int diff_1 = counter - last_counter;
+ int diff_2 = diff_1 - GAME_FRAME_DELAY;
+ int diff_2_max = 20;
+ int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
+ char diff_bar[2 * diff_2_max + 5];
+ int pos = 0;
+ int i;
- if (redraw_mask & REDRAW_TILES &&
- game_status == GAME_MODE_PLAYING &&
- border.draw_masked[GAME_MODE_PLAYING])
- redraw_mask |= REDRAW_FIELD;
+ diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
- if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
- {
- static boolean last_frame_skipped = FALSE;
- boolean skip_even_when_not_scrolling = TRUE;
- boolean just_scrolling = (ScreenMovDir != 0);
- boolean verbose = FALSE;
+ for (i = 0; i < diff_2_max; i++)
+ diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
+ i >= diff_2_max - diff_2_cut ? '-' : ' ');
- if (global.fps_slowdown_factor > 1 &&
- (FrameCounter % global.fps_slowdown_factor) &&
- (just_scrolling || skip_even_when_not_scrolling))
- {
- redraw_mask &= ~REDRAW_MAIN;
+ diff_bar[pos++] = '|';
- last_frame_skipped = TRUE;
+ for (i = 0; i < diff_2_max; i++)
+ diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
- if (verbose)
- printf("FRAME SKIPPED\n");
- }
- else
- {
- if (last_frame_skipped)
- redraw_mask |= REDRAW_FIELD;
+ diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
- last_frame_skipped = FALSE;
+ diff_bar[pos++] = '\0';
- if (verbose)
- printf("frame not skipped\n");
- }
- }
+ Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
+ counter,
+ diff_1,
+ (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
+ diff_bar);
- /* synchronize X11 graphics at this point; if we would synchronize the
- display immediately after the buffer switching (after the XFlush),
- this could mean that we have to wait for the graphics to complete,
- although we could go on doing calculations for the next frame */
+ last_counter = counter;
+}
+#endif
- /* SyncDisplay(); */
+static int unifiedRedrawMask(int mask)
+{
+ if (mask & REDRAW_ALL)
+ return REDRAW_ALL;
- /* never draw masked border to backbuffer when using playfield buffer */
- if (game_status != GAME_MODE_PLAYING ||
- redraw_mask & REDRAW_FROM_BACKBUFFER ||
- buffer == backbuffer)
- DrawMaskedBorder(redraw_mask);
- else
- DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
+ if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
+ return REDRAW_ALL;
- if (redraw_mask & REDRAW_ALL)
- {
- BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ return mask;
+}
- redraw_mask = REDRAW_NONE;
- }
+static boolean equalRedrawMasks(int mask_1, int mask_2)
+{
+ return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
+}
- if (redraw_mask & REDRAW_FIELD)
- {
- if (game_status != GAME_MODE_PLAYING ||
- redraw_mask & REDRAW_FROM_BACKBUFFER)
- {
- BlitBitmap(backbuffer, window,
- REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
- }
- else
- {
- BlitScreenToBitmap_RND(window);
- }
+void BackToFront()
+{
+ static int last_redraw_mask = REDRAW_NONE;
- redraw_mask &= ~REDRAW_MAIN;
- }
+ // force screen redraw in every frame to continue drawing global animations
+ // (but always use the last redraw mask to prevent unwanted side effects)
+ if (redraw_mask == REDRAW_NONE)
+ redraw_mask = last_redraw_mask;
- if (redraw_mask & REDRAW_DOORS)
- {
- if (redraw_mask & REDRAW_DOOR_1)
- BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
+ last_redraw_mask = redraw_mask;
- if (redraw_mask & REDRAW_DOOR_2)
- BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
+#if 1
+ // masked border now drawn immediately when blitting backbuffer to window
+#else
+ // draw masked border to all viewports, if defined
+ DrawMaskedBorder(redraw_mask);
+#endif
- if (redraw_mask & REDRAW_DOOR_3)
- BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
+ // draw frames per second (only if debug mode is enabled)
+ if (redraw_mask & REDRAW_FPS)
+ DrawFramesPerSecond();
- redraw_mask &= ~REDRAW_DOORS;
- }
+ // remove playfield redraw before potentially merging with doors redraw
+ if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
+ redraw_mask &= ~REDRAW_FIELD;
- if (redraw_mask & REDRAW_MICROLEVEL)
- {
- BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
- SX, SY + 10 * TILEY);
+ // redraw complete window if both playfield and (some) doors need redraw
+ if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
+ redraw_mask = REDRAW_ALL;
- redraw_mask &= ~REDRAW_MICROLEVEL;
- }
+ /* although redrawing the whole window would be fine for normal gameplay,
+ being able to only redraw the playfield is required for deactivating
+ certain drawing areas (mainly playfield) to work, which is needed for
+ warp-forward to be fast enough (by skipping redraw of most frames) */
- if (redraw_mask & REDRAW_TILES)
+ if (redraw_mask & REDRAW_ALL)
{
- int sx = SX;
- int sy = SY;
-
- int dx = 0, dy = 0;
- int dx_var = dx * TILESIZE_VAR / TILESIZE;
- int dy_var = dy * TILESIZE_VAR / TILESIZE;
- int ffx, ffy;
- int fx = FX, fy = FY;
-
- int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
- int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
-
- InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
-
- ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
- ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
+ BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ }
+ else if (redraw_mask & REDRAW_FIELD)
+ {
+ BlitBitmap(backbuffer, window,
+ REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
+ }
+ else if (redraw_mask & REDRAW_DOORS)
+ {
+ // merge door areas to prevent calling screen redraw more than once
+ int x1 = WIN_XSIZE;
+ int y1 = WIN_YSIZE;
+ int x2 = 0;
+ int y2 = 0;
- if (EVEN(SCR_FIELDX))
+ if (redraw_mask & REDRAW_DOOR_1)
{
- if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
- {
- fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
-
- if (fx % TILEX_VAR)
- sx -= TILEX_VAR / 2;
- else
- sx -= TILEX_VAR;
- }
- else
- {
- fx += (dx_var > 0 ? TILEX_VAR : 0);
- }
+ x1 = MIN(x1, DX);
+ y1 = MIN(y1, DY);
+ x2 = MAX(x2, DX + DXSIZE);
+ y2 = MAX(y2, DY + DYSIZE);
}
- if (EVEN(SCR_FIELDY))
+ if (redraw_mask & REDRAW_DOOR_2)
{
- if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
- {
- fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
+ x1 = MIN(x1, VX);
+ y1 = MIN(y1, VY);
+ x2 = MAX(x2, VX + VXSIZE);
+ y2 = MAX(y2, VY + VYSIZE);
+ }
- if (fy % TILEY_VAR)
- sy -= TILEY_VAR / 2;
- else
- sy -= TILEY_VAR;
- }
- else
- {
- fy += (dy_var > 0 ? TILEY_VAR : 0);
- }
+ if (redraw_mask & REDRAW_DOOR_3)
+ {
+ x1 = MIN(x1, EX);
+ y1 = MIN(y1, EY);
+ x2 = MAX(x2, EX + EXSIZE);
+ y2 = MAX(y2, EY + EYSIZE);
}
- for (x = 0; x < scr_fieldx; x++)
- for (y = 0 ; y < scr_fieldy; y++)
- if (redraw[redraw_x1 + x][redraw_y1 + y])
- BlitBitmap(buffer, window,
- FX + x * TILEX_VAR, FY + y * TILEY_VAR,
- TILEX_VAR, TILEY_VAR,
- sx + x * TILEX_VAR, sy + y * TILEY_VAR);
+ // 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);
- InitGfxClipRegion(FALSE, -1, -1, -1, -1);
+ BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
}
- if (redraw_mask & REDRAW_FPS) /* display frames per second */
- {
- char text[100];
- char info1[100];
+ redraw_mask = REDRAW_NONE;
- sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
- if (!global.fps_slowdown)
- info1[0] = '\0';
+#if DEBUG_FRAME_TIME
+ PrintFrameTimeDebugging();
+#endif
+}
- sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
+void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
+{
+ unsigned int frame_delay_value_old = GetVideoFrameDelay();
- DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
- }
+ SetVideoFrameDelay(frame_delay_value);
- for (x = 0; x < MAX_BUF_XSIZE; x++)
- for (y = 0; y < MAX_BUF_YSIZE; y++)
- redraw[x][y] = 0;
- redraw_tiles = 0;
- redraw_mask = REDRAW_NONE;
-}
+ BackToFront();
-static void FadeCrossSaveBackbuffer()
-{
- BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ SetVideoFrameDelay(frame_delay_value_old);
}
+static int fade_type_skip = FADE_TYPE_NONE;
+
static void FadeExt(int fade_mask, int fade_mode, int fade_type)
{
- static int fade_type_skip = FADE_TYPE_NONE;
void (*draw_border_function)(void) = NULL;
- Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
int x, y, width, height;
int fade_delay, post_delay;
}
if (fading.fade_mode & FADE_TYPE_TRANSFORM)
- {
- FadeCrossSaveBackbuffer();
-
return;
- }
}
redraw_mask |= fade_mask;
if (fade_mask == REDRAW_FIELD)
{
- x = REAL_SX;
- y = REAL_SY;
- width = FULL_SXSIZE;
- height = FULL_SYSIZE;
+ x = FADE_SX;
+ y = FADE_SY;
+ width = FADE_SXSIZE;
+ height = FADE_SYSIZE;
if (border.draw_masked_when_fading)
draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
return;
}
- FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
+ FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
draw_border_function);
redraw_mask &= ~fade_mask;
}
+static void SetScreenStates_BeforeFadingIn()
+{
+ // temporarily set screen mode for animations to screen after fading in
+ global.anim_status = global.anim_status_next;
+
+ // store backbuffer with all animations that will be started after fading in
+ if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
+ PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
+
+ // set screen mode for animations back to fading
+ global.anim_status = GAME_MODE_PSEUDO_FADING;
+}
+
+static void SetScreenStates_AfterFadingIn()
+{
+ // store new source screen (to use correct masked border for fading)
+ gfx.fade_border_source_status = global.border_status;
+
+ global.anim_status = global.anim_status_next;
+}
+
+static void SetScreenStates_BeforeFadingOut()
+{
+ // store new target screen (to use correct masked border for fading)
+ gfx.fade_border_target_status = game_status;
+
+ // set screen mode for animations to fading
+ global.anim_status = GAME_MODE_PSEUDO_FADING;
+
+ // store backbuffer with all animations that will be stopped for fading out
+ if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
+ PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
+}
+
+static void SetScreenStates_AfterFadingOut()
+{
+ global.border_status = game_status;
+}
+
void FadeIn(int fade_mask)
{
+ SetScreenStates_BeforeFadingIn();
+
+#if 1
+ DrawMaskedBorder(REDRAW_ALL);
+#endif
+
if (fading.fade_mode & FADE_TYPE_TRANSFORM)
FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
else
FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
+
+ FADE_SX = REAL_SX;
+ FADE_SY = REAL_SY;
+ 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
+ redraw_mask = REDRAW_ALL;
+ BackToFront();
}
void FadeOut(int fade_mask)
{
+ // update screen if areas covered by "fade_mask" and "redraw_mask" differ
+ if (!equalRedrawMasks(fade_mask, redraw_mask))
+ BackToFront();
+
+ SetScreenStates_BeforeFadingOut();
+
+ SetOverlayActive(FALSE);
+
+#if 0
+ DrawMaskedBorder(REDRAW_ALL);
+#endif
+
if (fading.fade_mode & FADE_TYPE_TRANSFORM)
FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
else
FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
- global.border_status = game_status;
+ SetScreenStates_AfterFadingOut();
}
static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
void FadeSetNextScreen()
{
- fading = menu.next_screen;
+ fading = menu.next_screen[game_status];
// (do not overwrite fade mode set by FadeSetEnterScreen)
// FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
}
+Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
+{
+ boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
+
+ return (graphic == IMG_UNDEFINED ? NULL :
+ graphic_info[graphic].bitmap != NULL || redefined ?
+ graphic_info[graphic].bitmap :
+ graphic_info[default_graphic].bitmap);
+}
+
+Bitmap *getBackgroundBitmap(int graphic)
+{
+ return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
+}
+
+Bitmap *getGlobalBorderBitmap(int graphic)
+{
+ return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
+}
+
+Bitmap *getGlobalBorderBitmapFromStatus(int status)
+{
+ 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 :
+ IMG_GLOBAL_BORDER);
+
+ return getGlobalBorderBitmap(graphic);
+}
+
void SetWindowBackgroundImageIfDefined(int graphic)
{
if (graphic_info[graphic].bitmap)
void SetWindowBackgroundImage(int graphic)
{
- SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
- graphic_info[graphic].bitmap ?
- graphic_info[graphic].bitmap :
- graphic_info[IMG_BACKGROUND].bitmap);
+ SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
}
void SetMainBackgroundImage(int graphic)
{
- SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
- graphic_info[graphic].bitmap ?
- graphic_info[graphic].bitmap :
- graphic_info[IMG_BACKGROUND].bitmap);
+ SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
}
void SetDoorBackgroundImage(int graphic)
{
- SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
- graphic_info[graphic].bitmap ?
- graphic_info[graphic].bitmap :
- graphic_info[IMG_BACKGROUND].bitmap);
+ SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
}
void SetPanelBackground()
DrawBackground(x, y, width, height);
}
+static int game_status_last = -1;
+static Bitmap *global_border_bitmap_last = NULL;
+static Bitmap *global_border_bitmap = NULL;
+static int real_sx_last = -1, real_sy_last = -1;
+static int full_sxsize_last = -1, full_sysize_last = -1;
+static int dx_last = -1, dy_last = -1;
+static int dxsize_last = -1, dysize_last = -1;
+static int vx_last = -1, vy_last = -1;
+static int vxsize_last = -1, vysize_last = -1;
+
+boolean CheckIfGlobalBorderHasChanged()
+{
+ // if game status has not changed, global border has not changed either
+ if (game_status == game_status_last)
+ return FALSE;
+
+ // determine and store new global border bitmap for current game status
+ global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
+
+ return (global_border_bitmap_last != global_border_bitmap);
+}
+
+boolean CheckIfGlobalBorderRedrawIsNeeded()
+{
+ // if game status has not changed, nothing has to be redrawn
+ if (game_status == game_status_last)
+ return FALSE;
+
+ // redraw if last screen was title screen
+ if (game_status_last == GAME_MODE_TITLE)
+ return TRUE;
+
+ // redraw if global screen border has changed
+ if (CheckIfGlobalBorderHasChanged())
+ return TRUE;
+
+ // redraw if position or size of playfield area has changed
+ if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
+ full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
+ return TRUE;
+
+ // redraw if position or size of door area has changed
+ if (dx_last != DX || dy_last != DY ||
+ dxsize_last != DXSIZE || dysize_last != DYSIZE)
+ return TRUE;
+
+ // redraw if position or size of tape area has changed
+ if (vx_last != VX || vy_last != VY ||
+ vxsize_last != VXSIZE || vysize_last != VYSIZE)
+ return TRUE;
+
+ return FALSE;
+}
+
+void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
+{
+ if (bitmap)
+ BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ else
+ ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+}
+
+void RedrawGlobalBorder()
+{
+ Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
+
+ RedrawGlobalBorderFromBitmap(bitmap);
+
+ redraw_mask = REDRAW_ALL;
+}
+
+static void RedrawGlobalBorderIfNeeded()
+{
+ if (game_status == game_status_last)
+ return;
+
+ // copy current draw buffer to later copy back areas that have not changed
+ if (game_status_last != GAME_MODE_TITLE)
+ BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+
+ if (CheckIfGlobalBorderRedrawIsNeeded())
+ {
+ // redraw global screen border (or clear, if defined to be empty)
+ RedrawGlobalBorderFromBitmap(global_border_bitmap);
+
+ // copy previous playfield and door areas, if they are defined on both
+ // previous and current screen and if they still have the same size
+
+ if (real_sx_last != -1 && real_sy_last != -1 &&
+ REAL_SX != -1 && REAL_SY != -1 &&
+ full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
+ BlitBitmap(bitmap_db_store_1, backbuffer,
+ real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
+ REAL_SX, REAL_SY);
+
+ if (dx_last != -1 && dy_last != -1 &&
+ DX != -1 && DY != -1 &&
+ dxsize_last == DXSIZE && dysize_last == DYSIZE)
+ BlitBitmap(bitmap_db_store_1, backbuffer,
+ dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
+
+ if (vx_last != -1 && vy_last != -1 &&
+ VX != -1 && VY != -1 &&
+ vxsize_last == VXSIZE && vysize_last == VYSIZE)
+ BlitBitmap(bitmap_db_store_1, backbuffer,
+ vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
+
+ redraw_mask = REDRAW_ALL;
+ }
+
+ game_status_last = game_status;
+
+ global_border_bitmap_last = global_border_bitmap;
+
+ real_sx_last = REAL_SX;
+ real_sy_last = REAL_SY;
+ full_sxsize_last = FULL_SXSIZE;
+ full_sysize_last = FULL_SYSIZE;
+ dx_last = DX;
+ dy_last = DY;
+ dxsize_last = DXSIZE;
+ dysize_last = DYSIZE;
+ vx_last = VX;
+ vy_last = VY;
+ vxsize_last = VXSIZE;
+ vysize_last = VYSIZE;
+}
+
void ClearField()
{
+ RedrawGlobalBorderIfNeeded();
+
/* !!! "drawto" might still point to playfield buffer here (see above) !!! */
/* (when entering hall of fame after playing) */
DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
/* !!! maybe this should be done before clearing the background !!! */
- if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
+ if (game_status == GAME_MODE_PLAYING)
{
ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
- SetDrawtoField(DRAW_BUFFERED);
+ SetDrawtoField(DRAW_TO_FIELDBUFFER);
}
else
- SetDrawtoField(DRAW_BACKBUFFER);
+ {
+ SetDrawtoField(DRAW_TO_BACKBUFFER);
+ }
}
void MarkTileDirty(int x, int y)
{
- int xx = redraw_x1 + x;
- int yy = redraw_y1 + y;
-
- if (!redraw[xx][yy])
- redraw_tiles++;
-
- redraw[xx][yy] = TRUE;
- redraw_mask |= REDRAW_TILES;
+ redraw_mask |= REDRAW_FIELD;
}
void SetBorderElement()
gfx.anim_random_frame = GfxRandom[x][y];
}
-inline int getGraphicAnimationFrame(int graphic, int sync_frame)
+int getGraphicAnimationFrame(int graphic, int sync_frame)
{
/* animation synchronized with global frame counter, not move position */
if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
sync_frame);
}
-void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
- Bitmap **bitmap, int *x, int *y,
- boolean get_backside)
+void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
{
struct GraphicInfo *g = &graphic_info[graphic];
- Bitmap *src_bitmap = g->bitmap;
- int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
- int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
- // if no in-game graphics defined, always use standard graphic size
- if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
- tilesize = TILESIZE;
-
if (tilesize == gfx.standard_tile_size)
- src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
+ *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
else if (tilesize == game.tile_size)
- src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
+ *bitmap = g->bitmaps[IMG_BITMAP_GAME];
else
- src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
+ *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
+}
+
+void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
+ boolean get_backside)
+{
+ struct GraphicInfo *g = &graphic_info[graphic];
+ int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
+ int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
if (g->offset_y == 0) /* frames are ordered horizontally */
{
int max_width = g->anim_frames_per_line * g->width;
int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
- src_x = pos % max_width;
- src_y = src_y % g->height + pos / max_width * g->height;
+ *x = pos % max_width;
+ *y = src_y % g->height + pos / max_width * g->height;
}
else if (g->offset_x == 0) /* frames are ordered vertically */
{
int max_height = g->anim_frames_per_line * g->height;
int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
- src_x = src_x % g->width + pos / max_height * g->width;
- src_y = pos % max_height;
+ *x = src_x % g->width + pos / max_height * g->width;
+ *y = pos % max_height;
}
else /* frames are ordered diagonally */
{
- src_x = src_x + frame * g->offset_x;
- src_y = src_y + frame * g->offset_y;
+ *x = src_x + frame * g->offset_x;
+ *y = src_y + frame * g->offset_y;
}
+}
+
+void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
+ Bitmap **bitmap, int *x, int *y,
+ boolean get_backside)
+{
+ struct GraphicInfo *g = &graphic_info[graphic];
- *bitmap = src_bitmap;
- *x = src_x * tilesize / TILESIZE;
- *y = src_y * tilesize / TILESIZE;
+ // if no in-game graphics defined, always use standard graphic size
+ if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
+ tilesize = TILESIZE;
+
+ getGraphicSourceBitmap(graphic, tilesize, bitmap);
+ getGraphicSourceXY(graphic, frame, x, y, get_backside);
+
+ *x = *x * tilesize / g->tile_size;
+ *y = *y * tilesize / g->tile_size;
}
void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
}
-inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
- int *x, int *y, boolean get_backside)
+inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
+ int *x, int *y, boolean get_backside)
{
- struct GraphicInfo *g = &graphic_info[graphic];
- int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
- int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
-
- if (TILESIZE_VAR != TILESIZE)
- return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
- get_backside);
-
- *bitmap = g->bitmap;
-
- if (g->offset_y == 0) /* frames are ordered horizontally */
- {
- int max_width = g->anim_frames_per_line * g->width;
- int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
-
- *x = pos % max_width;
- *y = src_y % g->height + pos / max_width * g->height;
- }
- else if (g->offset_x == 0) /* frames are ordered vertically */
- {
- int max_height = g->anim_frames_per_line * g->height;
- int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
-
- *x = src_x % g->width + pos / max_height * g->width;
- *y = pos % max_height;
- }
- else /* frames are ordered diagonally */
- {
- *x = src_x + frame * g->offset_x;
- *y = src_y + frame * g->offset_y;
- }
+ getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
+ get_backside);
}
void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
int graphic, int frame)
{
- struct GraphicInfo *g = &graphic_info[graphic];
Bitmap *src_bitmap;
int src_x, src_y;
getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
- BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
+ BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
dst_x, dst_y);
}
width = -dx;
dx = TILEX + dx;
}
- else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
+ else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
{
width += dx;
cx = -dx;
dx = 0;
}
- else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
+ else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
width -= dx;
else if (dx) /* general horizontal movement */
MarkTileDirty(x + SIGN(dx), y);
if (y < BY1) /* object enters playfield from the top */
{
- if (cut_mode==CUT_BELOW) /* object completely above top border */
+ if (cut_mode == CUT_BELOW) /* object completely above top border */
return;
y = BY1;
height = -dy;
dy = TILEY + dy;
}
- else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
+ else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
{
height += dy;
cy = -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);
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);
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;
/* (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 */
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];
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)
{
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];
+ int yy = y + xy[i][1];
+ int sxx = sx + xy[i][0];
+ int syy = sy + xy[i][1];
+
+ 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);
+
+ DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
+
+ MarkTileDirty(sxx, syy);
+ }
+
+ /* crumble inner field corners of corner 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 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))
graphic = el_act2crm(element, ACTION_DEFAULT);
- DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
+ if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
+ graphic_info[graphic].anim_frames == 2)
+ DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
MarkTileDirty(sxx, syy);
}
};
int i;
+ /* crumble direct neighbour fields (required for field borders) */
for (i = 0; i < 4; i++)
{
int xx = x + xy[i][0];
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)
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))
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);
+ int anim_delay_value = (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);
int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
int xstep = (xstart < xend ? 1 : 0);
int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
- int x, y;
+ int start = 0;
+ int end = MAX(xend - xstart, yend - ystart);
+ int i;
- for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
+ for (i = start; i <= end; i++)
{
+ int last_frame = end; // last frame of this "for" loop
+ int x = xstart + i * xstep;
+ int y = ystart + i * ystep;
int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
int sx = SX + (SXSIZE - xsize * font_width) / 2;
int sy = SY + (SYSIZE - ysize * font_height) / 2;
int xx, yy;
- SetDrawtoField(DRAW_BUFFERED);
+ SetDrawtoField(DRAW_TO_FIELDBUFFER);
BlitScreenToBitmap(backbuffer);
- SetDrawtoField(DRAW_BACKBUFFER);
+ SetDrawtoField(DRAW_TO_BACKBUFFER);
for (yy = 0; yy < ysize; yy++)
for (xx = 0; xx < xsize; xx++)
level.envelope[envelope_nr].autowrap,
level.envelope[envelope_nr].centered, FALSE);
- redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ redraw_mask |= REDRAW_FIELD;
BackToFront();
- WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
+ SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
}
}
game.envelope_active = FALSE;
- SetDrawtoField(DRAW_BUFFERED);
+ SetDrawtoField(DRAW_TO_FIELDBUFFER);
redraw_mask |= REDRAW_FIELD;
BackToFront();
}
-static void setRequestPosition(int *x, int *y, boolean add_border_size)
+static void setRequestBasePosition(int *x, int *y)
+{
+ int sx_base, sy_base;
+
+ if (request.x != -1)
+ sx_base = request.x;
+ else if (request.align == ALIGN_LEFT)
+ sx_base = SX;
+ else if (request.align == ALIGN_RIGHT)
+ sx_base = SX + SXSIZE;
+ else
+ sx_base = SX + SXSIZE / 2;
+
+ if (request.y != -1)
+ sy_base = request.y;
+ else if (request.valign == VALIGN_TOP)
+ sy_base = SY;
+ else if (request.valign == VALIGN_BOTTOM)
+ sy_base = SY + SYSIZE;
+ else
+ sy_base = SY + SYSIZE / 2;
+
+ *x = sx_base;
+ *y = sy_base;
+}
+
+static void setRequestPositionExt(int *x, int *y, int width, int height,
+ boolean add_border_size)
{
int border_size = request.border_size;
- int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
- int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
- int sx = sx_center - request.width / 2;
- int sy = sy_center - request.height / 2;
+ int sx_base, sy_base;
+ int sx, sy;
+
+ setRequestBasePosition(&sx_base, &sy_base);
+
+ if (request.align == ALIGN_LEFT)
+ sx = sx_base;
+ else if (request.align == ALIGN_RIGHT)
+ sx = sx_base - width;
+ else
+ sx = sx_base - width / 2;
+
+ if (request.valign == VALIGN_TOP)
+ sy = sy_base;
+ else if (request.valign == VALIGN_BOTTOM)
+ sy = sy_base - height;
+ else
+ sy = sy_base - height / 2;
+
+ sx = MAX(0, MIN(sx, WIN_XSIZE - width));
+ sy = MAX(0, MIN(sy, WIN_YSIZE - height));
if (add_border_size)
{
*y = sy;
}
+static void setRequestPosition(int *x, int *y, boolean add_border_size)
+{
+ setRequestPositionExt(x, y, request.width, request.height, add_border_size);
+}
+
void DrawEnvelopeRequest(char *text)
{
char *text_final = text;
int border_size = request.border_size;
int line_spacing = request.line_spacing;
int line_height = font_height + line_spacing;
- int text_width = request.width - 2 * border_size;
- int text_height = request.height - 2 * border_size;
- int line_length = text_width / font_width;
- int max_lines = text_height / line_height;
+ int max_text_width = request.width - 2 * border_size;
+ int max_text_height = request.height - 2 * border_size;
+ int line_length = max_text_width / font_width;
+ int max_lines = max_text_height / line_height;
+ int text_width = line_length * font_width;
int width = request.width;
int height = request.height;
- int tile_size = request.step_offset;
+ int tile_size = MAX(request.step_offset, 1);
int x_steps = width / tile_size;
int y_steps = height / tile_size;
+ int sx_offset = border_size;
+ int sy_offset = border_size;
int sx, sy;
int i, x, y;
- if (request.wrap_single_words)
+ if (request.centered)
+ sx_offset = (request.width - text_width) / 2;
+
+ if (request.wrap_single_words && !request.autowrap)
{
char *src_text_ptr, *dst_text_ptr;
x, y, x_steps, y_steps,
tile_size, tile_size);
- DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
+ /* force DOOR font inside door area */
+ SetFontStatus(GAME_MODE_PSEUDO_DOOR);
+
+ DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
line_length, -1, max_lines, line_spacing, mask_mode,
request.autowrap, request.centered, FALSE);
+ ResetFontStatus();
+
for (i = 0; i < NUM_TOOL_BUTTONS; i++)
RedrawGadget(tool_gadget[i]);
// store readily prepared envelope request for later use when animating
- BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
if (text_door_style)
free(text_door_style);
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);
+ int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
unsigned int anim_delay = 0;
- int width = request.width;
- int height = request.height;
- int tile_size = request.step_offset;
- int max_xsize = width / tile_size;
- int max_ysize = height / tile_size;
+ int tile_size = MAX(request.step_offset, 1);
+ int max_xsize = request.width / tile_size;
+ int max_ysize = request.height / tile_size;
int max_xsize_inner = max_xsize - 2;
int max_ysize_inner = max_ysize - 2;
int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
int xstep = (xstart < xend ? 1 : 0);
int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
- int x, y;
+ int start = 0;
+ int end = MAX(xend - xstart, yend - ystart);
+ int i;
if (setup.quick_doors)
{
xstart = xend;
ystart = yend;
- }
- else
- {
- if (action == ACTION_OPENING)
- PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
- else if (action == ACTION_CLOSING)
- PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
+ end = 0;
}
- for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
+ for (i = start; i <= end; i++)
{
+ int last_frame = end; // last frame of this "for" loop
+ int x = xstart + i * xstep;
+ int y = ystart + i * ystep;
int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
- int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
- int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
- int src_x = sx_center - width / 2;
- int src_y = sy_center - height / 2;
- int dst_x = sx_center - xsize * tile_size / 2;
- int dst_y = sy_center - ysize * tile_size / 2;
int xsize_size_left = (xsize - 1) * tile_size;
int ysize_size_top = (ysize - 1) * tile_size;
int max_xsize_pos = (max_xsize - 1) * tile_size;
int max_ysize_pos = (max_ysize - 1) * tile_size;
+ int width = xsize * tile_size;
+ int height = ysize * tile_size;
+ int src_x, src_y;
+ int dst_x, dst_y;
int xx, yy;
- BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ setRequestPosition(&src_x, &src_y, FALSE);
+ setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
+
+ BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
for (yy = 0; yy < 2; yy++)
{
int yy_size = (yy ? tile_size : ysize_size_top);
if (draw_masked)
- BlitBitmapMasked(bitmap_db_cross, backbuffer,
+ BlitBitmapMasked(bitmap_db_store_2, backbuffer,
src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
else
- BlitBitmap(bitmap_db_cross, backbuffer,
+ BlitBitmap(bitmap_db_store_2, backbuffer,
src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
}
}
- redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ redraw_mask |= REDRAW_FIELD;
- DoAnimation();
BackToFront();
- WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
+ SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
}
}
-
void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
{
- int last_game_status = game_status; /* save current game status */
int graphic = IMG_BACKGROUND_REQUEST;
int sound_opening = SND_REQUEST_OPENING;
int sound_closing = SND_REQUEST_CLOSING;
- int anim_mode = graphic_info[graphic].anim_mode;
+ int anim_mode_1 = request.anim_mode; /* (higher priority) */
+ int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
+ int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
if (game_status == GAME_MODE_PLAYING)
BlitScreenToBitmap(backbuffer);
- SetDrawtoField(DRAW_BACKBUFFER);
+ SetDrawtoField(DRAW_TO_BACKBUFFER);
// SetDrawBackgroundMask(REDRAW_NONE);
if (action == ACTION_OPENING)
{
- BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
if (req_state & REQ_ASK)
{
}
DrawEnvelopeRequest(text);
-
- if (game_status != GAME_MODE_MAIN)
- InitAnimation();
}
- /* force DOOR font inside door area */
- game_status = GAME_MODE_PSEUDO_DOOR;
-
game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
if (action == ACTION_OPENING)
AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
-
}
else
{
game.envelope_active = FALSE;
- game_status = last_game_status; /* restore current game status */
-
if (action == ACTION_CLOSING)
- {
- if (game_status != GAME_MODE_MAIN)
- StopAnimation();
-
- BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
- }
+ BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
// SetDrawBackgroundMask(last_draw_background_mask);
redraw_mask |= REDRAW_FIELD;
- if (game_status == GAME_MODE_MAIN)
- DoAnimation();
-
BackToFront();
if (action == ACTION_CLOSING &&
game_status == GAME_MODE_PLAYING &&
level.game_engine_type == GAME_ENGINE_TYPE_RND)
- SetDrawtoField(DRAW_BUFFERED);
+ SetDrawtoField(DRAW_TO_FIELDBUFFER);
}
void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
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);
}
}
- redraw_mask |= REDRAW_MICROLEVEL;
+ redraw_mask |= REDRAW_FIELD;
}
#define MICROLABEL_EMPTY 0
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;
if (strlen(label_text) > 0)
DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
- redraw_mask |= REDRAW_MICROLEVEL;
+ 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)
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);
- int last_game_status = game_status; /* save current game status */
if (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);
DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
}
- game_status = last_game_status; /* restore current game status */
-
return;
}
break;
}
- DrawPreviewLevelPlayfieldExt(from_x, from_y);
+ DrawPreviewLevelPlayfield(from_x, from_y);
}
/* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
- DrawPreviewLevelLabelExt(label_state);
+ DrawPreviewLevelLabel(label_state);
}
-
- game_status = last_game_status; /* restore current game status */
}
void DrawPreviewLevelInitial()
DrawPreviewLevelExt(FALSE);
}
-inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
- int graphic, int sync_frame, int mask_mode)
+inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
+ int graphic, int sync_frame,
+ int mask_mode)
{
int frame = getGraphicAnimationFrame(graphic, sync_frame);
DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
}
-inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
- int graphic, int sync_frame,
- int mask_mode)
+void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
+ int graphic, int sync_frame, int mask_mode)
{
int frame = getGraphicAnimationFrame(graphic, sync_frame);
DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
}
-inline void DrawGraphicAnimation(int x, int y, int graphic)
+inline static void DrawGraphicAnimation(int x, int y, int graphic)
{
int lx = LEVELX(x), ly = LEVELY(y);
MarkTileDirty(x, y);
}
-inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
+void DrawFixedGraphicAnimation(int x, int y, int graphic)
{
int lx = LEVELX(x), ly = LEVELY(y);
DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
}
-inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
+void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
{
int sx = SCREENX(x), sy = SCREENY(y);
syy = player->GfxPos;
}
- if (!setup.soft_scrolling && ScreenMovPos)
- sxx = syy = 0;
-
if (player_is_opaque)
DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
else
syy = player->GfxPos;
}
- if (!setup.soft_scrolling && ScreenMovPos)
- sxx = syy = 0;
-
if (player_is_opaque)
DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
else
{
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);
{
Event event;
- NextEvent(&event);
+ WaitEvent(&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;
still_wait = FALSE;
}
- DoAnimation();
-
- /* don't eat all CPU time */
- Delay(10);
+ BackToFront();
}
}
static int RequestHandleEvents(unsigned int req_state)
{
- int last_game_status = game_status; /* save current game status */
+ boolean level_solved = (game_status == GAME_MODE_PLAYING &&
+ local_player->LevelSolved_GameEnd);
+ int width = request.width;
+ int height = request.height;
+ int sx, sy;
int result;
- int mx, my;
+
+ setRequestPosition(&sx, &sy, FALSE);
button_status = MB_RELEASED;
while (result < 0)
{
+ if (level_solved)
+ {
+ SetDrawtoField(DRAW_TO_FIELDBUFFER);
+
+ HandleGameActions();
+
+ SetDrawtoField(DRAW_TO_BACKBUFFER);
+
+ if (global.use_envelope_request)
+ {
+ /* copy current state of request area to middle of playfield area */
+ BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
+ }
+ }
+
if (PendingEvent())
{
Event event;
case EVENT_BUTTONRELEASE:
case EVENT_MOTIONNOTIFY:
{
+ int mx, my;
+
if (event.type == EVENT_MOTIONNOTIFY)
{
- if (!PointerInWindow(window))
- continue; /* window and pointer on different screens */
-
if (!button_status)
continue;
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:
- switch (GetEventKey((KeyEvent *)&event, TRUE))
+ {
+ Key key = GetEventKey((KeyEvent *)&event, TRUE);
+
+ switch (key)
{
case KSYM_space:
if (req_state & REQ_CONFIRM)
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;
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;
default:
+ HandleKeysDebug(key);
break;
}
if (req_state & REQ_PLAYER)
result = 0;
+
break;
+ }
case EVENT_KEYRELEASE:
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;
result = 0;
}
- if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
- {
- HandleGameActions();
- }
- else
+ if (level_solved)
{
- DoAnimation();
-
- if (!PendingEvent()) /* delay only if no pending events */
- Delay(10);
+ if (global.use_envelope_request)
+ {
+ /* copy back current state of pressed buttons inside request area */
+ BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
+ }
}
- game_status = GAME_MODE_PSEUDO_DOOR;
-
BackToFront();
-
- game_status = last_game_status; /* restore current game status */
}
return result;
static boolean RequestDoor(char *text, unsigned int req_state)
{
unsigned int old_door_state;
- int last_game_status = game_status; /* save current game status */
int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
int font_nr = FONT_TEXT_2;
char *text_ptr;
DrawBackground(DX, DY, DXSIZE, DYSIZE);
/* force DOOR font inside door area */
- game_status = GAME_MODE_PSEUDO_DOOR;
+ SetFontStatus(GAME_MODE_PSEUDO_DOOR);
/* write text for request */
for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
// text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
}
- game_status = last_game_status; /* restore current game status */
+ ResetFontStatus();
if (req_state & REQ_ASK)
{
return FALSE;
}
- if (game_status != GAME_MODE_MAIN)
- InitAnimation();
-
SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
// ---------- handle request buttons ----------
result = RequestHandleEvents(req_state);
- if (game_status != GAME_MODE_MAIN)
- StopAnimation();
-
UnmapToolButtons();
if (!(req_state & REQ_STAY_OPEN))
// ---------- handle request buttons ----------
result = RequestHandleEvents(req_state);
- if (game_status != GAME_MODE_MAIN)
- StopAnimation();
-
UnmapToolButtons();
ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
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)
}
doors[] =
{
- { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
- { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
+ { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
+ { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
{ -1, -1, -1, NULL }
};
{ DX, DY, DXSIZE, DYSIZE },
{ VX, VY, VXSIZE, VYSIZE }
};
- static int door1 = DOOR_OPEN_1;
+ static int door1 = DOOR_CLOSE_1;
static int door2 = DOOR_CLOSE_2;
unsigned int door_delay = 0;
unsigned int door_delay_value;
for (k = start; k < num_move_steps; k++)
{
+ int last_frame = num_move_steps - 1; // last frame of this "for" loop
+
door_part_done_all = TRUE;
for (i = 0; i < NUM_DOORS; i++)
int sync_frame = kk_door * door_delay_value;
int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
- getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
+ getFixedGraphicSource(dpc->graphic, frame, &bitmap,
+ &g_src_x, &g_src_y);
}
// draw door panel
width = g->width - src_xx;
+ if (width > door_rect->width)
+ width = door_rect->width;
+
// printf("::: k == %d [%d] \n", k, start_step);
}
{
BackToFront();
- if (game_status == GAME_MODE_MAIN)
- DoAnimation();
-
- WaitUntilDelayReached(&door_delay, door_delay_value);
+ 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)
if (door_state & DOOR_ACTION_2)
door2 = door_state & DOOR_ACTION_2;
+ // draw masked border over door area
+ DrawMaskedBorder(REDRAW_DOOR_1);
+ DrawMaskedBorder(REDRAW_DOOR_2);
+
return (door1 | door2);
}
+static boolean useSpecialEditorDoor()
+{
+ int graphic = IMG_GLOBAL_BORDER_EDITOR;
+ boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
+
+ // do not draw special editor door if editor border defined or redefined
+ if (graphic_info[graphic].bitmap != NULL || redefined)
+ return FALSE;
+
+ // do not draw special editor door if global border defined to be empty
+ if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
+ return FALSE;
+
+ // do not draw special editor door if viewport definitions do not match
+ if (EX != VX ||
+ EY >= VY ||
+ EXSIZE != VXSIZE ||
+ EY + EYSIZE != VY + VYSIZE)
+ return FALSE;
+
+ return TRUE;
+}
+
void DrawSpecialEditorDoor()
{
struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
int vy = VY - outer_border;
int exsize = EXSIZE + 2 * outer_border;
+ if (!useSpecialEditorDoor())
+ return;
+
/* draw bigger level editor toolbox window */
BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
top_border_width, top_border_height, ex, ey - top_border_height);
int exsize = EXSIZE + 2 * outer_border;
int eysize = EYSIZE + 2 * outer_border;
+ if (!useSpecialEditorDoor())
+ return;
+
/* draw normal tape recorder window */
if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
{
} toolbutton_info[NUM_TOOL_BUTTONS] =
{
{
- IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
+ IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
TOOL_CTRL_ID_YES, "yes"
},
{
- IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
+ IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
TOOL_CTRL_ID_NO, "no"
},
{
- IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
+ IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
TOOL_CTRL_ID_CONFIRM, "confirm"
},
{
- IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
+ IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
TOOL_CTRL_ID_PLAYER_1, "player 1"
},
{
- IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
+ IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
TOOL_CTRL_ID_PLAYER_2, "player 2"
},
{
- IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
+ IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
TOOL_CTRL_ID_PLAYER_3, "player 3"
},
{
- IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
+ IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
TOOL_CTRL_ID_PLAYER_4, "player 4"
}
};
&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;
}
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;
}
#endif
}
+void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
+ boolean any_player_moving,
+ boolean any_player_snapping,
+ boolean any_player_dropping)
+{
+ if (frame == 0 && !any_player_dropping)
+ {
+ if (!local_player->was_waiting)
+ {
+ if (!CheckSaveEngineSnapshotToList())
+ return;
+
+ local_player->was_waiting = TRUE;
+ }
+ }
+ else if (any_player_moving || any_player_snapping || any_player_dropping)
+ {
+ local_player->was_waiting = FALSE;
+ }
+}
+
+void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
+ boolean murphy_is_dropping)
+{
+ if (murphy_is_waiting)
+ {
+ if (!local_player->was_waiting)
+ {
+ if (!CheckSaveEngineSnapshotToList())
+ return;
+
+ local_player->was_waiting = TRUE;
+ }
+ }
+ else
+ {
+ local_player->was_waiting = FALSE;
+ }
+}
+
void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
boolean any_player_moving,
- boolean player_is_dropping)
+ boolean any_player_snapping,
+ boolean any_player_dropping)
{
if (tape.single_step && tape.recording && !tape.pausing)
- if (frame == 0 && !player_is_dropping)
+ if (frame == 0 && !any_player_dropping)
TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
+ CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
+ any_player_snapping, any_player_dropping);
}
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);
}
void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
void PlayMenuMusic()
{
- PlayMenuMusicExt(menu.music[game_status]);
+ char *curr_music = getCurrentlyPlayingMusicFilename();
+ char *next_music = getMusicListEntry(menu.music[game_status])->filename;
+
+ 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 = getMusicListEntry(menu.music[game_status])->filename;
+
+ if (!strEqual(curr_music, next_music))
+ FadeMusic();
+}
+
+void FadeMenuSoundsAndMusic()
+{
+ FadeMenuSounds();
+ FadeMenuMusic();
}
void PlaySoundActivating()
{
boolean change_fullscreen = (setup.fullscreen !=
video.fullscreen_enabled);
- boolean change_fullscreen_mode = (video.fullscreen_enabled &&
- !strEqual(setup.fullscreen_mode,
- video.fullscreen_mode_current));
boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
setup.window_scaling_percent !=
video.window_scaling_percent);
#endif
if (change_fullscreen ||
- change_fullscreen_mode ||
change_window_scaling_percent)
{
Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
/* save backbuffer content which gets lost when toggling fullscreen mode */
BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
- if (change_fullscreen_mode)
- {
- /* keep fullscreen, but change fullscreen mode (screen resolution) */
- video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
- }
-
if (change_window_scaling_percent)
{
/* keep window mode, but change window scaling */
}
}
+void JoinRectangles(int *x, int *y, int *width, int *height,
+ int x2, int y2, int width2, int height2)
+{
+ // do not join with "off-screen" rectangle
+ if (x2 == -1 || y2 == -1)
+ return;
+
+ *x = MIN(*x, x2);
+ *y = MIN(*y, y2);
+ *width = MAX(*width, width2);
+ *height = MAX(*height, height2);
+}
+
+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;
+
+ // directly set screen modes that are entered without fading
+ if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
+ global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
+ (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
+ global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
+ global.anim_status = global.anim_status_next;
+}
+
+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);
+}
+
+void SetFontStatus(int game_status_new)
+{
+ static int last_game_status = -1;
+
+ if (game_status_new != -1)
+ {
+ // set game status for font use after storing last game status
+ last_game_status = game_status;
+ game_status = game_status_new;
+ }
+ else
+ {
+ // reset game status after font use from last stored game status
+ game_status = last_game_status;
+ }
+}
+
+void ResetFontStatus()
+{
+ SetFontStatus(-1);
+}
+
void ChangeViewportPropertiesIfNeeded()
{
int gfx_game_mode = game_status;
int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
game_status);
+ 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];
- struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
- struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
+ struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
+ struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
+ struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
+ int new_win_xsize = vp_window->width;
+ int new_win_ysize = vp_window->height;
int border_size = vp_playfield->border_size;
int new_sx = vp_playfield->x + border_size;
int new_sy = vp_playfield->y + border_size;
int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
boolean init_gfx_buffers = FALSE;
boolean init_video_buffer = FALSE;
- boolean init_gadgets_and_toons = FALSE;
+ boolean init_gadgets_and_anims = FALSE;
boolean init_em_graphics = FALSE;
- boolean drawing_area_changed = FALSE;
- if (viewport.window.width != WIN_XSIZE ||
- viewport.window.height != WIN_YSIZE)
+ if (new_win_xsize != WIN_XSIZE ||
+ new_win_ysize != WIN_YSIZE)
{
- WIN_XSIZE = viewport.window.width;
- WIN_YSIZE = viewport.window.height;
+ WIN_XSIZE = new_win_xsize;
+ WIN_YSIZE = new_win_ysize;
init_video_buffer = TRUE;
init_gfx_buffers = TRUE;
+ init_gadgets_and_anims = TRUE;
// printf("::: video: init_video_buffer, init_gfx_buffers\n");
}
new_tilesize_var != TILESIZE_VAR
)
{
+ // ------------------------------------------------------------------------
+ // determine next fading area for changed viewport definitions
+ // ------------------------------------------------------------------------
+
+ // start with current playfield area (default fading area)
+ FADE_SX = REAL_SX;
+ FADE_SY = REAL_SY;
+ FADE_SXSIZE = FULL_SXSIZE;
+ FADE_SYSIZE = FULL_SYSIZE;
+
+ // add new playfield area if position or size has changed
+ if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
+ new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
+ {
+ JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
+ new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
+ }
+
+ // add current and new door 1 area if position or size has changed
+ if (new_dx != DX || new_dy != DY ||
+ new_dxsize != DXSIZE || new_dysize != DYSIZE)
+ {
+ JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
+ DX, DY, DXSIZE, DYSIZE);
+ JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
+ new_dx, new_dy, new_dxsize, new_dysize);
+ }
+
+ // add current and new door 2 area if position or size has changed
+ if (new_dx != VX || new_dy != VY ||
+ new_dxsize != VXSIZE || new_dysize != VYSIZE)
+ {
+ JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
+ VX, VY, VXSIZE, VYSIZE);
+ JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
+ new_vx, new_vy, new_vxsize, new_vysize);
+ }
+
+ // ------------------------------------------------------------------------
+ // handle changed tile size
+ // ------------------------------------------------------------------------
+
if (new_tilesize_var != TILESIZE_VAR)
{
// printf("::: new_tilesize_var != TILESIZE_VAR\n");
// changing tile size invalidates scroll values of engine snapshots
- FreeEngineSnapshot();
+ FreeEngineSnapshotSingle();
// changing tile size requires update of graphic mapping for EM engine
init_em_graphics = TRUE;
}
- if (new_sx != SX ||
- new_sy != SY ||
- new_sxsize != SXSIZE ||
- new_sysize != SYSIZE ||
- new_real_sx != REAL_SX ||
- new_real_sy != REAL_SY ||
- new_full_sxsize != FULL_SXSIZE ||
- new_full_sysize != FULL_SYSIZE)
- {
- if (!init_video_buffer)
- drawing_area_changed = TRUE;
- }
-
SX = new_sx;
SY = new_sy;
DX = new_dx;
TILESIZE_VAR = new_tilesize_var;
init_gfx_buffers = TRUE;
- init_gadgets_and_toons = TRUE;
+ init_gadgets_and_anims = TRUE;
// printf("::: viewports: init_gfx_buffers\n");
- // printf("::: viewports: init_gadgets_and_toons\n");
+ // printf("::: viewports: init_gadgets_and_anims\n");
}
if (init_gfx_buffers)
SCR_FIELDX = new_scr_fieldx;
SCR_FIELDY = new_scr_fieldy;
- gfx.drawing_area_changed = drawing_area_changed;
-
SetDrawDeactivationMask(REDRAW_NONE);
SetDrawBackgroundMask(REDRAW_FIELD);
}
// printf("::: init_video_buffer\n");
InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
+ InitImageTextures();
}
- if (init_gadgets_and_toons)
+ if (init_gadgets_and_anims)
{
- // printf("::: init_gadgets_and_toons\n");
+ // printf("::: init_gadgets_and_anims\n");
InitGadgets();
- InitToons();
+ InitGlobalAnimations();
}
if (init_em_graphics)