SetGameStatus(GAME_MODE_PLAYING);
if (level_editor_test_game)
- FadeSkipNextFadeIn();
+ FadeSkipNextFadeOut();
else
FadeSetEnterScreen();
- if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
+ if (CheckFadeAll())
fade_mask = REDRAW_ALL;
FadeLevelSoundsAndMusic();
FadeOut(fade_mask);
+ if (level_editor_test_game)
+ FadeSkipNextFadeIn();
+
// needed if different viewport properties defined for playing
ChangeViewportPropertiesIfNeeded();
player->action = 0;
player->effective_action = 0;
player->programmed_action = 0;
+ player->snap_action = 0;
player->mouse_action.lx = 0;
player->mouse_action.ly = 0;
if (network_playing)
SendToServer_MovePlayer(MV_NONE);
- ZX = ZY = -1;
-
FrameCounter = 0;
TimeFrames = 0;
TimePlayed = 0;
ScrollStepSize = 0; // will be correctly initialized by ScrollScreen()
+ game.robot_wheel_x = -1;
+ game.robot_wheel_y = -1;
+
game.exit_x = -1;
game.exit_y = -1;
game.LevelSolved = FALSE;
game.GameOver = FALSE;
+ game.GamePlayed = !tape.playing;
+
game.LevelSolved_GameWon = FALSE;
game.LevelSolved_GameEnd = FALSE;
game.LevelSolved_SaveTape = FALSE;
game.belt_dir_nr[i] = 3; // not moving, next moving left
#if USE_NEW_PLAYER_ASSIGNMENTS
+ // use preferred player also in local single-player mode
+ if (!network.enabled && !game.team_mode)
+ {
+ int old_index_nr = local_player->index_nr;
+ int new_index_nr = setup.network_player_nr;
+
+ if (new_index_nr >= 0 && new_index_nr < MAX_PLAYERS)
+ {
+ stored_player[old_index_nr].connected_locally = FALSE;
+ stored_player[new_index_nr].connected_locally = TRUE;
+ }
+ }
+
for (i = 0; i < MAX_PLAYERS; i++)
{
stored_player[i].connected = FALSE;
int i;
// do not start end game actions before the player stops moving (to exit)
- if (local_player->MovPos)
+ if (local_player->active && local_player->MovPos)
return;
game.LevelSolved_GameWon = TRUE;
while (scroll_x != new_scroll_x || scroll_y != new_scroll_y)
{
- int dx = 0, dy = 0;
- int fx = FX, fy = FY;
-
- dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0);
- dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0);
+ int dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0);
+ int dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0);
if (dx == 0 && dy == 0) // no scrolling needed at all
break;
scroll_x -= dx;
scroll_y -= dy;
- fx += dx * TILEX / 2;
- fy += dy * TILEY / 2;
+ // set values for horizontal/vertical screen scrolling (half tile size)
+ int dir_x = (dx != 0 ? MV_HORIZONTAL : 0);
+ int dir_y = (dy != 0 ? MV_VERTICAL : 0);
+ int pos_x = dx * TILEX / 2;
+ int pos_y = dy * TILEY / 2;
+ int fx = getFieldbufferOffsetX_RND(dir_x, pos_x);
+ int fy = getFieldbufferOffsetY_RND(dir_y, pos_y);
ScrollLevel(dx, dy);
DrawAllPlayers();
// scroll in two steps of half tile size to make things smoother
- BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+ BlitScreenToBitmapExt_RND(window, fx, fy);
// scroll second step to align at full tile size
BlitScreenToBitmap(window);
}
}
- if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 &&
- (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE ||
+ if (element == EL_ROBOT &&
+ game.robot_wheel_x >= 0 &&
+ game.robot_wheel_y >= 0 &&
+ (Feld[game.robot_wheel_x][game.robot_wheel_y] == EL_ROBOT_WHEEL_ACTIVE ||
game.engine_version < VERSION_IDENT(3,1,0,0)))
{
- attr_x = ZX;
- attr_y = ZY;
+ attr_x = game.robot_wheel_x;
+ attr_y = game.robot_wheel_y;
}
if (element == EL_PENGUIN)
static void StopRobotWheel(int x, int y)
{
- if (ZX == x && ZY == y)
+ if (game.robot_wheel_x == x &&
+ game.robot_wheel_y == y)
{
- ZX = ZY = -1;
-
+ game.robot_wheel_x = -1;
+ game.robot_wheel_y = -1;
game.robot_wheel_active = FALSE;
}
}
if (!player->is_moving &&
!player->is_pushing &&
!player->is_dropping_pressed)
- {
TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
- SnapField(player, 0, 0); // stop snapping
- }
}
CheckSaveEngineSnapshot(player);
SetVideoFrameDelay(game_frame_delay_value);
+ // (de)activate virtual buttons depending on current game status
+ if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
+ {
+ if (game.all_players_gone) // if no players there to be controlled anymore
+ SetOverlayActive(FALSE);
+ else if (!tape.playing) // if game continues after tape stopped playing
+ SetOverlayActive(TRUE);
+ }
+
#if 0
#if 0
// ---------- main game synchronization point ----------
stored_player[map_player_action[local_player->index_nr]].effective_action =
summarized_player_action;
+ // summarize all actions at centered player in local team mode
if (tape.recording &&
- setup.team_mode &&
+ setup.team_mode && !network.enabled &&
setup.input_on_focus &&
game.centered_player_nr != -1)
{
for (i = 0; i < MAX_PLAYERS; i++)
- stored_player[i].effective_action =
+ stored_player[map_player_action[i]].effective_action =
(i == game.centered_player_nr ? summarized_player_action : 0);
}
if (tape.recording)
TapeRecordAction(tape_action);
+ // remember if game was played (especially after tape stopped playing)
+ if (!tape.playing && summarized_player_action)
+ game.GamePlayed = TRUE;
+
#if USE_NEW_PLAYER_ASSIGNMENTS
// !!! also map player actions in single player mode !!!
// if (game.team_mode)
element == EL_DC_MAGIC_WALL_FULL ||
element == EL_DC_MAGIC_WALL_ACTIVE ||
element == EL_DC_MAGIC_WALL_EMPTYING) &&
- ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy))
+ ABS(x - jx) + ABS(y - jy) <
+ ABS(magic_wall_x - jx) + ABS(magic_wall_y - jy))
{
magic_wall_x = x;
magic_wall_y = y;
DrawAllPlayers();
PlayAllPlayersSound();
- if (local_player->show_envelope != 0 && local_player->MovPos == 0)
+ for (i = 0; i < MAX_PLAYERS; i++)
{
- ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1);
+ struct PlayerInfo *player = &stored_player[i];
- local_player->show_envelope = 0;
+ if (player->show_envelope != 0 && (!player->active ||
+ player->MovPos == 0))
+ {
+ ShowEnvelope(player->show_envelope - EL_ENVELOPE_1);
+
+ player->show_envelope = 0;
+ }
}
// use random number generator in every frame to make it less predictable
game.centered_player_nr == -1))
{
int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
- int offset = game.scroll_delay_value;
if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
{
}
else
{
+ int offset_raw = game.scroll_delay_value;
+
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);
+ int offset = MIN(offset_raw, (SCR_FIELDX - 2) / 2);
+ int offset_x = offset * (player->MovDir == MV_LEFT ? +1 : -1);
+ int new_scroll_x = jx - MIDPOSX + offset_x;
+
+ if ((player->MovDir == MV_LEFT && scroll_x > new_scroll_x) ||
+ (player->MovDir == MV_RIGHT && scroll_x < new_scroll_x))
+ scroll_x = new_scroll_x;
// 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);
+ scroll_x = MIN(MAX(SBX_Left, scroll_x), SBX_Right);
// don't scroll more than one field at a time
scroll_x = old_scroll_x + SIGN(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);
+ int offset = MIN(offset_raw, (SCR_FIELDY - 2) / 2);
+ int offset_y = offset * (player->MovDir == MV_UP ? +1 : -1);
+ int new_scroll_y = jy - MIDPOSY + offset_y;
+
+ if ((player->MovDir == MV_UP && scroll_y > new_scroll_y) ||
+ (player->MovDir == MV_DOWN && scroll_y < new_scroll_y))
+ scroll_y = new_scroll_y;
// 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);
+ scroll_y = MIN(MAX(SBY_Upper, scroll_y), SBY_Lower);
// don't scroll more than one field at a time
scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
player->present = FALSE;
player->active = FALSE;
+ // required for some CE actions (even if the player is not active anymore)
+ player->MovPos = 0;
+
if (!ExplodeField[jx][jy])
StorePlayer[jx][jy] = 0;
game.GameOver = TRUE;
}
- game.exit_x = ZX = jx;
- game.exit_y = ZY = jy;
+ game.exit_x = game.robot_wheel_x = jx;
+ game.exit_y = game.robot_wheel_y = jy;
}
void ExitPlayer(struct PlayerInfo *player)
if (element == EL_ROBOT_WHEEL)
{
Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
- ZX = x;
- ZY = y;
+ game.robot_wheel_x = x;
+ game.robot_wheel_y = y;
game.robot_wheel_active = TRUE;
TEST_DrawLevelField(x, y);
{
// closing door required in case of envelope style request dialogs
if (!skip_request)
+ {
+ // prevent short reactivation of overlay buttons while closing door
+ SetOverlayActive(FALSE);
+
CloseDoor(DOOR_CLOSE_1);
+ }
if (network.enabled)
SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER);
if (game.request_active)
return;
+ // do not ask to play again if game was never actually played
+ if (!game.GamePlayed)
+ return;
+
if (!game_over)
{
last_game_over = FALSE;
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(game));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(tape));
- SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZX));
- SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZY));
-
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(FrameCounter));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed));
for (i = 0; i < NUM_GAME_BUTTONS; i++)
if (!on_tape || gamebutton_info[i].allowed_on_tape)
RedrawGadget(game_gadget[i]);
-
- // RedrawGadget() may have set REDRAW_ALL if buttons are defined off-area
- redraw_mask &= ~REDRAW_ALL;
}
static void SetGadgetState(struct GadgetInfo *gi, boolean state)