X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=0b731c327dc35ad1276082b0193367580f70fac3;hp=70febf6328c8ce86b4f8c9049a72d96e6b90f435;hb=8be31c2781126204470171aff7af45713ec42e9e;hpb=d2587727d750fdf2aae4eb8f4acb487a5c211041 diff --git a/src/game.c b/src/game.c index 70febf63..0b731c32 100644 --- a/src/game.c +++ b/src/game.c @@ -103,7 +103,7 @@ /* forward declaration for internal use */ static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); -static void KillHeroUnlessShield(struct PlayerInfo *); +static void KillHeroUnlessProtected(int, int); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); @@ -176,6 +176,9 @@ void GetPlayerConfig() setup.sound_music = FALSE; } + if (!fullscreen_available) + setup.fullscreen = FALSE; + setup.sound_simple = setup.sound; InitJoysticks(); @@ -229,8 +232,17 @@ static void InitField(int x, int y, boolean init_game) { switch (Feld[x][y]) { - case EL_SPIELFIGUR: case EL_SP_MURPHY: + if (init_game) + { + if (stored_player[0].present) + { + Feld[x][y] = EL_SP_MURPHY_CLONE; + break; + } + } + /* no break! */ + case EL_SPIELFIGUR: if (init_game) Feld[x][y] = EL_SPIELER1; /* no break! */ @@ -493,7 +505,7 @@ void InitGame() network_player_action_received = FALSE; -#ifndef MSDOS +#if !defined(MSDOS) && !defined(WIN32) /* initial null action */ if (network_playing) SendToServer_MovePlayer(MV_NO_MOVING); @@ -519,6 +531,7 @@ void InitGame() 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++) { @@ -699,20 +712,18 @@ void InitGame() DrawAllPlayers(); FadeToFront(); - /* after drawing the level, corect some elements */ - + /* after drawing the level, correct some elements */ if (game.timegate_time_left == 0) CloseAllOpenTimegates(); if (setup.soft_scrolling) - XCopyArea(display, fieldbuffer, backbuffer, gc, - FX, FY, SXSIZE, SYSIZE, SX, SY); + BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); redraw_mask |= REDRAW_FROM_BACKBUFFER; /* copy default game door content to main double buffer */ - XCopyArea(display, pix[PIX_DOOR], drawto, gc, - DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); + BlitBitmap(pix[PIX_DOOR], drawto, + DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); if (level_nr < 100) DrawText(DX + XX_LEVEL, DY + YY_LEVEL, @@ -721,10 +732,10 @@ void InitGame() { DrawTextExt(drawto, gc, DX + XX_EMERALDS, DY + YY_EMERALDS, int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3); - XCopyArea(display, drawto, drawto, gc, - DX + XX_EMERALDS, DY + YY_EMERALDS + 1, - FONT5_XSIZE * 3, FONT5_YSIZE - 1, - DX + XX_LEVEL - 1, DY + YY_LEVEL + 1); + BlitBitmap(drawto, drawto, + DX + XX_EMERALDS, DY + YY_EMERALDS + 1, + FONT5_XSIZE * 3, FONT5_YSIZE - 1, + DX + XX_LEVEL - 1, DY + YY_LEVEL + 1); } DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS, @@ -744,15 +755,15 @@ void InitGame() MapTapeButtons(); /* copy actual game door content to door double buffer for OpenDoor() */ - XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc, - DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); + BlitBitmap(drawto, pix[PIX_DB_DOOR], + DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); OpenDoor(DOOR_OPEN_ALL); if (setup.sound_music) PlaySoundLoop(background_loop[level_nr % num_bg_loops]); - XAutoRepeatOff(display); + KeyboardAutoRepeatOff(); if (options.verbose) { @@ -965,12 +976,12 @@ void GameWon() SaveTape(tape.level_nr); /* Ask to save tape */ } - if (level_nr == leveldir[leveldir_nr].handicap_level) + if (level_nr == leveldir_current->handicap_level) { - leveldir[leveldir_nr].handicap_level++; - SaveLevelSetup_SeriesInfo(leveldir_nr); + leveldir_current->handicap_level++; + SaveLevelSetup_SeriesInfo(); - if (level_nr < leveldir[leveldir_nr].last_level) + if (level_nr < leveldir_current->last_level) raise_level = TRUE; } @@ -1159,8 +1170,8 @@ void RemoveMovingField(int x, int y) if (Feld[x][y] == EL_BLOCKED && (Store[oldx][oldy] == EL_MORAST_LEER || - Store[oldx][oldy] == EL_SIEB_LEER || - Store[oldx][oldy] == EL_SIEB2_LEER || + Store[oldx][oldy] == EL_MAGIC_WALL_EMPTY || + Store[oldx][oldy] == EL_MAGIC_WALL_BD_EMPTY || Store[oldx][oldy] == EL_AMOEBE_NASS)) { Feld[oldx][oldy] = Store[oldx][oldy]; @@ -1289,7 +1300,7 @@ void Explode(int ex, int ey, int phase, int mode) if (element == EL_EXPLODING) element = Store2[x][y]; - if (IS_PLAYER(ex, ey) && !SHIELD_ON(PLAYERINFO(ex, ey))) + if (IS_PLAYER(ex, ey) && !PLAYER_PROTECTED(ex, ey)) { switch(StorePlayer[ex][ey]) { @@ -1337,6 +1348,10 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = EL_EDELSTEIN_ROT; else if (element == EL_ERZ_EDEL_LILA) Store[x][y] = EL_EDELSTEIN_LILA; + else if (element == EL_WALL_PEARL) + Store[x][y] = EL_PEARL; + else if (element == EL_WALL_CRYSTAL) + Store[x][y] = EL_CRYSTAL; else if (!IS_PFORTE(Store[x][y])) Store[x][y] = EL_LEERRAUM; @@ -1390,7 +1405,7 @@ void Explode(int ex, int ey, int phase, int mode) int element = Store2[x][y]; if (IS_PLAYER(x, y)) - KillHeroUnlessShield(PLAYERINFO(x, y)); + KillHeroUnlessProtected(x, y); else if (IS_EXPLOSIVE(element)) { Feld[x][y] = Store2[x][y]; @@ -1767,17 +1782,25 @@ void Impact(int x, int y) return; } - if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) && + if ((element == EL_BOMBE || + element == EL_SP_DISK_ORANGE || + element == EL_DX_SUPABOMB) && (lastline || object_hit)) /* element is bomb */ { Bang(x, y); return; } + else if (element == EL_PEARL) + { + Feld[x][y] = EL_PEARL_BREAKING; + PlaySoundLevel(x, y, SND_KNACK); + return; + } if (element == EL_TROPFEN && (lastline || object_hit)) /* acid drop */ { if (object_hit && IS_PLAYER(x, y+1)) - KillHeroUnlessShield(PLAYERINFO(x, y+1)); + KillHeroUnlessProtected(x, y+1); else if (object_hit && smashed == EL_PINGUIN) Bang(x, y+1); else @@ -1791,11 +1814,12 @@ void Impact(int x, int y) if (!lastline && object_hit) /* check which object was hit */ { if (CAN_CHANGE(element) && - (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV)) + (smashed == EL_MAGIC_WALL_OFF || smashed == EL_MAGIC_WALL_BD_OFF)) { int x, y; int activated_magic_wall = - (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER); + (smashed == EL_MAGIC_WALL_OFF ? EL_MAGIC_WALL_EMPTY : + EL_MAGIC_WALL_BD_EMPTY); /* activate magic wall / mill */ @@ -1810,7 +1834,7 @@ void Impact(int x, int y) if (IS_PLAYER(x, y+1)) { - KillHeroUnlessShield(PLAYERINFO(x, y+1)); + KillHeroUnlessProtected(x, y+1); return; } else if (smashed == EL_PINGUIN) @@ -1826,10 +1850,13 @@ void Impact(int x, int y) return; } } - else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK) + else if (element == EL_FELSBROCKEN || + element == EL_SP_ZONK || + element == EL_BD_ROCK) { if (IS_ENEMY(smashed) || smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE || + smashed == EL_DX_SUPABOMB || smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE || smashed == EL_MOLE) { @@ -1850,6 +1877,12 @@ void Impact(int x, int y) RaiseScoreElement(EL_KOKOSNUSS); return; } + else if (smashed == EL_PEARL) + { + Feld[x][y+1] = EL_PEARL_BREAKING; + PlaySoundLevel(x, y, SND_KNACK); + return; + } else if (smashed == EL_DIAMANT) { Feld[x][y+1] = EL_LEERRAUM; @@ -1876,7 +1909,8 @@ void Impact(int x, int y) /* play sound of magic wall / mill */ if (!lastline && - (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER)) + (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY || + Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY)) { PlaySoundLevel(x, y, SND_QUIRK); return; @@ -1902,6 +1936,7 @@ void Impact(int x, int y) sound = SND_KLUMPF; break; case EL_FELSBROCKEN: + case EL_BD_ROCK: sound = SND_KLOPF; break; case EL_SP_ZONK: @@ -2213,6 +2248,21 @@ void TurnRound(int x, int y) if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; } + else if (element == EL_BALLOON) + { + MovDir[x][y] = game.balloon_dir; + MovDelay[x][y] = 0; + } + else if (element == EL_SPRING_MOVING) + { + if (!IN_LEV_FIELD(move_x, move_y) || !IS_FREE(move_x, move_y) || + (IN_LEV_FIELD(x, y+1) && IS_FREE(x, y+1))) + { + Feld[x][y] = EL_SPRING; + MovDir[x][y] = MV_NO_MOVING; + } + MovDelay[x][y] = 0; + } else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN) { int attr_x = -1, attr_y = -1; @@ -2396,20 +2446,21 @@ void StartMoving(int x, int y) Feld[x][y+1] = EL_MORAST_VOLL; } } - else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER) + else if ((element == EL_FELSBROCKEN || element == EL_BD_ROCK) && + Feld[x][y+1] == EL_MORAST_LEER) { InitMovingField(x, y, MV_DOWN); Store[x][y] = EL_MORAST_VOLL; } - else if (element == EL_SIEB_VOLL) + else if (element == EL_MAGIC_WALL_FULL) { if (IS_FREE(x, y+1)) { InitMovingField(x, y, MV_DOWN); Feld[x][y] = EL_CHANGED(Store2[x][y]); - Store[x][y] = EL_SIEB_LEER; + Store[x][y] = EL_MAGIC_WALL_EMPTY; } - else if (Feld[x][y+1] == EL_SIEB_LEER) + else if (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY/4 + 1; @@ -2421,21 +2472,21 @@ void StartMoving(int x, int y) return; } - Feld[x][y] = EL_SIEB_LEER; - Feld[x][y+1] = EL_SIEB_VOLL; + Feld[x][y] = EL_MAGIC_WALL_EMPTY; + Feld[x][y+1] = EL_MAGIC_WALL_FULL; Store2[x][y+1] = EL_CHANGED(Store2[x][y]); Store2[x][y] = 0; } } - else if (element == EL_SIEB2_VOLL) + else if (element == EL_MAGIC_WALL_BD_FULL) { if (IS_FREE(x, y+1)) { InitMovingField(x, y, MV_DOWN); Feld[x][y] = EL_CHANGED2(Store2[x][y]); - Store[x][y] = EL_SIEB2_LEER; + Store[x][y] = EL_MAGIC_WALL_BD_EMPTY; } - else if (Feld[x][y+1] == EL_SIEB2_LEER) + else if (Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY/4 + 1; @@ -2447,18 +2498,20 @@ void StartMoving(int x, int y) return; } - Feld[x][y] = EL_SIEB2_LEER; - Feld[x][y+1] = EL_SIEB2_VOLL; + Feld[x][y] = EL_MAGIC_WALL_BD_EMPTY; + Feld[x][y+1] = EL_MAGIC_WALL_BD_FULL; Store2[x][y+1] = EL_CHANGED2(Store2[x][y]); Store2[x][y] = 0; } } else if (CAN_CHANGE(element) && - (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER)) + (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY || + Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY)) { InitMovingField(x, y, MV_DOWN); Store[x][y] = - (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL); + (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ? EL_MAGIC_WALL_FULL : + EL_MAGIC_WALL_BD_FULL); Store2[x][y+1] = element; } else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE) @@ -2485,7 +2538,8 @@ void StartMoving(int x, int y) else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1]) #else else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] && - !IS_FALLING(x, y+1) && !JustStopped[x][y+1]) + !IS_FALLING(x, y+1) && !JustStopped[x][y+1] && + element != EL_DX_SUPABOMB) #endif { boolean left = (x>0 && IS_FREE(x-1, y) && @@ -2495,7 +2549,9 @@ void StartMoving(int x, int y) if (left || right) { - if (left && right && game.emulation != EMU_BOULDERDASH) + if (left && right && + (game.emulation != EMU_BOULDERDASH && + element != EL_BD_ROCK && element != EL_EDELSTEIN_BD)) left = !(right = RND(2)); InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT); @@ -2517,7 +2573,9 @@ void StartMoving(int x, int y) { int newx, newy; - if (element == EL_SONDE && JustBeingPushed(x, y)) + if ((element == EL_SONDE || element == EL_BALLOON || + element == EL_SPRING_MOVING) + && JustBeingPushed(x, y)) return; if (!MovDelay[x][y]) /* start new movement phase */ @@ -2619,7 +2677,7 @@ void StartMoving(int x, int y) Moving2Blocked(x, y, &newx, &newy); /* get next screen position */ if (IS_ENEMY(element) && IS_PLAYER(newx, newy) && - !SHIELD_ON(PLAYERINFO(newx, newy))) + !PLAYER_PROTECTED(newx, newy)) { #if 1 @@ -2633,8 +2691,8 @@ void StartMoving(int x, int y) #endif } - else if ((element == EL_PINGUIN || - element == EL_ROBOT || element == EL_SONDE) && + else if ((element == EL_PINGUIN || element == EL_ROBOT || + element == EL_SONDE || element == EL_BALLOON) && IN_LEV_FIELD(newx, newy) && MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE) { @@ -2812,7 +2870,8 @@ void StartMoving(int x, int y) else if (element == EL_SP_ELECTRON) DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL); - TestIfBadThingHitsHero(x, y); + if (DONT_TOUCH(element)) + TestIfBadThingHitsHero(x, y); return; } @@ -2844,6 +2903,8 @@ void ContinueMoving(int x, int y) else if (CAN_FALL(element) && horiz_move && y < lev_fieldy-1 && IS_BELT(Feld[x][y+1])) step /= 2; + else if (element == EL_SPRING_MOVING) + step*=2; #if OLD_GAME_BEHAVIOUR else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element)) @@ -2894,27 +2955,30 @@ void ContinueMoving(int x, int y) Store[x][y] = 0; Feld[x][y] = EL_MORAST_LEER; } - else if (Store[x][y] == EL_SIEB_VOLL) + else if (Store[x][y] == EL_MAGIC_WALL_FULL) { Store[x][y] = 0; element = Feld[newx][newy] = - (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT); + (game.magic_wall_active ? EL_MAGIC_WALL_FULL : EL_MAGIC_WALL_DEAD); } - else if (Store[x][y] == EL_SIEB_LEER) + else if (Store[x][y] == EL_MAGIC_WALL_EMPTY) { Store[x][y] = Store2[x][y] = 0; - Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT); + Feld[x][y] = (game.magic_wall_active ? EL_MAGIC_WALL_EMPTY : + EL_MAGIC_WALL_DEAD); } - else if (Store[x][y] == EL_SIEB2_VOLL) + else if (Store[x][y] == EL_MAGIC_WALL_BD_FULL) { Store[x][y] = 0; element = Feld[newx][newy] = - (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT); + (game.magic_wall_active ? EL_MAGIC_WALL_BD_FULL : + EL_MAGIC_WALL_BD_DEAD); } - else if (Store[x][y] == EL_SIEB2_LEER) + else if (Store[x][y] == EL_MAGIC_WALL_BD_EMPTY) { Store[x][y] = Store2[x][y] = 0; - Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT); + Feld[x][y] = (game.magic_wall_active ? EL_MAGIC_WALL_BD_EMPTY : + EL_MAGIC_WALL_BD_DEAD); } else if (Store[x][y] == EL_SALZSAEURE) { @@ -3124,7 +3188,7 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element) if (done) PlaySoundLevel(ax, ay, - (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING)); + (new_element == EL_BD_ROCK ? SND_KLOPF : SND_PLING)); } void AmoebeWaechst(int x, int y) @@ -3308,7 +3372,7 @@ void AmoebeAbleger(int ax, int ay) if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200) { - AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN); + AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK); return; } } @@ -3495,7 +3559,8 @@ void NussKnacken(int x, int y) { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) - DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2); + DrawGraphic(SCREENX(x), SCREENY(y), + GFX_CRACKINGNUT + 3 - MovDelay[x][y]/2); if (!MovDelay[x][y]) { @@ -3505,9 +3570,29 @@ void NussKnacken(int x, int y) } } +void BreakingPearl(int x, int y) +{ + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = 9; + + if (MovDelay[x][y]) /* wait some time before next frame */ + { + MovDelay[x][y]--; + if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), + GFX_PEARL_BREAKING + 4 - MovDelay[x][y]/2); + + if (!MovDelay[x][y]) + { + Feld[x][y] = EL_LEERRAUM; + DrawLevelField(x, y); + } + } +} + void SiebAktivieren(int x, int y, int typ) { - int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3; + int graphic = (typ == 1 ? GFX_MAGIC_WALL_FULL : GFX_MAGIC_WALL_BD_FULL) + 3; DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE); } @@ -3709,8 +3794,8 @@ void EdelsteinFunkeln(int x, int y) dest_x = FX + SCREENX(x)*TILEX; dest_y = FY + SCREENY(y)*TILEY; - XCopyArea(display, drawto_field, window, gc, - dest_x, dest_y, TILEX, TILEY, dest_x, dest_y); + BlitBitmap(drawto_field, window, + dest_x, dest_y, TILEX, TILEY, dest_x, dest_y); SetDrawtoField(DRAW_DIRECT); } } @@ -3911,10 +3996,10 @@ static void CheckBuggyBase(int x, int y) if (element == EL_SP_BUG) { - if (!MovDelay[x][y]) /* start activating buggy base */ + if (!MovDelay[x][y]) /* wait some time before activating base */ MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); - if (MovDelay[x][y]) /* wait some time before activating base */ + if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) @@ -3930,7 +4015,7 @@ static void CheckBuggyBase(int x, int y) if (!MovDelay[x][y]) /* start activating buggy base */ MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND); - if (MovDelay[x][y]) /* wait some time before activating base */ + if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) @@ -3967,6 +4052,61 @@ static void CheckBuggyBase(int x, int y) } } +static void CheckTrap(int x, int y) +{ + int element = Feld[x][y]; + + if (element == EL_TRAP_INACTIVE) + { + if (!MovDelay[x][y]) /* wait some time before activating trap */ + MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); + + if (MovDelay[x][y]) + { + MovDelay[x][y]--; + if (MovDelay[x][y]) + return; + + Feld[x][y] = EL_TRAP_ACTIVE; + } + } + else if (element == EL_TRAP_ACTIVE) + { + int delay = 4; + int num_frames = 8; + + if (!MovDelay[x][y]) /* start activating trap */ + MovDelay[x][y] = num_frames * delay; + + if (MovDelay[x][y]) + { + MovDelay[x][y]--; + + if (MovDelay[x][y]) + { + if (!(MovDelay[x][y] % delay)) + { + int phase = MovDelay[x][y]/delay; + + if (phase >= num_frames/2) + phase = num_frames - phase; + + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + DrawGraphic(SCREENX(x),SCREENY(y), GFX_TRAP_INACTIVE + phase - 1); + ErdreichAnbroeckeln(SCREENX(x), SCREENY(y)); + } + } + + return; + } + + Feld[x][y] = EL_TRAP_INACTIVE; + DrawLevelField(x, y); + } + } +} + static void DrawBeltAnimation(int x, int y, int element) { int belt_nr = getBeltNrFromElement(element); @@ -4061,7 +4201,8 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy])) { int el = Feld[jx+dx][jy]; - int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10); + int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : + (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10); if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay) { @@ -4101,7 +4242,7 @@ void GameActions() #endif */ -#ifndef MSDOS +#if !defined(MSDOS) && !defined(WIN32) /* last chance to get network player actions without main loop delay */ HandleNetworking(); #endif @@ -4138,7 +4279,7 @@ void GameActions() stored_player[i].effective_action = stored_player[i].action; } -#ifndef MSDOS +#if !defined(MSDOS) && !defined(WIN32) if (network_playing) SendToServer_MovePlayer(summarized_player_action); #endif @@ -4251,6 +4392,8 @@ void GameActions() Blurb(x, y); else if (element == EL_CRACKINGNUT) NussKnacken(x, y); + else if (element == EL_PEARL_BREAKING) + BreakingPearl(x, y); else if (element == EL_AUSGANG_ZU) AusgangstuerPruefen(x, y); else if (element == EL_AUSGANG_ACT) @@ -4268,6 +4411,8 @@ void GameActions() CheckForDragon(x, y); else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE) CheckBuggyBase(x, y); + else if (element == EL_TRAP_INACTIVE || element == EL_TRAP_ACTIVE) + CheckTrap(x, y); else if (element == EL_SP_TERMINAL) DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL); else if (element == EL_SP_TERMINAL_ACTIVE) @@ -4294,14 +4439,15 @@ void GameActions() boolean sieb = FALSE; int jx = local_player->jx, jy = local_player->jy; - if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL || - Store[x][y] == EL_SIEB_LEER) + if (element == EL_MAGIC_WALL_EMPTY || element == EL_MAGIC_WALL_FULL || + Store[x][y] == EL_MAGIC_WALL_EMPTY) { SiebAktivieren(x, y, 1); sieb = TRUE; } - else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL || - Store[x][y] == EL_SIEB2_LEER) + else if (element == EL_MAGIC_WALL_BD_EMPTY || + element == EL_MAGIC_WALL_BD_FULL || + Store[x][y] == EL_MAGIC_WALL_BD_EMPTY) { SiebAktivieren(x, y, 2); sieb = TRUE; @@ -4330,14 +4476,15 @@ void GameActions() { element = Feld[x][y]; - if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL) + if (element == EL_MAGIC_WALL_EMPTY || element == EL_MAGIC_WALL_FULL) { - Feld[x][y] = EL_SIEB_TOT; + Feld[x][y] = EL_MAGIC_WALL_DEAD; DrawLevelField(x, y); } - else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL) + else if (element == EL_MAGIC_WALL_BD_EMPTY || + element == EL_MAGIC_WALL_BD_FULL) { - Feld[x][y] = EL_SIEB2_TOT; + Feld[x][y] = EL_MAGIC_WALL_BD_DEAD; DrawLevelField(x, y); } } @@ -4415,6 +4562,25 @@ void GameActions() } DrawAllPlayers(); + + if (options.debug) /* calculate frames per second */ + { + static unsigned long fps_counter = 0; + static int fps_frames = 0; + unsigned long fps_delay_ms = Counter() - fps_counter; + + fps_frames++; + + if (fps_delay_ms >= 500) /* calculate fps every 0.5 seconds */ + { + global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms; + + fps_frames = 0; + fps_counter = Counter(); + } + + redraw_mask |= REDRAW_FPS; + } } static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) @@ -4461,13 +4627,13 @@ void ScrollLevel(int dx, int dy) int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); int x, y; - XCopyArea(display, drawto_field, drawto_field, gc, - FX + TILEX*(dx == -1) - softscroll_offset, - FY + TILEY*(dy == -1) - softscroll_offset, - SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset, - SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset, - FX + TILEX*(dx == 1) - softscroll_offset, - FY + TILEY*(dy == 1) - softscroll_offset); + BlitBitmap(drawto_field, drawto_field, + FX + TILEX*(dx == -1) - softscroll_offset, + FY + TILEY*(dy == -1) - softscroll_offset, + SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset, + SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset, + FX + TILEX*(dx == 1) - softscroll_offset, + FY + TILEY*(dy == 1) - softscroll_offset); if (dx) { @@ -4551,14 +4717,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, BuryHero(player); } else - { -#if 1 TestIfBadThingHitsHero(new_jx, new_jy); -#else - if (player->shield_time_left == 0) - KillHero(player); -#endif - } return MF_MOVING; } @@ -4877,7 +5036,7 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) if (player->shield_active_time_left > 0) Bang(killx, killy); - else if (player->shield_passive_time_left == 0) + else if (!PLAYER_PROTECTED(goodx, goody)) KillHero(player); } else @@ -4942,7 +5101,7 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) if (player->shield_active_time_left > 0) Bang(badx, bady); - else if (player->shield_passive_time_left == 0) + else if (!PLAYER_PROTECTED(killx, killy)) KillHero(player); } else @@ -5022,10 +5181,10 @@ void KillHero(struct PlayerInfo *player) BuryHero(player); } -static void KillHeroUnlessShield(struct PlayerInfo *player) +static void KillHeroUnlessProtected(int x, int y) { - if (!SHIELD_ON(player)) - KillHero(player); + if (!PLAYER_PROTECTED(x, y)) + KillHero(PLAYERINFO(x, y)); } void BuryHero(struct PlayerInfo *player) @@ -5087,6 +5246,36 @@ int DigField(struct PlayerInfo *player, if (IS_MOVING(x, y) || IS_PLAYER(x, y)) return MF_NO_ACTION; + if (IS_TUBE(Feld[jx][jy])) + { + int i = 0; + int tube_leave_directions[][2] = + { + { EL_TUBE_CROSS, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, + { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, + { EL_TUBE_VERT_LEFT, MV_LEFT | MV_UP | MV_DOWN }, + { EL_TUBE_VERT_RIGHT, MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_HORIZ_UP, MV_LEFT | MV_RIGHT | MV_UP }, + { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN }, + { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP }, + { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN }, + { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP }, + { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN }, + { -1, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN } + }; + + while (tube_leave_directions[i][0] != Feld[jx][jy]) + { + i++; + if (tube_leave_directions[i][0] == -1) /* should not happen */ + break; + } + + if (!(tube_leave_directions[i][1] & move_direction)) + return MF_NO_ACTION; /* tube has no opening in this direction */ + } + element = Feld[x][y]; switch (element) @@ -5097,6 +5286,7 @@ int DigField(struct PlayerInfo *player, case EL_ERDREICH: case EL_SAND_INVISIBLE: + case EL_TRAP_INACTIVE: Feld[x][y] = EL_LEERRAUM; PlaySoundLevel(x, y, SND_SCHLURF); break; @@ -5114,8 +5304,12 @@ int DigField(struct PlayerInfo *player, case EL_EDELSTEIN_LILA: case EL_DIAMANT: case EL_SP_INFOTRON: + case EL_PEARL: + case EL_CRYSTAL: RemoveField(x, y); - local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1); + local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : + element == EL_PEARL ? 5 : + element == EL_CRYSTAL ? 8 : 1); if (local_player->gems_still_needed < 0) local_player->gems_still_needed = 0; RaiseScoreElement(element); @@ -5311,6 +5505,23 @@ int DigField(struct PlayerInfo *player, 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; @@ -5320,11 +5531,14 @@ int DigField(struct PlayerInfo *player, break; case EL_FELSBROCKEN: + case EL_BD_ROCK: case EL_BOMBE: + case EL_DX_SUPABOMB: case EL_KOKOSNUSS: case EL_ZEIT_LEER: case EL_SP_ZONK: case EL_SP_DISK_ORANGE: + case EL_SPRING: if (dy || mode == DF_SNAP) return MF_NO_ACTION; @@ -5342,23 +5556,29 @@ 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_SPRING) return MF_NO_ACTION; RemoveField(x, y); Feld[x+dx][y+dy] = element; - player->push_delay_value = 2+RND(8); + if (element == EL_SPRING) + { + Feld[x+dx][y+dy] = EL_SPRING_MOVING; + MovDir[x+dx][y+dy] = move_direction; + } + + player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8)); DrawLevelField(x+dx, y+dy); - if (element == EL_FELSBROCKEN) + if (element == EL_FELSBROCKEN || element == EL_BD_ROCK) PlaySoundLevel(x+dx, y+dy, SND_PUSCH); else if (element == EL_KOKOSNUSS) PlaySoundLevel(x+dx, y+dy, SND_KNURK); 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: @@ -5464,7 +5684,47 @@ int DigField(struct PlayerInfo *player, DOUBLE_PLAYER_SPEED(player); PlaySoundLevel(x, y, SND_GATE); + break; + case EL_TUBE_CROSS: + case EL_TUBE_VERTICAL: + case EL_TUBE_HORIZONTAL: + case EL_TUBE_VERT_LEFT: + case EL_TUBE_VERT_RIGHT: + case EL_TUBE_HORIZ_UP: + case EL_TUBE_HORIZ_DOWN: + case EL_TUBE_LEFT_UP: + case EL_TUBE_LEFT_DOWN: + case EL_TUBE_RIGHT_UP: + case EL_TUBE_RIGHT_DOWN: + { + int i = 0; + int tube_enter_directions[][2] = + { + { EL_TUBE_CROSS, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, + { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, + { EL_TUBE_VERT_LEFT, MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_VERT_RIGHT, MV_LEFT | MV_UP | MV_DOWN }, + { EL_TUBE_HORIZ_UP, MV_LEFT | MV_RIGHT | MV_DOWN }, + { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_UP }, + { EL_TUBE_LEFT_UP, MV_RIGHT | MV_DOWN }, + { EL_TUBE_LEFT_DOWN, MV_RIGHT | MV_UP }, + { EL_TUBE_RIGHT_UP, MV_LEFT | MV_DOWN }, + { EL_TUBE_RIGHT_DOWN, MV_LEFT | MV_UP }, + { -1, MV_NO_MOVING } + }; + + while (tube_enter_directions[i][0] != element) + { + i++; + if (tube_enter_directions[i][0] == -1) /* should not happen */ + break; + } + + if (!(tube_enter_directions[i][1] & move_direction)) + return MF_NO_ACTION; /* tube has no opening in this direction */ + } break; case EL_AUSGANG_ZU: @@ -5505,6 +5765,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; @@ -5530,7 +5791,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)) @@ -5559,11 +5820,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 && @@ -5821,7 +6085,7 @@ void CreateGameButtons() for (i=0; i