merged bad_guy patch from Matze Braun. (recycling Ricardo's stalactite patch and...
[supertux.git] / src / gameloop.cpp
index 084be64..4a8d7f2 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <math.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <math.h>
 #include <time.h>
 #include <SDL.h>
 
@@ -37,6 +39,8 @@
 #include "level.h"
 #include "scene.h"
 #include "collision.h"
+#include "tile.h"
+#include "particlesystem.h"
 
 /* extern variables */
 
@@ -50,7 +54,6 @@ static texture_type img_cloud[2][4];
 static SDL_Event event;
 static SDLKey key;
 static char level_subset[100];
-static char str[60];
 static float fps_fps;
 static int st_gl_mode;
 static unsigned int last_update_time;
@@ -69,8 +72,8 @@ void drawresultscreen(void);
 
 void levelintro(void)
 {
+  char str[60];
   /* Level Intro: */
-
   clearscreen(0, 0, 0);
 
   sprintf(str, "LEVEL %d", level);
@@ -97,22 +100,28 @@ void start_timers(void)
 
 void activate_bad_guys(void)
 {
-  int x,y;
-
-  /* Activate bad guys: */
-
-  for (y = 0; y < 15; y++)
+  for (std::vector<BadGuyData>::iterator i = current_level.badguy_data.begin();
+       i != current_level.badguy_data.end();
+       ++i)
     {
-      for (x = 0; x < current_level.width; x++)
-        {
-          if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
-            {
-              add_bad_guy(x * 32, y * 32, current_level.tiles[y][x] - '0');
-              current_level.tiles[y][x] = '.';
-            }
-        }
+      add_bad_guy(i->x, i->y, i->kind);
     }
+}
 
+void activate_particle_systems(void)
+{
+  if(current_level.particle_system == "clouds")
+    {
+      particle_systems.push_back(new CloudParticleSystem);
+    }
+  else if(current_level.particle_system == "snow")
+    {
+      particle_systems.push_back(new SnowParticleSystem);
+    }
+  else if(current_level.particle_system != "")
+    {
+      st_abort("unknown particle system specified in level", "");
+    }
 }
 
 /* --- GAME EVENT! --- */
@@ -133,7 +142,7 @@ void game_event(void)
           if(show_menu)
             menu_event(&event.key.keysym);
 
-          if(player_key_event(&tux,key,DOWN))
+          if(tux.key_event(key,DOWN))
             break;
 
           switch(key)
@@ -145,13 +154,13 @@ void game_event(void)
                     quit = 1;
                   else if(show_menu)
                     {
-                      menu_set_current(&game_menu);
+                      Menu::set_current(game_menu);
                       show_menu = 0;
                       st_pause_ticks_stop();
                     }
                   else
                     {
-                      menu_set_current(&game_menu);
+                      Menu::set_current(game_menu);
                       show_menu = 1;
                       st_pause_ticks_start();
                     }
@@ -164,7 +173,7 @@ void game_event(void)
         case SDL_KEYUP:      /* A keyrelease! */
           key = event.key.keysym.sym;
 
-          if(player_key_event(&tux,key,UP))
+          if(tux.key_event(key, UP))
             break;
 
           switch(key)
@@ -222,9 +231,9 @@ void game_event(void)
             case SDLK_f:
               if(debug_fps)
                 debug_fps = false;
-             else
+              else
                 debug_fps = true;
-              break;         
+              break;
             default:
               break;
             }
@@ -327,11 +336,11 @@ int game_action(void)
               arrays_free();
               return(0);
             }
-          player_level_begin(&tux);
+          tux.level_begin();
         }
       else
         {
-          player_dying(&tux);
+          tux.is_dying();
 
           /* No more lives!? */
 
@@ -356,7 +365,7 @@ int game_action(void)
 
       /* Either way, (re-)load the (next) level... */
 
-      player_level_begin(&tux);
+      tux.level_begin();
       set_defaults();
       level_free(&current_level);
 
@@ -374,6 +383,7 @@ int game_action(void)
       arrays_free();
       arrays_init();
       activate_bad_guys();
+      activate_particle_systems();
       level_free_gfx();
       level_load_gfx(&current_level);
       level_free_song();
@@ -385,10 +395,9 @@ int game_action(void)
       play_current_music();
     }
 
-  player_action(&tux);
+  tux.action();
 
   /* Handle bouncy distros: */
