static void KillPlayerUnlessEnemyProtected(int, int);
static void KillPlayerUnlessExplosionProtected(int, int);
+static void CheckNextToConditions(int, int);
+static void TestIfPlayerNextToCustomElement(int, int);
static void TestIfPlayerTouchesCustomElement(int, int);
+static void TestIfElementNextToCustomElement(int, int);
static void TestIfElementTouchesCustomElement(int, int);
static void TestIfElementHitsCustomElement(int, int, int);
void Bang(int, int);
void InitMovDir(int, int);
void InitAmoebaNr(int, int);
-int NewHighScore(int);
+void NewHighScore(int, boolean);
void TestIfGoodThingHitsBadThing(int, int, int);
void TestIfBadThingHitsGoodThing(int, int, int);
break;
case EL_STONEBLOCK:
- if (x < lev_fieldx-1 && Tile[x+1][y] == EL_ACID)
+ if (x < lev_fieldx - 1 && Tile[x + 1][y] == EL_ACID)
Tile[x][y] = EL_ACID_POOL_TOPLEFT;
- else if (x > 0 && Tile[x-1][y] == EL_ACID)
+ else if (x > 0 && Tile[x - 1][y] == EL_ACID)
Tile[x][y] = EL_ACID_POOL_TOPRIGHT;
- else if (y > 0 && Tile[x][y-1] == EL_ACID_POOL_TOPLEFT)
+ else if (y > 0 && Tile[x][y - 1] == EL_ACID_POOL_TOPLEFT)
Tile[x][y] = EL_ACID_POOL_BOTTOMLEFT;
- else if (y > 0 && Tile[x][y-1] == EL_ACID)
+ else if (y > 0 && Tile[x][y - 1] == EL_ACID)
Tile[x][y] = EL_ACID_POOL_BOTTOM;
- else if (y > 0 && Tile[x][y-1] == EL_ACID_POOL_TOPRIGHT)
+ else if (y > 0 && Tile[x][y - 1] == EL_ACID_POOL_TOPRIGHT)
Tile[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
break;
InitField(x, y, init_game);
}
+ else if (IS_EMPTY_ELEMENT(element))
+ {
+ GfxElementEmpty[x][y] = element;
+ Tile[x][y] = EL_EMPTY;
+
+ if (element_info[element].use_gfx_element)
+ game.use_masked_elements = TRUE;
+ }
break;
}
if (type == TYPE_INTEGER)
{
if (nr == GAME_PANEL_LEVEL_NUMBER ||
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_SCORE ||
+ nr == GAME_PANEL_HIGHSCORE ||
nr == GAME_PANEL_TIME)
{
boolean use_dynamic_size = (size == -1 ? TRUE : FALSE);
if (use_dynamic_size) // use dynamic number of digits
{
- int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000);
- int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3);
- int size2 = size1 + 1;
+ int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 :
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_TIME ? 1000 : 100000);
+ int size_add = (nr == GAME_PANEL_LEVEL_NUMBER ||
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_TIME ? 1 : 2);
+ int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 :
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_TIME ? 3 : 5);
+ int size2 = size1 + size_add;
int font1 = pos->font;
int font2 = pos->font_alt;
int fade_mask = REDRAW_FIELD;
boolean emulate_bd = TRUE; // unless non-BOULDERDASH elements found
- boolean emulate_sb = TRUE; // unless non-SOKOBAN elements found
boolean emulate_sp = TRUE; // unless non-SUPAPLEX elements found
int initial_move_dir = MV_DOWN;
int i, j, x, y;
game.envelope_active = FALSE;
+ // special case: set custom artwork setting to initial value
+ game.use_masked_elements = game.use_masked_elements_initial;
+
for (i = 0; i < NUM_BELTS; i++)
{
game.belt_dir[i] = MV_NONE;
GfxFrame[x][y] = 0;
GfxRandom[x][y] = INIT_GFX_RANDOM();
+ GfxRandomStatic[x][y] = INIT_GFX_RANDOM();
GfxElement[x][y] = EL_UNDEFINED;
+ GfxElementEmpty[x][y] = EL_EMPTY;
GfxAction[x][y] = ACTION_DEFAULT;
GfxDir[x][y] = MV_NONE;
GfxRedraw[x][y] = GFX_REDRAW_NONE;
{
if (emulate_bd && !IS_BD_ELEMENT(Tile[x][y]))
emulate_bd = FALSE;
- if (emulate_sb && !IS_SB_ELEMENT(Tile[x][y]))
- emulate_sb = FALSE;
if (emulate_sp && !IS_SP_ELEMENT(Tile[x][y]))
emulate_sp = FALSE;
}
game.emulation = (emulate_bd ? EMU_BOULDERDASH :
- emulate_sb ? EMU_SOKOBAN :
emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
// initialize type of slippery elements
{
// check for player created from custom element as single target
content = element_info[element].change_page[i].target_element;
- is_player = ELEM_IS_PLAYER(content);
+ is_player = IS_PLAYER_ELEMENT(content);
if (is_player && (found_rating < 3 ||
(found_rating == 3 && element < found_element)))
{
// check for player created from custom element as explosion content
content = element_info[element].content.e[xx][yy];
- is_player = ELEM_IS_PLAYER(content);
+ is_player = IS_PLAYER_ELEMENT(content);
if (is_player && (found_rating < 2 ||
(found_rating == 2 && element < found_element)))
content =
element_info[element].change_page[i].target_content.e[xx][yy];
- is_player = ELEM_IS_PLAYER(content);
+ is_player = IS_PLAYER_ELEMENT(content);
if (is_player && (found_rating < 1 ||
(found_rating == 1 && element < found_element)))
if (setup.sound_music)
PlayLevelMusic();
}
+
+ SetPlayfieldMouseCursorEnabled(!game.use_mouse_actions);
}
void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y,
AmoebaCnt2[group_nr]++;
}
+static void LevelSolved_SetFinalGameValues(void)
+{
+ game.time_final = (game.no_time_limit ? TimePlayed : TimeLeft);
+ game.score_time_final = (level.use_step_counter ? TimePlayed :
+ TimePlayed * FRAMES_PER_SECOND + TimeFrames);
+
+ game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
+ game_em.lev->score :
+ level.game_engine_type == GAME_ENGINE_TYPE_MM ?
+ game_mm.score :
+ game.score);
+
+ game.health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
+ MM_HEALTH(game_mm.laser_overload_value) :
+ game.health);
+
+ game.LevelSolved_CountingTime = game.time_final;
+ game.LevelSolved_CountingScore = game.score_final;
+ game.LevelSolved_CountingHealth = game.health_final;
+}
+
+static void LevelSolved_DisplayFinalGameValues(int time, int score, int health)
+{
+ game.LevelSolved_CountingTime = time;
+ game.LevelSolved_CountingScore = score;
+ game.LevelSolved_CountingHealth = health;
+
+ game_panel_controls[GAME_PANEL_TIME].value = time;
+ game_panel_controls[GAME_PANEL_SCORE].value = score;
+ game_panel_controls[GAME_PANEL_HEALTH].value = health;
+
+ DisplayGameControlValues();
+}
+
static void LevelSolved(void)
{
if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
game.LevelSolved = TRUE;
game.GameOver = TRUE;
+
+ // needed here to display correct panel values while player walks into exit
+ LevelSolved_SetFinalGameValues();
}
void GameWon(void)
if (local_player->active && local_player->MovPos)
return;
- game.time_final = (game.no_time_limit ? TimePlayed : TimeLeft);
- game.score_time_final = (level.use_step_counter ? TimePlayed :
- TimePlayed * FRAMES_PER_SECOND + TimeFrames);
-
- game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
- game_em.lev->score :
- level.game_engine_type == GAME_ENGINE_TYPE_MM ?
- game_mm.score :
- game.score);
-
- game.health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
- MM_HEALTH(game_mm.laser_overload_value) :
- game.health);
-
- game.LevelSolved_CountingTime = game.time_final;
- game.LevelSolved_CountingScore = game.score_final;
- game.LevelSolved_CountingHealth = game.health_final;
+ // calculate final game values after player finished walking into exit
+ LevelSolved_SetFinalGameValues();
game.LevelSolved_GameWon = TRUE;
game.LevelSolved_SaveTape = tape.recording;
score = score_final = game.score_final;
health = health_final = game.health_final;
+ // update game panel values before (delayed) counting of score (if any)
+ LevelSolved_DisplayFinalGameValues(time, score, health);
+
+ // if level has time score defined, calculate new final game values
if (time_score > 0)
{
int time_final_max = 999;
game.health_final = health_final;
}
+ // if not counting score after game, immediately update game panel values
if (level_editor_test_game || !setup.count_score_after_game)
{
time = time_final;
score = score_final;
- game.LevelSolved_CountingTime = time;
- game.LevelSolved_CountingScore = score;
-
- game_panel_controls[GAME_PANEL_TIME].value = time;
- game_panel_controls[GAME_PANEL_SCORE].value = score;
-
- DisplayGameControlValues();
+ LevelSolved_DisplayFinalGameValues(time, score, health);
}
if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
if (time == time_final)
score = score_final;
- game.LevelSolved_CountingTime = time;
- game.LevelSolved_CountingScore = score;
-
- game_panel_controls[GAME_PANEL_TIME].value = time;
- game_panel_controls[GAME_PANEL_SCORE].value = score;
-
- DisplayGameControlValues();
+ LevelSolved_DisplayFinalGameValues(time, score, health);
if (time == time_final)
StopSound(SND_GAME_LEVELTIME_BONUS);
health += health_count_dir;
score += time_score;
- game.LevelSolved_CountingHealth = health;
- game.LevelSolved_CountingScore = score;
-
- game_panel_controls[GAME_PANEL_HEALTH].value = health;
- game_panel_controls[GAME_PANEL_SCORE].value = score;
-
- DisplayGameControlValues();
+ LevelSolved_DisplayFinalGameValues(time, score, health);
if (health == health_final)
StopSound(SND_GAME_LEVELTIME_BONUS);
{
// used instead of "level_nr" (needed for network games)
int last_level_nr = levelset.level_nr;
- int highlight_position;
+ boolean tape_saved = FALSE;
game.LevelSolved_GameEnd = TRUE;
- if (game.LevelSolved_SaveTape)
+ if (game.LevelSolved_SaveTape && !score_info_tape_play)
{
// make sure that request dialog to save tape does not open door again
if (!global.use_envelope_request)
CloseDoor(DOOR_CLOSE_1);
- SaveTapeChecked_LevelSolved(tape.level_nr); // ask to save tape
+ // ask to save tape
+ tape_saved = SaveTapeChecked_LevelSolved(tape.level_nr);
// set unique basename for score tape (also saved in high score table)
strcpy(tape.score_tape_basename, getScoreTapeBasename(setup.player_name));
// if no tape is to be saved, close both doors simultaneously
CloseDoor(DOOR_CLOSE_ALL);
- if (level_editor_test_game)
+ if (level_editor_test_game || score_info_tape_play)
{
SetGameStatus(GAME_MODE_MAIN);
SaveLevelSetup_SeriesInfo();
}
+ // save score and score tape before potentially erasing tape below
+ NewHighScore(last_level_nr, tape_saved);
+
if (setup.increment_levels &&
level_nr < leveldir_current->last_level &&
!network_playing)
if (setup.auto_play_next_level)
{
+ scores.continue_playing = TRUE;
+ scores.next_level_nr = level_nr;
+
LoadLevel(level_nr);
SaveLevelSetup_SeriesInfo();
}
}
- highlight_position = NewHighScore(last_level_nr);
-
- if (highlight_position >= 0 && setup.show_scores_after_game)
+ if (scores.last_added >= 0 && setup.show_scores_after_game)
{
SetGameStatus(GAME_MODE_SCORES);
- DrawHallOfFame(last_level_nr, highlight_position);
+ DrawHallOfFame(last_level_nr);
}
- else if (setup.auto_play_next_level && setup.increment_levels &&
- last_level_nr < leveldir_current->last_level &&
- !network_playing)
+ else if (scores.continue_playing)
{
StartGameActions(network.enabled, setup.autorecord, level.random_seed);
}
}
}
-static int addScoreEntry(struct ScoreInfo *list, struct ScoreEntry *new_entry)
+static int addScoreEntry(struct ScoreInfo *list, struct ScoreEntry *new_entry,
+ boolean one_score_entry_per_name)
{
- boolean one_score_entry_per_name = !program.many_scores_per_name;
int i;
- if (strEqual(setup.player_name, EMPTY_PLAYER_NAME))
+ if (strEqual(new_entry->name, EMPTY_PLAYER_NAME))
return -1;
for (i = 0; i < MAX_SCORE_ENTRIES; i++)
boolean entry_is_empty = (entry->score == 0 &&
entry->time == 0);
+ // prevent adding server score entries if also existing in local score file
+ // (special case: historic score entries have an empty tape basename entry)
+ if (strEqual(new_entry->tape_basename, entry->tape_basename) &&
+ !strEqual(new_entry->tape_basename, UNDEFINED_FILENAME))
+ {
+ // special case: use server score instead of local score value if higher
+ // (historic scores might have been truncated to 16-bit values locally)
+ if (score_is_better)
+ entry->score = new_entry->score;
+
+ return -1;
+ }
+
if (is_better || entry_is_empty)
{
// player has made it to the hall of fame
if (one_score_entry_per_name)
{
for (l = i; l < MAX_SCORE_ENTRIES; l++)
- if (strEqual(list->entry[l].name, setup.player_name))
+ if (strEqual(list->entry[l].name, new_entry->name))
m = l;
if (m == i) // player's new highscore overwrites his old one
return i;
}
else if (one_score_entry_per_name &&
- strEqual(entry->name, setup.player_name))
+ strEqual(entry->name, new_entry->name))
{
// player already in high score list with better score or time
}
}
- return -1;
+ // special case: new score is beyond the last high score list position
+ return MAX_SCORE_ENTRIES;
}
-int NewHighScore(int level_nr)
+void NewHighScore(int level_nr, boolean tape_saved)
{
struct ScoreEntry new_entry = {{ 0 }}; // (prevent warning from GCC bug 53119)
+ boolean one_per_name = FALSE;
strncpy(new_entry.tape_basename, tape.score_tape_basename, MAX_FILENAME_LEN);
strncpy(new_entry.name, setup.player_name, MAX_PLAYER_NAME_LEN);
LoadScore(level_nr);
- int position = addScoreEntry(&scores, &new_entry);
+ scores.last_added = addScoreEntry(&scores, &new_entry, one_per_name);
+
+ if (scores.last_added >= MAX_SCORE_ENTRIES)
+ {
+ scores.last_added = MAX_SCORE_ENTRIES - 1;
+ scores.force_last_added = TRUE;
+
+ scores.entry[scores.last_added] = new_entry;
+
+ // store last added local score entry (before merging server scores)
+ scores.last_added_local = scores.last_added;
+
+ return;
+ }
+
+ if (scores.last_added < 0)
+ return;
+
+ SaveScore(level_nr);
+
+ // store last added local score entry (before merging server scores)
+ scores.last_added_local = scores.last_added;
+
+ if (!game.LevelSolved_SaveTape)
+ return;
+
+ SaveScoreTape(level_nr);
- if (position >= 0)
+ if (setup.ask_for_using_api_server)
{
- SaveScore(level_nr);
+ setup.use_api_server =
+ Request("Upload your score and tape to the high score server?", REQ_ASK);
- if (game.LevelSolved_SaveTape)
- SaveScoreTape(level_nr);
+ if (!setup.use_api_server)
+ Request("Not using high score server! Use setup menu to enable again!",
+ REQ_CONFIRM);
+
+ runtime.use_api_server = setup.use_api_server;
+
+ // after asking for using API server once, do not ask again
+ setup.ask_for_using_api_server = FALSE;
+
+ SaveSetup_ServerSetup();
}
- return position;
+ SaveServerScore(level_nr, tape_saved);
+}
+
+void MergeServerScore(void)
+{
+ struct ScoreEntry last_added_entry;
+ boolean one_per_name = FALSE;
+ int i;
+
+ if (scores.last_added >= 0)
+ last_added_entry = scores.entry[scores.last_added];
+
+ for (i = 0; i < server_scores.num_entries; i++)
+ {
+ int pos = addScoreEntry(&scores, &server_scores.entry[i], one_per_name);
+
+ if (pos >= 0 && pos <= scores.last_added)
+ scores.last_added++;
+ }
+
+ if (scores.last_added >= MAX_SCORE_ENTRIES)
+ {
+ scores.last_added = MAX_SCORE_ENTRIES - 1;
+ scores.force_last_added = TRUE;
+
+ scores.entry[scores.last_added] = last_added_entry;
+ }
}
static int getElementMoveStepsizeExt(int x, int y, int direction)
else if (game.use_masked_elements)
DrawLevelElement(x, y, EL_EMPTY);
- frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+ frame = getGraphicAnimationFrameXY(graphic, x, y);
if (Back[x][y] || Store[x][y] || game.use_masked_elements)
DrawGraphicThruMask(sx, sy, graphic, frame);
possible that the relocation target field did not contain a player element,
but a walkable element, to which the new player was relocated -- in this
case, restore that (already initialized!) element on the player field */
- if (!ELEM_IS_PLAYER(element)) // player may be set on walkable element
+ if (!IS_PLAYER_ELEMENT(element)) // player may be set on walkable element
{
Tile[jx][jy] = element; // restore previously existing element
}
// !!! check this case -- currently needed for rnd_rado_negundo_v,
// !!! levels 015 018 019 020 021 022 023 026 027 028 !!!
- else if (ELEM_IS_PLAYER(center_element))
+ else if (IS_PLAYER_ELEMENT(center_element))
Store[x][y] = EL_EMPTY;
else if (center_element == EL_YAMYAM)
Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
return;
}
+ // this can happen if the player was just killed by an explosion
+ if (GfxElement[x][y] == EL_UNDEFINED)
+ GfxElement[x][y] = EL_EMPTY;
+
if (phase == last_phase)
{
int element;
if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
StorePlayer[x][y] = 0;
- if (ELEM_IS_PLAYER(element))
+ if (IS_PLAYER_ELEMENT(element))
RelocatePlayer(x, y, element);
}
else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
- int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+ int frame = getGraphicAnimationFrameXY(graphic, x, y);
if (phase == delay)
TEST_DrawLevelFieldCrumbled(x, y);
}
else if (IS_WALKABLE_UNDER(Back[x][y]))
{
- DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ DrawLevelGraphic(x, y, graphic, frame);
DrawLevelElementThruMask(x, y, Back[x][y]);
}
else if (!IS_WALKABLE_INSIDE(Back[x][y]))
- DrawScreenGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ DrawLevelGraphic(x, y, graphic, frame);
}
}
dir == MV_RIGHT ? IMG_FLAMES_1_RIGHT :
dir == MV_UP ? IMG_FLAMES_1_UP :
dir == MV_DOWN ? IMG_FLAMES_1_DOWN : IMG_EMPTY);
- int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+ int frame = getGraphicAnimationFrameXY(graphic, x, y);
GfxAction[x][y] = ACTION_ATTACKING;
if (IN_SCR_FIELD(sx, sy))
{
TEST_DrawLevelFieldCrumbled(xx, yy);
- DrawGraphic(sx, sy, flame_graphic, frame);
+ DrawScreenGraphic(sx, sy, flame_graphic, frame);
}
}
else
GfxDir[x][y] = diagonal_move_dir;
ChangeDelay[x][y] = change_delay;
+ if (Store[x][y] == EL_EMPTY)
+ Store[x][y] = GfxElementEmpty[x][y];
+
graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],
GfxDir[x][y]);
if (GFX_CRUMBLED(Tile[x][y]))
TEST_DrawLevelFieldCrumbledNeighbours(x, y);
- if (ELEM_IS_PLAYER(move_leave_element))
+ if (IS_PLAYER_ELEMENT(move_leave_element))
RelocatePlayer(x, y, move_leave_element);
}
int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING,
6 - MovDelay[x][y]);
- DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame);
+ DrawLevelGraphic(x, y, IMG_AMOEBA_GROWING, frame);
}
if (!MovDelay[x][y])
int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
6 - MovDelay[x][y]);
- DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
+ DrawLevelGraphic(x, y, IMG_AMOEBA_SHRINKING, frame);
}
if (!MovDelay[x][y])
num_neighbours <= life_parameter[3])
{
Tile[xx][yy] = element;
- MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
+ MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time - 1);
if (Tile[xx][yy] != old_element)
TEST_DrawLevelField(xx, yy);
Stop[xx][yy] = TRUE;
int graphic = el_dir2img(Tile[x][y], GfxDir[x][y]);
int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
- DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ DrawLevelGraphic(x, y, graphic, frame);
}
if (!MovDelay[x][y])
return;
}
- if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
+ if (IN_LEV_FIELD(ax, ay - 1) && IS_FREE(ax, ay - 1))
oben_frei = TRUE;
- if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
+ if (IN_LEV_FIELD(ax, ay + 1) && IS_FREE(ax, ay + 1))
unten_frei = TRUE;
- if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
+ if (IN_LEV_FIELD(ax - 1, ay) && IS_FREE(ax - 1, ay))
links_frei = TRUE;
- if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
+ if (IN_LEV_FIELD(ax + 1, ay) && IS_FREE(ax + 1, ay))
rechts_frei = TRUE;
if (element == EL_EXPANDABLE_WALL_VERTICAL ||
{
if (oben_frei)
{
- Tile[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax][ay-1] = element;
- GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
- IMG_EXPANDABLE_WALL_GROWING_UP, 0);
+ Tile[ax][ay - 1] = EL_EXPANDABLE_WALL_GROWING;
+ Store[ax][ay - 1] = element;
+ GfxDir[ax][ay - 1] = MovDir[ax][ay - 1] = MV_UP;
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay - 1)))
+ DrawLevelGraphic(ax, ay - 1, IMG_EXPANDABLE_WALL_GROWING_UP, 0);
new_wall = TRUE;
}
if (unten_frei)
{
- Tile[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax][ay+1] = element;
- GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
- IMG_EXPANDABLE_WALL_GROWING_DOWN, 0);
+ Tile[ax][ay + 1] = EL_EXPANDABLE_WALL_GROWING;
+ Store[ax][ay + 1] = element;
+ GfxDir[ax][ay + 1] = MovDir[ax][ay + 1] = MV_DOWN;
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay + 1)))
+ DrawLevelGraphic(ax, ay + 1, IMG_EXPANDABLE_WALL_GROWING_DOWN, 0);
new_wall = TRUE;
}
}
{
if (links_frei)
{
- Tile[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax-1][ay] = element;
- GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
- if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
- IMG_EXPANDABLE_WALL_GROWING_LEFT, 0);
+ Tile[ax - 1][ay] = EL_EXPANDABLE_WALL_GROWING;
+ Store[ax - 1][ay] = element;
+ GfxDir[ax - 1][ay] = MovDir[ax - 1][ay] = MV_LEFT;
+ if (IN_SCR_FIELD(SCREENX(ax - 1), SCREENY(ay)))
+ DrawLevelGraphic(ax - 1, ay, IMG_EXPANDABLE_WALL_GROWING_LEFT, 0);
new_wall = TRUE;
}
if (rechts_frei)
{
- Tile[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax+1][ay] = element;
- GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
- if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
- IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0);
+ Tile[ax + 1][ay] = EL_EXPANDABLE_WALL_GROWING;
+ Store[ax + 1][ay] = element;
+ GfxDir[ax + 1][ay] = MovDir[ax + 1][ay] = MV_RIGHT;
+ if (IN_SCR_FIELD(SCREENX(ax + 1), SCREENY(ay)))
+ DrawLevelGraphic(ax + 1, ay, IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0);
new_wall = TRUE;
}
}
if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei))
TEST_DrawLevelField(ax, ay);
- if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Tile[ax][ay-1]))
+ if (!IN_LEV_FIELD(ax, ay - 1) || IS_WALL(Tile[ax][ay - 1]))
oben_massiv = TRUE;
- if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Tile[ax][ay+1]))
+ if (!IN_LEV_FIELD(ax, ay + 1) || IS_WALL(Tile[ax][ay + 1]))
unten_massiv = TRUE;
- if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Tile[ax-1][ay]))
+ if (!IN_LEV_FIELD(ax - 1, ay) || IS_WALL(Tile[ax - 1][ay]))
links_massiv = TRUE;
- if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Tile[ax+1][ay]))
+ if (!IN_LEV_FIELD(ax + 1, ay) || IS_WALL(Tile[ax + 1][ay]))
rechts_massiv = TRUE;
if (((oben_massiv && unten_massiv) ||
return;
}
- if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
+ if (IN_LEV_FIELD(ax, ay - 1) && IS_FREE(ax, ay - 1))
oben_frei = TRUE;
- if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
+ if (IN_LEV_FIELD(ax, ay + 1) && IS_FREE(ax, ay + 1))
unten_frei = TRUE;
- if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
+ if (IN_LEV_FIELD(ax - 1, ay) && IS_FREE(ax - 1, ay))
links_frei = TRUE;
- if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
+ if (IN_LEV_FIELD(ax + 1, ay) && IS_FREE(ax + 1, ay))
rechts_frei = TRUE;
if (element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
{
if (oben_frei)
{
- Tile[ax][ay-1] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax][ay-1] = element;
- GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
- IMG_EXPANDABLE_STEELWALL_GROWING_UP, 0);
+ Tile[ax][ay - 1] = EL_EXPANDABLE_STEELWALL_GROWING;
+ Store[ax][ay - 1] = element;
+ GfxDir[ax][ay - 1] = MovDir[ax][ay - 1] = MV_UP;
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay - 1)))
+ DrawLevelGraphic(ax, ay - 1, IMG_EXPANDABLE_STEELWALL_GROWING_UP, 0);
new_wall = TRUE;
}
if (unten_frei)
{
- Tile[ax][ay+1] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax][ay+1] = element;
- GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
- IMG_EXPANDABLE_STEELWALL_GROWING_DOWN, 0);
+ Tile[ax][ay + 1] = EL_EXPANDABLE_STEELWALL_GROWING;
+ Store[ax][ay + 1] = element;
+ GfxDir[ax][ay + 1] = MovDir[ax][ay + 1] = MV_DOWN;
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay + 1)))
+ DrawLevelGraphic(ax, ay + 1, IMG_EXPANDABLE_STEELWALL_GROWING_DOWN, 0);
new_wall = TRUE;
}
}
{
if (links_frei)
{
- Tile[ax-1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax-1][ay] = element;
- GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
- if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
- IMG_EXPANDABLE_STEELWALL_GROWING_LEFT, 0);
+ Tile[ax - 1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
+ Store[ax - 1][ay] = element;
+ GfxDir[ax - 1][ay] = MovDir[ax - 1][ay] = MV_LEFT;
+ if (IN_SCR_FIELD(SCREENX(ax - 1), SCREENY(ay)))
+ DrawLevelGraphic(ax - 1, ay, IMG_EXPANDABLE_STEELWALL_GROWING_LEFT, 0);
new_wall = TRUE;
}
if (rechts_frei)
{
- Tile[ax+1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax+1][ay] = element;
- GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
- if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
- IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT, 0);
+ Tile[ax + 1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
+ Store[ax + 1][ay] = element;
+ GfxDir[ax + 1][ay] = MovDir[ax + 1][ay] = MV_RIGHT;
+ if (IN_SCR_FIELD(SCREENX(ax + 1), SCREENY(ay)))
+ DrawLevelGraphic(ax + 1, ay, IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT, 0);
new_wall = TRUE;
}
}
- if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Tile[ax][ay-1]))
+ if (!IN_LEV_FIELD(ax, ay - 1) || IS_WALL(Tile[ax][ay - 1]))
oben_massiv = TRUE;
- if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Tile[ax][ay+1]))
+ if (!IN_LEV_FIELD(ax, ay + 1) || IS_WALL(Tile[ax][ay + 1]))
unten_massiv = TRUE;
- if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Tile[ax-1][ay]))
+ if (!IN_LEV_FIELD(ax - 1, ay) || IS_WALL(Tile[ax - 1][ay]))
links_massiv = TRUE;
- if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Tile[ax+1][ay]))
+ if (!IN_LEV_FIELD(ax + 1, ay) || IS_WALL(Tile[ax + 1][ay]))
rechts_massiv = TRUE;
if (((oben_massiv && unten_massiv) ||
int previous_move_direction = MovDir[x][y];
int last_ce_value = CustomValue[x][y];
boolean player_explosion_protected = PLAYER_EXPLOSION_PROTECTED(x, y);
- boolean new_element_is_player = ELEM_IS_PLAYER(new_element);
+ boolean new_element_is_player = IS_PLAYER_ELEMENT(new_element);
boolean add_player_onto_element = (new_element_is_player &&
new_element != EL_SOKOBAN_FIELD_PLAYER &&
IS_WALKABLE(old_element));
(change->replace_when == CP_WHEN_COLLECTIBLE && is_collectible) ||
(change->replace_when == CP_WHEN_REMOVABLE && is_removable) ||
(change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) &&
- !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element)));
+ !(IS_PLAYER(ex, ey) && IS_PLAYER_ELEMENT(content_element)));
if (!can_replace[xx][yy])
complete_replace = FALSE;
Store[x][y] = EL_EMPTY;
}
+ // special case: element changes to player (and may be kept if walkable)
+ if (IS_PLAYER_ELEMENT(target_element) && !level.keep_walkable_ce)
+ CreateElementFromChange(x, y, EL_EMPTY);
+
CreateElementFromChange(x, y, target_element);
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
different to element changes that affect other elements to change on the
whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */
boolean check_trigger_element =
- (trigger_event == CE_TOUCHING_X ||
+ (trigger_event == CE_NEXT_TO_X ||
+ trigger_event == CE_TOUCHING_X ||
trigger_event == CE_HITTING_X ||
trigger_event == CE_HIT_BY_X ||
trigger_event == CE_DIGGING_X); // this one was forgotten until 3.2.3
}
}
+static void CheckLevelTime_StepCounter(void)
+{
+ int i;
+
+ TimePlayed++;
+
+ if (TimeLeft > 0)
+ {
+ TimeLeft--;
+
+ if (TimeLeft <= 10 && setup.time_limit && !game.LevelSolved)
+ PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
+
+ game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
+
+ DisplayGameControlValues();
+
+ if (!TimeLeft && setup.time_limit && !game.LevelSolved)
+ for (i = 0; i < MAX_PLAYERS; i++)
+ KillPlayer(&stored_player[i]);
+ }
+ else if (game.no_time_limit && !game.all_players_gone)
+ {
+ game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
+
+ DisplayGameControlValues();
+ }
+}
+
static void CheckLevelTime(void)
{
int i;
if (record_tape)
TapeStartRecording(new_random_seed);
+ if (setup.auto_pause_on_start && !tape.pausing)
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
+
if (init_network_game)
{
SendToServer_LevelFile();
Warn("element '%s' caused endless loop in game engine",
EL_NAME(recursion_loop_element));
- RequestQuitGameExt(FALSE, level_editor_test_game, message);
+ RequestQuitGameExt(program.headless, level_editor_test_game, message);
recursion_loop_detected = FALSE; // if game should be continued
TEST_DrawLevelField(x, y);
TestFieldAfterSnapping(x, y, element, move_direction, player_index_bit);
+
+ if (IS_ENVELOPE(element))
+ local_player->show_envelope = element;
}
}
CheckElementChangeByMouse(x, y, element, CE_PRESSED_BY_MOUSE, ch_button);
CheckTriggeredElementChangeByMouse(x, y, element, CE_MOUSE_PRESSED_ON_X,
ch_button);
+
+ if (level.use_step_counter)
+ {
+ boolean counted_click = FALSE;
+
+ // element clicked that can change when clicked/pressed
+ if (CAN_CHANGE_OR_HAS_ACTION(element) &&
+ (HAS_ANY_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
+ HAS_ANY_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE)))
+ counted_click = TRUE;
+
+ // element clicked that can trigger change when clicked/pressed
+ if (trigger_events[element][CE_MOUSE_CLICKED_ON_X] ||
+ trigger_events[element][CE_MOUSE_PRESSED_ON_X])
+ counted_click = TRUE;
+
+ if (new_button && counted_click)
+ CheckLevelTime_StepCounter();
+ }
}
SCAN_PLAYFIELD(x, y)
graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
last_gfx_frame = GfxFrame[x][y];
+ if (element == EL_EMPTY)
+ graphic = el2img(GfxElementEmpty[x][y]);
+
ResetGfxFrame(x, y);
if (GfxFrame[x][y] != last_gfx_frame && !Stop[x][y])
graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
}
+ CheckNextToConditions(x, y);
+
if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
{
StartMoving(x, y);
element == EL_ACID_SPLASH_LEFT ||
element == EL_ACID_SPLASH_RIGHT))
{
- if ((IN_LEV_FIELD(x, y-1) && Tile[x][y-1] == EL_AMOEBA_WET) ||
- (IN_LEV_FIELD(x-1, y) && Tile[x-1][y] == EL_AMOEBA_WET) ||
- (IN_LEV_FIELD(x+1, y) && Tile[x+1][y] == EL_AMOEBA_WET) ||
- (IN_LEV_FIELD(x, y+1) && Tile[x][y+1] == EL_AMOEBA_WET))
+ if ((IN_LEV_FIELD(x, y - 1) && Tile[x][y - 1] == EL_AMOEBA_WET) ||
+ (IN_LEV_FIELD(x - 1, y) && Tile[x - 1][y] == EL_AMOEBA_WET) ||
+ (IN_LEV_FIELD(x + 1, y) && Tile[x + 1][y] == EL_AMOEBA_WET) ||
+ (IN_LEV_FIELD(x, y + 1) && Tile[x][y + 1] == EL_AMOEBA_WET))
Tile[x][y] = EL_AMOEBA_DROP;
}
}
}
- player->last_jx = jx;
- player->last_jy = jy;
-
if (Tile[jx][jy] == EL_EXIT_OPEN ||
Tile[jx][jy] == EL_EM_EXIT_OPEN ||
Tile[jx][jy] == EL_EM_EXIT_OPENING ||
LevelSolved();
}
+ player->last_jx = jx;
+ player->last_jy = jy;
+
// this breaks one level: "machine", level 000
{
int move_direction = player->MovDir;
}
if (level.use_step_counter)
- {
- int i;
-
- TimePlayed++;
-
- if (TimeLeft > 0)
- {
- TimeLeft--;
-
- if (TimeLeft <= 10 && setup.time_limit && !game.LevelSolved)
- PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
-
- game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
-
- DisplayGameControlValues();
-
- if (!TimeLeft && setup.time_limit && !game.LevelSolved)
- for (i = 0; i < MAX_PLAYERS; i++)
- KillPlayer(&stored_player[i]);
- }
- else if (game.no_time_limit && !game.all_players_gone)
- {
- game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
-
- DisplayGameControlValues();
- }
- }
+ CheckLevelTime_StepCounter();
if (tape.single_step && tape.recording && !tape.pausing &&
!player->programmed_action)
ScreenMovDir = MV_NONE;
}
+void CheckNextToConditions(int x, int y)
+{
+ int element = Tile[x][y];
+
+ if (IS_PLAYER(x, y))
+ TestIfPlayerNextToCustomElement(x, y);
+
+ if (CAN_CHANGE_OR_HAS_ACTION(element) &&
+ HAS_ANY_CHANGE_EVENT(element, CE_NEXT_TO_X))
+ TestIfElementNextToCustomElement(x, y);
+}
+
+void TestIfPlayerNextToCustomElement(int x, int y)
+{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int trigger_sides[4][2] =
+ {
+ // center side border side
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, // check top
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, // check left
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, // check right
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP } // check bottom
+ };
+ int i;
+
+ if (!IS_PLAYER(x, y))
+ return;
+
+ struct PlayerInfo *player = PLAYERINFO(x, y);
+
+ if (player->is_moving)
+ return;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+ continue; // center and border element not connected
+
+ border_element = Tile[xx][yy];
+
+ CheckElementChangeByPlayer(xx, yy, border_element, CE_NEXT_TO_PLAYER,
+ player->index_bit, border_side);
+ CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+ CE_PLAYER_NEXT_TO_X,
+ player->index_bit, border_side);
+
+ /* use player element that is initially defined in the level playfield,
+ not the player element that corresponds to the runtime player number
+ (example: a level that contains EL_PLAYER_3 as the only player would
+ incorrectly give EL_PLAYER_1 for "player->element_nr") */
+
+ CheckElementChangeBySide(xx, yy, border_element, player->initial_element,
+ CE_NEXT_TO_X, border_side);
+ }
+}
+
void TestIfPlayerTouchesCustomElement(int x, int y)
{
static int xy[4][2] =
}
}
+void TestIfElementNextToCustomElement(int x, int y)
+{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int trigger_sides[4][2] =
+ {
+ // center side border side
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, // check top
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, // check left
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, // check right
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP } // check bottom
+ };
+ int center_element = Tile[x][y]; // should always be non-moving!
+ int i;
+
+ if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+ return;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+ continue; // center and border element not connected
+
+ border_element = Tile[xx][yy];
+
+ // check for change of center element (but change it only once)
+ if (CheckElementChangeBySide(x, y, center_element, border_element,
+ CE_NEXT_TO_X, border_side))
+ break;
+ }
+}
+
void TestIfElementTouchesCustomElement(int x, int y)
{
static int xy[4][2] =
if (level.finish_dig_collect)
{
int dig_side = MV_DIR_OPPOSITE(direction);
+ int change_event = (IS_DIGGABLE(element) ? CE_PLAYER_DIGS_X :
+ CE_PLAYER_COLLECTS_X);
+ CheckTriggeredElementChangeByPlayer(x, y, element, change_event,
+ player_index_bit, dig_side);
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
player_index_bit, dig_side);
}
return MP_NO_ACTION;
}
}
-
if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
old_element = Back[jx][jy];
}
else if (IS_ENVELOPE(element))
{
- player->show_envelope = element;
+ boolean wait_for_snapping = (mode == DF_SNAP && level.block_snap_field);
+
+ if (!wait_for_snapping)
+ player->show_envelope = element;
}
else if (element == EL_EMC_LENSES)
{
if (sokoban_task_solved &&
game.sokoban_fields_still_needed == 0 &&
game.sokoban_objects_still_needed == 0 &&
- (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban))
+ level.auto_exit_sokoban)
{
game.players_still_needed = 0;
{
// prevent short reactivation of overlay buttons while closing door
SetOverlayActive(FALSE);
+ UnmapGameButtons();
// door may still be open due to skipped or envelope style request
- CloseDoor(DOOR_CLOSE_1);
+ CloseDoor(score_info_tape_play ? DOOR_CLOSE_ALL : DOOR_CLOSE_1);
}
if (network.enabled)
boolean quick_quit = ((escape_key_pressed && !ask_on_escape) ||
level_editor_test_game);
boolean skip_request = (game.all_players_gone || !setup.ask_on_quit_game ||
- quick_quit);
+ quick_quit || score_info_tape_play);
RequestQuitGameExt(skip_request, quick_quit,
"Do you really want to quit the game?");
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandom));
+ SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandomStatic));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElement));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxAction));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxDir));
int y = (is_touch_button ? pos->y : GDI_ACTIVE_POS(pos->y));
int id = i;
+ // do not use touch buttons if overlay touch buttons are disabled
+ if (is_touch_button && !setup.touch.overlay_buttons)
+ continue;
+
if (gfx->bitmap == NULL)
{
game_gadget[id] = NULL;
static void UnmapGameButtonsAtSamePosition_All(void)
{
- if (setup.show_snapshot_buttons)
+ if (setup.show_load_save_buttons)
{
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_SAVE);
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE2);
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_LOAD);
}
+ else if (setup.show_undo_redo_buttons)
+ {
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE2);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO);
+ }
else
{
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_STOP);
}
}
-static void MapGameButtonsAtSamePosition(int id)
+void MapLoadSaveButtons(void)
{
- int i;
-
- for (i = 0; i < NUM_GAME_BUTTONS; i++)
- if (i != id &&
- gamebutton_info[i].pos->x == gamebutton_info[id].pos->x &&
- gamebutton_info[i].pos->y == gamebutton_info[id].pos->y)
- MapGadget(game_gadget[i]);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_LOAD);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_SAVE);
- UnmapGameButtonsAtSamePosition_All();
+ MapGadget(game_gadget[GAME_CTRL_ID_LOAD]);
+ MapGadget(game_gadget[GAME_CTRL_ID_SAVE]);
}
void MapUndoRedoButtons(void)
MapGadget(game_gadget[GAME_CTRL_ID_REDO]);
}
-void UnmapUndoRedoButtons(void)
-{
- UnmapGadget(game_gadget[GAME_CTRL_ID_UNDO]);
- UnmapGadget(game_gadget[GAME_CTRL_ID_REDO]);
-
- MapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO);
- MapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO);
-}
-
void ModifyPauseButtons(void)
{
static int ids[] =
int i;
for (i = 0; i < NUM_GAME_BUTTONS; i++)
- if ((!on_tape || gamebutton_info[i].allowed_on_tape) &&
- i != GAME_CTRL_ID_UNDO &&
- i != GAME_CTRL_ID_REDO)
+ {
+ if ((i == GAME_CTRL_ID_UNDO ||
+ i == GAME_CTRL_ID_REDO) &&
+ game_status != GAME_MODE_PLAYING)
+ continue;
+
+ if (!on_tape || gamebutton_info[i].allowed_on_tape)
MapGadget(game_gadget[i]);
+ }
UnmapGameButtonsAtSamePosition_All();
DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter);
DrawVideoDisplay(VIDEO_STATE_1STEP(tape.single_step), 0);
+ ModifyPauseButtons();
+
BackToFront();
}
if (!CheckEngineSnapshotList())
return;
+ int tape_property_bits = tape.property_bits;
+
LoadEngineSnapshot_Undo(steps);
+ tape.property_bits |= tape_property_bits | TAPE_PROPERTY_SNAPSHOT;
+
GameUndoRedoExt();
}
if (!CheckEngineSnapshotList())
return;
+ int tape_property_bits = tape.property_bits;
+
LoadEngineSnapshot_Redo(steps);
+ tape.property_bits |= tape_property_bits | TAPE_PROPERTY_SNAPSHOT;
+
GameUndoRedoExt();
}
case GAME_CTRL_ID_STOP:
case GAME_CTRL_ID_PANEL_STOP:
case GAME_CTRL_ID_TOUCH_STOP:
- if (game_status == GAME_MODE_MAIN)
- break;
-
- if (tape.playing)
- TapeStop();
- else
- RequestQuitGame(FALSE);
+ TapeStopGame();
break;