+ for (i=0; i<4; i++)
+ {
+ x = ax+xy[i%4][0];
+ y = ay+xy[i%4][1];
+
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+ if (Feld[x][y] == EL_AMOEBA2DIAM)
+ Bang(x, y);
+ }
+ }
+}
+
+void AmoebeUmwandeln2(int ax, int ay, int new_element)
+{
+ int x, y;
+ int group_nr = AmoebaNr[ax][ay];
+ boolean done = FALSE;
+
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ {
+ if (AmoebaNr[x][y] == group_nr &&
+ (Feld[x][y] == EL_AMOEBE_TOT ||
+ Feld[x][y] == EL_AMOEBE_BD ||
+ Feld[x][y] == EL_AMOEBING))
+ {
+ AmoebaNr[x][y] = 0;
+ Feld[x][y] = new_element;
+ DrawLevelField(x, y);
+ done = TRUE;
+ }
+ }
+
+ if (done)
+ PlaySoundLevel(ax, ay,
+ (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
+}
+
+void AmoebeWaechst(int x, int y)
+{
+ static long sound_delay = 0;
+ static int sound_delay_value = 0;
+
+ if (!MovDelay[x][y]) /* start new growing cycle */
+ {
+ MovDelay[x][y] = 7;
+
+ if (DelayReached(&sound_delay, sound_delay_value))
+ {
+ PlaySoundLevel(x, y, SND_AMOEBE);
+ sound_delay_value = 30;
+ }
+ }
+
+ if (MovDelay[x][y]) /* wait some time before growing bigger */
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING+3-MovDelay[x][y]/2);
+
+ if (!MovDelay[x][y])
+ {
+ Feld[x][y] = Store[x][y];
+ Store[x][y] = 0;
+ DrawLevelField(x, y);
+ }
+ }
+}
+
+void AmoebeAbleger(int ax, int ay)
+{
+ int i;
+ int element = Feld[ax][ay];
+ int newax = ax, neway = ay;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
+ if (!level.tempo_amoebe)
+ {
+ Feld[ax][ay] = EL_AMOEBE_TOT;
+ DrawLevelField(ax, ay);
+ return;
+ }
+
+ if (!MovDelay[ax][ay]) /* start making new amoeba field */
+ MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
+
+ if (MovDelay[ax][ay]) /* wait some time before making new amoeba */
+ {
+ MovDelay[ax][ay]--;
+ if (MovDelay[ax][ay])
+ return;
+ }
+
+ if (element == EL_AMOEBE_NASS) /* object is an acid / amoeba drop */
+ {
+ int start = RND(4);
+ int x = ax+xy[start][0];
+ int y = ay+xy[start][1];
+
+ if (!IN_LEV_FIELD(x, y))
+ return;
+
+ if (IS_FREE(x, y) ||
+ Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
+ {
+ newax = x;
+ neway = y;
+ }
+
+ if (newax == ax && neway == ay)
+ return;
+ }
+ else /* normal or "filled" amoeba */
+ {
+ int start = RND(4);
+ boolean waiting_for_player = FALSE;
+
+ for (i=0; i<4; i++)
+ {
+ int j = (start+i)%4;
+ int x = ax+xy[j][0];
+ int y = ay+xy[j][1];
+
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+ if (IS_FREE(x, y) ||
+ Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
+ {
+ newax = x;
+ neway = y;
+ break;
+ }
+ else if (IS_PLAYER(x, y))
+ waiting_for_player = TRUE;
+ }
+
+ if (newax == ax && neway == ay)
+ {
+ if (i == 4 && !waiting_for_player)
+ {
+ Feld[ax][ay] = EL_AMOEBE_TOT;
+ DrawLevelField(ax, ay);
+ AmoebaCnt[AmoebaNr[ax][ay]]--;
+
+ if (AmoebaCnt[AmoebaNr[ax][ay]]<=0) /* amoeba is completely dead */
+ {
+ if (element == EL_AMOEBE_VOLL)
+ AmoebeUmwandeln(ax, ay);
+ else if (element == EL_AMOEBE_BD)
+ AmoebeUmwandeln2(ax, ay, level.amoebe_inhalt);
+ }
+ }
+ return;
+ }
+ else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
+ {
+ int new_group_nr = AmoebaNr[ax][ay];
+
+ AmoebaNr[newax][neway] = new_group_nr;
+ AmoebaCnt[new_group_nr]++;
+ AmoebaCnt2[new_group_nr]++;
+ AmoebenVereinigen(newax, neway);
+
+ if (AmoebaCnt2[new_group_nr] >= 200 && element == EL_AMOEBE_BD)
+ {
+ AmoebeUmwandeln2(newax, neway, EL_FELSBROCKEN);
+ return;
+ }
+ }
+ }
+
+ if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax, neway) ||
+ (neway == lev_fieldy-1 && newax!=ax))
+ {
+ Feld[newax][neway] = EL_AMOEBING;
+ Store[newax][neway] = element;
+ }
+ else if (neway == ay)
+ Feld[newax][neway] = EL_TROPFEN;
+ else
+ {
+ InitMovingField(ax, ay, MV_DOWN);
+ Feld[ax][ay] = EL_TROPFEN;
+ Store[ax][ay] = EL_AMOEBE_NASS;
+ ContinueMoving(ax, ay);
+ return;
+ }
+
+ DrawLevelField(newax, neway);
+}
+
+void Life(int ax, int ay)
+{
+ int x1, y1, x2, y2;
+ static int life[4] = { 2, 3, 3, 3 }; /* parameters for "game of life" */
+ int life_time = 40;
+ int element = Feld[ax][ay];
+
+ if (Stop[ax][ay])
+ return;
+
+ if (!MovDelay[ax][ay]) /* start new "game of life" cycle */
+ MovDelay[ax][ay] = life_time;
+
+ if (MovDelay[ax][ay]) /* wait some time before next cycle */
+ {
+ MovDelay[ax][ay]--;
+ if (MovDelay[ax][ay])
+ return;
+ }
+
+ for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
+ {
+ int xx = ax+x1, yy = ay+y1;
+ int nachbarn = 0;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
+ {
+ int x = xx+x2, y = yy+y2;
+
+ if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
+ continue;
+
+ if (((Feld[x][y] == element ||
+ (element == EL_LIFE && IS_PLAYER(x, y))) &&
+ !Stop[x][y]) ||
+ (IS_FREE(x, y) && Stop[x][y]))
+ nachbarn++;
+ }
+
+ if (xx == ax && yy == ay) /* field in the middle */
+ {
+ if (nachbarn<life[0] || nachbarn>life[1])
+ {
+ Feld[xx][yy] = EL_LEERRAUM;
+ if (!Stop[xx][yy])
+ DrawLevelField(xx, yy);
+ Stop[xx][yy] = TRUE;
+ }
+ }
+ else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
+ { /* free border field */
+ if (nachbarn>=life[2] && nachbarn<=life[3])
+ {
+ Feld[xx][yy] = element;
+ MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
+ if (!Stop[xx][yy])
+ DrawLevelField(xx, yy);
+ Stop[xx][yy] = TRUE;
+ }
+ }
+ }
+}
+
+void Ablenk(int x, int y)
+{
+ if (!MovDelay[x][y]) /* next animation frame */
+ MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
+
+ if (MovDelay[x][y]) /* wait some time before next frame */
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y])
+ {
+ if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
+ if (!(MovDelay[x][y]%4))
+ PlaySoundLevel(x, y, SND_MIEP);
+ return;
+ }
+ }
+
+ Feld[x][y] = EL_ABLENK_AUS;
+ DrawLevelField(x, y);
+ if (ZX == x && ZY == y)
+ ZX = ZY = -1;
+}
+
+void Birne(int x, int y)
+{
+ if (!MovDelay[x][y]) /* next animation frame */
+ MovDelay[x][y] = 800;
+
+ if (MovDelay[x][y]) /* wait some time before next frame */
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y])
+ {
+ if (!(MovDelay[x][y]%5))
+ {
+ if (!(MovDelay[x][y]%10))
+ Feld[x][y]=EL_ABLENK_EIN;
+ else
+ Feld[x][y]=EL_ABLENK_AUS;
+ DrawLevelField(x, y);
+ Feld[x][y]=EL_ABLENK_EIN;
+ }
+ return;
+ }
+ }
+
+ Feld[x][y]=EL_ABLENK_AUS;
+ DrawLevelField(x, y);
+ if (ZX == x && ZY == y)
+ ZX=ZY=-1;
+}
+
+void Blubber(int x, int y)
+{
+ if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
+ DrawLevelField(x, y-1);
+ else
+ DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
+}
+
+void NussKnacken(int x, int y)
+{
+ if (!MovDelay[x][y]) /* next animation frame */
+ MovDelay[x][y] = 7;
+
+ if (MovDelay[x][y]) /* wait some time before next frame */
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
+
+ if (!MovDelay[x][y])
+ {
+ Feld[x][y] = EL_EDELSTEIN;
+ DrawLevelField(x, y);
+ }
+ }
+}
+
+void SiebAktivieren(int x, int y, int typ)
+{
+ if (!(SiebAktiv % 4) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ DrawGraphic(SCREENX(x), SCREENY(y),
+ (typ == 1 ? GFX_SIEB_VOLL :
+ GFX_SIEB2_VOLL) + 3 - (SiebAktiv % 16) / 4);
+}
+
+void AusgangstuerPruefen(int x, int y)
+{
+ if (!local_player->gems_still_needed &&
+ !local_player->sokobanfields_still_needed &&
+ !local_player->lights_still_needed)
+ {
+ Feld[x][y] = EL_AUSGANG_ACT;
+
+ PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
+ (x > LEVELX(BX2) ? LEVELX(BX2) : x),
+ y < LEVELY(BY1) ? LEVELY(BY1) :
+ (y > LEVELY(BY2) ? LEVELY(BY2) : y),
+ SND_OEFFNEN);
+ }
+}
+
+void AusgangstuerOeffnen(int x, int y)
+{
+ int delay = 6;
+
+ if (!MovDelay[x][y]) /* next animation frame */
+ MovDelay[x][y] = 5*delay;
+
+ if (MovDelay[x][y]) /* wait some time before next frame */
+ {
+ int tuer;
+
+ MovDelay[x][y]--;
+ tuer = MovDelay[x][y]/delay;
+ if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
+
+ if (!MovDelay[x][y])
+ {
+ Feld[x][y] = EL_AUSGANG_AUF;
+ DrawLevelField(x, y);
+ }
+ }
+}
+
+void AusgangstuerBlinken(int x, int y)
+{
+ DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
+}
+
+void EdelsteinFunkeln(int x, int y)
+{
+ if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
+ return;
+
+ if (Feld[x][y] == EL_EDELSTEIN_BD)
+ DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
+ else
+ {
+ if (!MovDelay[x][y]) /* next animation frame */
+ MovDelay[x][y] = 11 * !SimpleRND(500);
+
+ if (MovDelay[x][y]) /* wait some time before next frame */
+ {
+ MovDelay[x][y]--;
+
+ if (setup.direct_draw && MovDelay[x][y])
+ SetDrawtoField(DRAW_BUFFERED);
+
+ DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
+
+ if (MovDelay[x][y])
+ {
+ int phase = (MovDelay[x][y]-1)/2;
+
+ if (phase > 2)
+ phase = 4-phase;
+
+ DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
+
+ if (setup.direct_draw)
+ {
+ int dest_x, dest_y;
+
+ dest_x = FX + SCREENX(x)*TILEX;
+ dest_y = FY + SCREENY(y)*TILEY;
+
+ XCopyArea(display, drawto_field, window, gc,
+ dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
+ SetDrawtoField(DRAW_DIRECT);
+ }
+ }
+ }
+ }
+}
+
+void MauerWaechst(int x, int y)
+{
+ int delay = 6;
+
+ if (!MovDelay[x][y]) /* next animation frame */
+ MovDelay[x][y] = 3*delay;
+
+ if (MovDelay[x][y]) /* wait some time before next frame */
+ {
+ int phase;
+
+ MovDelay[x][y]--;
+ phase = 2-MovDelay[x][y]/delay;
+ if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ DrawGraphic(SCREENX(x), SCREENY(y),
+ (MovDir[x][y] == MV_LEFT ? GFX_MAUER_LEFT :
+ MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
+ MovDir[x][y] == MV_UP ? GFX_MAUER_UP :
+ GFX_MAUER_DOWN ) + phase);
+
+ if (!MovDelay[x][y])
+ {
+ if (MovDir[x][y] == MV_LEFT)
+ {
+ if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
+ DrawLevelField(x-1, y);
+ }
+ else if (MovDir[x][y] == MV_RIGHT)
+ {
+ if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
+ DrawLevelField(x+1, y);
+ }
+ else if (MovDir[x][y] == MV_UP)
+ {
+ if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
+ DrawLevelField(x, y-1);
+ }
+ else
+ {
+ if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
+ DrawLevelField(x, y+1);
+ }
+
+ Feld[x][y] = Store[x][y];
+ Store[x][y] = 0;
+ MovDir[x][y] = MV_NO_MOVING;
+ DrawLevelField(x, y);
+ }
+ }
+}
+
+void MauerAbleger(int ax, int ay)
+{
+ int element = Feld[ax][ay];
+ boolean oben_frei = FALSE, unten_frei = FALSE;
+ boolean links_frei = FALSE, rechts_frei = FALSE;
+ boolean oben_massiv = FALSE, unten_massiv = FALSE;
+ boolean links_massiv = FALSE, rechts_massiv = FALSE;
+
+ if (!MovDelay[ax][ay]) /* start building new wall */
+ MovDelay[ax][ay] = 6;
+
+ if (MovDelay[ax][ay]) /* wait some time before building new wall */
+ {
+ MovDelay[ax][ay]--;
+ if (MovDelay[ax][ay])
+ return;
+ }
+
+ if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
+ oben_frei = TRUE;
+ if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
+ unten_frei = TRUE;
+ if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
+ links_frei = TRUE;
+ if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
+ rechts_frei = TRUE;
+
+ if (element == EL_MAUER_Y || element == EL_MAUER_XY)
+ {
+ if (oben_frei)
+ {
+ Feld[ax][ay-1] = EL_MAUERND;
+ Store[ax][ay-1] = element;
+ MovDir[ax][ay-1] = MV_UP;
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
+ DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
+ }
+ if (unten_frei)
+ {
+ Feld[ax][ay+1] = EL_MAUERND;
+ Store[ax][ay+1] = element;
+ MovDir[ax][ay+1] = MV_DOWN;
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
+ DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
+ }
+ }
+
+ if (element == EL_MAUER_X || element == EL_MAUER_XY ||
+ element == EL_MAUER_LEBT)
+ {
+ if (links_frei)
+ {
+ Feld[ax-1][ay] = EL_MAUERND;
+ Store[ax-1][ay] = element;
+ MovDir[ax-1][ay] = MV_LEFT;
+ if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
+ DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
+ }
+ if (rechts_frei)
+ {
+ Feld[ax+1][ay] = EL_MAUERND;
+ Store[ax+1][ay] = element;
+ MovDir[ax+1][ay] = MV_RIGHT;
+ if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
+ DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
+ }
+ }
+
+ if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
+ DrawLevelField(ax, ay);
+
+ if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
+ oben_massiv = TRUE;
+ if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
+ unten_massiv = TRUE;
+ if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
+ links_massiv = TRUE;
+ if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
+ rechts_massiv = TRUE;
+
+ if (((oben_massiv && unten_massiv) ||
+ element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
+ ((links_massiv && rechts_massiv) ||
+ element == EL_MAUER_Y))
+ Feld[ax][ay] = EL_MAUERWERK;
+}
+
+void CheckForDragon(int x, int y)
+{
+ int i, j;
+ boolean dragon_found = FALSE;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
+ for (i=0; i<4; i++)
+ {
+ for (j=0; j<4; j++)
+ {
+ int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+
+ if (IN_LEV_FIELD(xx, yy) &&
+ (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
+ {
+ if (Feld[xx][yy] == EL_DRACHE)
+ dragon_found = TRUE;
+ }
+ else
+ break;
+ }
+ }
+
+ if (!dragon_found)
+ {
+ for (i=0; i<4; i++)
+ {
+ for (j=0; j<3; j++)
+ {
+ int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+
+ if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
+ {
+ Feld[xx][yy] = EL_LEERRAUM;
+ DrawLevelField(xx, yy);
+ }
+ else
+ break;
+ }
+ }
+ }
+}
+
+static void PlayerActions(struct PlayerInfo *player, byte player_action)
+{
+ static byte stored_player_action[MAX_PLAYERS];
+ static int num_stored_actions = 0;
+ static boolean save_tape_entry = FALSE;
+ boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
+ int jx = player->jx, jy = player->jy;
+ int left = player_action & JOY_LEFT;
+ int right = player_action & JOY_RIGHT;
+ int up = player_action & JOY_UP;
+ int down = player_action & JOY_DOWN;
+ int button1 = player_action & JOY_BUTTON_1;
+ int button2 = player_action & JOY_BUTTON_2;
+ int dx = (left ? -1 : right ? 1 : 0);
+ int dy = (up ? -1 : down ? 1 : 0);
+
+ stored_player_action[player->index_nr] = 0;
+ num_stored_actions++;
+
+ if (!player->active || player->gone || tape.pausing)
+ return;
+
+ if (player_action)
+ {
+ save_tape_entry = TRUE;
+ player->frame_reset_delay = 0;
+
+ if (button1)
+ snapped = SnapField(player, dx, dy);
+ else
+ {
+ if (button2)
+ bombed = PlaceBomb(player);
+ moved = MoveFigure(player, dx, dy);
+ }
+
+ if (tape.recording && (moved || snapped || bombed))
+ {
+ if (bombed && !moved)
+ player_action &= JOY_BUTTON;
+
+ stored_player_action[player->index_nr] = player_action;
+
+#if 0
+ /* this allows cycled sequences of PlayerActions() */
+ if (num_stored_actions >= MAX_PLAYERS)
+ {
+ TapeRecordAction(stored_player_action);
+ num_stored_actions = 0;
+ }
+#endif
+
+ }
+ else if (tape.playing && snapped)
+ SnapField(player, 0, 0); /* stop snapping */
+ }
+ else
+ {
+ DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
+ SnapField(player, 0, 0);
+ if (++player->frame_reset_delay > MoveSpeed)
+ player->Frame = 0;
+ }
+
+ if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
+ {
+ TapeRecordAction(stored_player_action);
+ num_stored_actions = 0;
+ save_tape_entry = FALSE;
+ }
+
+ if (tape.playing && !tape.pausing && !player_action &&
+ tape.counter < tape.length)
+ {
+ int next_joy =
+ tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
+
+ if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
+ (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
+ {
+ int dx = (next_joy == JOY_LEFT ? -1 : +1);
+
+ if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
+ {
+ int el = Feld[jx+dx][jy];
+ int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10);
+
+ if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
+ {
+ player->MovDir = next_joy;
+ player->Frame = FrameCounter % 4;
+ player->Pushing = TRUE;
+ }
+ }
+ }
+ }
+}
+
+void GameActions()
+{
+ static long action_delay = 0;
+ long action_delay_value;
+ int sieb_x = 0, sieb_y = 0;
+ int i, x, y, element;
+ byte *recorded_player_action;
+ byte summarized_player_action = 0;
+
+ if (game_status != PLAYING)
+ return;
+
+ action_delay_value =
+ (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
+
+ /*
+ if (tape.playing && tape.fast_forward)
+ {
+ char buf[100];
+
+ sprintf(buf, "FFWD: %ld ms", action_delay_value);
+ print_debug(buf);
+ }
+ */
+
+
+ /* main game synchronization point */
+
+
+
+
+#if 1
+ WaitUntilDelayReached(&action_delay, action_delay_value);
+#else
+ /*
+ while (!DelayReached(&action_delay, action_delay_value));
+ */
+
+ while (!DelayReached(&action_delay, action_delay_value))
+ {
+ char buf[100];
+
+ sprintf(buf, "%ld %ld %ld",
+ Counter(), action_delay, action_delay_value);
+ print_debug(buf);
+ }
+ print_debug("done");
+
+
+#endif
+
+
+
+
+ if (network_playing && !network_player_action_received)
+ {
+ /*
+#ifdef DEBUG
+ printf("DEBUG: try to get network player actions in time\n");
+#endif
+ */
+
+#ifndef MSDOS
+ /* last chance to get network player actions without main loop delay */
+ HandleNetworking();
+#endif
+
+ if (game_status != PLAYING)
+ return;
+
+ if (!network_player_action_received)
+ {
+ /*
+#ifdef DEBUG
+ printf("DEBUG: failed to get network player actions in time\n");
+#endif
+ */
+ return;
+ }
+ }
+
+
+ /*
+ if (tape.pausing || (tape.playing && !TapePlayDelay()))
+ return;
+ else if (tape.recording)
+ TapeRecordDelay();
+ */
+
+ if (tape.pausing)
+ return;
+
+ if (tape.playing)
+ TapePlayDelay();
+ else if (tape.recording)
+ TapeRecordDelay();
+
+ recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ {
+ summarized_player_action |= stored_player[i].action;
+
+ if (!network_playing)
+ stored_player[i].effective_action = stored_player[i].action;
+ }
+
+#ifndef MSDOS
+ if (network_playing)
+ SendToServer_MovePlayer(summarized_player_action);
+#endif
+
+ if (!options.network && !setup.team_mode)
+ local_player->effective_action = summarized_player_action;
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ {
+ int actual_player_action = stored_player[i].effective_action;
+
+ if (recorded_player_action)
+ actual_player_action = recorded_player_action[i];
+
+ PlayerActions(&stored_player[i], actual_player_action);
+ ScrollFigure(&stored_player[i], SCROLL_GO_ON);
+ }
+
+ network_player_action_received = FALSE;
+
+ ScrollScreen(NULL, SCROLL_GO_ON);
+