X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=d8039785faa95e2179dfd8d154821fcca63bb23c;hb=cdc3c940197937b0508a1eb7dcf44874951908b7;hp=a383c6900334c24622e0fd32b3d82412f9979bc3;hpb=486d880026ce50d4e4d3a3b78a9e72db2b09d755;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index a383c690..d8039785 100644 --- a/src/game.c +++ b/src/game.c @@ -28,26 +28,37 @@ #define USE_NEW_AMOEBA_CODE FALSE /* EXPERIMENTAL STUFF */ -#define USE_NEW_STUFF (TRUE * 1) +#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_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_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) +#define USE_PUSH_BUGFIX (TRUE * USE_NEW_STUFF * 1) #if 0 -#define USE_BLOCK_DELAY_BUGFIX (TRUE * USE_NEW_STUFF * 1) +#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_GRAVITY_BUGFIX_NEW (TRUE * USE_NEW_STUFF * 1) +#define USE_GRAVITY_BUGFIX_OLD (TRUE * USE_NEW_STUFF * 0) -#define USE_PENGUIN_COLLECT_BUG (TRUE * USE_NEW_STUFF * 1) +#define USE_PENGUIN_COLLECT_BUGFIX (TRUE * USE_NEW_STUFF * 1) + +#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) /* for DigField() */ @@ -132,6 +143,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 : \ @@ -672,10 +685,9 @@ access_direction_list[] = { EL_UNDEFINED, MV_NO_MOVING } }; -static unsigned long trigger_events[MAX_NUM_ELEMENTS]; +static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS]; -#define IS_AUTO_CHANGING(e) (element_info[e].change_events & \ - CH_EVENT_BIT(CE_DELAY)) +#define IS_AUTO_CHANGING(e) (element_info[e].has_change_event[CE_DELAY]) #define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0) #define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \ IS_JUST_CHANGING(x, y)) @@ -1120,9 +1132,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) @@ -1269,7 +1287,7 @@ static void resolve_group_element(int group_element, int recursion_depth) static void InitGameEngine() { - int i, j, k; + int i, j, k, l; /* set game engine from tape file when re-playing, else from level file */ game.engine_version = (tape.playing ? tape.engine_version : @@ -1408,9 +1426,10 @@ static void InitGameEngine() ei->change->delay_frames = 1; } - ei->change_events = CE_BITMASK_DEFAULT; for (j = 0; j < NUM_CHANGE_EVENTS; j++) { + ei->has_change_event[j] = FALSE; + ei->event_page_nr[j] = 0; ei->event_page[j] = &ei->change_page[0]; } @@ -1429,7 +1448,7 @@ static void InitGameEngine() ei->change->change_function = ch_delay->change_function; ei->change->post_change_function = ch_delay->post_change_function; - ei->change_events |= CH_EVENT_BIT(CE_DELAY); + ei->has_change_event[CE_DELAY] = TRUE; #if 1 SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE); @@ -1450,10 +1469,10 @@ static void InitGameEngine() for (k = 0; k < NUM_CHANGE_EVENTS; k++) { /* only add event page for the first page found with this event */ - if (ei->change_page[j].events & CH_EVENT_BIT(k) && - !(ei->change_events & CH_EVENT_BIT(k))) + if (ei->change_page[j].has_event[k] && !(ei->has_change_event[k])) { - ei->change_events |= CH_EVENT_BIT(k); + ei->has_change_event[k] = TRUE; + ei->event_page_nr[k] = j; ei->event_page[k] = &ei->change_page[j]; } @@ -1470,7 +1489,7 @@ static void InitGameEngine() /* only add custom elements that change after fixed/random frame delay */ if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY)) - element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY); + element_info[element].has_change_event[CE_DELAY] = TRUE; } #endif @@ -1491,7 +1510,8 @@ static void InitGameEngine() /* initialize trigger events information */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) - trigger_events[i] = EP_BITMASK_DEFAULT; + for (j = 0; j < NUM_CHANGE_EVENTS; j++) + trigger_events[i][j] = FALSE; #if 1 /* add trigger events from element change event properties */ @@ -1504,20 +1524,26 @@ static void InitGameEngine() if (!ei->change_page[j].can_change) continue; - if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION)) + if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION]) { int trigger_element = ei->change_page[j].trigger_element; - if (IS_GROUP_ELEMENT(trigger_element)) + for (k = 0; k < NUM_CHANGE_EVENTS; k++) { - struct ElementGroupInfo *group = element_info[trigger_element].group; + if (ei->change_page[j].has_event[k]) + { + if (IS_GROUP_ELEMENT(trigger_element)) + { + struct ElementGroupInfo *group = + element_info[trigger_element].group; - for (k = 0; k < group->num_elements_resolved; k++) - trigger_events[group->element_resolved[k]] - |= ei->change_page[j].events; + for (l = 0; l < group->num_elements_resolved; l++) + trigger_events[group->element_resolved[l]][k] = TRUE; + } + else + trigger_events[trigger_element][k] = TRUE; + } } - else - trigger_events[trigger_element] |= ei->change_page[j].events; } } } @@ -1525,8 +1551,9 @@ static void InitGameEngine() /* 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)) - trigger_events[element_info[i].change->trigger_element] |= - element_info[i].change->events; + 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 -------------------------------------- */ @@ -1762,6 +1789,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; @@ -1857,8 +1889,8 @@ void InitGame() Stop[x][y] = FALSE; Pushed[x][y] = FALSE; - Changed[x][y] = CE_BITMASK_DEFAULT; - ChangeEvent[x][y] = CE_BITMASK_DEFAULT; + Changed[x][y] = FALSE; + ChangeEvent[x][y] = -1; ExplodePhase[x][y] = 0; ExplodeDelay[x][y] = 0; @@ -2164,7 +2196,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) @@ -2188,40 +2221,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 @@ -3197,7 +3238,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 @@ -3249,7 +3290,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 } @@ -4020,7 +4061,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) @@ -4382,13 +4423,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; @@ -4409,10 +4454,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; @@ -4594,10 +4639,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 @@ -4611,7 +4656,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)) { @@ -4624,7 +4669,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); } @@ -5561,6 +5606,15 @@ void StartMoving(int x, int y) 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))) || + + (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))) || @@ -5568,6 +5622,7 @@ void StartMoving(int x, int y) (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 @@ -5793,8 +5848,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 @@ -6185,7 +6240,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)) || @@ -6416,6 +6480,10 @@ void StartMoving(int x, int y) ContinueMoving(x, y); } +void dummy() +{ +} + void ContinueMoving(int x, int y) { int element = Feld[x][y]; @@ -6434,6 +6502,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); @@ -6565,8 +6634,8 @@ void ContinueMoving(int x, int y) ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; - Changed[x][y] = CE_BITMASK_DEFAULT; - ChangeEvent[x][y] = CE_BITMASK_DEFAULT; + Changed[x][y] = FALSE; + ChangeEvent[x][y] = -1; /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; @@ -6595,6 +6664,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 @@ -6723,20 +6798,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)) && - (!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 @@ -6769,7 +6843,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 @@ -6816,7 +6890,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++) { @@ -6824,19 +6898,19 @@ void ContinueMoving(int x, int y) &element_info[hitting_element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(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++) { @@ -6844,12 +6918,12 @@ void ContinueMoving(int x, int y) &element_info[touched_element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(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; } } @@ -7802,7 +7876,306 @@ 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; + + /* ---------- 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 @@ -7879,6 +8252,8 @@ static void ChangeElementNowExt(int x, int y, int 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 @@ -7887,6 +8262,11 @@ static void ChangeElementNowExt(int x, int y, int target_element) TestIfPlayerTouchesCustomElement(x, y); TestIfElementTouchesCustomElement(x, y); #endif + +#if 0 + if (change->use_action) + ExecuteCustomElementAction(...); +#endif } static boolean ChangeElementNow(int x, int y, int element, int page) @@ -7896,30 +8276,35 @@ static boolean ChangeElementNow(int x, int y, int element, int page) int old_element = Feld[x][y]; /* always use default change event to prevent running into a loop */ - if (ChangeEvent[x][y] == CE_BITMASK_DEFAULT) - ChangeEvent[x][y] = CH_EVENT_BIT(CE_DELAY); + if (ChangeEvent[x][y] == -1) + ChangeEvent[x][y] = CE_DELAY; - if (ChangeEvent[x][y] == CH_EVENT_BIT(CE_DELAY)) + 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; } - /* do not change already changed elements with same change event */ -#if 0 - if (Changed[x][y] & ChangeEvent[x][y]) +#if 1 + /* do not change any elements that have already changed in this frame */ + if (Changed[x][y]) return FALSE; #else - if (Changed[x][y]) + /* 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 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) @@ -8063,7 +8448,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; @@ -8081,14 +8466,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; @@ -8124,8 +8509,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); @@ -8168,6 +8557,11 @@ static void ChangeElement(int x, int y, int page) return; } +#if 1 + if (change->use_action) + ExecuteCustomElementAction(element, page); +#endif + if (ChangeElementNow(x, y, element, page)) { if (change->post_change_function) @@ -8186,7 +8580,7 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, int i, j, x, y; int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page); - if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event))) + if (!(trigger_events[trigger_element][trigger_event])) return FALSE; for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) @@ -8204,14 +8598,14 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, struct ElementChangeInfo *change = &element_info[element].change_page[j]; if (change->can_change && - change->events & CH_EVENT_BIT(trigger_event) && + 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->events & CH_EVENT_BIT(trigger_event))) + 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 @@ -8239,7 +8633,7 @@ static boolean CheckTriggeredElementChangeExt(int lx, int ly, if (Feld[x][y] == element) { ChangeDelay[x][y] = 1; - ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event); + ChangeEvent[x][y] = trigger_event; ChangeElement(x, y, page); } } @@ -8290,7 +8684,7 @@ static boolean CheckElementChangeExt(int x, int y, struct ElementChangeInfo *change = &element_info[element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(trigger_event) && + change->has_event[trigger_event] && change->trigger_side & trigger_side && change->trigger_player & trigger_player) { @@ -8328,7 +8722,7 @@ static boolean CheckElementChangeExt(int x, int y, #endif ChangeDelay[x][y] = 1; - ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event); + ChangeEvent[x][y] = trigger_event; ChangeElement(x, y, trigger_page); return TRUE; @@ -8956,8 +9350,8 @@ void GameActions() for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) { - Changed[x][y] = CE_BITMASK_DEFAULT; - ChangeEvent[x][y] = CE_BITMASK_DEFAULT; + Changed[x][y] = FALSE; + ChangeEvent[x][y] = -1; #if USE_NEW_BLOCK_STYLE /* this must be handled before main playfield loop */ @@ -9878,7 +10272,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); } @@ -9886,7 +10280,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); } @@ -10157,7 +10551,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)) @@ -10165,7 +10559,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 @@ -10414,7 +10808,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)) @@ -10422,7 +10816,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 @@ -10559,11 +10953,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); @@ -10584,11 +10978,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); @@ -10651,7 +11045,7 @@ void TestIfElementTouchesCustomElement(int x, int y) /* 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++) @@ -10660,7 +11054,7 @@ void TestIfElementTouchesCustomElement(int x, int y) &element_info[center_element].change_page[j]; if (change->can_change && - change->events & CH_EVENT_BIT(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) @@ -10680,7 +11074,7 @@ void TestIfElementTouchesCustomElement(int x, int y) /* 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++) { @@ -10688,7 +11082,7 @@ void TestIfElementTouchesCustomElement(int x, int y) &element_info[border_element].change_page[j]; if (change->can_change && - change->events & CH_EVENT_BIT(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) @@ -10702,7 +11096,7 @@ void TestIfElementTouchesCustomElement(int x, int y) #endif CheckElementChangeByPage(xx, yy, border_element, center_element, - CE_OTHER_IS_TOUCHING, j); + CE_TOUCHING_X, j); break; } } @@ -10716,7 +11110,7 @@ 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); } } @@ -10746,8 +11140,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)) { @@ -10769,11 +11166,13 @@ 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 (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++) { @@ -10781,7 +11180,7 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) &element_info[hitting_element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) && + change->has_event[CE_HITTING_X] && change->trigger_side & touched_side && #if 1 @@ -10792,14 +11191,14 @@ 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; } } } 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++) { @@ -10807,7 +11206,7 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) &element_info[touched_element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(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) @@ -10817,13 +11216,24 @@ 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; } } } + +#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 @@ -10888,7 +11298,7 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction) &element_info[hitting_element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(CE_OTHER_IS_SMASHING) && + change->has_event[CE_OTHER_IS_SMASHING] && change->trigger_side & touched_side && #if 1 @@ -10914,7 +11324,7 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction) &element_info[touched_element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(CE_OTHER_GETS_SMASHED) && + change->has_event[CE_OTHER_GETS_SMASHED] && change->trigger_side & hitting_side && #if 1 IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element) @@ -11382,6 +11792,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 @@ -11687,7 +12104,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 @@ -11708,7 +12125,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; @@ -11785,7 +12204,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 @@ -12009,7 +12428,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); } @@ -12023,10 +12442,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); @@ -12042,7 +12461,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; @@ -12136,10 +12555,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; @@ -12157,11 +12576,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); @@ -12172,10 +12591,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); @@ -12191,7 +12610,7 @@ int DigField(struct PlayerInfo *player, player->push_delay = 0; #endif -#if USE_PENGUIN_COLLECT_BUG +#if USE_PENGUIN_COLLECT_BUGFIX if (is_player) /* function can also be called by EL_PENGUIN */ #endif { @@ -12311,6 +12730,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); @@ -12388,7 +12816,7 @@ boolean DropElement(struct PlayerInfo *player) #if 1 /* needed if previous element just changed to "empty" in the last frame */ - Changed[dropx][dropy] = 0; /* allow another change */ + Changed[dropx][dropy] = FALSE; /* allow another change */ #endif #if 1 @@ -12396,11 +12824,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); @@ -12458,7 +12886,7 @@ boolean DropElement(struct PlayerInfo *player) nexty = dropy + GET_DY_FROM_DIR(move_direction); #if 1 - Changed[dropx][dropy] = 0; /* allow another change */ + Changed[dropx][dropy] = FALSE; /* allow another change */ CheckCollision[dropx][dropy] = 2; #else @@ -12477,7 +12905,7 @@ boolean DropElement(struct PlayerInfo *player) /* !!! commented out from 3.1.0-4 to 3.1.0-5 !!! */ else { - Changed[dropx][dropy] = 0; /* allow another change */ + Changed[dropx][dropy] = FALSE; /* allow another change */ #if 1 TestIfElementHitsCustomElement(dropx, dropy, move_direction); @@ -12507,6 +12935,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; }