X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=8c18d89ca64b71c9f1d92af961265137d20e4e37;hb=eae2f3467caaaf64a9370c1acd8cecf11fd58328;hp=fc0d64767d09631bef0d1fb55345d7ab2c7b26f2;hpb=5d50a7e10873581345ee63a5afafd43dbd45809b;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index fc0d6476..8c18d89c 100644 --- a/src/game.c +++ b/src/game.c @@ -101,7 +101,9 @@ #define NUM_GAME_BUTTONS 6 /* forward declaration for internal use */ +static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); +static void KillHeroUnlessShield(struct PlayerInfo *); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); @@ -188,19 +190,19 @@ static int getBeltNrFromElement(int element) static int getBeltNrFromSwitchElement(int element) { - return (element < EL_BELT2_SWITCH_L ? 0 : - element < EL_BELT3_SWITCH_L ? 1 : - element < EL_BELT4_SWITCH_L ? 2 : 3); + return (element < EL_BELT2_SWITCH_LEFT ? 0 : + element < EL_BELT3_SWITCH_LEFT ? 1 : + element < EL_BELT4_SWITCH_LEFT ? 2 : 3); } static int getBeltDirNrFromSwitchElement(int element) { static int belt_base_element[4] = { - EL_BELT1_SWITCH_L, - EL_BELT2_SWITCH_L, - EL_BELT3_SWITCH_L, - EL_BELT4_SWITCH_L + EL_BELT1_SWITCH_LEFT, + EL_BELT2_SWITCH_LEFT, + EL_BELT3_SWITCH_LEFT, + EL_BELT4_SWITCH_LEFT }; int belt_nr = getBeltNrFromSwitchElement(element); @@ -281,36 +283,41 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = EL_BADEWANNE5; break; - case EL_KAEFER_R: - case EL_KAEFER_O: - case EL_KAEFER_L: - case EL_KAEFER_U: + case EL_KAEFER_RIGHT: + case EL_KAEFER_UP: + case EL_KAEFER_LEFT: + case EL_KAEFER_DOWN: case EL_KAEFER: - case EL_FLIEGER_R: - case EL_FLIEGER_O: - case EL_FLIEGER_L: - case EL_FLIEGER_U: + case EL_FLIEGER_RIGHT: + case EL_FLIEGER_UP: + case EL_FLIEGER_LEFT: + case EL_FLIEGER_DOWN: case EL_FLIEGER: - case EL_BUTTERFLY_R: - case EL_BUTTERFLY_O: - case EL_BUTTERFLY_L: - case EL_BUTTERFLY_U: + case EL_BUTTERFLY_RIGHT: + case EL_BUTTERFLY_UP: + case EL_BUTTERFLY_LEFT: + case EL_BUTTERFLY_DOWN: case EL_BUTTERFLY: - case EL_FIREFLY_R: - case EL_FIREFLY_O: - case EL_FIREFLY_L: - case EL_FIREFLY_U: + case EL_FIREFLY_RIGHT: + case EL_FIREFLY_UP: + case EL_FIREFLY_LEFT: + case EL_FIREFLY_DOWN: case EL_FIREFLY: - case EL_PACMAN_R: - case EL_PACMAN_O: - case EL_PACMAN_L: - case EL_PACMAN_U: + case EL_PACMAN_RIGHT: + case EL_PACMAN_UP: + case EL_PACMAN_LEFT: + case EL_PACMAN_DOWN: case EL_MAMPFER: case EL_MAMPFER2: case EL_ROBOT: case EL_PACMAN: case EL_SP_SNIKSNAK: case EL_SP_ELECTRON: + case EL_MOLE_LEFT: + case EL_MOLE_RIGHT: + case EL_MOLE_UP: + case EL_MOLE_DOWN: + case EL_MOLE: InitMovDir(x, y); break; @@ -339,7 +346,6 @@ static void InitField(int x, int y, boolean init_game) local_player->sokobanfields_still_needed++; break; - case EL_MAULWURF: case EL_PINGUIN: local_player->friends_still_needed++; break; @@ -366,18 +372,18 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = EL_EM_KEY_4; break; - case EL_BELT1_SWITCH_L: - case EL_BELT1_SWITCH_M: - case EL_BELT1_SWITCH_R: - case EL_BELT2_SWITCH_L: - case EL_BELT2_SWITCH_M: - case EL_BELT2_SWITCH_R: - case EL_BELT3_SWITCH_L: - case EL_BELT3_SWITCH_M: - case EL_BELT3_SWITCH_R: - case EL_BELT4_SWITCH_L: - case EL_BELT4_SWITCH_M: - case EL_BELT4_SWITCH_R: + case EL_BELT1_SWITCH_LEFT: + case EL_BELT1_SWITCH_MIDDLE: + case EL_BELT1_SWITCH_RIGHT: + case EL_BELT2_SWITCH_LEFT: + case EL_BELT2_SWITCH_MIDDLE: + case EL_BELT2_SWITCH_RIGHT: + case EL_BELT3_SWITCH_LEFT: + case EL_BELT3_SWITCH_MIDDLE: + case EL_BELT3_SWITCH_RIGHT: + case EL_BELT4_SWITCH_LEFT: + case EL_BELT4_SWITCH_MIDDLE: + case EL_BELT4_SWITCH_RIGHT: if (init_game) { int belt_nr = getBeltNrFromSwitchElement(Feld[x][y]); @@ -403,7 +409,7 @@ static void InitField(int x, int y, boolean init_game) case EL_LIGHT_SWITCH_ON: if (init_game) - game.light_time_left = 10 * FRAMES_PER_SECOND; + game.light_time_left = level.time_light * FRAMES_PER_SECOND; break; default: @@ -475,6 +481,9 @@ void InitGame() player->last_jx = player->last_jy = 0; player->jx = player->jy = 0; + player->shield_passive_time_left = 0; + player->shield_active_time_left = 0; + DigField(player, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); @@ -507,8 +516,11 @@ void InitGame() AllPlayersGone = FALSE; game.magic_wall_active = FALSE; game.magic_wall_time_left = 0; - game.switchgate_pos = 0; game.light_time_left = 0; + game.timegate_time_left = 0; + game.switchgate_pos = 0; + game.balloon_dir = MV_NO_MOVING; + for (i=0; i<4; i++) { game.belt_dir[i] = MV_NO_MOVING; @@ -688,6 +700,11 @@ void InitGame() DrawAllPlayers(); FadeToFront(); + /* after drawing the level, corect some elements */ + + if (game.timegate_time_left == 0) + CloseAllOpenTimegates(); + if (setup.soft_scrolling) XCopyArea(display, fieldbuffer, backbuffer, gc, FX, FY, SXSIZE, SYSIZE, SX, SY); @@ -756,52 +773,53 @@ void InitMovDir(int x, int y) { 0, -1 }, { -1, 0 } }; - static int direction[2][4] = + static int direction[3][4] = { { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN }, - { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP } + { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }, + { MV_LEFT, MV_RIGHT, MV_UP, MV_DOWN } }; switch(element) { - case EL_KAEFER_R: - case EL_KAEFER_O: - case EL_KAEFER_L: - case EL_KAEFER_U: + case EL_KAEFER_RIGHT: + case EL_KAEFER_UP: + case EL_KAEFER_LEFT: + case EL_KAEFER_DOWN: Feld[x][y] = EL_KAEFER; - MovDir[x][y] = direction[0][element - EL_KAEFER_R]; + MovDir[x][y] = direction[0][element - EL_KAEFER_RIGHT]; break; - case EL_FLIEGER_R: - case EL_FLIEGER_O: - case EL_FLIEGER_L: - case EL_FLIEGER_U: + case EL_FLIEGER_RIGHT: + case EL_FLIEGER_UP: + case EL_FLIEGER_LEFT: + case EL_FLIEGER_DOWN: Feld[x][y] = EL_FLIEGER; - MovDir[x][y] = direction[0][element - EL_FLIEGER_R]; + MovDir[x][y] = direction[0][element - EL_FLIEGER_RIGHT]; break; - case EL_BUTTERFLY_R: - case EL_BUTTERFLY_O: - case EL_BUTTERFLY_L: - case EL_BUTTERFLY_U: + case EL_BUTTERFLY_RIGHT: + case EL_BUTTERFLY_UP: + case EL_BUTTERFLY_LEFT: + case EL_BUTTERFLY_DOWN: Feld[x][y] = EL_BUTTERFLY; - MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R]; + MovDir[x][y] = direction[0][element - EL_BUTTERFLY_RIGHT]; break; - case EL_FIREFLY_R: - case EL_FIREFLY_O: - case EL_FIREFLY_L: - case EL_FIREFLY_U: + case EL_FIREFLY_RIGHT: + case EL_FIREFLY_UP: + case EL_FIREFLY_LEFT: + case EL_FIREFLY_DOWN: Feld[x][y] = EL_FIREFLY; - MovDir[x][y] = direction[0][element - EL_FIREFLY_R]; + MovDir[x][y] = direction[0][element - EL_FIREFLY_RIGHT]; break; - case EL_PACMAN_R: - case EL_PACMAN_O: - case EL_PACMAN_L: - case EL_PACMAN_U: + case EL_PACMAN_RIGHT: + case EL_PACMAN_UP: + case EL_PACMAN_LEFT: + case EL_PACMAN_DOWN: Feld[x][y] = EL_PACMAN; - MovDir[x][y] = direction[0][element - EL_PACMAN_R]; + MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT]; break; case EL_SP_SNIKSNAK: @@ -812,6 +830,14 @@ void InitMovDir(int x, int y) MovDir[x][y] = MV_LEFT; break; + case EL_MOLE_LEFT: + case EL_MOLE_RIGHT: + case EL_MOLE_UP: + case EL_MOLE_DOWN: + Feld[x][y] = EL_MOLE; + MovDir[x][y] = direction[2][element - EL_MOLE_LEFT]; + break; + default: MovDir[x][y] = 1 << RND(4); if (element != EL_KAEFER && @@ -869,7 +895,7 @@ void InitAmoebaNr(int x, int y) void GameWon() { int hi_pos; - int bumplevel = FALSE; + boolean raise_level = FALSE; if (local_player->MovPos) return; @@ -940,17 +966,26 @@ void GameWon() SaveTape(tape.level_nr); /* Ask to save tape */ } + if (level_nr == leveldir[leveldir_nr].handicap_level) + { + leveldir[leveldir_nr].handicap_level++; + SaveLevelSetup_SeriesInfo(leveldir_nr); + + if (level_nr < leveldir[leveldir_nr].last_level) + raise_level = TRUE; + } + if ((hi_pos = NewHiScore()) >= 0) { game_status = HALLOFFAME; DrawHallOfFame(hi_pos); - if (bumplevel && TAPE_IS_EMPTY(tape)) + if (raise_level) level_nr++; } else { game_status = MAINMENU; - if (bumplevel && TAPE_IS_EMPTY(tape)) + if (raise_level) level_nr++; DrawMainMenu(); } @@ -1240,10 +1275,22 @@ void Explode(int ex, int ey, int phase, int mode) if (IS_MASSIVE(element) || element == EL_BURNING) continue; + if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y))) + { + if (IS_ACTIVE_BOMB(element)) + { + /* re-activate things under the bomb like gate or penguin */ + Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_LEERRAUM); + Store[x][y] = 0; + } + + continue; + } + if (element == EL_EXPLODING) element = Store2[x][y]; - if (IS_PLAYER(ex, ey)) + if (IS_PLAYER(ex, ey) && !SHIELD_ON(PLAYERINFO(ex, ey))) { switch(StorePlayer[ex][ey]) { @@ -1265,7 +1312,7 @@ void Explode(int ex, int ey, int phase, int mode) if (game.emulation == EMU_SUPAPLEX) Store[x][y] = EL_LEERRAUM; } - else if (center_element == EL_MAULWURF) + else if (center_element == EL_MOLE) Store[x][y] = EL_EDELSTEIN_ROT; else if (center_element == EL_PINGUIN) Store[x][y] = EL_EDELSTEIN_LILA; @@ -1344,7 +1391,7 @@ void Explode(int ex, int ey, int phase, int mode) int element = Store2[x][y]; if (IS_PLAYER(x, y)) - KillHero(PLAYERINFO(x, y)); + KillHeroUnlessShield(PLAYERINFO(x, y)); else if (IS_EXPLOSIVE(element)) { Feld[x][y] = Store2[x][y]; @@ -1444,8 +1491,10 @@ void Bang(int x, int y) else PlaySoundLevel(x, y, SND_ROAAAR); +#if 0 if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */ element = EL_LEERRAUM; +#endif switch(element) { @@ -1457,6 +1506,7 @@ void Bang(int x, int y) case EL_MAMPFER2: case EL_ROBOT: case EL_PACMAN: + case EL_MOLE: RaiseScoreElement(element); Explode(x, y, EX_PHASE_START, EX_NORMAL); break; @@ -1469,11 +1519,13 @@ void Bang(int x, int y) case EL_DYNABOMB_XL: DynaExplode(x, y); break; - case EL_MAULWURF: case EL_PINGUIN: case EL_BIRNE_AUS: case EL_BIRNE_EIN: - Explode(x, y, EX_PHASE_START, EX_CENTER); + if (IS_PLAYER(x, y)) + Explode(x, y, EX_PHASE_START, EX_NORMAL); + else + Explode(x, y, EX_PHASE_START, EX_CENTER); break; default: Explode(x, y, EX_PHASE_START, EX_NORMAL); @@ -1527,10 +1579,10 @@ static void ToggleBeltSwitch(int x, int y) { static int belt_base_element[4] = { - EL_BELT1_SWITCH_L, - EL_BELT2_SWITCH_L, - EL_BELT3_SWITCH_L, - EL_BELT4_SWITCH_L + EL_BELT1_SWITCH_LEFT, + EL_BELT2_SWITCH_LEFT, + EL_BELT3_SWITCH_LEFT, + EL_BELT4_SWITCH_LEFT }; static int belt_move_dir[4] = { @@ -1616,39 +1668,79 @@ static void ToggleSwitchgateSwitch(int x, int y) } } -static void ToggleLightSwitch(int x, int y) +static void RedrawAllLightSwitchesAndInvisibleElements() { - int element = Feld[x][y]; - int xx, yy; - - game.light_time_left = - (element == EL_LIGHT_SWITCH_OFF ? 10 * FRAMES_PER_SECOND : 0); + int x, y; - for (yy=0; yy 0) { - Feld[xx][yy] = EL_LIGHT_SWITCH_ON; - DrawLevelField(xx, yy); + Feld[x][y] = EL_LIGHT_SWITCH_ON; + DrawLevelField(x, y); } else if (element == EL_LIGHT_SWITCH_ON && game.light_time_left == 0) { - Feld[xx][yy] = EL_LIGHT_SWITCH_OFF; - DrawLevelField(xx, yy); + Feld[x][y] = EL_LIGHT_SWITCH_OFF; + DrawLevelField(x, y); } if (element == EL_INVISIBLE_STEEL || element == EL_UNSICHTBAR || element == EL_SAND_INVISIBLE) + DrawLevelField(x, y); + } + } +} + +static void ToggleLightSwitch(int x, int y) +{ + int element = Feld[x][y]; + + game.light_time_left = + (element == EL_LIGHT_SWITCH_OFF ? + level.time_light * FRAMES_PER_SECOND : 0); + + RedrawAllLightSwitchesAndInvisibleElements(); +} + +static void ActivateTimegateSwitch(int x, int y) +{ + int xx, yy; + + game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND; + + for (yy=0; yy= tape.pos[tape.counter].delay) { @@ -3936,12 +4244,16 @@ void GameActions() Explode(x, y, Frame[x][y], EX_NORMAL); else if (element == EL_AMOEBING) AmoebeWaechst(x, y); + else if (element == EL_DEAMOEBING) + AmoebeSchrumpft(x, y); else if (IS_AMOEBALIVE(element)) AmoebeAbleger(x, y); else if (element == EL_LIFE || element == EL_LIFE_ASYNC) Life(x, y); else if (element == EL_ABLENK_EIN) Ablenk(x, y); + else if (element == EL_TIMEGATE_SWITCH_ON) + TimegateWheel(x, y); else if (element == EL_SALZSAEURE) Blubber(x, y); else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT) @@ -3975,10 +4287,16 @@ void GameActions() OpenSwitchgate(x, y); else if (element == EL_SWITCHGATE_CLOSING) CloseSwitchgate(x, y); + else if (element == EL_TIMEGATE_OPENING) + OpenTimegate(x, y); + else if (element == EL_TIMEGATE_CLOSING) + CloseTimegate(x, y); else if (element == EL_EXTRA_TIME) DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL); - else if (element == EL_FORCE_FIELD) - DrawGraphicAnimation(x, y, GFX_FORCE_FIELD, 6, 4, ANIM_NORMAL); + else if (element == EL_SHIELD_PASSIVE) + DrawGraphicAnimation(x, y, GFX_SHIELD_PASSIVE, 6, 4, ANIM_NORMAL); + else if (element == EL_SHIELD_ACTIVE) + DrawGraphicAnimation(x, y, GFX_SHIELD_ACTIVE, 6, 4, ANIM_NORMAL); if (game.magic_wall_active) { @@ -4061,11 +4379,30 @@ void GameActions() } } - if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing) + if (game.timegate_time_left > 0) + { + game.timegate_time_left--; + + if (game.timegate_time_left == 0) + CloseAllOpenTimegates(); + } + + if (TimeFrames >= (1000 / GameFrameDelay)) { TimeFrames = 0; TimePlayed++; + for (i=0; i 0) + stored_player[i].shield_active_time_left--; + } + } + if (tape.recording || tape.playing) DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed); @@ -4073,12 +4410,12 @@ void GameActions() { TimeLeft--; - if (TimeLeft <= 10) + if (TimeLeft <= 10 && setup.time_limit) PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT); DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); - if (!TimeLeft) + if (!TimeLeft && setup.time_limit) for (i=0; ishield_time_left == 0) + KillHero(player); +#endif + } return MF_MOVING; } @@ -4537,7 +4881,14 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) if (killx != goodx || killy != goody) { if (IS_PLAYER(goodx, goody)) - KillHero(PLAYERINFO(goodx, goody)); + { + struct PlayerInfo *player = PLAYERINFO(goodx, goody); + + if (player->shield_active_time_left > 0) + Bang(killx, killy); + else if (player->shield_passive_time_left == 0) + KillHero(player); + } else Bang(goodx, goody); } @@ -4561,6 +4912,9 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) MV_DOWN }; + if (Feld[badx][bady] == EL_EXPLODING) /* skip just exploding bad things */ + return; + for (i=0; i<4; i++) { int x, y, element; @@ -4592,7 +4946,14 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) if (killx != badx || killy != bady) { if (IS_PLAYER(killx, killy)) - KillHero(PLAYERINFO(killx, killy)); + { + struct PlayerInfo *player = PLAYERINFO(killx, killy); + + if (player->shield_active_time_left > 0) + Bang(badx, bady); + else if (player->shield_passive_time_left == 0) + KillHero(player); + } else Bang(killx, killy); } @@ -4662,10 +5023,20 @@ void KillHero(struct PlayerInfo *player) if (IS_PFORTE(Feld[jx][jy])) Feld[jx][jy] = EL_LEERRAUM; + /* deactivate shield (else Bang()/Explode() would not work right) */ + player->shield_passive_time_left = 0; + player->shield_active_time_left = 0; + Bang(jx, jy); BuryHero(player); } +static void KillHeroUnlessShield(struct PlayerInfo *player) +{ + if (!SHIELD_ON(player)) + KillHero(player); +} + void BuryHero(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; @@ -4787,8 +5158,16 @@ int DigField(struct PlayerInfo *player, PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT); break; - case EL_FORCE_FIELD: + case EL_SHIELD_PASSIVE: RemoveField(x, y); + player->shield_passive_time_left += 10; + PlaySoundLevel(x, y, SND_PONG); + break; + + case EL_SHIELD_ACTIVE: + RemoveField(x, y); + player->shield_passive_time_left += 10; + player->shield_active_time_left += 10; PlaySoundLevel(x, y, SND_PONG); break; @@ -4895,18 +5274,18 @@ int DigField(struct PlayerInfo *player, } break; - case EL_BELT1_SWITCH_L: - case EL_BELT1_SWITCH_M: - case EL_BELT1_SWITCH_R: - case EL_BELT2_SWITCH_L: - case EL_BELT2_SWITCH_M: - case EL_BELT2_SWITCH_R: - case EL_BELT3_SWITCH_L: - case EL_BELT3_SWITCH_M: - case EL_BELT3_SWITCH_R: - case EL_BELT4_SWITCH_L: - case EL_BELT4_SWITCH_M: - case EL_BELT4_SWITCH_R: + case EL_BELT1_SWITCH_LEFT: + case EL_BELT1_SWITCH_MIDDLE: + case EL_BELT1_SWITCH_RIGHT: + case EL_BELT2_SWITCH_LEFT: + case EL_BELT2_SWITCH_MIDDLE: + case EL_BELT2_SWITCH_RIGHT: + case EL_BELT3_SWITCH_LEFT: + case EL_BELT3_SWITCH_MIDDLE: + case EL_BELT3_SWITCH_RIGHT: + case EL_BELT4_SWITCH_LEFT: + case EL_BELT4_SWITCH_MIDDLE: + case EL_BELT4_SWITCH_RIGHT: if (!player->Switching) { player->Switching = TRUE; @@ -4935,6 +5314,29 @@ int DigField(struct PlayerInfo *player, return MF_ACTION; break; + case EL_TIMEGATE_SWITCH_OFF: + ActivateTimegateSwitch(x, y); + + return MF_ACTION; + break; + + case EL_BALLOON_SEND_LEFT: + case EL_BALLOON_SEND_RIGHT: + case EL_BALLOON_SEND_UP: + case EL_BALLOON_SEND_DOWN: + case EL_BALLOON_SEND_ANY: + if (element == EL_BALLOON_SEND_ANY) + game.balloon_dir = move_direction; + else + game.balloon_dir = (element == EL_BALLOON_SEND_LEFT ? MV_LEFT : + element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT : + element == EL_BALLOON_SEND_UP ? MV_UP : + element == EL_BALLOON_SEND_DOWN ? MV_DOWN : + MV_NO_MOVING); + + return MF_ACTION; + break; + case EL_SP_EXIT: if (local_player->gems_still_needed > 0) return MF_NO_ACTION; @@ -4982,7 +5384,7 @@ int DigField(struct PlayerInfo *player, else if (IS_SP_ELEMENT(element)) PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH); else - PlaySoundLevel(x+dx, y+dy, SND_KLOPF); + PlaySoundLevel(x+dx, y+dy, SND_PUSCH); /* better than "SND_KLOPF" */ break; case EL_PFORTE1: @@ -5036,6 +5438,7 @@ int DigField(struct PlayerInfo *player, break; case EL_SWITCHGATE_OPEN: + case EL_TIMEGATE_OPEN: if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy)) return MF_NO_ACTION; @@ -5128,6 +5531,7 @@ int DigField(struct PlayerInfo *player, case EL_SOKOBAN_OBJEKT: case EL_SONDE: case EL_SP_DISK_YELLOW: + case EL_BALLOON: if (mode == DF_SNAP) return MF_NO_ACTION; @@ -5153,7 +5557,7 @@ int DigField(struct PlayerInfo *player, if (player->push_delay == 0) player->push_delay = FrameCounter; if (!FrameReached(&player->push_delay, player->push_delay_value) && - !tape.playing) + !tape.playing && element != EL_BALLOON) return MF_NO_ACTION; if (IS_SB_ELEMENT(element)) @@ -5182,11 +5586,14 @@ int DigField(struct PlayerInfo *player, Feld[x+dx][y+dy] = element; } - player->push_delay_value = 2; + player->push_delay_value = (element == EL_BALLOON ? 0 : 2); DrawLevelField(x, y); DrawLevelField(x+dx, y+dy); - PlaySoundLevel(x+dx, y+dy, SND_PUSCH); + if (element == EL_BALLOON) + PlaySoundLevel(x+dx, y+dy, SND_SCHLURF); + else + PlaySoundLevel(x+dx, y+dy, SND_PUSCH); if (IS_SB_ELEMENT(element) && local_player->sokobanfields_still_needed == 0 && @@ -5198,7 +5605,6 @@ int DigField(struct PlayerInfo *player, break; - case EL_MAULWURF: case EL_PINGUIN: case EL_SCHWEIN: case EL_DRACHE: