rnd-20040928-1-src
[rocksndiamonds.git] / src / game.c
index d43970cad7e203ffbb0f57dc74e884168fbf8c27..087c63e25c7bc2b2b5ccf2f4964a1c495c9f2425 100644 (file)
 #define USE_NEW_AMOEBA_CODE    FALSE
 
 /* EXPERIMENTAL STUFF */
-#define USE_NEW_MOVEMENT       FALSE
-#define USE_NEW_MOVE_DELAY     TRUE   *1
-#define USE_NEW_PUSH_DELAY     TRUE   *1
+#define USE_NEW_STUFF          TRUE                            * 1
+
+#define USE_NEW_MOVE_STYLE     TRUE    * USE_NEW_STUFF         * 1
+#define USE_NEW_MOVE_DELAY     TRUE    * USE_NEW_STUFF         * 1
+#define USE_NEW_PUSH_DELAY     TRUE    * USE_NEW_STUFF         * 1
+#define USE_NEW_BLOCK_STYLE    TRUE    * USE_NEW_STUFF         * 1 * 1
+#define USE_NEW_SP_SLIPPERY    TRUE    * USE_NEW_STUFF         * 1
+#define USE_NEW_RANDOMIZE      TRUE    * USE_NEW_STUFF         * 1
+
+#define USE_PUSH_BUGFIX                TRUE    * USE_NEW_STUFF         * 1
 
 /* for DigField() */
 #define DF_NO_PUSH             0
@@ -768,6 +775,24 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
                                level.sp_block_last_field :
                                level.block_last_field);
 
+#if USE_NEW_BLOCK_STYLE
+#if 1
+    player->block_delay = (player->block_last_field ?
+                          (element == EL_SP_MURPHY ?
+                           level.sp_block_delay :
+                           level.block_delay) : 0);
+#else
+    player->block_delay = (element == EL_SP_MURPHY ?
+                          (player->block_last_field ? 7 : 1) :
+                          (player->block_last_field ? 7 : 1));
+#endif
+
+#if 0
+    printf("::: block_last_field == %d, block_delay = %d\n",
+          player->block_last_field, player->block_delay);
+#endif
+#endif
+
     if (!options.network || player->connected)
     {
       player->active = TRUE;
@@ -1099,6 +1124,14 @@ void DrawGameDoorValues()
   DrawGameValue_Time(TimeLeft);
 }
 
+void DrawGameDoorValues_EM(int emeralds, int dynamite, int score, int time)
+{
+  DrawGameValue_Emeralds(emeralds);
+  DrawGameValue_Dynamite(dynamite);
+  DrawGameValue_Score(score);
+  DrawGameValue_Time(time);
+}
+
 static void resolve_group_element(int group_element, int recursion_depth)
 {
   static int group_nr;
@@ -1157,7 +1190,7 @@ static void resolve_group_element(int group_element, int recursion_depth)
 
 /*
   =============================================================================
- InitGameEngine()
 InitGameEngine()
   -----------------------------------------------------------------------------
   initialize game engine due to level / tape version number
   =============================================================================
@@ -1171,6 +1204,40 @@ static void InitGameEngine()
   game.engine_version = (tape.playing ? tape.engine_version :
                         level.game_version);
 
+  /* ---------------------------------------------------------------------- */
+  /* set flags for bugs and changes according to active game engine version */
+  /* ---------------------------------------------------------------------- */
+
+  /*
+    Type of bug/change:
+    Before 3.1.0, custom elements that "change when pushing" changed directly
+    after the player started pushing them (until then handled in "DigField()").
+    Since 3.1.0, these custom elements are not changed until the "pushing"
+    move of the element is finished (now handled in "ContinueMoving()").
+
+    Affected levels/tapes:
+    The first condition is generally needed for all levels/tapes before version
+    3.1.0, which might use the old behaviour before it was changed; known tapes
+    that are affected are some tapes from the level set "Walpurgis Gardens" by
+    Jamie Cullen.
+    The second condition is an exception from the above case and is needed for
+    the special case of tapes recorded with game (not engine!) version 3.1.0 or
+    above (including some development versions of 3.1.0), but before it was
+    known that this change would break tapes like the above and was fixed in
+    3.1.1, so that the changed behaviour was active although the engine version
+    while recording maybe was before 3.1.0. There is at least one tape that is
+    affected by this exception, which is the tape for the one-level set "Bug
+    Machine" by Juergen Bonhagen.
+  */
+
+  game.use_bug_change_when_pushing =
+    (game.engine_version < VERSION_IDENT(3,1,0,0) &&
+     !(tape.playing &&
+       tape.game_version >= VERSION_IDENT(3,1,0,0) &&
+       tape.game_version <  VERSION_IDENT(3,1,1,0)));
+
+  /* ---------------------------------------------------------------------- */
+
   /* dynamically adjust element properties according to game engine version */
   InitElementPropertiesEngine(game.engine_version);
 
@@ -1385,8 +1452,16 @@ static void InitGameEngine()
     {
       if (IS_SP_ELEMENT(i))
       {
+#if USE_NEW_MOVE_STYLE
+       /* set SP push delay to just enough to push under a falling zonk */
+       int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6);
+
+       element_info[i].push_delay_fixed  = delay;
+       element_info[i].push_delay_random = 0;
+#else
        element_info[i].push_delay_fixed  = 6;  /* just enough to escape ... */
        element_info[i].push_delay_random = 0;  /* ... from falling zonk     */
+#endif
       }
     }
   }
