X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ftools.c;h=88c813441050f05ac9595b2a56261e3d586b1866;hb=ba702cd338586991ab20176cf5587afbb4d77af7;hp=ff28a2c1785e1c8cc45034335d054891248374b9;hpb=2dea3ce5bd001ba9119808d9b7b271e868f844bb;p=rocksndiamonds.git diff --git a/src/tools.c b/src/tools.c index ff28a2c1..88c81344 100644 --- a/src/tools.c +++ b/src/tools.c @@ -19,6 +19,7 @@ #include "cartoons.h" #include "network.h" #include "tape.h" +#include "screens.h" /* select level set with EMC X11 graphics before activating EM GFX debugging */ @@ -194,14 +195,20 @@ void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height) BlitBitmap(drawto, window, x, y, width, height, x, y); } +void DrawMaskedBorder_Rect(int x, int y, int width, int height) +{ + Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap; + + SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0); + BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y); +} + void DrawMaskedBorder_FIELD() { if (game_status >= GAME_MODE_TITLE && game_status <= GAME_MODE_PLAYING && border.draw_masked[game_status]) - BlitBitmapMasked(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer, - REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, - REAL_SX, REAL_SY); + DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); } void DrawMaskedBorder_DOOR_1() @@ -209,16 +216,14 @@ void DrawMaskedBorder_DOOR_1() if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] && (game_status != GAME_MODE_EDITOR || border.draw_masked[GFX_SPECIAL_ARG_EDITOR])) - BlitBitmapMasked(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer, - DX, DY, DXSIZE, DYSIZE, DX, DY); + DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE); } void DrawMaskedBorder_DOOR_2() { if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] && game_status != GAME_MODE_EDITOR) - BlitBitmapMasked(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer, - VX, VY, VXSIZE, VYSIZE, VX, VY); + DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE); } void DrawMaskedBorder_DOOR_3() @@ -236,6 +241,11 @@ void DrawMaskedBorder_ALL() void DrawMaskedBorder(int redraw_mask) { + /* do not draw masked screen borders when displaying title screens */ + if (effectiveGameStatus() == GAME_MODE_TITLE || + effectiveGameStatus() == GAME_MODE_MESSAGE) + return; + if (redraw_mask & REDRAW_ALL) DrawMaskedBorder_ALL(); else @@ -270,7 +280,7 @@ void BackToFront() if (redraw_mask & REDRAW_TILES && game_status == GAME_MODE_PLAYING && - border.draw_masked[game_status]) + border.draw_masked[GAME_MODE_PLAYING]) redraw_mask |= REDRAW_FIELD; if (global.fps_slowdown && game_status == GAME_MODE_PLAYING) @@ -310,15 +320,16 @@ void BackToFront() SyncDisplay(); -#if 1 - DrawMaskedBorder(redraw_mask); -#endif + /* prevent drawing 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 (redraw_mask & REDRAW_ALL) { -#if 0 - DrawMaskedBorder(REDRAW_ALL); -#endif BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); redraw_mask = REDRAW_NONE; @@ -329,9 +340,6 @@ void BackToFront() if (game_status != GAME_MODE_PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER) { -#if 0 - DrawMaskedBorder(REDRAW_FIELD); -#endif BlitBitmap(backbuffer, window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); } @@ -350,21 +358,23 @@ void BackToFront() ABS(ScreenMovPos) == ScrollStepSize || redraw_tiles > REDRAWTILES_THRESHOLD) { -#if 1 - if (border.draw_masked[GFX_SPECIAL_ARG_MAIN]) + if (border.draw_masked[GAME_MODE_PLAYING]) { - BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY); + if (buffer != backbuffer) + { + /* copy playfield buffer to backbuffer to add masked border */ + BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY); + DrawMaskedBorder(REDRAW_FIELD); + } - DrawMaskedBorder(REDRAW_FIELD); BlitBitmap(backbuffer, window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); } else + { BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY); -#else - BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY); -#endif + } #if 0 #ifdef DEBUG @@ -388,28 +398,13 @@ void BackToFront() if (redraw_mask & REDRAW_DOORS) { if (redraw_mask & REDRAW_DOOR_1) - { -#if 0 - DrawMaskedBorder(REDRAW_DOOR_1); -#endif BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY); - } if (redraw_mask & REDRAW_DOOR_2) - { -#if 0 - DrawMaskedBorder(REDRAW_DOOR_2); -#endif BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY); - } if (redraw_mask & REDRAW_DOOR_3) - { -#if 0 - DrawMaskedBorder(REDRAW_DOOR_3); -#endif BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY); - } redraw_mask &= ~REDRAW_DOORS; } @@ -529,9 +524,8 @@ void FadeExt(int fade_mask, int fade_mode) { void (*draw_border_function)(void) = NULL; Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL); - int fade_delay = menu.fade_delay; - int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0); int x, y, width, height; + int fade_delay, post_delay; if (fade_mask & REDRAW_FIELD) { @@ -540,6 +534,9 @@ void FadeExt(int fade_mask, int fade_mode) width = FULL_SXSIZE; height = FULL_SYSIZE; + fade_delay = menu.fade_delay; + post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0); + draw_border_function = DrawMaskedBorder_FIELD; } else /* REDRAW_ALL */ @@ -548,6 +545,9 @@ void FadeExt(int fade_mask, int fade_mode) y = 0; width = WIN_XSIZE; height = WIN_YSIZE; + + fade_delay = title.fade_delay_final; + post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0); } redraw_mask |= fade_mask; @@ -588,10 +588,30 @@ void FadeCrossSaveBackbuffer() BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); } +void SetWindowBackgroundImageIfDefined(int graphic) +{ + if (graphic_info[graphic].bitmap) + SetWindowBackgroundBitmap(graphic_info[graphic].bitmap); +} + void SetMainBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) - SetMainBackgroundImage(graphic); + SetMainBackgroundBitmap(graphic_info[graphic].bitmap); +} + +void SetDoorBackgroundImageIfDefined(int graphic) +{ + if (graphic_info[graphic].bitmap) + SetDoorBackgroundBitmap(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); } void SetMainBackgroundImage(int graphic) @@ -618,21 +638,46 @@ void SetPanelBackground() SetDoorBackgroundBitmap(bitmap_db_panel); } -void DrawBackground(int dst_x, int dst_y, int width, int height) +void DrawBackground(int x, int y, int width, int height) { -#if 1 - ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height); + /* !!! "drawto" might still point to playfield buffer here (see below) !!! */ + /* (when entering hall of fame after playing) */ +#if 0 + ClearRectangleOnBackground(drawto, x, y, width, height); #else - ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height); + ClearRectangleOnBackground(backbuffer, x, y, width, height); #endif redraw_mask |= REDRAW_FIELD; } +void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr) +{ + struct FontBitmapInfo *font = getFontBitmapInfo(font_nr); + + if (font->bitmap == NULL) + return; + + DrawBackground(x, y, width, height); +} + +void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic) +{ + struct GraphicInfo *g = &graphic_info[graphic]; + + if (g->bitmap == NULL) + return; + + DrawBackground(x, y, width, height); +} + void ClearWindow() { + /* !!! "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) { ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE); @@ -679,6 +724,39 @@ void SetBorderElement() } } +void FloodFillLevel(int from_x, int from_y, int fill_element, + short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY], + int max_fieldx, int max_fieldy) +{ + int i,x,y; + int old_element; + static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } }; + static int safety = 0; + + /* check if starting field still has the desired content */ + if (field[from_x][from_y] == fill_element) + return; + + safety++; + + if (safety > max_fieldx * max_fieldy) + Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug."); + + old_element = field[from_x][from_y]; + field[from_x][from_y] = fill_element; + + for (i = 0; i < 4; i++) + { + x = from_x + check[i][0]; + y = from_y + check[i][1]; + + if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element) + FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy); + } + + safety--; +} + void SetRandomAnimationValue(int x, int y) { gfx.anim_random_frame = GfxRandom[x][y]; @@ -1346,13 +1424,17 @@ void DrawScreenField(int x, int y) boolean cut_mode = NO_CUTTING; if (element == EL_QUICKSAND_EMPTYING || + element == EL_QUICKSAND_FAST_EMPTYING || element == EL_MAGIC_WALL_EMPTYING || element == EL_BD_MAGIC_WALL_EMPTYING || + element == EL_DC_MAGIC_WALL_EMPTYING || element == EL_AMOEBA_DROPPING) cut_mode = CUT_ABOVE; else if (element == EL_QUICKSAND_FILLING || + element == EL_QUICKSAND_FAST_FILLING || element == EL_MAGIC_WALL_FILLING || - element == EL_BD_MAGIC_WALL_FILLING) + element == EL_BD_MAGIC_WALL_FILLING || + element == EL_DC_MAGIC_WALL_FILLING) cut_mode = CUT_BELOW; if (cut_mode == CUT_ABOVE) @@ -1394,8 +1476,10 @@ void DrawScreenField(int x, int y) content_old = Store[oldx][oldy]; if (element_old == EL_QUICKSAND_EMPTYING || + element_old == EL_QUICKSAND_FAST_EMPTYING || element_old == EL_MAGIC_WALL_EMPTYING || element_old == EL_BD_MAGIC_WALL_EMPTYING || + element_old == EL_DC_MAGIC_WALL_EMPTYING || element_old == EL_AMOEBA_DROPPING) cut_mode = CUT_ABOVE; @@ -1542,9 +1626,17 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action) for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++) DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr); +#if 1 + DrawTextBuffer(SX + sx + font_width, SY + sy + font_height, + level.envelope[envelope_nr].text, font_nr, max_xsize, + xsize - 2, ysize - 2, mask_mode, + level.envelope[envelope_nr].autowrap, + level.envelope[envelope_nr].centered, FALSE); +#else DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height, level.envelope[envelope_nr].text, font_nr, max_xsize, xsize - 2, ysize - 2, mask_mode); +#endif redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER; BackToFront(); @@ -1666,8 +1758,6 @@ void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y) static void DrawPreviewLevelExt(int from_x, int from_y) { boolean show_level_border = (BorderElement != EL_EMPTY); - int dst_x = preview.x; - int dst_y = preview.y; int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); int level_ysize = lev_fieldy + (show_level_border ? 2 : 0); int tile_size = preview.tile_size; @@ -1675,6 +1765,8 @@ static void DrawPreviewLevelExt(int from_x, int from_y) int preview_height = preview.ysize * tile_size; int real_preview_xsize = MIN(level_xsize, preview.xsize); int real_preview_ysize = MIN(level_ysize, preview.ysize); + int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align); + int dst_y = SY + preview.y; int x, y; DrawBackground(dst_x, dst_y, preview_width, preview_height); @@ -1708,8 +1800,24 @@ static void DrawPreviewLevelExt(int from_x, int from_y) #define MICROLABEL_IMPORTED_BY_HEAD 6 #define MICROLABEL_IMPORTED_BY 7 +static int getMaxTextLength(struct TextPosInfo *pos, int font_nr) +{ + int max_text_width = SXSIZE; + int font_width = getFontWidth(font_nr); + + if (pos->align == ALIGN_CENTER) + max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2); + else if (pos->align == ALIGN_RIGHT) + max_text_width = pos->x; + else + max_text_width = SXSIZE - pos->x; + + return max_text_width / font_width; +} + static void DrawPreviewLevelLabelExt(int mode) { + struct TextPosInfo *pos = &menu.main.text.level_info_2; char label_text[MAX_OUTPUT_LINESIZE + 1]; int max_len_label_text; int font_nr = FONT_TEXT_2; @@ -1720,7 +1828,16 @@ static void DrawPreviewLevelLabelExt(int mode) mode == MICROLABEL_IMPORTED_BY_HEAD) font_nr = FONT_TEXT_3; +#if 1 + max_len_label_text = getMaxTextLength(pos, font_nr); +#else max_len_label_text = SXSIZE / getFontWidth(font_nr); +#endif + +#if 1 + if (pos->chars != -1) + max_len_label_text = pos->chars; +#endif for (i = 0; i < max_len_label_text; i++) label_text[i] = ' '; @@ -1728,10 +1845,14 @@ static void DrawPreviewLevelLabelExt(int mode) if (strlen(label_text) > 0) { +#if 1 + DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); +#else int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2; int lypos = MICROLABEL2_YPOS; DrawText(lxpos, lypos, label_text, font_nr); +#endif } strncpy(label_text, @@ -1747,10 +1868,14 @@ static void DrawPreviewLevelLabelExt(int mode) if (strlen(label_text) > 0) { +#if 1 + DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); +#else int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2; int lypos = MICROLABEL2_YPOS; DrawText(lxpos, lypos, label_text, font_nr); +#endif } redraw_mask |= REDRAW_MICROLEVEL; @@ -1773,7 +1898,20 @@ void DrawPreviewLevel(boolean restart) if (restart) { - from_x = from_y = 0; + from_x = 0; + from_y = 0; + + if (preview.anim_mode == ANIM_CENTERED) + { + if (level_xsize > preview.xsize) + from_x = (level_xsize - preview.xsize) / 2; + if (level_ysize > preview.ysize) + from_y = (level_ysize - preview.ysize) / 2; + } + + from_x += preview.xoffset; + from_y += preview.yoffset; + scroll_direction = MV_RIGHT; label_state = 1; label_counter = 0; @@ -1787,18 +1925,35 @@ void DrawPreviewLevel(boolean restart) if (leveldir_current->name) { + struct TextPosInfo *pos = &menu.main.text.level_info_1; char label_text[MAX_OUTPUT_LINESIZE + 1]; int font_nr = FONT_TEXT_1; +#if 1 + int max_len_label_text = getMaxTextLength(pos, font_nr); +#else int max_len_label_text = SXSIZE / getFontWidth(font_nr); +#endif +#if 0 + int text_width; int lxpos, lypos; +#endif + +#if 1 + if (pos->chars != -1) + max_len_label_text = pos->chars; +#endif strncpy(label_text, leveldir_current->name, max_len_label_text); label_text[max_len_label_text] = '\0'; +#if 1 + DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); +#else lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2; lypos = SY + MICROLABEL1_YPOS; DrawText(lxpos, lypos, label_text, font_nr); +#endif } game_status = last_game_status; /* restore current game status */ @@ -1807,7 +1962,8 @@ void DrawPreviewLevel(boolean restart) } /* scroll preview level, if needed */ - if ((level_xsize > preview.xsize || level_ysize > preview.ysize) && + if (preview.anim_mode != ANIM_NONE && + (level_xsize > preview.xsize || level_ysize > preview.ysize) && DelayReached(&scroll_delay, scroll_delay_value)) { switch (scroll_direction) @@ -2399,7 +2555,11 @@ boolean Request(char *text, unsigned int req_state) if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN) { max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN; +#if 1 + font_nr = FONT_TEXT_1; +#else font_nr = FONT_LEVEL_NUMBER; +#endif break; } @@ -2544,7 +2704,7 @@ boolean Request(char *text, unsigned int req_state) NextEvent(&event); - switch(event.type) + switch (event.type) { case EVENT_BUTTONPRESS: case EVENT_BUTTONRELEASE: @@ -2576,7 +2736,7 @@ boolean Request(char *text, unsigned int req_state) /* this sets 'request_gadget_id' */ HandleGadgets(mx, my, button_status); - switch(request_gadget_id) + switch (request_gadget_id) { case TOOL_CTRL_ID_YES: result = TRUE; @@ -2609,7 +2769,7 @@ boolean Request(char *text, unsigned int req_state) } case EVENT_KEYPRESS: - switch(GetEventKey((KeyEvent *)&event, TRUE)) + switch (GetEventKey((KeyEvent *)&event, TRUE)) { case KSYM_Return: result = 1; @@ -2645,6 +2805,23 @@ boolean Request(char *text, unsigned int req_state) result = 0; } +#if 1 + + if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd) + { + HandleGameActions(); + BackToFront(); + } + else + { + DoAnimation(); + + if (!PendingEvent()) /* delay only if no pending events */ + Delay(10); + } + +#else + DoAnimation(); #if 1 @@ -2653,6 +2830,8 @@ boolean Request(char *text, unsigned int req_state) #else /* don't eat all CPU time */ Delay(10); +#endif + #endif } @@ -4366,19 +4545,19 @@ em_object_mapping_list[] = }, { Xexit, TRUE, FALSE, - EL_EXIT_CLOSED, -1, -1 + EL_EM_EXIT_CLOSED, -1, -1 }, { Xexit_1, TRUE, FALSE, - EL_EXIT_OPEN, -1, -1 + EL_EM_EXIT_OPEN, -1, -1 }, { Xexit_2, FALSE, FALSE, - EL_EXIT_OPEN, -1, -1 + EL_EM_EXIT_OPEN, -1, -1 }, { Xexit_3, FALSE, FALSE, - EL_EXIT_OPEN, -1, -1 + EL_EM_EXIT_OPEN, -1, -1 }, { Xdynamite, TRUE, FALSE, @@ -5283,14 +5462,18 @@ int map_direction_EM_to_RND(int direction) int get_next_element(int element) { - switch(element) + switch (element) { case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL; case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY; + case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL; + case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY; case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL; case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE; case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL; case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE; + case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL; + case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE; case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET; default: return element; @@ -6108,9 +6291,26 @@ void PlayMenuMusic() if (music == MUS_UNDEFINED) return; + if (!setup.sound_music) + return; + PlayMusic(music); } +void PlaySoundActivating() +{ +#if 0 + PlaySound(SND_MENU_ITEM_ACTIVATING); +#endif +} + +void PlaySoundSelecting() +{ +#if 0 + PlaySound(SND_MENU_ITEM_SELECTING); +#endif +} + void ToggleFullscreenIfNeeded() { boolean change_fullscreen = (setup.fullscreen !=