+ 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)
+ {
+ 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(byte player_action)
+{
+ static long action_delay = 0;
+ long action_delay_value;
+ int sieb_x = 0, sieb_y = 0;
+ int i, x,y, element;
+ int *recorded_player_action;
+
+ if (game_status != PLAYING)
+ return;
+
+#ifdef DEBUG
+ action_delay_value =
+ (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GameFrameDelay);
+#else
+ action_delay_value =
+ (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
+#endif
+
+ /* main game synchronization point */
+ WaitUntilDelayReached(&action_delay, action_delay_value);
+
+ if (!standalone && !network_player_action_received)
+ {
+ /*
+#ifdef DEBUG
+ printf("DEBUG: try to get network player actions in time\n");
+#endif
+ */
+
+ /* last chance to get network player actions without main loop delay */
+ HandleNetworking();
+
+ 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.playing)
+ recorded_player_action = TapePlayAction();
+ else
+ recorded_player_action = NULL;
+
+ if (!standalone)
+ SendToServer_MovePlayer(player_action);
+
+ for(i=0; i<MAX_PLAYERS; i++)
+ {
+ int actual_player_action =
+ (standalone ? player_action : network_player_action[i]);
+
+ /*
+ int actual_player_action = network_player_action[i];
+ */
+
+ /*
+ int actual_player_action = player_action;
+ */
+
+ /* TEST TEST TEST */
+
+ /*
+ if (i != TestPlayer && !stored_player[i].MovPos)
+ actual_player_action = 0;
+ */
+
+ if (standalone && i != TestPlayer)
+ actual_player_action = 0;
+
+ /* TEST TEST TEST */
+
+ 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[i] = 0;
+ }
+
+ network_player_action_received = FALSE;
+
+ ScrollScreen(NULL, SCROLL_GO_ON);
+
+ if (tape.pausing || (tape.playing && !TapePlayDelay()))
+ return;
+ else if (tape.recording)
+ TapeRecordDelay();
+
+ FrameCounter++;
+ TimeFrames++;
+
+
+ /*
+ printf("FrameCounter == %d, RND(100) == %d\n", FrameCounter, RND(100));
+ */
+
+
+ for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
+ {
+ Stop[x][y] = FALSE;
+ if (JustHit[x][y]>0)
+ JustHit[x][y]--;
+
+#if DEBUG
+ if (IS_BLOCKED(x,y))
+ {
+ int oldx,oldy;
+
+ Blocked2Moving(x,y,&oldx,&oldy);
+ if (!IS_MOVING(oldx,oldy))
+ {
+ printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
+ printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
+ printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
+ printf("GameActions(): This should never happen!\n");
+ }
+ }
+#endif
+ }
+
+ for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
+ {
+ element = Feld[x][y];
+
+ if (IS_INACTIVE(element))
+ continue;
+
+ if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
+ {
+ StartMoving(x,y);
+
+ if (IS_GEM(element))
+ EdelsteinFunkeln(x,y);
+ }
+ else if (IS_MOVING(x,y))
+ ContinueMoving(x,y);
+ else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
+ CheckDynamite(x,y);
+ else if (element==EL_EXPLODING)
+ Explode(x,y,Frame[x][y],EX_NORMAL);
+ else if (element==EL_AMOEBING)
+ AmoebeWaechst(x,y);
+ else if (IS_AMOEBALIVE(element))
+ AmoebeAbleger(x,y);
+ else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
+ Life(x,y);
+ else if (element==EL_ABLENK_EIN)
+ Ablenk(x,y);
+ else if (element==EL_SALZSAEURE)
+ Blubber(x,y);
+ else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
+ Blurb(x,y);
+ else if (element==EL_CRACKINGNUT)
+ NussKnacken(x,y);
+ else if (element==EL_AUSGANG_ZU)
+ AusgangstuerPruefen(x,y);
+ else if (element==EL_AUSGANG_ACT)
+ AusgangstuerOeffnen(x,y);
+ else if (element==EL_AUSGANG_AUF)
+ AusgangstuerBlinken(x,y);
+ else if (element==EL_MAUERND)
+ MauerWaechst(x,y);
+ else if (element==EL_MAUER_LEBT ||
+ element==EL_MAUER_X ||
+ element==EL_MAUER_Y ||
+ element==EL_MAUER_XY)
+ MauerAbleger(x,y);
+ else if (element==EL_BURNING)
+ CheckForDragon(x,y);
+
+ if (SiebAktiv)
+ {
+ BOOL sieb = FALSE;
+ int jx = local_player->jx, jy = local_player->jy;
+
+ if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
+ Store[x][y]==EL_SIEB_LEER)
+ {
+ SiebAktivieren(x, y, 1);
+ sieb = TRUE;
+ }
+ else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
+ Store[x][y]==EL_SIEB2_LEER)
+ {
+ SiebAktivieren(x, y, 2);
+ sieb = TRUE;
+ }
+
+ /* play the element sound at the position nearest to the player */
+ if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
+ {
+ sieb_x = x;
+ sieb_y = y;
+ }
+ }
+ }
+
+ if (SiebAktiv)
+ {
+ if (!(SiebAktiv%4))
+ PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
+ SiebAktiv--;
+ if (!SiebAktiv)
+ {
+ for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
+ {
+ element = Feld[x][y];
+ if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
+ {
+ Feld[x][y] = EL_SIEB_TOT;
+ DrawLevelField(x,y);
+ }
+ else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
+ {
+ Feld[x][y] = EL_SIEB2_TOT;
+ DrawLevelField(x,y);
+ }
+ }
+ }
+ }
+
+ if (TimeLeft>0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing)
+ {
+ TimeFrames = 0;
+ TimeLeft--;
+
+ if (tape.recording || tape.playing)
+ DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
+
+ if (TimeLeft<=10)
+ PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
+
+ DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
+
+ if (!TimeLeft)
+ for(i=0; i<MAX_PLAYERS; i++)
+ KillHero(&stored_player[i]);
+ }
+
+ DrawAllPlayers();
+}
+
+static BOOL AllPlayersInSight(struct PlayerInfo *player, int x, int y)
+{
+ int min_x = x, min_y = y, max_x = x, max_y = y;
+ int i;
+
+ for(i=0; i<MAX_PLAYERS; i++)
+ {
+ int jx = stored_player[i].jx, jy = stored_player[i].jy;
+
+ if (!stored_player[i].active || stored_player[i].gone ||
+ &stored_player[i] == player)
+ continue;
+
+ min_x = MIN(min_x, jx);
+ min_y = MIN(min_y, jy);
+ max_x = MAX(max_x, jx);
+ max_y = MAX(max_y, jy);
+ }
+
+ return(max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
+}
+
+static BOOL AllPlayersInVisibleScreen()
+{
+ int i;
+
+ for(i=0; i<MAX_PLAYERS; i++)
+ {
+ int jx = stored_player[i].jx, jy = stored_player[i].jy;
+
+ if (!stored_player[i].active || stored_player[i].gone)
+ continue;
+
+ if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
+ return(FALSE);