@@ -1511,7 +1586,9 @@ void InitGame()
 
     player->use_murphy_graphic = FALSE;
 
-    player->block_last_field = FALSE;
+    player->block_last_field = FALSE;  /* initialized in InitPlayerField() */
+    player->block_delay = -1;          /* initialized in InitPlayerField() */
+
     player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
 
     player->actual_frame_counter = 0;
@@ -1776,6 +1853,11 @@ void InitGame()
          player->element_nr = some_player->element_nr;
 #endif
 
+#if USE_NEW_BLOCK_STYLE
+         player->block_last_field = some_player->block_last_field;
+         player->block_delay = some_player->block_delay;
+#endif
+
          StorePlayer[jx][jy] = player->element_nr;
          player->jx = player->last_jx = jx;
          player->jy = player->last_jy = jy;
@@ -1978,18 +2060,27 @@ void InitGame()
 
   CloseDoor(DOOR_CLOSE_1);
 
-  DrawLevel();
-  DrawAllPlayers();
+  /* !!! FIX THIS (START) !!! */
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    InitGameEngine_EM();
+  }
+  else
+  {
+    DrawLevel();
+    DrawAllPlayers();
 
-  /* after drawing the level, correct some elements */
-  if (game.timegate_time_left == 0)
-    CloseAllOpenTimegates();
+    /* after drawing the level, correct some elements */
+    if (game.timegate_time_left == 0)
+      CloseAllOpenTimegates();
 
-  if (setup.soft_scrolling)
-    BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+    if (setup.soft_scrolling)
+      BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
 
-  redraw_mask |= REDRAW_FROM_BACKBUFFER;
-  FadeToFront();
+    redraw_mask |= REDRAW_FROM_BACKBUFFER;
+    FadeToFront();
+  }
+  /* !!! FIX THIS (END) !!! */
 
   /* copy default game door content to main double buffer */
   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
@@ -2030,6 +2121,15 @@ void InitGame()
 #endif
 }
 
+void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y)
+{
+  /* this is used for non-R'n'D game engines to update certain engine values */
+
+  /* needed to determine if sounds are played within the visible screen area */
+  scroll_x = actual_scroll_x;
+  scroll_y = actual_scroll_y;
+}
+
 void InitMovDir(int x, int y)
 {
   int i, element = Feld[x][y];
@@ -4597,8 +4697,15 @@ 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 1
+    /* !!! this bugfix breaks at least BD2K3, level 010 !!! [re-recorded] */
+    if (!IN_LEV_FIELD(xx, yy) ||
+        (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy])))
+      MovDir[x][y] = old_move_dir;
+#else
     if (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))
       MovDir[x][y] = old_move_dir;
+#endif
 
     MovDelay[x][y] = 0;
   }
@@ -5064,7 +5171,13 @@ inline static void TurnRoundExt(int x, int y)
 
     MovDir[x][y] = new_move_dir;
     if (old_move_dir != new_move_dir)
