+ 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 (stored_player[i].programmed_action)
+ actual_player_action = stored_player[i].programmed_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);
+
+
+
+#ifdef DEBUG
+#if 0
+ if (TimeFrames == 0 && local_player->active)
+ {
+ extern unsigned int last_RND();
+
+ printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
+ TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
+ }
+#endif
+#endif
+
+#ifdef DEBUG
+#if 0
+ if (GameFrameDelay >= 500)
+ printf("FrameCounter == %d\n", FrameCounter);
+#endif
+#endif
+
+
+
+ FrameCounter++;
+ TimeFrames++;
+
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ {
+ Stop[x][y] = FALSE;
+ if (JustStopped[x][y] > 0)
+ JustStopped[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 (IS_ACTIVE_BOMB(element))
+ 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 (element == EL_DEAMOEBING)
+ AmoebeSchrumpft(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);
+ else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
+ CheckBuggyBase(x, y);
+ else if (element == EL_SP_TERMINAL)
+ DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
+ else if (element == EL_SP_TERMINAL_ACTIVE)
+ DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
+ else if (IS_BELT(element))
+ DrawBeltAnimation(x, y, element);
+ else if (element == EL_SWITCHGATE_OPENING)
+ OpenSwitchgate(x, y);
+ else if (element == EL_SWITCHGATE_CLOSING)
+ CloseSwitchgate(x, y);
+ else if (element == EL_EXTRA_TIME)
+ DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL);
+ else if (element == EL_FORCE_FIELD_PASSIVE)
+ DrawGraphicAnimation(x, y, GFX_FORCE_FIELD_PASSIVE, 6, 4, ANIM_NORMAL);
+ else if (element == EL_FORCE_FIELD_ACTIVE)
+ DrawGraphicAnimation(x, y, GFX_FORCE_FIELD_ACTIVE, 6, 4, ANIM_NORMAL);
+
+ if (game.magic_wall_active)
+ {
+ boolean 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 (game.magic_wall_active)
+ {
+ if (!(game.magic_wall_time_left % 4))
+ PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
+
+ if (game.magic_wall_time_left > 0)
+ {
+ game.magic_wall_time_left--;
+ if (!game.magic_wall_time_left)
+ {
+ 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);
+ }
+ }
+
+ game.magic_wall_active = FALSE;
+ }
+ }
+ }
+
+ if (game.light_time_left > 0)
+ {
+ game.light_time_left--;
+
+ if (game.light_time_left == 0)
+ {
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ {
+ element = Feld[x][y];
+
+ if (element == EL_LIGHT_SWITCH_ON)
+ {
+ Feld[x][y] = EL_LIGHT_SWITCH_OFF;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_INVISIBLE_STEEL ||
+ element == EL_UNSICHTBAR ||
+ element == EL_SAND_INVISIBLE)
+ DrawLevelField(x, y);
+ }
+ }
+ }
+
+ if (TimeFrames >= (1000 / GameFrameDelay))
+ {
+ TimeFrames = 0;
+ TimePlayed++;
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ {
+ if (FORCE_FIELD_ON(&stored_player[i]))
+ {
+ stored_player[i].force_field_passive_time_left--;
+
+ if (stored_player[i].force_field_active_time_left > 0)
+ stored_player[i].force_field_active_time_left--;
+ }
+ }
+
+ if (tape.recording || tape.playing)
+ DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
+
+ if (TimeLeft > 0)
+ {
+ 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]);
+ }
+ else if (level.time == 0) /* level without time limit */
+ DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
+ }
+
+ DrawAllPlayers();
+}
+
+static boolean 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] == 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 boolean 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)
+ continue;
+
+ if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void ScrollLevel(int dx, int dy)
+{
+ int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
+ int x, y;
+
+ XCopyArea(display, drawto_field, drawto_field, gc,
+ FX + TILEX*(dx == -1) - softscroll_offset,
+ FY + TILEY*(dy == -1) - softscroll_offset,
+ SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
+ SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
+ FX + TILEX*(dx == 1) - softscroll_offset,
+ FY + TILEY*(dy == 1) - softscroll_offset);
+
+ if (dx)
+ {
+ x = (dx == 1 ? BX1 : BX2);
+ for (y=BY1; y<=BY2; y++)
+ DrawScreenField(x, y);
+ }
+ if (dy)
+ {
+ y = (dy == 1 ? BY1 : BY2);
+ for (x=BX1; x<=BX2; x++)
+ DrawScreenField(x, y);
+ }
+
+ redraw_mask |= REDRAW_FIELD;
+}
+
+static void CheckGravityMovement(struct PlayerInfo *player)
+{
+ if (level.gravity && !player->programmed_action)
+ {
+ int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
+ int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
+ int move_dir =
+ (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
+ (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
+ (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
+ int jx = player->jx, jy = player->jy;
+ 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 new_jx = jx + dx, new_jy = jy + dy;
+ boolean field_under_player_is_free =
+ (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
+ boolean player_is_moving_to_valid_field =
+ (IN_LEV_FIELD(new_jx, new_jy) &&
+ (Feld[new_jx][new_jy] == EL_SP_BASE ||
+ Feld[new_jx][new_jy] == EL_ERDREICH));
+
+ if (field_under_player_is_free && !player_is_moving_to_valid_field)
+ player->programmed_action = MV_DOWN;
+ }
+}
+
+boolean MoveFigureOneStep(struct PlayerInfo *player,
+ int dx, int dy, int real_dx, int real_dy)
+{
+ int jx = player->jx, jy = player->jy;
+ int new_jx = jx+dx, new_jy = jy+dy;
+ int element;
+ int can_move;
+
+ if (!player->active || (!dx && !dy))
+ return MF_NO_ACTION;
+
+ player->MovDir = (dx < 0 ? MV_LEFT :
+ dx > 0 ? MV_RIGHT :
+ dy < 0 ? MV_UP :
+ dy > 0 ? MV_DOWN : MV_NO_MOVING);
+
+ if (!IN_LEV_FIELD(new_jx, new_jy))
+ return MF_NO_ACTION;
+
+ if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
+ return MF_NO_ACTION;
+
+#if 0
+ element = MovingOrBlocked2Element(new_jx, new_jy);
+#else
+ element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
+#endif
+
+ if (DONT_GO_TO(element))
+ {
+ if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
+ {
+ Blurb(jx, jy);
+ Feld[jx][jy] = EL_SPIELFIGUR;
+ InitMovingField(jx, jy, MV_DOWN);
+ Store[jx][jy] = EL_SALZSAEURE;
+ ContinueMoving(jx, jy);
+ BuryHero(player);
+ }
+ else
+ {
+#if 1
+ TestIfBadThingHitsHero(new_jx, new_jy);
+#else
+ if (player->force_field_time_left == 0)
+ KillHero(player);
+#endif
+ }
+
+ return MF_MOVING;
+ }
+
+ can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
+ if (can_move != MF_MOVING)
+ return can_move;
+
+ StorePlayer[jx][jy] = 0;
+ player->last_jx = jx;
+ player->last_jy = jy;
+ jx = player->jx = new_jx;
+ jy = player->jy = new_jy;
+ StorePlayer[jx][jy] = player->element_nr;
+
+ player->MovPos =
+ (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
+
+ ScrollFigure(player, SCROLL_INIT);
+
+ return MF_MOVING;
+}
+
+boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
+{
+ int jx = player->jx, jy = player->jy;
+ int old_jx = jx, old_jy = jy;
+ int moved = MF_NO_ACTION;
+
+ if (!player->active || (!dx && !dy))
+ return FALSE;
+
+ if (!FrameReached(&player->move_delay, player->move_delay_value) &&
+ !tape.playing)
+ return FALSE;
+
+ /* remove the last programmed player action */
+ player->programmed_action = 0;
+
+ if (player->MovPos)
+ {
+ /* should only happen if pre-1.2 tape recordings are played */
+ /* this is only for backward compatibility */
+
+ int original_move_delay_value = player->move_delay_value;
+
+#if DEBUG
+ printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
+#endif
+
+ /* scroll remaining steps with finest movement resolution */
+ player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
+
+ while (player->MovPos)
+ {
+ ScrollFigure(player, SCROLL_GO_ON);
+ ScrollScreen(NULL, SCROLL_GO_ON);
+ FrameCounter++;
+ DrawAllPlayers();
+ BackToFront();
+ }
+
+ player->move_delay_value = original_move_delay_value;
+ }
+
+ if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
+ {
+ if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
+ moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
+ }
+ else
+ {
+ if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
+ moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
+ }
+
+ jx = player->jx;
+ jy = player->jy;
+
+ if (moved & MF_MOVING && !ScreenMovPos &&
+ (player == local_player || !options.network))
+ {
+ int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
+ int offset = (setup.scroll_delay ? 3 : 0);
+
+ if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
+ {
+ /* actual player has left the screen -- scroll in that direction */
+ if (jx != old_jx) /* player has moved horizontally */
+ scroll_x += (jx - old_jx);
+ else /* player has moved vertically */
+ scroll_y += (jy - old_jy);
+ }
+ else
+ {
+ if (jx != old_jx) /* player has moved horizontally */
+ {
+ if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
+ (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
+ scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
+
+ /* don't scroll over playfield boundaries */
+ if (scroll_x < SBX_Left || scroll_x > SBX_Right)
+ scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
+
+ /* don't scroll more than one field at a time */
+ scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
+
+ /* don't scroll against the player's moving direction */
+ if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
+ (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
+ scroll_x = old_scroll_x;
+ }
+ else /* player has moved vertically */
+ {
+ if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
+ (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
+ scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
+
+ /* don't scroll over playfield boundaries */
+ if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
+ scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+
+ /* don't scroll more than one field at a time */
+ scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
+
+ /* don't scroll against the player's moving direction */
+ if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
+ (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
+ scroll_y = old_scroll_y;
+ }
+ }
+
+ if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
+ {
+ if (!options.network && !AllPlayersInVisibleScreen())
+ {
+ scroll_x = old_scroll_x;
+ scroll_y = old_scroll_y;
+ }
+ else
+ {
+ ScrollScreen(player, SCROLL_INIT);
+ ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
+ }
+ }
+ }
+
+ if (!(moved & MF_MOVING) && !player->Pushing)
+ player->Frame = 0;
+ else
+ player->Frame = (player->Frame + 1) % 4;
+
+ if (moved & MF_MOVING)
+ {
+ if (old_jx != jx && old_jy == jy)
+ player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
+ else if (old_jx == jx && old_jy != jy)
+ player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
+
+ DrawLevelField(jx, jy); /* for "ErdreichAnbroeckeln()" */
+
+ player->last_move_dir = player->MovDir;
+ }
+ else
+ {
+ CheckGravityMovement(player);
+
+ player->last_move_dir = MV_NO_MOVING;
+ }
+
+ TestIfHeroHitsBadThing(jx, jy);
+
+ if (!player->active)
+ RemoveHero(player);
+
+ return moved;
+}
+
+void ScrollFigure(struct PlayerInfo *player, int mode)
+{
+ int jx = player->jx, jy = player->jy;
+ int last_jx = player->last_jx, last_jy = player->last_jy;
+ int move_stepsize = TILEX / player->move_delay_value;
+
+ if (!player->active || !player->MovPos)
+ return;
+
+ if (mode == SCROLL_INIT)
+ {
+ player->actual_frame_counter = FrameCounter;
+ player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
+
+ if (Feld[last_jx][last_jy] == EL_LEERRAUM)
+ Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
+
+ DrawPlayer(player);
+ return;
+ }
+ else if (!FrameReached(&player->actual_frame_counter, 1))
+ return;
+
+ player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
+ player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
+
+ if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
+ Feld[last_jx][last_jy] = EL_LEERRAUM;
+
+ /* before DrawPlayer() to draw correct player graphic for this case */
+ if (player->MovPos == 0)
+ CheckGravityMovement(player);
+
+ DrawPlayer(player);
+
+ if (player->MovPos == 0)
+ {
+ if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
+ {
+ /* continue with normal speed after quickly moving through gate */
+ HALVE_PLAYER_SPEED(player);
+
+ /* be able to make the next move without delay */
+ player->move_delay = 0;
+ }
+
+ player->last_jx = jx;
+ player->last_jy = jy;
+
+ if (Feld[jx][jy] == EL_AUSGANG_AUF)
+ {
+ RemoveHero(player);
+
+ if (!local_player->friends_still_needed)
+ player->LevelSolved = player->GameOver = TRUE;
+ }
+ }
+}
+
+void ScrollScreen(struct PlayerInfo *player, int mode)
+{
+ static unsigned long screen_frame_counter = 0;
+
+ if (mode == SCROLL_INIT)
+ {
+ /* set scrolling step size according to actual player's moving speed */
+ ScrollStepSize = TILEX / player->move_delay_value;
+
+ screen_frame_counter = FrameCounter;
+ ScreenMovDir = player->MovDir;
+ ScreenMovPos = player->MovPos;
+ ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
+ return;
+ }
+ else if (!FrameReached(&screen_frame_counter, 1))
+ return;
+
+ if (ScreenMovPos)
+ {
+ ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
+ ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
+ redraw_mask |= REDRAW_FIELD;
+ }
+ else
+ ScreenMovDir = MV_NO_MOVING;
+}
+
+void TestIfGoodThingHitsBadThing(int goodx, int goody)
+{
+ int i, killx = goodx, killy = goody;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int harmless[4] =
+ {
+ MV_UP,
+ MV_LEFT,
+ MV_RIGHT,
+ MV_DOWN
+ };
+
+ for (i=0; i<4; i++)
+ {
+ int x, y, element;
+
+ x = goodx + xy[i][0];
+ y = goody + xy[i][1];
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+#if 0
+ element = Feld[x][y];
+#else
+ element = MovingOrBlocked2ElementIfNotLeaving(x, y);
+#endif
+
+ if (DONT_TOUCH(element))
+ {
+ if (MovDir[x][y] == harmless[i])
+ continue;
+
+ killx = x;
+ killy = y;
+ break;
+ }
+ }
+
+ if (killx != goodx || killy != goody)
+ {
+ if (IS_PLAYER(goodx, goody))
+ {
+ struct PlayerInfo *player = PLAYERINFO(goodx, goody);
+
+ if (player->force_field_active_time_left > 0)
+ Bang(killx, killy);
+ else if (player->force_field_passive_time_left == 0)
+ KillHero(player);
+ }
+ else
+ Bang(goodx, goody);
+ }
+}
+
+void TestIfBadThingHitsGoodThing(int badx, int bady)
+{
+ int i, killx = badx, killy = bady;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int harmless[4] =
+ {
+ MV_UP,
+ MV_LEFT,
+ MV_RIGHT,
+ MV_DOWN
+ };
+
+ for (i=0; i<4; i++)
+ {
+ int x, y, element;
+
+ x = badx + xy[i][0];
+ y = bady + xy[i][1];
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+ element = Feld[x][y];
+
+ if (IS_PLAYER(x, y))
+ {
+ killx = x;
+ killy = y;
+ break;
+ }
+ else if (element == EL_PINGUIN)
+ {
+ if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
+ continue;
+
+ killx = x;
+ killy = y;
+ break;
+ }
+ }
+
+ if (killx != badx || killy != bady)
+ {
+ if (IS_PLAYER(killx, killy))
+ {
+ struct PlayerInfo *player = PLAYERINFO(killx, killy);
+
+ if (player->force_field_active_time_left > 0)
+ Bang(badx, bady);
+ else if (player->force_field_passive_time_left == 0)
+ KillHero(player);
+ }
+ else
+ Bang(killx, killy);
+ }
+}
+
+void TestIfHeroHitsBadThing(int x, int y)
+{
+ TestIfGoodThingHitsBadThing(x, y);
+}
+
+void TestIfBadThingHitsHero(int x, int y)
+{
+ TestIfBadThingHitsGoodThing(x, y);
+}
+
+void TestIfFriendHitsBadThing(int x, int y)
+{
+ TestIfGoodThingHitsBadThing(x, y);
+}
+
+void TestIfBadThingHitsFriend(int x, int y)
+{
+ TestIfBadThingHitsGoodThing(x, y);
+}
+
+void TestIfBadThingHitsOtherBadThing(int badx, int bady)
+{
+ int i, killx = badx, killy = bady;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
+ for (i=0; i<4; i++)
+ {
+ int x, y, element;
+
+ x=badx + xy[i][0];
+ y=bady + xy[i][1];
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+ element = Feld[x][y];
+ if (IS_AMOEBOID(element) || element == EL_LIFE ||
+ element == EL_AMOEBING || element == EL_TROPFEN)
+ {
+ killx = x;
+ killy = y;
+ break;
+ }
+ }
+
+ if (killx != badx || killy != bady)
+ Bang(badx, bady);
+}
+
+void KillHero(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+
+ if (!player->active)
+ return;
+
+ if (IS_PFORTE(Feld[jx][jy]))
+ Feld[jx][jy] = EL_LEERRAUM;
+
+ /* deactivate force field (else Bang()/Explode() would not work right) */
+ player->force_field_passive_time_left = 0;
+ player->force_field_active_time_left = 0;
+
+ Bang(jx, jy);
+ BuryHero(player);
+}
+
+static void KillHeroUnlessForceField(struct PlayerInfo *player)
+{
+ if (!FORCE_FIELD_ON(player))
+ KillHero(player);
+}
+
+void BuryHero(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+
+ if (!player->active)
+ return;
+
+ PlaySoundLevel(jx, jy, SND_AUTSCH);
+ PlaySoundLevel(jx, jy, SND_LACHEN);
+
+ player->GameOver = TRUE;
+ RemoveHero(player);
+}
+
+void RemoveHero(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+ int i, found = FALSE;
+
+ player->present = FALSE;
+ player->active = FALSE;
+
+ StorePlayer[jx][jy] = 0;
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ if (stored_player[i].active)
+ found = TRUE;
+
+ if (!found)
+ AllPlayersGone = TRUE;
+
+ ExitX = ZX = jx;
+ ExitY = ZY = jy;
+}
+
+int DigField(struct PlayerInfo *player,
+ int x, int y, int real_dx, int real_dy, int mode)
+{
+ int jx = player->jx, jy = player->jy;
+ int dx = x - jx, dy = y - jy;
+ int move_direction = (dx == -1 ? MV_LEFT :
+ dx == +1 ? MV_RIGHT :
+ dy == -1 ? MV_UP :
+ dy == +1 ? MV_DOWN : MV_NO_MOVING);
+ int element;
+
+ if (!player->MovPos)
+ player->Pushing = FALSE;
+
+ if (mode == DF_NO_PUSH)
+ {
+ player->Switching = FALSE;
+ player->push_delay = 0;
+ return MF_NO_ACTION;
+ }
+
+ if (IS_MOVING(x, y) || IS_PLAYER(x, y))
+ return MF_NO_ACTION;
+
+ element = Feld[x][y];
+
+ switch (element)
+ {
+ case EL_LEERRAUM:
+ PlaySoundLevel(x, y, SND_EMPTY);
+ break;
+
+ case EL_ERDREICH:
+ case EL_SAND_INVISIBLE:
+ Feld[x][y] = EL_LEERRAUM;
+ PlaySoundLevel(x, y, SND_SCHLURF);
+ break;
+
+ case EL_SP_BASE:
+ case EL_SP_BUG:
+ Feld[x][y] = EL_LEERRAUM;
+ PlaySoundLevel(x, y, SND_SP_BASE);
+ break;
+
+ case EL_EDELSTEIN:
+ case EL_EDELSTEIN_BD:
+ case EL_EDELSTEIN_GELB:
+ case EL_EDELSTEIN_ROT:
+ case EL_EDELSTEIN_LILA:
+ case EL_DIAMANT:
+ case EL_SP_INFOTRON:
+ RemoveField(x, y);
+ local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
+ if (local_player->gems_still_needed < 0)
+ local_player->gems_still_needed = 0;
+ RaiseScoreElement(element);
+ DrawText(DX_EMERALDS, DY_EMERALDS,
+ int2str(local_player->gems_still_needed, 3),
+ FS_SMALL, FC_YELLOW);
+ if (element == EL_SP_INFOTRON)
+ PlaySoundLevel(x, y, SND_SP_INFOTRON);
+ else
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_SPEED_PILL:
+ RemoveField(x, y);
+ player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_ENVELOPE:
+ Feld[x][y] = EL_LEERRAUM;
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_EXTRA_TIME:
+ RemoveField(x, y);
+ if (level.time > 0)
+ {
+ TimeLeft += 10;
+ DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+ }
+ PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
+ break;
+
+ case EL_FORCE_FIELD_PASSIVE:
+ RemoveField(x, y);
+ player->force_field_passive_time_left += 10;
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_FORCE_FIELD_ACTIVE:
+ RemoveField(x, y);
+ player->force_field_passive_time_left += 10;
+ player->force_field_active_time_left += 10;
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNAMITE_INACTIVE:
+ case EL_SP_DISK_RED:
+ RemoveField(x, y);
+ player->dynamite++;
+ RaiseScoreElement(EL_DYNAMITE_INACTIVE);
+ DrawText(DX_DYNAMITE, DY_DYNAMITE,
+ int2str(local_player->dynamite, 3),
+ FS_SMALL, FC_YELLOW);
+ if (element == EL_SP_DISK_RED)
+ PlaySoundLevel(x, y, SND_SP_INFOTRON);
+ else
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_NR:
+ RemoveField(x, y);
+ player->dynabomb_count++;
+ player->dynabombs_left++;
+ RaiseScoreElement(EL_DYNAMITE_INACTIVE);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_SZ:
+ RemoveField(x, y);
+ player->dynabomb_size++;
+ RaiseScoreElement(EL_DYNAMITE_INACTIVE);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_XL:
+ RemoveField(x, y);
+ player->dynabomb_xl = TRUE;
+ RaiseScoreElement(EL_DYNAMITE_INACTIVE);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_SCHLUESSEL1:
+ case EL_SCHLUESSEL2:
+ case EL_SCHLUESSEL3:
+ case EL_SCHLUESSEL4:
+ {
+ int key_nr = element - EL_SCHLUESSEL1;
+
+ RemoveField(x, y);
+ player->key[key_nr] = TRUE;
+ RaiseScoreElement(EL_SCHLUESSEL);
+ DrawMiniGraphicExt(drawto, gc,
+ DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
+ GFX_SCHLUESSEL1+key_nr);
+ DrawMiniGraphicExt(window, gc,
+ DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
+ GFX_SCHLUESSEL1+key_nr);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+ }
+
+ case EL_EM_KEY_1:
+ case EL_EM_KEY_2:
+ case EL_EM_KEY_3:
+ case EL_EM_KEY_4:
+ {
+ int key_nr = element - EL_EM_KEY_1;
+
+ RemoveField(x, y);
+ player->key[key_nr] = TRUE;
+ RaiseScoreElement(EL_SCHLUESSEL);
+ DrawMiniGraphicExt(drawto, gc,
+ DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
+ GFX_SCHLUESSEL1+key_nr);
+ DrawMiniGraphicExt(window, gc,
+ DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
+ GFX_SCHLUESSEL1+key_nr);
+ PlaySoundLevel(x, y, SND_PONG);