X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ftools.c;h=05219bf91a4003a6c88af470db545ec3cc6df62c;hb=2884cb273130660d64871bef2845525ef0bfc034;hp=eaea76ea0da5a3041978dac4ea08d4f24dbac870;hpb=3e71d06e9a97be7bb8c50c76717d08e5c46e0cc8;p=rocksndiamonds.git diff --git a/src/tools.c b/src/tools.c index eaea76ea..05219bf9 100644 --- a/src/tools.c +++ b/src/tools.c @@ -20,6 +20,10 @@ #include "network.h" #include "tape.h" + +/* select level set with EMC X11 graphics before activating EM GFX debugging */ +#define DEBUG_EM_GFX 0 + /* tool button identifiers */ #define TOOL_CTRL_ID_YES 0 #define TOOL_CTRL_ID_NO 1 @@ -63,6 +67,12 @@ void DumpTile(int x, int y) int sx = SCREENX(x); int sy = SCREENY(y); + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + { + x--; + y--; + } + printf_line("-", 79); printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y); printf_line("-", 79); @@ -127,11 +137,9 @@ void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height) if (game_status == GAME_MODE_PLAYING && level.game_engine_type == GAME_ENGINE_TYPE_EM) { -#if 1 - RedrawPlayfield_EM(force_redraw); -#else - BlitScreenToBitmap_EM(backbuffer); -#endif + /* currently there is no partial redraw -- always redraw whole playfield */ + + RedrawPlayfield_EM(TRUE); } else if (game_status == GAME_MODE_PLAYING && !game.envelope_active) { @@ -233,7 +241,8 @@ void BackToFront() if (redraw_mask & REDRAW_ALL) { BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); - redraw_mask = 0; + + redraw_mask = REDRAW_NONE; } if (redraw_mask & REDRAW_FIELD) @@ -405,6 +414,65 @@ void FadeToFront() BackToFront(); } +void FadeExt(int fade_mask, int fade_mode) +{ + 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; + + if (fade_mask & REDRAW_ALL) + { + x = 0; + y = 0; + width = WIN_XSIZE; + height = WIN_YSIZE; + } + else if (fade_mask & REDRAW_FIELD) + { + x = REAL_SX; + y = REAL_SY; + width = FULL_SXSIZE; + height = FULL_SYSIZE; + } + + redraw_mask |= fade_mask; + + if (!setup.fading || fade_delay == 0) + { + if (fade_mode == FADE_MODE_FADE_OUT) + ClearRectangle(backbuffer, x, y, width, height); + + BackToFront(); + + return; + } + + FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay); + + redraw_mask &= ~fade_mask; +} + +void FadeIn(int fade_mask) +{ + FadeExt(fade_mask, FADE_MODE_FADE_IN); +} + +void FadeOut(int fade_mask) +{ + FadeExt(fade_mask, FADE_MODE_FADE_OUT); +} + +void FadeCross(int fade_mask) +{ + FadeExt(fade_mask, FADE_MODE_CROSSFADE); +} + +void FadeCrossSaveBackbuffer() +{ + BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); +} + void SetMainBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) @@ -427,9 +495,21 @@ void SetDoorBackgroundImage(int graphic) graphic_info[IMG_BACKGROUND].bitmap); } +void SetPanelBackground() +{ + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel, + DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0); + + SetDoorBackgroundBitmap(bitmap_db_panel); +} + void DrawBackground(int dst_x, int dst_y, int width, int height) { +#if 1 + ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height); +#else ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height); +#endif redraw_mask |= REDRAW_FIELD; } @@ -495,6 +575,17 @@ inline int getGraphicAnimationFrame(int graphic, int sync_frame) if (graphic_info[graphic].anim_global_sync || sync_frame < 0) sync_frame = FrameCounter; +#if 0 + if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] && + sync_frame == 0 && + FrameCounter > 10) + { + int x = 1 / 0; + + printf("::: FOO!\n"); + } +#endif + return getAnimationFrame(graphic_info[graphic].anim_frames, graphic_info[graphic].anim_delay, graphic_info[graphic].anim_mode, @@ -1037,6 +1128,8 @@ void DrawLevelFieldCrumbledSand(int x, int y) return; #if 1 + /* !!! CHECK THIS !!! */ + /* if (Feld[x][y] == EL_ELEMENT_SNAPPING && GFX_CRUMBLED(GfxElement[x][y])) @@ -1332,8 +1425,8 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action) int font_nr = FONT_ENVELOPE_1 + envelope_nr; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); - int max_xsize = level.envelope_xsize[envelope_nr]; - int max_ysize = level.envelope_ysize[envelope_nr]; + int max_xsize = level.envelope[envelope_nr].xsize; + int max_ysize = level.envelope[envelope_nr].ysize; int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0); int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0); int xend = max_xsize; @@ -1360,7 +1453,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action) DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr); DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height, - level.envelope_text[envelope_nr], font_nr, max_xsize, + level.envelope[envelope_nr].text, font_nr, max_xsize, xsize - 2, ysize - 2, mask_mode); redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER; @@ -1386,7 +1479,7 @@ void ShowEnvelope(int envelope_nr) game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */ - PlaySoundStereo(sound_opening, SOUND_MIDDLE); + PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE); if (anim_mode == ANIM_DEFAULT) AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING); @@ -1398,7 +1491,7 @@ void ShowEnvelope(int envelope_nr) else WaitForEventToContinue(); - PlaySoundStereo(sound_closing, SOUND_MIDDLE); + PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE); if (anim_mode != ANIM_NONE) AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING); @@ -1414,28 +1507,45 @@ void ShowEnvelope(int envelope_nr) BackToFront(); } -void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y) +void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y, + int tilesize) { + struct + { + int width_mult, width_div; + int height_mult, height_div; + } offset_calc[4] = + { + { 0, 1, 0, 1 }, + { 0, 1, 2, 3 }, + { 1, 2, 2, 3 }, + { 3, 4, 2, 3 }, + }; + int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 : + 5 - log_2(tilesize)); Bitmap *src_bitmap = graphic_info[graphic].bitmap; - int mini_startx = src_bitmap->width * 3 / 4; - int mini_starty = src_bitmap->height * 2 / 3; - int src_x = mini_startx + graphic_info[graphic].src_x / 8; - int src_y = mini_starty + graphic_info[graphic].src_y / 8; + int width_mult = offset_calc[offset_calc_pos].width_mult; + int width_div = offset_calc[offset_calc_pos].width_div; + int height_mult = offset_calc[offset_calc_pos].height_mult; + int height_div = offset_calc[offset_calc_pos].height_div; + int mini_startx = src_bitmap->width * width_mult / width_div; + int mini_starty = src_bitmap->height * height_mult / height_div; + int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE; + int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE; *bitmap = src_bitmap; *x = src_x; *y = src_y; } -void DrawMicroElement(int xpos, int ypos, int element) +void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize) { Bitmap *src_bitmap; int src_x, src_y; int graphic = el2preimg(element); - getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y); - BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY, - xpos, ypos); + getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize); + BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y); } void DrawLevel() @@ -1463,33 +1573,36 @@ void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y) redraw_mask |= REDRAW_FIELD; } -static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_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; + int preview_width = preview.xsize * tile_size; + 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 x, y; - DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE); + DrawBackground(dst_x, dst_y, preview_width, preview_height); - if (lev_fieldx < STD_LEV_FIELDX) - xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX; - if (lev_fieldy < STD_LEV_FIELDY) - ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY; + dst_x += (preview_width - real_preview_xsize * tile_size) / 2; + dst_y += (preview_height - real_preview_ysize * tile_size) / 2; - xpos += MICRO_TILEX; - ypos += MICRO_TILEY; - - for (x = -1; x <= STD_LEV_FIELDX; x++) + for (x = 0; x < real_preview_xsize; x++) { - for (y = -1; y <= STD_LEV_FIELDY; y++) + for (y = 0; y < real_preview_ysize; y++) { - int lx = from_x + x, ly = from_y + y; - - if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy) - DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY, - level.field[lx][ly]); - else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1 - && BorderElement != EL_EMPTY) - DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY, - getBorderElement(lx, ly)); + int lx = from_x + x + (show_level_border ? -1 : 0); + int ly = from_y + y + (show_level_border ? -1 : 0); + int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] : + getBorderElement(lx, ly)); + + DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size, + element, tile_size); } } @@ -1505,7 +1618,7 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y) #define MICROLABEL_IMPORTED_BY_HEAD 6 #define MICROLABEL_IMPORTED_BY 7 -static void DrawMicroLevelLabelExt(int mode) +static void DrawPreviewLevelLabelExt(int mode) { char label_text[MAX_OUTPUT_LINESIZE + 1]; int max_len_label_text; @@ -1553,13 +1666,17 @@ static void DrawMicroLevelLabelExt(int mode) redraw_mask |= REDRAW_MICROLEVEL; } -void DrawMicroLevel(int xpos, int ypos, boolean restart) +void DrawPreviewLevel(boolean restart) { static unsigned long scroll_delay = 0; static unsigned long label_delay = 0; static int from_x, from_y, scroll_direction; static int label_state, label_counter; - int last_game_status = game_status; /* save current game status */ + unsigned long scroll_delay_value = preview.step_delay; + boolean show_level_border = (BorderElement != EL_EMPTY); + int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); + int level_ysize = lev_fieldy + (show_level_border ? 2 : 0); + int last_game_status = game_status; /* save current game status */ /* force PREVIEW font on preview level */ game_status = GAME_MODE_PSEUDO_PREVIEW; @@ -1571,8 +1688,8 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart) label_state = 1; label_counter = 0; - DrawMicroLevelExt(xpos, ypos, from_x, from_y); - DrawMicroLevelLabelExt(label_state); + DrawPreviewLevelExt(from_x, from_y); + DrawPreviewLevelLabelExt(label_state); /* initialize delay counters */ DelayReached(&scroll_delay, 0); @@ -1599,36 +1716,50 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart) return; } - /* scroll micro level, if needed */ - if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) && - DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY)) + /* scroll preview level, if needed */ + if ((level_xsize > preview.xsize || level_ysize > preview.ysize) && + DelayReached(&scroll_delay, scroll_delay_value)) { switch (scroll_direction) { case MV_LEFT: if (from_x > 0) - from_x--; + { + from_x -= preview.step_offset; + from_x = (from_x < 0 ? 0 : from_x); + } else scroll_direction = MV_UP; break; case MV_RIGHT: - if (from_x < lev_fieldx - STD_LEV_FIELDX) - from_x++; + if (from_x < level_xsize - preview.xsize) + { + from_x += preview.step_offset; + from_x = (from_x > level_xsize - preview.xsize ? + level_xsize - preview.xsize : from_x); + } else scroll_direction = MV_DOWN; break; case MV_UP: if (from_y > 0) - from_y--; + { + from_y -= preview.step_offset; + from_y = (from_y < 0 ? 0 : from_y); + } else scroll_direction = MV_RIGHT; break; case MV_DOWN: - if (from_y < lev_fieldy - STD_LEV_FIELDY) - from_y++; + if (from_y < level_ysize - preview.ysize) + { + from_y += preview.step_offset; + from_y = (from_y > level_ysize - preview.ysize ? + level_ysize - preview.ysize : from_y); + } else scroll_direction = MV_LEFT; break; @@ -1637,14 +1768,14 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart) break; } - DrawMicroLevelExt(xpos, ypos, from_x, from_y); + DrawPreviewLevelExt(from_x, from_y); } /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */ /* redraw micro level label, if needed */ - if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 && - strcmp(level.author, ANONYMOUS_NAME) != 0 && - strcmp(level.author, leveldir_current->name) != 0 && + if (!strEqual(level.name, NAMELESS_LEVEL_NAME) && + !strEqual(level.author, ANONYMOUS_NAME) && + !strEqual(level.author, leveldir_current->name) && DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY)) { int max_label_counter = 23; @@ -1678,7 +1809,7 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart) label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ? MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY); - DrawMicroLevelLabelExt(label_state); + DrawPreviewLevelLabelExt(label_state); } game_status = last_game_status; /* restore current game status */ @@ -1825,6 +1956,7 @@ void DrawPlayer(struct PlayerInfo *player) int next_jx = jx + dx; int next_jy = jy + dy; boolean player_is_moving = (player->MovPos ? TRUE : FALSE); + boolean player_is_opaque = FALSE; int sx = SCREENX(jx), sy = SCREENY(jy); int sxx = 0, syy = 0; int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy]; @@ -1865,6 +1997,11 @@ void DrawPlayer(struct PlayerInfo *player) player->is_dropping ? ACTION_DROPPING : player->is_waiting ? player->action_waiting : ACTION_DEFAULT); +#if 1 + if (player->is_waiting) + move_dir = player->dir_waiting; +#endif + InitPlayerGfxAnimation(player, action, move_dir); /* ----------------------------------------------------------------------- */ @@ -1888,8 +2025,17 @@ void DrawPlayer(struct PlayerInfo *player) last_element == EL_EM_DYNAMITE_ACTIVE || last_element == EL_SP_DISK_RED_ACTIVE) DrawDynamite(last_jx, last_jy); +#if 0 + /* !!! this is not enough to prevent flickering of players which are + moving next to each others without a free tile between them -- this + can only be solved by drawing all players layer by layer (first the + background, then the foreground etc.) !!! => TODO */ + else if (!IS_PLAYER(last_jx, last_jy)) + DrawLevelField(last_jx, last_jy); +#else else DrawLevelField(last_jx, last_jy); +#endif if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy))) DrawLevelElement(next_jx, next_jy, EL_EMPTY); @@ -1913,24 +2059,32 @@ void DrawPlayer(struct PlayerInfo *player) { if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED) { - if (GFX_CRUMBLED(GfxElement[jx][jy])) + int old_element = GfxElement[jx][jy]; + int old_graphic = el_act_dir2img(old_element, action, move_dir); + int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame); + + if (GFX_CRUMBLED(old_element)) DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame); else - { - int old_element = GfxElement[jx][jy]; - int old_graphic = el_act_dir2img(old_element, action, move_dir); - int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame); - DrawGraphic(sx, sy, old_graphic, frame); - } + + if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER) + player_is_opaque = TRUE; } else { GfxElement[jx][jy] = EL_UNDEFINED; /* make sure that pushed elements are drawn with correct frame rate */ +#if 1 + graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir); + + if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic)) + GfxFrame[jx][jy] = player->StepFrame; +#else if (player->is_pushing && player->is_moving) GfxFrame[jx][jy] = player->StepFrame; +#endif DrawLevelField(jx, jy); } @@ -1960,7 +2114,10 @@ void DrawPlayer(struct PlayerInfo *player) if (!setup.soft_scrolling && ScreenMovPos) sxx = syy = 0; - DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); + if (player_is_opaque) + DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING); + else + DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); if (SHIELD_ON(player)) { @@ -1987,15 +2144,26 @@ void DrawPlayer(struct PlayerInfo *player) int px = SCREENX(jx), py = SCREENY(jy); int pxx = (TILEX - ABS(sxx)) * dx; int pyy = (TILEY - ABS(syy)) * dy; + int gfx_frame = GfxFrame[jx][jy]; int graphic; + int sync_frame; int frame; if (!IS_MOVING(jx, jy)) /* push movement already finished */ + { element = Feld[next_jx][next_jy]; + gfx_frame = GfxFrame[next_jx][next_jy]; + } graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir); + +#if 1 + sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame); + frame = getGraphicAnimationFrame(graphic, sync_frame); +#else frame = getGraphicAnimationFrame(graphic, player->StepFrame); +#endif /* draw background element under pushed element (like the Sokoban field) */ if (Back[next_jx][next_jy]) @@ -2183,6 +2351,10 @@ boolean Request(char *text, unsigned int req_state) DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1); } +#if 1 + SetDoorBackgroundImage(IMG_BACKGROUND_DOOR); +#endif + SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1); /* clear door drawing field */ @@ -2252,7 +2424,15 @@ boolean Request(char *text, unsigned int req_state) if (!(req_state & REQUEST_WAIT_FOR_INPUT)) { - SetDrawBackgroundMask(REDRAW_FIELD); + if (game_status == GAME_MODE_PLAYING) + { + SetPanelBackground(); + SetDrawBackgroundMask(REDRAW_DOOR_1); + } + else + { + SetDrawBackgroundMask(REDRAW_FIELD); + } return FALSE; } @@ -2397,7 +2577,15 @@ boolean Request(char *text, unsigned int req_state) RemapAllGadgets(); - SetDrawBackgroundMask(REDRAW_FIELD); + if (game_status == GAME_MODE_PLAYING) + { + SetPanelBackground(); + SetDrawBackgroundMask(REDRAW_DOOR_1); + } + else + { + SetDrawBackgroundMask(REDRAW_FIELD); + } #if defined(NETWORK_AVALIABLE) /* continue network game after request */ @@ -2482,7 +2670,7 @@ unsigned int MoveDoor(unsigned int door_state) door_2.height = VYSIZE; if (door_state == DOOR_GET_STATE) - return(door1 | door2); + return (door1 | door2); if (door_state & DOOR_SET_STATE) { @@ -2491,17 +2679,20 @@ unsigned int MoveDoor(unsigned int door_state) if (door_state & DOOR_ACTION_2) door2 = door_state & DOOR_ACTION_2; - return(door1 | door2); + return (door1 | door2); } - if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1) - door_state &= ~DOOR_OPEN_1; - else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1) - door_state &= ~DOOR_CLOSE_1; - if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2) - door_state &= ~DOOR_OPEN_2; - else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2) - door_state &= ~DOOR_CLOSE_2; + if (!(door_state & DOOR_FORCE_REDRAW)) + { + if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1) + door_state &= ~DOOR_OPEN_1; + else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1) + door_state &= ~DOOR_CLOSE_1; + if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2) + door_state &= ~DOOR_OPEN_2; + else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2) + door_state &= ~DOOR_CLOSE_2; + } door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay : door_2.step_delay); @@ -2536,8 +2727,8 @@ unsigned int MoveDoor(unsigned int door_state) #if 1 int end = door_size; #else - int end = (door_state & DOOR_ACTION_1 && - door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE); + int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ? + DYSIZE : DXSIZE); #endif #if 1 int start = ((door_state & DOOR_NO_DELAY) ? end : 0); @@ -2550,9 +2741,9 @@ unsigned int MoveDoor(unsigned int door_state) { /* opening door sound has priority over simultaneously closing door */ if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2)) - PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE); + PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE); else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2)) - PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE); + PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE); } for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize) @@ -2655,9 +2846,15 @@ unsigned int MoveDoor(unsigned int door_state) if (door_state & DOOR_ACTION_2) { +#if 1 + int a = MIN(x * door_2.step_offset, door_size); + int p = (door_state & DOOR_OPEN_2 ? door_size - a : a); + int i = p + door_skip; +#else int a = MIN(x * door_2.step_offset, door_size_2); int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a); int i = p + door_skip; +#endif if (door_2.anim_mode & ANIM_STATIC_PANEL) { @@ -2734,13 +2931,15 @@ unsigned int MoveDoor(unsigned int door_state) door_2_done = (a == VXSIZE); } - BackToFront(); + if (!(door_state & DOOR_NO_DELAY)) + { + BackToFront(); - if (game_status == GAME_MODE_MAIN) - DoAnimation(); + if (game_status == GAME_MODE_MAIN) + DoAnimation(); - if (!(door_state & DOOR_NO_DELAY)) WaitUntilDelayReached(&door_delay, door_delay_value); + } } } @@ -3474,19 +3673,19 @@ em_object_mapping_list[] = }, { Xeater_n, TRUE, FALSE, - EL_YAMYAM, -1, -1 + EL_YAMYAM_UP, -1, -1 }, { - Xeater_e, FALSE, FALSE, - EL_YAMYAM, -1, -1 + Xeater_e, TRUE, FALSE, + EL_YAMYAM_RIGHT, -1, -1 }, { - Xeater_w, FALSE, FALSE, - EL_YAMYAM, -1, -1 + Xeater_w, TRUE, FALSE, + EL_YAMYAM_LEFT, -1, -1 }, { - Xeater_s, FALSE, FALSE, - EL_YAMYAM, -1, -1 + Xeater_s, TRUE, FALSE, + EL_YAMYAM_DOWN, -1, -1 }, { Yeater_n, FALSE, FALSE, @@ -4157,19 +4356,19 @@ em_object_mapping_list[] = EL_QUICKSAND_FULL, -1, -1 }, { - Xsand_stonein_1, FALSE, FALSE, + Xsand_stonein_1, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { - Xsand_stonein_2, FALSE, FALSE, + Xsand_stonein_2, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { - Xsand_stonein_3, FALSE, FALSE, + Xsand_stonein_3, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { - Xsand_stonein_4, FALSE, FALSE, + Xsand_stonein_4, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { @@ -4596,10 +4795,6 @@ em_object_mapping_list[] = Xalpha_copyr, TRUE, FALSE, EL_CHAR('©'), -1, -1 }, - { - Xalpha_copyr, TRUE, FALSE, - EL_CHAR('©'), -1, -1 - }, { Xboom_bug, FALSE, FALSE, @@ -5119,6 +5314,7 @@ int font2baseimg(int font_nr) return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT]; } +#if 0 void setCenteredPlayerNr_EM(int centered_player_nr) { game.centered_player_nr = game.centered_player_nr_next = centered_player_nr; @@ -5126,9 +5322,11 @@ void setCenteredPlayerNr_EM(int centered_player_nr) int getCenteredPlayerNr_EM() { +#if 0 if (game.centered_player_nr_next >= 0 && !native_em_level.ply[game.centered_player_nr_next]->alive) game.centered_player_nr_next = game.centered_player_nr; +#endif if (game.centered_player_nr != game.centered_player_nr_next) game.centered_player_nr = game.centered_player_nr_next; @@ -5136,7 +5334,18 @@ int getCenteredPlayerNr_EM() return game.centered_player_nr; } -int getActivePlayers_EM() +void setSetCenteredPlayer_EM(boolean set_centered_player) +{ + game.set_centered_player = set_centered_player; +} + +boolean getSetCenteredPlayer_EM() +{ + return game.set_centered_player; +} +#endif + +int getNumActivePlayers_EM() { int num_players = 0; int i; @@ -5151,6 +5360,7 @@ int getActivePlayers_EM() return num_players; } +#if 1 int getGameFrameDelay_EM(int native_em_game_frame_delay) { int game_frame_delay_value; @@ -5165,6 +5375,7 @@ int getGameFrameDelay_EM(int native_em_game_frame_delay) return game_frame_delay_value; } +#endif unsigned int InitRND(long seed) { @@ -5174,8 +5385,6 @@ unsigned int InitRND(long seed) return InitEngineRND(seed); } -#define DEBUG_EM_GFX 0 - void InitGraphicInfo_EM(void) { struct Mapping_EM_to_RND_object object_mapping[TILE_MAX]; @@ -5183,12 +5392,16 @@ void InitGraphicInfo_EM(void) int i, j, p; #if DEBUG_EM_GFX + int num_em_gfx_errors = 0; + if (graphic_info_em_object[0][0].bitmap == NULL) { /* EM graphics not yet initialized in em_open_all() */ return; } + + printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n"); #endif /* always start with reliable default values */ @@ -5282,12 +5495,12 @@ void InitGraphicInfo_EM(void) i == Ymagnify_eat ? element : i == Ygrass_eat ? element : i == Ydirt_eat ? element : - i == Yspring_kill_e ? EL_SPRING : - i == Yspring_kill_w ? EL_SPRING : i == Yemerald_stone ? EL_EMERALD : i == Ydiamond_stone ? EL_ROCK : - i == Xsand_stonein_4 ? EL_EMPTY : - i == Xsand_stoneout_2 ? EL_ROCK : + i == Xsand_stonein_1 ? element : + i == Xsand_stonein_2 ? element : + i == Xsand_stonein_3 ? element : + i == Xsand_stonein_4 ? element : is_backside ? EL_EMPTY : action_removing ? EL_EMPTY : element); @@ -5329,6 +5542,7 @@ void InitGraphicInfo_EM(void) direction)); int base_graphic = el_act2img(effective_element, ACTION_DEFAULT); int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT); + boolean has_action_graphics = (graphic != base_graphic); boolean has_crumbled_graphics = (base_crumbled != base_graphic); struct GraphicInfo *g = &graphic_info[graphic]; struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j]; @@ -5496,23 +5710,43 @@ void InitGraphicInfo_EM(void) g_em->crumbled_border_size = graphic_info[crumbled].border_size; } - if (!g->double_movement && (effective_action == ACTION_FALLING || - effective_action == ACTION_MOVING || - effective_action == ACTION_PUSHING || - effective_action == ACTION_EATING)) +#if 0 + if (element == EL_ROCK && + effective_action == ACTION_FILLING) + printf("::: has_action_graphics == %d\n", has_action_graphics); +#endif + + if ((!g->double_movement && (effective_action == ACTION_FALLING || + effective_action == ACTION_MOVING || + effective_action == ACTION_PUSHING || + effective_action == ACTION_EATING)) || + (!has_action_graphics && (effective_action == ACTION_FILLING || + effective_action == ACTION_EMPTYING))) { int move_dir = - (effective_action == ACTION_FALLING ? MV_DOWN : direction); + (effective_action == ACTION_FALLING || + effective_action == ACTION_FILLING || + effective_action == ACTION_EMPTYING ? MV_DOWN : direction); int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0); int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0); - int num_steps = (i == Ydrip_s1 || - i == Ydrip_s1B || - i == Ydrip_s2 || - i == Ydrip_s2B ? 16 : 8); + int num_steps = (i == Ydrip_s1 ? 16 : + i == Ydrip_s1B ? 16 : + i == Ydrip_s2 ? 16 : + i == Ydrip_s2B ? 16 : + i == Xsand_stonein_1 ? 32 : + i == Xsand_stonein_2 ? 32 : + i == Xsand_stonein_3 ? 32 : + i == Xsand_stonein_4 ? 32 : + i == Xsand_stoneout_1 ? 16 : + i == Xsand_stoneout_2 ? 16 : 8); int cx = ABS(dx) * (TILEX / num_steps); int cy = ABS(dy) * (TILEY / num_steps); - int step_frame = (i == Ydrip_s2 || - i == Ydrip_s2B ? j + 8 : j) + 1; + int step_frame = (i == Ydrip_s2 ? j + 8 : + i == Ydrip_s2B ? j + 8 : + i == Xsand_stonein_2 ? j + 8 : + i == Xsand_stonein_3 ? j + 16 : + i == Xsand_stonein_4 ? j + 24 : + i == Xsand_stoneout_2 ? j + 8 : j) + 1; int step = (is_backside ? step_frame : num_steps - step_frame); if (is_backside) /* tile where movement starts */ @@ -5634,6 +5868,8 @@ void InitGraphicInfo_EM(void) printf(" %d (%d): size %d,%d should be %d,%d\n", j, is_backside, g_em->width, g_em->height, TILEX, TILEY); + + num_em_gfx_errors++; } #endif @@ -5780,6 +6016,8 @@ void InitGraphicInfo_EM(void) g_em->src_x / 32, g_em->src_y / 32, debug_src_x, debug_src_y, debug_src_x / 32, debug_src_y / 32); + + num_em_gfx_errors++; } #endif @@ -5788,6 +6026,96 @@ void InitGraphicInfo_EM(void) } #if DEBUG_EM_GFX + printf("\n"); + printf("::: [%d errors found]\n", num_em_gfx_errors); + exit(0); #endif } + +void PlayMenuSound() +{ + int sound = menu.sound[game_status]; + + if (sound == SND_UNDEFINED) + return; + + if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || + (!setup.sound_loops && IS_LOOP_SOUND(sound))) + return; + + if (IS_LOOP_SOUND(sound)) + PlaySoundLoop(sound); + else + PlaySound(sound); +} + +void PlayMenuSoundStereo(int sound, int stereo_position) +{ + if (sound == SND_UNDEFINED) + return; + + if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || + (!setup.sound_loops && IS_LOOP_SOUND(sound))) + return; + + if (IS_LOOP_SOUND(sound)) + PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP); + else + PlaySoundStereo(sound, stereo_position); +} + +void PlayMenuSoundIfLoop() +{ + int sound = menu.sound[game_status]; + + if (sound == SND_UNDEFINED) + return; + + if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || + (!setup.sound_loops && IS_LOOP_SOUND(sound))) + return; + + if (IS_LOOP_SOUND(sound)) + PlaySoundLoop(sound); +} + +void PlayMenuMusic() +{ + int music = menu.music[game_status]; + + if (music == MUS_UNDEFINED) + return; + + PlayMusic(music); +} + +void ToggleFullscreenIfNeeded() +{ + if (setup.fullscreen != video.fullscreen_enabled || + setup.fullscreen_mode != video.fullscreen_mode_current) + { + 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 (setup.fullscreen && video.fullscreen_enabled) + { + /* keep fullscreen mode, but change screen mode */ + video.fullscreen_mode_current = setup.fullscreen_mode; + video.fullscreen_enabled = FALSE; + } + + /* toggle fullscreen */ + ChangeVideoModeIfNeeded(setup.fullscreen); + setup.fullscreen = video.fullscreen_enabled; + + /* restore backbuffer content from temporary backbuffer backup bitmap */ + BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); + + FreeBitmap(tmp_backbuffer); + + redraw_mask = REDRAW_ALL; + } +}