X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=71aab9a62cb17f5557c41e8933796f4acc6bd28b;hb=5e616edfe5f101927d2ff3f7a14d2c65897de3cc;hp=7b3017e95a7f2864f62b877f913e4bebceccb933;hpb=945d51a5966241e4964a2b72058b6295cbc4a688;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 7b3017e9..71aab9a6 100644 --- a/src/game.c +++ b/src/game.c @@ -169,9 +169,10 @@ static void KillHeroUnlessProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); +static boolean CheckTriggeredElementSideChange(int, int, int, int, int); static boolean CheckTriggeredElementChange(int, int, int, int); +static boolean CheckElementSideChange(int, int, int, int, int, int); static boolean CheckElementChange(int, int, int, int); -static void ChangeElementNow(int, int, int); static void PlaySoundLevel(int, int, int); static void PlaySoundLevelNearest(int, int, int); @@ -216,7 +217,7 @@ struct ChangingElementInfo void (*post_change_function)(int x, int y); }; -static struct ChangingElementInfo changing_element_list[] = +static struct ChangingElementInfo change_delay_list[] = { { EL_NUT_BREAKING, @@ -242,6 +243,14 @@ static struct ChangingElementInfo changing_element_list[] = NULL, NULL }, + { + EL_EXIT_CLOSING, + EL_EXIT_CLOSED, + 29, + NULL, + NULL, + NULL + }, { EL_SWITCHGATE_OPENING, EL_SWITCHGATE_OPEN, @@ -415,14 +424,16 @@ collect_count_list[] = { EL_UNDEFINED, 0 }, }; -static boolean changing_element[MAX_NUM_ELEMENTS]; static unsigned long trigger_events[MAX_NUM_ELEMENTS]; -#define IS_AUTO_CHANGING(e) (changing_element[e]) +#define IS_AUTO_CHANGING(e) (element_info[e].change_events & \ + CH_EVENT_BIT(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)) +#define CE_PAGE(e, ce) (element_info[e].event_page[ce]) + void GetPlayerConfig() { @@ -647,10 +658,13 @@ static void InitField(int x, int y, boolean init_game) MovDir[x][y] = 1 << RND(4); break; +#if 0 case EL_SP_EMPTY: Feld[x][y] = EL_EMPTY; break; +#endif +#if 0 case EL_EM_KEY_1_FILE: Feld[x][y] = EL_EM_KEY_1; break; @@ -663,6 +677,7 @@ static void InitField(int x, int y, boolean init_game) case EL_EM_KEY_4_FILE: Feld[x][y] = EL_EM_KEY_4; break; +#endif case EL_CONVEYOR_BELT_1_SWITCH_LEFT: case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE: @@ -742,7 +757,7 @@ void DrawGameDoorValues() static void InitGameEngine() { - int i; + int i, j, k; /* set game engine from tape file when re-playing, else from level file */ game.engine_version = (tape.playing ? tape.engine_version : @@ -752,11 +767,11 @@ static void InitGameEngine() InitElementPropertiesEngine(game.engine_version); #if 0 - printf("level %d: level version == %06d\n", level_nr, level.game_version); - printf(" tape version == %06d [%s] [file: %06d]\n", - tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"), - tape.file_version); - printf(" => game.engine_version == %06d\n", game.engine_version); + printf("level %d: level version == %06d\n", level_nr, level.game_version); + printf(" tape version == %06d [%s] [file: %06d]\n", + tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"), + tape.file_version); + printf(" => game.engine_version == %06d\n", game.engine_version); #endif /* ---------- initialize player's initial move delay --------------------- */ @@ -773,78 +788,82 @@ static void InitGameEngine() /* ---------- initialize changing elements ------------------------------- */ /* initialize changing elements information */ - for (i=0; ichange = &ei->change_page[0]; if (!IS_CUSTOM_ELEMENT(i)) { - element_info[i].change.target_element = EL_EMPTY_SPACE; - element_info[i].change.delay_fixed = 0; - element_info[i].change.delay_random = 0; - element_info[i].change.delay_frames = 1; + ei->change->target_element = EL_EMPTY_SPACE; + ei->change->delay_fixed = 0; + ei->change->delay_random = 0; + ei->change->delay_frames = 1; } - changing_element[i] = FALSE; -#else - changing_element[i].base_element = EL_UNDEFINED; - changing_element[i].next_element = EL_UNDEFINED; - changing_element[i].change_delay = -1; - changing_element[i].pre_change_function = NULL; - changing_element[i].change_function = NULL; - changing_element[i].post_change_function = NULL; -#endif + ei->change_events = CE_BITMASK_DEFAULT; + for (j=0; j < NUM_CHANGE_EVENTS; j++) + { + ei->event_page_nr[j] = 0; + ei->event_page[j] = &ei->change_page[0]; + } } /* add changing elements from pre-defined list */ - for (i=0; changing_element_list[i].element != EL_UNDEFINED; i++) + for (i=0; change_delay_list[i].element != EL_UNDEFINED; i++) { - int element = changing_element_list[i].element; - struct ChangingElementInfo *ce = &changing_element_list[i]; - struct ElementChangeInfo *change = &element_info[element].change; + struct ChangingElementInfo *ch_delay = &change_delay_list[i]; + struct ElementInfo *ei = &element_info[ch_delay->element]; + + ei->change->target_element = ch_delay->target_element; + ei->change->delay_fixed = ch_delay->change_delay; + + ei->change->pre_change_function = ch_delay->pre_change_function; + 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); + } #if 1 - change->target_element = ce->target_element; - change->delay_fixed = ce->change_delay; - change->pre_change_function = ce->pre_change_function; - change->change_function = ce->change_function; - change->post_change_function = ce->post_change_function; + /* add change events from custom element configuration */ + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; - changing_element[element] = TRUE; -#else - changing_element[element].base_element = ce->base_element; - changing_element[element].next_element = ce->next_element; - changing_element[element].change_delay = ce->change_delay; - changing_element[element].pre_change_function = ce->pre_change_function; - changing_element[element].change_function = ce->change_function; - changing_element[element].post_change_function = ce->post_change_function; -#endif + for (j=0; j < ei->num_change_pages; j++) + { + if (!ei->change_page[j].can_change) + continue; + + 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))) + { + ei->change_events |= CH_EVENT_BIT(k); + ei->event_page_nr[k] = j; + ei->event_page[k] = &ei->change_page[j]; + } + } + } } - /* add changing elements from custom element configuration */ +#else + + /* add change events from custom element configuration */ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; -#if 0 - struct ElementChangeInfo *change = &element_info[element].change; -#endif /* only add custom elements that change after fixed/random frame delay */ - if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, CE_DELAY)) - continue; - -#if 1 - changing_element[element] = TRUE; -#else - changing_element[element].base_element = element; - changing_element[element].next_element = change->target_element; - changing_element[element].change_delay = (change->delay_fixed * - change->delay_frames); -#endif + if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY)) + element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY); } +#endif /* ---------- initialize trigger events ---------------------------------- */ @@ -852,11 +871,32 @@ static void InitGameEngine() for (i=0; inum_change_pages; j++) + { + if (!ei->change_page->can_change) + continue; + + if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION)) + { + int trigger_element = ei->change_page[j].trigger_element; + + trigger_events[trigger_element] |= ei->change_page[j].events; + } + } + } +#else /* add trigger events from element change event properties */ for (i=0; itrigger_element] |= + element_info[i].change->events; +#endif /* ---------- initialize push delay -------------------------------------- */ @@ -988,6 +1028,8 @@ void InitGame() player->is_digging = FALSE; player->is_collecting = FALSE; + player->show_envelope = 0; + player->move_delay = game.initial_move_delay; player->move_delay_value = game.initial_move_delay_value; @@ -1064,7 +1106,10 @@ void InitGame() JustStopped[x][y] = 0; Stop[x][y] = FALSE; Pushed[x][y] = FALSE; - Changing[x][y] = FALSE; + + Changed[x][y] = CE_BITMASK_DEFAULT; + ChangeEvent[x][y] = CE_BITMASK_DEFAULT; + ExplodePhase[x][y] = 0; ExplodeField[x][y] = EX_NO_EXPLOSION; @@ -1236,16 +1281,19 @@ void InitGame() if (CAN_CHANGE(element)) { - content = element_info[element].change.target_element; - is_player = ELEM_IS_PLAYER(content); - - if (is_player && (found_rating < 3 || element < found_element)) + for (i=0; i < element_info[element].num_change_pages; i++) { - start_x = x; - start_y = y; + content = element_info[element].change_page[i].target_element; + is_player = ELEM_IS_PLAYER(content); - found_rating = 3; - found_element = element; + if (is_player && (found_rating < 3 || element < found_element)) + { + start_x = x; + start_y = y; + + found_rating = 3; + found_element = element; + } } } @@ -1266,16 +1314,19 @@ void InitGame() if (!CAN_CHANGE(element)) continue; - content = element_info[element].change.content[xx][yy]; - is_player = ELEM_IS_PLAYER(content); - - if (is_player && (found_rating < 1 || element < found_element)) + for (i=0; i < element_info[element].num_change_pages; i++) { - start_x = x + xx - 1; - start_y = y + yy - 1; + content = element_info[element].change_page[i].content[xx][yy]; + is_player = ELEM_IS_PLAYER(content); - found_rating = 1; - found_element = element; + if (is_player && (found_rating < 1 || element < found_element)) + { + start_x = x + xx - 1; + start_y = y + yy - 1; + + found_rating = 1; + found_element = element; + } } } } @@ -1549,8 +1600,13 @@ void GameWon() if (local_player->MovPos) return; +#if 1 + if (tape.auto_play) /* tape might already be stopped here */ + tape.auto_play_level_solved = TRUE; +#else if (tape.playing && tape.auto_play) tape.auto_play_level_solved = TRUE; +#endif local_player->LevelSolved = FALSE; @@ -1609,6 +1665,14 @@ void GameWon() StopSound(SND_GAME_LEVELTIME_BONUS); } + /* close exit door after last player */ + if (Feld[ExitX][ExitY] == EL_EXIT_OPEN && AllPlayersGone) + { + Feld[ExitX][ExitY] = EL_EXIT_CLOSING; + + PlaySoundLevelElementAction(ExitX, ExitY, EL_EXIT_OPEN, ACTION_CLOSING); + } + /* Hero disappears */ DrawLevelField(ExitX, ExitY); BackToFront(); @@ -2248,6 +2312,24 @@ void Explode(int ex, int ey, int phase, int mode) ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); +#ifdef DEBUG + + /* activate this even in non-DEBUG version until cause for crash in + getGraphicAnimationFrame() (see below) is found and eliminated */ +#endif +#if 1 + + if (GfxElement[x][y] == EL_UNDEFINED) + { + printf("\n\n\n"); + printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y); + printf("Explode(): This should never happen!\n"); + printf("\n\n\n"); + + GfxElement[x][y] = EL_EMPTY; + } +#endif + if (phase == first_phase_after_start) { int element = Store2[x][y]; @@ -2293,6 +2375,8 @@ void Explode(int ex, int ey, int phase, int mode) InitMovDir(x, y); DrawLevelField(x, y); + TestIfElementTouchesCustomElement(x, y); + if (CAN_BE_CRUMBLED(element)) DrawLevelFieldCrumbledSandNeighbours(x, y); @@ -2865,24 +2949,12 @@ void Impact(int x, int y) PlaySoundLevel(x, y, SND_PEARL_BREAKING); return; } -#if 1 else if (impact && CheckElementChange(x, y, element, CE_IMPACT)) { PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT); return; } -#else - else if (impact && CAN_CHANGE(element) && - HAS_CHANGE_EVENT(element, CE_IMPACT)) - { - PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT); - - ChangeElementNow(x, y, element); - - return; - } -#endif if (impact && element == EL_AMOEBA_DROP) { @@ -3014,17 +3086,10 @@ void Impact(int x, int y) { ToggleLightSwitch(x, y + 1); } -#if 1 else { CheckElementChange(x, y + 1, smashed, CE_SMASHED); } -#else - else if (CAN_CHANGE(smashed) && HAS_CHANGE_EVENT(smashed, CE_SMASHED)) - { - ChangeElementNow(x, y + 1, smashed); - } -#endif } else { @@ -4357,6 +4422,14 @@ void ContinueMoving(int x, int y) /* copy element change control values to new field */ ChangeDelay[newx][newy] = ChangeDelay[x][y]; +#if 1 + Changed[newx][newy] = Changed[x][y]; + ChangeEvent[newx][newy] = ChangeEvent[x][y]; + + ChangeDelay[x][y] = 0; + Changed[x][y] = CE_BITMASK_DEFAULT; + ChangeEvent[x][y] = CE_BITMASK_DEFAULT; +#endif /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; @@ -4414,6 +4487,10 @@ void ContinueMoving(int x, int y) if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) CheckElementChange(newx, newy, element, CE_COLLISION); +#if 1 + TestIfElementTouchesCustomElement(x, y); /* for empty space */ +#endif + TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); } @@ -4955,6 +5032,9 @@ void CheckExit(int x, int y) return; } + if (AllPlayersGone) /* do not re-open exit door closed after last player */ + return; + Feld[x][y] = EL_EXIT_OPENING; PlaySoundLevelNearest(x, y, SND_CLASS_EXIT_OPENING); @@ -5314,7 +5394,7 @@ static void ChangeElementNowExt(int x, int y, int target_element) { /* check if element under player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ - if (IS_PLAYER(x, y) && + if (IS_PLAYER(x, y) && !PLAYER_PROTECTED(x, y) && IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element)) { Bang(x, y); @@ -5324,6 +5404,8 @@ static void ChangeElementNowExt(int x, int y, int target_element) RemoveField(x, y); Feld[x][y] = target_element; + Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ + ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); @@ -5344,30 +5426,32 @@ static void ChangeElementNowExt(int x, int y, int target_element) RelocatePlayer(x, y, target_element); } -static void ChangeElementNow(int x, int y, int element) +static boolean ChangeElementNow(int x, int y, int element, int page) { - struct ElementChangeInfo *change = &element_info[element].change; + struct ElementChangeInfo *change = &element_info[element].change_page[page]; -#if 0 - if (element >= EL_CUSTOM_START + 17 && element <= EL_CUSTOM_START + 39) - printf("::: changing... [%d]\n", FrameCounter); -#endif + /* 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); + /* do not change already changed elements with same change event */ #if 0 - /* prevent CheckTriggeredElementChange() from looping */ - Changing[x][y] = TRUE; + if (Changed[x][y] & ChangeEvent[x][y]) + return FALSE; +#else + if (Changed[x][y]) + return FALSE; #endif - CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING); + Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ -#if 0 - Changing[x][y] = FALSE; -#endif + CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING); if (change->explode) { Bang(x, y); - return; + + return TRUE; } if (change->use_content) @@ -5425,7 +5509,7 @@ static void ChangeElementNow(int x, int y, int element) if (change->only_complete && change->use_random_change && RND(100) < change->random) - return; + return FALSE; for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++) { @@ -5442,9 +5526,9 @@ static void ChangeElementNow(int x, int y, int element) something_has_changed = TRUE; - /* for symmetry reasons, stop newly created border elements */ + /* for symmetry reasons, freeze newly created border elements */ if (ex != x || ey != y) - Stop[ex][ey] = TRUE; + Stop[ex][ey] = TRUE; /* no more moving in this frame */ } } @@ -5458,44 +5542,35 @@ static void ChangeElementNow(int x, int y, int element) PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); } + + return TRUE; } -static void ChangeElement(int x, int y) +static void ChangeElement(int x, int y, int page) { -#if 1 int element = MovingOrBlocked2Element(x, y); -#else - int element = Feld[x][y]; + struct ElementChangeInfo *change = &element_info[element].change_page[page]; + +#ifdef DEBUG + if (!CAN_CHANGE(element)) + { + printf("\n\n\n"); + printf("ChangeElement(): element = %d\n", element); + printf("Explode(): This should never happen!\n"); + printf("\n\n\n"); + } #endif - struct ElementChangeInfo *change = &element_info[element].change; if (ChangeDelay[x][y] == 0) /* initialize element change */ { -#if 1 ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames + RND(change->delay_random * change->delay_frames)) + 1; -#else - ChangeDelay[x][y] = changing_element[element].change_delay + 1; - - if (IS_CUSTOM_ELEMENT(element) && HAS_CHANGE_EVENT(element, CE_DELAY)) - { - int max_random_delay = element_info[element].change.delay_random; - int delay_frames = element_info[element].change.delay_frames; - - ChangeDelay[x][y] += RND(max_random_delay * delay_frames); - } -#endif ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); -#if 1 if (change->pre_change_function) change->pre_change_function(x, y); -#else - if (changing_element[element].pre_change_function) - changing_element[element].pre_change_function(x, y); -#endif } ChangeDelay[x][y]--; @@ -5507,20 +5582,11 @@ static void ChangeElement(int x, int y) if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); -#if 1 if (change->change_function) change->change_function(x, y); -#else - if (changing_element[element].change_function) - changing_element[element].change_function(x, y); -#endif } else /* finish element change */ { -#if 0 - int next_element = changing_element[element].next_element; -#endif - if (IS_MOVING(x, y)) /* never change a running system ;-) */ { ChangeDelay[x][y] = 1; /* try change after next move step */ @@ -5528,80 +5594,108 @@ static void ChangeElement(int x, int y) return; } -#if 1 - ChangeElementNow(x, y, element); - - if (change->post_change_function) - change->post_change_function(x, y); -#else - if (next_element != EL_UNDEFINED) - ChangeElementNow(x, y, next_element); - else - ChangeElementNow(x, y, element_info[element].change.target_element); - - if (changing_element[element].post_change_function) - changing_element[element].post_change_function(x, y); -#endif + if (ChangeElementNow(x, y, element, page)) + { + if (change->post_change_function) + change->post_change_function(x, y); + } } } -static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, - int trigger_event) +static boolean CheckTriggeredElementSideChange(int lx, int ly, + int trigger_element, + int trigger_side, + int trigger_event) { - int i, x, y; + int i, j, x, y; if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event))) return FALSE; - /* prevent this function from running into a loop */ - if (trigger_event == CE_OTHER_IS_CHANGING) - Changing[lx][ly] = TRUE; - - for (i=0; isides & trigger_side && + change->trigger_element == trigger_element) + { + change_element = TRUE; + page = j; + + break; + } + } + + if (!change_element) continue; for (y=0; yMovPos == 0) - { -#if 0 - printf("Trying... Player frame reset\n"); -#endif - InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir); - } if (player->MovPos == 0) /* needed for tape.playing */ player->is_moving = FALSE; @@ -5795,6 +5883,9 @@ void GameActions() for (y=0; y 0) JustStopped[x][y]--; @@ -5803,7 +5894,7 @@ void GameActions() #if 1 /* reset finished pushing action (not done in ContinueMoving() to allow - continous pushing animation for elements without push delay) */ + continous pushing animation for elements with zero push delay) */ if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y)) { ResetGfxAnimation(x, y); @@ -5871,7 +5962,7 @@ void GameActions() /* this may take place after moving, so 'element' may have changed */ if (IS_CHANGING(x, y)) { - ChangeElement(x, y); + ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]); element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]); } @@ -6207,6 +6298,15 @@ void GameActions() stored_player[i].StepFrame += move_frames; } #endif + +#if 1 + if (local_player->show_envelope != 0 && local_player->MovPos == 0) + { + ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); + + local_player->show_envelope = 0; + } +#endif } static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) @@ -6317,8 +6417,22 @@ static void CheckGravityMovement(struct PlayerInfo *player) boolean MoveFigureOneStep(struct PlayerInfo *player, int dx, int dy, int real_dx, int real_dy) { + static int change_sides[4][2] = + { + /* enter side leave side */ + { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */ + { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */ + { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */ + { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */ + }; + int move_direction = (dx == -1 ? MV_LEFT : + dx == +1 ? MV_RIGHT : + dy == -1 ? MV_UP : + dy == +1 ? MV_DOWN : MV_NO_MOVING); + int enter_side = change_sides[MV_DIR_BIT(move_direction)][0]; + int leave_side = change_sides[MV_DIR_BIT(move_direction)][1]; int jx = player->jx, jy = player->jy; - int new_jx = jx+dx, new_jy = jy+dy; + int new_jx = jx + dx, new_jy = jy + dy; int element; int can_move; @@ -6370,15 +6484,33 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, StorePlayer[jx][jy] = 0; player->last_jx = jx; player->last_jy = jy; - jx = player->jx = new_jx; - jy = player->jy = new_jy; - StorePlayer[jx][jy] = player->element_nr; + player->jx = new_jx; + player->jy = new_jy; + StorePlayer[new_jx][new_jy] = player->element_nr; player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value); ScrollFigure(player, SCROLL_INIT); +#if 1 + if (IS_CUSTOM_ELEMENT(Feld[jx][jy])) + { + CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy], leave_side, + CE_OTHER_GETS_LEFT); + CheckElementSideChange(jx, jy, Feld[jx][jy], leave_side, + CE_LEFT_BY_PLAYER, -1); + } + + if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy])) + { + CheckTriggeredElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy], + enter_side, CE_OTHER_GETS_ENTERED); + CheckElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy], enter_side, + CE_ENTERED_BY_PLAYER, -1); + } +#endif + return MF_MOVING; } @@ -6598,7 +6730,7 @@ void ScrollFigure(struct PlayerInfo *player, int mode) DrawPlayer(player); /* needed here only to cleanup last field */ #endif - if (player->MovPos == 0) + if (player->MovPos == 0) /* player reached destination field */ { if (IS_PASSABLE(Feld[last_jx][last_jy])) { @@ -6659,7 +6791,9 @@ void ScrollScreen(struct PlayerInfo *player, int mode) void TestIfPlayerTouchesCustomElement(int x, int y) { +#if 0 static boolean check_changing = FALSE; +#endif static int xy[4][2] = { { 0, -1 }, @@ -6669,10 +6803,12 @@ void TestIfPlayerTouchesCustomElement(int x, int y) }; int i; +#if 0 if (check_changing) /* prevent this function from running into a loop */ return; check_changing = TRUE; +#endif for (i=0; i<4; i++) { @@ -6696,12 +6832,16 @@ void TestIfPlayerTouchesCustomElement(int x, int y) } } +#if 0 check_changing = FALSE; +#endif } void TestIfElementTouchesCustomElement(int x, int y) { +#if 0 static boolean check_changing = FALSE; +#endif static int xy[4][2] = { { 0, -1 }, @@ -6709,19 +6849,32 @@ void TestIfElementTouchesCustomElement(int x, int y) { +1, 0 }, { 0, +1 } }; + static int change_sides[4][2] = + { + /* center side border side */ + { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ + { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ + { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ + { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ + }; boolean change_center_element = FALSE; + int center_element_change_page = 0; int center_element = Feld[x][y]; - int i; + int i, j; +#if 0 if (check_changing) /* prevent this function from running into a loop */ return; check_changing = TRUE; +#endif for (i=0; i<4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; + int center_side = change_sides[i][0]; + int border_side = change_sides[i][1]; int border_element; if (!IN_LEV_FIELD(xx, yy)) @@ -6731,19 +6884,54 @@ void TestIfElementTouchesCustomElement(int x, int y) /* check for change of center element (but change it only once) */ if (IS_CUSTOM_ELEMENT(center_element) && - border_element == element_info[center_element].change.trigger_element) - change_center_element = TRUE; + HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) && + !change_center_element) + { + for (j=0; j < element_info[center_element].num_change_pages; j++) + { + struct ElementChangeInfo *change = + &element_info[center_element].change_page[j]; + + if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && + change->sides & border_side && + change->trigger_element == border_element) + { + change_center_element = TRUE; + center_element_change_page = j; + + break; + } + } + } /* check for change of border element */ if (IS_CUSTOM_ELEMENT(border_element) && - center_element == element_info[border_element].change.trigger_element) - CheckElementChange(xx, yy, border_element, CE_OTHER_IS_TOUCHING); + HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING)) + { + for (j=0; j < element_info[border_element].num_change_pages; j++) + { + struct ElementChangeInfo *change = + &element_info[border_element].change_page[j]; + + if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && + change->sides & center_side && + change->trigger_element == center_element) + { + CheckElementSideChange(xx, yy, border_element, CH_SIDE_ANY, + CE_OTHER_IS_TOUCHING, j); + break; + } + } + } } if (change_center_element) - CheckElementChange(x, y, center_element, CE_OTHER_IS_TOUCHING); + CheckElementSideChange(x, y, center_element, CH_SIDE_ANY, + CE_OTHER_IS_TOUCHING, center_element_change_page); +#if 0 check_changing = FALSE; +#endif } void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) @@ -7075,6 +7263,16 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player, int DigField(struct PlayerInfo *player, int x, int y, int real_dx, int real_dy, int mode) { +#if 0 + static int change_sides[4][2] = + { + /* enter side leave side */ + { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */ + { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */ + { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */ + { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */ + }; +#endif boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0)); int jx = player->jx, jy = player->jy; int dx = x - jx, dy = y - jy; @@ -7083,6 +7281,10 @@ int DigField(struct PlayerInfo *player, dx == +1 ? MV_RIGHT : dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NO_MOVING); +#if 0 + int enter_side = change_sides[MV_DIR_BIT(move_direction)][0]; + int leave_side = change_sides[MV_DIR_BIT(move_direction)][1]; +#endif int element; if (player->MovPos == 0) @@ -7431,6 +7633,10 @@ int DigField(struct PlayerInfo *player, PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING); + CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED); + + TestIfElementTouchesCustomElement(x, y); /* for empty space */ + break; } else if (IS_COLLECTIBLE(element)) @@ -7491,6 +7697,14 @@ int DigField(struct PlayerInfo *player, el2edimg(EL_KEY_1 + key_nr)); redraw_mask |= REDRAW_DOOR_1; } + else if (IS_ENVELOPE(element)) + { +#if 1 + player->show_envelope = element; +#else + ShowEnvelope(element - EL_ENVELOPE_1); +#endif + } else if (IS_DROPPABLE(element)) /* can be collected and dropped */ { int i; @@ -7518,6 +7732,8 @@ int DigField(struct PlayerInfo *player, CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED); + TestIfElementTouchesCustomElement(x, y); /* for empty space */ + break; } else if (IS_PUSHABLE(element)) @@ -7626,6 +7842,24 @@ int DigField(struct PlayerInfo *player, if (Feld[x][y] != element) /* really digged/collected something */ player->is_collecting = !player->is_digging; +#if 0 + if (IS_CUSTOM_ELEMENT(Feld[jx][jy])) + { + CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy], leave_side, + CE_OTHER_GETS_LEFT); + CheckElementSideChange(jx, jy, Feld[jx][jy], leave_side, + CE_LEFT_BY_PLAYER, -1); + } + + if (IS_CUSTOM_ELEMENT(Feld[x][y])) + { + CheckTriggeredElementSideChange(x, y, Feld[x][y], enter_side, + CE_OTHER_GETS_ENTERED); + CheckElementSideChange(x, y, Feld[x][y], enter_side, + CE_ENTERED_BY_PLAYER, -1); + } +#endif + return MF_MOVING; } @@ -7756,6 +7990,8 @@ boolean DropElement(struct PlayerInfo *player) CheckTriggeredElementChange(jx, jy, new_element, CE_OTHER_GETS_DROPPED); CheckElementChange(jx, jy, new_element, CE_DROPPED_BY_PLAYER); + + TestIfElementTouchesCustomElement(jx, jy); } else /* player is dropping a dyna bomb */ {