+    {
+#if 1
+      MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+#else
       MovDelay[x][y] = 9;
+#endif
+    }
   }
 }
 
@@ -5392,13 +5505,39 @@ void StartMoving(int x, int y)
        can_fall_both = (can_fall_left && can_fall_right);
       }
 
+#if USE_NEW_SP_SLIPPERY
+      /* !!! better use the same properties as for custom elements here !!! */
+      else if (game.engine_version >= VERSION_IDENT(3,1,1,0) &&
+              can_fall_both && IS_SP_ELEMENT(Feld[x][y + 1]))
+      {
+       can_fall_right = FALSE;         /* slip down on left side */
+       can_fall_both = FALSE;
+      }
+#endif
+
+#if 1
+      if (can_fall_both)
+      {
+       if (game.emulation == EMU_BOULDERDASH ||
+           element == EL_BD_ROCK || element == EL_BD_DIAMOND)
+         can_fall_right = FALSE;       /* slip down on left side */
+       else
+         can_fall_left = !(can_fall_right = RND(2));
+
+       can_fall_both = FALSE;
+      }
+#endif
+
       if (can_fall_any)
       {
+#if 0
        if (can_fall_both &&
            (game.emulation != EMU_BOULDERDASH &&
             element != EL_BD_ROCK && element != EL_BD_DIAMOND))
          can_fall_left = !(can_fall_right = RND(2));
+#endif
 
+       /* if not determined otherwise, prefer left side for slipping down */
        InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT);
        started_moving = TRUE;
       }
@@ -6400,7 +6539,7 @@ void ContinueMoving(int x, int y)
   else if (element == EL_PENGUIN)
     TestIfFriendTouchesBadThing(newx, newy);
 
-#if USE_NEW_MOVEMENT
+#if USE_NEW_MOVE_STYLE
 #if 0
   if (CAN_FALL(element) && direction == MV_DOWN &&
       (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) &&
@@ -6411,7 +6550,8 @@ void ContinueMoving(int x, int y)
   /* give the player one last chance (one more frame) to move away */
   if (CAN_FALL(element) && direction == MV_DOWN &&
       (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) &&
-      !IS_PLAYER(x, newy + 1))
+      (!IS_PLAYER(x, newy + 1) ||
+       game.engine_version < VERSION_IDENT(3,1,1,0)))
     Impact(x, newy);
 #else
   if (CAN_FALL(element) && direction == MV_DOWN &&
@@ -6420,7 +6560,17 @@ void ContinueMoving(int x, int y)
 #endif
 
 #if 1
+
+#if USE_PUSH_BUGFIX
+#if 1
+  if (pushed_by_player && !game.use_bug_change_when_pushing)
+#else
+  if (pushed_by_player && game.engine_version >= VERSION_IDENT(3,1,0,0))
+#endif
+#else
   if (pushed_by_player)
+#endif
+
   {
 #if 1
     int dig_side = MV_DIR_OPPOSITE(direction);
@@ -8388,8 +8538,8 @@ void AdvanceFrameAndPlayerCounters(int player_nr)
 
 void GameActions()
 {
-  static unsigned long action_delay = 0;
-  unsigned long action_delay_value;
+  static unsigned long game_frame_delay = 0;
+  unsigned long game_frame_delay_value;
   int magic_wall_x = 0, magic_wall_y = 0;
   int i, x, y, element, graphic;
   byte *recorded_player_action;
@@ -8401,15 +8551,15 @@ void GameActions()
   if (game_status != GAME_MODE_PLAYING)
     return;
 
-  action_delay_value =
+  game_frame_delay_value =
     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
 
   if (tape.playing && tape.warp_forward && !tape.pausing)
-    action_delay_value = 0;
+    game_frame_delay_value = 0;
 
   /* ---------- main game synchronization point ---------- */
 
-  WaitUntilDelayReached(&action_delay, action_delay_value);
+  WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value);
 
   if (network_playing && !network_player_action_received)
   {
@@ -8448,6 +8598,7 @@ void GameActions()
   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
 
 #if 1
+  /* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
   if (recorded_player_action == NULL && tape.pausing)
     return;
 #endif
@@ -8580,7 +8731,7 @@ void GameActions()
 #endif
 
 #if 1
-  /* for downwards compatibility, the following code emulates a fixed bug that
+  /* for backwards compatibility, the following code emulates a fixed bug that
      occured when pushing elements (causing elements that just made their last
      pushing step to already (if possible) make their first falling step in the
      same game frame, which is bad); this code is also needed to use the famous
@@ -8627,6 +8778,16 @@ void GameActions()
     Changed[x][y] = CE_BITMASK_DEFAULT;
     ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
 
+#if USE_NEW_BLOCK_STYLE
+    /* this must be handled before main playfield loop */
+    if (Feld[x][y] == EL_PLAYER_IS_LEAVING)
+    {
+      MovDelay[x][y]--;
+      if (MovDelay[x][y] <= 0)
+       RemoveField(x, y);
+    }
+#endif
+
 #if DEBUG
     if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1)
     {
@@ -9111,6 +9272,12 @@ void GameActions()
     local_player->show_envelope = 0;
   }
 #endif
+
+#if USE_NEW_RANDOMIZE
+  /* use random number generator in every frame to make it less predictable */
+  if (game.engine_version >= VERSION_IDENT(3,1,1,0))
+    RND(1);
+#endif
 }
 
 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
@@ -9830,13 +9997,14 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     */
     player->is_moving = FALSE;
 
-#if USE_NEW_MOVEMENT
+#if USE_NEW_MOVE_STYLE
     /* player is ALLOWED to move, but CANNOT move (something blocks his way) */
     /* ensure that the player is also allowed to move in the next frame */
     /* (currently, the player is forced to wait eight frames before he can try
        again!!!) */
 
-    player->move_delay = -1;   /* allow direct movement in the next frame */
+    if (game.engine_version >= VERSION_IDENT(3,1,1,0))
+      player->move_delay = 0;  /* allow direct movement in the next frame */
 #endif
   }
 
