X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=8629abd6dc8f1108060cf26b6b5e851398f426f5;hb=9c285b0e8e4d81c5559815c5f7142685ce865206;hp=855e331ab1f5d54b359e3d10b9869dd70048397d;hpb=942ec4881e3b21c130df9ae105d06c2c633fa192;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 855e331a..8629abd6 100644 --- a/src/game.c +++ b/src/game.c @@ -144,9 +144,14 @@ Feld[x][y] == EL_EXIT_OPEN || \ Feld[x][y] == EL_ACID)) +#if 1 +#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \ + (IN_LEV_FIELD(x, y) && IS_FREE(x, y)) +#else #define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ IS_FOOD_DARK_YAMYAM(Feld[x][y]))) +#endif #define MOLE_CAN_ENTER_FIELD(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || (condition))) @@ -179,6 +184,7 @@ static void KillHeroUnlessProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); +static void TestIfElementHitsCustomElement(int, int, int); static void ChangeElement(int, int, int); static boolean CheckTriggeredElementSideChange(int, int, int, int, int); @@ -668,6 +674,11 @@ static void InitField(int x, int y, boolean init_game) break; case EL_DYNAMITE_ACTIVE: + case EL_SP_DISK_RED_ACTIVE: + case EL_DYNABOMB_PLAYER_1_ACTIVE: + case EL_DYNABOMB_PLAYER_2_ACTIVE: + case EL_DYNABOMB_PLAYER_3_ACTIVE: + case EL_DYNABOMB_PLAYER_4_ACTIVE: MovDelay[x][y] = 96; break; @@ -1065,6 +1076,7 @@ void InitGame() player->is_collecting = FALSE; player->is_pushing = FALSE; player->is_switching = FALSE; + player->is_dropping = FALSE; player->is_bored = FALSE; player->is_sleeping = FALSE; @@ -1075,6 +1087,8 @@ void InitGame() 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; @@ -1122,6 +1136,8 @@ void InitGame() player->push_delay = 0; player->push_delay_value = game.initial_push_delay_value; + player->drop_delay = 0; + player->last_jx = player->last_jy = 0; player->jx = player->jy = 0; @@ -1605,7 +1621,10 @@ void InitMovDir(int x, int y) MovDir[x][y] = element_info[element].move_direction_initial; 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) + element_info[element].move_pattern == MV_TURNING_RIGHT || + element_info[element].move_pattern == MV_TURNING_LEFT_RIGHT || + element_info[element].move_pattern == MV_TURNING_RIGHT_LEFT || + element_info[element].move_pattern == MV_TURNING_RANDOM) MovDir[x][y] = 1 << RND(4); else if (element_info[element].move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); @@ -2134,6 +2153,9 @@ void RelocatePlayer(int x, int y, int element) { struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1]; + if (player->GameOver) /* do not reanimate dead player */ + return; + #if 1 RemoveField(x, y); /* temporarily remove newly placed player */ DrawLevelField(x, y); @@ -2523,6 +2545,12 @@ void Explode(int ex, int ey, int phase, int mode) #endif int frame = getGraphicAnimationFrame(graphic, phase - delay); +#if 0 + printf("::: %d ['%s'] -> %d\n", GfxElement[x][y], + element_info[GfxElement[x][y]].token_name, + graphic); +#endif + if (phase == delay) DrawLevelFieldCrumbledSand(x, y); @@ -2544,6 +2572,7 @@ void Explode(int ex, int ey, int phase, int mode) void DynaExplode(int ex, int ey) { int i, j; + int dynabomb_element = Feld[ex][ey]; int dynabomb_size = 1; boolean dynabomb_xl = FALSE; struct PlayerInfo *player; @@ -2555,9 +2584,9 @@ void DynaExplode(int ex, int ey) { 0, +1 } }; - if (IS_ACTIVE_BOMB(Feld[ex][ey])) + if (IS_ACTIVE_BOMB(dynabomb_element)) { - player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_PLAYER_1_ACTIVE]; + player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE]; dynabomb_size = player->dynabomb_size; dynabomb_xl = player->dynabomb_xl; player->dynabombs_left++; @@ -2662,7 +2691,9 @@ void Bang(int x, int y) Explode(x, y, EX_PHASE_START, EX_CENTER); break; default: - if (CAN_EXPLODE_1X1(element)) + if (CAN_EXPLODE_DYNA(element)) + DynaExplode(x, y); + else if (CAN_EXPLODE_1X1(element)) Explode(x, y, EX_PHASE_START, EX_CENTER); else Explode(x, y, EX_PHASE_START, EX_NORMAL); @@ -3042,6 +3073,10 @@ void Impact(int x, int y) MovDir[x][y + 1] != MV_DOWN || MovPos[x][y + 1] <= TILEY / 2)); +#if 0 + object_hit = !IS_FREE(x, y + 1); +#endif + /* do not smash moving elements that left the smashed field in time */ if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) && ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX) @@ -3678,9 +3713,12 @@ inline static void TurnRoundExt(int x, int y) } } } - else if (move_pattern == MV_ALL_DIRECTIONS || - move_pattern == MV_TURNING_LEFT || - move_pattern == MV_TURNING_RIGHT) + else if (move_pattern == MV_TURNING_LEFT || + move_pattern == MV_TURNING_RIGHT || + move_pattern == MV_TURNING_LEFT_RIGHT || + move_pattern == MV_TURNING_RIGHT_LEFT || + move_pattern == MV_TURNING_RANDOM || + move_pattern == MV_ALL_DIRECTIONS) { 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); @@ -3689,6 +3727,14 @@ inline static void TurnRoundExt(int x, int y) MovDir[x][y] = left_dir; else if (move_pattern == MV_TURNING_RIGHT) MovDir[x][y] = right_dir; + else if (move_pattern == MV_TURNING_LEFT_RIGHT) + MovDir[x][y] = (can_turn_left || !can_turn_right ? left_dir : right_dir); + else if (move_pattern == MV_TURNING_RIGHT_LEFT) + MovDir[x][y] = (can_turn_right || !can_turn_left ? right_dir : left_dir); + else if (move_pattern == MV_TURNING_RANDOM) + MovDir[x][y] = (can_turn_left && !can_turn_right ? left_dir : + can_turn_right && !can_turn_left ? right_dir : + RND(2) ? left_dir : right_dir); else if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); else if (can_turn_left) @@ -3804,7 +3850,8 @@ inline static void TurnRoundExt(int x, int y) MovDir[x][y] = old_move_dir; } } - else if (move_pattern == MV_WHEN_PUSHED) + else if (move_pattern == MV_WHEN_PUSHED || + move_pattern == MV_WHEN_DROPPED) { if (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y)) MovDir[x][y] = MV_NO_MOVING; @@ -4123,6 +4170,11 @@ void StartMoving(int x, int y) element; also, the case of the player being the element to smash was simply not covered here... :-/ ) */ +#if 0 + WasJustMoving[x][y] = 0; + WasJustFalling[x][y] = 0; +#endif + Impact(x, y); } else if (IS_FREE(x, y + 1) && element == EL_SPRING && use_spring_bug) @@ -4225,6 +4277,8 @@ void StartMoving(int x, int y) int move_pattern = element_info[element].move_pattern; int newx, newy; + Moving2Blocked(x, y, &newx, &newy); + #if 1 if (IS_PUSHABLE(element) && JustBeingPushed(x, y)) return; @@ -4236,6 +4290,43 @@ void StartMoving(int x, int y) return; #endif +#if 1 + if (game.engine_version >= VERSION_IDENT(3,0,9,0) && + WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) && + (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy))) + { +#if 0 + printf("::: element %d '%s' WasJustMoving %d [%d, %d, %d, %d]\n", + element, element_info[element].token_name, + 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)); +#endif + +#if 1 + WasJustMoving[x][y] = 0; +#endif + + TestIfElementHitsCustomElement(x, y, MovDir[x][y]); + +#if 0 + if (Feld[x][y] != element) /* element has changed */ + { + element = Feld[x][y]; + move_pattern = element_info[element].move_pattern; + + if (!CAN_MOVE(element)) + return; + } +#else + if (Feld[x][y] != element) /* element has changed */ + return; +#endif + } +#endif + #if 0 #if 0 if (element == EL_SPRING && MovDir[x][y] == MV_DOWN) @@ -4265,7 +4356,10 @@ void StartMoving(int x, int y) element != EL_PACMAN && !(move_pattern & MV_ANY_DIRECTION) && move_pattern != MV_TURNING_LEFT && - move_pattern != MV_TURNING_RIGHT) + move_pattern != MV_TURNING_RIGHT && + move_pattern != MV_TURNING_LEFT_RIGHT && + move_pattern != MV_TURNING_RIGHT_LEFT && + move_pattern != MV_TURNING_RANDOM) { TurnRound(x, y); @@ -4437,8 +4531,13 @@ void StartMoving(int x, int y) { if (Feld[newx][newy] == EL_EXIT_OPEN) { +#if 1 + RemoveField(x, y); + DrawLevelField(x, y); +#else Feld[x][y] = EL_EMPTY; DrawLevelField(x, y); +#endif PlayLevelSound(newx, newy, SND_PENGUIN_PASSING); if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) @@ -4495,7 +4594,11 @@ void StartMoving(int x, int y) else if ((move_pattern & MV_MAZE_RUNNER_STYLE || element == EL_MAZE_RUNNER) && IN_LEV_FIELD(newx, newy)) { +#if 1 + if (IS_FREE(newx, newy)) +#else if (IS_FOOD_DARK_YAMYAM(Feld[newx][newy])) +#endif { if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); @@ -4695,7 +4798,9 @@ void ContinueMoving(int x, int y) int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int newx = x + dx, newy = y + dy; +#if 0 int nextx = newx + dx, nexty = newy + dy; +#endif boolean pushed = Pushed[x][y]; MovPos[x][y] += getElementMoveStepsize(x, y); @@ -4872,12 +4977,21 @@ void ContinueMoving(int x, int y) ChangeElement(newx, newy, ChangePage[newx][newy]); #endif +#if 1 + + TestIfElementHitsCustomElement(newx, newy, direction); + +#else + if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) { + int hitting_element = Feld[newx][newy]; + /* !!! fix side (direction) orientation here and elsewhere !!! */ - CheckElementSideChange(newx, newy, Feld[newx][newy], - direction, CE_COLLISION_ACTIVE, -1); + CheckElementSideChange(newx, newy, hitting_element, + direction, CE_HITTING_SOMETHING, -1); +#if 0 if (IN_LEV_FIELD(nextx, nexty)) { static int opposite_directions[] = @@ -4891,7 +5005,6 @@ void ContinueMoving(int x, int y) int opposite_direction = opposite_directions[move_dir_bit]; int hitting_side = direction; int touched_side = opposite_direction; - int hitting_element = Feld[newx][newy]; int touched_element = MovingOrBlocked2Element(nextx, nexty); boolean object_hit = (!IS_MOVING(nextx, nexty) || MovDir[nextx][nexty] != direction || @@ -4901,11 +5014,11 @@ void ContinueMoving(int x, int y) { int i; - CheckElementSideChange(nextx, nexty, Feld[nextx][nexty], - opposite_direction, CE_COLLISION_PASSIVE, -1); + CheckElementSideChange(nextx, nexty, touched_element, + opposite_direction, CE_HIT_BY_SOMETHING, -1); if (IS_CUSTOM_ELEMENT(hitting_element) && - HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_COLL_ACTIVE)) + HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING)) { for (i = 0; i < element_info[hitting_element].num_change_pages; i++) { @@ -4913,19 +5026,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_COLL_ACTIVE) && + change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) && change->sides & touched_side && change->trigger_element == touched_element) { CheckElementSideChange(newx, newy, hitting_element, - CH_SIDE_ANY, CE_OTHER_IS_COLL_ACTIVE, i); + CH_SIDE_ANY, CE_OTHER_IS_HITTING, i); break; } } } if (IS_CUSTOM_ELEMENT(touched_element) && - HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_IS_COLL_PASSIVE)) + HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT)) { for (i = 0; i < element_info[touched_element].num_change_pages; i++) { @@ -4933,19 +5046,21 @@ void ContinueMoving(int x, int y) &element_info[touched_element].change_page[i]; if (change->can_change && - change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_PASSIVE) && + change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) && change->sides & hitting_side && change->trigger_element == hitting_element) { CheckElementSideChange(nextx, nexty, touched_element, - CH_SIDE_ANY, CE_OTHER_IS_COLL_PASSIVE, i); + CH_SIDE_ANY, CE_OTHER_GETS_HIT, i); break; } } } } } +#endif } +#endif TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); @@ -6053,7 +6168,11 @@ static void ChangeElement(int x, int y, int page) ChangePage[x][y] = -1; } +#if 0 + if (IS_MOVING(x, y) && !change->explode) +#else if (IS_MOVING(x, y)) /* never change a running system ;-) */ +#endif { ChangeDelay[x][y] = 1; /* try change after next move step */ ChangePage[x][y] = page; /* remember page to use for change */ @@ -6172,17 +6291,49 @@ static boolean CheckElementChange(int x, int y, int element, int trigger_event) return CheckElementSideChange(x, y, element, CH_SIDE_ANY, trigger_event, -1); } -static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) +static void PlayPlayerSound(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; int element = player->element_nr; - boolean was_waiting = player->is_waiting; + int last_action = player->last_action_waiting; + int action = player->action_waiting; - if (is_waiting) + if (player->is_waiting) { - int action; + 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 (!was_waiting) /* not waiting -> waiting */ + if (is_waiting) + { + if (!last_waiting) /* not waiting -> waiting */ { player->is_waiting = TRUE; @@ -6198,30 +6349,93 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir); } - if (game.player_sleeping_delay_fixed != -1 && - game.player_sleeping_delay_random != -1 && + 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 != -1 && - game.player_boring_delay_random != -1 && + else if (game.player_boring_delay_fixed + + game.player_boring_delay_random > 0 && FrameCounter >= player->frame_counter_bored) player->is_bored = TRUE; - action = (player->is_sleeping ? ACTION_SLEEPING : - player->is_bored ? ACTION_BORING : ACTION_WAITING); + player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING : + player->is_bored ? ACTION_BORING : + ACTION_WAITING); - if (!was_waiting) - PlayLevelSoundElementAction(jx, jy, element, action); - else - PlayLevelSoundElementActionIfLoop(jx, jy, element, action); - } - else if (was_waiting) /* waiting -> not waiting */ - { if (player->is_sleeping) - PlayLevelSoundElementAction(jx, jy, element, ACTION_AWAKENING); + { + 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; @@ -6232,6 +6446,8 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) 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; } @@ -6317,6 +6533,8 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) if (player->MovPos == 0) /* needed for tape.playing */ player->is_moving = FALSE; + player->is_dropping = FALSE; + return 0; } @@ -6658,6 +6876,7 @@ void GameActions() StartMoving(x, y); #if 1 + element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); #if 0 if (element == EL_MOLE) @@ -6942,6 +7161,7 @@ void GameActions() } DrawAllPlayers(); + PlayAllPlayersSound(); if (options.debug) /* calculate frames per second */ { @@ -6986,6 +7206,9 @@ void GameActions() if (stored_player[i].MovPos != 0) stored_player[i].StepFrame += move_frames; + + if (stored_player[i].drop_delay > 0) + stored_player[i].drop_delay--; } #endif @@ -7185,6 +7408,8 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, player->step_counter++; + player->drop_delay = 0; + PlayerVisit[jx][jy] = FrameCounter; ScrollPlayer(player, SCROLL_INIT); @@ -7216,8 +7441,27 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) int old_jx = jx, old_jy = jy; int moved = MF_NO_ACTION; +#if 1 + if (!player->active) + return FALSE; + + if (!dx && !dy) + { + if (player->MovPos == 0) + { + player->is_moving = FALSE; + player->is_digging = FALSE; + player->is_collecting = FALSE; + player->is_snapping = FALSE; + player->is_pushing = FALSE; + } + + return FALSE; + } +#else if (!player->active || (!dx && !dy)) return FALSE; +#endif #if 0 if (!FrameReached(&player->move_delay, player->move_delay_value) && @@ -7372,6 +7616,8 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->is_switching = FALSE; #endif + player->is_dropping = FALSE; + #if 1 { @@ -7716,6 +7962,103 @@ void TestIfElementTouchesCustomElement(int x, int y) CE_OTHER_IS_TOUCHING, center_element_change_page); } +void TestIfElementHitsCustomElement(int x, int y, int direction) +{ + int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); + int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); + int hitx = x + dx, hity = y + dy; + int hitting_element = Feld[x][y]; +#if 0 + boolean object_hit = (IN_LEV_FIELD(hitx, hity) && + !IS_FREE(hitx, hity) && + (!IS_MOVING(hitx, hity) || + MovDir[hitx][hity] != direction || + ABS(MovPos[hitx][hity]) <= TILEY / 2)); +#endif + + if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity)) + return; + +#if 0 + if (IN_LEV_FIELD(hitx, hity) && !object_hit) + return; +#endif + + CheckElementSideChange(x, y, hitting_element, + direction, CE_HITTING_SOMETHING, -1); + + if (IN_LEV_FIELD(hitx, hity)) + { + static int opposite_directions[] = + { + MV_RIGHT, + MV_LEFT, + MV_DOWN, + MV_UP + }; + int move_dir_bit = MV_DIR_BIT(direction); + int opposite_direction = opposite_directions[move_dir_bit]; + int hitting_side = direction; + int touched_side = opposite_direction; + int touched_element = MovingOrBlocked2Element(hitx, hity); +#if 1 + boolean object_hit = (!IS_MOVING(hitx, hity) || + MovDir[hitx][hity] != direction || + ABS(MovPos[hitx][hity]) <= TILEY / 2); + + object_hit = TRUE; +#endif + + if (object_hit) + { + int i; + + CheckElementSideChange(hitx, hity, touched_element, + opposite_direction, CE_HIT_BY_SOMETHING, -1); + + if (IS_CUSTOM_ELEMENT(hitting_element) && + HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING)) + { + for (i = 0; i < element_info[hitting_element].num_change_pages; i++) + { + struct ElementChangeInfo *change = + &element_info[hitting_element].change_page[i]; + + if (change->can_change && + change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) && + change->sides & touched_side && + change->trigger_element == touched_element) + { + CheckElementSideChange(x, y, hitting_element, + CH_SIDE_ANY, CE_OTHER_IS_HITTING, i); + break; + } + } + } + + if (IS_CUSTOM_ELEMENT(touched_element) && + HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT)) + { + 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_GETS_HIT) && + change->sides & hitting_side && + change->trigger_element == hitting_element) + { + CheckElementSideChange(hitx, hity, touched_element, + CH_SIDE_ANY, CE_OTHER_GETS_HIT, i); + break; + } + } + } + } + } +} + void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) { int i, kill_x = -1, kill_y = -1; @@ -8721,6 +9064,8 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) player->is_digging = FALSE; player->is_collecting = FALSE; + player->is_dropping = FALSE; + if (DigField(player, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION) return FALSE; @@ -8739,13 +9084,13 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) boolean DropElement(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; - int old_element; + int old_element = Feld[jx][jy]; + int new_element; - if (!player->active || player->MovPos) + /* check if player is active, not moving and ready to drop */ + if (!player->active || player->MovPos || player->drop_delay > 0) return FALSE; - old_element = Feld[jx][jy]; - /* check if player has anything that can be dropped */ if (player->inventory_size == 0 && player->dynabombs_left == 0) return FALSE; @@ -8763,18 +9108,20 @@ boolean DropElement(struct PlayerInfo *player) if (old_element != EL_EMPTY) Back[jx][jy] = old_element; /* store old element on this field */ - MovDelay[jx][jy] = 96; - ResetGfxAnimation(jx, jy); ResetRandomAnimationValue(jx, jy); if (player->inventory_size > 0) { - int new_element = player->inventory_element[--player->inventory_size]; + player->inventory_size--; + new_element = player->inventory_element[player->inventory_size]; + + if (new_element == EL_DYNAMITE) + new_element = EL_DYNAMITE_ACTIVE; + else if (new_element == EL_SP_DISK_RED) + new_element = EL_SP_DISK_RED_ACTIVE; - Feld[jx][jy] = (new_element == EL_DYNAMITE ? EL_DYNAMITE_ACTIVE : - new_element == EL_SP_DISK_RED ? EL_SP_DISK_RED_ACTIVE : - new_element); + Feld[jx][jy] = new_element; DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->inventory_size, 3), FONT_TEXT_2); @@ -8792,9 +9139,9 @@ boolean DropElement(struct PlayerInfo *player) else /* player is dropping a dyna bomb */ { player->dynabombs_left--; + new_element = EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr; - Feld[jx][jy] = - EL_DYNABOMB_PLAYER_1_ACTIVE + (player->element_nr - EL_PLAYER_1); + Feld[jx][jy] = new_element; if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0); @@ -8802,6 +9149,67 @@ boolean DropElement(struct PlayerInfo *player) PlayLevelSoundAction(jx, jy, ACTION_DROPPING); } + + +#if 1 + + if (Feld[jx][jy] == new_element) /* uninitialized unless CE change */ + { + InitField(jx, jy, FALSE); + if (CAN_MOVE(Feld[jx][jy])) + InitMovDir(jx, jy); + } + + new_element = Feld[jx][jy]; + + if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) && + element_info[new_element].move_pattern == MV_WHEN_DROPPED) + { + int move_stepsize = element_info[new_element].move_stepsize; + int direction, dx, dy, nextx, nexty; + + if (element_info[new_element].move_direction_initial == MV_NO_MOVING) + MovDir[jx][jy] = player->MovDir; + + direction = MovDir[jx][jy]; + dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); + dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); + nextx = jx + dx; + nexty = jy + dy; + + if (IN_LEV_FIELD(nextx, nexty) && IS_FREE(nextx, nexty)) + { +#if 0 + WasJustMoving[jx][jy] = 3; +#else + InitMovingField(jx, jy, direction); + ContinueMoving(jx, jy); +#endif + } + else + { + Changed[jx][jy] = 0; /* allow another change */ + +#if 1 + TestIfElementHitsCustomElement(jx, jy, direction); +#else + CheckElementSideChange(jx, jy, new_element, + direction, CE_HITTING_SOMETHING, -1); +#endif + } + + player->drop_delay = 2 * TILEX / move_stepsize + 1; + } + +#if 0 + player->drop_delay = 8 + 8 + 8; +#endif + +#endif + + player->is_dropping = TRUE; + + return TRUE; } @@ -8816,13 +9224,10 @@ 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)); } @@ -8915,7 +9320,7 @@ 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()