ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Tile[x][y] == EL_DIAMOND)
#define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \
- ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Tile[x][y]))
+ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_FOOD_DARK_YAMYAM(Tile[x][y]))
#define PACMAN_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Tile[x][y]))
static void ExecuteCustomElementAction(int, int, int, int);
static boolean ChangeElement(int, int, int, int);
-static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
+static boolean CheckTriggeredElementChangeExt(int, int, int, int, int, int, int);
#define CheckTriggeredElementChange(x, y, e, ev) \
- CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY,CH_SIDE_ANY, -1)
+ CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1)
#define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s) \
CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1)
#define CheckTriggeredElementChangeBySide(x, y, e, ev, s) \
int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
int fade_mask = REDRAW_FIELD;
-
+ boolean restarting = (game_status == GAME_MODE_PLAYING);
boolean emulate_bd = TRUE; // unless non-BOULDERDASH elements found
boolean emulate_sp = TRUE; // unless non-SUPAPLEX elements found
int initial_move_dir = MV_DOWN;
if (!game.restart_level)
CloseDoor(DOOR_CLOSE_1);
- SetGameStatus(GAME_MODE_PLAYING);
+ if (restarting)
+ {
+ // force fading out global animations displayed during game play
+ SetGameStatus(GAME_MODE_PSEUDO_RESTARTING);
+ }
+ else
+ {
+ SetGameStatus(GAME_MODE_PLAYING);
+ }
if (level_editor_test_game)
FadeSkipNextFadeOut();
FadeOut(fade_mask);
+ if (restarting)
+ {
+ // force restarting global animations displayed during game play
+ RestartGlobalAnimsByStatus(GAME_MODE_PSEUDO_RESTARTING);
+
+ SetGameStatus(GAME_MODE_PLAYING);
+ }
+
if (level_editor_test_game)
FadeSkipNextFadeIn();
}
game.restart_level = FALSE;
- game.restart_game_message = NULL;
game.request_active = FALSE;
game.request_active_or_moving = FALSE;
void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
{
- int oldx = x, oldy = y;
int direction = MovDir[x][y];
-
- if (direction == MV_LEFT)
- oldx++;
- else if (direction == MV_RIGHT)
- oldx--;
- else if (direction == MV_UP)
- oldy++;
- else if (direction == MV_DOWN)
- oldy--;
+ int oldx = x + (direction & MV_LEFT ? +1 : direction & MV_RIGHT ? -1 : 0);
+ int oldy = y + (direction & MV_UP ? +1 : direction & MV_DOWN ? -1 : 0);
*comes_from_x = oldx;
*comes_from_y = oldy;
int oldx, oldy;
Blocked2Moving(x, y, &oldx, &oldy);
+
return Tile[oldx][oldy];
}
- else
- return element;
+
+ return element;
}
static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
{
// like MovingOrBlocked2Element(), but if element is moving
- // and (x,y) is the field the moving element is just leaving,
+ // and (x, y) is the field the moving element is just leaving,
// return EL_BLOCKED instead of the element value
int element = Tile[x][y];
int last_phase;
int border_element;
- // !!! eliminate this variable !!!
- int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
-
if (game.explosions_delayed)
{
ExplodeField[ex][ey] = mode;
if (phase == EX_PHASE_START) // initialize 'Store[][]' field
{
int center_element = Tile[ex][ey];
+ int ce_value = CustomValue[ex][ey];
+ int ce_score = element_info[center_element].collect_score;
int artwork_element, explosion_element; // set these values later
// remove things displayed in background while burning dynamite
else
Store[x][y] = EL_EMPTY;
+ if (IS_CUSTOM_ELEMENT(center_element))
+ Store[x][y] = (Store[x][y] == EL_CURRENT_CE_VALUE ? ce_value :
+ Store[x][y] == EL_CURRENT_CE_SCORE ? ce_score :
+ Store[x][y] >= EL_PREV_CE_8 &&
+ Store[x][y] <= EL_NEXT_CE_8 ?
+ RESOLVED_REFERENCE_ELEMENT(center_element, Store[x][y]) :
+ Store[x][y]);
+
if (x != ex || y != ey || mode == EX_TYPE_BORDER ||
center_element == EL_AMOEBA_TO_DIAMOND)
Store2[x][y] = element;
int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
int frame = getGraphicAnimationFrameXY(graphic, x, y);
- if (phase == delay)
+ if (phase == 1)
TEST_DrawLevelFieldCrumbled(x, y);
if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY)
boolean can_turn_left =
CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
boolean can_turn_right =
- CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
+ CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y);
if (element_info[element].move_stepsize == 0) // "not moving"
return;
PlayLevelSound(newx, newy, SND_PENGUIN_PASSING);
if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
- DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
+ DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2img(element), 0);
game.friends_still_needed--;
if (!game.friends_still_needed &&
}
else if (IS_FOOD_PENGUIN(Tile[newx][newy]))
{
- if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING)
+ if (DigField(local_player, x, y, newx, newy, 0, 0, DF_DIG) == MP_MOVING)
TEST_DrawLevelField(newx, newy);
else
GfxDir[x][y] = MovDir[x][y] = MV_NONE;
if (pushed_by_player) // special case: moving object pushed by player
{
- MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
+ MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x, y)->MovPos));
}
else if (use_step_delay) // special case: moving object has step delay
{
CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
player->index_bit, push_side);
- CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X,
+ CheckTriggeredElementChangeByPlayer(newx, newy, element, CE_PLAYER_PUSHES_X,
player->index_bit, push_side);
}
TapeRecordAction(tape_action);
// remember if game was played (especially after tape stopped playing)
- if (!tape.playing && summarized_player_action)
+ if (!tape.playing && summarized_player_action && !checkGameFailed())
game.GamePlayed = TRUE;
#if USE_NEW_PLAYER_ASSIGNMENTS
element == EL_DIAGONAL_SHRINKING ||
element == EL_DIAGONAL_GROWING)
{
- graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]);
+ graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y], GfxDir[x][y]);
DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
}
y = RND(lev_fieldy);
element = Tile[x][y];
- if (!IS_PLAYER(x,y) &&
+ if (!IS_PLAYER(x, y) &&
(element == EL_EMPTY ||
CAN_GROW_INTO(element) ||
element == EL_QUICKSAND_EMPTY ||
!AllPlayersInSight(player, new_jx, new_jy))
return MP_NO_ACTION;
- can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
+ can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx, real_dy, DF_DIG);
if (can_move != MP_MOVING)
return can_move;
CE_PLAYER_LEAVES_X,
player->index_bit, leave_side);
- if (IS_CUSTOM_ELEMENT(new_element))
- CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
- player->index_bit, enter_side);
+ // needed because pushed element has not yet reached its destination,
+ // so it would trigger a change event at its previous field location
+ if (!player->is_pushing)
+ {
+ if (IS_CUSTOM_ELEMENT(new_element))
+ CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
+ player->index_bit, enter_side);
- CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
- CE_PLAYER_ENTERS_X,
- player->index_bit, enter_side);
+ CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
+ CE_PLAYER_ENTERS_X,
+ player->index_bit, enter_side);
+ }
CheckTriggeredElementChangeBySide(jx, jy, player->initial_element,
CE_MOVE_OF_X, move_direction);
TestIfPlayerTouchesBadThing(jx, jy);
TestIfPlayerTouchesCustomElement(jx, jy);
- /* needed because pushed element has not yet reached its destination,
- so it would trigger a change event at its previous field location */
+ // needed because pushed element has not yet reached its destination,
+ // so it would trigger a change event at its previous field location
if (!player->is_pushing)
TestIfElementTouchesCustomElement(jx, jy); // for empty space
player->killed = TRUE;
// remove accessible field at the player's position
- Tile[jx][jy] = EL_EMPTY;
+ RemoveField(jx, jy);
// deactivate shield (else Bang()/Explode() would not work right)
player->shield_normal_time_left = 0;
return;
PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING);
- PlayLevelSound(jx, jy, SND_GAME_LOSING);
RemovePlayer(player);
if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
return MP_NO_ACTION; // field has no opening in this direction
- if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
+ if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element, opposite_direction))
return MP_NO_ACTION; // field has no opening in this direction
if (player_can_move && element == EL_ACID && move_direction == MV_DOWN)
LevelSolved();
- PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
+ PlaySound(SND_GAME_SOKOBAN_SOLVING);
}
}
else
static int getLevelMusicNr(void)
{
+ int level_pos = level_nr - leveldir_current->first_level;
+
if (levelset.music[level_nr] != MUS_UNDEFINED)
return levelset.music[level_nr]; // from config file
else
- return MAP_NOCONF_MUSIC(level_nr); // from music dir
+ return MAP_NOCONF_MUSIC(level_pos); // from music dir
}
static void FadeLevelSounds(void)
"Do you really want to quit the game?");
}
-void RequestRestartGame(char *message)
+static char *getRestartGameMessage(void)
{
- game.restart_game_message = NULL;
+ boolean play_again = hasStartedNetworkGame();
+ static char message[MAX_OUTPUT_LINESIZE];
+ char *game_over_text = "Game over!";
+ char *play_again_text = " Play it again?";
+
+ if (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
+ game_mm.game_over_message != NULL)
+ game_over_text = game_mm.game_over_message;
+
+ snprintf(message, MAX_OUTPUT_LINESIZE, "%s%s", game_over_text,
+ (play_again ? play_again_text : ""));
+
+ return message;
+}
+static void RequestRestartGame(void)
+{
+ char *message = getRestartGameMessage();
boolean has_started_game = hasStartedNetworkGame();
int request_mode = (has_started_game ? REQ_ASK : REQ_CONFIRM);
+ int door_state = DOOR_CLOSE_1;
- if (Request(message, request_mode | REQ_STAY_CLOSED) && has_started_game)
+ if (Request(message, request_mode | REQ_STAY_OPEN) && has_started_game)
{
+ CloseDoor(door_state);
+
StartGameActions(network.enabled, setup.autorecord, level.random_seed);
}
else
{
- // needed in case of envelope request to close game panel
- CloseDoor(DOOR_CLOSE_1);
+ // if game was invoked from level editor, also close tape recorder door
+ if (level_editor_test_game)
+ door_state = DOOR_CLOSE_ALL;
+
+ CloseDoor(door_state);
SetGameStatus(GAME_MODE_MAIN);
}
}
-void CheckGameOver(void)
+boolean CheckRestartGame(void)
{
- static boolean last_game_over = FALSE;
static int game_over_delay = 0;
int game_over_delay_value = 50;
boolean game_over = checkGameFailed();
- // do not handle game over if request dialog is already active
- 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;
game_over_delay = game_over_delay_value;
- return;
+ return FALSE;
}
if (game_over_delay > 0)
{
+ if (game_over_delay == game_over_delay_value / 2)
+ PlaySound(SND_GAME_LOSING);
+
game_over_delay--;
- return;
+ return FALSE;
}
- if (last_game_over != game_over)
- game.restart_game_message = (hasStartedNetworkGame() ?
- "Game over! Play it again?" :
- "Game over!");
+ // do not handle game over if request dialog is already active
+ if (game.request_active)
+ return FALSE;
+
+ // do not ask to play again if game was never actually played
+ if (!game.GamePlayed)
+ return FALSE;
- last_game_over = game_over;
+ // do not ask to play again if this was disabled in setup menu
+ if (!setup.ask_on_game_over)
+ return FALSE;
+
+ RequestRestartGame();
+
+ return TRUE;
}
boolean checkGameSolved(void)