@@ -9871,14 +10039,37 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
     player->actual_frame_counter = FrameCounter;
     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
-#if USE_NEW_MOVEMENT
-    if (player->block_last_field &&
+#if 0
+    printf("::: %06d: %d,%d: %d (%d) [%d]\n",
+          FrameCounter,
+          last_jx, last_jy, Feld[last_jx][last_jy], EL_EXPLOSION,
+          player->block_delay);
+#endif
+
+#if USE_NEW_BLOCK_STYLE
+
+#if 0
+    if (player->block_delay <= 0)
+      printf("::: ALERT! block_delay == %d\n", player->block_delay);
+#endif
+
+    if (player->block_delay > 0 &&
+       Feld[last_jx][last_jy] == EL_EMPTY)
+    {
+      Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
+      MovDelay[last_jx][last_jy] = player->block_delay + 1;
+    }
+#else
+#if USE_NEW_MOVE_STYLE
+    if ((game.engine_version < VERSION_IDENT(3,1,1,0) ||
+        player->block_last_field) &&
        Feld[last_jx][last_jy] == EL_EMPTY)
       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
 #else
     if (Feld[last_jx][last_jy] == EL_EMPTY)
       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
 #endif
+#endif
 
 #if 0
     DrawPlayer(player);
@@ -9892,9 +10083,16 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
+#if USE_NEW_BLOCK_STYLE
+#else
   if (!player->block_last_field &&
       Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
+#if 1
+    RemoveField(last_jx, last_jy);
+#else
     Feld[last_jx][last_jy] = EL_EMPTY;
+#endif
+#endif
 
   /* before DrawPlayer() to draw correct player graphic for this case */
   if (player->MovPos == 0)
@@ -9931,9 +10129,16 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
     }
 #endif
 
+#if USE_NEW_BLOCK_STYLE
+#else
     if (player->block_last_field &&
        Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
+#if 1
+      RemoveField(last_jx, last_jy);
+#else
       Feld[last_jx][last_jy] = EL_EMPTY;
+#endif
+#endif
 
     player->last_jx = jx;
     player->last_jy = jy;
@@ -11575,12 +11780,28 @@ int DigField(struct PlayerInfo *player,
        else
          player->push_delay_value = -1;        /* get new value later */
 
+#if USE_PUSH_BUGFIX
+       /* now: check for element change _after_ element has been pushed! */
+#if 1
+       if (game.use_bug_change_when_pushing)
+#else
+       if (game.engine_version < VERSION_IDENT(3,1,0,0))
+#endif
+       {
+         CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
+                                    player->index_bit, dig_side);
+         CheckTriggeredElementChangeByPlayer(x,y,element,CE_OTHER_GETS_PUSHED,
+                                             player->index_bit, dig_side);
+       }
+
+#else
+
 #if 1
        /* check for element change _after_ element has been pushed! */
 #else
 
 #if 1
-      /* !!! TEST ONLY !!! */
+       /* !!! TEST ONLY !!! */
        CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
                                   player->index_bit, dig_side);
        CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
@@ -11591,6 +11812,8 @@ int DigField(struct PlayerInfo *player,
        CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
                                   player->index_bit, dig_side);
 #endif
+#endif
+
 #endif
 
        break;
@@ -12180,6 +12403,151 @@ static void PlayLevelMusic()
     PlayMusic(MAP_NOCONF_MUSIC(level_nr));     /* from music dir */
 }
 