-
   for (i = 0; i < bouncy_distros.size(); i++)
     {
       bouncy_distro_action(&bouncy_distros[i]);
@@ -396,7 +405,6 @@ int game_action(void)
 
 
   /* Handle broken bricks: */
-
   for (i = 0; i < broken_bricks.size(); i++)
     {
       broken_brick_action(&broken_bricks[i]);
@@ -449,7 +457,14 @@ int game_action(void)
 
   for (i = 0; i < bad_guys.size(); i++)
     {
-      badguy_action(&bad_guys[i]);
+      bad_guys[i].action();
+    }
+
+  /* update particle systems */
+  std::vector<ParticleSystem*>::iterator p;
+  for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
+    {
+      (*p)->simulate(frame_ratio);
     }
 
   /* Handle all possible collisions. */
@@ -462,12 +477,10 @@ int game_action(void)
 
 void game_draw(void)
 {
-  int y, s;
-  unsigned int i,x;
+int y,x;
 
   /* Draw screen: */
-
-  if (tux.dying && (frame % 4) == 0)
+  if (tux.dying && (global_frame_counter % 4) == 0)
     clearscreen(255, 255, 255);
   else if(timer_check(&super_bkgd_timer))
     texture_draw(&img_super_bkgd, 0, 0);
@@ -476,7 +489,7 @@ void game_draw(void)
       /* Draw the real background */
       if(current_level.bkgd_image[0] != '\0')
         {
-          s = (int)scroll_x / 30;
+          int s = (int)scroll_x / 30;
           texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
           texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
         }
@@ -486,82 +499,83 @@ void game_draw(void)
         }
     }
 
+  /* Draw particle systems (background) */
+  std::vector<ParticleSystem*>::iterator p;
+  for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
+    {
+      (*p)->draw(scroll_x, 0, 0);
+    }
+
   /* Draw background: */
 
   for (y = 0; y < 15; ++y)
     {
       for (x = 0; x < 21; ++x)
         {
-          drawshape(x * 32 - ((int)scroll_x % 32), y * 32,
-                    current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
+          drawshape(32*x - fmodf(scroll_x, 32), y * 32,
+                    current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
         }
     }
 
+  /* Draw interactive tiles: */
 
-  /* (Bouncy bricks): */
-
-  for (i = 0; i < bouncy_bricks.size(); ++i)
-    {
-      bouncy_brick_draw(&bouncy_bricks[i]);
-    }
-
-
-  /* (Bad guys): */
-
-  for (i = 0; i < bad_guys.size(); ++i)
+  for (y = 0; y < 15; ++y)
     {
-      badguy_draw(&bad_guys[i]);
+      for (x = 0; x < 21; ++x)
+        {
+          drawshape(32*x - fmodf(scroll_x, 32), y * 32,
+                    current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
+        }
     }
 
-  /* (Tux): */
-
-  player_draw(&tux);
+  /* (Bouncy bricks): */
 
-  /* (Bullets): */
+  for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
+    bouncy_brick_draw(&bouncy_bricks[i]);
 
-  for (i = 0; i < bullets.size(); ++i)
-    {
-      bullet_draw(&bullets[i]);
-    }
+  for (unsigned int i = 0; i < bad_guys.size(); ++i)
+    bad_guys[i].draw();
 
-  /* (Floating scores): */
+  tux.draw();
 
-  for (i = 0; i < floating_scores.size(); ++i)
-    {
-      floating_score_draw(&floating_scores[i]);
-    }
+  for (unsigned int i = 0; i < bullets.size(); ++i)
+    bullet_draw(&bullets[i]);
 
+  for (unsigned int i = 0; i < floating_scores.size(); ++i)
+    floating_score_draw(&floating_scores[i]);
 
-  /* (Upgrades): */
+  for (unsigned int i = 0; i < upgrades.size(); ++i)
+    upgrade_draw(&upgrades[i]);
 
-  for (i = 0; i < upgrades.size(); ++i)
-    {
-      upgrade_draw(&upgrades[i]);
-    }
+  for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
+      bouncy_distro_draw(&bouncy_distros[i]);
 
+  for (unsigned int i = 0; i < broken_bricks.size(); ++i)
+    broken_brick_draw(&broken_bricks[i]);
 
-  /* (Bouncy distros): */
+  /* Draw foreground: */
 
-  for (i = 0; i < bouncy_distros.size(); ++i)
+  for (y = 0; y < 15; ++y)
     {
-      bouncy_distro_draw(&bouncy_distros[i]);
+      for (x = 0; x < 21; ++x)
+        {
+          drawshape(32*x - fmodf(scroll_x, 32), y * 32,
+                    current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
+        }
     }
 
-
-  /* (Broken bricks): */
-
-  for (i = 0; i < broken_bricks.size(); ++i)
+  /* Draw particle systems (foreground) */
+  for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
     {
-      broken_brick_draw(&broken_bricks[i]);
+      (*p)->draw(scroll_x, 0, 1);
     }
 
   drawstatus();
 
-
   if(game_pause)
     {
-      x = screen->h / 20;
-      for(i = 0; i < x; ++i)
+      int x = screen->h / 20;
+      for(int i = 0; i < x; ++i)
         {
           fillrect(i % 2 ? (pause_menu_frame * i)%screen->w : -((pause_menu_frame * i)%screen->w) ,(i*20+pause_menu_frame)%screen->h,screen->w,10,20,20,20, rand() % 20 + 1);
         }
@@ -573,10 +587,7 @@ void game_draw(void)
     menu_process_current();
 
   /* (Update it all!) */
-
   updatescreen();
-
-
 }
 
 /* --- GAME LOOP! --- */
@@ -612,9 +623,10 @@ int gameloop(const char * subset, int levelnb, int mode)
 
   level_load_gfx(&current_level);
   activate_bad_guys();
+  activate_particle_systems();
   level_load_song(&current_level);
 
-  player_init(&tux);
+  tux.init();
 
   if(st_gl_mode != ST_GL_TEST)
     load_hs();
@@ -630,13 +642,12 @@ int gameloop(const char * subset, int levelnb, int mode)
   if(st_gl_mode == ST_GL_LOAD_GAME)
     loadgame(levelnb);
 
-
   /* --- MAIN GAME LOOP!!! --- */
 
   jump = false;
   done = 0;
   quit = 0;
-  frame = 0;
+  global_frame_counter = 0;
   game_pause = 0;
   timer_init(&fps_timer,true);
   timer_init(&frame_timer,true);
@@ -652,7 +663,7 @@ int gameloop(const char * subset, int levelnb, int mode)
 
 
   while (SDL_PollEvent(&event))
-    {}
+  {}
 
   game_draw();
   do
@@ -663,11 +674,11 @@ int gameloop(const char * subset, int levelnb, int mode)
       frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
-      
+
       if(!timer_check(&frame_timer))
         {
           timer_start(&frame_timer,25);
-          ++frame;
+          ++global_frame_counter;
         }
 
       /* Handle events: */
@@ -678,18 +689,18 @@ int gameloop(const char * subset, int levelnb, int mode)
 
       if(show_menu)
         {
-          if(current_menu == &game_menu)
+          if(current_menu == game_menu)
             {
-              switch (menu_check(&game_menu))
+              switch (game_menu->check())
                 {
                 case 2:
                   st_pause_ticks_stop();
                   break;
                 case 3:
-                  update_load_save_game_menu(&save_game_menu, false);
+                  update_load_save_game_menu(save_game_menu, false);
                   break;
                 case 4:
-                  update_load_save_game_menu(&load_game_menu, true);
+                  update_load_save_game_menu(load_game_menu, true);
                   break;
                 case 7:
                   st_pause_ticks_stop();
@@ -697,15 +708,15 @@ int gameloop(const char * subset, int levelnb, int mode)
                   break;
                 }
             }
-          else if(current_menu == &options_menu)
+          else if(current_menu == options_menu)
             {
               process_options_menu();
             }
-          else if(current_menu == &save_game_menu )
+          else if(current_menu == save_game_menu )
             {
               process_save_load_game_menu(true);
             }
-          else if(current_menu == &load_game_menu )
+          else if(current_menu == load_game_menu )
             {
               process_save_load_game_menu(false);
             }
@@ -726,8 +737,8 @@ int gameloop(const char * subset, int levelnb, int mode)
               /* == -1: continues */
               return 0;
             }
-         /*  --z;
-              }*/
+          /*  --z;
+                     }*/
         }
       else
         {
@@ -735,7 +746,7 @@ int gameloop(const char * subset, int levelnb, int mode)
           SDL_Delay(50);
         }
 
-      if(debug_mode && debug_fps == true)
+      if(debug_mode && debug_fps)
         SDL_Delay(60);
 
       /*Draw the current scene to the screen */
@@ -758,7 +769,6 @@ int gameloop(const char * subset, int levelnb, int mode)
       last_update_time = update_time;
       update_time = st_get_ticks();
 
-
       /* Pause till next frame, if the machine running the game is too fast: */
       /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
          the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
@@ -783,7 +793,7 @@ int gameloop(const char * subset, int levelnb, int mode)
 
         }
       else
-        player_kill(&tux,KILL);
+        tux.kill(KILL);
 
 
       /* Calculate frames per second */
@@ -1134,7 +1144,21 @@ void loadshared(void)
                "/images/shared/bag-right-1.png",
                USE_ALPHA);
 
+  /* Mr. Bomb */
+  for(int i=0; i<4; ++i) {
+      char num[4];
+      snprintf(num, 4, "%d", i);
+      texture_load(&img_mrbomb_left[i],
+              datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
+      texture_load(&img_mrbomb_right[i],
+              datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
+  }
 
+  /* stalactite */
+  texture_load(&img_stalactite, 
+          datadir + "/images/shared/stalactite.png", USE_ALPHA);
+  texture_load(&img_stalactite_broken,
+          datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
 
   /* Upgrades: */
 
@@ -1261,6 +1285,14 @@ void unloadshared(void)
       texture_free(&img_money_right[i]);
     }
 
+  for(i = 0; i < 4; i++) {
+      texture_free(&img_mrbomb_left[i]);
+      texture_free(&img_mrbomb_right[i]);
+  }
+
+  texture_free(&img_stalactite);
+  texture_free(&img_stalactite_broken);
+
   texture_free(&img_box_full);
   texture_free(&img_box_empty);
 
@@ -1296,10 +1328,29 @@ void unloadshared(void)
 
 /* Draw a tile on the screen: */
 
-void drawshape(float x, float y, unsigned char c)
+void drawshape(float x, float y, unsigned int c)
 {
-  int z;
+  if (c != 0)
+    {
+      Tile* ptile = TileManager::instance()->get(c);
+      if(ptile)
+        {
+          if(ptile->images.size() > 1)
+            {
+              texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
+            }
+          else if (ptile->images.size() == 1)
+            {
+              texture_draw(&ptile->images[0],x,y);
+            }
+          else
+            {
+              printf("Tile not dravable %u\n", c);
+            }
+        }
+    }
 
+  /*
   if (c == 'X' || c == 'x')
     texture_draw(&img_brick[0], x, y);
   else if (c == 'Y' || c == 'y')
@@ -1326,7 +1377,7 @@ void drawshape(float x, float y, unsigned char c)
     texture_draw(&img_solid[3], x, y);
   else if (c == '$')
     {
-      z = (frame / 2) % 6;
+      z = (global_frame_counter / 2) % 6;
 
       if (z < 4)
         texture_draw(&img_distro[z], x, y);
@@ -1337,7 +1388,7 @@ void drawshape(float x, float y, unsigned char c)
     }
   else if (c == '^')
     {
-      z = (frame / 3) % 3;
+      z = (global_frame_counter / 3) % 3;
 
       texture_draw(&img_waves[z], x, y);
     }
@@ -1350,60 +1401,75 @@ void drawshape(float x, float y, unsigned char c)
     }
   else if (c == '\\')
     {
-      z = (frame / 3) % 2;
+      z = (global_frame_counter / 3) % 2;
 
       texture_draw(&img_flag[z], x + 16, y);
     }
   else if (c == '&')
-    texture_draw(&img_water, x, y);
+    texture_draw(&img_water, x, y);*/
+
 }
 
 
 /* What shape is at some position? */
-
-unsigned char shape(float x, float y)
+unsigned int shape(float x, float y)
 {
 
   int xx, yy;
-  unsigned char c;
+  unsigned int c;
 
   yy = ((int)y / 32);
   xx = ((int)x / 32);
 
   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
     {
-      c = current_level.tiles[yy][xx];
+      c = current_level.ia_tiles[yy][xx];
     }
   else
-    c = '.';
+    c = 0;
 
   return(c);
 }
 
-/* Is is ground? */
-
+Tile* gettile(float x, float y)
+{
+  return TileManager::instance()->get(shape(x, y));
+}
 
 bool issolid(float x, float y)
 {
-  return (isbrick(x, y) ||
-          isice(x, y) ||
-          (shape(x, y) == '[') ||
-          (shape(x, y) == '=') ||
-          (shape(x, y) == ']') ||
-          (shape(x, y) == 'A') ||
-          (shape(x, y) == 'B') ||
-          (shape(x, y) == '!') ||
-          (shape(x, y) == 'a'));
+  Tile* tile = TileManager::instance()->get
+               (shape(x,y));
+  if(tile)
+    {
+      if(tile->solid == true)
+        return true;
+      else
+        return false;
+    }
+  else
+    {
+      return false;
+    }
 }
 
 /* Is it a brick? */
 
 bool isbrick(float x, float y)
 {
-  return (shape(x, y) == 'X' ||
-          shape(x, y) == 'x' ||
-          shape(x, y) == 'Y' ||
-          shape(x, y) == 'y');
+  Tile* tile = TileManager::instance()->get
+               (shape(x,y));
+  if(tile)
+    {
+      if(tile->brick == true)
+        return true;
+      else
+        return false;
+    }
+  else
+    {
+      return false;
+    }
 }
 
 
@@ -1411,28 +1477,56 @@ bool isbrick(float x, float y)
 
 bool isice(float x, float y)
 {
-  return (shape(x, y) == '#');
+  Tile* tile = TileManager::instance()->get
+               (shape(x,y));
+  if(tile)
+    {
+      if(tile->ice == true)
+        return true;
+      else
+        return false;
+    }
+  else
+    {
+      return false;
+    }
 }
 
 /* Is it a full box? */
 
 bool isfullbox(float x, float y)
 {
-  return (shape(x, y) == 'A' ||
-          shape(x, y) == 'B' ||
-          shape(x, y) == '!');
+  Tile* tile = TileManager::instance()->get
+               (shape(x,y));
+  if(tile)
+    {
+      if(tile->fullbox == true)
+        return true;
+      else
+        return false;
+    }
+  else
+    {
+      return false;
+    }
+}
+
+bool isdistro(float x, float y)
+{
+  Tile* tile = TileManager::instance()->get(shape(x,y));
+  return tile && tile->distro;
 }
 
 /* Break a brick: */
 
 void trybreakbrick(float x, float y)
 {
-  if (isbrick(x, y))
+  Tile* tile = gettile(x, y);
+  if (tile->brick)
     {
-      if (shape(x, y) == 'x' || shape(x, y) == 'y')
+      if (tile->data > 0)
         {
           /* Get a distro from it: */
-
           add_bouncy_distro(((int)(x + 1) / 32) * 32,
                             (int)(y / 32) * 32);
 
@@ -1443,7 +1537,7 @@ void trybreakbrick(float x, float y)
             }
 
           if (distro_counter <= 0)
-            level_change(&current_level,x, y, 'a');
+            level_change(&current_level,x, y, TM_IA, tile->next_tile2);
 
           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
           score = score + SCORE_DISTRO;
@@ -1452,8 +1546,7 @@ void trybreakbrick(float x, float y)
       else
         {
           /* Get rid of it: */
-
-          level_change(&current_level,x, y,'.');
+          level_change(&current_level,x, y, TM_IA, tile->next_tile);
         }
 
 
@@ -1484,35 +1577,36 @@ void bumpbrick(float x, float y)
 
 
 /* Empty a box: */
-
 void tryemptybox(float x, float y, int col_side)
 {
-  if (!isfullbox(x, y))
+  Tile* tile = gettile(x,y);
+  if (!tile->fullbox)
     return;
 
   // according to the collision side, set the upgrade direction
-
   if(col_side == LEFT)
     col_side = RIGHT;
   else
     col_side = LEFT;
 
-  switch(shape(x,y))
+  switch(tile->data)
     {
-    case 'A':      /* Box with a distro! */
+    case 1: //'A':      /* Box with a distro! */
       add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
       score = score + SCORE_DISTRO;
       distros++;
       break;
-    case 'B':      /* Add an upgrade! */
+
+    case 2: // 'B':      /* Add an upgrade! */
       if (tux.size == SMALL)     /* Tux is small, add mints! */
         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
       else     /* Tux is big, add coffee: */
         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
       play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
       break;
-    case '!':     /* Add a golden herring */
+
+    case 3:// '!':     /* Add a golden herring */
       add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
       break;
     default:
@@ -1520,17 +1614,16 @@ void tryemptybox(float x, float y, int col_side)
     }
 
   /* Empty the box: */
-  level_change(&current_level,x, y, 'a');
+  level_change(&current_level,x, y, TM_IA, tile->next_tile);
 }
 
-
 /* Try to grab a distro: */
-
 void trygrabdistro(float x, float y, int bounciness)
 {
-  if (shape(x, y) == '$')
+  Tile* tile = gettile(x, y);
+  if (tile && tile->distro)
     {
-      level_change(&current_level,x, y, '.');
+      level_change(&current_level,x, y, TM_IA, tile->next_tile);
       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
 
       if (bounciness == BOUNCE)
@@ -1545,30 +1638,21 @@ void trygrabdistro(float x, float y, int bounciness)
 }
 
 /* Try to bump a bad guy from below: */
-
 void trybumpbadguy(float x, float y)
 {
-  unsigned int i;
-
   /* Bad guys: */
-  for (i = 0; i < bad_guys.size(); i++)
+  for (unsigned int i = 0; i < bad_guys.size(); i++)
     {
       if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
           bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
         {
-          if (bad_guys[i].kind == BAD_BSOD ||
-              bad_guys[i].kind == BAD_LAPTOP)
-            {
-              bad_guys[i].dying = DYING_FALLING;
-              bad_guys[i].base.ym = -8;
-              play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
-            }
+          bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
         }
     }
 
 
   /* Upgrades: */
-  for (i = 0; i < upgrades.size(); i++)
+  for (unsigned int i = 0; i < upgrades.size(); i++)
     {
       if (upgrades[i].base.height == 32 &&
           upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
@@ -1584,7 +1668,7 @@ void trybumpbadguy(float x, float y)
 /* (Status): */
 void drawstatus(void)
 {
-  int i;
+  char str[60];
 
   sprintf(str, "%d", score);
   text_draw(&white_text, "SCORE", 0, 0, 1);
@@ -1601,7 +1685,7 @@ void drawstatus(void)
       text_draw(&white_text,"Press ESC To Return",0,20,1);
     }
 
-  if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
+  if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
     {
       sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
       text_draw(&white_text, "TIME", 224, 0, 1);
@@ -1621,7 +1705,7 @@ void drawstatus(void)
       text_draw(&gold_text, str, screen->h + 60, 40, 1);
     }
 
-  for(i=0; i < tux.lives; ++i)
+  for(int i=0; i < tux.lives; ++i)
     {
       texture_draw(&tux_life,565+(18*i),20);
     }
@@ -1677,7 +1761,6 @@ void savegame(int slot)
   if (fi == NULL)
     {
       fprintf(stderr, "Warning: I could not open the slot file ");
-
     }
   else
     {
@@ -1687,7 +1770,7 @@ void savegame(int slot)
       fwrite(&score,sizeof(int),1,fi);
       fwrite(&distros,sizeof(int),1,fi);
       fwrite(&scroll_x,sizeof(float),1,fi);
-      fwrite(&tux,sizeof(player_type),1,fi);
+      fwrite(&tux,sizeof(Player),1,fi);
       timer_fwrite(&tux.invincible_timer,fi);
       timer_fwrite(&tux.skidding_timer,fi);
       timer_fwrite(&tux.safe_timer,fi);
@@ -1730,6 +1813,7 @@ void loadgame(int slot)
       arrays_free();
       arrays_init();
       activate_bad_guys();
+      activate_particle_systems();
       level_free_gfx();
       level_load_gfx(&current_level);
       level_free_song();
@@ -1740,7 +1824,7 @@ void loadgame(int slot)
       fread(&score,sizeof(int),1,fi);
       fread(&distros,sizeof(int),1,fi);
       fread(&scroll_x,sizeof(float),1,fi);
-      fread(&tux,sizeof(player_type),1,fi);
+      fread(&tux, sizeof(Player), 1, fi);
       timer_fread(&tux.invincible_timer,fi);
       timer_fread(&tux.skidding_timer,fi);
       timer_fread(&tux.safe_timer,fi);
@@ -1785,6 +1869,5 @@ void slotinfo(char **pinfo, int slot)
 
   *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));
   strcpy(*pinfo,tmp);
-
 }