+ if (tape.playing)
+ Delay(1000);
+ else
+ WaitForEventToContinue();
+
+ /* close envelope window vertically */
+ for (i = level.envelope_ysize + 2; i >= 2; i -= 2)
+ {
+ int xsize = level.envelope_xsize + 2;
+ int startx = (SXSIZE / font_width - (xsize - 1)) / 2;
+ int starty = (SYSIZE / font_height - i) / 2;
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+ for (y=0; y < i; y++) for (x=0; x < xsize; x++)
+ {
+ int sx = SX + (startx + x) * font_width;
+ int sy = SY + (starty + y) * font_height;
+ int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
+ int ey = (y == 0 ? -1 : y == i - 1 ? +1 : 0);
+
+ DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
+ }
+
+ DrawTextToTextArea(SX + (startx + 1) * font_width,
+ SY + (starty + 1) * font_height, level.envelope,
+ FONT_TEXT_1, level.envelope_xsize, i - 2, mask_mode);
+
+ redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ BackToFront();
+
+ Delay(GAME_FRAME_DELAY);
+
+ /* special case: envelope has odd height */
+ if (level.envelope_ysize % 2 && i == level.envelope_ysize + 2)
+ i++;
+ }
+
+ /* close envelope window horizontally */
+ for (i = level.envelope_xsize + 2; i >= 2; i -= 2)
+ {
+ int startx = (SXSIZE / font_width - i) / 2;
+ int starty = (SYSIZE / font_height) / 2 - 1;
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+ for (y=0; y < 2; y++) for (x=0; x < i; x++)
+ {
+ int sx = SX + (startx + x) * font_width;
+ int sy = SY + (starty + y) * font_height;
+ int ex = (x == 0 ? -1 : x == i - 1 ? +1 : 0);
+ int ey = (y == 0 ? -1 : y == 1 ? +1 : 0);
+
+ DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
+ }
+
+ redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ BackToFront();
+
+ Delay(GAME_FRAME_DELAY);
+
+ /* special case: envelope has odd width */
+ if (level.envelope_xsize % 2 && i == level.envelope_xsize + 2)
+ i++;
+ }
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ redraw_mask |= REDRAW_FIELD;
+ BackToFront();
+}
+
+void RelocatePlayer(int x, int y, int element)
+{
+ struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1];
+
+ if (player->present)
+ {
+ while (player->MovPos)
+ {
+ ScrollFigure(player, SCROLL_GO_ON);
+ ScrollScreen(NULL, SCROLL_GO_ON);
+ FrameCounter++;
+ DrawAllPlayers();
+ BackToFront();
+ }
+
+ RemoveField(player->jx, player->jy);
+ DrawLevelField(player->jx, player->jy);
+ }
+
+ InitPlayerField(x, y, element, TRUE);
+
+ if (player == local_player)
+ {
+ int scroll_xx = -999, scroll_yy = -999;
+
+ while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+ {
+ int dx = 0, dy = 0;
+ int fx = FX, fy = FY;
+
+ scroll_xx = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left :
+ local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+ local_player->jx - MIDPOSX);
+
+ scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+ local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+ local_player->jy - MIDPOSY);
+
+ dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
+ dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
+
+ scroll_x -= dx;
+ scroll_y -= dy;
+
+ fx += dx * TILEX / 2;
+ fy += dy * TILEY / 2;
+
+ ScrollLevel(dx, dy);
+ DrawAllPlayers();
+
+ /* scroll in to steps of half tile size to make things smoother */
+ BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+ FlushDisplay();
+ Delay(GAME_FRAME_DELAY);
+
+ /* scroll second step to align at full tile size */
+ BackToFront();
+ Delay(GAME_FRAME_DELAY);
+ }
+ }
+}
+
+void Explode(int ex, int ey, int phase, int mode)
+{
+ int x, y;
+ int num_phase = 9;
+ int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
+ int last_phase = num_phase * delay;
+ int half_phase = (num_phase / 2) * delay;
+ int first_phase_after_start = EX_PHASE_START + 1;
+
+ if (game.explosions_delayed)
+ {
+ ExplodeField[ex][ey] = mode;
+ return;
+ }
+
+ if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */
+ {
+ int center_element = Feld[ex][ey];
+
+#if 0
+ /* --- This is only really needed (and now handled) in "Impact()". --- */
+ /* do not explode moving elements that left the explode field in time */
+ if (game.engine_version >= RELEASE_IDENT(2,2,0,7) &&
+ center_element == EL_EMPTY && (mode == EX_NORMAL || mode == EX_CENTER))
+ return;
+#endif
+
+ if (mode == EX_NORMAL || mode == EX_CENTER)
+ PlaySoundLevelAction(ex, ey, ACTION_EXPLODING);
+
+ /* remove things displayed in background while burning dynamite */
+ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey]))
+ Back[ex][ey] = 0;
+
+ if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
+ {
+ /* put moving element to center field (and let it explode there) */
+ center_element = MovingOrBlocked2Element(ex, ey);
+ RemoveMovingField(ex, ey);
+ Feld[ex][ey] = center_element;
+ }
+
+ for (y = ey - 1; y <= ey + 1; y++) for(x = ex - 1; x <= ex + 1; x++)
+ {
+ int xx = x - ex + 1;
+ int yy = y - ey + 1;
+ int element;
+
+ if (!IN_LEV_FIELD(x, y) ||
+ ((mode != EX_NORMAL || center_element == EL_AMOEBA_TO_DIAMOND) &&
+ (x != ex || y != ey)))
+ continue;
+
+ element = Feld[x][y];
+
+ if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+ {
+ element = MovingOrBlocked2Element(x, y);
+
+ if (!IS_EXPLOSION_PROOF(element))
+ RemoveMovingField(x, y);
+ }
+
+#if 1
+
+#if 0
+ if (IS_EXPLOSION_PROOF(element))
+ continue;
+#else
+ /* indestructible elements can only explode in center (but not flames) */
+ if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) ||
+ element == EL_FLAMES)
+ continue;
+#endif
+
+#else
+ if ((IS_INDESTRUCTIBLE(element) &&
+ (game.engine_version < VERSION_IDENT(2,2,0) ||
+ (!IS_WALKABLE_OVER(element) && !IS_WALKABLE_UNDER(element)))) ||
+ element == EL_FLAMES)