X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=daa0b30eb457c97ec29bd0aa69755f40964e19fd;hb=e4f31a4e6f4b611a1dddb16afb66e3af177dd937;hp=8f5a51fe4fb9d77af9a4ec40888aba90f454fed9;hpb=77f9631ec22275d3016783caee7135efd0cf04ec;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 8f5a51fe..daa0b30e 100644 --- a/src/game.c +++ b/src/game.c @@ -41,9 +41,17 @@ #define USE_STOP_CHANGED_ELEMENTS (USE_NEW_STUFF * 1) #define USE_ELEMENT_TOUCHING_BUGFIX (USE_NEW_STUFF * 1) #define USE_NEW_CONTINUOUS_SNAPPING (USE_NEW_STUFF * 1) +#define USE_GFX_RESET_GFX_ANIMATION (USE_NEW_STUFF * 1) +#define USE_BOTH_SWITCHGATE_SWITCHES (USE_NEW_STUFF * 1) +#define USE_PLAYER_GRAVITY (USE_NEW_STUFF * 1) +#define USE_FIXED_BORDER_RUNNING_GFX (USE_NEW_STUFF * 1) +#define USE_QUICKSAND_BD_ROCK_BUGFIX (USE_NEW_STUFF * 0) #define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0) +#define USE_CODE_THAT_BREAKS_SNAKE_BITE (USE_NEW_STUFF * 1) + + /* for DigField() */ #define DF_NO_PUSH 0 #define DF_DIG 1 @@ -142,13 +150,15 @@ RND(element_info[e].move_delay_random)) #define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \ (element_info[e].move_delay_random)) -#define GET_NEW_CUSTOM_VALUE(e) ( (element_info[e].ce_value_fixed_initial) +\ +#define GET_NEW_CE_VALUE(e) ( (element_info[e].ce_value_fixed_initial) +\ RND(element_info[e].ce_value_random_initial)) +#define GET_CE_SCORE(e) ( (element_info[e].collect_score)) #define GET_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \ RND((c)->delay_random * (c)->delay_frames)) #define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \ RND((c)->delay_random)) + #if 1 #define GET_VALID_RUNTIME_ELEMENT(e) \ ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e)) @@ -157,10 +167,21 @@ ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e)) #endif -#define GET_TARGET_ELEMENT(e, ch) \ - ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \ - (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ - (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : (e)) +#define RESOLVED_REFERENCE_ELEMENT(be, e) \ + ((be) + (e) - EL_SELF < EL_CUSTOM_START ? EL_CUSTOM_START : \ + (be) + (e) - EL_SELF > EL_CUSTOM_END ? EL_CUSTOM_END : \ + (be) + (e) - EL_SELF) + +#define GET_TARGET_ELEMENT(be, e, ch, cv, cs) \ + ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \ + (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ + (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : \ + (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \ + (e) == EL_CURRENT_CE_VALUE ? (cv) : \ + (e) == EL_CURRENT_CE_SCORE ? (cs) : \ + (e) >= EL_LAST_CE_8 && (e) <= EL_NEXT_CE_8 ? \ + RESOLVED_REFERENCE_ELEMENT(be, e) : \ + (e)) #define CAN_GROW_INTO(e) \ ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable)) @@ -358,6 +379,8 @@ void RemovePlayer(struct PlayerInfo *); boolean SnapField(struct PlayerInfo *, int, int); boolean DropElement(struct PlayerInfo *); +static int getInvisibleActiveFromInvisibleElement(int); +static int getInvisibleFromInvisibleActiveElement(int); static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; @@ -770,6 +793,7 @@ static int get_move_delay_from_stepsize(int move_stepsize) static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, boolean init_game) { + int player_nr = player->index_nr; int move_delay = get_move_delay_from_stepsize(move_stepsize); boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE); @@ -781,8 +805,8 @@ static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, if (init_game) { - player->move_delay = game.initial_move_delay; - player->move_delay_value = game.initial_move_delay_value; + player->move_delay = game.initial_move_delay[player_nr]; + player->move_delay_value = game.initial_move_delay_value[player_nr]; player->move_delay_value_next = -1; @@ -861,6 +885,32 @@ static int getBeltDirFromBeltSwitchElement(int element) return belt_move_dir[belt_dir_nr]; } +static int get_element_from_group_element(int element) +{ + if (IS_GROUP_ELEMENT(element)) + { + struct ElementGroupInfo *group = element_info[element].group; + int last_anim_random_frame = gfx.anim_random_frame; + int element_pos; + + if (group->choice_mode == ANIM_RANDOM) + gfx.anim_random_frame = RND(group->num_elements_resolved); + + element_pos = getAnimationFrame(group->num_elements_resolved, 1, + group->choice_mode, 0, + group->choice_pos); + + if (group->choice_mode == ANIM_RANDOM) + gfx.anim_random_frame = last_anim_random_frame; + + group->choice_pos++; + + element = group->element_resolved[element_pos]; + } + + return element; +} + static void InitPlayerField(int x, int y, int element, boolean init_game) { if (element == EL_SP_MURPHY) @@ -1085,16 +1135,26 @@ static void InitField(int x, int y, boolean init_game) } break; +#if !USE_BOTH_SWITCHGATE_SWITCHES case EL_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */ if (init_game) Feld[x][y] = EL_SWITCHGATE_SWITCH_UP; break; +#endif case EL_LIGHT_SWITCH_ACTIVE: if (init_game) game.light_time_left = level.time_light * FRAMES_PER_SECOND; break; + case EL_INVISIBLE_STEELWALL: + case EL_INVISIBLE_WALL: + case EL_INVISIBLE_SAND: + if (game.light_time_left > 0 || + game.lenses_time_left > 0) + Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); + break; + case EL_EMC_MAGIC_BALL: if (game.ball_state) Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE; @@ -1114,7 +1174,7 @@ static void InitField(int x, int y, boolean init_game) #if USE_NEW_CUSTOM_VALUE if (!element_info[element].use_last_ce_value || init_game) - CustomValue[x][y] = GET_NEW_CUSTOM_VALUE(Feld[x][y]); + CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]); #endif } #else @@ -1123,6 +1183,11 @@ static void InitField(int x, int y, boolean init_game) #endif else if (IS_GROUP_ELEMENT(element)) { +#if 1 + Feld[x][y] = get_element_from_group_element(element); + + InitField(x, y, init_game); +#else struct ElementGroupInfo *group = element_info[element].group; int last_anim_random_frame = gfx.anim_random_frame; int element_pos; @@ -1142,7 +1207,9 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = group->element_resolved[element_pos]; InitField(x, y, init_game); +#endif } + break; } @@ -1156,7 +1223,7 @@ static void InitField(int x, int y, boolean init_game) #if USE_NEW_CUSTOM_VALUE #if 1 - CustomValue[x][y] = GET_NEW_CUSTOM_VALUE(Feld[x][y]); + CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]); #else CustomValue[x][y] = element_info[Feld[x][y]].custom_value_initial; #endif @@ -1199,12 +1266,16 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game) inline void DrawGameValue_Emeralds(int value) { - DrawText(DX_EMERALDS, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2); + int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + + DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2); } inline void DrawGameValue_Dynamite(int value) { - DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2); + int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + + DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2); } inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) @@ -1230,15 +1301,24 @@ inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) inline void DrawGameValue_Score(int value) { - DrawText(DX_SCORE, DY_SCORE, int2str(value, 5), FONT_TEXT_2); + int xpos = (5 * 14 - 5 * getFontWidth(FONT_TEXT_2)) / 2; + + DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), FONT_TEXT_2); } inline void DrawGameValue_Time(int value) { + int xpos3 = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + int xpos4 = (4 * 10 - 4 * getFontWidth(FONT_LEVEL_NUMBER)) / 2; + + /* clear background if value just changed its size */ + if (value == 999 || value == 1000) + ClearRectangle(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); + if (value < 1000) - DrawText(DX_TIME1, DY_TIME, int2str(value, 3), FONT_TEXT_2); + DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), FONT_TEXT_2); else - DrawText(DX_TIME2, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER); + DrawText(DX_TIME2 + xpos4, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER); } inline void DrawGameValue_Level(int value) @@ -1384,6 +1464,18 @@ static void resolve_group_element(int group_element, int recursion_depth) } #endif +#if 0 +static void replace_reference_element(int base_element, int *element) +{ + if (*element >= EL_LAST_CE_8 && *element <= EL_NEXT_CE_8) + { + *element = base_element + *element - EL_SELF; + *element = (*element < EL_CUSTOM_START ? EL_CUSTOM_START : + *element > EL_CUSTOM_END ? EL_CUSTOM_END : *element); + } +} +#endif + /* ============================================================================= InitGameEngine() @@ -1529,8 +1621,9 @@ static void InitGameEngine() #if 1 /* dynamically adjust player properties according to level information */ - game.initial_move_delay_value = - get_move_delay_from_stepsize(level.initial_player_stepsize); + for (i = 0; i < MAX_PLAYERS; i++) + game.initial_move_delay_value[i] = + get_move_delay_from_stepsize(level.initial_player_stepsize[i]); #else /* dynamically adjust player properties according to level information */ game.initial_move_delay_value = @@ -1538,8 +1631,10 @@ static void InitGameEngine() #endif /* dynamically adjust player properties according to game engine version */ - game.initial_move_delay = (game.engine_version <= VERSION_IDENT(2,0,1,0) ? - game.initial_move_delay_value : 0); + for (i = 0; i < MAX_PLAYERS; i++) + game.initial_move_delay[i] = + (game.engine_version <= VERSION_IDENT(2,0,1,0) ? + game.initial_move_delay_value[i] : 0); /* ---------- initialize player's initial push delay --------------------- */ @@ -1646,6 +1741,7 @@ static void InitGameEngine() ei->change_page[j].actual_trigger_player = EL_PLAYER_1; ei->change_page[j].actual_trigger_side = CH_SIDE_NONE; ei->change_page[j].actual_trigger_ce_value = 0; + ei->change_page[j].actual_trigger_ce_score = 0; } } @@ -1682,6 +1778,11 @@ static void InitGameEngine() for (l = 0; l < group->num_elements_resolved; l++) trigger_events[group->element_resolved[l]][k] = TRUE; } +#if 1 + else if (trigger_element == EL_ANY_ELEMENT) + for (l = 0; l < MAX_NUM_ELEMENTS; l++) + trigger_events[l][k] = TRUE; +#endif else trigger_events[trigger_element][k] = TRUE; } @@ -1697,8 +1798,22 @@ static void InitGameEngine() { if (!IS_CUSTOM_ELEMENT(i)) { +#if 1 + /* set default push delay values (corrected since version 3.0.7-1) */ + if (game.engine_version < VERSION_IDENT(3,0,7,1)) + { + element_info[i].push_delay_fixed = 2; + element_info[i].push_delay_random = 8; + } + else + { + element_info[i].push_delay_fixed = 8; + element_info[i].push_delay_random = 8; + } +#else element_info[i].push_delay_fixed = game.default_push_delay_fixed; element_info[i].push_delay_random = game.default_push_delay_random; +#endif } } @@ -1805,6 +1920,29 @@ static void InitGameEngine() EL_EMPTY); } } + +#if 0 + /* ---------- initialize reference elements ------------------------------- */ + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + struct ElementInfo *ei = &element_info[element]; + + for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) + replace_reference_element(element, &ei->content.e[x][y]); + + for (j = 0; j < ei->num_change_pages; j++) + { + struct ElementChangeInfo *change = &ei->change_page[j]; + + replace_reference_element(element, &change->target_element); + replace_reference_element(element, &change->trigger_element); + + for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) + replace_reference_element(element, &change->target_content.e[x][y]); + } + } +#endif } int get_num_special_action(int element, int action_first, int action_last) @@ -1899,6 +2037,8 @@ void InitGame() player->block_last_field = FALSE; /* initialized in InitPlayerField() */ player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */ + player->gravity = level.initial_player_gravity[i]; + player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr); player->actual_frame_counter = 0; @@ -1907,6 +2047,8 @@ void InitGame() player->last_move_dir = MV_NONE; + player->is_active = FALSE; + player->is_waiting = FALSE; player->is_moving = FALSE; player->is_auto_moving = FALSE; @@ -1954,7 +2096,7 @@ void InitGame() player->show_envelope = 0; #if 1 - SetPlayerMoveSpeed(player, level.initial_player_stepsize, TRUE); + SetPlayerMoveSpeed(player, level.initial_player_stepsize[i], TRUE); #else player->move_delay = game.initial_move_delay; player->move_delay_value = game.initial_move_delay_value; @@ -2020,8 +2162,15 @@ void InitGame() game.timegate_time_left = 0; game.switchgate_pos = 0; game.wind_direction = level.wind_direction_initial; + +#if !USE_PLAYER_GRAVITY +#if 1 + game.gravity = FALSE; +#else game.gravity = level.initial_gravity; +#endif game.explosions_delayed = TRUE; +#endif game.lenses_time_left = 0; game.magnify_time_left = 0; @@ -2031,9 +2180,23 @@ void InitGame() game.envelope_active = FALSE; - game.centered_player_nr = game.centered_player_nr_next = -1; /* focus all */ + /* set focus to local player for network games, else to all players */ + 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; + if (network_playing && tape.recording) + { + /* store client dependent player focus when recording network games */ + tape.centered_player_nr_next = game.centered_player_nr_next; + tape.set_centered_player = TRUE; + } + +#if 0 + printf("::: focus set to player %d [%d]\n", + game.centered_player_nr, local_player->index_nr); +#endif + for (i = 0; i < NUM_BELTS; i++) { game.belt_dir[i] = MV_NONE; @@ -2846,7 +3009,7 @@ int NewHiScore() LoadScore(level_nr); - if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 || + if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) || local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; @@ -2862,7 +3025,7 @@ int NewHiScore() #ifdef ONE_PER_NAME for (l = k; l < MAX_SCORE_ENTRIES; l++) - if (!strcmp(setup.player_name, highscore[l].Name)) + if (strEqual(setup.player_name, highscore[l].Name)) m = l; if (m == k) /* player's new highscore overwrites his old one */ goto put_into_list; @@ -2946,10 +3109,26 @@ void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir) } } -static void ResetRandomAnimationValue(int x, int y) +#if USE_GFX_RESET_GFX_ANIMATION +static void ResetGfxFrame(int x, int y, boolean redraw) { - GfxRandom[x][y] = INIT_GFX_RANDOM(); + int element = Feld[x][y]; + int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + int last_gfx_frame = GfxFrame[x][y]; + + if (graphic_info[graphic].anim_global_sync) + GfxFrame[x][y] = FrameCounter; + else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) + GfxFrame[x][y] = CustomValue[x][y]; + else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) + GfxFrame[x][y] = element_info[element].collect_score; + else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) + GfxFrame[x][y] = ChangeDelay[x][y]; + + if (redraw && GfxFrame[x][y] != last_gfx_frame) + DrawLevelGraphicAnimation(x, y, graphic); } +#endif static void ResetGfxAnimation(int x, int y) { @@ -2957,9 +3136,9 @@ static void ResetGfxAnimation(int x, int y) int element, graphic; #endif - GfxFrame[x][y] = 0; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MovDir[x][y]; + GfxFrame[x][y] = 0; #if 0 element = Feld[x][y]; @@ -2971,9 +3150,20 @@ static void ResetGfxAnimation(int x, int y) GfxFrame[x][y] = CustomValue[x][y]; else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) GfxFrame[x][y] = element_info[element].collect_score; + else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) + GfxFrame[x][y] = ChangeDelay[x][y]; +#endif + +#if USE_GFX_RESET_GFX_ANIMATION + ResetGfxFrame(x, y, FALSE); #endif } +static void ResetRandomAnimationValue(int x, int y) +{ + GfxRandom[x][y] = INIT_GFX_RANDOM(); +} + void InitMovingField(int x, int y, int direction) { int element = Feld[x][y]; @@ -3002,6 +3192,8 @@ void InitMovingField(int x, int y, int direction) GfxFrame[x][y] = CustomValue[x][y]; else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) GfxFrame[x][y] = element_info[element].collect_score; + else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) + GfxFrame[x][y] = ChangeDelay[x][y]; #endif /* this is needed for CEs with property "can move" / "not moving" */ @@ -4320,12 +4512,25 @@ static void ToggleSwitchgateSwitch(int x, int y) { int element = Feld[xx][yy]; +#if !USE_BOTH_SWITCHGATE_SWITCHES if (element == EL_SWITCHGATE_SWITCH_UP || element == EL_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; DrawLevelField(xx, yy); } +#else + if (element == EL_SWITCHGATE_SWITCH_UP) + { + Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN; + DrawLevelField(xx, yy); + } + else if (element == EL_SWITCHGATE_SWITCH_DOWN) + { + Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP; + DrawLevelField(xx, yy); + } +#endif else if (element == EL_SWITCHGATE_OPEN || element == EL_SWITCHGATE_OPENING) { @@ -5631,7 +5836,7 @@ inline static void TurnRoundExt(int x, int y) static void TurnRound(int x, int y) { int direction = MovDir[x][y]; -#if 1 +#if 0 int element, graphic; #endif @@ -5646,6 +5851,8 @@ static void TurnRound(int x, int y) GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction); #if 1 + ResetGfxFrame(x, y, FALSE); +#else element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); @@ -5655,6 +5862,8 @@ static void TurnRound(int x, int y) GfxFrame[x][y] = CustomValue[x][y]; else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) GfxFrame[x][y] = element_info[element].collect_score; + else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) + GfxFrame[x][y] = ChangeDelay[x][y]; #endif } @@ -5705,7 +5914,12 @@ void StartMoving(int x, int y) started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_EMPTYING; +#if USE_QUICKSAND_BD_ROCK_BUGFIX + if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK) + Store[x][y] = EL_ROCK; +#else Store[x][y] = EL_ROCK; +#endif PlayLevelSoundAction(x, y, ACTION_EMPTYING); } @@ -7648,7 +7862,8 @@ void MauerAbleger(int ax, int ay) if (element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_ANY || - element == EL_EXPANDABLE_WALL) + element == EL_EXPANDABLE_WALL || + element == EL_BD_EXPANDABLE_WALL) { if (links_frei) { @@ -7830,6 +8045,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; + int target_element = change->target_element; int action_type = change->action_type; int action_mode = change->action_mode; int action_arg = change->action_arg; @@ -7868,21 +8084,21 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_type == CA_SET_LEVEL_GEMS ? 999 : action_type == CA_SET_LEVEL_TIME ? 9999 : action_type == CA_SET_LEVEL_SCORE ? 99999 : - action_type == CA_SET_CE_SCORE ? 9999 : action_type == CA_SET_CE_VALUE ? 9999 : + action_type == CA_SET_CE_SCORE ? 9999 : CA_ARG_MAX); int action_arg_number_reset = - (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize : + (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize[0] : action_type == CA_SET_LEVEL_GEMS ? level.gems_needed : action_type == CA_SET_LEVEL_TIME ? level.time : action_type == CA_SET_LEVEL_SCORE ? 0 : - action_type == CA_SET_CE_SCORE ? 0 : #if 1 - action_type == CA_SET_CE_VALUE ? GET_NEW_CUSTOM_VALUE(element) : + action_type == CA_SET_CE_VALUE ? GET_NEW_CE_VALUE(element) : #else action_type == CA_SET_CE_VALUE ? ei->custom_value_initial : #endif + action_type == CA_SET_CE_SCORE ? 0 : 0); int action_arg_number = @@ -7893,18 +8109,20 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min : action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max : action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset : - action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : #if USE_NEW_CUSTOM_VALUE action_arg == CA_ARG_NUMBER_CE_VALUE ? CustomValue[x][y] : #else action_arg == CA_ARG_NUMBER_CE_VALUE ? ei->custom_value_initial : #endif + 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_ELEMENT_CV_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) : + 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_CS_TARGET ? GET_CE_SCORE(target_element) : + action_arg == CA_ARG_ELEMENT_CS_TRIGGER ? change->actual_trigger_ce_score: action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element : action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element : -1); @@ -7913,8 +8131,8 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) (action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed : action_type == CA_SET_LEVEL_TIME ? TimeLeft : action_type == CA_SET_LEVEL_SCORE ? local_player->score : - action_type == CA_SET_CE_SCORE ? ei->collect_score : action_type == CA_SET_CE_VALUE ? CustomValue[x][y] : + action_type == CA_SET_CE_SCORE ? ei->collect_score : 0); int action_arg_number_new = @@ -7997,6 +8215,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } +#if !USE_PLAYER_GRAVITY case CA_SET_LEVEL_GRAVITY: { game.gravity = (action_arg == CA_ARG_GRAVITY_OFF ? FALSE : @@ -8005,6 +8224,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) game.gravity); break; } +#endif case CA_SET_LEVEL_WIND: { @@ -8091,6 +8311,10 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE : CA_MODE_MULTIPLY); } + else if (action_arg == CA_ARG_NUMBER_RESET) + { + action_arg_number = level.initial_player_stepsize[i]; + } move_stepsize = getModifiedActionNumber(move_stepsize, @@ -8143,6 +8367,25 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } +#if USE_PLAYER_GRAVITY + case CA_SET_PLAYER_GRAVITY: + { + for (i = 0; i < MAX_PLAYERS; i++) + { + if (trigger_player_bits & (1 << i)) + { + stored_player[i].gravity = + (action_arg == CA_ARG_GRAVITY_OFF ? FALSE : + action_arg == CA_ARG_GRAVITY_ON ? TRUE : + action_arg == CA_ARG_GRAVITY_TOGGLE ? !stored_player[i].gravity : + stored_player[i].gravity); + } + } + + break; + } +#endif + case CA_SET_PLAYER_ARTWORK: { for (i = 0; i < MAX_PLAYERS; i++) @@ -8175,37 +8418,95 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) /* ---------- CE actions ---------------------------------------------- */ - case CA_SET_CE_SCORE: + case CA_SET_CE_VALUE: { - ei->collect_score = action_arg_number_new; +#if USE_NEW_CUSTOM_VALUE + int last_ce_value = CustomValue[x][y]; + + CustomValue[x][y] = action_arg_number_new; + +#if 0 + printf("::: CE value == %d\n", CustomValue[x][y]); +#endif + + if (CustomValue[x][y] != last_ce_value) + { + CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_CHANGES); + CheckTriggeredElementChange(x, y, element, CE_VALUE_CHANGES_OF_X); + + if (CustomValue[x][y] == 0) + { +#if 0 + printf("::: CE_VALUE_GETS_ZERO\n"); +#endif + + CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO); + CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X); + +#if 0 + printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]); +#endif + } + } + +#endif break; } - case CA_SET_CE_VALUE: + case CA_SET_CE_SCORE: { #if USE_NEW_CUSTOM_VALUE - int last_custom_value = CustomValue[x][y]; + int last_ce_score = ei->collect_score; - CustomValue[x][y] = action_arg_number_new; + ei->collect_score = action_arg_number_new; #if 0 - printf("::: Count == %d\n", CustomValue[x][y]); + printf("::: CE score == %d\n", ei->collect_score); #endif - if (CustomValue[x][y] == 0 && last_custom_value > 0) + if (ei->collect_score != last_ce_score) { + CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_CHANGES); + CheckTriggeredElementChange(x, y, element, CE_SCORE_CHANGES_OF_X); + + if (ei->collect_score == 0) + { + int xx, yy; + #if 0 - printf("::: CE_VALUE_GETS_ZERO\n"); + printf("::: CE_SCORE_GETS_ZERO\n"); #endif - CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO); - CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X); + CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO); + CheckTriggeredElementChange(x, y, element, CE_SCORE_GETS_ZERO_OF_X); #if 0 - printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]); + printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]); #endif + +#if 1 + /* + This is a very special case that seems to be a mixture between + CheckElementChange() and CheckTriggeredElementChange(): while + the first one only affects single elements that are triggered + directly, the second one affects multiple elements in the playfield + that are triggered indirectly by another element. This is a third + case: Changing the CE score always affects multiple identical CEs, + so every affected CE must be checked, not only the single CE for + which the CE score was changed in the first place (as every instance + of that CE shares the same CE score, and therefore also can change)! + */ + SCAN_PLAYFIELD(xx, yy) + { + if (Feld[xx][yy] == element) + CheckElementChange(xx, yy, element, EL_UNDEFINED, + CE_SCORE_GETS_ZERO); + } +#endif + } } + #endif break; @@ -8227,54 +8528,87 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) static void CreateFieldExt(int x, int y, int element, boolean is_change) { + int old_element = Feld[x][y]; + int new_element = get_element_from_group_element(element); int previous_move_direction = MovDir[x][y]; #if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; #endif - boolean add_player = (ELEM_IS_PLAYER(element) && - IS_WALKABLE(Feld[x][y])); + boolean new_element_is_player = ELEM_IS_PLAYER(new_element); + boolean add_player_onto_element = (new_element_is_player && +#if USE_CODE_THAT_BREAKS_SNAKE_BITE + /* this breaks SnakeBite when a snake is + halfway through a door that closes */ + /* NOW FIXED AT LEVEL INIT IN files.c */ + new_element != EL_SOKOBAN_FIELD_PLAYER && +#endif + IS_WALKABLE(old_element)); - /* check if element under player changes from accessible to unaccessible +#if 0 + /* check if element under the player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && - IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(element)) + IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { Bang(x, y); return; } +#endif - if (!add_player) + if (!add_player_onto_element) { if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) RemoveMovingField(x, y); else RemoveField(x, y); - Feld[x][y] = element; + Feld[x][y] = new_element; +#if !USE_GFX_RESET_GFX_ANIMATION ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); +#endif - if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS) + if (element_info[new_element].move_direction_initial == MV_START_PREVIOUS) MovDir[x][y] = previous_move_direction; #if USE_NEW_CUSTOM_VALUE - if (element_info[Feld[x][y]].use_last_ce_value) + if (element_info[new_element].use_last_ce_value) CustomValue[x][y] = last_ce_value; #endif InitField_WithBug1(x, y, FALSE); + new_element = Feld[x][y]; /* element may have changed */ + +#if USE_GFX_RESET_GFX_ANIMATION + ResetGfxAnimation(x, y); + ResetRandomAnimationValue(x, y); +#endif + DrawLevelField(x, y); - if (GFX_CRUMBLED(Feld[x][y])) + if (GFX_CRUMBLED(new_element)) DrawLevelFieldCrumbledSandNeighbours(x, y); } +#if 1 + /* check if element under the player changes from accessible to unaccessible + (needed for special case of dropping element which then changes) */ + /* (must be checked after creating new element for walkable group elements) */ + if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && + IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) + { + Bang(x, y); + + return; + } +#endif + /* "ChangeCount" not set yet to allow "entered by player" change one time */ - if (ELEM_IS_PLAYER(element)) - RelocatePlayer(x, y, element); + if (new_element_is_player) + RelocatePlayer(x, y, new_element); if (is_change) ChangeCount[x][y]++; /* count number of changes in the same frame */ @@ -8311,7 +8645,10 @@ static void CreateElementFromChange(int x, int y, int element) static boolean ChangeElement(int x, int y, int element, int page) { - struct ElementChangeInfo *change = &element_info[element].change_page[page]; + struct ElementInfo *ei = &element_info[element]; + struct ElementChangeInfo *change = &ei->change_page[page]; + int ce_value = CustomValue[x][y]; + int ce_score = ei->collect_score; int target_element; int old_element = Feld[x][y]; @@ -8326,6 +8663,7 @@ static boolean ChangeElement(int x, int y, int element, int page) change->actual_trigger_player = EL_PLAYER_1; change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; + change->actual_trigger_ce_score = 0; } /* do not change elements more than a specified maximum number of changes */ @@ -8430,7 +8768,8 @@ static boolean ChangeElement(int x, int y, int element, int page) ChangeEvent[ex][ey] = ChangeEvent[x][y]; content_element = change->target_content.e[xx][yy]; - target_element = GET_TARGET_ELEMENT(content_element, change); + target_element = GET_TARGET_ELEMENT(element, content_element, change, + ce_value, ce_score); CreateElementFromChange(ex, ey, target_element); @@ -8451,7 +8790,8 @@ static boolean ChangeElement(int x, int y, int element, int page) } else { - target_element = GET_TARGET_ELEMENT(change->target_element, change); + target_element = GET_TARGET_ELEMENT(element, change->target_element, change, + ce_value, ce_score); if (element == EL_DIAGONAL_GROWING || element == EL_DIAGONAL_SHRINKING) @@ -8685,6 +9025,7 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y]; + change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); if ((change->can_change && !change_done) || change->has_action) { @@ -8789,6 +9130,7 @@ static boolean CheckElementChangeExt(int x, int y, change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[x][y]; + change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); /* special case: trigger element not at (x,y) position for some events */ if (check_trigger_element) @@ -8811,6 +9153,7 @@ static boolean CheckElementChangeExt(int x, int y, int yy = y + move_xy[MV_DIR_OPPOSITE(trigger_side)].dy; change->actual_trigger_ce_value = CustomValue[xx][yy]; + change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); } if (change->can_change && !change_done) @@ -9168,6 +9511,11 @@ void AdvanceFrameAndPlayerCounters(int player_nr) { int i; +#if 0 + Error(ERR_NETWORK_CLIENT, "advancing frame counter from %d to %d", + FrameCounter, FrameCounter + 1); +#endif + /* advance frame counters (global frame counter and time frame counter) */ FrameCounter++; TimeFrames++; @@ -9218,15 +9566,10 @@ void AdvanceFrameAndPlayerCounters(int player_nr) void StartGameActions(boolean init_network_game, boolean record_tape, long random_seed) { -#if 1 unsigned long new_random_seed = InitRND(random_seed); if (record_tape) TapeStartRecording(new_random_seed); -#else - if (record_tape) - TapeStartRecording(random_seed); -#endif #if defined(NETWORK_AVALIABLE) if (init_network_game) @@ -9241,10 +9584,6 @@ void StartGameActions(boolean init_network_game, boolean record_tape, game_status = GAME_MODE_PLAYING; -#if 0 - InitRND(random_seed); -#endif - InitGame(); } @@ -9311,11 +9650,19 @@ void GameActions() if (!network_player_action_received) return; /* failed to get network player actions in time */ + + /* do not yet reset "network_player_action_received" (for tape.pausing) */ } if (tape.pausing) return; + /* at this point we know that we really continue executing the game */ + +#if 1 + network_player_action_received = FALSE; +#endif + recorded_player_action = (tape.playing ? TapePlayAction() : NULL); if (tape.set_centered_player) @@ -9383,6 +9730,10 @@ void GameActions_EM_Main() for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; +#if 0 + printf("::: %04d: %08x\n", FrameCounter, effective_action[0]); +#endif + GameActions_EM(effective_action, warp_mode); CheckLevelTime(); @@ -9483,7 +9834,9 @@ void GameActions_RND() ScrollPlayer(&stored_player[i], SCROLL_GO_ON); } +#if 0 network_player_action_received = FALSE; +#endif ScrollScreen(NULL, SCROLL_GO_ON); @@ -9611,6 +9964,9 @@ void GameActions_RND() printf("::: Yo man! Rocks can fall!\n"); #endif +#if 1 + ResetGfxFrame(x, y, TRUE); +#else if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) @@ -9635,6 +9991,18 @@ void GameActions_RND() #endif DrawLevelGraphicAnimation(x, y, graphic); } + else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) + { + int old_gfx_frame = GfxFrame[x][y]; + + GfxFrame[x][y] = ChangeDelay[x][y]; + +#if 1 + if (GfxFrame[x][y] != old_gfx_frame) +#endif + DrawLevelGraphicAnimation(x, y, graphic); + } +#endif if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(GfxFrame[x][y], graphic)) @@ -9736,7 +10104,8 @@ void GameActions_RND() else if (element == EL_EXPANDABLE_WALL || element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_VERTICAL || - element == EL_EXPANDABLE_WALL_ANY) + element == EL_EXPANDABLE_WALL_ANY || + element == EL_BD_EXPANDABLE_WALL) MauerAbleger(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); @@ -10081,11 +10450,15 @@ static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) static void CheckGravityMovement(struct PlayerInfo *player) { +#if USE_PLAYER_GRAVITY + if (player->gravity && !player->programmed_action) +#else if (game.gravity && !player->programmed_action) +#endif { int move_dir_horizontal = player->effective_action & MV_HORIZONTAL; int move_dir_vertical = player->effective_action & MV_VERTICAL; - boolean player_is_snapping = player->effective_action & JOY_BUTTON_1; + boolean player_is_snapping = (player->effective_action & JOY_BUTTON_1); int jx = player->jx, jy = player->jy; boolean player_is_moving_to_valid_field = (!player_is_snapping && @@ -10103,7 +10476,11 @@ static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player) { return CheckGravityMovement(player); +#if USE_PLAYER_GRAVITY + if (player->gravity && !player->programmed_action) +#else if (game.gravity && !player->programmed_action) +#endif { int jx = player->jx, jy = player->jy; boolean field_under_player_is_free = @@ -10304,6 +10681,8 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->move_delay_value = original_move_delay_value; } + player->is_active = FALSE; + if (player->last_move_dir & MV_HORIZONTAL) { if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy))) @@ -10315,6 +10694,17 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) moved |= MovePlayerOneStep(player, 0, dy, dx, dy); } +#if USE_FIXED_BORDER_RUNNING_GFX + if (!moved && !player->is_active) + { + player->is_moving = FALSE; + player->is_digging = FALSE; + player->is_collecting = FALSE; + player->is_snapping = FALSE; + player->is_pushing = FALSE; + } +#endif + jx = player->jx; jy = player->jy; @@ -10486,8 +10876,13 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) last_field_block_delay += player->move_delay_value; /* when blocking enabled, prevent moving up despite gravity */ +#if USE_PLAYER_GRAVITY + if (player->gravity && player->MovDir == MV_UP) + block_delay_adjustment = -1; +#else if (game.gravity && player->MovDir == MV_UP) block_delay_adjustment = -1; +#endif } /* add block delay adjustment (also possible when not blocking) */ @@ -11409,6 +11804,8 @@ int DigField(struct PlayerInfo *player, game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; + /* checking here causes player to move into acid even if the current field + cannot be left to that direction */ #if 0 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) @@ -11430,6 +11827,43 @@ int DigField(struct PlayerInfo *player, #endif #endif +#if 1 /* ------------------------------ NEW ------------------------------ */ + + if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction)) + return MP_NO_ACTION; /* field has no opening in this direction */ + + if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) + return MP_NO_ACTION; /* field has no opening in this direction */ + +#if USE_FIXED_DONT_RUN_INTO + if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) + { + SplashAcid(x, y); +#if 1 + Feld[jx][jy] = player->artwork_element; +#else + Feld[jx][jy] = EL_PLAYER_1; +#endif + InitMovingField(jx, jy, MV_DOWN); + Store[jx][jy] = EL_ACID; + ContinueMoving(jx, jy); + BuryPlayer(player); + + return MP_DONT_RUN_INTO; + } +#endif + +#if USE_FIXED_DONT_RUN_INTO + if (player_can_move && DONT_RUN_INTO(element)) + { + TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); + + return MP_DONT_RUN_INTO; + } +#endif + +#else /* ------------------------------ OLD ------------------------------ */ + #if 1 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) @@ -11447,6 +11881,7 @@ int DigField(struct PlayerInfo *player, if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) return MP_NO_ACTION; /* field has no opening in this direction */ + /* checking here causes player to explode when moving into acid */ #if 1 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) @@ -11463,6 +11898,8 @@ int DigField(struct PlayerInfo *player, #endif #endif +#endif /* ------------------------------ END ------------------------------ */ + #if 0 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) @@ -11515,10 +11952,17 @@ int DigField(struct PlayerInfo *player, return MP_NO_ACTION; } +#if USE_PLAYER_GRAVITY + if (player->gravity && is_player && !player->is_auto_moving && + canFallDown(player) && move_direction != MV_DOWN && + !canMoveToValidFieldWithGravity(jx, jy, move_direction)) + return MP_NO_ACTION; /* player cannot walk here due to gravity */ +#else if (game.gravity && is_player && !player->is_auto_moving && canFallDown(player) && move_direction != MV_DOWN && !canMoveToValidFieldWithGravity(jx, jy, move_direction)) return MP_NO_ACTION; /* player cannot walk here due to gravity */ +#endif if (player_can_move && IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) @@ -11582,23 +12026,50 @@ int DigField(struct PlayerInfo *player, if (!player->key[EM_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } + else if (IS_EMC_GATE(element)) + { + if (!player->key[EMC_GATE_NR(element)]) + return MP_NO_ACTION; + } + else if (IS_EMC_GATE_GRAY(element)) + { + if (!player->key[EMC_GATE_GRAY_NR(element)]) + return MP_NO_ACTION; + } + else if (IS_EMC_GATE_GRAY_ACTIVE(element)) + { + if (!player->key[EMC_GATE_GRAY_ACTIVE_NR(element)]) + return MP_NO_ACTION; + } else if (IS_SP_PORT(element)) { if (element == EL_SP_GRAVITY_PORT_LEFT || element == EL_SP_GRAVITY_PORT_RIGHT || element == EL_SP_GRAVITY_PORT_UP || element == EL_SP_GRAVITY_PORT_DOWN) +#if USE_PLAYER_GRAVITY + player->gravity = !player->gravity; +#else game.gravity = !game.gravity; +#endif else if (element == EL_SP_GRAVITY_ON_PORT_LEFT || element == EL_SP_GRAVITY_ON_PORT_RIGHT || element == EL_SP_GRAVITY_ON_PORT_UP || element == EL_SP_GRAVITY_ON_PORT_DOWN) +#if USE_PLAYER_GRAVITY + player->gravity = TRUE; +#else game.gravity = TRUE; +#endif else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT || element == EL_SP_GRAVITY_OFF_PORT_RIGHT || element == EL_SP_GRAVITY_OFF_PORT_UP || element == EL_SP_GRAVITY_OFF_PORT_DOWN) +#if USE_PLAYER_GRAVITY + player->gravity = FALSE; +#else game.gravity = FALSE; +#endif } /* automatically move to the next field with double speed */ @@ -11818,6 +12289,7 @@ int DigField(struct PlayerInfo *player, } player->is_pushing = TRUE; + player->is_active = TRUE; if (!(IN_LEV_FIELD(nextx, nexty) && (IS_FREE(nextx, nexty) || @@ -12070,7 +12542,10 @@ int DigField(struct PlayerInfo *player, if (is_player) /* function can also be called by EL_PENGUIN */ { if (Feld[x][y] != element) /* really digged/collected something */ + { player->is_collecting = !player->is_digging; + player->is_active = TRUE; + } } return MP_MOVING; @@ -12139,6 +12614,7 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) return FALSE; player->is_snapping = TRUE; + player->is_active = TRUE; if (player->MovPos == 0) { @@ -12673,7 +13149,7 @@ void RequestQuitGame(boolean ask_if_really_quit) { #if defined(NETWORK_AVALIABLE) if (options.network) - SendToServer_StopPlaying(); + SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER); else #endif { @@ -12850,7 +13326,10 @@ static void HandleGameButtons(struct GadgetInfo *gi) switch (id) { case GAME_CTRL_ID_STOP: - RequestQuitGame(TRUE); + if (tape.playing) + TapeStop(); + else + RequestQuitGame(TRUE); break; case GAME_CTRL_ID_PAUSE: @@ -12877,7 +13356,7 @@ static void HandleGameButtons(struct GadgetInfo *gi) #endif { tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); + DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0); } } break;