if (!local_player->LevelSolved_SaveScore)
{
- FadeOut(REDRAW_FIELD);
-
game_status = GAME_MODE_MAIN;
DrawMainMenu();
}
else
{
- FadeOut(REDRAW_FIELD);
-
game_status = GAME_MODE_MAIN;
if (raise_level)
boolean no_delay = (tape.warp_forward);
int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
int wait_delay_value = (no_delay ? 0 : frame_delay_value);
+ int new_scroll_x, new_scroll_y;
- if (quick_relocation)
+ if (level.lazy_relocation && IN_VIS_FIELD(SCREENX(x), SCREENY(y)))
{
- if (!IN_VIS_FIELD(SCREENX(x), SCREENY(y)) || center_screen)
- {
- if (!level.shifted_relocation || center_screen)
- {
- /* quick relocation (without scrolling), with centering of screen */
-
- scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left :
- x > SBX_Right + MIDPOSX ? SBX_Right :
- x - MIDPOSX);
-
- scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
- y > SBY_Lower + MIDPOSY ? SBY_Lower :
- y - MIDPOSY);
- }
- else
- {
- /* quick relocation (without scrolling), but do not center screen */
-
- int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left :
- old_x > SBX_Right + MIDPOSX ? SBX_Right :
- old_x - MIDPOSX);
+ /* case 1: quick relocation inside visible screen (without scrolling) */
- int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper :
- old_y > SBY_Lower + MIDPOSY ? SBY_Lower :
- old_y - MIDPOSY);
-
- int offset_x = x + (scroll_x - center_scroll_x);
- int offset_y = y + (scroll_y - center_scroll_y);
+ RedrawPlayfield();
- scroll_x = (offset_x < SBX_Left + MIDPOSX ? SBX_Left :
- offset_x > SBX_Right + MIDPOSX ? SBX_Right :
- offset_x - MIDPOSX);
+ return;
+ }
- scroll_y = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper :
- offset_y > SBY_Lower + MIDPOSY ? SBY_Lower :
- offset_y - MIDPOSY);
- }
- }
- else
- {
- if (!level.shifted_relocation || center_screen)
- {
- /* quick relocation (without scrolling), with centering of screen */
+ if (!level.shifted_relocation || center_screen)
+ {
+ /* relocation _with_ centering of screen */
- scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left :
+ new_scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left :
x > SBX_Right + MIDPOSX ? SBX_Right :
x - MIDPOSX);
- scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
+ new_scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
y > SBY_Lower + MIDPOSY ? SBY_Lower :
y - MIDPOSY);
- }
- else
- {
- /* quick relocation (without scrolling), but do not center screen */
+ }
+ else
+ {
+ /* relocation _without_ centering of screen */
- int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left :
- old_x > SBX_Right + MIDPOSX ? SBX_Right :
- old_x - MIDPOSX);
+ int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left :
+ old_x > SBX_Right + MIDPOSX ? SBX_Right :
+ old_x - MIDPOSX);
- int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper :
- old_y > SBY_Lower + MIDPOSY ? SBY_Lower :
- old_y - MIDPOSY);
+ int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper :
+ old_y > SBY_Lower + MIDPOSY ? SBY_Lower :
+ old_y - MIDPOSY);
- int offset_x = x + (scroll_x - center_scroll_x);
- int offset_y = y + (scroll_y - center_scroll_y);
+ int offset_x = x + (scroll_x - center_scroll_x);
+ int offset_y = y + (scroll_y - center_scroll_y);
- scroll_x = (offset_x < SBX_Left + MIDPOSX ? SBX_Left :
+ new_scroll_x = (offset_x < SBX_Left + MIDPOSX ? SBX_Left :
offset_x > SBX_Right + MIDPOSX ? SBX_Right :
offset_x - MIDPOSX);
- scroll_y = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper :
+ new_scroll_y = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper :
offset_y > SBY_Lower + MIDPOSY ? SBY_Lower :
offset_y - MIDPOSY);
- }
- }
-
- RedrawPlayfield();
}
- else
- {
- int scroll_xx, scroll_yy;
-
- if (!level.shifted_relocation || center_screen)
- {
- /* visible relocation (with scrolling), with centering of screen */
-
- scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left :
- x > SBX_Right + MIDPOSX ? SBX_Right :
- x - MIDPOSX);
-
- scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
- y > SBY_Lower + MIDPOSY ? SBY_Lower :
- y - MIDPOSY);
- }
- else
- {
- /* visible relocation (with scrolling), but do not center screen */
-
- int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left :
- old_x > SBX_Right + MIDPOSX ? SBX_Right :
- old_x - MIDPOSX);
- int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper :
- old_y > SBY_Lower + MIDPOSY ? SBY_Lower :
- old_y - MIDPOSY);
-
- int offset_x = x + (scroll_x - center_scroll_x);
- int offset_y = y + (scroll_y - center_scroll_y);
+ if (quick_relocation)
+ {
+ /* case 2: quick relocation (redraw without visible scrolling) */
- scroll_xx = (offset_x < SBX_Left + MIDPOSX ? SBX_Left :
- offset_x > SBX_Right + MIDPOSX ? SBX_Right :
- offset_x - MIDPOSX);
+ scroll_x = new_scroll_x;
+ scroll_y = new_scroll_y;
- scroll_yy = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper :
- offset_y > SBY_Lower + MIDPOSY ? SBY_Lower :
- offset_y - MIDPOSY);
- }
+ RedrawPlayfield();
+ return;
+ }
- ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */
+ /* case 3: visible relocation (with scrolling to new position) */
- while (scroll_x != scroll_xx || scroll_y != scroll_yy)
- {
- int dx = 0, dy = 0;
- int fx = FX, fy = FY;
+ ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */
- dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
- dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
+ while (scroll_x != new_scroll_x || scroll_y != new_scroll_y)
+ {
+ int dx = 0, dy = 0;
+ int fx = FX, fy = FY;
- if (dx == 0 && dy == 0) /* no scrolling needed at all */
- break;
+ dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0);
+ dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0);
- scroll_x -= dx;
- scroll_y -= dy;
+ if (dx == 0 && dy == 0) /* no scrolling needed at all */
+ break;
- fx += dx * TILEX / 2;
- fy += dy * TILEY / 2;
+ scroll_x -= dx;
+ scroll_y -= dy;
- ScrollLevel(dx, dy);
- DrawAllPlayers();
+ fx += dx * TILEX / 2;
+ fy += dy * TILEY / 2;
- /* scroll in two steps of half tile size to make things smoother */
- BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
- Delay(wait_delay_value);
+ ScrollLevel(dx, dy);
+ DrawAllPlayers();
- /* scroll second step to align at full tile size */
- BackToFront();
- Delay(wait_delay_value);
- }
+ /* scroll in two steps of half tile size to make things smoother */
+ BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+ Delay(wait_delay_value);
- DrawAllPlayers();
+ /* scroll second step to align at full tile size */
BackToFront();
Delay(wait_delay_value);
}
+
+ DrawAllPlayers();
+ BackToFront();
+ Delay(wait_delay_value);
}
void RelocatePlayer(int jx, int jy, int el_player_raw)
{
/* !!! not clear why graphic animation should be reset at all here !!! */
/* !!! UPDATE: but is needed for correct Snake Bite tail animation !!! */
+ /* !!! SOLUTION: do not reset if graphics engine set to 4 or above !!! */
+
+ /*
+ GRAPHICAL BUG ADDRESSED BY CHECKING GRAPHICS ENGINE VERSION:
+
+ When using an animation frame delay of 1 (this only happens with
+ "sp_zonk.moving.left/right" in the classic graphics), the default
+ (non-moving) animation shows wrong animation frames (while the
+ moving animation, like "sp_zonk.moving.left/right", is correct,
+ so this graphical bug never shows up with the classic graphics).
+ For an animation with 4 frames, this causes wrong frames 0,0,1,2
+ be drawn instead of the correct frames 0,1,2,3. This is caused by
+ "GfxFrame[][]" being reset *twice* (in two successive frames) after
+ an element change: First when the change delay ("ChangeDelay[][]")
+ counter has reached zero after decrementing, then a second time in
+ the next frame (after "GfxFrame[][]" was already incremented) when
+ "ChangeDelay[][]" is reset to the initial delay value again.
+
+ This causes frame 0 to be drawn twice, while the last frame won't
+ be drawn anymore, resulting in the wrong frame sequence 0,0,1,2.
+
+ As some animations may already be cleverly designed around this bug
+ (at least the "Snake Bite" snake tail animation does this), it cannot
+ simply be fixed here without breaking such existing animations.
+ Unfortunately, it cannot easily be detected if a graphics set was
+ designed "before" or "after" the bug was fixed. As a workaround,
+ a new graphics set option "game.graphics_engine_version" was added
+ to be able to specify the game's major release version for which the
+ graphics set was designed, which can then be used to decide if the
+ bugfix should be used (version 4 and above) or not (version 3 or
+ below, or if no version was specified at all, as with old sets).
+
+ (The wrong/fixed animation frames can be tested with the test level set
+ "test_gfxframe" and level "000", which contains a specially prepared
+ custom element at level position (x/y) == (11/9) which uses the zonk
+ animation mentioned above. Using "game.graphics_engine_version: 4"
+ fixes the wrong animation frames, showing the correct frames 0,1,2,3.
+ This can also be seen from the debug output for this test element.)
+ */
+
/* when a custom element is about to change (for example by change delay),
do not reset graphic animation when the custom element is moving */
- if (!IS_MOVING(x, y))
+ if (game.graphics_engine_version < 4 &&
+ !IS_MOVING(x, y))
{
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
#endif
{
if (quick_quit)
- {
FadeSkipNextFadeIn();
- game_status = GAME_MODE_MAIN;
+ game_status = GAME_MODE_MAIN;
- DrawMainMenu();
- }
- else
- {
- game_status = GAME_MODE_MAIN;
-
- DrawMainMenu();
- }
+ DrawMainMenu();
}
}
else /* continue playing the game */