X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=05e65026508d942835b1e28bd9c464b7fa2d2e8c;hp=c7dc1009585d5f62aa1f9dbbaa497858ec7fafe9;hb=8f33ee4940b9c35bf4627b7ef1126d03748da646;hpb=66a22ebb170de96a59c015e49b15d95419fd87ae diff --git a/src/game.c b/src/game.c index c7dc1009..05e65026 100644 --- a/src/game.c +++ b/src/game.c @@ -144,6 +144,10 @@ Feld[x][y] == EL_EXIT_OPEN || \ Feld[x][y] == EL_ACID)) +#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \ + (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ + IS_FOOD_DARK_YAMYAM(Feld[x][y]))) + #define MOLE_CAN_ENTER_FIELD(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || (condition))) @@ -182,12 +186,14 @@ 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 PlaySoundLevel(int, int, int); -static void PlaySoundLevelNearest(int, int, int); -static void PlaySoundLevelAction(int, int, int); -static void PlaySoundLevelElementAction(int, int, int, int); -static void PlaySoundLevelActionIfLoop(int, int, int); -static void StopSoundLevelActionIfLoop(int, int, int); +static void PlayLevelSound(int, int, int); +static void PlayLevelSoundNearest(int, int, int); +static void PlayLevelSoundAction(int, int, int); +static void PlayLevelSoundElementAction(int, int, int, int); +static void PlayLevelSoundElementActionIfLoop(int, int, int, int); +static void PlayLevelSoundActionIfLoop(int, int, int); +static void StopLevelSoundActionIfLoop(int, int, int); +static void PlayLevelMusic(); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); @@ -754,8 +760,8 @@ void DrawGameDoorValues() { int i, j; - for (i=0; ichange_events = CE_BITMASK_DEFAULT; - for (j=0; j < NUM_CHANGE_EVENTS; j++) + for (j = 0; j < NUM_CHANGE_EVENTS; j++) { ei->event_page_nr[j] = 0; ei->event_page[j] = &ei->change_page[0]; @@ -842,7 +848,7 @@ static void InitGameEngine() } /* add changing elements from pre-defined list */ - for (i=0; change_delay_list[i].element != EL_UNDEFINED; i++) + for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++) { struct ChangingElementInfo *ch_delay = &change_delay_list[i]; struct ElementInfo *ei = &element_info[ch_delay->element]; @@ -859,16 +865,16 @@ static void InitGameEngine() #if 1 /* add change events from custom element configuration */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; - for (j=0; j < ei->num_change_pages; j++) + 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++) + 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) && @@ -885,7 +891,7 @@ static void InitGameEngine() #else /* add change events from custom element configuration */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -898,16 +904,16 @@ static void InitGameEngine() /* ---------- initialize trigger events ---------------------------------- */ /* initialize trigger events information */ - for (i=0; inum_change_pages; j++) + for (j = 0; j < ei->num_change_pages; j++) { if (!ei->change_page[j].can_change) continue; @@ -922,7 +928,7 @@ static void InitGameEngine() } #else /* add trigger events from element change event properties */ - for (i=0; itrigger_element] |= element_info[i].change->events; @@ -931,7 +937,7 @@ static void InitGameEngine() /* ---------- initialize push delay -------------------------------------- */ /* initialize push delay values to default */ - for (i=0; ilights_still_needed = 0; player->friends_still_needed = 0; - for (j=0; j<4; j++) + for (j = 0; j < 4; j++) player->key[j] = FALSE; player->dynabomb_count = 0; @@ -1048,6 +1054,8 @@ void InitGame() player->actual_frame_counter = 0; + player->step_counter = 0; + player->last_move_dir = MV_NO_MOVING; player->is_waiting = FALSE; @@ -1058,6 +1066,53 @@ void InitGame() player->is_pushing = FALSE; player->is_switching = FALSE; + player->is_bored = FALSE; + player->is_sleeping = FALSE; + + player->frame_counter_bored = -1; + player->frame_counter_sleeping = -1; + + player->anim_delay_counter = 0; + player->post_delay_counter = 0; + + player->action_waiting = ACTION_DEFAULT; + player->last_action_waiting = ACTION_DEFAULT; + player->special_action_bored = ACTION_DEFAULT; + player->special_action_sleeping = ACTION_DEFAULT; + + player->num_special_action_bored = 0; + player->num_special_action_sleeping = 0; + + /* determine number of special actions for bored and sleeping animation */ + for (j = ACTION_BORING_1; j <= ACTION_BORING_LAST; j++) + { + boolean found = FALSE; + + for (k = 0; k < NUM_DIRECTIONS; k++) + if (el_act_dir2img(player->element_nr, j, k) != + el_act_dir2img(player->element_nr, ACTION_DEFAULT, k)) + found = TRUE; + + if (found) + player->num_special_action_bored++; + else + break; + } + for (j = ACTION_SLEEPING_1; j <= ACTION_SLEEPING_LAST; j++) + { + boolean found = FALSE; + + for (k = 0; k < NUM_DIRECTIONS; k++) + if (el_act_dir2img(player->element_nr, j, k) != + el_act_dir2img(player->element_nr, ACTION_DEFAULT, k)) + found = TRUE; + + if (found) + player->num_special_action_sleeping++; + else + break; + } + player->switch_x = -1; player->switch_y = -1; @@ -1119,18 +1174,18 @@ void InitGame() game.envelope_active = FALSE; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { game.belt_dir[i] = MV_NO_MOVING; game.belt_dir_nr[i] = 3; /* not moving, next moving left */ } - for (i=0; iconnected && !player->present) { - for (j=0; jjx, jy = some_player->jy; @@ -1216,7 +1274,7 @@ void InitGame() { /* when playing a tape, eliminate all players who do not participate */ - for (i=0; iscore < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; - for (k=0; kscore > highscore[k].Score) { @@ -1788,14 +1851,14 @@ int NewHiScore() int m = MAX_SCORE_ENTRIES - 1; #ifdef ONE_PER_NAME - for (l=k; lk; l--) + for (l = m; l > k; l--) { strcpy(highscore[l].Name, highscore[l - 1].Name); highscore[l].Score = highscore[l - 1].Score; @@ -2050,14 +2113,14 @@ void CheckDynamite(int x, int y) if (MovDelay[x][y] != 0) { DrawDynamite(x, y); - PlaySoundLevelActionIfLoop(x, y, ACTION_ACTIVE); + PlayLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); return; } } #if 1 - StopSoundLevelActionIfLoop(x, y, ACTION_ACTIVE); + StopLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); #else if (Feld[x][y] == EL_DYNAMITE_ACTIVE || Feld[x][y] == EL_SP_DISK_RED_ACTIVE) @@ -2170,7 +2233,7 @@ void Explode(int ex, int ey, int phase, int mode) #endif if (mode == EX_NORMAL || mode == EX_CENTER) - PlaySoundLevelAction(ex, ey, ACTION_EXPLODING); + PlayLevelSoundAction(ex, ey, ACTION_EXPLODING); /* remove things displayed in background while burning dynamite */ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) @@ -2184,7 +2247,7 @@ void Explode(int ex, int ey, int phase, int mode) Feld[ex][ey] = center_element; } - for (y = ey - 1; y <= ey + 1; y++) for(x = ex - 1; x <= ex + 1; x++) + for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++) { int xx = x - ex + 1; int yy = y - ey + 1; @@ -2504,9 +2567,9 @@ void DynaExplode(int ex, int ey) Explode(ex, ey, EX_PHASE_START, EX_CENTER); - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { - for (j=1; j<=dynabomb_size; j++) + for (j = 1; j <= dynabomb_size; j++) { int x = ex + j * xy[i % 4][0]; int y = ey + j * xy[i % 4][1]; @@ -2555,12 +2618,12 @@ void Bang(int x, int y) #if 0 #if 1 - PlaySoundLevelAction(x, y, ACTION_EXPLODING); + PlayLevelSoundAction(x, y, ACTION_EXPLODING); #else if (game.emulation == EMU_SUPAPLEX) - PlaySoundLevel(x, y, SND_SP_ELEMENT_EXPLODING); + PlayLevelSound(x, y, SND_SP_ELEMENT_EXPLODING); else - PlaySoundLevel(x, y, SND_ELEMENT_EXPLODING); + PlayLevelSound(x, y, SND_ELEMENT_EXPLODING); #endif #endif @@ -2618,7 +2681,7 @@ void SplashAcid(int x, int y) if (element != EL_ACID_SPLASH_LEFT && element != EL_ACID_SPLASH_RIGHT) { - PlaySoundLevel(x, y, SND_ACID_SPLASHING); + PlayLevelSound(x, y, SND_ACID_SPLASHING); if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) && (!IN_LEV_FIELD(x-1, y-1) || @@ -2652,11 +2715,11 @@ static void InitBeltMovement() int x, y, i, j; /* set frame order for belt animation graphic according to belt direction */ - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int belt_nr = i; - for (j=0; j<3; j++) + for (j = 0; j < 3; j++) { int element = belt_base_active_element[belt_nr] + j; int graphic = el2img(element); @@ -2668,13 +2731,13 @@ static void InitBeltMovement() } } - for(y=0; y rnd_value / 8) MovDir[x][y] = old_move_dir; else if (can_turn_left && can_turn_right) @@ -3402,8 +3472,25 @@ inline static void TurnRoundExt(int x, int y) xx = x + move_xy[MovDir[x][y]].x; yy = y + move_xy[MovDir[x][y]].y; +#if 0 + if (FrameCounter < 1 && x == 0 && y == 29) + printf(":3: %d/%d: %d (%d/%d: %d) [%d]\n", x, y, MovDir[x][y], + xx, yy, Feld[xx][yy], + FrameCounter); +#endif + +#if 1 + if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy)) + MovDir[x][y] = old_move_dir; +#else if (!IS_FREE(xx, yy)) MovDir[x][y] = old_move_dir; +#endif + +#if 0 + if (FrameCounter < 1 && x == 0 && y == 29) + printf(":4: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter); +#endif MovDelay[x][y] = 0; } @@ -3463,7 +3550,7 @@ inline static void TurnRoundExt(int x, int y) { int i; - for (i=0; ijx, jy = player->jy; @@ -3497,7 +3584,7 @@ inline static void TurnRoundExt(int x, int y) { 0, +1 } }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int ex = x + xy[i % 4][0]; int ey = y + xy[i % 4][1]; @@ -3593,16 +3680,16 @@ inline static void TurnRoundExt(int x, int y) } } } - else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS || - element_info[element].move_pattern == MV_TURNING_LEFT || - element_info[element].move_pattern == MV_TURNING_RIGHT) + else if (move_pattern == MV_ALL_DIRECTIONS || + move_pattern == MV_TURNING_LEFT || + move_pattern == MV_TURNING_RIGHT) { boolean can_turn_left = ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); - if (element_info[element].move_pattern == MV_TURNING_LEFT) + if (move_pattern == MV_TURNING_LEFT) MovDir[x][y] = left_dir; - else if (element_info[element].move_pattern == MV_TURNING_RIGHT) + else if (move_pattern == MV_TURNING_RIGHT) MovDir[x][y] = right_dir; else if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); @@ -3615,24 +3702,24 @@ inline static void TurnRoundExt(int x, int y) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_HORIZONTAL || - element_info[element].move_pattern == MV_VERTICAL) + else if (move_pattern == MV_HORIZONTAL || + move_pattern == MV_VERTICAL) { - if (element_info[element].move_pattern & old_move_dir) + if (move_pattern & old_move_dir) MovDir[x][y] = back_dir; - else if (element_info[element].move_pattern == MV_HORIZONTAL) + else if (move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); - else if (element_info[element].move_pattern == MV_VERTICAL) + else if (move_pattern == MV_VERTICAL) MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN); MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern & MV_ANY_DIRECTION) + else if (move_pattern & MV_ANY_DIRECTION) { - MovDir[x][y] = element_info[element].move_pattern; + MovDir[x][y] = move_pattern; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_ALONG_LEFT_SIDE) + else if (move_pattern == MV_ALONG_LEFT_SIDE) { if (ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y)) MovDir[x][y] = left_dir; @@ -3642,7 +3729,7 @@ inline static void TurnRoundExt(int x, int y) if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE) + else if (move_pattern == MV_ALONG_RIGHT_SIDE) { if (ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y)) MovDir[x][y] = right_dir; @@ -3652,13 +3739,12 @@ inline static void TurnRoundExt(int x, int y) if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_TOWARDS_PLAYER || - element_info[element].move_pattern == MV_AWAY_FROM_PLAYER) + else if (move_pattern == MV_TOWARDS_PLAYER || + move_pattern == MV_AWAY_FROM_PLAYER) { int attr_x = -1, attr_y = -1; int newx, newy; - boolean move_away = - (element_info[element].move_pattern == MV_AWAY_FROM_PLAYER); + boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER); if (AllPlayersGone) { @@ -3669,7 +3755,7 @@ inline static void TurnRoundExt(int x, int y) { int i; - for (i=0; ijx, jy = player->jy; @@ -3720,13 +3806,84 @@ inline static void TurnRoundExt(int x, int y) MovDir[x][y] = old_move_dir; } } - else if (element_info[element].move_pattern == MV_WHEN_PUSHED) + else if (move_pattern == MV_WHEN_PUSHED) { if (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y)) MovDir[x][y] = MV_NO_MOVING; MovDelay[x][y] = 0; } + else if (move_pattern & MV_MAZE_RUNNER_STYLE || + element == EL_MAZE_RUNNER) + { + static int test_xy[7][2] = + { + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 }, + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + }; + static int test_dir[7] = + { + MV_UP, + MV_LEFT, + MV_RIGHT, + MV_DOWN, + MV_UP, + MV_LEFT, + MV_RIGHT, + }; + boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER); + int move_preference = -1000000; /* start with very low preference */ + int new_move_dir = MV_NO_MOVING; + int start_test = RND(4); + int i; + + for (i = 0; i < 4; i++) + { + int move_dir = test_dir[start_test + i]; + int move_dir_preference; + + xx = x + test_xy[start_test + i][0]; + yy = y + test_xy[start_test + i][1]; + + if (hunter_mode && IN_LEV_FIELD(xx, yy) && + (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING)) + { + new_move_dir = move_dir; + + break; + } + + if (!MAZE_RUNNER_CAN_ENTER_FIELD(xx, yy)) + continue; + + move_dir_preference = -1 * RunnerVisit[xx][yy]; + if (hunter_mode && PlayerVisit[xx][yy] > 0) + move_dir_preference = PlayerVisit[xx][yy]; + + if (move_dir_preference > move_preference) + { + /* prefer field that has not been visited for the longest time */ + move_preference = move_dir_preference; + new_move_dir = move_dir; + } + else if (move_dir_preference == move_preference && + move_dir == old_move_dir) + { + /* prefer last direction when all directions are preferred equally */ + move_preference = move_dir_preference; + new_move_dir = move_dir; + } + } + + MovDir[x][y] = new_move_dir; + if (old_move_dir != new_move_dir) + MovDelay[x][y] = 9; + } } static void TurnRound(int x, int y) @@ -3759,7 +3916,7 @@ static boolean JustBeingPushed(int x, int y) { int i; - for (i=0; ican_change && + change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_ACTIVE) && + change->sides & touched_side && + change->trigger_element == touched_element) + { + CheckElementSideChange(newx, newy, hitting_element, + CH_SIDE_ANY, CE_OTHER_IS_COLL_ACTIVE, i); + break; + } + } + } + + if (IS_CUSTOM_ELEMENT(touched_element) && + HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_IS_COLL_PASSIVE)) + { + for (i = 0; i < element_info[touched_element].num_change_pages; i++) + { + struct ElementChangeInfo *change = + &element_info[touched_element].change_page[i]; + + if (change->can_change && + change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_PASSIVE) && + change->sides & hitting_side && + change->trigger_element == hitting_element) + { + CheckElementSideChange(nextx, nexty, touched_element, + CH_SIDE_ANY, CE_OTHER_IS_COLL_PASSIVE, i); + break; + } + } + } + } + } +#endif + } TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); @@ -4696,7 +4968,7 @@ int AmoebeNachbarNr(int ax, int ay) { 0, +1 } }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int x = ax + xy[i][0]; int y = ay + xy[i][1]; @@ -4726,7 +4998,7 @@ void AmoebenVereinigen(int ax, int ay) if (new_group_nr == 0) return; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { x = ax + xy[i][0]; y = ay + xy[i][1]; @@ -4749,9 +5021,9 @@ void AmoebenVereinigen(int ax, int ay) AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr]; AmoebaCnt2[old_group_nr] = 0; - for (yy=0; yyrandom) return FALSE; - for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++) + for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++) { int ex = x + xx - 1; int ey = y + yy - 1; @@ -5721,14 +5993,14 @@ static boolean ChangeElementNow(int x, int y, int element, int page) } if (something_has_changed) - PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); + PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); } } else { ChangeElementNowExt(x, y, change->target_element); - PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); + PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); } return TRUE; @@ -5811,7 +6083,7 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly, if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event))) return FALSE; - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -5821,7 +6093,7 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly, if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) continue; - for (j=0; j < element_info[element].num_change_pages; j++) + for (j = 0; j < element_info[element].num_change_pages; j++) { struct ElementChangeInfo *change = &element_info[element].change_page[j]; @@ -5848,7 +6120,7 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly, if (!change_element) continue; - for (y=0; yjx, jy = player->jy; + int element = player->element_nr; + int last_action = player->last_action_waiting; + int action = player->action_waiting; + + if (player->is_waiting) + { + if (action != last_action) + PlayLevelSoundElementAction(jx, jy, element, action); + else + PlayLevelSoundElementActionIfLoop(jx, jy, element, action); + } + else + { + if (action != last_action) + StopSound(element_info[element].sound[last_action]); + + if (last_action == ACTION_SLEEPING) + PlayLevelSoundElementAction(jx, jy, element, ACTION_AWAKENING); + } +} + +static void PlayAllPlayersSound() +{ + int i; + + for (i = 0; i < MAX_PLAYERS; i++) + if (stored_player[i].active) + PlayPlayerSound(&stored_player[i]); +} + +static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) +{ + boolean last_waiting = player->is_waiting; + int move_dir = player->MovDir; + + player->last_action_waiting = player->action_waiting; + + if (is_waiting) + { + if (!last_waiting) /* not waiting -> waiting */ + { + player->is_waiting = TRUE; + + player->frame_counter_bored = + FrameCounter + + game.player_boring_delay_fixed + + SimpleRND(game.player_boring_delay_random); + player->frame_counter_sleeping = + FrameCounter + + game.player_sleeping_delay_fixed + + SimpleRND(game.player_sleeping_delay_random); + + InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir); + } + + if (game.player_sleeping_delay_fixed + + game.player_sleeping_delay_random > 0 && + player->anim_delay_counter == 0 && + player->post_delay_counter == 0 && + FrameCounter >= player->frame_counter_sleeping) + player->is_sleeping = TRUE; + else if (game.player_boring_delay_fixed + + game.player_boring_delay_random > 0 && + FrameCounter >= player->frame_counter_bored) + player->is_bored = TRUE; + + player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING : + player->is_bored ? ACTION_BORING : + ACTION_WAITING); + + if (player->is_sleeping) + { + if (player->num_special_action_sleeping > 0) + { + if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) + { + int last_special_action = player->special_action_sleeping; + int num_special_action = player->num_special_action_sleeping; + int special_action = + (last_special_action == ACTION_DEFAULT ? ACTION_SLEEPING_1 : + last_special_action == ACTION_SLEEPING ? ACTION_SLEEPING : + last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ? + last_special_action + 1 : ACTION_SLEEPING); + int special_graphic = + el_act_dir2img(player->element_nr, special_action, move_dir); + + player->anim_delay_counter = + graphic_info[special_graphic].anim_delay_fixed + + SimpleRND(graphic_info[special_graphic].anim_delay_random); + player->post_delay_counter = + graphic_info[special_graphic].post_delay_fixed + + SimpleRND(graphic_info[special_graphic].post_delay_random); + + player->special_action_sleeping = special_action; + } + + if (player->anim_delay_counter > 0) + { + player->action_waiting = player->special_action_sleeping; + player->anim_delay_counter--; + } + else if (player->post_delay_counter > 0) + { + player->post_delay_counter--; + } + } + } + else if (player->is_bored) + { + if (player->num_special_action_bored > 0) + { + if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) + { + int special_action = + ACTION_BORING_1 + SimpleRND(player->num_special_action_bored); + int special_graphic = + el_act_dir2img(player->element_nr, special_action, move_dir); + + player->anim_delay_counter = + graphic_info[special_graphic].anim_delay_fixed + + SimpleRND(graphic_info[special_graphic].anim_delay_random); + player->post_delay_counter = + graphic_info[special_graphic].post_delay_fixed + + SimpleRND(graphic_info[special_graphic].post_delay_random); + + player->special_action_bored = special_action; + } + + if (player->anim_delay_counter > 0) + { + player->action_waiting = player->special_action_bored; + player->anim_delay_counter--; + } + else if (player->post_delay_counter > 0) + { + player->post_delay_counter--; + } + } + } + } + else if (last_waiting) /* waiting -> not waiting */ + { + player->is_waiting = FALSE; + player->is_bored = FALSE; + player->is_sleeping = FALSE; + + player->frame_counter_bored = -1; + player->frame_counter_sleeping = -1; + + player->anim_delay_counter = 0; + player->post_delay_counter = 0; + + player->action_waiting = ACTION_DEFAULT; + + player->special_action_bored = ACTION_DEFAULT; + player->special_action_sleeping = ACTION_DEFAULT; + } +} + +#if 1 +static byte PlayerActions(struct PlayerInfo *player, byte player_action) +{ +#if 0 + static byte stored_player_action[MAX_PLAYERS]; + static int num_stored_actions = 0; +#endif + boolean moved = FALSE, snapped = FALSE, dropped = FALSE; + int left = player_action & JOY_LEFT; + int right = player_action & JOY_RIGHT; + int up = player_action & JOY_UP; + int down = player_action & JOY_DOWN; + int button1 = player_action & JOY_BUTTON_1; + int button2 = player_action & JOY_BUTTON_2; + int dx = (left ? -1 : right ? 1 : 0); + int dy = (up ? -1 : down ? 1 : 0); + +#if 0 + stored_player_action[player->index_nr] = 0; + num_stored_actions++; +#endif + +#if 0 + printf("::: player %d [%d]\n", player->index_nr, FrameCounter); +#endif + + if (!player->active || tape.pausing) + return 0; + + if (player_action) + { +#if 0 + printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter); +#endif + + if (button1) + snapped = SnapField(player, dx, dy); + else + { + if (button2) + dropped = DropElement(player); + + moved = MovePlayer(player, dx, dy); + } + + if (tape.single_step && tape.recording && !tape.pausing) + { + if (button1 || (dropped && !moved)) + { + TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); + SnapField(player, 0, 0); /* stop snapping */ + } + } + + SetPlayerWaiting(player, FALSE); + +#if 1 + return player_action; +#else + stored_player_action[player->index_nr] = player_action; +#endif + } + else + { +#if 0 + printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter); +#endif + + /* no actions for this player (no input at player's configured device) */ + + DigField(player, 0, 0, 0, 0, DF_NO_PUSH); + SnapField(player, 0, 0); + CheckGravityMovement(player); + + if (player->MovPos == 0) + SetPlayerWaiting(player, TRUE); + + if (player->MovPos == 0) /* needed for tape.playing */ + player->is_moving = FALSE; + + return 0; + } + +#if 0 + if (tape.recording && num_stored_actions >= MAX_PLAYERS) + { + printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter); + + TapeRecordAction(stored_player_action); + num_stored_actions = 0; + } +#endif +} + +#else + static void PlayerActions(struct PlayerInfo *player, byte player_action) { static byte stored_player_action[MAX_PLAYERS]; @@ -5921,11 +6451,15 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) stored_player_action[player->index_nr] = 0; num_stored_actions++; + printf("::: player %d [%d]\n", player->index_nr, FrameCounter); + if (!player->active || tape.pausing) return; if (player_action) { + printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter); + if (button1) snapped = SnapField(player, dx, dy); else @@ -5949,6 +6483,8 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) } else { + printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter); + /* no actions for this player (no input at player's configured device) */ DigField(player, 0, 0, 0, 0, DF_NO_PUSH); @@ -5964,10 +6500,13 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) if (tape.recording && num_stored_actions >= MAX_PLAYERS) { + printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter); + TapeRecordAction(stored_player_action); num_stored_actions = 0; } } +#endif void GameActions() { @@ -5977,6 +6516,9 @@ void GameActions() int i, x, y, element, graphic; byte *recorded_player_action; byte summarized_player_action = 0; +#if 1 + byte tape_action[MAX_PLAYERS]; +#endif if (game_status != GAME_MODE_PLAYING) return; @@ -6021,9 +6563,13 @@ void GameActions() if (tape.pausing) return; +#if 0 + printf("::: getting new tape action [%d]\n", FrameCounter); +#endif + recorded_player_action = (tape.playing ? TapePlayAction() : NULL); - for (i=0; ieffective_action = summarized_player_action; - for (i=0; ijx; @@ -6089,7 +6644,7 @@ void GameActions() } #endif - for (y=0; y 0) @@ -6392,7 +6952,7 @@ void GameActions() game.magic_wall_time_left--; if (!game.magic_wall_time_left) { - for (y=0; yshield_deadly_time_left) - PlaySoundLevel(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE); + PlayLevelSound(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE); else if (player->shield_normal_time_left) - PlaySoundLevel(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE); + PlayLevelSound(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE); } } @@ -6449,7 +7009,7 @@ void GameActions() TimeFrames = 0; TimePlayed++; - for (i=0; iMovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value); + player->step_counter++; + + PlayerVisit[jx][jy] = FrameCounter; + ScrollPlayer(player, SCROLL_INIT); #if 0 @@ -7107,7 +7672,7 @@ void TestIfPlayerTouchesCustomElement(int x, int y) int center_element = Feld[x][y]; /* should always be non-moving! */ int i; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; @@ -7165,7 +7730,7 @@ void TestIfElementTouchesCustomElement(int x, int y) }; static int change_sides[4][2] = { - /* center side border side */ + /* 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 */ @@ -7183,7 +7748,7 @@ void TestIfElementTouchesCustomElement(int x, int y) int center_element = Feld[x][y]; /* should always be non-moving! */ int i, j; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; @@ -7208,7 +7773,7 @@ void TestIfElementTouchesCustomElement(int x, int y) 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++) + for (j = 0; j < element_info[center_element].num_change_pages; j++) { struct ElementChangeInfo *change = &element_info[center_element].change_page[j]; @@ -7230,7 +7795,7 @@ void TestIfElementTouchesCustomElement(int x, int y) if (IS_CUSTOM_ELEMENT(border_element) && HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING)) { - for (j=0; j < element_info[border_element].num_change_pages; j++) + for (j = 0; j < element_info[border_element].num_change_pages; j++) { struct ElementChangeInfo *change = &element_info[border_element].change_page[j]; @@ -7271,7 +7836,7 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) MV_DOWN }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int test_x, test_y, test_move_dir, test_element; @@ -7346,7 +7911,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) if (bad_element == EL_EXPLOSION) /* skip just exploding bad things */ return; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int test_x, test_y, test_move_dir, test_element; @@ -7450,7 +8015,7 @@ void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y) { 0, +1 } }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int x, y, element; @@ -7505,11 +8070,11 @@ void BuryHero(struct PlayerInfo *player) return; #if 1 - PlaySoundLevelElementAction(jx, jy, player->element_nr, ACTION_DYING); + PlayLevelSoundElementAction(jx, jy, player->element_nr, ACTION_DYING); #else - PlaySoundLevel(jx, jy, SND_CLASS_PLAYER_DYING); + PlayLevelSound(jx, jy, SND_CLASS_PLAYER_DYING); #endif - PlaySoundLevel(jx, jy, SND_GAME_LOSING); + PlayLevelSound(jx, jy, SND_GAME_LOSING); player->GameOver = TRUE; RemoveHero(player); @@ -7526,7 +8091,7 @@ void RemoveHero(struct PlayerInfo *player) if (!ExplodeField[jx][jy]) StorePlayer[jx][jy] = 0; - for (i=0; iprogrammed_action = move_direction; DOUBLE_PLAYER_SPEED(player); - PlaySoundLevel(x, y, SND_CLASS_SP_PORT_PASSING); + PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING); break; case EL_TUBE_ANY: @@ -7746,7 +8311,7 @@ int DigField(struct PlayerInfo *player, if (!(tube_enter_directions[i][1] & move_direction)) return MF_NO_ACTION; /* tube has no opening in this direction */ - PlaySoundLevel(x, y, SND_CLASS_TUBE_WALKING); + PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING); } break; @@ -7779,9 +8344,9 @@ int DigField(struct PlayerInfo *player, /* play sound from background or player, whatever is available */ if (element_info[element].sound[sound_action] != SND_UNDEFINED) - PlaySoundLevelElementAction(x, y, element, sound_action); + PlayLevelSoundElementAction(x, y, element, sound_action); else - PlaySoundLevelElementAction(x, y, player->element_nr, sound_action); + PlayLevelSoundElementAction(x, y, player->element_nr, sound_action); break; } @@ -7810,7 +8375,7 @@ int DigField(struct PlayerInfo *player, player->programmed_action = move_direction; DOUBLE_PLAYER_SPEED(player); - PlaySoundLevelAction(x, y, ACTION_PASSING); + PlayLevelSoundAction(x, y, ACTION_PASSING); break; } @@ -7829,7 +8394,7 @@ int DigField(struct PlayerInfo *player, player->is_digging = TRUE; } - PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING); + PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED); @@ -7908,7 +8473,7 @@ int DigField(struct PlayerInfo *player, { int i; - for (i=0; i < element_info[element].collect_count; i++) + for (i = 0; i < element_info[element].collect_count; i++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; @@ -7927,7 +8492,7 @@ int DigField(struct PlayerInfo *player, } RaiseScoreElement(element); - PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING); + PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED); @@ -8051,23 +8616,23 @@ int DigField(struct PlayerInfo *player, Feld[x][y] = EL_SOKOBAN_OBJECT; if (Back[x][y] == Back[nextx][nexty]) - PlaySoundLevelAction(x, y, ACTION_PUSHING); + PlayLevelSoundAction(x, y, ACTION_PUSHING); else if (Back[x][y] != 0) - PlaySoundLevelElementAction(x, y, EL_SOKOBAN_FIELD_FULL, + PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL, ACTION_EMPTYING); else - PlaySoundLevelElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, + PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, ACTION_FILLING); if (local_player->sokobanfields_still_needed == 0 && game.emulation == EMU_SOKOBAN) { player->LevelSolved = player->GameOver = TRUE; - PlaySoundLevel(x, y, SND_GAME_SOKOBAN_SOLVING); + PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); } } else - PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); + PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); InitMovingField(x, y, move_direction); GfxAction[x][y] = ACTION_PUSHING; @@ -8101,7 +8666,7 @@ int DigField(struct PlayerInfo *player, player->switch_x = x; player->switch_y = y; - PlaySoundLevelElementAction(x, y, element, ACTION_ACTIVATING); + PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); if (element == EL_ROBOT_WHEEL) { @@ -8115,7 +8680,7 @@ int DigField(struct PlayerInfo *player, { int xx, yy; - for (yy=0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++) + for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++) { if (Feld[xx][yy] == EL_SP_DISK_YELLOW) Bang(xx, yy); @@ -8138,7 +8703,7 @@ int DigField(struct PlayerInfo *player, ToggleLightSwitch(x, y); #if 0 - PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ? + PlayLevelSound(x, y, element == EL_LIGHT_SWITCH ? SND_LIGHT_SWITCH_ACTIVATING : SND_LIGHT_SWITCH_DEACTIVATING); #endif @@ -8319,7 +8884,7 @@ boolean DropElement(struct PlayerInfo *player) if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0); - PlaySoundLevelAction(jx, jy, ACTION_DROPPING); + PlayLevelSoundAction(jx, jy, ACTION_DROPPING); CheckTriggeredElementChange(jx, jy, new_element, CE_OTHER_GETS_DROPPED); CheckElementChange(jx, jy, new_element, CE_DROPPED_BY_PLAYER); @@ -8336,7 +8901,7 @@ boolean DropElement(struct PlayerInfo *player) if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0); - PlaySoundLevelAction(jx, jy, ACTION_DROPPING); + PlayLevelSoundAction(jx, jy, ACTION_DROPPING); } return TRUE; @@ -8349,21 +8914,18 @@ boolean DropElement(struct PlayerInfo *player) static int *loop_sound_frame = NULL; static int *loop_sound_volume = NULL; -void InitPlaySoundLevel() +void InitPlayLevelSound() { int num_sounds = getSoundListSize(); - if (loop_sound_frame != NULL) - free(loop_sound_frame); - - if (loop_sound_volume != NULL) - free(loop_sound_volume); + checked_free(loop_sound_frame); + checked_free(loop_sound_volume); - loop_sound_frame = checked_calloc(num_sounds * sizeof(int)); + loop_sound_frame = checked_calloc(num_sounds * sizeof(int)); loop_sound_volume = checked_calloc(num_sounds * sizeof(int)); } -static void PlaySoundLevel(int x, int y, int nr) +static void PlayLevelSound(int x, int y, int nr) { int sx = SCREENX(x), sy = SCREENY(y); int volume, stereo_position; @@ -8408,42 +8970,59 @@ static void PlaySoundLevel(int x, int y, int nr) PlaySoundExt(nr, volume, stereo_position, type); } -static void PlaySoundLevelNearest(int x, int y, int sound_action) +static void PlayLevelSoundNearest(int x, int y, int sound_action) { - PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) : + PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) : x > LEVELX(BX2) ? LEVELX(BX2) : x, y < LEVELY(BY1) ? LEVELY(BY1) : y > LEVELY(BY2) ? LEVELY(BY2) : y, sound_action); } -static void PlaySoundLevelAction(int x, int y, int action) +static void PlayLevelSoundAction(int x, int y, int action) { - PlaySoundLevelElementAction(x, y, Feld[x][y], action); + PlayLevelSoundElementAction(x, y, Feld[x][y], action); } -static void PlaySoundLevelElementAction(int x, int y, int element, int action) +static void PlayLevelSoundElementAction(int x, int y, int element, int action) { int sound_effect = element_info[element].sound[action]; if (sound_effect != SND_UNDEFINED) - PlaySoundLevel(x, y, sound_effect); + PlayLevelSound(x, y, sound_effect); } -static void PlaySoundLevelActionIfLoop(int x, int y, int action) +static void PlayLevelSoundElementActionIfLoop(int x, int y, int element, + int action) +{ + int sound_effect = element_info[element].sound[action]; + + if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) + PlayLevelSound(x, y, sound_effect); +} + +static void PlayLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[Feld[x][y]].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) - PlaySoundLevel(x, y, sound_effect); + PlayLevelSound(x, y, sound_effect); } -static void StopSoundLevelActionIfLoop(int x, int y, int action) +static void StopLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[Feld[x][y]].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) - StopSoundExt(sound_effect, SND_CTRL_STOP_SOUND); + StopSound(sound_effect); +} + +static void PlayLevelMusic() +{ + if (levelset.music[level_nr] != MUS_UNDEFINED) + PlayMusic(levelset.music[level_nr]); /* from config file */ + else + PlayMusic(MAP_NOCONF_MUSIC(level_nr)); /* from music dir */ } void RaiseScore(int value) @@ -8607,7 +9186,7 @@ void CreateGameButtons() { int i; - for (i=0; i