X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Ftools.c;h=3dcf88af26d04ebdcc2cff721e38734d10bcdc03;hp=da879fa684a8fdc6db2179cc52523c596d86d5f3;hb=2178db0a0652bc87717aa1a55c888258ad6701e5;hpb=f89a490028c36509216b97a96b779b779c2065c9 diff --git a/src/tools.c b/src/tools.c index da879fa6..3dcf88af 100644 --- a/src/tools.c +++ b/src/tools.c @@ -24,7 +24,8 @@ /* 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 @@ -173,6 +174,9 @@ static int el_act2crm(int, int); static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS]; static int request_gadget_id = -1; +static unsigned int sync_frame_delay = 0; +static unsigned int sync_frame_delay_value = GAME_FRAME_DELAY; + static char *print_if_not_empty(int element) { static char *s = NULL; @@ -227,7 +231,7 @@ void DumpTile(int x, int y) 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("\n"); } @@ -284,68 +288,125 @@ void RedrawPlayfield() 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; + + if (x == -1 && y == -1) + return; - BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y); + if (draw_target == DRAW_BORDER_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 && 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_BORDER_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_BORDER_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) + if (game_status == GAME_MODE_LOADING || + game_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); + } +} + +void DrawMaskedBorder_FIELD() +{ + DrawMaskedBorderExt_FIELD(DRAW_BORDER_TO_BACKBUFFER); +} + +void DrawMaskedBorder(int redraw_mask) +{ + DrawMaskedBorderExt(redraw_mask, DRAW_BORDER_TO_BACKBUFFER); +} + +void DrawMaskedBorderToTarget(int draw_target) +{ + if (draw_target == DRAW_BORDER_TO_SCREEN) + { + DrawMaskedBorderExt(REDRAW_ALL, draw_target); + } + else + { + int last_border_status = global.border_status; + + if (draw_target == DRAW_BORDER_TO_FADE_SOURCE) + { + global.border_status = gfx.fade_border_source_status; + gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source; + } + else + { + global.border_status = gfx.fade_border_target_status; + gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target; + } + + DrawMaskedBorderExt(REDRAW_ALL, draw_target); + + global.border_status = last_border_status; + gfx.masked_border_bitmap_ptr = backbuffer; } } @@ -431,13 +492,61 @@ void DrawFramesPerSecond() font_nr, BLIT_OPAQUE); } +#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; + + diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' '); + + for (i = 0; i < diff_2_max; i++) + diff_bar[pos++] = (diff_2 >= 0 ? ' ' : + i >= diff_2_max - diff_2_cut ? '-' : ' '); + + diff_bar[pos++] = '|'; + + for (i = 0; i < diff_2_max; i++) + diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' '); + + diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' '); + + diff_bar[pos++] = '\0'; + + Error(ERR_INFO, "%06d [%02d] [%c%02d] %s", + counter, + diff_1, + (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2), + diff_bar); + + last_counter = counter; +} +#endif + void BackToFront() { + static int last_redraw_mask = REDRAW_NONE; + + // 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) - return; + redraw_mask = last_redraw_mask; + + last_redraw_mask = redraw_mask; +#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 // draw frames per second (only if debug mode is enabled) if (redraw_mask & REDRAW_FPS) @@ -474,6 +583,10 @@ void BackToFront() } redraw_mask = REDRAW_NONE; + +#if DEBUG_FRAME_TIME + PrintFrameTimeDebugging(); +#endif } static void FadeCrossSaveBackbuffer() @@ -483,7 +596,12 @@ static void FadeCrossSaveBackbuffer() static void FadeCrossRestoreBackbuffer() { + int redraw_mask_last = redraw_mask; + BlitBitmap(bitmap_db_cross, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); + + // do not change redraw mask when restoring backbuffer after cross-fading + redraw_mask = redraw_mask_last; } static void FadeExt(int fade_mask, int fade_mode, int fade_type) @@ -547,10 +665,10 @@ static void FadeExt(int fade_mask, int fade_mode, int fade_type) 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 */ @@ -588,22 +706,70 @@ static void FadeExt(int fade_mask, int fade_mode, int fade_type) redraw_mask &= ~fade_mask; } +static void SetScreenStates_BeforeFadingIn() +{ +} + +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; + + // force update of global animation status in case of rapid screen changes + redraw_mask = REDRAW_ALL; + BackToFront(); +} + +static void SetScreenStates_BeforeFadingOut() +{ + // store new target screen (to use correct masked border for fading) + gfx.fade_border_target_status = game_status; + + global.anim_status = GAME_MODE_PSEUDO_FADING; +} + +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; + + SetScreenStates_AfterFadingIn(); } void FadeOut(int fade_mask) { + SetScreenStates_BeforeFadingOut(); + +#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) @@ -639,7 +805,7 @@ void FadeSetEnterScreen() 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) */ @@ -677,6 +843,39 @@ void FadeSkipNextFadeOut() 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) @@ -697,26 +896,17 @@ void SetDoorBackgroundImageIfDefined(int graphic) 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() @@ -774,27 +964,30 @@ 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 CheckIfRedrawGlobalBorderIsNeeded() +boolean CheckIfGlobalBorderHasChanged() { - int global_border_graphic; - + // if game status has not changed, global border has not changed either if (game_status == game_status_last) return FALSE; - global_border_graphic = - (game_status == GAME_MODE_MAIN ? IMG_GLOBAL_BORDER_MAIN : - game_status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES : - game_status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR : - game_status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING : - IMG_GLOBAL_BORDER); + // determine and store new global border bitmap for current game status + global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status); - global_border_bitmap = - (graphic_info[global_border_graphic].bitmap ? - graphic_info[global_border_graphic].bitmap : - graphic_info[IMG_GLOBAL_BORDER].bitmap); + 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 (global_border_bitmap_last != global_border_bitmap) + if (CheckIfGlobalBorderHasChanged()) return TRUE; // redraw if position or size of playfield area has changed @@ -815,23 +1008,36 @@ boolean CheckIfRedrawGlobalBorderIsNeeded() 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 - BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); + if (game_status_last != GAME_MODE_TITLE) + BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); - if (CheckIfRedrawGlobalBorderIsNeeded()) + if (CheckIfGlobalBorderRedrawIsNeeded()) { // redraw global screen border (or clear, if defined to be empty) - - if (global_border_bitmap) - BlitBitmap(global_border_bitmap, backbuffer, - 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); - else - ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE); + 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 @@ -958,7 +1164,7 @@ void SetRandomAnimationValue(int x, int y) 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) @@ -1015,8 +1221,8 @@ void getSizedGraphicSourceExt(int graphic, int frame, int tilesize, } *bitmap = src_bitmap; - *x = src_x * tilesize / TILESIZE; - *y = src_y * tilesize / TILESIZE; + *x = src_x * tilesize / g->tile_size; + *y = src_y * tilesize / g->tile_size; } void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap, @@ -1043,8 +1249,8 @@ void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y) 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); @@ -1077,6 +1283,9 @@ inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap, *x = src_x + frame * g->offset_x; *y = src_y + frame * g->offset_y; } + + *x = *x * TILESIZE_VAR / g->tile_size; + *y = *y * TILESIZE_VAR / g->tile_size; } void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y) @@ -1186,13 +1395,12 @@ void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic, 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); } @@ -1253,20 +1461,20 @@ inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy, 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; @@ -1280,7 +1488,7 @@ inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy, 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; @@ -2219,6 +2427,7 @@ static void setRequestPosition(int *x, int *y, boolean add_border_size) void DrawEnvelopeRequest(char *text) { + int last_game_status = game_status; /* save current game status */ char *text_final = text; char *text_door_style = NULL; int graphic = IMG_BACKGROUND_REQUEST; @@ -2230,19 +2439,25 @@ void DrawEnvelopeRequest(char *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; @@ -2279,10 +2494,15 @@ void DrawEnvelopeRequest(char *text) 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 */ + SetGameStatus(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); + SetGameStatus(last_game_status); /* restore current game status */ + for (i = 0; i < NUM_TOOL_BUTTONS; i++) RedrawGadget(tool_gadget[i]); @@ -2305,7 +2525,7 @@ void AnimateEnvelopeRequest(int anim_mode, int action) int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2; unsigned int anim_delay = 0; - int tile_size = request.step_offset; + 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; @@ -2327,13 +2547,6 @@ void AnimateEnvelopeRequest(int anim_mode, int action) ystart = yend; end = 0; } - else - { - if (action == ACTION_OPENING) - PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE); - else if (action == ACTION_CLOSING) - PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE); - } for (i = start; i <= end; i++) { @@ -2388,7 +2601,6 @@ void AnimateEnvelopeRequest(int anim_mode, int action) 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; @@ -2432,9 +2644,6 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action) 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) @@ -2459,8 +2668,6 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action) game.envelope_active = FALSE; - game_status = last_game_status; /* restore current game status */ - if (action == ACTION_CLOSING) { if (game_status != GAME_MODE_MAIN) @@ -2699,7 +2906,7 @@ static void DrawPreviewLevelExt(boolean restart) DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); } - game_status = last_game_status; /* restore current game status */ + SetGameStatus(last_game_status); /* restore current game status */ return; } @@ -2801,7 +3008,7 @@ static void DrawPreviewLevelExt(boolean restart) DrawPreviewLevelLabelExt(label_state); } - game_status = last_game_status; /* restore current game status */ + SetGameStatus(last_game_status); /* restore current game status */ } void DrawPreviewLevelInitial() @@ -2814,8 +3021,9 @@ void DrawPreviewLevelAnimation() 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); @@ -2825,9 +3033,8 @@ inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y, 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); @@ -2837,7 +3044,7 @@ inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y, 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); @@ -2850,7 +3057,7 @@ inline void DrawGraphicAnimation(int x, int y, int graphic) 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); @@ -2874,7 +3081,7 @@ void DrawLevelElementAnimation(int x, int y, int element) 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); @@ -3345,8 +3552,7 @@ void WaitForEventToContinue() DoAnimation(); - /* don't eat all CPU time */ - Delay(10); + WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value); } } @@ -3358,7 +3564,6 @@ static int RequestHandleEvents(unsigned int req_state) { boolean level_solved = (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd); - int last_game_status = game_status; /* save current game status */ int width = request.width; int height = request.height; int sx, sy; @@ -3518,16 +3723,11 @@ static int RequestHandleEvents(unsigned int req_state) else { DoAnimation(); - - if (!PendingEvent()) /* delay only if no pending events */ - Delay(10); } - game_status = GAME_MODE_PSEUDO_DOOR; - BackToFront(); - game_status = last_game_status; /* restore current game status */ + WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value); } return result; @@ -3593,7 +3793,7 @@ static boolean RequestDoor(char *text, unsigned int req_state) DrawBackground(DX, DY, DXSIZE, DYSIZE); /* force DOOR font inside door area */ - game_status = GAME_MODE_PSEUDO_DOOR; + SetGameStatus(GAME_MODE_PSEUDO_DOOR); /* write text for request */ for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++) @@ -3633,7 +3833,7 @@ static boolean RequestDoor(char *text, unsigned int req_state) // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0); } - game_status = last_game_status; /* restore current game status */ + SetGameStatus(last_game_status); /* restore current game status */ if (req_state & REQ_ASK) { @@ -4077,7 +4277,7 @@ unsigned int MoveDoor(unsigned int door_state) { 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; @@ -4305,6 +4505,9 @@ unsigned int MoveDoor(unsigned int door_state) width = g->width - src_xx; + if (width > door_rect->width) + width = door_rect->width; + // printf("::: k == %d [%d] \n", k, start_step); } @@ -4388,9 +4591,36 @@ unsigned int MoveDoor(unsigned int door_state) 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]; @@ -4402,6 +4632,9 @@ void DrawSpecialEditorDoor() 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); @@ -4423,6 +4656,9 @@ void UndrawSpecialEditorDoor() 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) { @@ -8042,15 +8278,38 @@ void ToggleFullscreenOrChangeWindowScalingIfNeeded() } } +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 SetGameStatus(int game_status_new) +{ + game_status = game_status_new; + + global.anim_status_next = game_status; +} + 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; @@ -8086,14 +8345,15 @@ void ChangeViewportPropertiesIfNeeded() boolean init_gadgets_and_toons = FALSE; boolean init_em_graphics = 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_toons = TRUE; // printf("::: video: init_video_buffer, init_gfx_buffers\n"); } @@ -8132,6 +8392,48 @@ void ChangeViewportPropertiesIfNeeded() 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"); @@ -8193,6 +8495,7 @@ void ChangeViewportPropertiesIfNeeded() // printf("::: init_video_buffer\n"); InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen); + InitImageTextures(); } if (init_gadgets_and_toons) @@ -8201,6 +8504,7 @@ void ChangeViewportPropertiesIfNeeded() InitGadgets(); InitToons(); + InitGlobalAnimations(); } if (init_em_graphics)