X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=23667a16aec7298aaabe1f4c5748af5b3152daa1;hb=9b360b977c0c1988c9a9bd63bb6d3f3991d1a650;hp=ed511ad661728b37f43cddf69a21d001dad8e42c;hpb=098ef036131fbf9cdcd77d1b985abae78df7cb3c;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index ed511ad6..23667a16 100644 --- a/src/game.c +++ b/src/game.c @@ -51,6 +51,17 @@ #define USE_IMPACT_BUGFIX (TRUE * 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_DROP_BUGFIX (TRUE * USE_NEW_STUFF * 1) + +#define USE_CHANGE_TO_TRIGGERED (TRUE * USE_NEW_STUFF * 1) + +#define USE_BACK_WALKABLE_BUGFIX (TRUE * USE_NEW_STUFF * 1) + +#define TEST_NEW_STUFF (TRUE) + /* for DigField() */ #define DF_NO_PUSH 0 @@ -134,6 +145,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 : \ @@ -358,9 +371,9 @@ static boolean CheckElementChangeExt(int, 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) #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, -1) #define CheckElementChangeBySide(x, y, e, te, ev, s) \ - CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s, CH_PAGE_ANY) + CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s, -1) #define CheckElementChangeByPage(x, y, e, te, ev, p) \ CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p) @@ -1121,9 +1134,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) @@ -1476,6 +1495,20 @@ static void InitGameEngine() } #endif + /* ---------- 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); + } + } + /* ---------- initialize run-time trigger player and element ------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) @@ -1772,6 +1805,11 @@ void InitGame() player->switch_x = -1; player->switch_y = -1; +#if USE_DROP_BUGFIX + player->drop_x = -1; + player->drop_y = -1; +#endif + player->show_envelope = 0; player->move_delay = game.initial_move_delay; @@ -2174,7 +2212,8 @@ void InitGame() #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) @@ -2198,40 +2237,48 @@ 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 ")); + } } + game.restart_level = FALSE; + #if 0 printf("::: starting game [%d]\n", FrameCounter); #endif @@ -3207,7 +3254,7 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) player->index_bit, leave_side); CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, - CE_OTHER_GETS_LEFT, + CE_PLAYER_LEAVES_X, player->index_bit, leave_side); #endif @@ -3259,7 +3306,7 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) player->index_bit, enter_side); CheckTriggeredElementChangeByPlayer(jx, jy, element, - CE_OTHER_GETS_ENTERED, + CE_PLAYER_ENTERS_X, player->index_bit, enter_side); #endif } @@ -4030,7 +4077,7 @@ void Bang(int x, int y) break; } - CheckTriggeredElementChange(x, y, element, CE_OTHER_IS_EXPLODING); + CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X); } void SplashAcid(int x, int y) @@ -4392,13 +4439,17 @@ 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 (!lastline) /* check if element below was hit */ +#if 0 + printf("IMPACT!\n"); +#endif + + if (!last_line) /* check if element below was hit */ { if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING) return; @@ -4419,10 +4470,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; @@ -4604,10 +4655,10 @@ void Impact(int x, int y) CheckElementChangeBySide(x, y + 1, smashed, element, CE_SWITCHED, CH_SIDE_TOP); CheckTriggeredElementChangeBySide(x, y + 1, smashed, - CE_OTHER_IS_SWITCHING,CH_SIDE_TOP); + CE_SWITCH_OF_X, CH_SIDE_TOP); #else CheckTriggeredElementChangeBySide(x, y + 1, smashed, - CE_OTHER_IS_SWITCHING,CH_SIDE_TOP); + CE_SWITCH_OF_X, CH_SIDE_TOP); CheckElementChangeBySide(x, y + 1, smashed, element, CE_SWITCHED, CH_SIDE_TOP); #endif @@ -4621,7 +4672,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)) { @@ -4634,7 +4685,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); } @@ -5813,8 +5864,8 @@ void StartMoving(int x, int y) 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_OTHER_IS_HITTING), - HAS_ANY_CHANGE_EVENT(element, CE_OTHER_GETS_HIT)); + HAS_ANY_CHANGE_EVENT(element, CE_HITTING_X), + HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_X)); #endif #if 1 @@ -6205,7 +6256,16 @@ void StartMoving(int x, int y) #if 1 Store[newx][newy] = EL_EMPTY; if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) + { +#if USE_CHANGE_TO_TRIGGERED + int move_leave_element = element_info[element].move_leave_element; + + Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ? + new_element : move_leave_element); +#else Store[newx][newy] = element_info[element].move_leave_element; +#endif + } #else Store[newx][newy] = EL_EMPTY; if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)) || @@ -6436,6 +6496,10 @@ void StartMoving(int x, int y) ContinueMoving(x, y); } +void dummy() +{ +} + void ContinueMoving(int x, int y) { int element = Feld[x][y]; @@ -6454,6 +6518,7 @@ void ContinueMoving(int x, int y) #else boolean pushed_by_player = Pushed[x][y]; #endif + boolean last_line = (newy == lev_fieldy - 1); MovPos[x][y] += getElementMoveStepsize(x, y); @@ -6615,6 +6680,12 @@ void ContinueMoving(int x, int y) { int move_leave_element = ei->move_leave_element; +#if USE_CHANGE_TO_TRIGGERED + if (ei->move_leave_type == LEAVE_TYPE_LIMITED && + ei->move_leave_element == EL_TRIGGER_ELEMENT) + move_leave_element = stored; +#endif + Feld[x][y] = move_leave_element; #if USE_PREVIOUS_MOVE_DIR @@ -6743,20 +6814,19 @@ void ContinueMoving(int x, int y) #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)) + !last_line && 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))) + (last_line || !IS_FREE(x, newy + 1))) Impact(x, newy); #endif @@ -6789,7 +6859,7 @@ void ContinueMoving(int x, int y) CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER, player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(newx,newy,element,CE_OTHER_GETS_PUSHED, + CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X, player->index_bit, dig_side); } #endif @@ -6836,7 +6906,7 @@ void ContinueMoving(int x, int y) CE_HIT_BY_SOMETHING, opposite_direction); if (IS_CUSTOM_ELEMENT(hitting_element) && - HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING)) + HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X)) { for (i = 0; i < element_info[hitting_element].num_change_pages; i++) { @@ -6844,19 +6914,19 @@ void ContinueMoving(int x, int y) &element_info[hitting_element].change_page[i]; if (change->can_change && - change->has_event[CE_OTHER_IS_HITTING] && + change->has_event[CE_HITTING_X] && change->trigger_side & touched_side && change->trigger_element == touched_element) { CheckElementChangeByPage(newx, newy, hitting_element, - touched_element, CE_OTHER_IS_HITTING,i); + touched_element, CE_HITTING_X, i); break; } } } if (IS_CUSTOM_ELEMENT(touched_element) && - HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT)) + HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X)) { for (i = 0; i < element_info[touched_element].num_change_pages; i++) { @@ -6864,12 +6934,12 @@ void ContinueMoving(int x, int y) &element_info[touched_element].change_page[i]; if (change->can_change && - change->has_event[CE_OTHER_GETS_HIT] && + 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_OTHER_GETS_HIT, i); + hitting_element, CE_HIT_BY_X,i); break; } } @@ -7822,7 +7892,309 @@ 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) +{ + return (element != EL_EMPTY ? element : + number != -1 ? base_element + number - 1 : + EL_EMPTY); +} + +static int getModifiedActionNumber(int value_old, int value_min, int value_max, + int operator, int operand) +{ + int value_new = (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_SET ? operand : + value_old); + + return (value_new < value_min ? value_min : + value_new > value_max ? value_max : + value_new); +} + +static void ExecuteCustomElementAction(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; + + /* ---------- 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 = + (action_arg <= CA_ARG_MAX ? action_arg : + action_arg == CA_ARG_NUMBER_MIN ? CA_ARG_MIN : + action_arg == CA_ARG_NUMBER_MAX ? CA_ARG_MAX : + action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : + action_arg == CA_ARG_NUMBER_CE_COUNT ? ei->collect_count : + action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CHANGE_DELAY(change) : + -1); + + /* (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; + } + + 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; + + break; + } + + case CA_KILL_PLAYER: + { + for (i = 0; i < MAX_PLAYERS; i++) + if (action_arg_player_bits & (1 << i)) + KillHero(&stored_player[i]); + + break; + } + + case CA_RESTART_LEVEL: + { + game.restart_level = TRUE; + + break; + } + + case CA_SHOW_ENVELOPE: + { + int element = getSpecialActionElement(action_arg_element, + action_arg_number, EL_ENVELOPE_1); + + if (IS_ENVELOPE(element)) + local_player->show_envelope = element; + + break; + } + + case CA_ADD_KEY: + { + int element = getSpecialActionElement(action_arg_element, + action_arg_number, EL_KEY_1); + + 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; + + DrawGameValue_Keys(stored_player[i].key); + + redraw_mask |= REDRAW_DOOR_1; + } + } + } + + break; + } + + case CA_DEL_KEY: + { + int element = getSpecialActionElement(action_arg_element, + action_arg_number, EL_KEY_1); + + 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; + + DrawGameValue_Keys(stored_player[i].key); + + redraw_mask |= REDRAW_DOOR_1; + } + } + } + + break; + } + + case CA_SET_PLAYER_SPEED: + { + for (i = 0; i < MAX_PLAYERS; i++) + { + if (trigger_player_bits & (1 << i)) + { + if (action_arg == CA_ARG_NUMBER_RESET) + stored_player[i].move_delay_value = game.initial_move_delay_value; + else if (action_arg == CA_ARG_NUMBER_NORMAL) + stored_player[i].move_delay_value = MOVE_DELAY_NORMAL_SPEED; + else if (action_arg == CA_ARG_NUMBER_MIN) + stored_player[i].move_delay_value = 16; + else if (action_arg == CA_ARG_NUMBER_MAX) + stored_player[i].move_delay_value = MOVE_DELAY_HIGH_SPEED; + else + { +#if 0 + if (action_mode == CA_MODE_ADD) + { + action_mode = CA_MODE_DIVIDE; + action_arg_number = (1 << action_arg_number); + } + else if (action_mode == CA_MODE_SUBTRACT) + { + action_mode = CA_MODE_MULTIPLY; + action_arg_number = (1 << action_arg_number); + } + + int mode = (action_mode == CA_MODE_MULTIPLY ? CA_MODE_DIVIDE : + action_mode == CA_MODE_DIVIDE ? CA_MODE_MULTIPLY : + action_mode); + + stored_player[i].move_delay_value = + getModifiedActionNumber(stored_player[i].move_delay_value, + 1, 16, + action_mode, action_arg_number); +#endif + } + } + } + + break; + } + + case CA_SET_GEMS: + { + local_player->gems_still_needed = + getModifiedActionNumber(local_player->gems_still_needed, 0, 999, + action_mode, action_arg_number); + + DrawGameValue_Emeralds(local_player->gems_still_needed); + + break; + } + + case CA_SET_TIME: + { + if (level.time > 0) /* only modify limited time value */ + { + TimeLeft = getModifiedActionNumber(TimeLeft, 0, 9999, + action_mode, action_arg_number); + + DrawGameValue_Time(TimeLeft); + } + + break; + } + + case CA_SET_SCORE: + { + local_player->score = + getModifiedActionNumber(local_player->score, 0, 99999, + action_mode, action_arg_number); + + DrawGameValue_Score(local_player->score); + + break; + } + + case CA_SET_CE_SCORE: + { + printf("::: CA_SET_CE_SCORE -- not yet implemented\n"); + + break; + } + + case CA_SET_CE_COUNT: + { + printf("::: CA_SET_CE_COUNT -- not yet implemented\n"); + + 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]; #if 1 @@ -7909,6 +8281,11 @@ static void ChangeElementNowExt(int x, int y, int target_element) TestIfPlayerTouchesCustomElement(x, y); TestIfElementTouchesCustomElement(x, y); #endif + +#if 0 + if (change->has_action) + ExecuteCustomElementAction(...); +#endif } static boolean ChangeElementNow(int x, int y, int element, int page) @@ -7923,7 +8300,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page) if (ChangeEvent[x][y] == CE_DELAY) { - /* reset actual trigger element and player */ + /* reset actual trigger element, trigger player and action element */ change->actual_trigger_element = EL_EMPTY; change->actual_trigger_player = EL_PLAYER_1; } @@ -7946,7 +8323,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page) #if 0 /* !!! indirect change before direct change !!! */ - CheckTriggeredElementChangeByPage(x,y,Feld[x][y], CE_OTHER_IS_CHANGING,page); + CheckTriggeredElementChangeByPage(x, y, Feld[x][y], CE_CHANGE_OF_X, page); #endif if (change->explode) @@ -8090,7 +8467,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; @@ -8108,14 +8485,14 @@ 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_OTHER_IS_CHANGING,page); + CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page); #endif return TRUE; @@ -8151,8 +8528,12 @@ static void ChangeElement(int x, int y, int page) if (ChangeDelay[x][y] == 0) /* initialize element change */ { +#if 1 + ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1; +#else ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames + RND(change->delay_random * change->delay_frames)) + 1; +#endif ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); @@ -8195,6 +8576,11 @@ static void ChangeElement(int x, int y, int page) return; } +#if 0 + if (change->has_action) + ExecuteCustomElementAction(element, page); +#endif + if (ChangeElementNow(x, y, element, page)) { if (change->post_change_function) @@ -8220,17 +8606,19 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, { int element = EL_CUSTOM_START + i; + boolean change_found = FALSE; 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++) { struct ElementChangeInfo *change = &element_info[element].change_page[j]; - 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 && @@ -8243,6 +8631,28 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, trigger_element-EL_CUSTOM_START+1, i+1, j, trigger_event); #endif +#if 1 + change->actual_trigger_element = trigger_element; + change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); + + if (change->can_change && !change_found) + { + change_found = TRUE; + + for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) + { + if (Feld[x][y] == element) + { + ChangeDelay[x][y] = 1; + ChangeEvent[x][y] = trigger_event; + ChangeElement(x, y, j); + } + } + } + + if (change->has_action) + ExecuteCustomElementAction(element, j); +#else change_element = TRUE; page = j; @@ -8250,9 +8660,11 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); break; +#endif } } +#if 0 if (!change_element) continue; @@ -8270,6 +8682,7 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, ChangeElement(x, y, page); } } +#endif } return TRUE; @@ -8306,6 +8719,103 @@ static boolean CheckElementChangeExt(int x, int y, } #endif +#if 1 + if (trigger_page < 0) + { + boolean change_element = FALSE; + int i; + + for (i = 0; i < element_info[element].num_change_pages; i++) + { + struct ElementChangeInfo *change = &element_info[element].change_page[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 && + change->has_event[trigger_event] && + change->trigger_side & trigger_side && + change->trigger_player & trigger_player +#if 1 + && + (!check_trigger_element || + IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)) +#endif + ) + { + change_element = TRUE; + trigger_page = i; + + change->actual_trigger_element = trigger_element; + change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); + + break; + } + } + + 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 */ + } + +#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; +} + +static boolean CheckElementChangeExtTEST(int x, int y, + int element, + int trigger_element, + int trigger_event, + int trigger_player, + int trigger_side, + int trigger_page) +{ + if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) + return FALSE; + + if (Feld[x][y] == EL_BLOCKED) + { + Blocked2Moving(x, y, &x, &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) { @@ -8319,7 +8829,8 @@ static boolean CheckElementChangeExt(int x, int y, if (change->can_change && change->has_event[trigger_event] && change->trigger_side & trigger_side && - change->trigger_player & trigger_player) + change->trigger_player & trigger_player && + IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)) { change_element = TRUE; trigger_page = i; @@ -9905,7 +10416,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, #if 0 if (IS_CUSTOM_ELEMENT(Feld[jx][jy])) { - CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_OTHER_GETS_LEFT, + CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_PLAYER_LEAVES_X, leave_side); CheckElementChangeBySide(jx,jy, Feld[jx][jy],CE_LEFT_BY_PLAYER,leave_side); } @@ -9913,7 +10424,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy])) { CheckTriggeredElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy], - CE_OTHER_GETS_ENTERED, enter_side); + CE_PLAYER_ENTERS_X, enter_side); CheckElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy], CE_ENTERED_BY_PLAYER, enter_side); } @@ -10184,7 +10695,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->index_bit, leave_side); CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, - CE_OTHER_GETS_LEFT, + CE_PLAYER_LEAVES_X, player->index_bit, leave_side); if (IS_CUSTOM_ELEMENT(new_element)) @@ -10192,7 +10703,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->index_bit, enter_side); CheckTriggeredElementChangeByPlayer(jx, jy, new_element, - CE_OTHER_GETS_ENTERED, + CE_PLAYER_ENTERS_X, player->index_bit, enter_side); #endif @@ -10441,7 +10952,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) player->index_bit, leave_side); CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, - CE_OTHER_GETS_LEFT, + CE_PLAYER_LEAVES_X, player->index_bit, leave_side); if (IS_CUSTOM_ELEMENT(new_element)) @@ -10449,7 +10960,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) player->index_bit, enter_side); CheckTriggeredElementChangeByPlayer(jx, jy, new_element, - CE_OTHER_GETS_ENTERED, + CE_PLAYER_ENTERS_X, player->index_bit, enter_side); #endif @@ -10586,11 +11097,11 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER, player->index_bit, border_side); CheckTriggeredElementChangeByPlayer(xx, yy, border_element, - CE_OTHER_GETS_TOUCHED, + CE_PLAYER_TOUCHES_X, player->index_bit, border_side); #else CheckTriggeredElementChangeByPlayer(xx, yy, border_element, - CE_OTHER_GETS_TOUCHED, + CE_PLAYER_TOUCHES_X, player->index_bit, border_side); CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER, player->index_bit, border_side); @@ -10611,11 +11122,11 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER, player->index_bit, center_side); CheckTriggeredElementChangeByPlayer(x, y, center_element, - CE_OTHER_GETS_TOUCHED, + CE_PLAYER_TOUCHES_X, player->index_bit, center_side); #else CheckTriggeredElementChangeByPlayer(x, y, center_element, - CE_OTHER_GETS_TOUCHED, + CE_PLAYER_TOUCHES_X, player->index_bit, center_side); CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER, player->index_bit, center_side); @@ -10676,9 +11187,21 @@ void TestIfElementTouchesCustomElement(int x, int y) else continue; /* center and border element do not touch */ +#if TEST_NEW_STUFF + + /* check for change of center element (but change it only once) */ + if (!change_center_element) + change_center_element = + CheckElementChangeBySide(x, y, center_element, border_element, + CE_TOUCHING_X, border_side); + + /* -> CheckElementChangeExtTEST */ + +#else + /* check for change of center element (but change it only once) */ if (IS_CUSTOM_ELEMENT(center_element) && - HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) && + HAS_ANY_CHANGE_EVENT(center_element, CE_TOUCHING_X) && !change_center_element) { for (j = 0; j < element_info[center_element].num_change_pages; j++) @@ -10687,7 +11210,7 @@ void TestIfElementTouchesCustomElement(int x, int y) &element_info[center_element].change_page[j]; if (change->can_change && - change->has_event[CE_OTHER_IS_TOUCHING] && + change->has_event[CE_TOUCHING_X] && change->trigger_side & border_side && #if 1 IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element) @@ -10705,9 +11228,19 @@ void TestIfElementTouchesCustomElement(int x, int y) } } +#endif + +#if TEST_NEW_STUFF + + /* check for change of border element */ + CheckElementChangeBySide(xx, yy, border_element, center_element, + CE_TOUCHING_X, center_side); + +#else + /* check for change of border element */ if (IS_CUSTOM_ELEMENT(border_element) && - HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING)) + HAS_ANY_CHANGE_EVENT(border_element, CE_TOUCHING_X)) { for (j = 0; j < element_info[border_element].num_change_pages; j++) { @@ -10715,7 +11248,7 @@ void TestIfElementTouchesCustomElement(int x, int y) &element_info[border_element].change_page[j]; if (change->can_change && - change->has_event[CE_OTHER_IS_TOUCHING] && + change->has_event[CE_TOUCHING_X] && change->trigger_side & center_side && #if 1 IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element) @@ -10729,13 +11262,18 @@ void TestIfElementTouchesCustomElement(int x, int y) #endif CheckElementChangeByPage(xx, yy, border_element, center_element, - CE_OTHER_IS_TOUCHING, j); + CE_TOUCHING_X, j); break; } } } + +#endif + } +#if !TEST_NEW_STUFF + if (change_center_element) { #if 0 @@ -10743,8 +11281,11 @@ void TestIfElementTouchesCustomElement(int x, int y) #endif CheckElementChangeByPage(x, y, center_element, border_trigger_element, - CE_OTHER_IS_TOUCHING, center_element_change_page); + CE_TOUCHING_X, center_element_change_page); } + +#endif + } void TestIfElementHitsCustomElement(int x, int y, int direction) @@ -10773,8 +11314,11 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) 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)) { @@ -10796,11 +11340,20 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) { int i; +#if !USE_HIT_BY_SOMETHING_BUGFIX CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_HIT_BY_SOMETHING, opposite_direction); +#endif + +#if TEST_NEW_STUFF + + CheckElementChangeBySide(x, y, hitting_element, touched_element, + CE_HITTING_X, touched_side); + +#else if (IS_CUSTOM_ELEMENT(hitting_element) && - HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING)) + HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X)) { for (i = 0; i < element_info[hitting_element].num_change_pages; i++) { @@ -10808,7 +11361,7 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) &element_info[hitting_element].change_page[i]; if (change->can_change && - change->has_event[CE_OTHER_IS_HITTING] && + change->has_event[CE_HITTING_X] && change->trigger_side & touched_side && #if 1 @@ -10819,14 +11372,22 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) ) { CheckElementChangeByPage(x, y, hitting_element, touched_element, - CE_OTHER_IS_HITTING, i); + CE_HITTING_X, i); break; } } } +#endif + +#if TEST_NEW_STUFF + + CheckElementChangeBySide(hitx, hity, touched_element, + hitting_element, CE_HIT_BY_X, hitting_side); +#else + if (IS_CUSTOM_ELEMENT(touched_element) && - HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT)) + HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X)) { for (i = 0; i < element_info[touched_element].num_change_pages; i++) { @@ -10834,7 +11395,7 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) &element_info[touched_element].change_page[i]; if (change->can_change && - change->has_event[CE_OTHER_GETS_HIT] && + change->has_event[CE_HIT_BY_X] && change->trigger_side & hitting_side && #if 1 IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element) @@ -10844,13 +11405,26 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) ) { CheckElementChangeByPage(hitx, hity, touched_element, - hitting_element, CE_OTHER_GETS_HIT, i); + hitting_element, CE_HIT_BY_X, i); break; } } } + +#endif + +#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 @@ -10906,6 +11480,12 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction) CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_SMASHED_BY_SOMETHING, opposite_direction); +#if TEST_NEW_STUFF + + CheckElementChangeBySide(x, y, hitting_element, touched_element, + CE_OTHER_IS_SMASHING, touched_side); +#else + if (IS_CUSTOM_ELEMENT(hitting_element) && HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_SMASHING)) { @@ -10932,6 +11512,14 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction) } } +#endif + +#if TEST_NEW_STUFF + + CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, + CE_OTHER_GETS_SMASHED, hitting_side); +#else + if (IS_CUSTOM_ELEMENT(touched_element) && HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_SMASHED)) { @@ -10956,6 +11544,9 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction) } } } + +#endif + } } } @@ -11409,6 +12000,13 @@ int DigField(struct PlayerInfo *player, if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; +#if USE_BACK_WALKABLE_BUGFIX + + /* 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]; +#endif #endif @@ -11714,7 +12312,7 @@ int DigField(struct PlayerInfo *player, PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); - CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_DIGGED, + CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X, player->index_bit, dig_side); #if 1 @@ -11735,7 +12333,9 @@ int DigField(struct PlayerInfo *player, } if (element == EL_SPEED_PILL) + { player->move_delay_value = MOVE_DELAY_HIGH_SPEED; + } else if (element == EL_EXTRA_TIME && level.time > 0) { TimeLeft += 10; @@ -11812,7 +12412,7 @@ int DigField(struct PlayerInfo *player, if (is_player) CheckTriggeredElementChangeByPlayer(x, y, element, - CE_OTHER_GETS_COLLECTED, + CE_PLAYER_COLLECTS_X, player->index_bit, dig_side); #if 1 @@ -12036,7 +12636,7 @@ int DigField(struct PlayerInfo *player, { CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(x,y,element,CE_OTHER_GETS_PUSHED, + CheckTriggeredElementChangeByPlayer(x,y, element, CE_PLAYER_PUSHES_X, player->index_bit, dig_side); } @@ -12050,10 +12650,10 @@ int DigField(struct PlayerInfo *player, /* !!! TEST ONLY !!! */ CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED, + CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X, player->index_bit, dig_side); #else - CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED, + 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); @@ -12069,7 +12669,7 @@ int DigField(struct PlayerInfo *player, if (PLAYER_SWITCHING(player, x, y)) { CheckTriggeredElementChangeByPlayer(x,y, element, - CE_OTHER_GETS_PRESSED, + CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MF_ACTION; @@ -12163,10 +12763,10 @@ int DigField(struct PlayerInfo *player, } CheckTriggeredElementChangeByPlayer(x, y, element, - CE_OTHER_IS_SWITCHING, + CE_SWITCH_OF_X, player->index_bit, dig_side); - CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED, + CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MF_ACTION; @@ -12184,11 +12784,11 @@ int DigField(struct PlayerInfo *player, CheckElementChangeByPlayer(x, y, element, CE_SWITCHED, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, - CE_OTHER_IS_SWITCHING, + CE_SWITCH_OF_X, player->index_bit, dig_side); #else CheckTriggeredElementChangeByPlayer(x, y, element, - CE_OTHER_IS_SWITCHING, + CE_SWITCH_OF_X, player->index_bit, dig_side); CheckElementChangeByPlayer(x, y, element, CE_SWITCHED, player->index_bit, dig_side); @@ -12199,10 +12799,10 @@ int DigField(struct PlayerInfo *player, /* !!! 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_OTHER_GETS_PRESSED, + CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); #else - CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED, + 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); @@ -12338,6 +12938,15 @@ boolean DropElement(struct PlayerInfo *player) EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr : EL_UNDEFINED); +#if USE_DROP_BUGFIX + /* 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; +#endif + if (IS_THROWABLE(drop_element)) { dropx += GET_DX_FROM_DIR(drop_direction); @@ -12423,11 +13032,11 @@ boolean DropElement(struct PlayerInfo *player) CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element, - CE_OTHER_GETS_DROPPED, + CE_PLAYER_DROPS_X, player->index_bit, drop_side); #else CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element, - CE_OTHER_GETS_DROPPED, + CE_PLAYER_DROPS_X, player->index_bit, drop_side); CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); @@ -12534,6 +13143,10 @@ boolean DropElement(struct PlayerInfo *player) player->is_dropping = TRUE; +#if USE_DROP_BUGFIX + player->drop_x = dropx; + player->drop_y = dropy; +#endif return TRUE; }