#define GAME_CTRL_ID_PANEL_STOP 8
#define GAME_CTRL_ID_PANEL_PAUSE 9
#define GAME_CTRL_ID_PANEL_PLAY 10
-#define SOUND_CTRL_ID_MUSIC 11
-#define SOUND_CTRL_ID_LOOPS 12
-#define SOUND_CTRL_ID_SIMPLE 13
-#define SOUND_CTRL_ID_PANEL_MUSIC 14
-#define SOUND_CTRL_ID_PANEL_LOOPS 15
-#define SOUND_CTRL_ID_PANEL_SIMPLE 16
+#define GAME_CTRL_ID_TOUCH_STOP 11
+#define GAME_CTRL_ID_TOUCH_PAUSE 12
+#define SOUND_CTRL_ID_MUSIC 13
+#define SOUND_CTRL_ID_LOOPS 14
+#define SOUND_CTRL_ID_SIMPLE 15
+#define SOUND_CTRL_ID_PANEL_MUSIC 16
+#define SOUND_CTRL_ID_PANEL_LOOPS 17
+#define SOUND_CTRL_ID_PANEL_SIMPLE 18
-#define NUM_GAME_BUTTONS 17
+#define NUM_GAME_BUTTONS 19
// forward declaration for internal use
return element;
}
+static void IncrementSokobanFieldsNeeded(void)
+{
+ if (level.sb_fields_needed)
+ game.sokoban_fields_still_needed++;
+}
+
+static void IncrementSokobanObjectsNeeded(void)
+{
+ if (level.sb_objects_needed)
+ game.sokoban_objects_still_needed++;
+}
+
+static void DecrementSokobanFieldsNeeded(void)
+{
+ if (game.sokoban_fields_still_needed > 0)
+ game.sokoban_fields_still_needed--;
+}
+
+static void DecrementSokobanObjectsNeeded(void)
+{
+ if (game.sokoban_objects_still_needed > 0)
+ game.sokoban_objects_still_needed--;
+}
+
static void InitPlayerField(int x, int y, int element, boolean init_game)
{
if (element == EL_SP_MURPHY)
player->jy = player->last_jy = y;
}
- if (!init_game)
+ // always check if player was just killed and should be reanimated
{
int player_nr = GET_PLAYER_NR(element);
struct PlayerInfo *player = &stored_player[player_nr];
break;
case EL_SOKOBAN_FIELD_EMPTY:
- local_player->sokobanfields_still_needed++;
+ IncrementSokobanFieldsNeeded();
+ break;
+
+ case EL_SOKOBAN_OBJECT:
+ IncrementSokobanObjectsNeeded();
break;
case EL_STONEBLOCK:
case EL_MOLE_RIGHT:
case EL_MOLE_UP:
case EL_MOLE_DOWN:
+ case EL_SPRING_LEFT:
+ case EL_SPRING_RIGHT:
InitMovDir(x, y);
break;
break;
case EL_LAMP:
- local_player->lights_still_needed++;
+ game.lights_still_needed++;
break;
case EL_PENGUIN:
- local_player->friends_still_needed++;
+ game.friends_still_needed++;
break;
case EL_PIG:
break;
case EL_EMC_MAGIC_BALL:
- if (game.ball_state)
+ if (game.ball_active)
Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE;
break;
case EL_EMC_MAGIC_BALL_SWITCH:
- if (game.ball_state)
+ if (game.ball_active)
Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE;
break;
int getPlayerInventorySize(int player_nr)
{
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
- return level.native_em_level->ply[player_nr]->dynamite;
+ return game_em.ply[player_nr]->dynamite;
else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
- return level.native_sp_level->game_sp->red_disk_count;
+ return game_sp.red_disk_count;
else
return stored_player[player_nr].inventory_size;
}
static void UpdateGameControlValues(void)
{
int i, k;
- int time = (local_player->LevelSolved ?
- local_player->LevelSolved_CountingTime :
+ int time = (game.LevelSolved ?
+ game.LevelSolved_CountingTime :
level.game_engine_type == GAME_ENGINE_TYPE_EM ?
- level.native_em_level->lev->time :
+ game_em.lev->time :
level.game_engine_type == GAME_ENGINE_TYPE_SP ?
- level.native_sp_level->game_sp->time_played :
+ game_sp.time_played :
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
game_mm.energy_left :
game.no_time_limit ? TimePlayed : TimeLeft);
- int score = (local_player->LevelSolved ?
- local_player->LevelSolved_CountingScore :
+ int score = (game.LevelSolved ?
+ game.LevelSolved_CountingScore :
level.game_engine_type == GAME_ENGINE_TYPE_EM ?
- level.native_em_level->lev->score :
+ game_em.lev->score :
level.game_engine_type == GAME_ENGINE_TYPE_SP ?
- level.native_sp_level->game_sp->score :
+ game_sp.score :
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
game_mm.score :
- local_player->score);
+ game.score);
int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
- level.native_em_level->lev->required :
+ game_em.lev->gems_needed :
level.game_engine_type == GAME_ENGINE_TYPE_SP ?
- level.native_sp_level->game_sp->infotrons_still_needed :
+ game_sp.infotrons_still_needed :
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
game_mm.kettles_still_needed :
- local_player->gems_still_needed);
+ game.gems_still_needed);
int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
- level.native_em_level->lev->required > 0 :
+ game_em.lev->gems_needed > 0 :
level.game_engine_type == GAME_ENGINE_TYPE_SP ?
- level.native_sp_level->game_sp->infotrons_still_needed > 0 :
+ game_sp.infotrons_still_needed > 0 :
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
game_mm.kettles_still_needed > 0 ||
game_mm.lights_still_needed > 0 :
- local_player->gems_still_needed > 0 ||
- local_player->sokobanfields_still_needed > 0 ||
- local_player->lights_still_needed > 0);
- int health = (local_player->LevelSolved ?
- local_player->LevelSolved_CountingHealth :
+ game.gems_still_needed > 0 ||
+ game.sokoban_fields_still_needed > 0 ||
+ game.sokoban_objects_still_needed > 0 ||
+ game.lights_still_needed > 0);
+ int health = (game.LevelSolved ?
+ game.LevelSolved_CountingHealth :
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
MM_HEALTH(game_mm.laser_overload_value) :
- local_player->health);
+ game.health);
UpdatePlayfieldElementCount();
{
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
{
- if (level.native_em_level->ply[i]->keys & (1 << k))
+ if (game_em.ply[i]->keys & (1 << k))
game_panel_controls[GAME_PANEL_KEY_1 + k].value =
get_key_element_from_nr(k);
}
{
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
{
- if (level.native_em_level->ply[player_nr]->keys & (1 << k))
+ if (game_em.ply[player_nr]->keys & (1 << k))
game_panel_controls[GAME_PANEL_KEY_1 + k].value =
get_key_element_from_nr(k);
}
(exit_closed ? EL_EXIT_CLOSED : EL_EXIT_OPEN);
game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL].value =
- (game.ball_state ? EL_EMC_MAGIC_BALL_ACTIVE : EL_EMC_MAGIC_BALL);
+ (game.ball_active ? EL_EMC_MAGIC_BALL_ACTIVE : EL_EMC_MAGIC_BALL);
game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL_SWITCH].value =
- (game.ball_state ? EL_EMC_MAGIC_BALL_SWITCH_ACTIVE :
+ (game.ball_active ? EL_EMC_MAGIC_BALL_SWITCH_ACTIVE :
EL_EMC_MAGIC_BALL_SWITCH);
game_panel_controls[GAME_PANEL_LIGHT_SWITCH].value =
(local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY);
game_panel_controls[GAME_PANEL_PENGUINS].value =
- local_player->friends_still_needed;
+ game.friends_still_needed;
game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value =
- local_player->sokobanfields_still_needed;
+ game.sokoban_objects_still_needed;
game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value =
- local_player->sokobanfields_still_needed;
+ game.sokoban_fields_still_needed;
game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value =
(game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL);
game.team_mode = (num_players > 1);
}
+#if 0
+ printf("level %d: level.game_version == %06d\n", level_nr,
+ level.game_version);
+ printf(" tape.file_version == %06d\n",
+ tape.file_version);
+ printf(" tape.game_version == %06d\n",
+ tape.game_version);
+ printf(" tape.engine_version == %06d\n",
+ tape.engine_version);
+ printf(" => game.engine_version == %06d [tape mode: %s]\n",
+ game.engine_version, (tape.playing ? "PLAYING" : "RECORDING"));
+#endif
+
// --------------------------------------------------------------------------
// set flags for bugs and changes according to active game engine version
// --------------------------------------------------------------------------
+ /*
+ Summary of bugfix:
+ Fixed property "can fall" for run-time element "EL_AMOEBA_DROPPING"
+
+ Bug was introduced in version:
+ 2.0.1
+
+ Bug was fixed in version:
+ 4.1.4.2
+
+ Description:
+ In version 2.0.1, a new run-time element "EL_AMOEBA_DROPPING" was added,
+ but the property "can fall" was missing, which caused some levels to be
+ unsolvable. This was fixed in version 4.1.4.2.
+
+ Affected levels/tapes:
+ An example for a tape that was fixed by this bugfix is tape 029 from the
+ level set "rnd_sam_bateman".
+ The wrong behaviour will still be used for all levels or tapes that were
+ created/recorded with it. An example for this is tape 023 from the level
+ set "rnd_gerhard_haeusler", which was recorded with a buggy game engine.
+ */
+
+ boolean use_amoeba_dropping_cannot_fall_bug =
+ ((game.engine_version >= VERSION_IDENT(2,0,1,0) &&
+ game.engine_version <= VERSION_IDENT(4,1,4,1)) ||
+ (tape.playing &&
+ tape.game_version >= VERSION_IDENT(2,0,1,0) &&
+ tape.game_version <= VERSION_IDENT(4,1,4,1)));
+
+ /*
+ Summary of bugfix/change:
+ Fixed move speed of elements entering or leaving magic wall.
+
+ Fixed/changed in version:
+ 2.0.1
+
+ Description:
+ Before 2.0.1, move speed of elements entering or leaving magic wall was
+ twice as fast as it is now.
+ Since 2.0.1, this is set to a lower value by using move_stepsize_list[].
+
+ Affected levels/tapes:
+ The first condition is generally needed for all levels/tapes before version
+ 2.0.1, which might use the old behaviour before it was changed; known tapes
+ that are affected: Tape 014 from the level set "rnd_conor_mancone".
+ The second condition is an exception from the above case and is needed for
+ the special case of tapes recorded with game (not engine!) version 2.0.1 or
+ above, but before it was known that this change would break tapes like the
+ above and was fixed in 4.1.4.2, so that the changed behaviour was active
+ although the engine version while recording maybe was before 2.0.1. There
+ are a lot of tapes that are affected by this exception, like tape 006 from
+ the level set "rnd_conor_mancone".
+ */
+
+ boolean use_old_move_stepsize_for_magic_wall =
+ (game.engine_version < VERSION_IDENT(2,0,1,0) &&
+ !(tape.playing &&
+ tape.game_version >= VERSION_IDENT(2,0,1,0) &&
+ tape.game_version < VERSION_IDENT(4,1,4,2)));
+
/*
Summary of bugfix/change:
Fixed handling for custom elements that change when pushed by the player.
game.use_block_last_field_bug =
(game.engine_version < VERSION_IDENT(3,1,1,0));
+ /* various special flags and settings for native Emerald Mine game engine */
+
game_em.use_single_button =
(game.engine_version > VERSION_IDENT(4,0,0,2));
game_em.use_snap_key_bug =
(game.engine_version < VERSION_IDENT(4,0,1,0));
+ game_em.use_old_explosions =
+ (game.engine_version < VERSION_IDENT(4,1,4,2));
+
+ game_em.use_wrap_around =
+ (game.engine_version > VERSION_IDENT(4,1,4,1));
+
// --------------------------------------------------------------------------
// set maximal allowed number of custom element changes per game frame
// dynamically adjust element properties according to game engine version
InitElementPropertiesEngine(game.engine_version);
-#if 0
- printf("level %d: level version == %06d\n", level_nr, level.game_version);
- printf(" tape version == %06d [%s] [file: %06d]\n",
- tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
- tape.file_version);
- printf(" => game.engine_version == %06d\n", game.engine_version);
-#endif
+ // ---------- initialize special element properties -------------------------
+
+ // "EL_AMOEBA_DROPPING" missed property "can fall" between 2.0.1 and 4.1.4.1
+ if (use_amoeba_dropping_cannot_fall_bug)
+ SET_PROPERTY(EL_AMOEBA_DROPPING, EP_CAN_FALL, FALSE);
// ---------- initialize player's initial move delay ------------------------
int e = move_stepsize_list[i].element;
element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
+
+ // set move stepsize value for certain elements for older engine versions
+ if (use_old_move_stepsize_for_magic_wall)
+ {
+ if (e == EL_MAGIC_WALL_FILLING ||
+ e == EL_MAGIC_WALL_EMPTYING ||
+ e == EL_BD_MAGIC_WALL_FILLING ||
+ e == EL_BD_MAGIC_WALL_EMPTYING)
+ element_info[e].move_stepsize *= 2;
+ }
}
// ---------- initialize collect score --------------------------------------
// ---------- initialize graphics engine ------------------------------------
game.scroll_delay_value =
(game.forced_scroll_delay_value != -1 ? game.forced_scroll_delay_value :
+ level.game_engine_type == GAME_ENGINE_TYPE_EM &&
+ !setup.forced_scroll_delay ? 0 :
setup.scroll_delay ? setup.scroll_delay_value : 0);
game.scroll_delay_value =
MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY);
// Supaplex levels with time limit currently unsupported -- should be added
if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
level.time = 0;
+
+ // ---------- initialize flags for handling game actions --------------------
+
+ // set flags for game actions to default values
+ game.use_key_actions = TRUE;
+ game.use_mouse_actions = FALSE;
+
+ // when using Mirror Magic game engine, handle mouse events only
+ if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
+ {
+ game.use_key_actions = FALSE;
+ game.use_mouse_actions = TRUE;
+ }
+
+ // check for custom elements with mouse click events
+ if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
+ {
+ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+
+ if (HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
+ HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ||
+ HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ||
+ HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X))
+ game.use_mouse_actions = TRUE;
+ }
+ }
}
static int get_num_special_action(int element, int action_first,
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();
InitGameEngine();
InitGameControlValues();
+ // initialize tape actions from game when recording tape
+ if (tape.recording)
+ {
+ tape.use_key_actions = game.use_key_actions;
+ tape.use_mouse_actions = game.use_mouse_actions;
+ }
+
// don't play tapes over network
network_playing = (network.enabled && !tape.playing);
player->killed = FALSE;
player->reanimated = FALSE;
+ player->buried = FALSE;
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;
player->effective_mouse_action.button = 0;
player->effective_mouse_action.button_hint = 0;
- player->score = 0;
- player->score_final = 0;
-
- player->health = MAX_HEALTH;
- player->health_final = MAX_HEALTH;
-
- player->gems_still_needed = level.gems_needed;
- player->sokobanfields_still_needed = 0;
- player->lights_still_needed = 0;
- player->players_still_needed = 0;
- player->friends_still_needed = 0;
-
for (j = 0; j < MAX_NUM_KEYS; j++)
player->key[j] = FALSE;
DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
SnapField(player, 0, 0);
- player->LevelSolved = FALSE;
- player->GameOver = FALSE;
-
- player->LevelSolved_GameWon = FALSE;
- player->LevelSolved_GameEnd = FALSE;
- player->LevelSolved_SaveTape = FALSE;
- player->LevelSolved_SaveScore = FALSE;
-
- player->LevelSolved_CountingTime = 0;
- player->LevelSolved_CountingScore = 0;
- player->LevelSolved_CountingHealth = 0;
-
map_player_action[i] = i;
}
if (network_playing)
SendToServer_MovePlayer(MV_NONE);
- ZX = ZY = -1;
- ExitX = ExitY = -1;
-
FrameCounter = 0;
TimeFrames = 0;
TimePlayed = 0;
ScrollStepSize = 0; // will be correctly initialized by ScrollScreen()
- AllPlayersGone = FALSE;
+ game.robot_wheel_x = -1;
+ game.robot_wheel_y = -1;
+
+ game.exit_x = -1;
+ game.exit_y = -1;
+
+ game.all_players_gone = FALSE;
+
+ game.LevelSolved = FALSE;
+ game.GameOver = FALSE;
+
+ game.GamePlayed = !tape.playing;
+
+ game.LevelSolved_GameWon = FALSE;
+ game.LevelSolved_GameEnd = FALSE;
+ game.LevelSolved_SaveTape = FALSE;
+ game.LevelSolved_SaveScore = FALSE;
+
+ game.LevelSolved_CountingTime = 0;
+ game.LevelSolved_CountingScore = 0;
+ game.LevelSolved_CountingHealth = 0;
game.panel.active = TRUE;
game.switchgate_pos = 0;
game.wind_direction = level.wind_direction_initial;
+ game.score = 0;
+ game.score_final = 0;
+
+ game.health = MAX_HEALTH;
+ game.health_final = MAX_HEALTH;
+
+ game.gems_still_needed = level.gems_needed;
+ game.sokoban_fields_still_needed = 0;
+ game.sokoban_objects_still_needed = 0;
+ game.lights_still_needed = 0;
+ game.players_still_needed = 0;
+ game.friends_still_needed = 0;
+
game.lenses_time_left = 0;
game.magnify_time_left = 0;
- game.ball_state = level.ball_state_initial;
+ game.ball_active = level.ball_active_initial;
game.ball_content_nr = 0;
game.explosions_delayed = TRUE;
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 new_index_nr = setup.network_player_nr;
+
+ if (new_index_nr >= 0 && new_index_nr < MAX_PLAYERS)
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ stored_player[i].connected_locally = FALSE;
+
+ stored_player[new_index_nr].connected_locally = TRUE;
+ }
+ }
+
for (i = 0; i < MAX_PLAYERS; i++)
{
stored_player[i].connected = FALSE;
game.centered_player_nr = (network_playing ? local_player->index_nr : -1);
game.centered_player_nr_next = game.centered_player_nr;
game.set_centered_player = FALSE;
+ game.set_centered_player_wrap = FALSE;
if (network_playing && tape.recording)
{
for (i = 0; i < MAX_PLAYERS; i++)
if (stored_player[i].active)
- local_player->players_still_needed++;
+ game.players_still_needed++;
if (level.solved_by_one_player)
- local_player->players_still_needed = 1;
+ game.players_still_needed = 1;
// when recording the game, store which players take part in the game
if (tape.recording)
{
// this is used for non-R'n'D game engines to update certain engine values
- if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
- {
- actual_player_x = correctLevelPosX_EM(actual_player_x);
- actual_player_y = correctLevelPosY_EM(actual_player_y);
- }
-
// needed to determine if sounds are played within the visible screen area
scroll_x = actual_scroll_x;
scroll_y = actual_scroll_y;
MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
break;
+ case EL_SPRING_LEFT:
+ case EL_SPRING_RIGHT:
+ Feld[x][y] = EL_SPRING;
+ MovDir[x][y] = direction[2][element - EL_SPRING_LEFT];
+ break;
+
default:
if (IS_CUSTOM_ELEMENT(element))
{
AmoebaCnt2[group_nr]++;
}
-static void PlayerWins(struct PlayerInfo *player)
+static void LevelSolved(void)
{
if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
- local_player->players_still_needed > 0)
+ game.players_still_needed > 0)
return;
- player->LevelSolved = TRUE;
- player->GameOver = TRUE;
+ game.LevelSolved = TRUE;
+ game.GameOver = TRUE;
- player->score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
- level.native_em_level->lev->score :
- level.game_engine_type == GAME_ENGINE_TYPE_MM ?
- game_mm.score :
- player->score);
- player->health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
- MM_HEALTH(game_mm.laser_overload_value) :
- player->health);
+ 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);
- player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed :
- TimeLeft);
- player->LevelSolved_CountingScore = player->score_final;
- player->LevelSolved_CountingHealth = player->health_final;
+ game.LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : TimeLeft);
+ game.LevelSolved_CountingScore = game.score_final;
+ game.LevelSolved_CountingHealth = game.health_final;
}
void GameWon(void)
int game_over_delay_value_2 = 25;
int game_over_delay_value_3 = 50;
- if (!local_player->LevelSolved_GameWon)
+ if (!game.LevelSolved_GameWon)
{
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;
- local_player->LevelSolved_GameWon = TRUE;
- local_player->LevelSolved_SaveTape = tape.recording;
- local_player->LevelSolved_SaveScore = !tape.playing;
+ game.LevelSolved_GameWon = TRUE;
+ game.LevelSolved_SaveTape = tape.recording;
+ game.LevelSolved_SaveScore = !tape.playing;
if (!tape.playing)
{
game_over_delay_3 = game_over_delay_value_3;
time = time_final = (game.no_time_limit ? TimePlayed : TimeLeft);
- score = score_final = local_player->score_final;
- health = health_final = local_player->health_final;
+ score = score_final = game.score_final;
+ health = health_final = game.health_final;
if (level.score[SC_TIME_BONUS] > 0)
{
game_over_delay_2 = game_over_delay_value_2;
}
- local_player->score_final = score_final;
- local_player->health_final = health_final;
+ game.score_final = score_final;
+ game.health_final = health_final;
}
if (level_editor_test_game)
time = time_final;
score = score_final;
- local_player->LevelSolved_CountingTime = time;
- local_player->LevelSolved_CountingScore = score;
+ game.LevelSolved_CountingTime = time;
+ game.LevelSolved_CountingScore = score;
game_panel_controls[GAME_PANEL_TIME].value = time;
game_panel_controls[GAME_PANEL_SCORE].value = score;
if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
{
- if (ExitX >= 0 && ExitY >= 0) // local player has left the level
+ // check if last player has left the level
+ if (game.exit_x >= 0 &&
+ game.exit_y >= 0)
{
+ int x = game.exit_x;
+ int y = game.exit_y;
+ int element = Feld[x][y];
+
// close exit door after last player
- if ((AllPlayersGone &&
- (Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
- Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN ||
- Feld[ExitX][ExitY] == EL_STEEL_EXIT_OPEN)) ||
- Feld[ExitX][ExitY] == EL_EM_EXIT_OPEN ||
- Feld[ExitX][ExitY] == EL_EM_STEEL_EXIT_OPEN)
+ if ((game.all_players_gone &&
+ (element == EL_EXIT_OPEN ||
+ element == EL_SP_EXIT_OPEN ||
+ element == EL_STEEL_EXIT_OPEN)) ||
+ element == EL_EM_EXIT_OPEN ||
+ element == EL_EM_STEEL_EXIT_OPEN)
{
- int element = Feld[ExitX][ExitY];
- Feld[ExitX][ExitY] =
+ Feld[x][y] =
(element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING :
element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING:
element == EL_STEEL_EXIT_OPEN ? EL_STEEL_EXIT_CLOSING:
EL_EM_STEEL_EXIT_CLOSING);
- PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
+ PlayLevelSoundElementAction(x, y, element, ACTION_CLOSING);
}
// player disappears
- DrawLevelField(ExitX, ExitY);
+ DrawLevelField(x, y);
}
for (i = 0; i < MAX_PLAYERS; i++)
time += time_count_steps * time_count_dir;
score += time_count_steps * level.score[SC_TIME_BONUS];
- local_player->LevelSolved_CountingTime = time;
- local_player->LevelSolved_CountingScore = score;
+ game.LevelSolved_CountingTime = time;
+ game.LevelSolved_CountingScore = score;
game_panel_controls[GAME_PANEL_TIME].value = time;
game_panel_controls[GAME_PANEL_SCORE].value = score;
health += health_count_dir;
score += level.score[SC_TIME_BONUS];
- local_player->LevelSolved_CountingHealth = health;
- local_player->LevelSolved_CountingScore = 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;
int last_level_nr = levelset.level_nr;
int hi_pos;
- local_player->LevelSolved_GameEnd = TRUE;
+ game.LevelSolved_GameEnd = TRUE;
- if (local_player->LevelSolved_SaveTape)
+ if (game.LevelSolved_SaveTape)
{
// make sure that request dialog to save tape does not open door again
if (!global.use_envelope_request)
return;
}
- if (!local_player->LevelSolved_SaveScore)
+ if (!game.LevelSolved_SaveScore)
{
SetGameStatus(GAME_MODE_MAIN);
LoadScore(level_nr);
if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) ||
- local_player->score_final < highscore[MAX_SCORE_ENTRIES - 1].Score)
+ game.score_final < highscore[MAX_SCORE_ENTRIES - 1].Score)
return -1;
- for (k = 0; k < MAX_SCORE_ENTRIES; k++)
+ for (k = 0; k < MAX_SCORE_ENTRIES; k++)
{
- if (local_player->score_final > highscore[k].Score)
+ if (game.score_final > highscore[k].Score)
{
// player has made it to the hall of fame
strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
- highscore[k].Score = local_player->score_final;
+ highscore[k].Score = game.score_final;
position = k;
break;
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);
int enter_side = enter_side_horiz | enter_side_vert;
int leave_side = leave_side_horiz | leave_side_vert;
- if (player->GameOver) // do not reanimate dead player
+ if (player->buried) // do not reanimate dead player
return;
if (!player_relocated) // no need to relocate the player
{
int attr_x = -1, attr_y = -1;
- if (AllPlayersGone)
+ if (game.all_players_gone)
{
- attr_x = ExitX;
- attr_y = ExitY;
+ attr_x = game.exit_x;
+ attr_y = game.exit_y;
}
else
{
}
}
- 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)
MovDir[x][y] = MV_NONE;
if (attr_x < x)
- MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
+ MovDir[x][y] |= (game.all_players_gone ? MV_RIGHT : MV_LEFT);
else if (attr_x > x)
- MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
+ MovDir[x][y] |= (game.all_players_gone ? MV_LEFT : MV_RIGHT);
if (attr_y < y)
- MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
+ MovDir[x][y] |= (game.all_players_gone ? MV_DOWN : MV_UP);
else if (attr_y > y)
- MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
+ MovDir[x][y] |= (game.all_players_gone ? MV_UP : MV_DOWN);
if (element == EL_ROBOT)
{
int newx, newy;
boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER);
- if (AllPlayersGone)
+ if (game.all_players_gone)
{
- attr_x = ExitX;
- attr_y = ExitY;
+ attr_x = game.exit_x;
+ attr_y = game.exit_y;
}
else
{
if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
- local_player->friends_still_needed--;
- if (!local_player->friends_still_needed &&
- !local_player->GameOver && AllPlayersGone)
- PlayerWins(local_player);
+ game.friends_still_needed--;
+ if (!game.friends_still_needed &&
+ !game.GameOver &&
+ game.all_players_gone)
+ LevelSolved();
return;
}
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;
}
}
static void CheckExit(int x, int y)
{
- if (local_player->gems_still_needed > 0 ||
- local_player->sokobanfields_still_needed > 0 ||
- local_player->lights_still_needed > 0)
+ if (game.gems_still_needed > 0 ||
+ game.sokoban_fields_still_needed > 0 ||
+ game.sokoban_objects_still_needed > 0 ||
+ game.lights_still_needed > 0)
{
int element = Feld[x][y];
int graphic = el2img(element);
return;
}
- if (AllPlayersGone) // do not re-open exit door closed after last player
+ // do not re-open exit door closed after last player
+ if (game.all_players_gone)
return;
Feld[x][y] = EL_EXIT_OPENING;
static void CheckExitEM(int x, int y)
{
- if (local_player->gems_still_needed > 0 ||
- local_player->sokobanfields_still_needed > 0 ||
- local_player->lights_still_needed > 0)
+ if (game.gems_still_needed > 0 ||
+ game.sokoban_fields_still_needed > 0 ||
+ game.sokoban_objects_still_needed > 0 ||
+ game.lights_still_needed > 0)
{
int element = Feld[x][y];
int graphic = el2img(element);
return;
}
- if (AllPlayersGone) // do not re-open exit door closed after last player
+ // do not re-open exit door closed after last player
+ if (game.all_players_gone)
return;
Feld[x][y] = EL_EM_EXIT_OPENING;
static void CheckExitSteel(int x, int y)
{
- if (local_player->gems_still_needed > 0 ||
- local_player->sokobanfields_still_needed > 0 ||
- local_player->lights_still_needed > 0)
+ if (game.gems_still_needed > 0 ||
+ game.sokoban_fields_still_needed > 0 ||
+ game.sokoban_objects_still_needed > 0 ||
+ game.lights_still_needed > 0)
{
int element = Feld[x][y];
int graphic = el2img(element);
return;
}
- if (AllPlayersGone) // do not re-open exit door closed after last player
+ // do not re-open exit door closed after last player
+ if (game.all_players_gone)
return;
Feld[x][y] = EL_STEEL_EXIT_OPENING;
static void CheckExitSteelEM(int x, int y)
{
- if (local_player->gems_still_needed > 0 ||
- local_player->sokobanfields_still_needed > 0 ||
- local_player->lights_still_needed > 0)
+ if (game.gems_still_needed > 0 ||
+ game.sokoban_fields_still_needed > 0 ||
+ game.sokoban_objects_still_needed > 0 ||
+ game.lights_still_needed > 0)
{
int element = Feld[x][y];
int graphic = el2img(element);
return;
}
- if (AllPlayersGone) // do not re-open exit door closed after last player
+ // do not re-open exit door closed after last player
+ if (game.all_players_gone)
return;
Feld[x][y] = EL_EM_STEEL_EXIT_OPENING;
static void CheckExitSP(int x, int y)
{
- if (local_player->gems_still_needed > 0)
+ if (game.gems_still_needed > 0)
{
int element = Feld[x][y];
int graphic = el2img(element);
return;
}
- if (AllPlayersGone) // do not re-open exit door closed after last player
+ // do not re-open exit door closed after last player
+ if (game.all_players_gone)
return;
Feld[x][y] = EL_SP_EXIT_OPENING;
action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score :
action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) :
action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value :
- action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed :
- action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score :
+ action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? game.gems_still_needed :
+ action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? game.score :
action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CE_VALUE(target_element):
action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value:
action_arg == CA_ARG_ELEMENT_CV_ACTION ? GET_NEW_CE_VALUE(action_element):
-1);
int action_arg_number_old =
- (action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed :
+ (action_type == CA_SET_LEVEL_GEMS ? game.gems_still_needed :
action_type == CA_SET_LEVEL_TIME ? TimeLeft :
- action_type == CA_SET_LEVEL_SCORE ? local_player->score :
+ action_type == CA_SET_LEVEL_SCORE ? game.score :
action_type == CA_SET_CE_VALUE ? CustomValue[x][y] :
action_type == CA_SET_CE_SCORE ? ei->collect_score :
0);
case CA_SET_LEVEL_SCORE:
{
- local_player->score = action_arg_number_new;
+ game.score = action_arg_number_new;
- game_panel_controls[GAME_PANEL_SCORE].value = local_player->score;
+ game_panel_controls[GAME_PANEL_SCORE].value = game.score;
DisplayGameControlValues();
case CA_SET_LEVEL_GEMS:
{
- local_player->gems_still_needed = action_arg_number_new;
+ game.gems_still_needed = action_arg_number_new;
game.snapshot.collected_item = TRUE;
- game_panel_controls[GAME_PANEL_GEMS].value =
- local_player->gems_still_needed;
+ game_panel_controls[GAME_PANEL_GEMS].value = game.gems_still_needed;
DisplayGameControlValues();
// ---------- player actions ---------------------------------------------
case CA_MOVE_PLAYER:
+ case CA_MOVE_PLAYER_NEW:
{
// automatically move to the next field in specified direction
for (i = 0; i < MAX_PLAYERS; i++)
if (trigger_player_bits & (1 << i))
- stored_player[i].programmed_action = action_arg_direction;
+ if (action_type == CA_MOVE_PLAYER ||
+ stored_player[i].MovPos == 0)
+ stored_player[i].programmed_action = action_arg_direction;
break;
}
if (action_arg_player_bits & (1 << i))
ExitPlayer(&stored_player[i]);
- if (AllPlayersGone)
- PlayerWins(local_player);
+ if (game.players_still_needed == 0)
+ LevelSolved();
break;
}
if (CustomValue[x][y] == 0)
{
+ // reset change counter (else CE_VALUE_GETS_ZERO would not work)
+ ChangeCount[x][y] = 0; // allow at least one more change
+
CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
}
{
int xx, yy;
+ // reset change counter (else CE_SCORE_GETS_ZERO would not work)
+ ChangeCount[x][y] = 0; // allow at least one more change
+
CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO);
CheckTriggeredElementChange(x, y, element, CE_SCORE_GETS_ZERO_OF_X);
if (!player->is_moving &&
!player->is_pushing &&
!player->is_dropping_pressed)
- {
TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
- SnapField(player, 0, 0); // stop snapping
- }
}
CheckSaveEngineSnapshot(player);
static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action,
byte *tape_action)
{
- if (!tape.use_mouse)
+ if (!tape.use_mouse_actions)
return;
mouse_action->lx = tape_action[TAPE_ACTION_LX];
static void SetTapeActionFromMouseAction(byte *tape_action,
struct MouseActionInfo *mouse_action)
{
- if (!tape.use_mouse)
+ if (!tape.use_mouse_actions)
return;
tape_action[TAPE_ACTION_LX] = mouse_action->lx;
{
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
{
- if (level.native_em_level->lev->home == 0) // all players at home
+ if (game_em.level_solved &&
+ !game_em.game_over) // game won
{
- PlayerWins(local_player);
+ LevelSolved();
- AllPlayersGone = TRUE;
+ game_em.game_over = TRUE;
- level.native_em_level->lev->home = -1;
+ game.all_players_gone = TRUE;
}
- if (level.native_em_level->ply[0]->alive == 0 &&
- level.native_em_level->ply[1]->alive == 0 &&
- level.native_em_level->ply[2]->alive == 0 &&
- level.native_em_level->ply[3]->alive == 0) // all dead
- AllPlayersGone = TRUE;
+ if (game_em.game_over) // game lost
+ game.all_players_gone = TRUE;
}
else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
{
- if (game_sp.LevelSolved &&
- !game_sp.GameOver) // game won
+ if (game_sp.level_solved &&
+ !game_sp.game_over) // game won
{
- PlayerWins(local_player);
+ LevelSolved();
- game_sp.GameOver = TRUE;
+ game_sp.game_over = TRUE;
- AllPlayersGone = TRUE;
+ game.all_players_gone = TRUE;
}
- if (game_sp.GameOver) // game lost
- AllPlayersGone = TRUE;
+ if (game_sp.game_over) // game lost
+ game.all_players_gone = TRUE;
}
else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
{
if (game_mm.level_solved &&
!game_mm.game_over) // game won
{
- PlayerWins(local_player);
+ LevelSolved();
game_mm.game_over = TRUE;
- AllPlayersGone = TRUE;
+ game.all_players_gone = TRUE;
}
if (game_mm.game_over) // game lost
- AllPlayersGone = TRUE;
+ game.all_players_gone = TRUE;
}
}
}
}
- if (!local_player->LevelSolved && !level.use_step_counter)
+ if (!game.LevelSolved && !level.use_step_counter)
{
TimePlayed++;
if (!TimeLeft && setup.time_limit)
{
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
- level.native_em_level->lev->killed_out_of_time = TRUE;
+ game_em.lev->killed_out_of_time = TRUE;
else
for (i = 0; i < MAX_PLAYERS; i++)
KillPlayer(&stored_player[i]);
}
}
- else if (game.no_time_limit && !AllPlayersGone) // level w/o time limit
+ else if (game.no_time_limit && !game.all_players_gone)
{
game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
}
- level.native_em_level->lev->time =
- (game.no_time_limit ? TimePlayed : TimeLeft);
+ game_em.lev->time = (game.no_time_limit ? TimePlayed : TimeLeft);
}
if (tape.recording || tape.playing)
unsigned int game_frame_delay_value;
byte *recorded_player_action;
byte summarized_player_action = 0;
- byte tape_action[MAX_PLAYERS];
+ byte tape_action[MAX_TAPE_ACTIONS] = { 0 };
int i;
// detect endless loops, caused by custom element programming
CheckLevelSolved();
- if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd)
+ if (game.LevelSolved && !game.LevelSolved_GameEnd)
GameWon();
- if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
+ if (game.all_players_gone && !TAPE_IS_STOPPED(tape))
TapeStop();
if (game_status != GAME_MODE_PLAYING) // status might have changed
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)
void GameActions_RND(void)
{
+ static struct MouseActionInfo mouse_action_last = { 0 };
+ struct MouseActionInfo mouse_action = local_player->effective_mouse_action;
int magic_wall_x = 0, magic_wall_y = 0;
int i, x, y, element, graphic, last_gfx_frame;
#endif
}
+ if (mouse_action.button)
+ {
+ int new_button = (mouse_action.button && mouse_action_last.button == 0);
+
+ x = mouse_action.lx;
+ y = mouse_action.ly;
+ element = Feld[x][y];
+
+ if (new_button)
+ {
+ CheckElementChange(x, y, element, EL_UNDEFINED, CE_CLICKED_BY_MOUSE);
+ CheckTriggeredElementChange(x, y, element, CE_MOUSE_CLICKED_ON_X);
+ }
+
+ CheckElementChange(x, y, element, EL_UNDEFINED, CE_PRESSED_BY_MOUSE);
+ CheckTriggeredElementChange(x, y, element, CE_MOUSE_PRESSED_ON_X);
+ }
+
SCAN_PLAYFIELD(x, y)
{
element = Feld[x][y];
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];
+
+ if (player->show_envelope != 0 && (!player->active ||
+ player->MovPos == 0))
+ {
+ ShowEnvelope(player->show_envelope - EL_ENVELOPE_1);
- local_player->show_envelope = 0;
+ player->show_envelope = 0;
+ }
}
// use random number generator in every frame to make it less predictable
if (game.engine_version >= VERSION_IDENT(3,1,1,0))
RND(1);
+
+ mouse_action_last = mouse_action;
}
static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
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);
{
ExitPlayer(player);
- if ((local_player->friends_still_needed == 0 ||
- IS_SP_ELEMENT(Feld[jx][jy])) &&
- AllPlayersGone)
- PlayerWins(local_player);
+ if (game.players_still_needed == 0 &&
+ (game.friends_still_needed == 0 ||
+ IS_SP_ELEMENT(Feld[jx][jy])))
+ LevelSolved();
}
// this breaks one level: "machine", level 000
RemovePlayer(player);
}
- if (!local_player->LevelSolved && level.use_step_counter)
+ if (!game.LevelSolved && level.use_step_counter)
{
int i;
for (i = 0; i < MAX_PLAYERS; i++)
KillPlayer(&stored_player[i]);
}
- else if (game.no_time_limit && !AllPlayersGone) // level w/o time limit
+ else if (game.no_time_limit && !game.all_players_gone)
{
game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING);
PlayLevelSound(jx, jy, SND_GAME_LOSING);
- player->GameOver = TRUE;
RemovePlayer(player);
+
+ player->buried = TRUE;
+
+ if (game.all_players_gone)
+ game.GameOver = TRUE;
}
void RemovePlayer(struct PlayerInfo *player)
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;
found = TRUE;
if (!found)
- AllPlayersGone = TRUE;
+ {
+ game.all_players_gone = TRUE;
+ game.GameOver = TRUE;
+ }
- ExitX = ZX = jx;
- ExitY = ZY = jy;
+ game.exit_x = game.robot_wheel_x = jx;
+ game.exit_y = game.robot_wheel_y = jy;
}
void ExitPlayer(struct PlayerInfo *player)
DrawPlayer(player); // needed here only to cleanup last field
RemovePlayer(player);
- if (local_player->players_still_needed > 0)
- local_player->players_still_needed--;
-
- // also set if some players not yet gone, but not needed to solve level
- if (local_player->players_still_needed == 0)
- AllPlayersGone = TRUE;
+ if (game.players_still_needed > 0)
+ game.players_still_needed--;
}
static void setFieldForSnapping(int x, int y, int element, int direction)
}
else if (collect_count > 0)
{
- local_player->gems_still_needed -= collect_count;
- if (local_player->gems_still_needed < 0)
- local_player->gems_still_needed = 0;
+ game.gems_still_needed -= collect_count;
+ if (game.gems_still_needed < 0)
+ game.gems_still_needed = 0;
game.snapshot.collected_item = TRUE;
- game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed;
+ game_panel_controls[GAME_PANEL_GEMS].value = game.gems_still_needed;
DisplayGameControlValues();
}
if (IS_SB_ELEMENT(element))
{
+ boolean sokoban_task_solved = FALSE;
+
if (element == EL_SOKOBAN_FIELD_FULL)
{
Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
- local_player->sokobanfields_still_needed++;
+
+ IncrementSokobanFieldsNeeded();
+ IncrementSokobanObjectsNeeded();
}
if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY)
{
Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY;
- local_player->sokobanfields_still_needed--;
+
+ DecrementSokobanFieldsNeeded();
+ DecrementSokobanObjectsNeeded();
+
+ // sokoban object was pushed from empty field to sokoban field
+ if (Back[x][y] == EL_EMPTY)
+ sokoban_task_solved = TRUE;
}
Feld[x][y] = EL_SOKOBAN_OBJECT;
PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
ACTION_FILLING);
- if (local_player->sokobanfields_still_needed == 0 &&
+ if (sokoban_task_solved &&
+ game.sokoban_fields_still_needed == 0 &&
+ game.sokoban_objects_still_needed == 0 &&
(game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban))
{
- local_player->players_still_needed = 0;
+ game.players_still_needed = 0;
- PlayerWins(local_player);
+ LevelSolved();
PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
}
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);
else if (element == EL_LAMP)
{
Feld[x][y] = EL_LAMP_ACTIVE;
- local_player->lights_still_needed--;
+ game.lights_still_needed--;
ResetGfxAnimation(x, y);
TEST_DrawLevelField(x, y);
{
int xx, yy;
- game.ball_state = !game.ball_state;
+ game.ball_active = !game.ball_active;
SCAN_PLAYFIELD(xx, yy)
{
int e = Feld[xx][yy];
- if (game.ball_state)
+ if (game.ball_active)
{
if (e == EL_EMC_MAGIC_BALL)
CreateField(xx, yy, EL_EMC_MAGIC_BALL_ACTIVE);
void PlayLevelSound_EM(int xx, int yy, int element_em, int sample)
{
- int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0);
- int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
- int x = xx - 1 - offset;
- int y = yy - 1 - offset;
+ int element = (element_em > -1 ? map_element_EM_to_RND_game(element_em) : 0);
+ int offset = 0;
+ int x = xx - offset;
+ int y = yy - offset;
switch (sample)
{
- case SAMPLE_blank:
+ case SOUND_blank:
PlayLevelSoundElementAction(x, y, element, ACTION_WALKING);
break;
- case SAMPLE_roll:
+ case SOUND_roll:
PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
break;
- case SAMPLE_stone:
+ case SOUND_stone:
PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
break;
- case SAMPLE_nut:
+ case SOUND_nut:
PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
break;
- case SAMPLE_crack:
+ case SOUND_crack:
PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
break;
- case SAMPLE_bug:
+ case SOUND_bug:
PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
break;
- case SAMPLE_tank:
+ case SOUND_tank:
PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
break;
- case SAMPLE_android_clone:
+ case SOUND_android_clone:
PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
break;
- case SAMPLE_android_move:
+ case SOUND_android_move:
PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
break;
- case SAMPLE_spring:
+ case SOUND_spring:
PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
break;
- case SAMPLE_slurp:
+ case SOUND_slurp:
PlayLevelSoundElementAction(x, y, element, ACTION_EATING);
break;
- case SAMPLE_eater:
+ case SOUND_eater:
PlayLevelSoundElementAction(x, y, element, ACTION_WAITING);
break;
- case SAMPLE_eater_eat:
+ case SOUND_eater_eat:
PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
break;
- case SAMPLE_alien:
+ case SOUND_alien:
PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
break;
- case SAMPLE_collect:
+ case SOUND_collect:
PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
break;
- case SAMPLE_diamond:
+ case SOUND_diamond:
PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
break;
- case SAMPLE_squash:
+ case SOUND_squash:
// !!! CHECK THIS !!!
#if 1
PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
#endif
break;
- case SAMPLE_wonderfall:
+ case SOUND_wonderfall:
PlayLevelSoundElementAction(x, y, element, ACTION_FILLING);
break;
- case SAMPLE_drip:
+ case SOUND_drip:
PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
break;
- case SAMPLE_push:
+ case SOUND_push:
PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
break;
- case SAMPLE_dirt:
+ case SOUND_dirt:
PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
break;
- case SAMPLE_acid:
+ case SOUND_acid:
PlayLevelSoundElementAction(x, y, element, ACTION_SPLASHING);
break;
- case SAMPLE_ball:
+ case SOUND_ball:
PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
break;
- case SAMPLE_grow:
+ case SOUND_slide:
PlayLevelSoundElementAction(x, y, element, ACTION_GROWING);
break;
- case SAMPLE_wonder:
+ case SOUND_wonder:
PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
break;
- case SAMPLE_door:
+ case SOUND_door:
PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
break;
- case SAMPLE_exit_open:
+ case SOUND_exit_open:
PlayLevelSoundElementAction(x, y, element, ACTION_OPENING);
break;
- case SAMPLE_exit_leave:
+ case SOUND_exit_leave:
PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
break;
- case SAMPLE_dynamite:
+ case SOUND_dynamite:
PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
break;
- case SAMPLE_tick:
+ case SOUND_tick:
PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
break;
- case SAMPLE_press:
+ case SOUND_press:
PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
break;
- case SAMPLE_wheel:
+ case SOUND_wheel:
PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
break;
- case SAMPLE_boom:
+ case SOUND_boom:
PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING);
break;
- case SAMPLE_die:
+ case SOUND_die:
PlayLevelSoundElementAction(x, y, element, ACTION_DYING);
break;
- case SAMPLE_time:
+ case SOUND_time:
PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
break;
void RaiseScore(int value)
{
- local_player->score += value;
+ game.score += value;
- game_panel_controls[GAME_PANEL_SCORE].value = local_player->score;
+ game_panel_controls[GAME_PANEL_SCORE].value = game.score;
DisplayGameControlValues();
}
{
// 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);
void RequestQuitGame(boolean ask_if_really_quit)
{
boolean quick_quit = (!ask_if_really_quit || level_editor_test_game);
- boolean skip_request = AllPlayersGone || quick_quit;
+ boolean skip_request = game.all_players_gone || quick_quit;
RequestQuitGameExt(skip_request, quick_quit,
"Do you really want to quit the game?");
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;
boolean checkGameSolved(void)
{
// set for all game engines if level was solved
- return local_player->LevelSolved_GameEnd;
+ return game.LevelSolved_GameEnd;
}
boolean checkGameFailed(void)
{
- if (!AllPlayersGone)
- return FALSE;
-
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
- return (level.native_em_level->lev->home > 0);
+ return (game_em.game_over && !game_em.level_solved);
else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
- return (game_sp.GameOver && !game_sp.LevelSolved);
+ return (game_sp.game_over && !game_sp.level_solved);
else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
return (game_mm.game_over && !game_mm.level_solved);
else // GAME_ENGINE_TYPE_RND
- return (local_player->GameOver && !local_player->LevelSolved);
+ return (game.GameOver && !game.LevelSolved);
}
boolean checkGameEnded(void)
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(ExitX));
- SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitY));
-
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(FrameCounter));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize));
- SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone));
-
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2));
int gadget_id;
boolean *setup_value;
boolean allowed_on_tape;
+ boolean is_touch_button;
char *infotext;
} gamebutton_info[NUM_GAME_BUTTONS] =
{
{
IMG_GFX_GAME_BUTTON_STOP, &game.button.stop,
GAME_CTRL_ID_STOP, NULL,
- TRUE, "stop game"
+ TRUE, FALSE, "stop game"
},
{
IMG_GFX_GAME_BUTTON_PAUSE, &game.button.pause,
GAME_CTRL_ID_PAUSE, NULL,
- TRUE, "pause game"
+ TRUE, FALSE, "pause game"
},
{
IMG_GFX_GAME_BUTTON_PLAY, &game.button.play,
GAME_CTRL_ID_PLAY, NULL,
- TRUE, "play game"
+ TRUE, FALSE, "play game"
},
{
IMG_GFX_GAME_BUTTON_UNDO, &game.button.undo,
GAME_CTRL_ID_UNDO, NULL,
- TRUE, "undo step"
+ TRUE, FALSE, "undo step"
},
{
IMG_GFX_GAME_BUTTON_REDO, &game.button.redo,
GAME_CTRL_ID_REDO, NULL,
- TRUE, "redo step"
+ TRUE, FALSE, "redo step"
},
{
IMG_GFX_GAME_BUTTON_SAVE, &game.button.save,
GAME_CTRL_ID_SAVE, NULL,
- TRUE, "save game"
+ TRUE, FALSE, "save game"
},
{
IMG_GFX_GAME_BUTTON_PAUSE2, &game.button.pause2,
GAME_CTRL_ID_PAUSE2, NULL,
- TRUE, "pause game"
+ TRUE, FALSE, "pause game"
},
{
IMG_GFX_GAME_BUTTON_LOAD, &game.button.load,
GAME_CTRL_ID_LOAD, NULL,
- TRUE, "load game"
+ TRUE, FALSE, "load game"
},
{
IMG_GFX_GAME_BUTTON_PANEL_STOP, &game.button.panel_stop,
GAME_CTRL_ID_PANEL_STOP, NULL,
- FALSE, "stop game"
+ FALSE, FALSE, "stop game"
},
{
IMG_GFX_GAME_BUTTON_PANEL_PAUSE, &game.button.panel_pause,
GAME_CTRL_ID_PANEL_PAUSE, NULL,
- FALSE, "pause game"
+ FALSE, FALSE, "pause game"
},
{
IMG_GFX_GAME_BUTTON_PANEL_PLAY, &game.button.panel_play,
GAME_CTRL_ID_PANEL_PLAY, NULL,
- FALSE, "play game"
+ FALSE, FALSE, "play game"
+ },
+ {
+ IMG_GFX_GAME_BUTTON_TOUCH_STOP, &game.button.touch_stop,
+ GAME_CTRL_ID_TOUCH_STOP, NULL,
+ FALSE, TRUE, "stop game"
+ },
+ {
+ IMG_GFX_GAME_BUTTON_TOUCH_PAUSE, &game.button.touch_pause,
+ GAME_CTRL_ID_TOUCH_PAUSE, NULL,
+ FALSE, TRUE, "pause game"
},
{
IMG_GFX_GAME_BUTTON_SOUND_MUSIC, &game.button.sound_music,
SOUND_CTRL_ID_MUSIC, &setup.sound_music,
- TRUE, "background music on/off"
+ TRUE, FALSE, "background music on/off"
},
{
IMG_GFX_GAME_BUTTON_SOUND_LOOPS, &game.button.sound_loops,
SOUND_CTRL_ID_LOOPS, &setup.sound_loops,
- TRUE, "sound loops on/off"
+ TRUE, FALSE, "sound loops on/off"
},
{
IMG_GFX_GAME_BUTTON_SOUND_SIMPLE, &game.button.sound_simple,
SOUND_CTRL_ID_SIMPLE, &setup.sound_simple,
- TRUE, "normal sounds on/off"
+ TRUE, FALSE, "normal sounds on/off"
},
{
IMG_GFX_GAME_BUTTON_PANEL_SOUND_MUSIC, &game.button.panel_sound_music,
SOUND_CTRL_ID_PANEL_MUSIC, &setup.sound_music,
- FALSE, "background music on/off"
+ FALSE, FALSE, "background music on/off"
},
{
IMG_GFX_GAME_BUTTON_PANEL_SOUND_LOOPS, &game.button.panel_sound_loops,
SOUND_CTRL_ID_PANEL_LOOPS, &setup.sound_loops,
- FALSE, "sound loops on/off"
+ FALSE, FALSE, "sound loops on/off"
},
{
IMG_GFX_GAME_BUTTON_PANEL_SOUND_SIMPLE, &game.button.panel_sound_simple,
SOUND_CTRL_ID_PANEL_SIMPLE, &setup.sound_simple,
- FALSE, "normal sounds on/off"
+ FALSE, FALSE, "normal sounds on/off"
}
};
int button_type;
boolean checked;
unsigned int event_mask;
+ boolean is_touch_button = gamebutton_info[i].is_touch_button;
boolean allowed_on_tape = gamebutton_info[i].allowed_on_tape;
boolean on_tape = (tape.show_game_buttons && allowed_on_tape);
- int base_x = (on_tape ? VX : DX);
- int base_y = (on_tape ? VY : DY);
+ int base_x = (is_touch_button ? 0 : on_tape ? VX : DX);
+ int base_y = (is_touch_button ? 0 : on_tape ? VY : DY);
int gd_x = gfx->src_x;
int gd_y = gfx->src_y;
int gd_xp = gfx->src_x + gfx->pressed_xoffset;
int gd_ya = gfx->src_y + gfx->active_yoffset;
int gd_xap = gfx->src_x + gfx->active_xoffset + gfx->pressed_xoffset;
int gd_yap = gfx->src_y + gfx->active_yoffset + gfx->pressed_yoffset;
+ int x = (is_touch_button ? pos->x : GDI_ACTIVE_POS(pos->x));
+ int y = (is_touch_button ? pos->y : GDI_ACTIVE_POS(pos->y));
int id = i;
if (gfx->bitmap == NULL)
if (id == GAME_CTRL_ID_STOP ||
id == GAME_CTRL_ID_PANEL_STOP ||
+ id == GAME_CTRL_ID_TOUCH_STOP ||
id == GAME_CTRL_ID_PLAY ||
id == GAME_CTRL_ID_PANEL_PLAY ||
id == GAME_CTRL_ID_SAVE ||
gi = CreateGadget(GDI_CUSTOM_ID, id,
GDI_IMAGE_ID, graphic,
GDI_INFO_TEXT, gamebutton_info[i].infotext,
- GDI_X, base_x + GDI_ACTIVE_POS(pos->x),
- GDI_Y, base_y + GDI_ACTIVE_POS(pos->y),
+ GDI_X, base_x + x,
+ GDI_Y, base_y + y,
GDI_WIDTH, gfx->width,
GDI_HEIGHT, gfx->height,
GDI_TYPE, button_type,
GDI_ALT_DESIGN_UNPRESSED, gfx->bitmap, gd_xa, gd_ya,
GDI_ALT_DESIGN_PRESSED, gfx->bitmap, gd_xap, gd_yap,
GDI_DIRECT_DRAW, FALSE,
+ GDI_OVERLAY_TOUCH_BUTTON, is_touch_button,
GDI_EVENT_MASK, event_mask,
GDI_CALLBACK_ACTION, HandleGameButtons,
GDI_END);
MapGadget(game_gadget[GAME_CTRL_ID_UNDO]);
MapGadget(game_gadget[GAME_CTRL_ID_REDO]);
-
- ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, TRUE, GDI_END);
}
void UnmapUndoRedoButtons(void)
MapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO);
MapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO);
+}
+
+void ModifyPauseButtons(void)
+{
+ static int ids[] =
+ {
+ GAME_CTRL_ID_PAUSE,
+ GAME_CTRL_ID_PAUSE2,
+ GAME_CTRL_ID_PANEL_PAUSE,
+ GAME_CTRL_ID_TOUCH_PAUSE,
+ -1
+ };
+ int i;
- ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END);
+ for (i = 0; ids[i] > -1; i++)
+ ModifyGadget(game_gadget[ids[i]], GDI_CHECKED, tape.pausing, GDI_END);
}
static void MapGameButtonsExt(boolean on_tape)
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)
{
case GAME_CTRL_ID_STOP:
case GAME_CTRL_ID_PANEL_STOP:
+ case GAME_CTRL_ID_TOUCH_STOP:
if (game_status == GAME_MODE_MAIN)
break;
case GAME_CTRL_ID_PAUSE:
case GAME_CTRL_ID_PAUSE2:
case GAME_CTRL_ID_PANEL_PAUSE:
+ case GAME_CTRL_ID_TOUCH_PAUSE:
if (network.enabled && game_status == GAME_MODE_PLAYING)
{
if (tape.pausing)