X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=1c606b528b6888d76720480a64b8cd0c9c8447cd;hp=dd8af0d3679aa16450f8a65fac907bd7aadab7ee;hb=ff9566324863d1ba0a72478982fe9c2b4ff3dd88;hpb=d31107293214cf22c06b58465923e29f3a64e73b diff --git a/src/game.c b/src/game.c index dd8af0d3..1c606b52 100644 --- a/src/game.c +++ b/src/game.c @@ -21,38 +21,17 @@ #include "tape.h" #include "network.h" -/* this switch controls how rocks move horizontally */ -#define OLD_GAME_BEHAVIOUR FALSE - /* EXPERIMENTAL STUFF */ #define USE_NEW_AMOEBA_CODE FALSE /* EXPERIMENTAL STUFF */ -#define USE_NEW_STUFF (TRUE * 1) - -#define USE_NEW_MOVE_STYLE (TRUE * USE_NEW_STUFF * 1) -#define USE_NEW_MOVE_DELAY (TRUE * USE_NEW_STUFF * 1) -#define USE_NEW_PUSH_DELAY (TRUE * USE_NEW_STUFF * 1) -#define USE_NEW_BLOCK_STYLE (TRUE * USE_NEW_STUFF * 1) -#define USE_NEW_SP_SLIPPERY (TRUE * USE_NEW_STUFF * 1) -#define USE_NEW_RANDOMIZE (TRUE * USE_NEW_STUFF * 1) - -#define USE_CAN_MOVE_NOT_MOVING (TRUE * USE_NEW_STUFF * 1) -#define USE_PREVIOUS_MOVE_DIR (TRUE * USE_NEW_STUFF * 1) - -#define USE_PUSH_BUGFIX (TRUE * USE_NEW_STUFF * 1) -#if 0 -#define USE_BLOCK_DELAY_BUGFIX (TRUE * USE_NEW_STUFF * 1) -#endif -#define USE_GRAVITY_BUGFIX_NEW (TRUE * USE_NEW_STUFF * 1) -#define USE_GRAVITY_BUGFIX_OLD (TRUE * USE_NEW_STUFF * 0) - -#define USE_PENGUIN_COLLECT_BUGFIX (TRUE * USE_NEW_STUFF * 1) - -#define USE_IMPACT_BUGFIX (TRUE * USE_NEW_STUFF * 1) +#define USE_NEW_STUFF ( * 1) -#define USE_HITTING_SOMETHING_BUGFIX (TRUE * USE_NEW_STUFF * 1) -#define USE_HIT_BY_SOMETHING_BUGFIX (TRUE * USE_NEW_STUFF * 1) +#define USE_NEW_SP_SLIPPERY (USE_NEW_STUFF * 1) +#define USE_NEW_COLLECT_COUNT (USE_NEW_STUFF * 1) +#define USE_NEW_PLAYER_ANIM (USE_NEW_STUFF * 1) +#define USE_NEW_ALL_SLIPPERY (USE_NEW_STUFF * 1) +#define USE_NEW_PLAYER_SPEED (USE_NEW_STUFF * 1) /* for DigField() */ @@ -113,16 +92,25 @@ #define INITIAL_MOVE_DELAY_ON 0 /* values for player movement speed (which is in fact a delay value) */ +#define MOVE_DELAY_MIN_SPEED 32 #define MOVE_DELAY_NORMAL_SPEED 8 #define MOVE_DELAY_HIGH_SPEED 4 +#define MOVE_DELAY_MAX_SPEED 1 +#if 0 #define DOUBLE_MOVE_DELAY(x) (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x)) #define HALVE_MOVE_DELAY(x) (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x)) +#else +#define DOUBLE_MOVE_DELAY(x) (x = (x < MOVE_DELAY_MIN_SPEED ? x * 2 : x)) +#define HALVE_MOVE_DELAY(x) (x = (x > MOVE_DELAY_MAX_SPEED ? x / 2 : x)) +#endif #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY((p)->move_delay_value)) #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) /* values for other actions */ #define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED) +#define MOVE_STEPSIZE_MIN (1) +#define MOVE_STEPSIZE_MAX (TILEX) #define GET_DX_FROM_DIR(d) ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0) #define GET_DY_FROM_DIR(d) ((d) == MV_UP ? -1 : (d) == MV_DOWN ? 1 : 0) @@ -137,6 +125,8 @@ 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_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \ + RND((c)->delay_random * (c)->delay_frames)) #define GET_TARGET_ELEMENT(e, ch) \ ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ @@ -173,35 +163,15 @@ IS_PLAYER(x, y) && \ !PLAYER_ENEMY_PROTECTED(x, y)))) -#if 0 -#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \ - (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (condition) || \ - (DONT_COLLIDE_WITH(e) && \ - IS_PLAYER(x, y) && \ - !PLAYER_ENEMY_PROTECTED(x, y)))) -#endif - #define ELEMENT_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0) -#if 1 #define SATELLITE_CAN_ENTER_FIELD(x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0) -#else -#define SATELLITE_CAN_ENTER_FIELD(x, y) \ - ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, Feld[x][y] == EL_ACID) -#endif - -#if 0 -#define ENEMY_CAN_ENTER_FIELD(e, x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y)) -#endif #define ENEMY_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) -#if 1 - #define YAMYAM_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND) @@ -226,57 +196,6 @@ #define SPRING_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) -#else - -#define YAMYAM_CAN_ENTER_FIELD(e, x, y) \ - (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID) || \ - Feld[x][y] == EL_DIAMOND)) - -#define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \ - (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID) || \ - IS_FOOD_DARK_YAMYAM(Feld[x][y]))) - -#define PACMAN_CAN_ENTER_FIELD(e, x, y) \ - (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID) || \ - IS_AMOEBOID(Feld[x][y]))) - -#define PIG_CAN_ENTER_FIELD(e, x, y) \ - (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID) || \ - IS_FOOD_PIG(Feld[x][y]))) - -#define PENGUIN_CAN_ENTER_FIELD(e, x, y) \ - (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID) || \ - IS_FOOD_PENGUIN(Feld[x][y]) || \ - Feld[x][y] == EL_EXIT_OPEN)) - -#define DRAGON_CAN_ENTER_FIELD(e, x, y) \ - (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID))) - -#define MOLE_CAN_ENTER_FIELD(e, x, y, condition) \ - (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID) || \ - (condition))) - -#define SPRING_CAN_ENTER_FIELD(e, x, y) \ - (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID))) - -#endif - #define GROUP_NR(e) ((e) - EL_GROUP_START) #define MOVE_ENTER_EL(e) (element_info[e].move_enter_element) #define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE) @@ -285,16 +204,9 @@ #define IS_EQUAL_OR_IN_GROUP(e, ge) \ (IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge)) -#if 0 -#define CE_ENTER_FIELD_COND(e, x, y) \ - (!IS_PLAYER(x, y) && \ - (Feld[x][y] == EL_ACID || \ - IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))) -#else #define CE_ENTER_FIELD_COND(e, x, y) \ (!IS_PLAYER(x, y) && \ IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e))) -#endif #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y)) @@ -333,8 +245,8 @@ static void InitBeltMovement(void); static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *); -static void KillHeroUnlessEnemyProtected(int, int); -static void KillHeroUnlessExplosionProtected(int, int); +static void KillPlayerUnlessEnemyProtected(int, int); +static void KillPlayerUnlessExplosionProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); @@ -345,27 +257,23 @@ static void TestIfElementSmashesCustomElement(int, int, int); static void ChangeElement(int, int, int); -static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int); -#define CheckTriggeredElementChange(x, y, e, ev) \ - CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, \ - CH_SIDE_ANY, -1) -#define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s) \ - CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1) -#define CheckTriggeredElementChangeBySide(x, y, e, ev, s) \ - CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1) -#define CheckTriggeredElementChangeByPage(x, y, e, ev, p) \ - CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, \ - CH_SIDE_ANY, p) - -static boolean CheckElementChangeExt(int, int, int, int, int, int, int, int); +static boolean CheckTriggeredElementChangeExt(int, int, int,int,int); +#define CheckTriggeredElementChange(e, ev) \ + CheckTriggeredElementChangeExt(e, ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1) +#define CheckTriggeredElementChangeByPlayer(e, ev, p, s) \ + CheckTriggeredElementChangeExt(e, ev, p, s, -1) +#define CheckTriggeredElementChangeBySide(e, ev, s) \ + CheckTriggeredElementChangeExt(e, ev, CH_PLAYER_ANY, s, -1) +#define CheckTriggeredElementChangeByPage(e, ev, p) \ + CheckTriggeredElementChangeExt(e, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p) + +static boolean CheckElementChangeExt(int, int, int, int, int, int, int); #define CheckElementChange(x, y, e, te, ev) \ - CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1) + CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY) #define CheckElementChangeByPlayer(x, y, e, ev, p, s) \ - CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s, CH_PAGE_ANY) + CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s) #define CheckElementChangeBySide(x, y, e, te, ev, s) \ - CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s, CH_PAGE_ANY) -#define CheckElementChangeByPage(x, y, e, te, ev, p) \ - CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p) + CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s) static void PlayLevelSound(int, int, int); static void PlayLevelSoundNearest(int, int, int); @@ -790,9 +698,6 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) level.sp_block_last_field : level.block_last_field); -#if USE_NEW_BLOCK_STYLE -#if 1 - /* ---------- initialize player's last field block delay --------------- */ /* always start with reliable default value (no adjustment needed) */ @@ -806,49 +711,6 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) if (game.use_block_last_field_bug) player->block_delay_adjustment = (player->block_last_field ? -1 : 1); -#if 0 - /* blocking the last field when moving was corrected in version 3.1.1 */ - if (game.use_block_last_field_bug) - { - /* even "not blocking" was blocking the last field for one frame */ - level.block_delay = (level.block_last_field ? 7 : 1); - level.sp_block_delay = (level.sp_block_last_field ? 7 : 1); - - level.block_last_field = TRUE; - level.sp_block_last_field = TRUE; - } -#endif - -#if 0 /* !!! THIS IS NOT A LEVEL SETTING => REMOVED !!! */ - level.block_delay = 8; /* when blocking, block 8 frames */ - level.sp_block_delay = 9; /* SP indeed blocks 9 frames, not 8 */ -#endif - -#if 0 - printf("::: %d, %d\n", level.block_delay, level.sp_block_delay); -#endif - -#else - -#if 1 - player->block_delay = (player->block_last_field ? - (element == EL_SP_MURPHY ? - level.sp_block_delay : - level.block_delay) : 0); -#else - player->block_delay = (element == EL_SP_MURPHY ? - (player->block_last_field ? 7 : 1) : - (player->block_last_field ? 7 : 1)); -#endif - -#endif - -#if 0 - printf("::: block_last_field == %d, block_delay = %d\n", - player->block_last_field, player->block_delay); -#endif -#endif - if (!options.network || player->connected) { player->active = TRUE; @@ -987,27 +849,6 @@ static void InitField(int x, int y, boolean init_game) GfxDir[x][y] = MovDir[x][y] = 1 << RND(4); break; -#if 0 - case EL_SP_EMPTY: - Feld[x][y] = EL_EMPTY; - break; -#endif - -#if 0 - case EL_EM_KEY_1_FILE: - Feld[x][y] = EL_EM_KEY_1; - break; - case EL_EM_KEY_2_FILE: - Feld[x][y] = EL_EM_KEY_2; - break; - case EL_EM_KEY_3_FILE: - Feld[x][y] = EL_EM_KEY_3; - break; - case EL_EM_KEY_4_FILE: - Feld[x][y] = EL_EM_KEY_4; - break; -#endif - case EL_CONVEYOR_BELT_1_SWITCH_LEFT: case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_1_SWITCH_RIGHT: @@ -1075,6 +916,10 @@ static void InitField(int x, int y, boolean init_game) } break; } + +#if USE_NEW_COLLECT_COUNT + Count[x][y] = element_info[Feld[x][y]].collect_count_initial; +#endif } static inline void InitField_WithBug1(int x, int y, boolean init_game) @@ -1124,9 +969,15 @@ inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) /* currently only 4 of 8 possible keys are displayed */ for (i = 0; i < STD_NUM_KEYS; i++) + { if (key[i]) DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS, el2edimg(EL_KEY_1 + i)); + else + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, + DOOR_GFX_PAGEX5 + XX_KEYS + i * MINI_TILEX, YY_KEYS, + MINI_TILEX, MINI_TILEY, DX_KEYS + i * MINI_TILEX, DY_KEYS); + } } inline void DrawGameValue_Score(int value) @@ -1249,17 +1100,6 @@ static void resolve_group_element(int group_element, int recursion_depth) element_info[element].in_group[group_nr] = TRUE; } } - -#if 0 - if (recursion_depth == 0 && group_element <= EL_GROUP_4) - { - printf("::: group %d: %d resolved elements\n", - group_element - EL_GROUP_START, group->num_elements_resolved); - for (i = 0; i < group->num_elements_resolved; i++) - printf("::: - %d ['%s']\n", group->element_resolved[i], - element_info[group->element_resolved[i]].token_name); - } -#endif } @@ -1369,7 +1209,6 @@ static void InitGameEngine() /* ---------- initialize player's initial move delay --------------------- */ -#if USE_NEW_MOVE_DELAY /* dynamically adjust player properties according to level information */ game.initial_move_delay_value = (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED); @@ -1377,16 +1216,6 @@ static void InitGameEngine() /* 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); -#else - /* dynamically adjust player properties according to game engine version */ - game.initial_move_delay = - (game.engine_version <= VERSION_IDENT(2,0,1,0) ? INITIAL_MOVE_DELAY_ON : - INITIAL_MOVE_DELAY_OFF); - - /* dynamically adjust player properties according to level information */ - game.initial_move_delay_value = - (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED); -#endif /* ---------- initialize player's initial push delay --------------------- */ @@ -1436,12 +1265,24 @@ static void InitGameEngine() ei->has_change_event[CE_DELAY] = TRUE; -#if 1 SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE); -#endif + SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE); + } + + /* ---------- initialize internal run-time variables ------------- */ + + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; + + for (j = 0; j < ei->num_change_pages; j++) + { + ei->change_page[j].can_change_or_has_action = + (ei->change_page[j].can_change | + ei->change_page[j].has_action); + } } -#if 1 /* add change events from custom element configuration */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { @@ -1449,7 +1290,7 @@ static void InitGameEngine() for (j = 0; j < ei->num_change_pages; j++) { - if (!ei->change_page[j].can_change) + if (!ei->change_page[j].can_change_or_has_action) continue; for (k = 0; k < NUM_CHANGE_EVENTS; k++) @@ -1466,19 +1307,6 @@ static void InitGameEngine() } } -#else - - /* add change events from custom element configuration */ - for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) - { - int element = EL_CUSTOM_START + i; - - /* only add custom elements that change after fixed/random frame delay */ - if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY)) - element_info[element].has_change_event[CE_DELAY] = TRUE; - } -#endif - /* ---------- initialize run-time trigger player and element ------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) @@ -1499,7 +1327,6 @@ static void InitGameEngine() for (j = 0; j < NUM_CHANGE_EVENTS; j++) trigger_events[i][j] = FALSE; -#if 1 /* add trigger events from element change event properties */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { @@ -1507,7 +1334,7 @@ static void InitGameEngine() for (j = 0; j < ei->num_change_pages; j++) { - if (!ei->change_page[j].can_change) + if (!ei->change_page[j].can_change_or_has_action) continue; if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION]) @@ -1533,14 +1360,6 @@ static void InitGameEngine() } } } -#else - /* add trigger events from element change event properties */ - for (i = 0; i < MAX_NUM_ELEMENTS; i++) - if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION)) - for (j = 0; j < NUM_CHANGE_EVENTS; j++) - if (element_info[i].change->has_event[j]) - trigger_events[element_info[i].change->trigger_element][j] = TRUE; -#endif /* ---------- initialize push delay -------------------------------------- */ @@ -1570,16 +1389,11 @@ static void InitGameEngine() { if (IS_SP_ELEMENT(i)) { -#if USE_NEW_MOVE_STYLE /* set SP push delay to just enough to push under a falling zonk */ int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6); element_info[i].push_delay_fixed = delay; element_info[i].push_delay_random = 0; -#else - element_info[i].push_delay_fixed = 6; /* just enough to escape ... */ - element_info[i].push_delay_random = 0; /* ... from falling zonk */ -#endif } } } @@ -1599,26 +1413,23 @@ static void InitGameEngine() element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize; } -#if 0 - /* ---------- initialize move dig/leave ---------------------------------- */ + /* ---------- initialize collect score ----------------------------------- */ + /* initialize collect score values for custom elements from initial value */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) - { - element_info[i].can_leave_element = FALSE; - element_info[i].can_leave_element_last = FALSE; - } -#endif + if (IS_CUSTOM_ELEMENT(i)) + element_info[i].collect_score = element_info[i].collect_score_initial; - /* ---------- initialize gem count --------------------------------------- */ + /* ---------- initialize collect count ----------------------------------- */ - /* initialize gem count values for each element */ + /* initialize collect count values for non-custom elements */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) - element_info[i].collect_count = 0; + element_info[i].collect_count_initial = 0; - /* add gem count values for all elements from pre-defined list */ + /* add collect count values for all elements from pre-defined list */ for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++) - element_info[collect_count_list[i].element].collect_count = + element_info[collect_count_list[i].element].collect_count_initial = collect_count_list[i].count; /* ---------- initialize access direction -------------------------------- */ @@ -1652,16 +1463,6 @@ void InitGame() InitGameEngine(); -#if 0 -#if DEBUG -#if USE_NEW_AMOEBA_CODE - printf("Using new amoeba code.\n"); -#else - printf("Using old amoeba code.\n"); -#endif -#endif -#endif - /* don't play tapes over network */ network_playing = (options.network && !tape.playing); @@ -1775,6 +1576,9 @@ void InitGame() player->switch_x = -1; player->switch_y = -1; + player->drop_x = -1; + player->drop_y = -1; + player->show_envelope = 0; player->move_delay = game.initial_move_delay; @@ -1782,13 +1586,8 @@ void InitGame() player->move_delay_reset_counter = 0; -#if USE_NEW_PUSH_DELAY player->push_delay = -1; /* initialized when pushing starts */ player->push_delay_value = game.initial_push_delay_value; -#else - player->push_delay = 0; - player->push_delay_value = game.initial_push_delay_value; -#endif player->drop_delay = 0; @@ -1862,6 +1661,9 @@ void InitGame() MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; +#if USE_NEW_COLLECT_COUNT + Count[x][y] = 0; /* initialized in InitField() */ +#endif Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0; AmoebaNr[x][y] = 0; WasJustMoving[x][y] = 0; @@ -1909,6 +1711,26 @@ void InitGame() emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); +#if USE_NEW_ALL_SLIPPERY + /* initialize type of slippery elements */ + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + { + if (!IS_CUSTOM_ELEMENT(i)) + { + /* default: elements slip down either to the left or right randomly */ + element_info[i].slippery_type = SLIPPERY_ANY_RANDOM; + + /* SP style elements prefer to slip down on the left side */ + if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i)) + element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; + + /* BD style elements prefer to slip down on the left side */ + if (game.emulation == EMU_BOULDERDASH) + element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; + } + } +#endif + /* initialize explosion and ignition delay */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { @@ -1924,13 +1746,8 @@ void InitGame() element_info[i].explosion_delay = last_phase - 1; element_info[i].ignition_delay = half_phase; -#if 0 - if (i == EL_BLACK_ORB) - element_info[i].ignition_delay = 0; -#else if (i == EL_BLACK_ORB) element_info[i].ignition_delay = 1; -#endif } #if 0 @@ -1972,10 +1789,8 @@ void InitGame() player->element_nr = some_player->element_nr; #endif -#if USE_NEW_BLOCK_STYLE player->block_last_field = some_player->block_last_field; player->block_delay_adjustment = some_player->block_delay_adjustment; -#endif StorePlayer[jx][jy] = player->element_nr; player->jx = player->last_jx = jx; @@ -2155,7 +1970,6 @@ void InitGame() } else { -#if 1 scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : local_player->jx - MIDPOSX); @@ -2163,21 +1977,10 @@ void InitGame() scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : local_player->jy - MIDPOSY); -#else - scroll_x = SBX_Left; - scroll_y = SBY_Upper; - if (local_player->jx >= SBX_Left + MIDPOSX) - scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ? - local_player->jx - MIDPOSX : - SBX_Right); - if (local_player->jy >= SBY_Upper + MIDPOSY) - scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ? - local_player->jy - MIDPOSY : - SBY_Lower); -#endif } - CloseDoor(DOOR_CLOSE_1); + if (!game.restart_level) + CloseDoor(DOOR_CLOSE_1); /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) @@ -2201,43 +2004,47 @@ void InitGame() } /* !!! FIX THIS (END) !!! */ - /* copy default game door content to main double buffer */ - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); + if (!game.restart_level) + { + /* copy default game door content to main double buffer */ + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, + DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); + } DrawGameDoorValues(); - UnmapGameButtons(); - UnmapTapeButtons(); - game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music; - game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops; - game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple; - MapGameButtons(); - MapTapeButtons(); + if (!game.restart_level) + { + UnmapGameButtons(); + UnmapTapeButtons(); + game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music; + game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops; + game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple; + MapGameButtons(); + MapTapeButtons(); - /* copy actual game door content to door double buffer for OpenDoor() */ - BlitBitmap(drawto, bitmap_db_door, - DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); + /* copy actual game door content to door double buffer for OpenDoor() */ + BlitBitmap(drawto, bitmap_db_door, + DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); - OpenDoor(DOOR_OPEN_ALL); + OpenDoor(DOOR_OPEN_ALL); - PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE); + PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE); - if (setup.sound_music) - PlayLevelMusic(); + if (setup.sound_music) + PlayLevelMusic(); - KeyboardAutoRepeatOffUnlessAutoplay(); + KeyboardAutoRepeatOffUnlessAutoplay(); - if (options.debug) - { - for (i = 0; i < MAX_PLAYERS; i++) - printf("Player %d %sactive.\n", - i + 1, (stored_player[i].active ? "" : "not ")); + if (options.debug) + { + for (i = 0; i < MAX_PLAYERS; i++) + printf("Player %d %sactive.\n", + i + 1, (stored_player[i].active ? "" : "not ")); + } } -#if 0 - printf("::: starting game [%d]\n", FrameCounter); -#endif + game.restart_level = FALSE; } void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y) @@ -2359,11 +2166,9 @@ void InitMovDir(int x, int y) else if (move_pattern == MV_ALONG_LEFT_SIDE || move_pattern == MV_ALONG_RIGHT_SIDE) { -#if 1 /* use random direction as default start direction */ if (game.engine_version >= VERSION_IDENT(3,1,0,0)) MovDir[x][y] = 1 << RND(4); -#endif for (i = 0; i < NUM_DIRECTIONS; i++) { @@ -2449,13 +2254,8 @@ void GameWon() if (local_player->MovPos) return; -#if 1 if (tape.auto_play) /* tape might already be stopped here */ tape.auto_play_level_solved = TRUE; -#else - if (tape.playing && tape.auto_play) - tape.auto_play_level_solved = TRUE; -#endif local_player->LevelSolved = FALSE; @@ -2531,7 +2331,7 @@ void GameWon() PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); } - /* Hero disappears */ + /* player disappears */ if (ExitX >= 0 && ExitY >= 0) DrawLevelField(ExitX, ExitY); @@ -2713,43 +2513,29 @@ void InitMovingField(int x, int y, int direction) if (!WasJustMoving[x][y] || direction != MovDir[x][y]) ResetGfxAnimation(x, y); -#if USE_CAN_MOVE_NOT_MOVING - MovDir[x][y] = direction; GfxDir[x][y] = direction; GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); + /* this is needed for CEs with property "can move" / "not moving" */ + if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */ { if (Feld[newx][newy] == EL_EMPTY) Feld[newx][newy] = EL_BLOCKED; MovDir[newx][newy] = MovDir[x][y]; + +#if USE_NEW_COLLECT_COUNT + Count[newx][newy] = Count[x][y]; +#endif + GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; GfxAction[newx][newy] = GfxAction[x][y]; GfxDir[newx][newy] = GfxDir[x][y]; } - -#else - - MovDir[newx][newy] = MovDir[x][y] = direction; - GfxDir[x][y] = direction; - - if (Feld[newx][newy] == EL_EMPTY) - Feld[newx][newy] = EL_BLOCKED; - - if (direction == MV_DOWN && CAN_FALL(element)) - GfxAction[x][y] = ACTION_FALLING; - else - GfxAction[x][y] = ACTION_MOVING; - - GfxFrame[newx][newy] = GfxFrame[x][y]; - GfxRandom[newx][newy] = GfxRandom[x][y]; - GfxAction[newx][newy] = GfxAction[x][y]; - GfxDir[newx][newy] = GfxDir[x][y]; -#endif } void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y) @@ -2826,6 +2612,10 @@ static void RemoveField(int x, int y) MovDir[x][y] = 0; MovDelay[x][y] = 0; +#if USE_NEW_COLLECT_COUNT + Count[x][y] = 0; +#endif + AmoebaNr[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; @@ -2852,10 +2642,7 @@ void RemoveMovingField(int x, int y) if (IS_MOVING(x, y)) { Moving2Blocked(x, y, &newx, &newy); -#if 0 - if (Feld[newx][newy] != EL_BLOCKED) - return; -#else + if (Feld[newx][newy] != EL_BLOCKED) { /* element is moving, but target field is not free (blocked), but @@ -2870,7 +2657,6 @@ void RemoveMovingField(int x, int y) return; } -#endif } else if (element == EL_BLOCKED) { @@ -2917,19 +2703,10 @@ void DrawDynamite(int x, int y) frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); -#if 1 if (Back[x][y] || Store[x][y]) DrawGraphicThruMask(sx, sy, graphic, frame); else DrawGraphic(sx, sy, graphic, frame); -#else - if (game.emulation == EMU_SUPAPLEX) - DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame); - else if (Store[x][y]) - DrawGraphicThruMask(sx, sy, graphic, frame); - else - DrawGraphic(sx, sy, graphic, frame); -#endif } void CheckDynamite(int x, int y) @@ -2947,15 +2724,7 @@ void CheckDynamite(int x, int y) } } -#if 1 StopLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); -#else - if (Feld[x][y] == EL_DYNAMITE_ACTIVE || - Feld[x][y] == EL_SP_DISK_RED_ACTIVE) - StopSound(SND_DYNAMITE_ACTIVE); - else - StopSound(SND_DYNABOMB_ACTIVE); -#endif Bang(x, y); } @@ -2971,7 +2740,6 @@ void DrawRelocatePlayer(struct PlayerInfo *player) if (level.instant_relocation) { -#if 1 int offset = (setup.scroll_delay ? 3 : 0); if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) @@ -3002,27 +2770,11 @@ void DrawRelocatePlayer(struct PlayerInfo *player) if (scroll_y < SBY_Upper || scroll_y > SBY_Lower) scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); } -#else - scroll_x += (local_player->jx - old_jx); - scroll_y += (local_player->jy - old_jy); - - /* 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); - - /* 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); -#endif RedrawPlayfield(TRUE, 0,0,0,0); } else { -#if 1 -#if 0 - int offset = (setup.scroll_delay ? 3 : 0); -#endif int scroll_xx = -999, scroll_yy = -999; ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ @@ -3043,60 +2795,8 @@ void DrawRelocatePlayer(struct PlayerInfo *player) dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0); dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0); -#if 1 - if (dx == 0 && dy == 0) /* no scrolling needed at all */ - break; -#else - if (scroll_xx == scroll_x && scroll_yy == scroll_y) - break; -#endif - - scroll_x -= dx; - scroll_y -= dy; - - fx += dx * TILEX / 2; - fy += dy * TILEY / 2; - - 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); - FlushDisplay(); - Delay(wait_delay_value); - - /* scroll second step to align at full tile size */ - BackToFront(); - Delay(wait_delay_value); - } -#else - int scroll_xx = -999, scroll_yy = -999; - - ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ - - while (scroll_xx != scroll_x || scroll_yy != scroll_y) - { - int dx = 0, dy = 0; - int fx = FX, fy = FY; - - scroll_xx = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : - local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : - local_player->jx - MIDPOSX); - - scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : - local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : - local_player->jy - MIDPOSY); - - dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0); - dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0); - -#if 1 if (dx == 0 && dy == 0) /* no scrolling needed at all */ break; -#else - if (scroll_xx == scroll_x && scroll_yy == scroll_y) - break; -#endif scroll_x -= dx; scroll_y -= dy; @@ -3116,7 +2816,6 @@ void DrawRelocatePlayer(struct PlayerInfo *player) BackToFront(); Delay(wait_delay_value); } -#endif DrawPlayer(player); BackToFront(); @@ -3126,11 +2825,7 @@ void DrawRelocatePlayer(struct PlayerInfo *player) void RelocatePlayer(int jx, int jy, int el_player_raw) { -#if 1 int el_player = GET_VALID_PLAYER_ELEMENT(el_player_raw); -#else - int el_player = (el_player_raw == EL_SP_MURPHY ? EL_PLAYER_1 :el_player_raw); -#endif struct PlayerInfo *player = &stored_player[el_player - EL_PLAYER_1]; boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); @@ -3144,25 +2839,10 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) int move_dir_horiz = (jx < old_jx ? MV_LEFT : jx > old_jx ? MV_RIGHT : 0); int move_dir_vert = (jy < old_jy ? MV_UP : jy > old_jy ? MV_DOWN : 0); -#if 1 int enter_side_horiz = MV_DIR_OPPOSITE(move_dir_horiz); int enter_side_vert = MV_DIR_OPPOSITE(move_dir_vert); int leave_side_horiz = move_dir_horiz; int leave_side_vert = move_dir_vert; -#else - static int trigger_sides[4][2] = - { - /* enter side leave side */ - { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */ - { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */ - { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */ - { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */ - }; - int enter_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][0]; - int enter_side_vert = trigger_sides[MV_DIR_BIT(move_dir_vert)][0]; - int leave_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][1]; - int leave_side_vert = trigger_sides[MV_DIR_BIT(move_dir_vert)][1]; -#endif int enter_side = enter_side_horiz | enter_side_vert; int leave_side = leave_side_horiz | leave_side_vert; @@ -3185,11 +2865,7 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) ScrollPlayer(player, SCROLL_GO_ON); ScrollScreen(NULL, SCROLL_GO_ON); -#if USE_NEW_MOVE_DELAY AdvanceFrameAndPlayerCounters(player->index_nr); -#else - FrameCounter++; -#endif DrawPlayer(player); @@ -3203,16 +2879,13 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) player->is_moving = FALSE; } -#if 1 if (IS_CUSTOM_ELEMENT(old_element)) CheckElementChangeByPlayer(old_jx, old_jy, old_element, CE_LEFT_BY_PLAYER, player->index_bit, leave_side); - CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, - CE_PLAYER_LEAVES_X, + CheckTriggeredElementChangeByPlayer(old_element, CE_PLAYER_LEAVES_X, player->index_bit, leave_side); -#endif Feld[jx][jy] = el_player; InitPlayerField(jx, jy, el_player, TRUE); @@ -3223,69 +2896,29 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) InitField(jx, jy, FALSE); } -#if 1 if (player == local_player) /* only visually relocate local player */ DrawRelocatePlayer(player); -#endif -#if 1 - TestIfHeroTouchesBadThing(jx, jy); + TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); -#endif - -#if 0 - printf("::: %d,%d: %d\n", jx, jy-1, Changed[jx][jy-1]); -#endif - -#if 0 -#if 0 - /* needed to allow change of walkable custom element by entering player */ - if (!(Changed[jx][jy] & CH_EVENT_BIT(CE_ENTERED_BY_PLAYER))) - Changed[jx][jy] = 0; /* allow another change (but prevent loop) */ -#else - /* needed to allow change of walkable custom element by entering player */ - Changed[jx][jy] = 0; /* allow another change */ -#endif -#endif - -#if 0 - printf("::: player entering %d, %d from %s ...\n", jx, jy, - enter_side == MV_LEFT ? "left" : - enter_side == MV_RIGHT ? "right" : - enter_side == MV_UP ? "top" : - enter_side == MV_DOWN ? "bottom" : "oops! no idea!"); -#endif -#if 1 if (IS_CUSTOM_ELEMENT(element)) CheckElementChangeByPlayer(jx, jy, element, CE_ENTERED_BY_PLAYER, player->index_bit, enter_side); - CheckTriggeredElementChangeByPlayer(jx, jy, element, - CE_PLAYER_ENTERS_X, + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_ENTERS_X, player->index_bit, enter_side); -#endif } void Explode(int ex, int ey, int phase, int mode) { int x, y; -#if 0 - int num_phase = 9; -#endif + int last_phase; + int border_element; /* !!! eliminate this variable !!! */ int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); -#if 1 - int last_phase; -#else - int last_phase = num_phase * delay; - int half_phase = (num_phase / 2) * delay; - int first_phase_after_start = EX_PHASE_START + 1; -#endif - int border_element; - if (game.explosions_delayed) { ExplodeField[ex][ey] = mode; @@ -3296,10 +2929,6 @@ void Explode(int ex, int ey, int phase, int mode) { int center_element = Feld[ex][ey]; -#if 0 - printf("::: start explosion %d,%d [%d]\n", ex, ey, FrameCounter); -#endif - #if 0 /* --- This is only really needed (and now handled) in "Impact()". --- */ /* do not explode moving elements that left the explode field in time */ @@ -3309,15 +2938,10 @@ void Explode(int ex, int ey, int phase, int mode) return; #endif -#if 1 if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER || mode == EX_TYPE_CROSS) PlayLevelSoundAction(ex, ey, ACTION_EXPLODING); -#else - if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER) - PlayLevelSoundAction(ex, ey, ACTION_EXPLODING); -#endif /* remove things displayed in background while burning dynamite */ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) @@ -3331,18 +2955,7 @@ void Explode(int ex, int ey, int phase, int mode) Feld[ex][ey] = center_element; } -#if 1 - -#if 1 last_phase = element_info[center_element].explosion_delay + 1; -#else - last_phase = element_info[center_element].explosion_delay; -#endif - -#if 0 - printf("::: %d -> %d\n", center_element, last_phase); -#endif -#endif for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++) { @@ -3350,24 +2963,10 @@ void Explode(int ex, int ey, int phase, int mode) int yy = y - ey + 1; int element; -#if 1 -#if 1 if (!IN_LEV_FIELD(x, y) || (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) || (mode == EX_TYPE_CROSS && (x != ex && y != ey))) continue; -#else - if (!IN_LEV_FIELD(x, y) || - (mode != EX_TYPE_NORMAL && (x != ex || y != ey))) - continue; -#endif -#else - if (!IN_LEV_FIELD(x, y) || - ((mode != EX_TYPE_NORMAL || - center_element == EL_AMOEBA_TO_DIAMOND) && - (x != ex || y != ey))) - continue; -#endif element = Feld[x][y]; @@ -3379,32 +2978,11 @@ void Explode(int ex, int ey, int phase, int mode) RemoveMovingField(x, y); } -#if 1 - -#if 0 - if (IS_EXPLOSION_PROOF(element)) - continue; -#else /* indestructible elements can only explode in center (but not flames) */ -#if 1 if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) || element == EL_FLAMES) continue; -#else - if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) || - element == EL_FLAMES) - continue; -#endif -#endif - -#else - if ((IS_INDESTRUCTIBLE(element) && - (game.engine_version < VERSION_IDENT(2,2,0,0) || - (!IS_WALKABLE_OVER(element) && !IS_WALKABLE_UNDER(element)))) || - element == EL_FLAMES) - continue; -#endif /* no idea why this was changed from 3.0.8 to 3.1.0 -- this causes buggy behaviour, for example when touching a yamyam that explodes to rocks @@ -3421,50 +2999,22 @@ void Explode(int ex, int ey, int phase, int mode) if (IS_ACTIVE_BOMB(element)) { /* re-activate things under the bomb like gate or penguin */ -#if 1 Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY); Back[x][y] = 0; -#else - Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_EMPTY); - Store[x][y] = 0; -#endif - -#if 0 - printf("::: %d,%d: %d %s [%d, %d]\n", x, y, Feld[x][y], - element_info[Feld[x][y]].token_name, - Store[x][y], Store2[x][y]); -#endif } continue; } /* save walkable background elements while explosion on same tile */ -#if 0 - if (IS_INDESTRUCTIBLE(element)) - Back[x][y] = element; -#else -#if 1 -#if 1 if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) Back[x][y] = element; -#else - if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) && - (x != ex || y != ey)) - Back[x][y] = element; -#endif -#else - if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element)) - Back[x][y] = element; -#endif -#endif /* ignite explodable elements reached by other explosion */ if (element == EL_EXPLOSION) element = Store2[x][y]; -#if 1 if (AmoebaNr[x][y] && (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA || @@ -3475,7 +3025,6 @@ void Explode(int ex, int ey, int phase, int mode) } RemoveField(x, y); -#endif if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey)) { @@ -3496,13 +3045,8 @@ void Explode(int ex, int ey, int phase, int mode) break; } -#if 1 if (PLAYERINFO(ex, ey)->use_murphy_graphic) Store[x][y] = EL_EMPTY; -#else - if (game.emulation == EMU_SUPAPLEX) - Store[x][y] = EL_EMPTY; -#endif } else if (center_element == EL_MOLE) Store[x][y] = EL_EMERALD_RED; @@ -3546,49 +3090,11 @@ void Explode(int ex, int ey, int phase, int mode) center_element == EL_AMOEBA_TO_DIAMOND) Store2[x][y] = element; -#if 0 - printf("::: %d,%d: %d %s\n", x, y, Store2[x][y], - element_info[Store2[x][y]].token_name); -#endif - -#if 0 - if (AmoebaNr[x][y] && - (element == EL_AMOEBA_FULL || - element == EL_BD_AMOEBA || - element == EL_AMOEBA_GROWING)) - { - AmoebaCnt[AmoebaNr[x][y]]--; - AmoebaCnt2[AmoebaNr[x][y]]--; - } - -#if 1 - RemoveField(x, y); -#else - MovDir[x][y] = MovPos[x][y] = 0; - GfxDir[x][y] = MovDir[x][y]; - AmoebaNr[x][y] = 0; -#endif -#endif - Feld[x][y] = EL_EXPLOSION; -#if 1 GfxElement[x][y] = center_element; -#else - GfxElement[x][y] = EL_UNDEFINED; -#endif ExplodePhase[x][y] = 1; -#if 1 ExplodeDelay[x][y] = last_phase; -#endif - -#if 0 -#if 1 - GfxFrame[x][y] = 0; /* animation does not start until next frame */ -#else - GfxFrame[x][y] = -1; /* animation does not start until next frame */ -#endif -#endif Stop[x][y] = TRUE; } @@ -3597,11 +3103,6 @@ void Explode(int ex, int ey, int phase, int mode) game.yamyam_content_nr = (game.yamyam_content_nr + 1) % level.num_yamyam_contents; -#if 0 - printf("::: %d,%d: %d %s [%d]\n", ex + 1, ey, Feld[ex + 1][ey], - element_info[Feld[ex + 1][ey]].token_name, Store2[ex + 1][ey]); -#endif - return; } @@ -3611,18 +3112,10 @@ void Explode(int ex, int ey, int phase, int mode) x = ex; y = ey; -#if 1 if (phase == 1) GfxFrame[x][y] = 0; /* restart explosion animation */ -#endif -#if 0 - printf(":X: phase == %d [%d]\n", phase, GfxFrame[x][y]); -#endif - -#if 1 last_phase = ExplodeDelay[x][y]; -#endif ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); @@ -3630,6 +3123,7 @@ void Explode(int ex, int ey, int phase, int mode) /* activate this even in non-DEBUG version until cause for crash in getGraphicAnimationFrame() (see below) is found and eliminated */ + #endif #if 1 @@ -3644,136 +3138,49 @@ void Explode(int ex, int ey, int phase, int mode) } #endif -#if 1 - border_element = Store2[x][y]; -#if 1 if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) border_element = StorePlayer[x][y]; -#else - if (IS_PLAYER(x, y)) - border_element = StorePlayer[x][y]; -#endif - -#if 0 - printf("::: %d,%d: %d %s [%d]\n", x, y, border_element, - element_info[border_element].token_name, Store2[x][y]); -#endif - -#if 0 - printf("::: phase == %d\n", phase); -#endif if (phase == element_info[border_element].ignition_delay || phase == last_phase) { boolean border_explosion = FALSE; -#if 1 -#if 1 if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present && !PLAYER_EXPLOSION_PROTECTED(x, y)) -#else - if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present) -#endif -#else - if (IS_PLAYER(x, y)) -#endif { - KillHeroUnlessExplosionProtected(x, y); + KillPlayerUnlessExplosionProtected(x, y); border_explosion = TRUE; - -#if 0 - if (phase == last_phase) - printf("::: IS_PLAYER\n"); -#endif } else if (CAN_EXPLODE_BY_EXPLOSION(border_element)) { -#if 0 - printf("::: %d,%d: %d %s\n", x, y, border_element, - element_info[border_element].token_name); -#endif - Feld[x][y] = Store2[x][y]; Store2[x][y] = 0; Bang(x, y); border_explosion = TRUE; - -#if 0 - if (phase == last_phase) - printf("::: CAN_EXPLODE_BY_EXPLOSION\n"); -#endif } else if (border_element == EL_AMOEBA_TO_DIAMOND) { AmoebeUmwandeln(x, y); Store2[x][y] = 0; border_explosion = TRUE; - -#if 0 - if (phase == last_phase) - printf("::: EL_AMOEBA_TO_DIAMOND [%d, %d] [%d]\n", - element_info[border_element].explosion_delay, - element_info[border_element].ignition_delay, - phase); -#endif } -#if 1 /* if an element just explodes due to another explosion (chain-reaction), do not immediately end the new explosion when it was the last frame of the explosion (as it would be done in the following "if"-statement!) */ if (border_explosion && phase == last_phase) return; -#endif } -#else - - if (phase == first_phase_after_start) + if (phase == last_phase) { - int element = Store2[x][y]; + int element; - if (element == EL_BLACK_ORB) - { - Feld[x][y] = Store2[x][y]; - Store2[x][y] = 0; - Bang(x, y); - } - } - else if (phase == half_phase) - { - int element = Store2[x][y]; - - if (IS_PLAYER(x, y)) - KillHeroUnlessExplosionProtected(x, y); - else if (CAN_EXPLODE_BY_EXPLOSION(element)) - { - Feld[x][y] = Store2[x][y]; - Store2[x][y] = 0; - Bang(x, y); - } - else if (element == EL_AMOEBA_TO_DIAMOND) - AmoebeUmwandeln(x, y); - } -#endif - - if (phase == last_phase) - { - int element; - -#if 0 - printf("::: done: phase == %d\n", phase); -#endif - -#if 0 - printf("::: explosion %d,%d done [%d]\n", x, y, FrameCounter); -#endif - - element = Feld[x][y] = Store[x][y]; - Store[x][y] = Store2[x][y] = 0; - GfxElement[x][y] = EL_UNDEFINED; + element = Feld[x][y] = Store[x][y]; + Store[x][y] = Store2[x][y] = 0; + GfxElement[x][y] = EL_UNDEFINED; /* player can escape from explosions and might therefore be still alive */ if (element >= EL_PLAYER_IS_EXPLODING_1 && @@ -3795,22 +3202,12 @@ void Explode(int ex, int ey, int phase, int mode) ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; -#if 1 - InitField_WithBug2(x, y, FALSE); -#else - InitField(x, y, FALSE); -#if 1 - /* !!! not needed !!! */ -#if 1 - if (game.engine_version < VERSION_IDENT(3,1,0,0) && - CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE) - InitMovDir(x, y); -#else - if (CAN_MOVE(element)) - InitMovDir(x, y); -#endif -#endif +#if USE_NEW_COLLECT_COUNT + Count[x][y] = 0; #endif + + InitField_WithBug2(x, y, FALSE); + DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); @@ -3824,40 +3221,10 @@ void Explode(int ex, int ey, int phase, int mode) if (ELEM_IS_PLAYER(element)) RelocatePlayer(x, y, element); } -#if 1 else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) -#else - else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) -#endif { -#if 1 int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING); -#else - int stored = Store[x][y]; - int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION : - stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON : - IMG_SP_EXPLOSION); -#endif -#if 1 int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); -#else - int frame = getGraphicAnimationFrame(graphic, phase - delay); -#endif - -#if 0 - printf("::: phase == %d [%d]\n", phase, GfxFrame[x][y]); -#endif - -#if 0 - printf("::: %d / %d [%d - %d]\n", - GfxFrame[x][y], phase - delay, phase, delay); -#endif - -#if 0 - printf("::: %d ['%s'] -> %d\n", GfxElement[x][y], - element_info[GfxElement[x][y]].token_name, - graphic); -#endif if (phase == delay) DrawLevelFieldCrumbledSand(x, y); @@ -3921,39 +3288,18 @@ void DynaExplode(int ex, int ey) Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER); -#if 1 -#if 1 if (element != EL_EMPTY && element != EL_EXPLOSION && !IS_DIGGABLE(element) && !dynabomb_xl) break; -#else - if (element != EL_EMPTY && element != EL_EXPLOSION && - !CAN_GROW_INTO(element) && !dynabomb_xl) - break; -#endif -#else - /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ - if (element != EL_EMPTY && element != EL_EXPLOSION && - element != EL_SAND && !dynabomb_xl) - break; -#endif } } } void Bang(int x, int y) { -#if 1 int element = MovingOrBlocked2Element(x, y); -#else - int element = Feld[x][y]; -#endif -#if 1 if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) -#else - if (IS_PLAYER(x, y)) -#endif { struct PlayerInfo *player = PLAYERINFO(x, y); @@ -3961,22 +3307,6 @@ void Bang(int x, int y) player->element_nr); } -#if 0 -#if 1 - PlayLevelSoundAction(x, y, ACTION_EXPLODING); -#else - if (game.emulation == EMU_SUPAPLEX) - PlayLevelSound(x, y, SND_SP_ELEMENT_EXPLODING); - else - PlayLevelSound(x, y, SND_ELEMENT_EXPLODING); -#endif -#endif - -#if 0 - if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */ - element = EL_EMPTY; -#endif - switch(element) { case EL_BUG: @@ -4003,42 +3333,27 @@ void Bang(int x, int y) case EL_PENGUIN: case EL_LAMP: case EL_LAMP_ACTIVE: -#if 1 case EL_AMOEBA_TO_DIAMOND: -#endif if (IS_PLAYER(x, y)) Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL); else Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER); break; default: -#if 1 if (element_info[element].explosion_type == EXPLODES_CROSS) -#else - if (CAN_EXPLODE_CROSS(element)) -#endif -#if 1 Explode(x, y, EX_PHASE_START, EX_TYPE_CROSS); -#else - DynaExplode(x, y); -#endif -#if 1 else if (element_info[element].explosion_type == EXPLODES_1X1) -#else - else if (CAN_EXPLODE_1X1(element)) -#endif Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER); else Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL); break; } - CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X); + CheckTriggeredElementChange(element, CE_EXPLOSION_OF_X); } void SplashAcid(int x, int y) { -#if 1 if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) && (!IN_LEV_FIELD(x - 1, y - 2) || !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2)))) @@ -4050,30 +3365,6 @@ void SplashAcid(int x, int y) Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT; PlayLevelSound(x, y, SND_ACID_SPLASHING); -#else - /* input: position of element entering acid (obsolete) */ - - int element = Feld[x][y]; - - if (!IN_LEV_FIELD(x, y + 1) || Feld[x][y + 1] != EL_ACID) - return; - - if (element != EL_ACID_SPLASH_LEFT && - element != EL_ACID_SPLASH_RIGHT) - { - PlayLevelSound(x, y, SND_ACID_SPLASHING); - - if (IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y) && - (!IN_LEV_FIELD(x - 1, y - 1) || - !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 1)))) - Feld[x - 1][y] = EL_ACID_SPLASH_LEFT; - - if (IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y) && - (!IN_LEV_FIELD(x + 1, y - 1) || - !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 1)))) - Feld[x + 1][y] = EL_ACID_SPLASH_RIGHT; - } -#endif } static void InitBeltMovement() @@ -4261,21 +3552,15 @@ static void ToggleSwitchgateSwitch(int x, int y) element == EL_SWITCHGATE_OPENING) { Feld[xx][yy] = EL_SWITCHGATE_CLOSING; -#if 1 + PlayLevelSoundAction(xx, yy, ACTION_CLOSING); -#else - PlayLevelSound(xx, yy, SND_SWITCHGATE_CLOSING); -#endif } else if (element == EL_SWITCHGATE_CLOSED || element == EL_SWITCHGATE_CLOSING) { Feld[xx][yy] = EL_SWITCHGATE_OPENING; -#if 1 + PlayLevelSoundAction(xx, yy, ACTION_OPENING); -#else - PlayLevelSound(xx, yy, SND_SWITCHGATE_OPENING); -#endif } } } @@ -4395,17 +3680,13 @@ static void ActivateTimegateSwitch(int x, int y) void Impact(int x, int y) { - boolean lastline = (y == lev_fieldy-1); + boolean last_line = (y == lev_fieldy - 1); boolean object_hit = FALSE; - boolean impact = (lastline || object_hit); + boolean impact = (last_line || object_hit); int element = Feld[x][y]; int smashed = EL_STEELWALL; -#if 0 - printf("IMPACT!\n"); -#endif - - if (!lastline) /* check if element below was hit */ + if (!last_line) /* check if element below was hit */ { if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING) return; @@ -4414,10 +3695,6 @@ void Impact(int x, int y) MovDir[x][y + 1] != MV_DOWN || MovPos[x][y + 1] <= TILEY / 2)); -#if 0 - object_hit = !IS_FREE(x, y + 1); -#endif - /* do not smash moving elements that left the smashed field in time */ if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) && ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX) @@ -4426,10 +3703,10 @@ void Impact(int x, int y) if (object_hit) smashed = MovingOrBlocked2Element(x, y + 1); - impact = (lastline || object_hit); + impact = (last_line || object_hit); } - if (!lastline && smashed == EL_ACID) /* element falls into acid */ + if (!last_line && smashed == EL_ACID) /* element falls into acid */ { SplashAcid(x, y + 1); return; @@ -4467,7 +3744,7 @@ void Impact(int x, int y) if (impact && element == EL_AMOEBA_DROP) { if (object_hit && IS_PLAYER(x, y + 1)) - KillHeroUnlessEnemyProtected(x, y + 1); + KillPlayerUnlessEnemyProtected(x, y + 1); else if (object_hit && smashed == EL_PENGUIN) Bang(x, y + 1); else @@ -4509,7 +3786,7 @@ void Impact(int x, int y) { if (CAN_SMASH_PLAYER(element)) { - KillHeroUnlessEnemyProtected(x, y + 1); + KillPlayerUnlessEnemyProtected(x, y + 1); return; } } @@ -4540,13 +3817,6 @@ void Impact(int x, int y) Bang(x, y + 1); return; } -#if 0 - else if (CAN_SMASH_ENEMIES(element) && IS_CLASSIC_ENEMY(smashed)) - { - Bang(x, y + 1); - return; - } -#endif else if (CAN_SMASH_EVERYTHING(element)) { if (IS_CLASSIC_ENEMY(smashed) || @@ -4606,18 +3876,10 @@ void Impact(int x, int y) CheckElementChange(x, y + 1, smashed, element, CE_SMASHED); -#if 1 - /* !!! TEST ONLY !!! */ CheckElementChangeBySide(x, y + 1, smashed, element, CE_SWITCHED, CH_SIDE_TOP); - CheckTriggeredElementChangeBySide(x, y + 1, smashed, - CE_SWITCH_OF_X, CH_SIDE_TOP); -#else - CheckTriggeredElementChangeBySide(x, y + 1, smashed, - CE_SWITCH_OF_X, CH_SIDE_TOP); - CheckElementChangeBySide(x, y + 1, smashed, element, - CE_SWITCHED, CH_SIDE_TOP); -#endif + CheckTriggeredElementChangeBySide(smashed, CE_SWITCH_OF_X, + CH_SIDE_TOP); } } else @@ -4628,7 +3890,7 @@ void Impact(int x, int y) } /* play sound of magic wall / mill */ - if (!lastline && + if (!last_line && (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) { @@ -4641,7 +3903,7 @@ void Impact(int x, int y) } /* play sound of object that hits the ground */ - if (lastline || object_hit) + if (last_line || object_hit) PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); } @@ -4709,26 +3971,6 @@ inline static void TurnRoundExt(int x, int y) else if (element == EL_BD_BUTTERFLY) /* && MovDir[x][y] == left_dir) */ MovDelay[x][y] = 1; } -#if 0 - else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY || - element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) - { - TestIfBadThingTouchesOtherBadThing(x, y); - - if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y)) - MovDir[x][y] = left_dir; - else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y)) - MovDir[x][y] = right_dir; - - if ((element == EL_SPACESHIP || - element == EL_SP_SNIKSNAK || - element == EL_SP_ELECTRON) - && MovDir[x][y] != old_move_dir) - MovDelay[x][y] = 9; - else if (element == EL_BD_FIREFLY) /* && MovDir[x][y] == right_dir) */ - MovDelay[x][y] = 1; - } -#else else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY) { TestIfBadThingTouchesOtherBadThing(x, y); @@ -4755,7 +3997,6 @@ inline static void TurnRoundExt(int x, int y) if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; } -#endif else if (element == EL_YAMYAM) { boolean can_turn_left = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y); @@ -4864,15 +4105,9 @@ inline static void TurnRoundExt(int x, int y) xx = x + move_xy[MovDir[x][y]].x; yy = y + move_xy[MovDir[x][y]].y; -#if 1 - /* !!! this bugfix breaks at least BD2K3, level 010 !!! [re-recorded] */ if (!IN_LEV_FIELD(xx, yy) || (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))) MovDir[x][y] = old_move_dir; -#else - if (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy])) - MovDir[x][y] = old_move_dir; -#endif MovDelay[x][y] = 0; } @@ -4884,11 +4119,6 @@ inline static void TurnRoundExt(int x, int y) int rnd_value = 24; int rnd = RND(rnd_value); -#if 0 - if (FrameCounter < 1 && x == 0 && y == 29) - printf(":2: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter); -#endif - if (can_move_on && rnd > rnd_value / 8) MovDir[x][y] = old_move_dir; else if (can_turn_left && can_turn_right) @@ -4903,25 +4133,8 @@ inline static void TurnRoundExt(int x, int y) xx = x + move_xy[MovDir[x][y]].x; yy = y + move_xy[MovDir[x][y]].y; -#if 0 - if (FrameCounter < 1 && x == 0 && y == 29) - printf(":3: %d/%d: %d (%d/%d: %d) [%d]\n", x, y, MovDir[x][y], - xx, yy, Feld[xx][yy], - FrameCounter); -#endif - -#if 1 if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy)) MovDir[x][y] = old_move_dir; -#else - if (!IS_FREE(xx, yy)) - MovDir[x][y] = old_move_dir; -#endif - -#if 0 - if (FrameCounter < 1 && x == 0 && y == 29) - printf(":4: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter); -#endif MovDelay[x][y] = 0; } @@ -4959,16 +4172,10 @@ inline static void TurnRoundExt(int x, int y) } else if (element == EL_SPRING) { -#if 0 - if (MovDir[x][y] & MV_HORIZONTAL && - !SPRING_CAN_ENTER_FIELD(element, move_x, move_y)) - MovDir[x][y] = MV_NO_MOVING; -#else if (MovDir[x][y] & MV_HORIZONTAL && (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) || SPRING_CAN_ENTER_FIELD(element, x, y + 1))) MovDir[x][y] = MV_NO_MOVING; -#endif MovDelay[x][y] = 0; } @@ -5004,13 +4211,9 @@ inline static void TurnRoundExt(int x, int y) } } -#if 1 if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 && (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE || game.engine_version < VERSION_IDENT(3,1,0,0))) -#else - if (element == EL_ROBOT && ZX >= 0 && ZY >= 0) -#endif { attr_x = ZX; attr_y = ZY; @@ -5135,10 +4338,8 @@ inline static void TurnRoundExt(int x, int y) boolean can_turn_right = CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); -#if USE_CAN_MOVE_NOT_MOVING - if (element_info[element].move_stepsize == 0) /* not moving */ + if (element_info[element].move_stepsize == 0) /* "not moving" */ return; -#endif if (move_pattern == MV_TURNING_LEFT) MovDir[x][y] = left_dir; @@ -5250,15 +4451,13 @@ inline static void TurnRoundExt(int x, int y) boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; -#if USE_CAN_MOVE_NOT_MOVING - if (element_info[element].move_stepsize == 0) /* not moving */ + if (element_info[element].move_stepsize == 0) /* "not moving" */ { first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y)); MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); return; } -#endif MovDir[x][y] = new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); @@ -5353,13 +4552,7 @@ inline static void TurnRoundExt(int x, int y) MovDir[x][y] = new_move_dir; if (old_move_dir != new_move_dir) - { -#if 1 MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); -#else - MovDelay[x][y] = 9; -#endif - } } } @@ -5367,26 +4560,15 @@ static void TurnRound(int x, int y) { int direction = MovDir[x][y]; -#if 0 - GfxDir[x][y] = MovDir[x][y]; -#endif - TurnRoundExt(x, y); -#if 1 GfxDir[x][y] = MovDir[x][y]; -#endif if (direction != MovDir[x][y]) GfxFrame[x][y] = 0; -#if 1 if (MovDelay[x][y]) GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_BIT(direction); -#else - if (MovDelay[x][y]) - GfxAction[x][y] = ACTION_WAITING; -#endif } static boolean JustBeingPushed(int x, int y) @@ -5412,23 +4594,14 @@ static boolean JustBeingPushed(int x, int y) void StartMoving(int x, int y) { -#if 0 - boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0)); -#endif boolean started_moving = FALSE; /* some elements can fall _and_ move */ int element = Feld[x][y]; if (Stop[x][y]) return; -#if 1 if (MovDelay[x][y] == 0) GfxAction[x][y] = ACTION_DEFAULT; -#else - /* !!! this should be handled more generic (not only for mole) !!! */ - if (element != EL_MOLE && GfxAction[x][y] != ACTION_DIGGING) - GfxAction[x][y] = ACTION_DEFAULT; -#endif if (CAN_FALL(element) && y < lev_fieldy - 1) { @@ -5446,11 +4619,8 @@ void StartMoving(int x, int y) Feld[x][y] = EL_QUICKSAND_EMPTYING; Store[x][y] = EL_ROCK; -#if 1 + PlayLevelSoundAction(x, y, ACTION_EMPTYING); -#else - PlayLevelSound(x, y, SND_QUICKSAND_EMPTYING); -#endif } else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { @@ -5468,11 +4638,8 @@ void StartMoving(int x, int y) Feld[x][y + 1] = EL_QUICKSAND_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; -#if 1 + PlayLevelSoundAction(x, y, ACTION_FILLING); -#else - PlayLevelSound(x, y, SND_QUICKSAND_FILLING); -#endif } } else if ((element == EL_ROCK || element == EL_BD_ROCK) && @@ -5483,11 +4650,8 @@ void StartMoving(int x, int y) Feld[x][y] = EL_QUICKSAND_FILLING; Store[x][y] = element; -#if 1 + PlayLevelSoundAction(x, y, ACTION_FILLING); -#else - PlayLevelSound(x, y, SND_QUICKSAND_FILLING); -#endif } else if (element == EL_MAGIC_WALL_FULL) { @@ -5557,11 +4721,7 @@ void StartMoving(int x, int y) EL_BD_MAGIC_WALL_FILLING); Store[x][y] = element; } -#if 0 - else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_ACID) -#else else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID) -#endif { SplashAcid(x, y + 1); @@ -5569,16 +4729,10 @@ void StartMoving(int x, int y) started_moving = TRUE; Store[x][y] = EL_ACID; -#if 0 - /* !!! TEST !!! better use "_FALLING" etc. !!! */ - GfxAction[x][y + 1] = ACTION_ACTIVE; -#endif } -#if 1 else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckCollision[x][y] && !IS_FREE(x, y + 1)) || -#if USE_IMPACT_BUGFIX (game.engine_version >= VERSION_IDENT(3,0,7,0) && CAN_FALL(element) && WasJustFalling[x][y] && (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) || @@ -5586,27 +4740,6 @@ void StartMoving(int x, int y) (game.engine_version < VERSION_IDENT(2,2,0,7) && CAN_FALL(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] && (Feld[x][y + 1] == EL_BLOCKED))) -#else - (game.engine_version >= VERSION_IDENT(3,0,7,0) && - CAN_SMASH(element) && WasJustFalling[x][y] && - (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) || - - (game.engine_version < VERSION_IDENT(2,2,0,7) && - CAN_SMASH(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] && - (Feld[x][y + 1] == EL_BLOCKED))) -#endif - -#else -#if 1 - else if (game.engine_version < VERSION_IDENT(2,2,0,7) && - CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED && - WasJustMoving[x][y] && !Pushed[x][y + 1]) -#else - else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED && - WasJustMoving[x][y]) -#endif -#endif - { /* this is needed for a special case not covered by calling "Impact()" from "ContinueMoving()": if an element moves to a tile directly below @@ -5618,18 +4751,8 @@ void StartMoving(int x, int y) element; also, the case of the player being the element to smash was simply not covered here... :-/ ) */ -#if 0 - WasJustMoving[x][y] = 0; - WasJustFalling[x][y] = 0; -#endif - CheckCollision[x][y] = 0; -#if 0 - if (IS_PLAYER(x, y + 1)) - printf("::: we ARE now killing the player [%d]\n", FrameCounter); -#endif - Impact(x, y); } else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug) @@ -5653,23 +4776,10 @@ void StartMoving(int x, int y) Feld[x][y] = EL_AMOEBA_GROWING; Store[x][y] = EL_AMOEBA_WET; } - /* Store[x][y + 1] must be zero, because: - (EL_QUICKSAND_FULL -> EL_ROCK): Store[x][y + 1] == EL_QUICKSAND_EMPTY - */ -#if 0 -#if OLD_GAME_BEHAVIOUR - else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1]) -#else - else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1] && - !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] && - element != EL_DX_SUPABOMB) -#endif -#else else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) || (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) && !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] && element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE) -#endif { boolean can_fall_left = (x > 0 && IS_FREE(x - 1, y) && (IS_FREE(x - 1, y + 1) || @@ -5679,11 +4789,26 @@ void StartMoving(int x, int y) Feld[x + 1][y + 1] == EL_ACID)); boolean can_fall_any = (can_fall_left || can_fall_right); boolean can_fall_both = (can_fall_left && can_fall_right); + int slippery_type = element_info[Feld[x][y + 1]].slippery_type; - if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1])) +#if USE_NEW_ALL_SLIPPERY + if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM) { - int slippery_type = element_info[Feld[x][y + 1]].slippery_type; + if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both) + can_fall_right = FALSE; + else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both) + can_fall_left = FALSE; + else if (slippery_type == SLIPPERY_ONLY_LEFT) + can_fall_right = FALSE; + else if (slippery_type == SLIPPERY_ONLY_RIGHT) + can_fall_left = FALSE; + can_fall_any = (can_fall_left || can_fall_right); + can_fall_both = FALSE; + } +#else + if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1])) + { if (slippery_type == SLIPPERY_ONLY_LEFT) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ONLY_RIGHT) @@ -5696,7 +4821,10 @@ void StartMoving(int x, int y) can_fall_any = (can_fall_left || can_fall_right); can_fall_both = (can_fall_left && can_fall_right); } +#endif +#if USE_NEW_ALL_SLIPPERY +#else #if USE_NEW_SP_SLIPPERY /* !!! better use the same properties as for custom elements here !!! */ else if (game.engine_version >= VERSION_IDENT(3,1,1,0) && @@ -5706,29 +4834,33 @@ void StartMoving(int x, int y) can_fall_both = FALSE; } #endif +#endif -#if 1 +#if USE_NEW_ALL_SLIPPERY if (can_fall_both) { - if (game.emulation == EMU_BOULDERDASH || - element == EL_BD_ROCK || element == EL_BD_DIAMOND) + if (element == EL_BD_ROCK || element == EL_BD_DIAMOND) can_fall_right = FALSE; /* slip down on left side */ else can_fall_left = !(can_fall_right = RND(2)); can_fall_both = FALSE; } -#endif - - if (can_fall_any) +#else + if (can_fall_both) { -#if 0 - if (can_fall_both && - (game.emulation != EMU_BOULDERDASH && - element != EL_BD_ROCK && element != EL_BD_DIAMOND)) + if (game.emulation == EMU_BOULDERDASH || + element == EL_BD_ROCK || element == EL_BD_DIAMOND) + can_fall_right = FALSE; /* slip down on left side */ + else can_fall_left = !(can_fall_right = RND(2)); + + can_fall_both = FALSE; + } #endif + if (can_fall_any) + { /* if not determined otherwise, prefer left side for slipping down */ InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT); started_moving = TRUE; @@ -5748,17 +4880,13 @@ void StartMoving(int x, int y) if ((belt_dir == MV_LEFT && left_is_free) || (belt_dir == MV_RIGHT && right_is_free)) { -#if 1 int nextx = (belt_dir == MV_LEFT ? x - 1 : x + 1); -#endif InitMovingField(x, y, belt_dir); started_moving = TRUE; -#if 1 Pushed[x][y] = TRUE; Pushed[nextx][y] = TRUE; -#endif GfxAction[x][y] = ACTION_DEFAULT; } @@ -5792,80 +4920,20 @@ void StartMoving(int x, int y) Moving2Blocked(x, y, &newx, &newy); -#if 1 if (IS_PUSHABLE(element) && JustBeingPushed(x, y)) return; -#else - if ((element == EL_SATELLITE || - element == EL_BALLOON || - element == EL_SPRING) - && JustBeingPushed(x, y)) - return; -#endif - -#if 1 -#if 1 if (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy)) -#else - if (game.engine_version >= VERSION_IDENT(3,1,0,0) && - WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) && - (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy))) -#endif { -#if 0 - printf("::: element %d '%s' WasJustMoving %d [%d, %d, %d, %d]\n", - element, element_info[element].token_name, - WasJustMoving[x][y], - HAS_ANY_CHANGE_EVENT(element, CE_HITTING_SOMETHING), - HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING), - HAS_ANY_CHANGE_EVENT(element, CE_HITTING_X), - HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_X)); -#endif - -#if 1 WasJustMoving[x][y] = 0; -#endif - CheckCollision[x][y] = 0; TestIfElementHitsCustomElement(x, y, MovDir[x][y]); -#if 0 - if (Feld[x][y] != element) /* element has changed */ - { - element = Feld[x][y]; - move_pattern = element_info[element].move_pattern; - - if (!CAN_MOVE(element)) - return; - } -#else if (Feld[x][y] != element) /* element has changed */ return; -#endif - } -#endif - -#if 0 -#if 0 - if (element == EL_SPRING && MovDir[x][y] == MV_DOWN) - Feld[x][y + 1] = EL_EMPTY; /* was set to EL_BLOCKED above */ -#else - if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING) - { - Moving2Blocked(x, y, &newx, &newy); - if (Feld[newx][newy] == EL_BLOCKED) - Feld[newx][newy] = EL_EMPTY; /* was set to EL_BLOCKED above */ } -#endif -#endif - -#if 0 - if (FrameCounter < 1 && x == 0 && y == 29) - printf(":1: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter); -#endif if (!MovDelay[x][y]) /* start new movement phase */ { @@ -5884,11 +4952,6 @@ void StartMoving(int x, int y) { TurnRound(x, y); -#if 0 - if (FrameCounter < 1 && x == 0 && y == 29) - printf(":9: %d: %d [%d]\n", y, MovDir[x][y], FrameCounter); -#endif - if (MovDelay[x][y] && (element == EL_BUG || element == EL_SPACESHIP || element == EL_SP_SNIKSNAK || @@ -5902,42 +4965,11 @@ void StartMoving(int x, int y) { MovDelay[x][y]--; -#if 0 - if (element == EL_YAMYAM) - { - printf("::: %d\n", - el_act_dir2img(EL_YAMYAM, ACTION_WAITING, MV_LEFT)); - DrawLevelElementAnimation(x, y, element); - } -#endif - - if (MovDelay[x][y]) /* element still has to wait some time */ - { -#if 0 - /* !!! PLACE THIS SOMEWHERE AFTER "TurnRound()" !!! */ - ResetGfxAnimation(x, y); -#endif - -#if 0 - if (GfxAction[x][y] != ACTION_WAITING) - printf("::: %d: %d != ACTION_WAITING\n", element, GfxAction[x][y]); - - GfxAction[x][y] = ACTION_WAITING; -#endif - } - if (element == EL_ROBOT || -#if 0 - element == EL_PACMAN || -#endif element == EL_YAMYAM || element == EL_DARK_YAMYAM) { -#if 0 - DrawLevelElementAnimation(x, y, element); -#else DrawLevelElementAnimationIfNeeded(x, y, element); -#endif PlayLevelSoundAction(x, y, ACTION_WAITING); } else if (element == EL_SP_ELECTRON) @@ -5954,10 +4986,6 @@ void StartMoving(int x, int y) dir == MV_DOWN ? IMG_FLAMES_1_DOWN : IMG_EMPTY); int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); -#if 0 - printf("::: %d, %d\n", GfxAction[x][y], GfxFrame[x][y]); -#endif - GfxAction[x][y] = ACTION_ATTACKING; if (IS_PLAYER(x, y)) @@ -5997,16 +5025,10 @@ void StartMoving(int x, int y) RemoveMovingField(xx, yy); #endif -#if 0 - if (ChangeDelay[xx][yy]) - printf("::: !!! [%d]\n", (IS_MOVING(xx, yy) || - Feld[xx][yy] == EL_BLOCKED)); -#endif - -#if 1 ChangeDelay[xx][yy] = 0; -#endif + Feld[xx][yy] = EL_FLAMES; + if (IN_SCR_FIELD(sx, sy)) { DrawLevelFieldCrumbledSand(xx, yy); @@ -6028,13 +5050,6 @@ void StartMoving(int x, int y) return; } - -#if 0 - /* special case of "moving" animation of waiting elements (FIX THIS !!!); - for all other elements GfxAction will be set by InitMovingField() */ - if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY) - GfxAction[x][y] = ACTION_MOVING; -#endif } /* now make next step */ @@ -6045,38 +5060,15 @@ void StartMoving(int x, int y) IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) && !PLAYER_ENEMY_PROTECTED(newx, newy)) { -#if 1 - TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]); + TestIfBadThingRunsIntoPlayer(x, y, MovDir[x][y]); return; -#else - /* player killed by element which is deadly when colliding with */ - MovDir[x][y] = 0; - KillHero(PLAYERINFO(newx, newy)); - return; -#endif - } -#if 1 -#if 1 + else if (CAN_MOVE_INTO_ACID(element) && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID && (MovDir[x][y] == MV_DOWN || game.engine_version >= VERSION_IDENT(3,1,0,0))) -#else - else if (CAN_MOVE_INTO_ACID(element) && MovDir[x][y] == MV_DOWN && - IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID) -#endif -#else - - else if ((element == EL_PENGUIN || - element == EL_ROBOT || - element == EL_SATELLITE || - element == EL_BALLOON || - IS_CUSTOM_ELEMENT(element)) && - IN_LEV_FIELD(newx, newy) && - MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID) -#endif { SplashAcid(newx, newy); Store[x][y] = EL_ACID; @@ -6085,13 +5077,8 @@ void StartMoving(int x, int y) { if (Feld[newx][newy] == EL_EXIT_OPEN) { -#if 1 RemoveField(x, y); DrawLevelField(x, y); -#else - Feld[x][y] = EL_EMPTY; - DrawLevelField(x, y); -#endif PlayLevelSound(newx, newy, SND_PENGUIN_PASSING); if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) @@ -6147,32 +5134,11 @@ void StartMoving(int x, int y) return; } } - -#if 1 - - /* - else if (move_pattern & MV_MAZE_RUNNER_STYLE && IN_LEV_FIELD(newx, newy)) - */ - else if (IS_CUSTOM_ELEMENT(element) && - CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy) - -#if 0 - && - !IS_FREE(newx, newy) -#endif - -) + CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) { int new_element = Feld[newx][newy]; -#if 0 - printf("::: '%s' digs '%s' [%d]\n", - element_info[element].token_name, - element_info[Feld[newx][newy]].token_name, - StorePlayer[newx][newy]); -#endif - if (!IS_FREE(newx, newy)) { int action = (IS_DIGGABLE(new_element) ? ACTION_DIGGING : @@ -6208,21 +5174,15 @@ void StartMoving(int x, int y) PlayLevelSoundAction(x, y, action); } -#if 1 -#if 1 - Store[newx][newy] = EL_EMPTY; - if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) - Store[newx][newy] = element_info[element].move_leave_element; -#else Store[newx][newy] = EL_EMPTY; - if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)) || - element_info[element].move_leave_type == LEAVE_TYPE_UNLIMITED) - Store[newx][newy] = element_info[element].move_leave_element; -#endif -#else if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) - element_info[element].can_leave_element = TRUE; -#endif + { + int move_leave_element = element_info[element].move_leave_element; + + /* this makes it possible to leave the removed element again */ + Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ? + new_element : move_leave_element); + } if (move_pattern & MV_MAZE_RUNNER_STYLE) { @@ -6230,9 +5190,6 @@ void StartMoving(int x, int y) PlayerVisit[x][y] /= 8; /* expire player visit path */ } } - -#endif - else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy)) { if (!IS_FREE(newx, newy)) @@ -6261,10 +5218,8 @@ void StartMoving(int x, int y) element1 != EL_DRAGON && element2 != EL_DRAGON && element1 != EL_FLAMES && element2 != EL_FLAMES) { -#if 1 ResetGfxAnimation(x, y); GfxAction[x][y] = ACTION_ATTACKING; -#endif if (IS_PLAYER(x, y)) DrawPlayerField(x, y); @@ -6326,12 +5281,15 @@ void StartMoving(int x, int y) #if 0 /* !!! test !!! */ if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy)) + { + RemoveMovingField(newx, newy); + } #else if (IS_MOVING(newx, newy)) -#endif { RemoveMovingField(newx, newy); } +#endif else { Feld[newx][newy] = EL_EMPTY; @@ -6385,19 +5343,13 @@ void StartMoving(int x, int y) TurnRound(x, y); #if 0 + /* !!! NEW "CE_BLOCKED" STUFF !!! -- DOES NOT WORK YET... !!! */ if (move_pattern & MV_ANY_DIRECTION && move_pattern == MovDir[x][y]) { int blocking_element = (IN_LEV_FIELD(newx, newy) ? Feld[newx][newy] : BorderElement); -#if 0 - printf("::: '%s' is blocked by '%s'! [%d,%d -> %d,%d]\n", - element_info[element].token_name, - element_info[blocking_element].token_name, - x, y, newx, newy); -#endif - CheckElementChangeBySide(x, y, element, blocking_element, CE_BLOCKED, MovDir[x][y]); @@ -6405,31 +5357,11 @@ void StartMoving(int x, int y) } #endif -#if 1 if (GFX_ELEMENT(element) != EL_SAND) /* !!! FIX THIS (crumble) !!! */ DrawLevelElementAnimation(x, y, element); -#else - if (element == EL_BUG || - element == EL_SPACESHIP || - element == EL_SP_SNIKSNAK) - DrawLevelField(x, y); - else if (element == EL_MOLE) - DrawLevelField(x, y); - else if (element == EL_BD_BUTTERFLY || - element == EL_BD_FIREFLY) - DrawLevelElementAnimationIfNeeded(x, y, element); - else if (element == EL_SATELLITE) - DrawLevelElementAnimationIfNeeded(x, y, element); - else if (element == EL_SP_ELECTRON) - DrawLevelElementAnimationIfNeeded(x, y, element); -#endif if (DONT_TOUCH(element)) - TestIfBadThingTouchesHero(x, y); - -#if 0 - PlayLevelSoundAction(x, y, ACTION_WAITING); -#endif + TestIfBadThingTouchesPlayer(x, y); return; } @@ -6452,28 +5384,14 @@ void ContinueMoving(int x, int y) int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int newx = x + dx, newy = y + dy; -#if 0 - int nextx = newx + dx, nexty = newy + dy; -#endif -#if 1 boolean pushed_by_player = (Pushed[x][y] && IS_PLAYER(x, y)); boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y)); -#else - boolean pushed_by_player = Pushed[x][y]; -#endif + boolean last_line = (newy == lev_fieldy - 1); MovPos[x][y] += getElementMoveStepsize(x, y); -#if 0 - if (pushed_by_player && IS_PLAYER(x, y)) - { - /* special case: moving object pushed by player */ - MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); - } -#else if (pushed_by_player) /* special case: moving object pushed by player */ MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); -#endif if (ABS(MovPos[x][y]) < TILEX) { @@ -6488,12 +5406,10 @@ void ContinueMoving(int x, int y) Feld[newx][newy] = element; MovPos[x][y] = 0; /* force "not moving" for "crumbled sand" */ -#if 1 if (Store[x][y] == EL_ACID) /* element is moving into acid pool */ { element = Feld[newx][newy] = EL_ACID; } -#endif else if (element == EL_MOLE) { Feld[x][y] = EL_SAND; @@ -6523,6 +5439,10 @@ void ContinueMoving(int x, int y) if (!game.magic_wall_active) Feld[x][y] = EL_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; + +#if USE_NEW_COLLECT_COUNT + InitField(newx, newy, FALSE); +#endif } else if (element == EL_BD_MAGIC_WALL_FILLING) { @@ -6537,6 +5457,10 @@ void ContinueMoving(int x, int y) if (!game.magic_wall_active) Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; + +#if USE_NEW_COLLECT_COUNT + InitField(newx, newy, FALSE); +#endif } else if (element == EL_AMOEBA_DROPPING) { @@ -6553,32 +5477,12 @@ void ContinueMoving(int x, int y) Back[x][y] = Back[newx][newy] = 0; } -#if 0 - else if (Store[x][y] == EL_ACID) - { - element = Feld[newx][newy] = EL_ACID; - } -#endif -#if 0 - else if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) && - ei->move_leave_element != EL_EMPTY && - (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || - Store[x][y] != EL_EMPTY)) - { - /* some elements can leave other elements behind after moving */ - - Feld[x][y] = ei->move_leave_element; - InitField(x, y, FALSE); - - if (GFX_CRUMBLED(Feld[x][y])) - DrawLevelFieldCrumbledSandNeighbours(x, y); - } -#endif Store[x][y] = EL_EMPTY; MovPos[x][y] = 0; MovDir[x][y] = 0; MovDelay[x][y] = 0; + MovDelay[newx][newy] = 0; if (CAN_CHANGE(element)) @@ -6588,6 +5492,10 @@ void ContinueMoving(int x, int y) ChangePage[newx][newy] = ChangePage[x][y]; Changed[newx][newy] = Changed[x][y]; ChangeEvent[newx][newy] = ChangeEvent[x][y]; + +#if USE_NEW_COLLECT_COUNT + Count[newx][newy] = Count[x][y]; +#endif } ChangeDelay[x][y] = 0; @@ -6595,6 +5503,10 @@ void ContinueMoving(int x, int y) Changed[x][y] = FALSE; ChangeEvent[x][y] = -1; +#if USE_NEW_COLLECT_COUNT + Count[x][y] = 0; +#endif + /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */ @@ -6603,31 +5515,22 @@ void ContinueMoving(int x, int y) Pushed[x][y] = Pushed[newx][newy] = FALSE; -#if 0 - /* do this after checking for left-behind element */ - ResetGfxAnimation(x, y); /* reset animation values for old field */ -#endif - -#if 1 /* some elements can leave other elements behind after moving */ -#if 1 if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) -#else - if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY && - (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && - !IS_PLAYER(x, y)) -#endif { int move_leave_element = ei->move_leave_element; + /* this makes it possible to leave the removed element again */ + if (ei->move_leave_type == LEAVE_TYPE_LIMITED && + ei->move_leave_element == EL_TRIGGER_ELEMENT) + move_leave_element = stored; + Feld[x][y] = move_leave_element; -#if USE_PREVIOUS_MOVE_DIR if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS) MovDir[x][y] = direction; -#endif InitField(x, y, FALSE); @@ -6637,63 +5540,16 @@ void ContinueMoving(int x, int y) if (ELEM_IS_PLAYER(move_leave_element)) RelocatePlayer(x, y, move_leave_element); } -#endif - -#if 0 - /* some elements can leave other elements behind after moving */ - if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) && - ei->move_leave_element != EL_EMPTY && - (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || - ei->can_leave_element_last)) - { - Feld[x][y] = ei->move_leave_element; - InitField(x, y, FALSE); - - if (GFX_CRUMBLED(Feld[x][y])) - DrawLevelFieldCrumbledSandNeighbours(x, y); - } - - ei->can_leave_element_last = ei->can_leave_element; - ei->can_leave_element = FALSE; -#endif -#if 1 /* do this after checking for left-behind element */ ResetGfxAnimation(x, y); /* reset animation values for old field */ -#endif - -#if 0 - /* 2.1.1 (does not work correctly for spring) */ - if (!CAN_MOVE(element)) - MovDir[newx][newy] = 0; -#else - -#if 0 - /* (does not work for falling objects that slide horizontally) */ - if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN) - MovDir[newx][newy] = 0; -#else - /* - if (!CAN_MOVE(element) || - (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN)) - MovDir[newx][newy] = 0; - */ -#if 0 - if (!CAN_MOVE(element) || - (CAN_FALL(element) && direction == MV_DOWN)) - GfxDir[x][y] = MovDir[newx][newy] = 0; -#else if (!CAN_MOVE(element) || (CAN_FALL(element) && direction == MV_DOWN && (element == EL_SPRING || element_info[element].move_pattern == MV_WHEN_PUSHED || element_info[element].move_pattern == MV_WHEN_DROPPED))) GfxDir[x][y] = MovDir[newx][newy] = 0; -#endif - -#endif -#endif DrawLevelField(x, y); DrawLevelField(newx, newy); @@ -6706,21 +5562,10 @@ void ContinueMoving(int x, int y) !(element_info[element].move_pattern & direction)) TurnRound(newx, newy); -#if 1 /* prevent elements on conveyor belt from moving on in last direction */ if (pushed_by_conveyor && CAN_FALL(element) && direction & MV_HORIZONTAL) - { -#if 0 - if (CAN_MOVE(element)) - InitMovDir(newx, newy); - else - MovDir[newx][newy] = 0; -#else MovDir[newx][newy] = 0; -#endif - } -#endif if (!pushed_by_player) { @@ -6738,7 +5583,7 @@ void ContinueMoving(int x, int y) if (DONT_TOUCH(element)) /* object may be nasty to player or others */ { - TestIfBadThingTouchesHero(newx, newy); + TestIfBadThingTouchesPlayer(newx, newy); TestIfBadThingTouchesFriend(newx, newy); if (!IS_CUSTOM_ELEMENT(element)) @@ -6747,146 +5592,27 @@ void ContinueMoving(int x, int y) else if (element == EL_PENGUIN) TestIfFriendTouchesBadThing(newx, newy); -#if USE_NEW_MOVE_STYLE -#if 0 - if (CAN_FALL(element) && direction == MV_DOWN && - (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) && - IS_PLAYER(x, newy + 1)) - printf("::: we would now kill the player [%d]\n", FrameCounter); -#endif - /* give the player one last chance (one more frame) to move away */ if (CAN_FALL(element) && direction == MV_DOWN && - (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) && - ((newy < lev_fieldy - 1 && !IS_PLAYER(x, newy + 1)) || - game.engine_version < VERSION_IDENT(3,1,1,0))) + (last_line || (!IS_FREE(x, newy + 1) && + (!IS_PLAYER(x, newy + 1) || + game.engine_version < VERSION_IDENT(3,1,1,0))))) Impact(x, newy); -#else - if (CAN_FALL(element) && direction == MV_DOWN && - (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1))) - Impact(x, newy); -#endif - -#if 1 -#if USE_PUSH_BUGFIX -#if 1 if (pushed_by_player && !game.use_change_when_pushing_bug) -#else - if (pushed_by_player && game.engine_version >= VERSION_IDENT(3,1,0,0)) -#endif -#else - if (pushed_by_player) -#endif - { -#if 1 int dig_side = MV_DIR_OPPOSITE(direction); -#else - static int trigger_sides[4] = - { - CH_SIDE_RIGHT, /* moving left */ - CH_SIDE_LEFT, /* moving right */ - CH_SIDE_BOTTOM, /* moving up */ - CH_SIDE_TOP, /* moving down */ - }; - int dig_side = trigger_sides[MV_DIR_BIT(direction)]; -#endif struct PlayerInfo *player = PLAYERINFO(x, y); CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER, player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X, + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PUSHES_X, player->index_bit, dig_side); } -#endif -#if 1 TestIfElementTouchesCustomElement(x, y); /* empty or new element */ -#endif - -#if 0 - if (ChangePage[newx][newy] != -1) /* delayed change */ - ChangeElement(newx, newy, ChangePage[newx][newy]); -#endif - -#if 1 TestIfElementHitsCustomElement(newx, newy, direction); - -#else - - if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) - { - int hitting_element = Feld[newx][newy]; - - /* !!! fix side (direction) orientation here and elsewhere !!! */ - CheckElementChangeBySide(newx, newy, hitting_element, CE_HITTING_SOMETHING, - direction); - -#if 0 - if (IN_LEV_FIELD(nextx, nexty)) - { - int opposite_direction = MV_DIR_OPPOSITE(direction); - int hitting_side = direction; - int touched_side = opposite_direction; - int touched_element = MovingOrBlocked2Element(nextx, nexty); - boolean object_hit = (!IS_MOVING(nextx, nexty) || - MovDir[nextx][nexty] != direction || - ABS(MovPos[nextx][nexty]) <= TILEY / 2); - - if (object_hit) - { - int i; - - CheckElementChangeBySide(nextx, nexty, touched_element, - CE_HIT_BY_SOMETHING, opposite_direction); - - if (IS_CUSTOM_ELEMENT(hitting_element) && - HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X)) - { - for (i = 0; i < element_info[hitting_element].num_change_pages; i++) - { - struct ElementChangeInfo *change = - &element_info[hitting_element].change_page[i]; - - if (change->can_change && - change->has_event[CE_HITTING_X] && - change->trigger_side & touched_side && - change->trigger_element == touched_element) - { - CheckElementChangeByPage(newx, newy, hitting_element, - touched_element, CE_HITTING_X, i); - break; - } - } - } - - if (IS_CUSTOM_ELEMENT(touched_element) && - HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X)) - { - for (i = 0; i < element_info[touched_element].num_change_pages; i++) - { - struct ElementChangeInfo *change = - &element_info[touched_element].change_page[i]; - - if (change->can_change && - change->has_event[CE_HIT_BY_X] && - change->trigger_side & hitting_side && - change->trigger_element == hitting_element) - { - CheckElementChangeByPage(nextx, nexty, touched_element, - hitting_element, CE_HIT_BY_X,i); - break; - } - } - } - } - } -#endif - } -#endif - TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); } @@ -7081,14 +5807,7 @@ void AmoebeWaechst(int x, int y) if (DelayReached(&sound_delay, sound_delay_value)) { -#if 1 PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING); -#else - if (Store[x][y] == EL_BD_AMOEBA) - PlayLevelSound(x, y, SND_BD_AMOEBA_GROWING); - else - PlayLevelSound(x, y, SND_AMOEBA_GROWING); -#endif sound_delay_value = 30; } } @@ -7192,7 +5911,6 @@ void AmoebeAbleger(int ax, int ay) if (!IN_LEV_FIELD(x, y)) return; -#if 1 if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || Feld[x][y] == EL_QUICKSAND_EMPTY) @@ -7200,15 +5918,6 @@ void AmoebeAbleger(int ax, int ay) newax = x; neway = y; } -#else - /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ - if (IS_FREE(x, y) || - Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY) - { - newax = x; - neway = y; - } -#endif if (newax == ax && neway == ay) return; @@ -7227,7 +5936,6 @@ void AmoebeAbleger(int ax, int ay) if (!IN_LEV_FIELD(x, y)) continue; -#if 1 if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || Feld[x][y] == EL_QUICKSAND_EMPTY) @@ -7236,27 +5944,13 @@ void AmoebeAbleger(int ax, int ay) neway = y; break; } -#else - /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ - if (IS_FREE(x, y) || - Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY) - { - newax = x; - neway = y; - break; - } -#endif else if (IS_PLAYER(x, y)) waiting_for_player = TRUE; } if (newax == ax && neway == ay) /* amoeba cannot grow */ { -#if 1 if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA)) -#else - if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH)) -#endif { Feld[ax][ay] = EL_AMOEBA_DEAD; DrawLevelField(ax, ay); @@ -7311,11 +6005,8 @@ void AmoebeAbleger(int ax, int ay) else if (neway == ay) { Feld[newax][neway] = EL_AMOEBA_DROP; /* drop left/right of amoeba */ -#if 1 + PlayLevelSoundAction(newax, neway, ACTION_GROWING); -#else - PlayLevelSound(newax, neway, SND_AMOEBA_GROWING); -#endif } else { @@ -7387,7 +6078,6 @@ void Life(int ax, int ay) changed = TRUE; } } -#if 1 else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy])) { /* free border field */ if (nachbarn >= life[2] && nachbarn <= life[3]) @@ -7400,21 +6090,6 @@ void Life(int ax, int ay) changed = TRUE; } } -#else - /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ - else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND) - { /* free border field */ - if (nachbarn >= life[2] && nachbarn <= life[3]) - { - Feld[xx][yy] = element; - MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1); - if (!Stop[xx][yy]) - DrawLevelField(xx, yy); - Stop[xx][yy] = TRUE; - changed = TRUE; - } - } -#endif } if (changed) @@ -7440,12 +6115,7 @@ static void StopRobotWheel(int x, int y) static void InitTimegateWheel(int x, int y) { -#if 1 ChangeDelay[x][y] = level.time_timegate * FRAMES_PER_SECOND; -#else - /* another brainless, "type style" bug ... :-( */ - ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND; -#endif } static void RunTimegateWheel(int x, int y) @@ -7510,11 +6180,8 @@ static void CloseAllOpenTimegates() if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING) { Feld[x][y] = EL_TIMEGATE_CLOSING; -#if 1 + PlayLevelSoundAction(x, y, ACTION_CLOSING); -#else - PlayLevelSound(x, y, SND_TIMEGATE_CLOSING); -#endif } } } @@ -7716,11 +6383,7 @@ void MauerAbleger(int ax, int ay) Feld[ax][ay] = EL_WALL; if (new_wall) -#if 1 PlayLevelSoundAction(ax, ay, ACTION_GROWING); -#else - PlayLevelSound(ax, ay, SND_EXPANDABLE_WALL_GROWING); -#endif } void CheckForDragon(int x, int y) @@ -7829,142 +6492,460 @@ static void ChangeActiveTrap(int x, int y) DrawLevelFieldCrumbledSand(x, y); } -static void ChangeElementNowExt(int x, int y, int target_element) +static int getSpecialActionElement(int element, int number, int base_element) { - int previous_move_direction = MovDir[x][y]; -#if 1 - boolean add_player = (ELEM_IS_PLAYER(target_element) && - IS_WALKABLE(Feld[x][y])); -#else - boolean add_player = (ELEM_IS_PLAYER(target_element) && - IS_WALKABLE(Feld[x][y]) && - !IS_MOVING(x, y)); -#endif + return (element != EL_EMPTY ? element : + number != -1 ? base_element + number - 1 : + EL_EMPTY); +} - /* check if element under 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(target_element)) - { -#if 0 - printf("::: BOOOM! [%d, '%s']\n", target_element, - element_info[target_element].token_name); -#endif +static int getModifiedActionNumber(int value_old, int operator, int operand, + int value_min, int value_max) +{ + int value_new = (operator == CA_MODE_SET ? operand : + operator == CA_MODE_ADD ? value_old + operand : + operator == CA_MODE_SUBTRACT ? value_old - operand : + operator == CA_MODE_MULTIPLY ? value_old * operand : + operator == CA_MODE_DIVIDE ? value_old / MAX(1, operand) : + operator == CA_MODE_MODULO ? value_old % MAX(1, operand) : + value_old); - Bang(x, y); + return (value_new < value_min ? value_min : + value_new > value_max ? value_max : + value_new); +} + +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 action_type = change->action_type; + int action_mode = change->action_mode; + int action_arg = change->action_arg; + int i; + + if (!change->has_action) return; - } -#if 1 - if (!add_player) -#endif - { -#if 1 - if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) - RemoveMovingField(x, y); - else - RemoveField(x, y); + /* ---------- determine action paramater values ---------- */ + + int action_arg_element = + (action_arg == CA_ARG_PLAYER_TRIGGER ? change->actual_trigger_player : + action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element : + action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element : + EL_EMPTY); + + int action_arg_number_min = + (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MIN : + CA_ARG_MIN); + + int action_arg_number_max = + (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MAX : + action_type == CA_SET_GEMS ? 999 : + action_type == CA_SET_TIME ? 9999 : + action_type == CA_SET_SCORE ? 99999 : + action_type == CA_SET_CE_SCORE ? 9999 : + action_type == CA_SET_CE_COUNT ? 9999 : + CA_ARG_MAX); + + int action_arg_number_reset = + (action_type == CA_SET_PLAYER_SPEED ? TILEX/game.initial_move_delay_value : + action_type == CA_SET_GEMS ? level.gems_needed : + action_type == CA_SET_TIME ? level.time : + action_type == CA_SET_SCORE ? 0 : + action_type == CA_SET_CE_SCORE ? 0 : + action_type == CA_SET_CE_COUNT ? ei->collect_count_initial : + 0); + + int action_arg_number_normal = + (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_NORMAL : + action_arg_number_reset); + + int action_arg_number = + (action_arg <= CA_ARG_MAX ? action_arg : + 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_NORMAL ? action_arg_number_normal : + action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : +#if USE_NEW_COLLECT_COUNT + action_arg == CA_ARG_NUMBER_CE_COUNT ? Count[x][y] : +#else + action_arg == CA_ARG_NUMBER_CE_COUNT ? ei->collect_count_initial : +#endif + action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CHANGE_DELAY(change) : + -1); + + int action_arg_number_old = + (action_type == CA_SET_GEMS ? local_player->gems_still_needed : + action_type == CA_SET_TIME ? TimeLeft : + action_type == CA_SET_SCORE ? local_player->score : + action_type == CA_SET_CE_SCORE ? ei->collect_score : + action_type == CA_SET_CE_COUNT ? Count[x][y] : + 0); + + int action_arg_number_new = + getModifiedActionNumber(action_arg_number_old, + action_mode, action_arg_number, + action_arg_number_min, action_arg_number_max); + + /* (for explicit player choice, set invalid value to "no player") */ + int action_arg_player_bits = + (action_arg == CA_ARG_PLAYER_ANY ? action_arg - CA_ARG_PLAYER : + action_arg >= CA_ARG_PLAYER_1 && + action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER : + action_arg >= CA_ARG_1 && + action_arg <= CA_ARG_PLAYER_4 ? (1 << (action_arg - 1)) : + action_arg_element >= EL_PLAYER_1 && + action_arg_element <= EL_PLAYER_4 ? + (1 << (action_arg_element - EL_PLAYER_1)) : + 0); + + /* (for implicit player choice, set invalid value to "all players") */ + int trigger_player_bits = + (change->actual_trigger_player >= EL_PLAYER_1 && + change->actual_trigger_player <= EL_PLAYER_4 ? + (1 << (change->actual_trigger_player - EL_PLAYER_1)) : + PLAYER_BITS_ANY); + + /* ---------- execute action ---------- */ + + switch(action_type) + { + case CA_NO_ACTION: + { + return; + } - Feld[x][y] = target_element; -#else - RemoveField(x, y); - Feld[x][y] = target_element; -#endif + case CA_EXIT_PLAYER: + { + for (i = 0; i < MAX_PLAYERS; i++) + if (action_arg_player_bits & (1 << i)) + stored_player[i].LevelSolved = stored_player[i].GameOver = TRUE; - ResetGfxAnimation(x, y); - ResetRandomAnimationValue(x, y); + break; + } - if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS) - MovDir[x][y] = previous_move_direction; + case CA_KILL_PLAYER: + { + for (i = 0; i < MAX_PLAYERS; i++) + if (action_arg_player_bits & (1 << i)) + KillPlayer(&stored_player[i]); -#if 1 - InitField_WithBug1(x, y, FALSE); -#else - InitField(x, y, FALSE); - if (CAN_MOVE(Feld[x][y])) - InitMovDir(x, y); -#endif + break; + } - DrawLevelField(x, y); + case CA_RESTART_LEVEL: + { + game.restart_level = TRUE; - if (GFX_CRUMBLED(Feld[x][y])) - DrawLevelFieldCrumbledSandNeighbours(x, y); - } + break; + } -#if 0 - Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ -#endif + case CA_SHOW_ENVELOPE: + { + int element = getSpecialActionElement(action_arg_element, + action_arg_number, EL_ENVELOPE_1); -#if 0 - TestIfBadThingTouchesHero(x, y); - TestIfPlayerTouchesCustomElement(x, y); - TestIfElementTouchesCustomElement(x, y); -#endif + if (IS_ENVELOPE(element)) + local_player->show_envelope = element; - /* "Changed[][]" not set yet to allow "entered by player" change one time */ - if (ELEM_IS_PLAYER(target_element)) - RelocatePlayer(x, y, target_element); + break; + } -#if 1 - Changed[x][y] = TRUE; /* ignore all further changes in this frame */ -#else - Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ -#endif + case CA_ADD_KEY: + { + int element = getSpecialActionElement(action_arg_element, + action_arg_number, EL_KEY_1); -#if 1 - TestIfBadThingTouchesHero(x, y); - TestIfPlayerTouchesCustomElement(x, y); - TestIfElementTouchesCustomElement(x, y); -#endif -} + if (IS_KEY(element)) + { + for (i = 0; i < MAX_PLAYERS; i++) + { + if (trigger_player_bits & (1 << i)) + { + stored_player[i].key[KEY_NR(element)] = TRUE; -static boolean ChangeElementNow(int x, int y, int element, int page) -{ - struct ElementChangeInfo *change = &element_info[element].change_page[page]; - int target_element; - int old_element = Feld[x][y]; + DrawGameValue_Keys(stored_player[i].key); - /* always use default change event to prevent running into a loop */ - if (ChangeEvent[x][y] == -1) - ChangeEvent[x][y] = CE_DELAY; + redraw_mask |= REDRAW_DOOR_1; + } + } + } - if (ChangeEvent[x][y] == CE_DELAY) - { - /* reset actual trigger element and player */ - change->actual_trigger_element = EL_EMPTY; - change->actual_trigger_player = EL_PLAYER_1; - } + break; + } -#if 1 - /* do not change any elements that have already changed in this frame */ - if (Changed[x][y]) - return FALSE; -#else - /* do not change already changed elements with same change event */ - if (Changed[x][y] & ChangeEvent[x][y]) - return FALSE; -#endif + case CA_DEL_KEY: + { + int element = getSpecialActionElement(action_arg_element, + action_arg_number, EL_KEY_1); -#if 1 - Changed[x][y] = TRUE; /* ignore all further changes in this frame */ -#else - Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ -#endif + if (IS_KEY(element)) + { + for (i = 0; i < MAX_PLAYERS; i++) + { + if (trigger_player_bits & (1 << i)) + { + stored_player[i].key[KEY_NR(element)] = FALSE; -#if 0 - /* !!! indirect change before direct change !!! */ - CheckTriggeredElementChangeByPage(x, y, Feld[x][y], CE_CHANGE_OF_X, page); -#endif + DrawGameValue_Keys(stored_player[i].key); - if (change->explode) - { - Bang(x, y); + redraw_mask |= REDRAW_DOOR_1; + } + } + } - return TRUE; - } + break; + } - if (change->use_target_content) - { + case CA_SET_PLAYER_SPEED: + { + for (i = 0; i < MAX_PLAYERS; i++) + { + if (trigger_player_bits & (1 << i)) + { + int move_stepsize = TILEX / stored_player[i].move_delay_value; + + if (action_mode == CA_MODE_ADD || action_mode == CA_MODE_SUBTRACT) + { + /* translate "+" and "-" to "*" and "/" with powers of two */ + action_arg_number = 1 << action_arg_number; + action_mode = (action_mode == CA_MODE_ADD ? CA_MODE_MULTIPLY : + CA_MODE_DIVIDE); + } + + move_stepsize = + getModifiedActionNumber(move_stepsize, + action_mode, + action_arg_number, + action_arg_number_min, + action_arg_number_max); + + /* make sure that value is power of 2 */ + move_stepsize = (1 << log_2(move_stepsize)); + + stored_player[i].move_delay_value = TILEX / move_stepsize; + +#if 0 + printf("::: move_delay_value == %d [%d]\n", + stored_player[i].move_delay_value, action_arg_number); +#endif + } + } + + break; + } + + case CA_SET_GEMS: + { + local_player->gems_still_needed = action_arg_number_new; + + DrawGameValue_Emeralds(local_player->gems_still_needed); + + break; + } + + case CA_SET_TIME: + { + if (level.time > 0) /* only modify limited time value */ + { + TimeLeft = action_arg_number_new; + + DrawGameValue_Time(TimeLeft); + + if (!TimeLeft && setup.time_limit) + for (i = 0; i < MAX_PLAYERS; i++) + KillPlayer(&stored_player[i]); + } + + break; + } + + case CA_SET_SCORE: + { + local_player->score = action_arg_number_new; + + DrawGameValue_Score(local_player->score); + + break; + } + + case CA_SET_CE_SCORE: + { + ei->collect_score = action_arg_number_new; + + break; + } + + case CA_SET_CE_COUNT: + { +#if USE_NEW_COLLECT_COUNT + int count_last = Count[x][y]; + + Count[x][y] = action_arg_number_new; + +#if 0 + printf("::: Count == %d\n", Count[x][y]); +#endif + + if (Count[x][y] == 0 && count_last > 0) + { +#if 0 + printf("::: CE_COUNT_AT_ZERO\n"); +#endif + + CheckElementChange(x, y, element, EL_UNDEFINED, CE_COUNT_AT_ZERO); + CheckTriggeredElementChange(element, CE_COUNT_AT_ZERO_OF_X); + } +#endif + + break; + } + + case CA_SET_DYNABOMB_NUMBER: + { + printf("::: CA_SET_DYNABOMB_NUMBER -- not yet implemented\n"); + + break; + } + + case CA_SET_DYNABOMB_SIZE: + { + printf("::: CA_SET_DYNABOMB_SIZE -- not yet implemented\n"); + + break; + } + + case CA_SET_DYNABOMB_POWER: + { + printf("::: CA_SET_DYNABOMB_POWER -- not yet implemented\n"); + + break; + } + + case CA_TOGGLE_PLAYER_GRAVITY: + { + game.gravity = !game.gravity; + + break; + } + + case CA_ENABLE_PLAYER_GRAVITY: + { + game.gravity = TRUE; + + break; + } + + case CA_DISABLE_PLAYER_GRAVITY: + { + game.gravity = FALSE; + + break; + } + + default: + break; + } +} + +static void ChangeElementNowExt(struct ElementChangeInfo *change, + int x, int y, int target_element) +{ + int previous_move_direction = MovDir[x][y]; + boolean add_player = (ELEM_IS_PLAYER(target_element) && + IS_WALKABLE(Feld[x][y])); + + /* check if element under 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(target_element)) + { + Bang(x, y); + return; + } + + if (!add_player) + { + if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) + RemoveMovingField(x, y); + else + RemoveField(x, y); + + Feld[x][y] = target_element; + + ResetGfxAnimation(x, y); + ResetRandomAnimationValue(x, y); + + if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS) + MovDir[x][y] = previous_move_direction; + + InitField_WithBug1(x, y, FALSE); + + DrawLevelField(x, y); + + if (GFX_CRUMBLED(Feld[x][y])) + DrawLevelFieldCrumbledSandNeighbours(x, y); + } + + /* "Changed[][]" not set yet to allow "entered by player" change one time */ + if (ELEM_IS_PLAYER(target_element)) + RelocatePlayer(x, y, target_element); + +#if 1 + Changed[x][y] = TRUE; /* ignore all further changes in this frame */ +#else + Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ +#endif + + TestIfBadThingTouchesPlayer(x, y); + TestIfPlayerTouchesCustomElement(x, y); + TestIfElementTouchesCustomElement(x, y); +} + +static boolean ChangeElementNow(int x, int y, int element, int page) +{ + struct ElementChangeInfo *change = &element_info[element].change_page[page]; + int target_element; + int old_element = Feld[x][y]; + + /* always use default change event to prevent running into a loop */ + if (ChangeEvent[x][y] == -1) + ChangeEvent[x][y] = CE_DELAY; + + if (ChangeEvent[x][y] == CE_DELAY) + { + /* reset actual trigger element, trigger player and action element */ + change->actual_trigger_element = EL_EMPTY; + change->actual_trigger_player = EL_PLAYER_1; + } + +#if 1 + /* do not change any elements that have already changed in this frame */ + if (Changed[x][y]) + return FALSE; +#else + /* do not change already changed elements with same change event */ + if (Changed[x][y] & ChangeEvent[x][y]) + return FALSE; +#endif + +#if 1 + Changed[x][y] = TRUE; /* ignore all further changes in this frame */ +#else + Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ +#endif + + if (change->explode) + { + Bang(x, y); + + return TRUE; + } + + if (change->use_target_content) + { boolean complete_replace = TRUE; boolean can_replace[3][3]; int xx, yy; @@ -8002,39 +6983,13 @@ static boolean ChangeElementNow(int x, int y, int element, int page) continue; } -#if 0 - if (Changed[ex][ey]) /* do not change already changed elements */ - { - can_replace[xx][yy] = FALSE; - complete_replace = FALSE; - - continue; - } -#endif - e = Feld[ex][ey]; if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) e = MovingOrBlocked2Element(ex, ey); -#if 1 - -#if 0 - is_empty = (IS_FREE(ex, ey) || - (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element)) || - (IS_WALKABLE(e) && ELEM_IS_PLAYER(content_element) && - !IS_MOVING(ex, ey) && !IS_BLOCKED(ex, ey))); -#else - -#if 0 - is_empty = (IS_FREE(ex, ey) || - (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element))); -#else is_empty = (IS_FREE(ex, ey) || (IS_FREE_OR_PLAYER(ex, ey) && IS_WALKABLE(content_element))); -#endif - -#endif is_walkable = (is_empty || IS_WALKABLE(e)); is_diggable = (is_empty || IS_DIGGABLE(e)); @@ -8053,23 +7008,6 @@ static boolean ChangeElementNow(int x, int y, int element, int page) if (!can_replace[xx][yy]) complete_replace = FALSE; -#else - empty_for_element = (IS_FREE(ex, ey) || (IS_FREE_OR_PLAYER(ex, ey) && - IS_WALKABLE(content_element))); -#if 1 - half_destructible = (empty_for_element || IS_DIGGABLE(e)); -#else - half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e)); -#endif - - if ((change->replace_when <= CP_WHEN_EMPTY && !empty_for_element) || - (change->replace_when <= CP_WHEN_DIGGABLE && !half_destructible) || - (change->replace_when <= CP_WHEN_DESTRUCTIBLE && IS_INDESTRUCTIBLE(e))) - { - can_replace[xx][yy] = FALSE; - complete_replace = FALSE; - } -#endif } if (!change->only_if_complete || complete_replace) @@ -8097,7 +7035,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page) content_element = change->target_content[xx][yy]; target_element = GET_TARGET_ELEMENT(content_element, change); - ChangeElementNowExt(ex, ey, target_element); + ChangeElementNowExt(change, ex, ey, target_element); something_has_changed = TRUE; @@ -8115,15 +7053,13 @@ static boolean ChangeElementNow(int x, int y, int element, int page) { target_element = GET_TARGET_ELEMENT(change->target_element, change); - ChangeElementNowExt(x, y, target_element); + ChangeElementNowExt(change, x, y, target_element); PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); } -#if 1 /* this uses direct change before indirect change */ - CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page); -#endif + CheckTriggeredElementChangeByPage(old_element, CE_CHANGE_OF_X, page); return TRUE; } @@ -8158,8 +7094,7 @@ static void ChangeElement(int x, int y, int page) if (ChangeDelay[x][y] == 0) /* initialize element change */ { - ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames + - RND(change->delay_random * change->delay_frames)) + 1; + ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1; ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); @@ -8190,11 +7125,7 @@ static void ChangeElement(int x, int y, int page) change = &ei->change_page[page]; } -#if 0 - if (IS_MOVING(x, y) && !change->explode) -#else if (IS_MOVING(x, y)) /* never change a running system ;-) */ -#endif { ChangeDelay[x][y] = 1; /* try change after next move step */ ChangePage[x][y] = page; /* remember page to use for change */ @@ -8210,15 +7141,15 @@ static void ChangeElement(int x, int y, int page) } } -static boolean CheckTriggeredElementChangeExt(int lx, int ly, - int trigger_element, +static boolean CheckTriggeredElementChangeExt(int trigger_element, int trigger_event, int trigger_player, int trigger_side, int trigger_page) { - int i, j, x, y; + boolean change_done_any = FALSE; int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page); + int i; if (!(trigger_events[trigger_element][trigger_event])) return FALSE; @@ -8226,60 +7157,58 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; + boolean change_done = FALSE; + int p; - boolean change_element = FALSE; - int page = 0; - - if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) + if (!CAN_CHANGE_OR_HAS_ACTION(element) || + !HAS_ANY_CHANGE_EVENT(element, trigger_event)) continue; - for (j = 0; j < element_info[element].num_change_pages; j++) + for (p = 0; p < element_info[element].num_change_pages; p++) { - struct ElementChangeInfo *change = &element_info[element].change_page[j]; + struct ElementChangeInfo *change = &element_info[element].change_page[p]; - if (change->can_change && + if (change->can_change_or_has_action && change->has_event[trigger_event] && change->trigger_side & trigger_side && change->trigger_player & trigger_player && change->trigger_page & trigger_page_bits && IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)) { -#if 0 - if (!(change->has_event[trigger_event])) - printf("::: !!! %d triggers %d: using wrong page %d [event %d]\n", - trigger_element-EL_CUSTOM_START+1, i+1, j, trigger_event); -#endif - - change_element = TRUE; - page = j; - change->actual_trigger_element = trigger_element; change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); - break; - } - } - - if (!change_element) - continue; + if ((change->can_change && !change_done) || change->has_action) + { + int x, y; - for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) - { -#if 0 - if (x == lx && y == ly) /* do not change trigger element itself */ - continue; -#endif + for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) + { + if (Feld[x][y] == element) + { + if (change->can_change && !change_done) + { + ChangeDelay[x][y] = 1; + ChangeEvent[x][y] = trigger_event; + ChangeElement(x, y, p); + } + + if (change->has_action) + ExecuteCustomElementAction(x, y, element, p); + } + } - if (Feld[x][y] == element) - { - ChangeDelay[x][y] = 1; - ChangeEvent[x][y] = trigger_event; - ChangeElement(x, y, page); + if (change->can_change) + { + change_done = TRUE; + change_done_any = TRUE; + } + } } } } - return TRUE; + return change_done_any; } static boolean CheckElementChangeExt(int x, int y, @@ -8287,10 +7216,13 @@ static boolean CheckElementChangeExt(int x, int y, int trigger_element, int trigger_event, int trigger_player, - int trigger_side, - int trigger_page) + int trigger_side) { - if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) + boolean change_done = FALSE; + int p; + + if (!CAN_CHANGE_OR_HAS_ACTION(element) || + !HAS_ANY_CHANGE_EVENT(element, trigger_event)) return FALSE; if (Feld[x][y] == EL_BLOCKED) @@ -8299,73 +7231,43 @@ static boolean CheckElementChangeExt(int x, int y, element = Feld[x][y]; } -#if 1 if (Feld[x][y] != element) /* check if element has already changed */ - { -#if 0 - printf("::: %d ('%s') != %d ('%s') [%d]\n", - Feld[x][y], element_info[Feld[x][y]].token_name, - element, element_info[element].token_name, - trigger_event); -#endif - return FALSE; - } -#endif -#if 1 - if (trigger_page < 0) + for (p = 0; p < element_info[element].num_change_pages; p++) { - boolean change_element = FALSE; - int i; + struct ElementChangeInfo *change = &element_info[element].change_page[p]; - for (i = 0; i < element_info[element].num_change_pages; i++) + boolean check_trigger_element = + (trigger_event == CE_TOUCHING_X || + trigger_event == CE_HITTING_X || + trigger_event == CE_HIT_BY_X); + + if (change->can_change_or_has_action && + change->has_event[trigger_event] && + change->trigger_side & trigger_side && + change->trigger_player & trigger_player && + (!check_trigger_element || + IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))) { - struct ElementChangeInfo *change = &element_info[element].change_page[i]; + change->actual_trigger_element = trigger_element; + change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); - if (change->can_change && - change->has_event[trigger_event] && - change->trigger_side & trigger_side && - change->trigger_player & trigger_player) + if (change->can_change && !change_done) { - change_element = TRUE; - trigger_page = i; - - change->actual_trigger_element = trigger_element; - change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); + ChangeDelay[x][y] = 1; + ChangeEvent[x][y] = trigger_event; + ChangeElement(x, y, p); - break; + change_done = TRUE; } - } - - if (!change_element) - return FALSE; - } - else - { - struct ElementInfo *ei = &element_info[element]; - struct ElementChangeInfo *change = &ei->change_page[trigger_page]; - change->actual_trigger_element = trigger_element; - change->actual_trigger_player = EL_PLAYER_1; /* unused */ + if (change->has_action) + ExecuteCustomElementAction(x, y, element, p); + } } -#else - - /* !!! this check misses pages with same event, but different side !!! */ - - if (trigger_page < 0) - trigger_page = element_info[element].event_page_nr[trigger_event]; - - if (!(element_info[element].change_page[trigger_page].trigger_side & trigger_side)) - return FALSE; -#endif - - ChangeDelay[x][y] = 1; - ChangeEvent[x][y] = trigger_event; - ChangeElement(x, y, trigger_page); - - return TRUE; + return change_done; } static void PlayPlayerSound(struct PlayerInfo *player) @@ -8530,13 +7432,8 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) } } -#if 1 static byte PlayerActions(struct PlayerInfo *player, byte player_action) { -#if 0 - static byte stored_player_action[MAX_PLAYERS]; - static int num_stored_actions = 0; -#endif boolean moved = FALSE, snapped = FALSE, dropped = FALSE; int left = player_action & JOY_LEFT; int right = player_action & JOY_RIGHT; @@ -8547,34 +7444,11 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) int dx = (left ? -1 : right ? 1 : 0); int dy = (up ? -1 : down ? 1 : 0); -#if 0 - stored_player_action[player->index_nr] = 0; - num_stored_actions++; -#endif - -#if 0 - printf("::: player %d [%d]\n", player->index_nr, FrameCounter); -#endif - if (!player->active || tape.pausing) return 0; -#if 0 - printf("::: [%d %d %d %d] [%d %d]\n", - left, right, up, down, button1, button2); -#endif - if (player_action) { -#if 0 - printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter); -#endif - -#if 0 - /* !!! TEST !!! */ - if (player->MovPos == 0) - CheckGravityMovement(player); -#endif if (button1) snapped = SnapField(player, dx, dy); else @@ -8596,18 +7470,10 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) SetPlayerWaiting(player, FALSE); -#if 1 return player_action; -#else - stored_player_action[player->index_nr] = player_action; -#endif } else { -#if 0 - printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter); -#endif - /* no actions for this player (no input at player's configured device) */ DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); @@ -8624,93 +7490,7 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) return 0; } - -#if 0 - if (tape.recording && num_stored_actions >= MAX_PLAYERS) - { - printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter); - - TapeRecordAction(stored_player_action); - num_stored_actions = 0; - } -#endif -} - -#else - -static void PlayerActions(struct PlayerInfo *player, byte player_action) -{ - static byte stored_player_action[MAX_PLAYERS]; - static int num_stored_actions = 0; - boolean moved = FALSE, snapped = FALSE, dropped = FALSE; - int left = player_action & JOY_LEFT; - int right = player_action & JOY_RIGHT; - int up = player_action & JOY_UP; - int down = player_action & JOY_DOWN; - int button1 = player_action & JOY_BUTTON_1; - int button2 = player_action & JOY_BUTTON_2; - int dx = (left ? -1 : right ? 1 : 0); - int dy = (up ? -1 : down ? 1 : 0); - - stored_player_action[player->index_nr] = 0; - num_stored_actions++; - - printf("::: player %d [%d]\n", player->index_nr, FrameCounter); - - if (!player->active || tape.pausing) - return; - - if (player_action) - { - printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter); - - if (button1) - snapped = SnapField(player, dx, dy); - else - { - if (button2) - dropped = DropElement(player); - - moved = MovePlayer(player, dx, dy); - } - - if (tape.single_step && tape.recording && !tape.pausing) - { - if (button1 || (dropped && !moved)) - { - TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); - SnapField(player, 0, 0); /* stop snapping */ - } - } - - stored_player_action[player->index_nr] = player_action; - } - else - { - printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter); - - /* no actions for this player (no input at player's configured device) */ - - DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); - SnapField(player, 0, 0); - CheckGravityMovementWhenNotMoving(player); - - if (player->MovPos == 0) - InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir); - - if (player->MovPos == 0) /* needed for tape.playing */ - player->is_moving = FALSE; - } - - if (tape.recording && num_stored_actions >= MAX_PLAYERS) - { - printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter); - - TapeRecordAction(stored_player_action); - num_stored_actions = 0; - } } -#endif void AdvanceFrameAndPlayerCounters(int player_nr) { @@ -8724,27 +7504,36 @@ void AdvanceFrameAndPlayerCounters(int player_nr) for (i = 0; i < MAX_PLAYERS; i++) { boolean advance_player_counters = (player_nr == -1 || player_nr == i); - int move_frames = - MOVE_DELAY_NORMAL_SPEED / stored_player[i].move_delay_value; + int move_delay_value = stored_player[i].move_delay_value; + int move_frames = MOVE_DELAY_NORMAL_SPEED / move_delay_value; if (!advance_player_counters) /* not all players may be affected */ continue; +#if USE_NEW_PLAYER_ANIM + if (move_frames == 0) /* less than one move per game frame */ + { + int stepsize = TILEX / move_delay_value; + int delay = move_delay_value / MOVE_DELAY_NORMAL_SPEED; + int count = (stored_player[i].is_moving ? + ABS(stored_player[i].MovPos) / stepsize : FrameCounter); + + if (count % delay == 0) + move_frames = 1; + } +#endif + stored_player[i].Frame += move_frames; if (stored_player[i].MovPos != 0) stored_player[i].StepFrame += move_frames; -#if USE_NEW_MOVE_DELAY if (stored_player[i].move_delay > 0) stored_player[i].move_delay--; -#endif -#if USE_NEW_PUSH_DELAY /* due to bugs in previous versions, counter must count up, not down */ if (stored_player[i].push_delay != -1) stored_player[i].push_delay++; -#endif if (stored_player[i].drop_delay > 0) stored_player[i].drop_delay--; @@ -8759,9 +7548,7 @@ void GameActions() int i, x, y, element, graphic; byte *recorded_player_action; byte summarized_player_action = 0; -#if 1 byte tape_action[MAX_PLAYERS]; -#endif if (game_status != GAME_MODE_PLAYING) return; @@ -8778,38 +7565,24 @@ void GameActions() if (network_playing && !network_player_action_received) { - /* -#ifdef DEBUG - printf("DEBUG: try to get network player actions in time\n"); -#endif - */ + /* try to get network player actions in time */ #if defined(NETWORK_AVALIABLE) /* last chance to get network player actions without main loop delay */ HandleNetworking(); #endif + /* game was quit by network peer */ if (game_status != GAME_MODE_PLAYING) return; if (!network_player_action_received) - { - /* -#ifdef DEBUG - printf("DEBUG: failed to get network player actions in time\n"); -#endif - */ - return; - } + return; /* failed to get network player actions in time */ } if (tape.pausing) return; -#if 0 - printf("::: getting new tape action [%d]\n", FrameCounter); -#endif - recorded_player_action = (tape.playing ? TapePlayAction() : NULL); #if 1 @@ -8818,16 +7591,6 @@ void GameActions() return; #endif -#if 0 - printf("::: %d\n", stored_player[0].action); -#endif - -#if 0 - if (recorded_player_action != NULL) - for (i = 0; i < MAX_PLAYERS; i++) - stored_player[i].action = recorded_player_action[i]; -#endif - for (i = 0; i < MAX_PLAYERS; i++) { summarized_player_action |= stored_player[i].action; @@ -8844,13 +7607,10 @@ void GameActions() if (!options.network && !setup.team_mode) local_player->effective_action = summarized_player_action; -#if 1 if (recorded_player_action != NULL) for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = recorded_player_action[i]; -#endif -#if 1 for (i = 0; i < MAX_PLAYERS; i++) { tape_action[i] = stored_player[i].effective_action; @@ -8862,7 +7622,6 @@ void GameActions() /* only save actions from input devices, but not programmed actions */ if (tape.recording) TapeRecordAction(tape_action); -#endif for (i = 0; i < MAX_PLAYERS; i++) { @@ -8879,42 +7638,9 @@ void GameActions() CheckGravityMovement(&stored_player[i]); #endif -#if 1 /* overwrite programmed action with tape action */ if (stored_player[i].programmed_action) actual_player_action = stored_player[i].programmed_action; -#endif - -#if 0 - if (stored_player[i].programmed_action) - printf("::: %d\n", stored_player[i].programmed_action); -#endif - - if (recorded_player_action) - { -#if 0 - if (stored_player[i].programmed_action && - stored_player[i].programmed_action != recorded_player_action[i]) - printf("::: %d: %d <-> %d\n", i, - stored_player[i].programmed_action, recorded_player_action[i]); -#endif - -#if 0 - actual_player_action = recorded_player_action[i]; -#endif - } - -#if 0 - /* overwrite tape action with programmed action */ - if (stored_player[i].programmed_action) - actual_player_action = stored_player[i].programmed_action; -#endif - -#if 0 - if (i == 0) - printf("::: action: %d: %x [%d]\n", - stored_player[i].MovPos, actual_player_action, FrameCounter); -#endif #if 1 PlayerActions(&stored_player[i], actual_player_action); @@ -8928,24 +7654,10 @@ void GameActions() ScrollPlayer(&stored_player[i], SCROLL_GO_ON); } -#if 0 - if (tape.recording) - TapeRecordAction(tape_action); -#endif - network_player_action_received = FALSE; ScrollScreen(NULL, SCROLL_GO_ON); -#if 0 - FrameCounter++; - TimeFrames++; - - for (i = 0; i < MAX_PLAYERS; i++) - stored_player[i].Frame++; -#endif - -#if 1 /* for backwards compatibility, the following code emulates a fixed bug that occured when pushing elements (causing elements that just made their last pushing step to already (if possible) make their first falling step in the @@ -8954,11 +7666,7 @@ void GameActions() used also in newer levels, but in this case the buggy pushing code is only affecting the "spring" element and no other elements */ -#if 1 if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug) -#else - if (game.engine_version < VERSION_IDENT(2,2,0,7)) -#endif { for (i = 0; i < MAX_PLAYERS; i++) { @@ -8966,15 +7674,10 @@ void GameActions() int x = player->jx; int y = player->jy; -#if 1 if (player->active && player->is_pushing && player->is_moving && IS_MOVING(x, y) && (game.engine_version < VERSION_IDENT(2,2,0,7) || Feld[x][y] == EL_SPRING)) -#else - if (player->active && player->is_pushing && player->is_moving && - IS_MOVING(x, y)) -#endif { ContinueMoving(x, y); @@ -8986,14 +7689,12 @@ void GameActions() } } } -#endif for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) { Changed[x][y] = FALSE; ChangeEvent[x][y] = -1; -#if USE_NEW_BLOCK_STYLE /* this must be handled before main playfield loop */ if (Feld[x][y] == EL_PLAYER_IS_LEAVING) { @@ -9001,7 +7702,6 @@ void GameActions() if (MovDelay[x][y] <= 0) RemoveField(x, y); } -#endif #if DEBUG if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1) @@ -9023,7 +7723,6 @@ void GameActions() GfxFrame[x][y]++; -#if 1 /* reset finished pushing action (not done in ContinueMoving() to allow continous pushing animation for elements with zero push delay) */ if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y)) @@ -9031,7 +7730,6 @@ void GameActions() ResetGfxAnimation(x, y); DrawLevelField(x, y); } -#endif #if DEBUG if (IS_BLOCKED(x, y)) @@ -9053,20 +7751,7 @@ void GameActions() for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) { element = Feld[x][y]; -#if 1 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); -#else - graphic = el2img(element); -#endif - -#if 0 - if (element == -1) - { - printf("::: %d,%d: %d [%d]\n", x, y, element, FrameCounter); - - element = graphic = 0; - } -#endif if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; @@ -9077,9 +7762,7 @@ void GameActions() SetRandomAnimationValue(x, y); -#if 1 PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]); -#endif if (IS_INACTIVE(element)) { @@ -9089,64 +7772,42 @@ void GameActions() continue; } -#if 1 /* this may take place after moving, so 'element' may have changed */ -#if 0 - if (IS_CHANGING(x, y)) -#else if (IS_CHANGING(x, y) && (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y])) -#endif { + int page = element_info[element].event_page_nr[CE_DELAY]; #if 0 - ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : - element_info[element].event_page_nr[CE_DELAY]); + ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page); #else - ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]); + +#if 0 + printf("::: ChangeDelay == %d\n", ChangeDelay[x][y]); +#endif + + if (CAN_CHANGE(element)) + ChangeElement(x, y, page); + + if (HAS_ACTION(element) && ChangeDelay[x][y] == 0) + ExecuteCustomElementAction(x, y, element, page); #endif element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); } -#endif if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) { StartMoving(x, y); -#if 1 element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); -#if 0 - if (element == EL_MOLE) - printf("::: %d, %d, %d [%d]\n", - IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y], - GfxAction[x][y]); -#endif -#if 0 - if (element == EL_YAMYAM) - printf("::: %d, %d, %d\n", - IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y]); -#endif -#endif if (IS_ANIMATED(graphic) && !IS_MOVING(x, y) && !Stop[x][y]) - { DrawLevelGraphicAnimationIfNeeded(x, y, graphic); -#if 0 - if (element == EL_BUG) - printf("::: %d, %d\n", graphic, GfxFrame[x][y]); -#endif - -#if 0 - if (element == EL_MOLE) - printf("::: %d, %d\n", graphic, GfxFrame[x][y]); -#endif - } - if (IS_GEM(element) || element == EL_SP_INFOTRON) EdelsteinFunkeln(x, y); } @@ -9164,10 +7825,6 @@ void GameActions() ContinueMoving(x, y); else if (IS_ACTIVE_BOMB(element)) CheckDynamite(x, y); -#if 0 - else if (element == EL_EXPLOSION && !game.explosions_delayed) - Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL); -#endif else if (element == EL_AMOEBA_GROWING) AmoebeWaechst(x, y); else if (element == EL_AMOEBA_SHRINKING) @@ -9193,21 +7850,11 @@ void GameActions() MauerAbleger(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); -#if 0 - else if (IS_AUTO_CHANGING(element)) - ChangeElement(x, y); -#endif else if (element == EL_EXPLOSION) ; /* drawing of correct explosion animation is handled separately */ else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); -#if 0 - /* this may take place after moving, so 'element' may have changed */ - if (IS_AUTO_CHANGING(Feld[x][y])) - ChangeElement(x, y); -#endif - if (IS_BELT_ACTIVE(element)) PlayLevelSoundAction(x, y, ACTION_ACTIVE); @@ -9232,24 +7879,16 @@ void GameActions() #if USE_NEW_AMOEBA_CODE /* new experimental amoeba growth stuff */ -#if 1 if (!(FrameCounter % 8)) -#endif { static unsigned long random = 1684108901; for (i = 0; i < level.amoeba_speed * 28 / 8; i++) { -#if 0 - x = (random >> 10) % lev_fieldx; - y = (random >> 20) % lev_fieldy; -#else x = RND(lev_fieldx); y = RND(lev_fieldy); -#endif element = Feld[x][y]; -#if 1 if (!IS_PLAYER(x,y) && (element == EL_EMPTY || CAN_GROW_INTO(element) || @@ -9263,22 +7902,6 @@ void GameActions() (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET)) Feld[x][y] = EL_AMOEBA_DROP; } -#else - /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ - if (!IS_PLAYER(x,y) && - (element == EL_EMPTY || - element == EL_SAND || - element == EL_QUICKSAND_EMPTY || - element == EL_ACID_SPLASH_LEFT || - element == EL_ACID_SPLASH_RIGHT)) - { - if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) || - (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) || - (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) || - (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET)) - Feld[x][y] = EL_AMOEBA_DROP; - } -#endif random = random * 129 + 1; } @@ -9410,7 +8033,7 @@ void GameActions() if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) - KillHero(&stored_player[i]); + KillPlayer(&stored_player[i]); } else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); @@ -9442,57 +8065,18 @@ void GameActions() redraw_mask |= REDRAW_FPS; } -#if 0 - if (stored_player[0].jx != stored_player[0].last_jx || - stored_player[0].jy != stored_player[0].last_jy) - printf("::: %d, %d, %d, %d, %d\n", - stored_player[0].MovDir, - stored_player[0].MovPos, - stored_player[0].GfxPos, - stored_player[0].Frame, - stored_player[0].StepFrame); -#endif - -#if USE_NEW_MOVE_DELAY AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ -#else - FrameCounter++; - TimeFrames++; - - for (i = 0; i < MAX_PLAYERS; i++) - { - int move_frames = - MOVE_DELAY_NORMAL_SPEED / stored_player[i].move_delay_value; - - stored_player[i].Frame += move_frames; - - if (stored_player[i].MovPos != 0) - stored_player[i].StepFrame += move_frames; - -#if USE_NEW_MOVE_DELAY - if (stored_player[i].move_delay > 0) - stored_player[i].move_delay--; -#endif - - if (stored_player[i].drop_delay > 0) - stored_player[i].drop_delay--; - } -#endif -#if 1 if (local_player->show_envelope != 0 && local_player->MovPos == 0) { ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); local_player->show_envelope = 0; } -#endif -#if USE_NEW_RANDOMIZE /* use random number generator in every frame to make it less predictable */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) RND(1); -#endif } static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) @@ -9564,51 +8148,12 @@ void ScrollLevel(int dx, int dy) redraw_mask |= REDRAW_FIELD; } -#if 0 -static boolean canEnterSupaplexPort(int x, int y, int dx, int dy) -{ - int nextx = x + dx, nexty = y + dy; - int element = Feld[x][y]; - - if ((dx == -1 && - element != EL_SP_PORT_LEFT && - element != EL_SP_GRAVITY_PORT_LEFT && - element != EL_SP_PORT_HORIZONTAL && - element != EL_SP_PORT_ANY) || - (dx == +1 && - element != EL_SP_PORT_RIGHT && - element != EL_SP_GRAVITY_PORT_RIGHT && - element != EL_SP_PORT_HORIZONTAL && - element != EL_SP_PORT_ANY) || - (dy == -1 && - element != EL_SP_PORT_UP && - element != EL_SP_GRAVITY_PORT_UP && - element != EL_SP_PORT_VERTICAL && - element != EL_SP_PORT_ANY) || - (dy == +1 && - element != EL_SP_PORT_DOWN && - element != EL_SP_GRAVITY_PORT_DOWN && - element != EL_SP_PORT_VERTICAL && - element != EL_SP_PORT_ANY) || - !IN_LEV_FIELD(nextx, nexty) || - !IS_FREE(nextx, nexty)) - return FALSE; - - return TRUE; -} -#endif - static boolean canFallDown(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; return (IN_LEV_FIELD(jx, jy + 1) && (IS_FREE(jx, jy + 1) || -#if USE_NEW_BLOCK_STYLE -#if USE_GRAVITY_BUGFIX_OLD - Feld[jx][jy + 1] == EL_PLAYER_IS_LEAVING || -#endif -#endif (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) && IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) && !IS_WALKABLE_INSIDE(Feld[jx][jy])); @@ -9637,166 +8182,37 @@ static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); int newx = x + dx; int newy = y + dy; -#if 0 - int nextx = newx + dx; - int nexty = newy + dy; -#endif -#if 1 - return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && - IS_GRAVITY_REACHABLE(Feld[newx][newy]) && -#if 0 - (!IS_SP_PORT(Feld[newx][newy]) || move_dir == MV_UP) && -#endif - (IS_DIGGABLE(Feld[newx][newy]) || - IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || - canPassField(newx, newy, move_dir))); -#else -#if 1 return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && IS_GRAVITY_REACHABLE(Feld[newx][newy]) && (IS_DIGGABLE(Feld[newx][newy]) || IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || canPassField(newx, newy, move_dir))); -#else -#if 1 - return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && - (IS_DIGGABLE_WITH_GRAVITY(Feld[newx][newy]) || - IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || - canPassField(newx, newy, move_dir))); -#else - return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && - (IS_DIGGABLE(Feld[newx][newy]) || - IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || - (IS_PASSABLE_FROM(Feld[newx][newy], opposite_dir) && - !CAN_MOVE(Feld[newx][newy]) && - IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) && - IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) && - (level.can_pass_to_walkable || IS_FREE(nextx, nexty))))); -#endif -#endif -#endif } static void CheckGravityMovement(struct PlayerInfo *player) { if (game.gravity && !player->programmed_action) { -#if 1 int move_dir_horizontal = player->effective_action & MV_HORIZONTAL; int move_dir_vertical = player->effective_action & MV_VERTICAL; -#else - int move_dir_horizontal = player->action & MV_HORIZONTAL; - int move_dir_vertical = player->action & MV_VERTICAL; -#endif - -#if 1 boolean player_is_snapping = player->effective_action & JOY_BUTTON_1; -#else - boolean player_is_snapping = player->action & JOY_BUTTON_1; -#endif - int jx = player->jx, jy = player->jy; - boolean player_is_moving_to_valid_field = (!player_is_snapping && (canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) || canMoveToValidFieldWithGravity(jx, jy, move_dir_vertical))); - -#if 0 - int move_dir = - (player->last_move_dir & MV_HORIZONTAL ? - (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) : - (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical)); -#endif - -#if 0 - int opposite_dir = MV_DIR_OPPOSITE(move_dir); - int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0); - int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); - int new_jx = jx + dx, new_jy = jy + dy; - int nextx = new_jx + dx, nexty = new_jy + dy; -#endif - -#if 1 - -#if 1 boolean player_can_fall_down = canFallDown(player); -#else - boolean player_can_fall_down = - (IN_LEV_FIELD(jx, jy + 1) && - (IS_FREE(jx, jy + 1) || - (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid))); -#endif - -#else - boolean player_can_fall_down = - (IN_LEV_FIELD(jx, jy + 1) && - (IS_FREE(jx, jy + 1))); -#endif - -#if 0 - boolean player_is_moving_to_valid_field = - ( -#if 1 - !player_is_snapping && -#endif - -#if 1 - IN_LEV_FIELD(new_jx, new_jy) && - (IS_DIGGABLE(Feld[new_jx][new_jy]) || - (IS_SP_PORT(Feld[new_jx][new_jy]) && - element_info[Feld[new_jx][new_jy]].access_direction & opposite_dir && - IN_LEV_FIELD(nextx, nexty) && - element_info[Feld[nextx][nexty]].access_direction & move_dir)) -#else - IN_LEV_FIELD(new_jx, new_jy) && - (Feld[new_jx][new_jy] == EL_SP_BASE || - Feld[new_jx][new_jy] == EL_SAND || - (IS_SP_PORT(Feld[new_jx][new_jy]) && - canEnterSupaplexPort(new_jx, new_jy, dx, dy))) - /* !!! extend EL_SAND to anything diggable !!! */ -#endif - ); -#endif - -#if 0 - boolean player_is_standing_on_valid_field = - (IS_WALKABLE_INSIDE(Feld[jx][jy]) || - (IS_WALKABLE(Feld[jx][jy]) && !ACCESS_FROM(Feld[jx][jy], MV_DOWN))); -#endif - -#if 0 - printf("::: checking gravity NOW [%d, %d, %d] [%d] [%d / %d] ...\n", - player_can_fall_down, - player_is_standing_on_valid_field, - player_is_moving_to_valid_field, - (player_is_moving_to_valid_field ? Feld[new_jx][new_jy] : -1), - player->effective_action, - player->can_fall_into_acid); -#endif if (player_can_fall_down && -#if 0 - !player_is_standing_on_valid_field && -#endif !player_is_moving_to_valid_field) - { -#if 0 - printf("::: setting programmed_action to MV_DOWN [%d,%d - %d] ...\n", - jx, jy, FrameCounter); -#endif - player->programmed_action = MV_DOWN; - } } } static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player) { -#if 1 return CheckGravityMovement(player); -#endif if (game.gravity && !player->programmed_action) { @@ -9823,22 +8239,6 @@ static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player) boolean MovePlayerOneStep(struct PlayerInfo *player, int dx, int dy, int real_dx, int real_dy) { -#if 0 - static int trigger_sides[4][2] = - { - /* enter side leave side */ - { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */ - { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */ - { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */ - { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */ - }; - int move_direction = (dx == -1 ? MV_LEFT : - dx == +1 ? MV_RIGHT : - dy == -1 ? MV_UP : - dy == +1 ? MV_DOWN : MV_NO_MOVING); - int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0]; - int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1]; -#endif int jx = player->jx, jy = player->jy; int new_jx = jx + dx, new_jy = jy + dy; int element; @@ -9858,11 +8258,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, if (!options.network && !AllPlayersInSight(player, new_jx, new_jy)) return MF_NO_ACTION; -#if 0 - element = MovingOrBlocked2Element(new_jx, new_jy); -#else element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy); -#endif if (DONT_RUN_INTO(element)) { @@ -9873,10 +8269,10 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, InitMovingField(jx, jy, MV_DOWN); Store[jx][jy] = EL_ACID; ContinueMoving(jx, jy); - BuryHero(player); + BuryPlayer(player); } else - TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir); + TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); return MF_MOVING; } @@ -9901,31 +8297,10 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, player->step_counter++; -#if 0 - player->drop_delay = 0; -#endif - PlayerVisit[jx][jy] = FrameCounter; ScrollPlayer(player, SCROLL_INIT); -#if 0 - if (IS_CUSTOM_ELEMENT(Feld[jx][jy])) - { - CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_PLAYER_LEAVES_X, - leave_side); - CheckElementChangeBySide(jx,jy, Feld[jx][jy],CE_LEFT_BY_PLAYER,leave_side); - } - - if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy])) - { - CheckTriggeredElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy], - CE_PLAYER_ENTERS_X, enter_side); - CheckElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy], - CE_ENTERED_BY_PLAYER, enter_side); - } -#endif - return MF_MOVING; } @@ -9935,7 +8310,6 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) int old_jx = jx, old_jy = jy; int moved = MF_NO_ACTION; -#if 1 if (!player->active) return FALSE; @@ -9952,51 +8326,11 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) return FALSE; } -#else - if (!player->active || (!dx && !dy)) - return FALSE; -#endif - -#if 0 - if (!FrameReached(&player->move_delay, player->move_delay_value) && - !tape.playing) - return FALSE; -#else - -#if 1 - -#if 0 - printf("::: %d <= %d < %d ?\n", player->move_delay, FrameCounter, - player->move_delay + player->move_delay_value); -#endif -#if USE_NEW_MOVE_DELAY if (player->move_delay > 0) -#else - if (!FrameReached(&player->move_delay, player->move_delay_value)) -#endif - { -#if 0 - printf("::: can NOT move\n"); -#endif - - return FALSE; - } -#else - if (!FrameReached(&player->move_delay, player->move_delay_value) && - !(tape.playing && tape.file_version < FILE_VERSION_2_0)) return FALSE; -#endif - -#endif -#if 0 - printf("::: COULD move now\n"); -#endif - -#if USE_NEW_MOVE_DELAY player->move_delay = -1; /* set to "uninitialized" value */ -#endif /* store if player is automatically moved to next field */ player->is_auto_moving = (player->programmed_action != MV_NO_MOVING); @@ -10024,11 +8358,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) ScrollPlayer(player, SCROLL_GO_ON); ScrollScreen(NULL, SCROLL_GO_ON); -#if USE_NEW_MOVE_DELAY AdvanceFrameAndPlayerCounters(player->index_nr); -#else - FrameCounter++; -#endif DrawAllPlayers(); BackToFront(); @@ -10120,23 +8450,10 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) } } -#if 0 -#if 1 - InitPlayerGfxAnimation(player, ACTION_DEFAULT); -#else - if (!(moved & MF_MOVING) && !player->is_pushing) - player->Frame = 0; -#endif -#endif - player->StepFrame = 0; if (moved & MF_MOVING) { -#if 0 - printf("::: REALLY moves now\n"); -#endif - if (old_jx != jx && old_jy == jy) player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT); else if (old_jx == jx && old_jy != jy) @@ -10146,101 +8463,36 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->last_move_dir = player->MovDir; player->is_moving = TRUE; -#if 1 player->is_snapping = FALSE; -#endif - -#if 1 player->is_switching = FALSE; -#endif - player->is_dropping = FALSE; - - -#if 0 - /* !!! ENABLE THIS FOR OLD VERSIONS !!! */ - -#if 1 - if (game.engine_version < VERSION_IDENT(3,1,0,0)) -#endif - { - int move_direction = player->MovDir; -#if 1 - int enter_side = MV_DIR_OPPOSITE(move_direction); - int leave_side = move_direction; -#else - static int trigger_sides[4][2] = - { - /* enter side leave side */ - { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */ - { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */ - { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */ - { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */ - }; - int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0]; - int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1]; -#endif - int old_element = Feld[old_jx][old_jy]; - int new_element = Feld[jx][jy]; - -#if 1 - /* !!! TEST ONLY !!! */ - if (IS_CUSTOM_ELEMENT(old_element)) - CheckElementChangeByPlayer(old_jx, old_jy, old_element, - CE_LEFT_BY_PLAYER, - player->index_bit, leave_side); - - CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, - CE_PLAYER_LEAVES_X, - player->index_bit, leave_side); - - if (IS_CUSTOM_ELEMENT(new_element)) - CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER, - player->index_bit, enter_side); - - CheckTriggeredElementChangeByPlayer(jx, jy, new_element, - CE_PLAYER_ENTERS_X, - player->index_bit, enter_side); -#endif - - } -#endif - - } else { CheckGravityMovementWhenNotMoving(player); - /* - player->last_move_dir = MV_NO_MOVING; - */ player->is_moving = FALSE; -#if USE_NEW_MOVE_STYLE - /* player is ALLOWED to move, but CANNOT move (something blocks his way) */ - /* ensure that the player is also allowed to move in the next frame */ - /* (currently, the player is forced to wait eight frames before he can try - again!!!) */ + /* at this point, the player is allowed to move, but cannot move right now + (e.g. because of something blocking the way) -- ensure that the player + is also allowed to move in the next frame (in old versions before 3.1.1, + the player was forced to wait again for eight frames before next try) */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) player->move_delay = 0; /* allow direct movement in the next frame */ -#endif } -#if USE_NEW_MOVE_DELAY if (player->move_delay == -1) /* not yet initialized by DigField() */ player->move_delay = player->move_delay_value; -#endif if (game.engine_version < VERSION_IDENT(3,0,7,0)) { - TestIfHeroTouchesBadThing(jx, jy); + TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); } if (!player->active) - RemoveHero(player); + RemovePlayer(player); return moved; } @@ -10251,28 +8503,22 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) int last_jx = player->last_jx, last_jy = player->last_jy; int move_stepsize = TILEX / player->move_delay_value; - if (!player->active || !player->MovPos) +#if USE_NEW_PLAYER_SPEED + if (!player->active) + return; + + if (player->MovPos == 0 && mode == SCROLL_GO_ON) /* player not moving */ + return; +#else + if (!player->active || player->MovPos == 0) return; +#endif if (mode == SCROLL_INIT) { player->actual_frame_counter = FrameCounter; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); -#if 0 - printf("::: %06d: %d,%d: %d (%d) [%d]\n", - FrameCounter, - last_jx, last_jy, Feld[last_jx][last_jy], EL_EXPLOSION, - player->block_delay); -#endif - -#if USE_NEW_BLOCK_STYLE - -#if 0 - if (player->block_delay <= 0) - printf("::: ALERT! block_delay == %d\n", player->block_delay); -#endif - if ((player->block_last_field || player->block_delay_adjustment > 0) && Feld[last_jx][last_jy] == EL_EMPTY) { @@ -10284,84 +8530,59 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) { last_field_block_delay += player->move_delay_value; -#if USE_GRAVITY_BUGFIX_NEW /* when blocking enabled, prevent moving up despite gravity */ if (game.gravity && player->MovDir == MV_UP) block_delay_adjustment = -1; -#endif } /* add block delay adjustment (also possible when not blocking) */ last_field_block_delay += block_delay_adjustment; -#if 0 -#if USE_BLOCK_DELAY_BUGFIX - /* when blocking enabled, correct block delay for fast movement */ - if (player->block_last_field && - player->move_delay_value < MOVE_DELAY_NORMAL_SPEED) - last_field_block_delay = - player->move_delay_value + player->block_delay_adjustment; -#endif -#endif - -#if 0 -#if USE_GRAVITY_BUGFIX_NEW - /* when blocking enabled, correct block delay for gravity movement */ - if (player->block_last_field && - game.gravity && player->MovDir == MV_UP) - last_field_block_delay = player->move_delay_value - 1; -#endif -#endif - Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; MovDelay[last_jx][last_jy] = last_field_block_delay + 1; } + +#if USE_NEW_PLAYER_SPEED + if (player->MovPos != 0) /* player has not yet reached destination */ + return; #else -#if USE_NEW_MOVE_STYLE - if ((game.engine_version < VERSION_IDENT(3,1,1,0) || - player->block_last_field) && - Feld[last_jx][last_jy] == EL_EMPTY) - Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; -#else - if (Feld[last_jx][last_jy] == EL_EMPTY) - Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; -#endif + return; #endif + } + else if (!FrameReached(&player->actual_frame_counter, 1)) + return; #if 0 - DrawPlayer(player); + printf("::: player->MovPos: %d -> %d\n", + player->MovPos, + player->MovPos + (player->MovPos > 0 ? -1 : 1) * move_stepsize); #endif - return; - } - else if (!FrameReached(&player->actual_frame_counter, 1)) - return; +#if USE_NEW_PLAYER_SPEED + if (player->MovPos != 0) + { + player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; + player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); + /* before DrawPlayer() to draw correct player graphic for this case */ + if (player->MovPos == 0) + CheckGravityMovement(player); + } +#else player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); -#if USE_NEW_BLOCK_STYLE -#else - if (!player->block_last_field && - Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING) -#if 1 - RemoveField(last_jx, last_jy); -#else - Feld[last_jx][last_jy] = EL_EMPTY; -#endif -#endif - /* before DrawPlayer() to draw correct player graphic for this case */ if (player->MovPos == 0) CheckGravityMovement(player); - -#if 0 - DrawPlayer(player); /* needed here only to cleanup last field */ #endif if (player->MovPos == 0) /* player reached destination field */ { -#if 1 +#if 0 + printf("::: player reached destination field\n"); +#endif + if (player->move_delay_reset_counter > 0) { player->move_delay_reset_counter--; @@ -10375,27 +8596,6 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) player->move_delay = 0; } } -#else - if (IS_PASSABLE(Feld[last_jx][last_jy])) - { - /* continue with normal speed after quickly moving through gate */ - HALVE_PLAYER_SPEED(player); - - /* be able to make the next move without delay */ - player->move_delay = 0; - } -#endif - -#if USE_NEW_BLOCK_STYLE -#else - if (player->block_last_field && - Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING) -#if 1 - RemoveField(last_jx, last_jy); -#else - Feld[last_jx][last_jy] = EL_EMPTY; -#endif -#endif player->last_jx = jx; player->last_jy = jy; @@ -10405,79 +8605,51 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */ { DrawPlayer(player); /* needed here only to cleanup last field */ - RemoveHero(player); + RemovePlayer(player); if (local_player->friends_still_needed == 0 || IS_SP_ELEMENT(Feld[jx][jy])) player->LevelSolved = player->GameOver = TRUE; } -#if 1 - /* !!! ENABLE THIS FOR NEW VERSIONS !!! */ /* this breaks one level: "machine", level 000 */ -#if 0 - if (game.engine_version >= VERSION_IDENT(3,1,0,0)) -#endif { int move_direction = player->MovDir; -#if 1 int enter_side = MV_DIR_OPPOSITE(move_direction); int leave_side = move_direction; -#else - static int trigger_sides[4][2] = - { - /* enter side leave side */ - { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */ - { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */ - { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */ - { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */ - }; - int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0]; - int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1]; -#endif int old_jx = last_jx; int old_jy = last_jy; int old_element = Feld[old_jx][old_jy]; int new_element = Feld[jx][jy]; -#if 1 - /* !!! TEST ONLY !!! */ if (IS_CUSTOM_ELEMENT(old_element)) CheckElementChangeByPlayer(old_jx, old_jy, old_element, CE_LEFT_BY_PLAYER, player->index_bit, leave_side); - CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, - CE_PLAYER_LEAVES_X, + CheckTriggeredElementChangeByPlayer(old_element, CE_PLAYER_LEAVES_X, player->index_bit, leave_side); if (IS_CUSTOM_ELEMENT(new_element)) CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER, player->index_bit, enter_side); - CheckTriggeredElementChangeByPlayer(jx, jy, new_element, - CE_PLAYER_ENTERS_X, + CheckTriggeredElementChangeByPlayer(new_element, CE_PLAYER_ENTERS_X, player->index_bit, enter_side); -#endif - } -#endif if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { - TestIfHeroTouchesBadThing(jx, jy); + TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); -#if 1 -#if 1 + /* needed because pushed element has not yet reached its destination, so it would trigger a change event at its previous field location */ if (!player->is_pushing) -#endif TestIfElementTouchesCustomElement(jx, jy); /* for empty space */ -#endif if (!player->active) - RemoveHero(player); + RemovePlayer(player); } if (level.use_step_counter) @@ -10497,7 +8669,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) - KillHero(&stored_player[i]); + KillPlayer(&stored_player[i]); } else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); @@ -10588,20 +8760,10 @@ void TestIfPlayerTouchesCustomElement(int x, int y) else continue; /* center and border element do not touch */ -#if 1 - /* !!! TEST ONLY !!! */ CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER, player->index_bit, border_side); - CheckTriggeredElementChangeByPlayer(xx, yy, border_element, - CE_PLAYER_TOUCHES_X, - player->index_bit, border_side); -#else - CheckTriggeredElementChangeByPlayer(xx, yy, border_element, - CE_PLAYER_TOUCHES_X, + CheckTriggeredElementChangeByPlayer(border_element, CE_PLAYER_TOUCHES_X, player->index_bit, border_side); - CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER, - player->index_bit, border_side); -#endif } else if (IS_PLAYER(xx, yy)) { @@ -10613,21 +8775,10 @@ void TestIfPlayerTouchesCustomElement(int x, int y) continue; /* center and border element do not touch */ } -#if 1 - /* !!! TEST ONLY !!! */ CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER, player->index_bit, center_side); - CheckTriggeredElementChangeByPlayer(x, y, center_element, - CE_PLAYER_TOUCHES_X, + CheckTriggeredElementChangeByPlayer(center_element, CE_PLAYER_TOUCHES_X, player->index_bit, center_side); -#else - CheckTriggeredElementChangeByPlayer(x, y, center_element, - CE_PLAYER_TOUCHES_X, - player->index_bit, center_side); - CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER, - player->index_bit, center_side); -#endif - break; } } @@ -10658,10 +8809,8 @@ void TestIfElementTouchesCustomElement(int x, int y) MV_LEFT | MV_RIGHT }; boolean change_center_element = FALSE; - int center_element_change_page = 0; int center_element = Feld[x][y]; /* should always be non-moving! */ - int border_trigger_element = EL_UNDEFINED; - int i, j; + int i; for (i = 0; i < NUM_DIRECTIONS; i++) { @@ -10684,73 +8833,14 @@ void TestIfElementTouchesCustomElement(int x, int y) continue; /* center and border element do not touch */ /* check for change of center element (but change it only once) */ - if (IS_CUSTOM_ELEMENT(center_element) && - HAS_ANY_CHANGE_EVENT(center_element, CE_TOUCHING_X) && - !change_center_element) - { - for (j = 0; j < element_info[center_element].num_change_pages; j++) - { - struct ElementChangeInfo *change = - &element_info[center_element].change_page[j]; - - if (change->can_change && - change->has_event[CE_TOUCHING_X] && - change->trigger_side & border_side && -#if 1 - IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element) -#else - change->trigger_element == border_element -#endif - ) - { - change_center_element = TRUE; - center_element_change_page = j; - border_trigger_element = border_element; - - break; - } - } - } + if (!change_center_element) + change_center_element = + CheckElementChangeBySide(x, y, center_element, border_element, + CE_TOUCHING_X, border_side); /* check for change of border element */ - if (IS_CUSTOM_ELEMENT(border_element) && - HAS_ANY_CHANGE_EVENT(border_element, CE_TOUCHING_X)) - { - for (j = 0; j < element_info[border_element].num_change_pages; j++) - { - struct ElementChangeInfo *change = - &element_info[border_element].change_page[j]; - - if (change->can_change && - change->has_event[CE_TOUCHING_X] && - change->trigger_side & center_side && -#if 1 - IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element) -#else - change->trigger_element == center_element -#endif - ) - { -#if 0 - printf("::: border_element %d, %d\n", x, y); -#endif - - CheckElementChangeByPage(xx, yy, border_element, center_element, - CE_TOUCHING_X, j); - break; - } - } - } - } - - if (change_center_element) - { -#if 0 - printf("::: center_element %d, %d\n", x, y); -#endif - - CheckElementChangeByPage(x, y, center_element, border_trigger_element, - CE_TOUCHING_X, center_element_change_page); + CheckElementChangeBySide(xx, yy, border_element, center_element, + CE_TOUCHING_X, center_side); } } @@ -10761,119 +8851,40 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) int hitx = x + dx, hity = y + dy; int hitting_element = Feld[x][y]; int touched_element; -#if 0 - boolean object_hit = (IN_LEV_FIELD(hitx, hity) && - !IS_FREE(hitx, hity) && - (!IS_MOVING(hitx, hity) || - MovDir[hitx][hity] != direction || - ABS(MovPos[hitx][hity]) <= TILEY / 2)); -#endif if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity)) return; -#if 0 - if (IN_LEV_FIELD(hitx, hity) && !object_hit) - return; -#endif - touched_element = (IN_LEV_FIELD(hitx, hity) ? MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL); -#if !USE_HITTING_SOMETHING_BUGFIX - /* "hitting something" is also true when hitting the playfield border */ - CheckElementChangeBySide(x, y, hitting_element, touched_element, - CE_HITTING_SOMETHING, direction); -#endif - if (IN_LEV_FIELD(hitx, hity)) { int opposite_direction = MV_DIR_OPPOSITE(direction); int hitting_side = direction; int touched_side = opposite_direction; -#if 0 - int touched_element = MovingOrBlocked2Element(hitx, hity); -#endif -#if 1 boolean object_hit = (!IS_MOVING(hitx, hity) || MovDir[hitx][hity] != direction || ABS(MovPos[hitx][hity]) <= TILEY / 2); object_hit = TRUE; -#endif if (object_hit) { - int i; - -#if !USE_HIT_BY_SOMETHING_BUGFIX - CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, - CE_HIT_BY_SOMETHING, opposite_direction); -#endif + CheckElementChangeBySide(x, y, hitting_element, touched_element, + CE_HITTING_X, touched_side); - if (IS_CUSTOM_ELEMENT(hitting_element) && - HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X)) - { - for (i = 0; i < element_info[hitting_element].num_change_pages; i++) - { - struct ElementChangeInfo *change = - &element_info[hitting_element].change_page[i]; - - if (change->can_change && - change->has_event[CE_HITTING_X] && - change->trigger_side & touched_side && - -#if 1 - IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element) -#else - change->trigger_element == touched_element -#endif - ) - { - CheckElementChangeByPage(x, y, hitting_element, touched_element, - CE_HITTING_X, i); - break; - } - } - } - - if (IS_CUSTOM_ELEMENT(touched_element) && - HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X)) - { - for (i = 0; i < element_info[touched_element].num_change_pages; i++) - { - struct ElementChangeInfo *change = - &element_info[touched_element].change_page[i]; - - if (change->can_change && - change->has_event[CE_HIT_BY_X] && - change->trigger_side & hitting_side && -#if 1 - IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element) -#else - change->trigger_element == hitting_element -#endif - ) - { - CheckElementChangeByPage(hitx, hity, touched_element, - hitting_element, CE_HIT_BY_X, i); - break; - } - } - } + CheckElementChangeBySide(hitx, hity, touched_element, + hitting_element, CE_HIT_BY_X, hitting_side); -#if USE_HIT_BY_SOMETHING_BUGFIX CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_HIT_BY_SOMETHING, opposite_direction); -#endif } } -#if USE_HITTING_SOMETHING_BUGFIX /* "hitting something" is also true when hitting the playfield border */ CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_HITTING_SOMETHING, direction); -#endif } #if 0 @@ -10929,56 +8940,11 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction) CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_SMASHED_BY_SOMETHING, opposite_direction); - if (IS_CUSTOM_ELEMENT(hitting_element) && - HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_SMASHING)) - { - for (i = 0; i < element_info[hitting_element].num_change_pages; i++) - { - struct ElementChangeInfo *change = - &element_info[hitting_element].change_page[i]; - - if (change->can_change && - change->has_event[CE_OTHER_IS_SMASHING] && - change->trigger_side & touched_side && - -#if 1 - IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element) -#else - change->trigger_element == touched_element -#endif - ) - { - CheckElementChangeByPage(x, y, hitting_element, touched_element, - CE_OTHER_IS_SMASHING, i); - break; - } - } - } - - if (IS_CUSTOM_ELEMENT(touched_element) && - HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_SMASHED)) - { - for (i = 0; i < element_info[touched_element].num_change_pages; i++) - { - struct ElementChangeInfo *change = - &element_info[touched_element].change_page[i]; + CheckElementChangeBySide(x, y, hitting_element, touched_element, + CE_OTHER_IS_SMASHING, touched_side); - if (change->can_change && - change->has_event[CE_OTHER_GETS_SMASHED] && - change->trigger_side & hitting_side && -#if 1 - IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element) -#else - change->trigger_element == hitting_element -#endif - ) - { - CheckElementChangeByPage(hitx, hity, touched_element, - hitting_element, CE_OTHER_GETS_SMASHED,i); - break; - } - } - } + CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, + CE_OTHER_GETS_SMASHED, hitting_side); } } } @@ -11016,11 +8982,7 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) test_move_dir = (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING); -#if 0 - test_element = Feld[test_x][test_y]; -#else test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y); -#endif /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing; 2nd case: DONT_TOUCH style bad thing does not move away from good thing @@ -11042,18 +9004,11 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) { struct PlayerInfo *player = PLAYERINFO(good_x, good_y); -#if 1 if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(kill_x, kill_y); else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y)) - KillHero(player); -#else - if (player->shield_deadly_time_left > 0) - Bang(kill_x, kill_y); - else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y)) - KillHero(player); -#endif + KillPlayer(player); } else Bang(good_x, good_y); @@ -11142,40 +9097,33 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) { struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y); -#if 1 if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(bad_x, bad_y); else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y)) - KillHero(player); -#else - if (player->shield_deadly_time_left > 0) - Bang(bad_x, bad_y); - else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y)) - KillHero(player); -#endif + KillPlayer(player); } else Bang(kill_x, kill_y); } } -void TestIfHeroTouchesBadThing(int x, int y) +void TestIfPlayerTouchesBadThing(int x, int y) { TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING); } -void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir) +void TestIfPlayerRunsIntoBadThing(int x, int y, int move_dir) { TestIfGoodThingHitsBadThing(x, y, move_dir); } -void TestIfBadThingTouchesHero(int x, int y) +void TestIfBadThingTouchesPlayer(int x, int y) { TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING); } -void TestIfBadThingRunsIntoHero(int x, int y, int move_dir) +void TestIfBadThingRunsIntoPlayer(int x, int y, int move_dir) { TestIfBadThingHitsGoodThing(x, y, move_dir); } @@ -11224,7 +9172,7 @@ void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y) Bang(bad_x, bad_y); } -void KillHero(struct PlayerInfo *player) +void KillPlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; @@ -11239,40 +9187,36 @@ void KillHero(struct PlayerInfo *player) player->shield_deadly_time_left = 0; Bang(jx, jy); - BuryHero(player); + BuryPlayer(player); } -static void KillHeroUnlessEnemyProtected(int x, int y) +static void KillPlayerUnlessEnemyProtected(int x, int y) { if (!PLAYER_ENEMY_PROTECTED(x, y)) - KillHero(PLAYERINFO(x, y)); + KillPlayer(PLAYERINFO(x, y)); } -static void KillHeroUnlessExplosionProtected(int x, int y) +static void KillPlayerUnlessExplosionProtected(int x, int y) { if (!PLAYER_EXPLOSION_PROTECTED(x, y)) - KillHero(PLAYERINFO(x, y)); + KillPlayer(PLAYERINFO(x, y)); } -void BuryHero(struct PlayerInfo *player) +void BuryPlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; if (!player->active) return; -#if 1 PlayLevelSoundElementAction(jx, jy, player->element_nr, ACTION_DYING); -#else - PlayLevelSound(jx, jy, SND_CLASS_PLAYER_DYING); -#endif PlayLevelSound(jx, jy, SND_GAME_LOSING); player->GameOver = TRUE; - RemoveHero(player); + RemovePlayer(player); } -void RemoveHero(struct PlayerInfo *player) +void RemovePlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; int i, found = FALSE; @@ -11283,6 +9227,9 @@ void RemoveHero(struct PlayerInfo *player) if (!ExplodeField[jx][jy]) StorePlayer[jx][jy] = 0; + if (player->is_moving) + DrawLevelField(player->last_jx, player->last_jy); + for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) found = TRUE; @@ -11335,9 +9282,6 @@ int DigField(struct PlayerInfo *player, int oldx, int oldy, int x, int y, int real_dx, int real_dy, int mode) { -#if 0 - boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0)); -#endif boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG); boolean player_was_pushing = player->is_pushing; int jx = oldx, jy = oldy; @@ -11348,20 +9292,10 @@ int DigField(struct PlayerInfo *player, dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NO_MOVING); int opposite_direction = MV_DIR_OPPOSITE(move_direction); -#if 1 int dig_side = MV_DIR_OPPOSITE(move_direction); -#else - static int trigger_sides[4] = - { - CH_SIDE_RIGHT, /* moving left */ - CH_SIDE_LEFT, /* moving right */ - CH_SIDE_BOTTOM, /* moving up */ - CH_SIDE_TOP, /* moving down */ - }; - int dig_side = trigger_sides[MV_DIR_BIT(move_direction)]; -#endif int old_element = Feld[jx][jy]; int element; + int collect_count; if (is_player) /* function can also be called by EL_PENGUIN */ { @@ -11377,11 +9311,7 @@ int DigField(struct PlayerInfo *player, if (mode == DF_NO_PUSH) /* player just stopped pushing */ { player->is_switching = FALSE; -#if USE_NEW_PUSH_DELAY player->push_delay = -1; -#else - player->push_delay = 0; -#endif return MF_NO_ACTION; } @@ -11390,50 +9320,13 @@ int DigField(struct PlayerInfo *player, if (IS_MOVING(x, y) || IS_PLAYER(x, y)) return MF_NO_ACTION; -#if 0 - -#if 0 - if (IS_TUBE(Feld[jx][jy]) || IS_TUBE(Back[jx][jy])) -#else - if (IS_TUBE(Feld[jx][jy]) || - (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))) -#endif - { - int i = 0; - int tube_element = (IS_TUBE(Feld[jx][jy]) ? Feld[jx][jy] : Back[jx][jy]); - int tube_leave_directions[][2] = - { - { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, - { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, - { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, - { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN }, - { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN }, - { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP }, - { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN }, - { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP }, - { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN }, - { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP }, - { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN }, - { -1, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN } - }; - - while (tube_leave_directions[i][0] != tube_element) - { - i++; - if (tube_leave_directions[i][0] == -1) /* should not happen */ - break; - } - - if (!(tube_leave_directions[i][1] & move_direction)) - return MF_NO_ACTION; /* tube has no opening in this direction */ - } - -#else - if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; -#endif + /* in case of element dropped at player position, check background */ + else if (Back[jx][jy] != EL_EMPTY && + game.engine_version >= VERSION_IDENT(2,2,0,0)) + old_element = Back[jx][jy]; if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction)) return MF_NO_ACTION; /* field has no opening in this direction */ @@ -11442,6 +9335,20 @@ int DigField(struct PlayerInfo *player, return MF_NO_ACTION; /* field has no opening in this direction */ element = Feld[x][y]; +#if USE_NEW_COLLECT_COUNT + collect_count = Count[x][y]; +#else + collect_count = element_info[element].collect_count_initial; +#endif + +#if 0 + if (element != EL_BLOCKED && + Count[x][y] != element_info[element].collect_count_initial) + printf("::: %d: %d != %d\n", + element, + Count[x][y], + element_info[element].collect_count_initial); +#endif if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */ return MF_NO_ACTION; @@ -11450,800 +9357,451 @@ int DigField(struct PlayerInfo *player, game.engine_version >= VERSION_IDENT(2,2,0,0)) return MF_NO_ACTION; -#if 1 if (game.gravity && is_player && !player->is_auto_moving && canFallDown(player) && move_direction != MV_DOWN && !canMoveToValidFieldWithGravity(jx, jy, move_direction)) return MF_NO_ACTION; /* player cannot walk here due to gravity */ -#endif -#if 0 - if (element == EL_EMPTY_SPACE && - game.gravity && !player->is_auto_moving && - canFallDown(player) && move_direction != MV_DOWN) - return MF_NO_ACTION; /* player cannot walk here due to gravity */ -#endif - - switch (element) + if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) { -#if 0 - case EL_SP_PORT_LEFT: - case EL_SP_PORT_RIGHT: - case EL_SP_PORT_UP: - case EL_SP_PORT_DOWN: - case EL_SP_PORT_HORIZONTAL: - case EL_SP_PORT_VERTICAL: - case EL_SP_PORT_ANY: - case EL_SP_GRAVITY_PORT_LEFT: - case EL_SP_GRAVITY_PORT_RIGHT: - case EL_SP_GRAVITY_PORT_UP: - case EL_SP_GRAVITY_PORT_DOWN: -#if 1 - if (!canEnterSupaplexPort(x, y, dx, dy)) + int sound_element = SND_ELEMENT(element); + int sound_action = ACTION_WALKING; + + if (IS_RND_GATE(element)) + { + if (!player->key[RND_GATE_NR(element)]) return MF_NO_ACTION; -#else - if ((dx == -1 && - element != EL_SP_PORT_LEFT && - element != EL_SP_GRAVITY_PORT_LEFT && - element != EL_SP_PORT_HORIZONTAL && - element != EL_SP_PORT_ANY) || - (dx == +1 && - element != EL_SP_PORT_RIGHT && - element != EL_SP_GRAVITY_PORT_RIGHT && - element != EL_SP_PORT_HORIZONTAL && - element != EL_SP_PORT_ANY) || - (dy == -1 && - element != EL_SP_PORT_UP && - element != EL_SP_GRAVITY_PORT_UP && - element != EL_SP_PORT_VERTICAL && - element != EL_SP_PORT_ANY) || - (dy == +1 && - element != EL_SP_PORT_DOWN && - element != EL_SP_GRAVITY_PORT_DOWN && - element != EL_SP_PORT_VERTICAL && - element != EL_SP_PORT_ANY) || - !IN_LEV_FIELD(nextx, nexty) || - !IS_FREE(nextx, nexty)) + } + else if (IS_RND_GATE_GRAY(element)) + { + if (!player->key[RND_GATE_GRAY_NR(element)]) return MF_NO_ACTION; -#endif + } + else if (element == EL_EXIT_OPEN || + element == EL_SP_EXIT_OPEN || + element == EL_SP_EXIT_OPENING) + { + sound_action = ACTION_PASSING; /* player is passing exit */ + } + else if (element == EL_EMPTY) + { + sound_action = ACTION_MOVING; /* nothing to walk on */ + } + + /* play sound from background or player, whatever is available */ + if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED) + PlayLevelSoundElementAction(x, y, sound_element, sound_action); + else + PlayLevelSoundElementAction(x, y, player->element_nr, sound_action); + } + else if (IS_PASSABLE(element) && canPassField(x, y, move_direction)) + { + if (!ACCESS_FROM(element, opposite_direction)) + return MF_NO_ACTION; /* field not accessible from this direction */ + + if (CAN_MOVE(element)) /* only fixed elements can be passed! */ + return MF_NO_ACTION; + if (IS_EM_GATE(element)) + { + if (!player->key[EM_GATE_NR(element)]) + return MF_NO_ACTION; + } + else if (IS_EM_GATE_GRAY(element)) + { + if (!player->key[EM_GATE_GRAY_NR(element)]) + return MF_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) game.gravity = !game.gravity; + 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) + game.gravity = TRUE; + 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) + game.gravity = FALSE; + } - /* automatically move to the next field with double speed */ - player->programmed_action = move_direction; -#if 1 - if (player->move_delay_reset_counter == 0) - { - player->move_delay_reset_counter = 2; /* two double speed steps */ + /* automatically move to the next field with double speed */ + player->programmed_action = move_direction; - DOUBLE_PLAYER_SPEED(player); - } -#else - player->move_delay_reset_counter = 2; + if (player->move_delay_reset_counter == 0) + { + player->move_delay_reset_counter = 2; /* two double speed steps */ DOUBLE_PLAYER_SPEED(player); -#endif - -#if 0 - printf("::: passing port %d,%d [%d]\n", x, y, FrameCounter); -#endif - - PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING); - break; -#endif - -#if 0 - case EL_TUBE_ANY: - case EL_TUBE_VERTICAL: - case EL_TUBE_HORIZONTAL: - case EL_TUBE_VERTICAL_LEFT: - case EL_TUBE_VERTICAL_RIGHT: - case EL_TUBE_HORIZONTAL_UP: - case EL_TUBE_HORIZONTAL_DOWN: - case EL_TUBE_LEFT_UP: - case EL_TUBE_LEFT_DOWN: - case EL_TUBE_RIGHT_UP: - case EL_TUBE_RIGHT_DOWN: - { - int i = 0; - int tube_enter_directions[][2] = - { - { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, - { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, - { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, - { EL_TUBE_VERTICAL_LEFT, MV_RIGHT | MV_UP | MV_DOWN }, - { EL_TUBE_VERTICAL_RIGHT, MV_LEFT | MV_UP | MV_DOWN }, - { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_DOWN }, - { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_UP }, - { EL_TUBE_LEFT_UP, MV_RIGHT | MV_DOWN }, - { EL_TUBE_LEFT_DOWN, MV_RIGHT | MV_UP }, - { EL_TUBE_RIGHT_UP, MV_LEFT | MV_DOWN }, - { EL_TUBE_RIGHT_DOWN, MV_LEFT | MV_UP }, - { -1, MV_NO_MOVING } - }; - - while (tube_enter_directions[i][0] != element) - { - i++; - if (tube_enter_directions[i][0] == -1) /* should not happen */ - break; - } - - if (!(tube_enter_directions[i][1] & move_direction)) - return MF_NO_ACTION; /* tube has no opening in this direction */ - - PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING); - } - break; -#endif - - default: - -#if 1 - if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) -#else - if (IS_WALKABLE(element)) -#endif - { - int sound_element = SND_ELEMENT(element); - int sound_action = ACTION_WALKING; - -#if 0 - if (!ACCESS_FROM(element, opposite_direction)) - return MF_NO_ACTION; /* field not accessible from this direction */ -#endif - -#if 0 - if (element == EL_EMPTY_SPACE && - game.gravity && !player->is_auto_moving && - canFallDown(player) && move_direction != MV_DOWN) - return MF_NO_ACTION; /* player cannot walk here due to gravity */ -#endif - - if (IS_RND_GATE(element)) - { - if (!player->key[RND_GATE_NR(element)]) - return MF_NO_ACTION; - } - else if (IS_RND_GATE_GRAY(element)) - { - if (!player->key[RND_GATE_GRAY_NR(element)]) - return MF_NO_ACTION; - } - else if (element == EL_EXIT_OPEN || - element == EL_SP_EXIT_OPEN || - element == EL_SP_EXIT_OPENING) - { - sound_action = ACTION_PASSING; /* player is passing exit */ - } - else if (element == EL_EMPTY) - { - sound_action = ACTION_MOVING; /* nothing to walk on */ - } - - /* play sound from background or player, whatever is available */ - if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED) - PlayLevelSoundElementAction(x, y, sound_element, sound_action); - else - PlayLevelSoundElementAction(x, y, player->element_nr, sound_action); - - break; - } -#if 1 - else if (IS_PASSABLE(element) && canPassField(x, y, move_direction)) -#else - else if (IS_PASSABLE(element)) -#endif - { -#if 0 - if (!canPassField(x, y, move_direction)) - return MF_NO_ACTION; -#else - -#if 0 -#if 1 - if (!IN_LEV_FIELD(nextx, nexty) || IS_PLAYER(nextx, nexty) || - !IS_WALKABLE_FROM(Feld[nextx][nexty], move_direction) || - (!level.can_pass_to_walkable && !IS_FREE(nextx, nexty))) - return MF_NO_ACTION; -#else - if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) - return MF_NO_ACTION; -#endif -#endif - -#if 1 - if (!ACCESS_FROM(element, opposite_direction)) - return MF_NO_ACTION; /* field not accessible from this direction */ -#else - if (IS_CUSTOM_ELEMENT(element) && - !ACCESS_FROM(element, opposite_direction)) - return MF_NO_ACTION; /* field not accessible from this direction */ -#endif - -#if 1 - if (CAN_MOVE(element)) /* only fixed elements can be passed! */ - return MF_NO_ACTION; -#endif - -#endif - - if (IS_EM_GATE(element)) - { - if (!player->key[EM_GATE_NR(element)]) - return MF_NO_ACTION; - } - else if (IS_EM_GATE_GRAY(element)) - { - if (!player->key[EM_GATE_GRAY_NR(element)]) - return MF_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) - game.gravity = !game.gravity; - 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) - game.gravity = TRUE; - 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) - game.gravity = FALSE; - } - - /* automatically move to the next field with double speed */ - player->programmed_action = move_direction; -#if 1 - if (player->move_delay_reset_counter == 0) - { - player->move_delay_reset_counter = 2; /* two double speed steps */ + } - DOUBLE_PLAYER_SPEED(player); - } -#else - player->move_delay_reset_counter = 2; + PlayLevelSoundAction(x, y, ACTION_PASSING); + } + else if (IS_DIGGABLE(element)) + { + RemoveField(x, y); - DOUBLE_PLAYER_SPEED(player); -#endif + if (mode != DF_SNAP) + { + GfxElement[x][y] = GFX_ELEMENT(element); + player->is_digging = TRUE; + } - PlayLevelSoundAction(x, y, ACTION_PASSING); + PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); - break; - } - else if (IS_DIGGABLE(element)) - { - RemoveField(x, y); + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_DIGS_X, + player->index_bit, dig_side); - if (mode != DF_SNAP) - { -#if 1 - GfxElement[x][y] = GFX_ELEMENT(element); -#else - GfxElement[x][y] = - (GFX_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element)); -#endif - player->is_digging = TRUE; - } + if (mode == DF_SNAP) + TestIfElementTouchesCustomElement(x, y); /* for empty space */ + } + else if (IS_COLLECTIBLE(element)) + { + RemoveField(x, y); - PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); + if (is_player && mode != DF_SNAP) + { + GfxElement[x][y] = element; + player->is_collecting = TRUE; + } - CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X, - player->index_bit, dig_side); + if (element == EL_SPEED_PILL) + { + player->move_delay_value = MOVE_DELAY_HIGH_SPEED; + } + else if (element == EL_EXTRA_TIME && level.time > 0) + { + TimeLeft += 10; + DrawGameValue_Time(TimeLeft); + } + else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) + { + player->shield_normal_time_left += 10; + if (element == EL_SHIELD_DEADLY) + player->shield_deadly_time_left += 10; + } + else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED) + { + if (player->inventory_size < MAX_INVENTORY_SIZE) + player->inventory_element[player->inventory_size++] = element; -#if 1 - if (mode == DF_SNAP) - TestIfElementTouchesCustomElement(x, y); /* for empty space */ -#endif + DrawGameValue_Dynamite(local_player->inventory_size); + } + else if (element == EL_DYNABOMB_INCREASE_NUMBER) + { + player->dynabomb_count++; + player->dynabombs_left++; + } + else if (element == EL_DYNABOMB_INCREASE_SIZE) + { + player->dynabomb_size++; + } + else if (element == EL_DYNABOMB_INCREASE_POWER) + { + player->dynabomb_xl = TRUE; + } + else if (IS_KEY(element)) + { + player->key[KEY_NR(element)] = TRUE; - break; - } - else if (IS_COLLECTIBLE(element)) - { - RemoveField(x, y); + DrawGameValue_Keys(player->key); - if (is_player && mode != DF_SNAP) - { - GfxElement[x][y] = element; - player->is_collecting = TRUE; - } + redraw_mask |= REDRAW_DOOR_1; + } + else if (IS_ENVELOPE(element)) + { + player->show_envelope = element; + } + else if (IS_DROPPABLE(element) || + IS_THROWABLE(element)) /* can be collected and dropped */ + { + int i; - if (element == EL_SPEED_PILL) - player->move_delay_value = MOVE_DELAY_HIGH_SPEED; - else if (element == EL_EXTRA_TIME && level.time > 0) - { - TimeLeft += 10; - DrawGameValue_Time(TimeLeft); - } - else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) - { - player->shield_normal_time_left += 10; - if (element == EL_SHIELD_DEADLY) - player->shield_deadly_time_left += 10; - } - else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED) - { + if (collect_count == 0) + player->inventory_infinite_element = element; + else + for (i = 0; i < collect_count; i++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; - DrawGameValue_Dynamite(local_player->inventory_size); - } - else if (element == EL_DYNABOMB_INCREASE_NUMBER) - { - player->dynabomb_count++; - player->dynabombs_left++; - } - else if (element == EL_DYNABOMB_INCREASE_SIZE) - { - player->dynabomb_size++; - } - else if (element == EL_DYNABOMB_INCREASE_POWER) - { - player->dynabomb_xl = TRUE; - } - else if (IS_KEY(element)) - { - player->key[KEY_NR(element)] = TRUE; - - DrawGameValue_Keys(player->key); - - redraw_mask |= REDRAW_DOOR_1; - } - else if (IS_ENVELOPE(element)) - { -#if 1 - player->show_envelope = element; -#else - ShowEnvelope(element - EL_ENVELOPE_1); -#endif - } - else if (IS_DROPPABLE(element) || - IS_THROWABLE(element)) /* can be collected and dropped */ - { - int i; - - if (element_info[element].collect_count == 0) - player->inventory_infinite_element = element; - else - for (i = 0; i < element_info[element].collect_count; i++) - if (player->inventory_size < MAX_INVENTORY_SIZE) - player->inventory_element[player->inventory_size++] = element; - - DrawGameValue_Dynamite(local_player->inventory_size); - } - else if (element_info[element].collect_count > 0) - { - local_player->gems_still_needed -= - element_info[element].collect_count; - if (local_player->gems_still_needed < 0) - local_player->gems_still_needed = 0; - - DrawGameValue_Emeralds(local_player->gems_still_needed); - } - - RaiseScoreElement(element); - PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); - - if (is_player) - CheckTriggeredElementChangeByPlayer(x, y, element, - CE_PLAYER_COLLECTS_X, - player->index_bit, dig_side); - -#if 1 - if (mode == DF_SNAP) - TestIfElementTouchesCustomElement(x, y); /* for empty space */ -#endif - - break; - } - else if (IS_PUSHABLE(element)) - { - if (mode == DF_SNAP && element != EL_BD_ROCK) - return MF_NO_ACTION; - - if (CAN_FALL(element) && dy) - return MF_NO_ACTION; - - if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) && - !(element == EL_SPRING && level.use_spring_bug)) - return MF_NO_ACTION; - -#if 1 - if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 && - ((move_direction & MV_VERTICAL && - ((element_info[element].move_pattern & MV_LEFT && - IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) || - (element_info[element].move_pattern & MV_RIGHT && - IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) || - (move_direction & MV_HORIZONTAL && - ((element_info[element].move_pattern & MV_UP && - IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) || - (element_info[element].move_pattern & MV_DOWN && - IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1)))))) - return MF_NO_ACTION; -#endif - -#if 1 - /* do not push elements already moving away faster than player */ - if (CAN_MOVE(element) && MovDir[x][y] == move_direction && - ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL) - return MF_NO_ACTION; -#else - if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING) - return MF_NO_ACTION; -#endif - -#if 1 - -#if 1 - if (game.engine_version >= VERSION_IDENT(3,1,0,0)) - { - if (player->push_delay_value == -1 || !player_was_pushing) - player->push_delay_value = GET_NEW_PUSH_DELAY(element); - } - else if (game.engine_version >= VERSION_IDENT(3,0,7,1)) - { - if (player->push_delay_value == -1) - player->push_delay_value = GET_NEW_PUSH_DELAY(element); - } -#else - if (game.engine_version >= VERSION_IDENT(3,0,7,1)) - { - if (player->push_delay_value == -1 || !player_was_pushing) - player->push_delay_value = GET_NEW_PUSH_DELAY(element); - } -#endif - else if (game.engine_version >= VERSION_IDENT(2,2,0,7)) - { - if (!player->is_pushing) - player->push_delay_value = GET_NEW_PUSH_DELAY(element); - } - - /* - if (game.engine_version >= VERSION_IDENT(2,2,0,7) && - (game.engine_version < VERSION_IDENT(3,0,7,1) || - !player_is_pushing)) - player->push_delay_value = GET_NEW_PUSH_DELAY(element); - */ -#else - if (!player->is_pushing && - game.engine_version >= VERSION_IDENT(2,2,0,7)) - player->push_delay_value = GET_NEW_PUSH_DELAY(element); -#endif - -#if 0 - printf("::: push delay: %ld -> %ld [%d, %d] [%d / %d] [%d '%s': %d]\n", - player->push_delay, player->push_delay_value, - FrameCounter, game.engine_version, - player_was_pushing, player->is_pushing, - element, element_info[element].token_name, - GET_NEW_PUSH_DELAY(element)); -#endif - - player->is_pushing = TRUE; - - if (!(IN_LEV_FIELD(nextx, nexty) && - (IS_FREE(nextx, nexty) || - (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY && - IS_SB_ELEMENT(element))))) - return MF_NO_ACTION; - - if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) - return MF_NO_ACTION; - -#if USE_NEW_PUSH_DELAY - -#if 0 - if ( (player->push_delay == -1) != (player->push_delay2 == 0) ) - printf("::: ALERT: %d, %d [%d / %d]\n", - player->push_delay, player->push_delay2, - FrameCounter, FrameCounter / 50); -#endif - - if (player->push_delay == -1) /* new pushing; restart delay */ - player->push_delay = 0; -#else - if (player->push_delay == 0) /* new pushing; restart delay */ - player->push_delay = FrameCounter; -#endif - -#if USE_NEW_PUSH_DELAY -#if 0 - if ( (player->push_delay > 0) != (!xxx_fr) ) - printf("::: PUSH BUG! %d, (%d -> %d) %d [%d / %d]\n", - player->push_delay, - xxx_pdv2, player->push_delay2, player->push_delay_value, - FrameCounter, FrameCounter / 50); -#endif - -#if 0 - if (player->push_delay > 0 && - !(tape.playing && tape.file_version < FILE_VERSION_2_0) && - element != EL_SPRING && element != EL_BALLOON) -#else - /* !!! */ - if (player->push_delay < player->push_delay_value && - !(tape.playing && tape.file_version < FILE_VERSION_2_0) && - element != EL_SPRING && element != EL_BALLOON) -#endif - -#else - if (!FrameReached(&player->push_delay, player->push_delay_value) && - !(tape.playing && tape.file_version < FILE_VERSION_2_0) && - element != EL_SPRING && element != EL_BALLOON) -#endif - { - /* make sure that there is no move delay before next try to push */ -#if USE_NEW_MOVE_DELAY - if (game.engine_version >= VERSION_IDENT(3,0,7,1)) - player->move_delay = 0; -#else - if (game.engine_version >= VERSION_IDENT(3,0,7,1)) - player->move_delay = INITIAL_MOVE_DELAY_OFF; -#endif - - return MF_NO_ACTION; - } + DrawGameValue_Dynamite(local_player->inventory_size); + } + 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; -#if 0 - printf("::: NOW PUSHING... [%d]\n", FrameCounter); -#endif + DrawGameValue_Emeralds(local_player->gems_still_needed); + } - if (IS_SB_ELEMENT(element)) - { - if (element == EL_SOKOBAN_FIELD_FULL) - { - Back[x][y] = EL_SOKOBAN_FIELD_EMPTY; - local_player->sokobanfields_still_needed++; - } + RaiseScoreElement(element); + PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); - if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) - { - Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY; - local_player->sokobanfields_still_needed--; - } + if (is_player) + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_COLLECTS_X, + player->index_bit, dig_side); - Feld[x][y] = EL_SOKOBAN_OBJECT; + if (mode == DF_SNAP) + TestIfElementTouchesCustomElement(x, y); /* for empty space */ + } + else if (IS_PUSHABLE(element)) + { + if (mode == DF_SNAP && element != EL_BD_ROCK) + return MF_NO_ACTION; - if (Back[x][y] == Back[nextx][nexty]) - PlayLevelSoundAction(x, y, ACTION_PUSHING); - else if (Back[x][y] != 0) - PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL, - ACTION_EMPTYING); - else - PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, - ACTION_FILLING); + if (CAN_FALL(element) && dy) + return MF_NO_ACTION; - if (local_player->sokobanfields_still_needed == 0 && - game.emulation == EMU_SOKOBAN) - { - player->LevelSolved = player->GameOver = TRUE; - PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); - } - } - else - PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); + if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) && + !(element == EL_SPRING && level.use_spring_bug)) + return MF_NO_ACTION; - InitMovingField(x, y, move_direction); - GfxAction[x][y] = ACTION_PUSHING; + if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 && + ((move_direction & MV_VERTICAL && + ((element_info[element].move_pattern & MV_LEFT && + IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) || + (element_info[element].move_pattern & MV_RIGHT && + IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) || + (move_direction & MV_HORIZONTAL && + ((element_info[element].move_pattern & MV_UP && + IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) || + (element_info[element].move_pattern & MV_DOWN && + IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1)))))) + return MF_NO_ACTION; - if (mode == DF_SNAP) - ContinueMoving(x, y); - else - MovPos[x][y] = (dx != 0 ? dx : dy); + /* do not push elements already moving away faster than player */ + if (CAN_MOVE(element) && MovDir[x][y] == move_direction && + ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL) + return MF_NO_ACTION; - Pushed[x][y] = TRUE; - Pushed[nextx][nexty] = TRUE; + if (game.engine_version >= VERSION_IDENT(3,1,0,0)) + { + if (player->push_delay_value == -1 || !player_was_pushing) + player->push_delay_value = GET_NEW_PUSH_DELAY(element); + } + else if (game.engine_version >= VERSION_IDENT(3,0,7,1)) + { + if (player->push_delay_value == -1) + player->push_delay_value = GET_NEW_PUSH_DELAY(element); + } + else if (game.engine_version >= VERSION_IDENT(2,2,0,7)) + { + if (!player->is_pushing) + player->push_delay_value = GET_NEW_PUSH_DELAY(element); + } - if (game.engine_version < VERSION_IDENT(2,2,0,7)) - player->push_delay_value = GET_NEW_PUSH_DELAY(element); - else - player->push_delay_value = -1; /* get new value later */ + player->is_pushing = TRUE; -#if USE_PUSH_BUGFIX - /* now: check for element change _after_ element has been pushed! */ -#if 1 - if (game.use_change_when_pushing_bug) -#else - if (game.engine_version < VERSION_IDENT(3,1,0,0)) -#endif - { - CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, - player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(x,y, element, CE_PLAYER_PUSHES_X, - player->index_bit, dig_side); - } + if (!(IN_LEV_FIELD(nextx, nexty) && + (IS_FREE(nextx, nexty) || + (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY && + IS_SB_ELEMENT(element))))) + return MF_NO_ACTION; -#else + if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) + return MF_NO_ACTION; -#if 1 - /* check for element change _after_ element has been pushed! */ -#else + if (player->push_delay == -1) /* new pushing; restart delay */ + player->push_delay = 0; -#if 1 - /* !!! TEST ONLY !!! */ - CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, - player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X, - player->index_bit, dig_side); -#else - CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X, - player->index_bit, dig_side); - CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, - player->index_bit, dig_side); -#endif -#endif + if (player->push_delay < player->push_delay_value && + !(tape.playing && tape.file_version < FILE_VERSION_2_0) && + element != EL_SPRING && element != EL_BALLOON) + { + /* make sure that there is no move delay before next try to push */ + if (game.engine_version >= VERSION_IDENT(3,0,7,1)) + player->move_delay = 0; -#endif + return MF_NO_ACTION; + } - break; + if (IS_SB_ELEMENT(element)) + { + if (element == EL_SOKOBAN_FIELD_FULL) + { + Back[x][y] = EL_SOKOBAN_FIELD_EMPTY; + local_player->sokobanfields_still_needed++; } - else if (IS_SWITCHABLE(element)) + + if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) { - if (PLAYER_SWITCHING(player, x, y)) - { - CheckTriggeredElementChangeByPlayer(x,y, element, - CE_PLAYER_PRESSES_X, - player->index_bit, dig_side); + Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY; + local_player->sokobanfields_still_needed--; + } - return MF_ACTION; - } + Feld[x][y] = EL_SOKOBAN_OBJECT; + + if (Back[x][y] == Back[nextx][nexty]) + PlayLevelSoundAction(x, y, ACTION_PUSHING); + else if (Back[x][y] != 0) + PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL, + ACTION_EMPTYING); + else + PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, + ACTION_FILLING); - player->is_switching = TRUE; - player->switch_x = x; - player->switch_y = y; + if (local_player->sokobanfields_still_needed == 0 && + game.emulation == EMU_SOKOBAN) + { + player->LevelSolved = player->GameOver = TRUE; + PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); + } + } + else + PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); - PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); + InitMovingField(x, y, move_direction); + GfxAction[x][y] = ACTION_PUSHING; - if (element == EL_ROBOT_WHEEL) - { - Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE; - ZX = x; - ZY = y; + if (mode == DF_SNAP) + ContinueMoving(x, y); + else + MovPos[x][y] = (dx != 0 ? dx : dy); - DrawLevelField(x, y); - } - else if (element == EL_SP_TERMINAL) - { - int xx, yy; + Pushed[x][y] = TRUE; + Pushed[nextx][nexty] = TRUE; - for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++) - { - if (Feld[xx][yy] == EL_SP_DISK_YELLOW) - Bang(xx, yy); - else if (Feld[xx][yy] == EL_SP_TERMINAL) - Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE; - } - } - else if (IS_BELT_SWITCH(element)) - { - ToggleBeltSwitch(x, y); - } - else if (element == EL_SWITCHGATE_SWITCH_UP || - element == EL_SWITCHGATE_SWITCH_DOWN) - { - ToggleSwitchgateSwitch(x, y); - } - else if (element == EL_LIGHT_SWITCH || - element == EL_LIGHT_SWITCH_ACTIVE) - { - ToggleLightSwitch(x, y); + if (game.engine_version < VERSION_IDENT(2,2,0,7)) + player->push_delay_value = GET_NEW_PUSH_DELAY(element); + else + player->push_delay_value = -1; /* get new value later */ -#if 0 - PlayLevelSound(x, y, element == EL_LIGHT_SWITCH ? - SND_LIGHT_SWITCH_ACTIVATING : - SND_LIGHT_SWITCH_DEACTIVATING); -#endif - } - else if (element == EL_TIMEGATE_SWITCH) - { - ActivateTimegateSwitch(x, y); - } - else if (element == EL_BALLOON_SWITCH_LEFT || - element == EL_BALLOON_SWITCH_RIGHT || - element == EL_BALLOON_SWITCH_UP || - element == EL_BALLOON_SWITCH_DOWN || - element == EL_BALLOON_SWITCH_ANY) - { - if (element == EL_BALLOON_SWITCH_ANY) - game.balloon_dir = move_direction; - else - game.balloon_dir = (element == EL_BALLOON_SWITCH_LEFT ? MV_LEFT : - element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT : - element == EL_BALLOON_SWITCH_UP ? MV_UP : - element == EL_BALLOON_SWITCH_DOWN ? MV_DOWN : - MV_NO_MOVING); - } - else if (element == EL_LAMP) - { - Feld[x][y] = EL_LAMP_ACTIVE; - local_player->lights_still_needed--; + /* check for element change _after_ element has been pushed */ + if (game.use_change_when_pushing_bug) + { + CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, + player->index_bit, dig_side); + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PUSHES_X, + player->index_bit, dig_side); + } + } + else if (IS_SWITCHABLE(element)) + { + if (PLAYER_SWITCHING(player, x, y)) + { + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PRESSES_X, + player->index_bit, dig_side); - ResetGfxAnimation(x, y); - DrawLevelField(x, y); - } - else if (element == EL_TIME_ORB_FULL) - { - Feld[x][y] = EL_TIME_ORB_EMPTY; - TimeLeft += 10; - DrawGameValue_Time(TimeLeft); + return MF_ACTION; + } - ResetGfxAnimation(x, y); - DrawLevelField(x, y); + player->is_switching = TRUE; + player->switch_x = x; + player->switch_y = y; -#if 0 - PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MIDDLE); -#endif - } + PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); - CheckTriggeredElementChangeByPlayer(x, y, element, - CE_SWITCH_OF_X, - player->index_bit, dig_side); + if (element == EL_ROBOT_WHEEL) + { + Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE; + ZX = x; + ZY = y; - CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, - player->index_bit, dig_side); + DrawLevelField(x, y); + } + else if (element == EL_SP_TERMINAL) + { + int xx, yy; - return MF_ACTION; + for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++) + { + if (Feld[xx][yy] == EL_SP_DISK_YELLOW) + Bang(xx, yy); + else if (Feld[xx][yy] == EL_SP_TERMINAL) + Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE; } + } + else if (IS_BELT_SWITCH(element)) + { + ToggleBeltSwitch(x, y); + } + else if (element == EL_SWITCHGATE_SWITCH_UP || + element == EL_SWITCHGATE_SWITCH_DOWN) + { + ToggleSwitchgateSwitch(x, y); + } + else if (element == EL_LIGHT_SWITCH || + element == EL_LIGHT_SWITCH_ACTIVE) + { + ToggleLightSwitch(x, y); + } + else if (element == EL_TIMEGATE_SWITCH) + { + ActivateTimegateSwitch(x, y); + } + else if (element == EL_BALLOON_SWITCH_LEFT || + element == EL_BALLOON_SWITCH_RIGHT || + element == EL_BALLOON_SWITCH_UP || + element == EL_BALLOON_SWITCH_DOWN || + element == EL_BALLOON_SWITCH_ANY) + { + if (element == EL_BALLOON_SWITCH_ANY) + game.balloon_dir = move_direction; else - { - if (!PLAYER_SWITCHING(player, x, y)) - { - player->is_switching = TRUE; - player->switch_x = x; - player->switch_y = y; + game.balloon_dir = (element == EL_BALLOON_SWITCH_LEFT ? MV_LEFT : + element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT : + element == EL_BALLOON_SWITCH_UP ? MV_UP : + element == EL_BALLOON_SWITCH_DOWN ? MV_DOWN : + MV_NO_MOVING); + } + else if (element == EL_LAMP) + { + Feld[x][y] = EL_LAMP_ACTIVE; + local_player->lights_still_needed--; -#if 1 - /* !!! TEST ONLY !!! */ - CheckElementChangeByPlayer(x, y, element, CE_SWITCHED, - player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(x, y, element, - CE_SWITCH_OF_X, - player->index_bit, dig_side); -#else - CheckTriggeredElementChangeByPlayer(x, y, element, - CE_SWITCH_OF_X, - player->index_bit, dig_side); - CheckElementChangeByPlayer(x, y, element, CE_SWITCHED, - player->index_bit, dig_side); -#endif - } + ResetGfxAnimation(x, y); + DrawLevelField(x, y); + } + else if (element == EL_TIME_ORB_FULL) + { + Feld[x][y] = EL_TIME_ORB_EMPTY; + TimeLeft += 10; + DrawGameValue_Time(TimeLeft); -#if 1 - /* !!! TEST ONLY !!! (this breaks "machine", level 000) */ - CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER, - player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, - player->index_bit, dig_side); -#else - CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, - player->index_bit, dig_side); - CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER, - player->index_bit, dig_side); -#endif - } + ResetGfxAnimation(x, y); + DrawLevelField(x, y); + } - return MF_NO_ACTION; + CheckTriggeredElementChangeByPlayer(element, CE_SWITCH_OF_X, + player->index_bit, dig_side); + + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PRESSES_X, + player->index_bit, dig_side); + + return MF_ACTION; + } + else + { + if (!PLAYER_SWITCHING(player, x, y)) + { + player->is_switching = TRUE; + player->switch_x = x; + player->switch_y = y; + + CheckElementChangeByPlayer(x, y, element, CE_SWITCHED, + player->index_bit, dig_side); + CheckTriggeredElementChangeByPlayer(element, CE_SWITCH_OF_X, + player->index_bit, dig_side); + } + + CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER, + player->index_bit, dig_side); + CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PRESSES_X, + player->index_bit, dig_side); + + return MF_NO_ACTION; } -#if USE_NEW_PUSH_DELAY player->push_delay = -1; -#else - player->push_delay = 0; -#endif -#if USE_PENGUIN_COLLECT_BUGFIX if (is_player) /* function can also be called by EL_PENGUIN */ -#endif { if (Feld[x][y] != element) /* really digged/collected something */ player->is_collecting = !player->is_digging; @@ -12261,13 +9819,8 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NO_MOVING); -#if 0 - if (player->MovPos != 0) - return FALSE; -#else if (player->MovPos != 0 && game.engine_version >= VERSION_IDENT(2,2,0,0)) return FALSE; -#endif if (!player->active || !IN_LEV_FIELD(x, y)) return FALSE; @@ -12297,9 +9850,7 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) player->MovDir = snap_direction; -#if 1 if (player->MovPos == 0) -#endif { player->is_moving = FALSE; player->is_digging = FALSE; @@ -12313,26 +9864,18 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) player->is_snapping = TRUE; -#if 1 if (player->MovPos == 0) -#endif { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; } -#if 1 if (player->MovPos != 0) /* prevent graphic bugs in versions < 2.2.0 */ DrawLevelField(player->last_jx, player->last_jy); -#endif DrawLevelField(x, y); -#if 0 - BackToFront(); -#endif - return TRUE; } @@ -12341,18 +9884,7 @@ boolean DropElement(struct PlayerInfo *player) int old_element, new_element; int dropx = player->jx, dropy = player->jy; int drop_direction = player->MovDir; -#if 1 int drop_side = drop_direction; -#else - static int trigger_sides[4] = - { - CH_SIDE_LEFT, /* dropping left */ - CH_SIDE_RIGHT, /* dropping right */ - CH_SIDE_TOP, /* dropping up */ - CH_SIDE_BOTTOM, /* dropping down */ - }; - int drop_side = trigger_sides[MV_DIR_BIT(drop_direction)]; -#endif int drop_element = (player->inventory_size > 0 ? player->inventory_element[player->inventory_size - 1] : player->inventory_infinite_element != EL_UNDEFINED ? @@ -12361,6 +9893,13 @@ boolean DropElement(struct PlayerInfo *player) EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr : EL_UNDEFINED); + /* do not drop an element on top of another element; when holding drop key + pressed without moving, dropped element must move away before the next + element can be dropped (this is especially important if the next element + is dynamite, which can be placed on background for historical reasons) */ + if (PLAYER_DROPPING(player, dropx, dropy) && Feld[dropx][dropy] != EL_EMPTY) + return MF_ACTION; + if (IS_THROWABLE(drop_element)) { dropx += GET_DX_FROM_DIR(drop_direction); @@ -12378,30 +9917,16 @@ boolean DropElement(struct PlayerInfo *player) return FALSE; /* check if player has anything that can be dropped */ -#if 1 if (new_element == EL_UNDEFINED) return FALSE; -#else - if (player->inventory_size == 0 && - player->inventory_infinite_element == EL_UNDEFINED && - player->dynabombs_left == 0) - return FALSE; -#endif /* check if anything can be dropped at the current position */ if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION) return FALSE; /* collected custom elements can only be dropped on empty fields */ -#if 1 if (IS_CUSTOM_ELEMENT(new_element) && old_element != EL_EMPTY) return FALSE; -#else - if (player->inventory_size > 0 && - IS_CUSTOM_ELEMENT(player->inventory_element[player->inventory_size - 1]) - && old_element != EL_EMPTY) - return FALSE; -#endif if (old_element != EL_EMPTY) Back[dropx][dropy] = old_element; /* store old element on this field */ @@ -12416,10 +9941,6 @@ boolean DropElement(struct PlayerInfo *player) { player->inventory_size--; -#if 0 - new_element = player->inventory_element[player->inventory_size]; -#endif - DrawGameValue_Dynamite(local_player->inventory_size); if (new_element == EL_DYNAMITE) @@ -12436,25 +9957,13 @@ boolean DropElement(struct PlayerInfo *player) PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); -#if 1 /* needed if previous element just changed to "empty" in the last frame */ Changed[dropx][dropy] = FALSE; /* allow another change */ -#endif -#if 1 - /* !!! TEST ONLY !!! */ CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); - CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element, - CE_PLAYER_DROPS_X, + CheckTriggeredElementChangeByPlayer(new_element, CE_PLAYER_DROPS_X, player->index_bit, drop_side); -#else - CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element, - CE_PLAYER_DROPS_X, - player->index_bit, drop_side); - CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, - player->index_bit, drop_side); -#endif TestIfElementTouchesCustomElement(dropx, dropy); } @@ -12462,10 +9971,6 @@ boolean DropElement(struct PlayerInfo *player) { player->dynabombs_left--; -#if 0 - new_element = EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr; -#endif - Feld[dropx][dropy] = new_element; if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy))) @@ -12475,29 +9980,14 @@ boolean DropElement(struct PlayerInfo *player) PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); } - - -#if 1 - if (Feld[dropx][dropy] == new_element) /* uninitialized unless CE change */ - { -#if 1 InitField_WithBug1(dropx, dropy, FALSE); -#else - InitField(dropx, dropy, FALSE); - if (CAN_MOVE(Feld[dropx][dropy])) - InitMovDir(dropx, dropy); -#endif - } new_element = Feld[dropx][dropy]; /* element might have changed */ if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) && element_info[new_element].move_pattern == MV_WHEN_DROPPED) { -#if 0 - int move_stepsize = element_info[new_element].move_stepsize; -#endif int move_direction, nextx, nexty; if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC) @@ -12507,56 +9997,15 @@ boolean DropElement(struct PlayerInfo *player) nextx = dropx + GET_DX_FROM_DIR(move_direction); nexty = dropy + GET_DY_FROM_DIR(move_direction); -#if 1 Changed[dropx][dropy] = FALSE; /* allow another change */ CheckCollision[dropx][dropy] = 2; -#else - - if (IN_LEV_FIELD_AND_IS_FREE(nextx, nexty)) - { -#if 0 - WasJustMoving[dropx][dropy] = 3; -#else -#if 1 - InitMovingField(dropx, dropy, move_direction); - ContinueMoving(dropx, dropy); -#endif -#endif - } -#if 0 - /* !!! commented out from 3.1.0-4 to 3.1.0-5 !!! */ - else - { - Changed[dropx][dropy] = FALSE; /* allow another change */ - -#if 1 - TestIfElementHitsCustomElement(dropx, dropy, move_direction); -#else - CheckElementChangeBySide(dropx, dropy, new_element, touched_element, - CE_HITTING_SOMETHING, move_direction); -#endif - } -#endif - -#endif - -#if 0 - player->drop_delay = 2 * TILEX / move_stepsize + 1; -#endif } -#if 0 - player->drop_delay = 8 + 8 + 8; -#endif - -#if 1 player->drop_delay = GET_NEW_DROP_DELAY(drop_element); -#endif - -#endif - player->is_dropping = TRUE; + player->drop_x = dropx; + player->drop_y = dropy; return TRUE; } @@ -12683,11 +10132,6 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample) { int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0); -#if 0 - if (sample == SAMPLE_bug) - printf("::: PlayLevelSound_EM: %d, %d: %d\n", x, y, sample); -#endif - switch (sample) { case SAMPLE_blank: @@ -12946,19 +10390,13 @@ void RequestQuitGame(boolean ask_if_really_quit) } else { - -#if 1 if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOff(TRUE); -#endif OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); -#if 1 if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOn(); -#endif - } }