X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=e3007408dd8b4f65da4ffddb77f446689f338357;hb=c93f939100438a9047653b2c2c6b86f034e1bb01;hp=a383c6900334c24622e0fd32b3d82412f9979bc3;hpb=486d880026ce50d4e4d3a3b78a9e72db2b09d755;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index a383c690..e3007408 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() */ @@ -672,10 +683,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)) @@ -1269,7 +1279,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 +1418,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 +1440,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 +1461,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 +1481,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 +1502,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 +1516,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 +1543,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 +1781,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 +1881,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; @@ -3197,7 +3221,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 +3273,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 +4044,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 +4406,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 +4437,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 +4622,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 +4639,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 +4652,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 +5589,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 +5605,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 +5831,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 +6223,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 +6463,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 +6485,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 +6617,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 +6647,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 +6781,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 +6826,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 +6873,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 +6881,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 +6901,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 +7859,26 @@ static void ChangeActiveTrap(int x, int y) DrawLevelFieldCrumbledSand(x, y); } -static void ChangeElementNowExt(int x, int y, int target_element) +static void HandleChangeAction(int change_action) +{ + if (change_action == CA_EXIT_PLAYER) + { + printf("::: CA_EXIT_GAME\n"); + + /* !!! local_player <-> 4 players !!! (EXTEND THIS) !!! */ + local_player->LevelSolved = local_player->GameOver = TRUE; + } + else if (change_action == CA_KILL_PLAYER) + { + printf("::: CA_KILL_PLAYER\n"); + + /* !!! local_player <-> 4 players !!! (EXTEND THIS) !!! */ + KillHero(local_player); + } +} + +static void ChangeElementNowExt(struct ElementChangeInfo *change, + int x, int y, int target_element) { int previous_move_direction = MovDir[x][y]; #if 1 @@ -7879,6 +7955,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 +7965,9 @@ static void ChangeElementNowExt(int x, int y, int target_element) TestIfPlayerTouchesCustomElement(x, y); TestIfElementTouchesCustomElement(x, y); #endif + + if (change->use_change_action) + HandleChangeAction(change->change_action); } static boolean ChangeElementNow(int x, int y, int element, int page) @@ -7896,30 +7977,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 */ 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 +8149,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 +8167,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; @@ -8186,7 +8272,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 +8290,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 +8325,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 +8376,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 +8414,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 +9042,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 +9964,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 +9972,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 +10243,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 +10251,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 +10500,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 +10508,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 +10645,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 +10670,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 +10737,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 +10746,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 +10766,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 +10774,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 +10788,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 +10802,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 +10832,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 +10858,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 +10872,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 +10883,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 +10898,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 +10908,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 +10990,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 +11016,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 +11484,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 +11796,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 @@ -11785,7 +11894,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 +12118,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 +12132,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 +12151,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 +12245,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 +12266,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 +12281,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 +12300,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 +12420,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 +12506,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 +12514,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 +12576,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 +12595,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 +12625,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; }