+void PlayLevelSound_EM(int x, int y, int element_em, int sample)
+{
+  int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0);
+
+#if 0
+  if (sample == SAMPLE_bug)
+    printf("::: PlayLevelSound_EM: %d, %d: %d\n", x, y, sample);
+#endif
+
+  switch (sample)
+  {
+    case SAMPLE_blank:
+      PlayLevelSoundElementAction(x, y, element, ACTION_WALKING);
+      break;
+
+    case SAMPLE_roll:
+      PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
+      break;
+
+    case SAMPLE_stone:
+      PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+      break;
+
+    case SAMPLE_nut:
+      PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+      break;
+
+    case SAMPLE_crack:
+      PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
+      break;
+
+    case SAMPLE_bug:
+      PlayLevelSoundElementAction(x, y, EL_BUG, ACTION_MOVING);
+      break;
+
+    case SAMPLE_tank:
+      PlayLevelSoundElementAction(x, y, EL_SPACESHIP, ACTION_MOVING);
+      break;
+
+    case SAMPLE_android:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+      break;
+
+    case SAMPLE_spring:
+      PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+      break;
+
+    case SAMPLE_slurp:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DYING);
+      break;
+
+    case SAMPLE_eater:
+      PlayLevelSoundElementAction(x, y, EL_YAMYAM, ACTION_WAITING);
+      break;
+
+    case SAMPLE_alien:
+      PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+      break;
+
+    case SAMPLE_collect:
+      PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
+      break;
+
+    case SAMPLE_diamond:
+      PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+      break;
+
+    case SAMPLE_squash:
+      PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
+      break;
+
+    case SAMPLE_wonderfall:
+      PlayLevelSoundElementAction(x, y, EL_MAGIC_WALL, ACTION_FILLING);
+      break;
+
+    case SAMPLE_drip:
+      PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+      break;
+
+    case SAMPLE_push:
+      PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
+      break;
+
+    case SAMPLE_dirt:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
+      break;
+
+    case SAMPLE_acid:
+      PlayLevelSound(x, y, SND_ACID_SPLASHING);
+      break;
+
+    case SAMPLE_ball:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+      break;
+
+    case SAMPLE_grow:
+      PlayLevelSoundElementAction(x, y, element, ACTION_GROWING);
+      break;
+
+    case SAMPLE_wonder:
+      PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+      break;
+
+    case SAMPLE_door:
+      PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
+      break;
+
+    case SAMPLE_exit:
+      PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
+      break;
+
+    case SAMPLE_dynamite:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+      break;
+
+    case SAMPLE_tick:
+      PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+      break;
+
+    case SAMPLE_press:
+      PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
+      break;
+
+    case SAMPLE_wheel:
+      PlaySoundStereo(SND_MAGIC_WALL_ACTIVE, SOUND_MIDDLE);
+      break;
+
+    case SAMPLE_boom:
+      PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING);
+      break;
+
+    case SAMPLE_time:
+      PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
+      break;
+
+    case SAMPLE_die:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DYING);
+      break;
+
+    default:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DEFAULT);
+      break;
+  }
+}
+
 void RaiseScore(int value)
 {
   local_player->score += value;