+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->gone || (!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;
+
+ element = MovingOrBlocked2Element(new_jx, new_jy);
+
+ 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
+ KillHero(player);
+
+ 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 / MoveSpeed);
+
+ 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->gone || (!dx && !dy))
+ return FALSE;
+
+ if (!FrameReached(&player->move_delay, MoveSpeed) && !tape.playing)
+ return FALSE;
+
+ if (player->MovPos)
+ {
+ /* should only happen if pre-1.2 tape recordings are played */
+ /* this is only for backward compatibility */
+
+ int old_move_speed = MoveSpeed;
+
+#if DEBUG
+ printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
+#endif
+
+ /* scroll remaining steps with finest movement resolution */
+ MoveSpeed = 8;
+
+ while (player->MovPos)
+ {
+ ScrollFigure(player, SCROLL_GO_ON);
+ ScrollScreen(NULL, SCROLL_GO_ON);
+ FrameCounter++;
+ DrawAllPlayers();
+ BackToFront();
+ }
+
+ MoveSpeed = old_move_speed;
+ }
+
+ 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
+ player->last_move_dir = MV_NO_MOVING;
+
+ TestIfHeroHitsBadThing(jx, jy);
+
+ if (player->gone)
+ 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;
+
+ if (!player->active || player->gone || !player->MovPos)
+ return;
+
+ if (mode == SCROLL_INIT)
+ {
+ player->actual_frame_counter = FrameCounter;
+ player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
+
+ 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) * TILEX / MoveSpeed;
+ player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);