X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame_bd%2Fbd_caveengine.c;h=2793d26f2f93c968e7b4d4d83ff2df997abac611;hb=dc51f089096a0c775d2a03d0b862a14d6ce88d51;hp=b2c78716ecb08b8379e6e09215257c8e564cd0cc;hpb=3fb6a71ff8cb550457ba2f4497993d75ef2742bd;p=rocksndiamonds.git diff --git a/src/game_bd/bd_caveengine.c b/src/game_bd/bd_caveengine.c index b2c78716..2793d26f 100644 --- a/src/game_bd/bd_caveengine.c +++ b/src/game_bd/bd_caveengine.c @@ -126,9 +126,19 @@ void gd_cave_set_seconds_sound(GdCave *cave) } } +// returns true if the element can fall +static inline boolean el_can_fall(const int element) +{ + return (gd_elements[element & O_MASK].properties & P_CAN_FALL) != 0; +} + // play diamond or stone sound of given element. static void play_sound_of_element(GdCave *cave, GdElement element, int x, int y) { + // check if sound should be skipped for falling elements (and only be played on impact) + if (el_can_fall(element) && skip_bd_falling_sounds()) + return; + // stone and diamond fall sounds. switch (element) { @@ -449,7 +459,7 @@ static inline boolean rotates_ccw (const GdCave *cave, const int x, const int y) } // returns true if the element is a player -static inline boolean is_player(const GdCave *cave, const int x, const int y) +boolean is_player(const GdCave *cave, const int x, const int y) { return (gd_elements[get(cave, x, y) & O_MASK].properties & P_PLAYER) != 0; } @@ -467,6 +477,13 @@ static inline boolean can_be_hammered_dir(const GdCave *cave, const int x, const return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_CAN_BE_HAMMERED) != 0; } +// returns true if the element can be pushed +boolean can_be_pushed_dir(const GdCave *cave, const int x, const int y, + const GdDirection dir) +{ + return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_PUSHABLE) != 0; +} + // returns true if the element is explodable and explodes to space, for example the player static inline boolean is_first_stage_of_explosion(const GdCave *cave, const int x, const int y) { @@ -748,6 +765,13 @@ static void explode(GdCave *cave, int x, int y) creature_explode(cave, x, y, O_EXPLODE_1); break; + case O_ROCKET_1: + case O_ROCKET_2: + case O_ROCKET_3: + case O_ROCKET_4: + creature_explode(cave, x, y, O_EXPLODE_1); + break; + case O_BUTTER_1: case O_BUTTER_2: case O_BUTTER_3: @@ -780,6 +804,7 @@ static void explode(GdCave *cave, int x, int y) case O_PLAYER_BOMB: case O_PLAYER_GLUED: case O_PLAYER_STIRRING: + case O_PLAYER_ROCKET_LAUNCHER: case O_PLAYER_PNEUMATIC_LEFT: case O_PLAYER_PNEUMATIC_RIGHT: creature_explode(cave, x, y, O_EXPLODE_1); @@ -983,17 +1008,18 @@ static GdElement player_get_element(GdCave* cave, const GdElement object, int x, process a crazy dream-style teleporter. called from gd_cave_iterate, for a player or a player_bomb. player is standing at px, py, and trying to move in the direction player_move, - where there is a teleporter. - we check the whole cave, from px+1,py, till we get back to px,py (by wrapping + where there is a teleporter at (tx_start, ty_start). we check the whole cave, + from (tx_start + 1, ty_start), till we get back to (tx_start, ty_start) (by wrapping around). the first teleporter we find, and which is suitable, will be the destination. return TRUE if teleporter worked, FALSE if cound not find any suitable teleporter. - */ +*/ static boolean do_teleporter(GdCave *cave, int px, int py, GdDirection player_move) { - int tx, ty; - - tx = px; - ty = py; + // start at teleporter position (not at player position!) + int tx_start = px + gd_dx[player_move]; + int ty_start = py + gd_dy[player_move]; + int tx = tx_start; + int ty = ty_start; do { @@ -1025,7 +1051,7 @@ static boolean do_teleporter(GdCave *cave, int px, int py, GdDirection player_mo } } // loop until we get back to original coordinates - while (tx != px || ty != py); + while (tx != tx_start || ty != ty_start); // return false as we did not find any usable teleporter return FALSE; @@ -1362,6 +1388,9 @@ static boolean do_fall_try_magic(GdCave *cave, int x, int y, // active or non-active or anything, element falling in will always disappear store(cave, x, y, O_SPACE); + if (cave->magic_wall_breakscan && cave->amoeba_state == GD_AM_AWAKE) + cave->convert_amoeba_this_frame = TRUE; + return TRUE; } else @@ -1595,6 +1624,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, // score collected this frame cave->score = 0; + // to implement buggy bd1 amoeba+magic wall behaviour + cave->convert_amoeba_this_frame = FALSE; + // suicide only kills the active player // player_x, player_y was set by the previous iterate routine, or the cave setup. // we must check if there is a player or not - he may have exploded or something like that @@ -1746,6 +1778,19 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, move(cave, x, y, player_move, O_PLAYER_BOMB); break; + case O_ROCKET_LAUNCHER: + // if its a rocket launcher, remember he now has one. + // we do not change the "remains" and "what" variables, + // so that part of the code will be ineffective + gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y); + store_dir(cave, x, y, player_move, O_SPACE); + + if (player_fire) + store(cave, x, y, O_PLAYER_ROCKET_LAUNCHER); + else + move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER); + break; + case O_POT: // we do not change the "remains" and "what" variables, // so that part of the code will be ineffective @@ -1887,6 +1932,98 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, } break; + case O_PLAYER_ROCKET_LAUNCHER: + // much simpler; cannot snap-push stones + if (cave->kill_player) + { + explode(cave, x, y); + break; + } + + cave->player_seen_ago = 0; + // bd4 intermission caves have many players. so if one of them has exited, + // do not change the flag anymore. so this if () is needed + if (cave->player_state != GD_PL_EXITED) + cave->player_state = GD_PL_LIVING; + + // firing a rocket? + if (player_move != GD_MV_STILL) + { + // if the player does not move, nothing to do + GdElement what = get_dir(cave, x, y, player_move); + GdElement remains = what; + + // to fire a rocket, diagonal movement should not be allowed. + // so either x or y must be zero + if (player_fire) + { + // placing a rocket into empty space + if (is_space_dir(cave, x, y, player_move)) + { + switch (player_move) + { + case GD_MV_RIGHT: + store_dir(cave, x, y, player_move, O_ROCKET_1); + if (!cave->infinite_rockets) + store(cave, x, y, O_PLAYER); + break; + + case GD_MV_UP: + store_dir(cave, x, y, player_move, O_ROCKET_2); + if (!cave->infinite_rockets) + store(cave, x, y, O_PLAYER); + break; + + case GD_MV_LEFT: + store_dir(cave, x, y, player_move, O_ROCKET_3); + if (!cave->infinite_rockets) + store(cave, x, y, O_PLAYER); + break; + + case GD_MV_DOWN: + store_dir(cave, x, y, player_move, O_ROCKET_4); + if (!cave->infinite_rockets) + store(cave, x, y, O_PLAYER); + break; + + default: + // cannot fire in other directions + break; + } + + gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y); + } + + // a player with rocket launcher cannot snap elements, so stop here + break; + } + + // pushing and collecting + // if we are 'eating' a teleporter, and the function returns true + // (teleporting worked), break here + if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move)) + break; + + // player fire is false... + if (do_push(cave, x, y, player_move, FALSE)) + { + remains = O_SPACE; + } + else + { + // get element. if cannot get, player_get_element will return the same + remains = player_get_element(cave, what, x, y); + } + + // if something changed, OR there is space, move. + if (remains != what || remains == O_SPACE) + { + // if anything changed, apply the change. + move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER); + } + } + break; + case O_PLAYER_STIRRING: if (cave->kill_player) { @@ -2733,6 +2870,13 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, // ============================================================================ case O_AMOEBA: + // emulating BD1 amoeba+magic wall bug + if (cave->convert_amoeba_this_frame && amoeba_found_enclosed) + { + store(cave, x, y, cave->amoeba_enclosed_effect); + break; + } + amoeba_count++; switch (cave->amoeba_state) { @@ -3168,6 +3312,38 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, } break; + // ============================================================================ + // R O C K E T S + // ============================================================================ + + case O_ROCKET_1: + if (is_space_dir(cave, x, y, GD_MV_RIGHT)) + move(cave, x, y, GD_MV_RIGHT, O_ROCKET_1); + else + explode(cave, x, y); + break; + + case O_ROCKET_2: + if (is_space_dir(cave, x, y, GD_MV_UP)) + move(cave, x, y, GD_MV_UP, O_ROCKET_2); + else + explode(cave, x, y); + break; + + case O_ROCKET_3: + if (is_space_dir(cave, x, y, GD_MV_LEFT)) + move(cave, x, y, GD_MV_LEFT, O_ROCKET_3); + else + explode(cave, x, y); + break; + + case O_ROCKET_4: + if (is_space_dir(cave, x, y, GD_MV_DOWN)) + move(cave, x, y, GD_MV_DOWN, O_ROCKET_4); + else + explode(cave, x, y); + break; + // ============================================================================ // S I M P L E C H A N G I N G; E X P L O S I O N S // ============================================================================ @@ -3472,7 +3648,7 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, // PLAYER // check if player is alive. - if ((cave->player_state == GD_PL_LIVING && cave->player_seen_ago > 15) || cave->kill_player) + if ((cave->player_state == GD_PL_LIVING && cave->player_seen_ago > 1) || cave->kill_player) cave->player_state = GD_PL_DIED; // check if any voodoo exploded, and kill players the next scan if that happended. @@ -3567,7 +3743,8 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, // magic wall; if active&wait or not wait for hatching if (cave->magic_wall_state == GD_MW_ACTIVE && - (cave->hatched || !cave->magic_timer_wait_for_hatching)) + (cave->hatched || !cave->magic_timer_wait_for_hatching) && + !(cave->magic_wall_time == 0 && cave->magic_timer_zero_is_infinite)) { cave->magic_wall_time -= cave->speed; if (cave->magic_wall_time < 0)