new levelformat with multiple layers and and new tileset code. Along with a new parti...
authorTobias Gläßer <tobi.web@gmx.de>
Wed, 24 Mar 2004 22:25:33 +0000 (22:25 +0000)
committerTobias Gläßer <tobi.web@gmx.de>
Wed, 24 Mar 2004 22:25:33 +0000 (22:25 +0000)
SVN-Revision: 345

13 files changed:
src/gameloop.cpp
src/gameloop.h
src/level.cpp
src/level.h
src/leveleditor.cpp
src/particlesystem.cpp [new file with mode: 0644]
src/particlesystem.h [new file with mode: 0644]
src/player.cpp
src/scene.h
src/setup.cpp
src/texture.cpp
src/tile.cpp [new file with mode: 0644]
src/tile.h [new file with mode: 0644]

index d5097b3..13347ad 100644 (file)
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <math.h>
 #include <time.h>
 #include <SDL.h>
 
@@ -38,6 +39,8 @@
 #include "level.h"
 #include "scene.h"
 #include "collision.h"
+#include "tile.h"
+#include "particlesystem.h"
 
 /* extern variables */
 
@@ -105,14 +108,30 @@ void activate_bad_guys(void)
     {
       for (x = 0; x < current_level.width; x++)
         {
-          if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
+          if (current_level.dn_tiles[y][x] >= '0' && current_level.dn_tiles[y][x] <= '9')
             {
-              add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(current_level.tiles[y][x] - '0'));
-              current_level.tiles[y][x] = '.';
+              add_bad_guy(x * 32, y * 32,  static_cast<BadGuyKind>(current_level.dn_tiles[y][x] - '0'));
+              current_level.dn_tiles[y][x] = 0;
             }
         }
     }
+}
 
+void activate_particle_systems(void)
+{
+  printf("PSys: %s\n", current_level.particle_system.c_str());
+  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! --- */
@@ -222,9 +241,9 @@ void game_event(void)
             case SDLK_f:
               if(debug_fps)
                 debug_fps = false;
-             else
+              else
                 debug_fps = true;
-              break;         
+              break;
             default:
               break;
             }
@@ -374,6 +393,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();
@@ -450,6 +470,13 @@ int game_action(void)
       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. */
   collision_handler();
 
@@ -460,6 +487,8 @@ int game_action(void)
 
 void game_draw(void)
 {
+int y,x;
+
   /* Draw screen: */
   if (tux.dying && (global_frame_counter % 4) == 0)
     clearscreen(255, 255, 255);
@@ -480,11 +509,36 @@ void game_draw(void)
         }
     }
 
-  // Draw background:
-  for (int y = 0; y < 15; ++y)
-    for (int x = 0; x < 21; ++x)
-      drawshape(32*x - fmodf(scroll_x, 32), y * 32,
-                current_level.tiles[y][x + (int)(scroll_x / 32)]);
+  /* 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(32*x - fmodf(scroll_x, 32), y * 32,
+                    current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
+        }
+    }
+
+  /* Draw interactive tiles: */
+
+  for (y = 0; y < 15; ++y)
+    {
+      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)]);
+        }
+    }
+
+  /* (Bouncy bricks): */
 
   for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
     bouncy_brick_draw(&bouncy_bricks[i]);
@@ -509,6 +563,23 @@ void game_draw(void)
   for (unsigned int i = 0; i < broken_bricks.size(); ++i)
     broken_brick_draw(&broken_bricks[i]);
 
+  /* Draw foreground: */
+
+  for (y = 0; y < 15; ++y)
+    {
+      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)]);
+        }
+    }
+
+  /* Draw particle systems (foreground) */
+  for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
+    {
+      (*p)->draw(scroll_x, 0, 1);
+    }
+
   drawstatus();
 
   if(game_pause)
@@ -526,10 +597,7 @@ void game_draw(void)
     menu_process_current();
 
   /* (Update it all!) */
-
   updatescreen();
-
-
 }
 
 /* --- GAME LOOP! --- */
@@ -565,6 +633,7 @@ 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);
 
   tux.init();
@@ -583,7 +652,6 @@ int gameloop(const char * subset, int levelnb, int mode)
   if(st_gl_mode == ST_GL_LOAD_GAME)
     loadgame(levelnb);
 
-
   /* --- MAIN GAME LOOP!!! --- */
 
   jump = false;
@@ -605,7 +673,7 @@ int gameloop(const char * subset, int levelnb, int mode)
 
 
   while (SDL_PollEvent(&event))
-    {}
+  {}
 
   game_draw();
   do
@@ -616,7 +684,7 @@ 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);
@@ -679,8 +747,8 @@ int gameloop(const char * subset, int levelnb, int mode)
               /* == -1: continues */
               return 0;
             }
-         /*  --z;
-              }*/
+          /*  --z;
+                     }*/
         }
       else
         {
@@ -711,7 +779,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+. */
@@ -1249,10 +1316,25 @@ 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;
 
+  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
+        {
+          texture_draw(&ptile->images[0],x,y);
+        }
+    }
+
+  /*
   if (c == 'X' || c == 'x')
     texture_draw(&img_brick[0], x, y);
   else if (c == 'Y' || c == 'y')
@@ -1308,24 +1390,25 @@ void drawshape(float x, float y, unsigned char c)
       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 = '.';
@@ -1338,25 +1421,38 @@ unsigned char shape(float x, float 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;
+    }
 }
 
 
@@ -1364,16 +1460,38 @@ 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;
+    }
 }
 
 /* Break a brick: */
@@ -1396,7 +1514,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, 'a');
 
           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
           score = score + SCORE_DISTRO;
@@ -1406,7 +1524,7 @@ void trybreakbrick(float x, float y)
         {
           /* Get rid of it: */
 
-          level_change(&current_level,x, y,'.');
+          level_change(&current_level,x, y, TM_IA, '.');
         }
 
 
@@ -1473,7 +1591,7 @@ 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, 'a');
 }
 
 
@@ -1483,7 +1601,7 @@ void trygrabdistro(float x, float y, int bounciness)
 {
   if (shape(x, y) == '$')
     {
-      level_change(&current_level,x, y, '.');
+      level_change(&current_level,x, y, TM_IA, '.');
       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
 
       if (bounciness == BOUNCE)
@@ -1683,6 +1801,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();
index b8e0eb2..a92f85f 100644 (file)
@@ -38,8 +38,8 @@ bool isbrick(float x, float y);
 bool isice(float x, float y);
 bool isfullbox(float x, float y);
 bool rectcollision(base_type* one, base_type* two);
-void drawshape(float x, float y, unsigned char c);
-unsigned char shape(float x, float y);
+void drawshape(float x, float y, unsigned int c);
+unsigned int shape(float x, float y);
 void bumpbrick(float x, float y);
 void trygrabdistro(float x, float y, int bounciness);
 void trybreakbrick(float x, float y);
index db25e4c..9eb156c 100644 (file)
@@ -206,11 +206,29 @@ void level_default(st_level* plevel)
 
   for(i = 0; i < 15; ++i)
     {
-      plevel->tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int));
-      plevel->tiles[i][plevel->width] = (unsigned int) '\0';
+      plevel->ia_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int));
+      plevel->ia_tiles[i][plevel->width] = (unsigned int) '\0';
       for(y = 0; y < plevel->width; ++y)
-        plevel->tiles[i][y] = (unsigned int) '.';
-      plevel->tiles[i][plevel->width] = (unsigned int) '\0';
+        plevel->ia_tiles[i][y] = (unsigned int) '.';
+      plevel->ia_tiles[i][plevel->width] = (unsigned int) '\0';
+
+      plevel->bg_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int));
+      plevel->bg_tiles[i][plevel->width] = (unsigned int) '\0';
+      for(y = 0; y < plevel->width; ++y)
+        plevel->bg_tiles[i][y] = (unsigned int) '.';
+      plevel->bg_tiles[i][plevel->width] = (unsigned int) '\0';
+
+      plevel->fg_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int));
+      plevel->fg_tiles[i][plevel->width] = (unsigned int) '\0';
+      for(y = 0; y < plevel->width; ++y)
+        plevel->fg_tiles[i][y] = (unsigned int) '.';
+      plevel->fg_tiles[i][plevel->width] = (unsigned int) '\0';
+
+      plevel->dn_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int));
+      plevel->dn_tiles[i][plevel->width] = (unsigned int) '\0';
+      for(y = 0; y < plevel->width; ++y)
+        plevel->dn_tiles[i][y] = (unsigned int) '.';
+      plevel->dn_tiles[i][plevel->width] = (unsigned int) '\0';
     }
 }
 
@@ -231,7 +249,7 @@ int level_load(st_level* plevel, const  char *subset, int level)
 
 int level_load(st_level* plevel, const char* filename)
 {
-  int x, y;
+  int x, y, j;
   FILE * fi;
   lisp_object_t* root_obj = 0;
   fi = fopen(filename, "r");
@@ -250,12 +268,15 @@ int level_load(st_level* plevel, const char* filename)
       printf("World: Parse Error in file %s", filename);
     }
 
-  vector<int> vi;
+  vector<int> ia_tm;
+  vector<int> dn_tm;
+  vector<int> bg_tm;
+  vector<int> fg_tm;
 
   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
     {
       LispReader reader(lisp_cdr(root_obj));
-      
+
       reader.read_int("width",  &plevel->width);
       reader.read_int("time",  &plevel->time_left);
       reader.read_int("bkgd_red",  &plevel->bkgd_red);
@@ -266,20 +287,64 @@ int level_load(st_level* plevel, const char* filename)
       reader.read_string("theme",  &plevel->theme);
       reader.read_string("music",  &plevel->song_title);
       reader.read_string("background",  &plevel->bkgd_image);
-      reader.read_int_vector("tilemap",  &vi);
+      reader.read_string("particle_system", &plevel->particle_system);
+      reader.read_int_vector("background-tm",  &bg_tm);
+      reader.read_int_vector("interactive-tm",  &ia_tm);
+      reader.read_int_vector("dynamic-tm",  &dn_tm);
+      reader.read_int_vector("foreground-tm",  &fg_tm);
     }
-    
-    
+
+
   int i;
   for( i = 0; i < 15; ++i)
-    plevel->tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) );
+    {
+      plevel->dn_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) );
+      plevel->ia_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) );
+      plevel->bg_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) );
+      plevel->fg_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) );
+    }
+
+  i = j = 0;
+  for(vector<int>::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i)
+    {
+
+      plevel->ia_tiles[j][i] = (*it);
+      if(i == plevel->width - 1)
+        {
+          i = -1;
+          ++j;
+        }
+    }
+
+  i = j = 0;
+  for(vector<int>::iterator it = dn_tm.begin(); it != dn_tm.end(); ++it, ++i)
+    {
+
+      plevel->dn_tiles[j][i] = (*it);
+      if(i == plevel->width - 1)
+        {
+          i = -1;
+          ++j;
+        }
+    }
+
+  i = j = 0;
+  for(vector<int>::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i)
+    {
+
+      plevel->bg_tiles[j][i] = (*it);
+      if(i == plevel->width - 1)
+        {
+          i = -1;
+          ++j;
+        }
+    }
 
-  i = 0;
-  int j = 0;
-  for(vector<int>::iterator it = vi.begin(); it != vi.end(); ++it, ++i)
+  i = j = 0;
+  for(vector<int>::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i)
     {
 
-      plevel->tiles[j][i] = (*it);
+      plevel->fg_tiles[j][i] = (*it);
       if(i == plevel->width - 1)
         {
           i = -1;
@@ -290,7 +355,7 @@ int level_load(st_level* plevel, const char* filename)
   /* Set the global gravity to the latest loaded level's gravity */
   gravity = plevel->gravity;
 
-  /*  Mark the end position of this level! - Is a bit wrong here thought */
+  /*  Mark the end position of this level! - Is a bit wrong here thought * /
 
   for (y = 0; y < 15; ++y)
     {
@@ -302,7 +367,7 @@ int level_load(st_level* plevel, const char* filename)
                 endpos = x*32;
             }
         }
-    }
+    }*/
 
   fclose(fi);
   return 0;
@@ -333,30 +398,58 @@ void level_save(st_level* plevel,const  char * subset, int level)
     }
 
 
-        /* Write header: */
-      fprintf(fi,";SuperTux-Level\n");
-      fprintf(fi,"(supertux-level\n");
-
-      fprintf(fi,"  (name \"%s\")\n", plevel->name.c_str());
-      fprintf(fi,"  (theme \"%s\")\n", plevel->theme.c_str());
-      fprintf(fi,"  (music \"%s\")\n", plevel->song_title.c_str());
-      fprintf(fi,"  (background \"%s\")\n", plevel->bkgd_image.c_str());
-      fprintf(fi,"  (bkgd_red %d)\n", plevel->bkgd_red);
-      fprintf(fi,"  (bkgd_green %d)\n", plevel->bkgd_green);
-      fprintf(fi,"  (bkgd_blue %d)\n", plevel->bkgd_blue);
-      fprintf(fi,"  (time %d)\n", plevel->time_left);
-      fprintf(fi,"  (width %d)\n", plevel->width);
-      fprintf(fi,"  (gravity %2.1f)\n", plevel->gravity);
-      fprintf(fi,"  (tilemap ");     
-       
+  /* Write header: */
+  fprintf(fi,";SuperTux-Level\n");
+  fprintf(fi,"(supertux-level\n");
+
+  fprintf(fi,"  (name \"%s\")\n", plevel->name.c_str());
+  fprintf(fi,"  (theme \"%s\")\n", plevel->theme.c_str());
+  fprintf(fi,"  (music \"%s\")\n", plevel->song_title.c_str());
+  fprintf(fi,"  (background \"%s\")\n", plevel->bkgd_image.c_str());
+  fprintf(fi,"  (particle_system \"%s\")\n", plevel->particle_system.c_str());
+  fprintf(fi,"  (bkgd_red %d)\n", plevel->bkgd_red);
+  fprintf(fi,"  (bkgd_green %d)\n", plevel->bkgd_green);
+  fprintf(fi,"  (bkgd_blue %d)\n", plevel->bkgd_blue);
+  fprintf(fi,"  (time %d)\n", plevel->time_left);
+  fprintf(fi,"  (width %d)\n", plevel->width);
+  fprintf(fi,"  (gravity %2.1f)\n", plevel->gravity);
+  fprintf(fi,"  (background-tm ");
+
+  for(y = 0; y < 15; ++y)
+    {
+      for(i = 0; i < plevel->width; ++i)
+        fprintf(fi," %d ", plevel->bg_tiles[y][i]);
+    }
+
+  fprintf( fi,")\n");
+  fprintf(fi,"  (interactive-tm ");
+
   for(y = 0; y < 15; ++y)
     {
-    for(i = 0; i < plevel->width; ++i)
-    fprintf(fi," %d ", plevel->tiles[y][i]); 
+      for(i = 0; i < plevel->width; ++i)
+        fprintf(fi," %d ", plevel->ia_tiles[y][i]);
     }
-    
-      fprintf( fi,")");    
-      fprintf( fi,")\n");
+
+  fprintf( fi,")\n");
+  fprintf(fi,"  (dynamic-tm ");
+
+  for(y = 0; y < 15; ++y)
+    {
+      for(i = 0; i < plevel->width; ++i)
+        fprintf(fi," %d ", plevel->dn_tiles[y][i]);
+    }
+
+  fprintf( fi,")\n");
+  fprintf(fi,"  (foreground-tm ");
+
+  for(y = 0; y < 15; ++y)
+    {
+      for(i = 0; i < plevel->width; ++i)
+        fprintf(fi," %d ", plevel->fg_tiles[y][i]);
+    }
+
+  fprintf( fi,")");
+  fprintf( fi,")\n");
 
   fclose(fi);
 }
@@ -368,7 +461,13 @@ void level_free(st_level* plevel)
 {
   int i;
   for(i=0; i < 15; ++i)
-    free(plevel->tiles[i]);
+    free(plevel->bg_tiles[i]);
+  for(i=0; i < 15; ++i)
+    free(plevel->ia_tiles[i]);
+  for(i=0; i < 15; ++i)
+    free(plevel->dn_tiles[i]);
+  for(i=0; i < 15; ++i)
+    free(plevel->fg_tiles[i]);
 
   plevel->name.clear();
   plevel->theme.clear();
@@ -446,9 +545,37 @@ void level_load_image(texture_type* ptexture, string theme,const  char * file, i
   texture_load(ptexture, fname, use_alpha);
 }
 
+void tilemap_change_size(unsigned int** tilemap[15], int w, int old_w)
+{
+  int j,y;
+  for(y = 0; y < 15; ++y)
+    {
+      *tilemap[y] = (unsigned int*) realloc(*tilemap[y],(w+1)*sizeof(unsigned int));
+      if(w > old_w)
+        for(j = 0; j < w - old_w; ++j)
+          *tilemap[y][old_w+j] = 0;
+      *tilemap[y][w] = 0;
+    }
+}
+
+/* Change the size of a level (width) */
+void level_change_size (st_level* plevel, int new_width)
+{
+  int y;
+
+  if(new_width < 21)
+    new_width = 21;
+  tilemap_change_size((unsigned int***)&plevel->ia_tiles,new_width,plevel->width);
+  tilemap_change_size((unsigned int***)&plevel->dn_tiles,new_width,plevel->width);
+  tilemap_change_size((unsigned int***)&plevel->bg_tiles,new_width,plevel->width);
+  tilemap_change_size((unsigned int***)&plevel->fg_tiles,new_width,plevel->width);
+  plevel->width = new_width;
+
+}
+
 /* Edit a piece of the map! */
 
-void level_change(st_level* plevel, float x, float y, unsigned char c)
+void level_change(st_level* plevel, float x, float y, int tm, unsigned int c)
 {
   int xx, yy;
 
@@ -456,7 +583,19 @@ void level_change(st_level* plevel, float x, float y, unsigned char c)
   xx = ((int)x / 32);
 
   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= plevel->width)
-    plevel->tiles[yy][xx] = c;
+    {
+      switch(tm)
+        {
+        case 0:
+          plevel->bg_tiles[yy][xx] = c;
+        case 1:
+          plevel->ia_tiles[yy][xx] = c;
+        case 2:
+          plevel->dn_tiles[yy][xx] = c;
+        case 4:
+          plevel->fg_tiles[yy][xx] = c;
+        }
+    }
 }
 
 /* Free music data for this level: */
index f9cdbff..ed93b8b 100644 (file)
@@ -46,7 +46,11 @@ struct st_level
   std::string theme;
   std::string song_title;
   std::string bkgd_image;
-  unsigned int* tiles[15];
+  std::string particle_system;
+  unsigned int* bg_tiles[15]; /* Tiles in the background */
+  unsigned int* ia_tiles[15]; /* Tiles which can interact in the game (solids for example)*/
+  unsigned int* dn_tiles[15]; /* Dynamic tiles (bad guys and moving platforms for example)*/
+  unsigned int* fg_tiles[15]; /* Tiles in the foreground */
   int time_left;
   int bkgd_red;
   int bkgd_green;
@@ -55,6 +59,13 @@ struct st_level
   float gravity;
 };
 
+enum {
+ TM_BG,
+ TM_IA,
+ TM_DN,
+ TM_FG
+ };
+
 extern texture_type img_bkgd, img_bkgd_tile[2][4], img_solid[4], img_brick[2];
 
 void level_default  (st_level* plevel);
@@ -64,7 +75,8 @@ int  level_load     (st_level* plevel, const char* filename);
 void level_save     (st_level* plevel, const char * subset, int level);
 void level_free     (st_level* plevel);
 void level_load_gfx (st_level* plevel);
-void level_change   (st_level* plevel, float x, float y, unsigned char c);
+void level_change   (st_level* plevel, float x, float y, int tm, unsigned int c);
+void level_change_size (st_level* plevel, int new_width);
 void level_load_song(st_level* plevel);
 void level_free_gfx();
 void level_load_image(texture_type* ptexture, std::string theme, const char * file, int use_alpha);
index 7863015..6fc2b3b 100644 (file)
@@ -66,7 +66,7 @@ void le_quit();
 void le_drawlevel();
 void le_drawinterface();
 void le_checkevents();
-void le_change(float x, float y, unsigned char c);
+void le_change(float x, float y, int tm, unsigned int c);
 void le_testlevel();
 void le_showhelp();
 void le_set_defaults(void);
@@ -129,8 +129,11 @@ void le_activate_bad_guys(void)
 
   for (y = 0; y < 15; ++y)
     for (x = 0; x < le_current_level->width; ++x)
-      if (le_current_level->tiles[y][x] >= '0' && le_current_level->tiles[y][x] <= '9')
-        add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(le_current_level->tiles[y][x] - '0'));
+      if (le_current_level->dn_tiles[y][x] >= '0' && le_current_level->dn_tiles[y][x] <= '9')
+        add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(le_current_level->dn_tiles[y][x] - '0'));
+
+
+
 }
 
 void le_set_defaults()
@@ -620,28 +623,7 @@ void apply_level_settings_menu()
 
   le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
 
-  i = le_current_level->width;
-  le_current_level->width = atoi(level_settings_menu->item[6].input);
-  if(le_current_level->width < i)
-    {
-      if(le_current_level->width < 21)
-        le_current_level->width = 21;
-      for(y = 0; y < 15; ++y)
-        {
-          le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
-          le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
-        }
-    }
-  else if(le_current_level->width > i)
-    {
-      for(y = 0; y < 15; ++y)
-        {
-          le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
-          for(j = 0; j < le_current_level->width - i; ++j)
-            le_current_level->tiles[y][i+j] = (unsigned int) '.';
-          le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
-        }
-    }
+  level_change_size(le_current_level, atoi(level_settings_menu->item[6].input));
   le_current_level->time_left = atoi(level_settings_menu->item[7].input);
   le_current_level->gravity = atof(level_settings_menu->item[8].input);
   le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
@@ -838,12 +820,11 @@ void le_drawlevel()
   for (y = 0; y < 15; ++y)
     for (x = 0; x < 20; ++x)
       {
-        drawshape(x * 32 - ((int)pos_x % 32), y * 32,
-                  le_current_level->tiles[y][x + (int)(pos_x / 32)]);
+        drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]);
 
         /* draw whats inside stuff when cursor is selecting those */
         /* (draw them all the time - is this the right behaviour?) */
-        switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
+        switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)])
           {
           case 'B':
             texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
@@ -1250,7 +1231,7 @@ void le_checkevents()
 
               if(le_mouse_pressed[LEFT])
                 {
-                  le_change(cursor_x, cursor_y, le_current_tile);
+                  le_change(cursor_x, cursor_y, TM_IA, le_current_tile);
                 }
             }
         }
@@ -1311,7 +1292,7 @@ void le_highlight_selection()
   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
 }
 
-void le_change(float x, float y, unsigned char c)
+void le_change(float x, float y, int tm, unsigned int c)
 {
   if(le_current_level != NULL)
     {
@@ -1324,7 +1305,7 @@ void le_change(float x, float y, unsigned char c)
       switch(le_selection_mode)
         {
         case CURSOR:
-          level_change(le_current_level,x,y,c);
+          level_change(le_current_level,x,y,tm,c);
 
           yy = ((int)y / 32);
           xx = ((int)x / 32);
@@ -1378,7 +1359,7 @@ void le_change(float x, float y, unsigned char c)
           for(xx = x1; xx <= x2; xx++)
             for(yy = y1; yy <= y2; yy++)
               {
-                level_change(le_current_level, xx*32, yy*32, c);
+                level_change(le_current_level, xx*32, yy*32, tm, c);
 
                 if(c == '0')  // if it's a bad guy
                   add_bad_guy(xx*32, yy*32, BAD_BSOD);
diff --git a/src/particlesystem.cpp b/src/particlesystem.cpp
new file mode 100644 (file)
index 0000000..db1ca26
--- /dev/null
@@ -0,0 +1,141 @@
+//  $Id$
+// 
+//  SuperTux
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include "particlesystem.h"
+
+#include <iostream>
+#include <math.h>
+#include "globals.h"
+#include "scene.h"
+
+ParticleSystem::ParticleSystem()
+{
+    virtual_width = screen->w;
+    virtual_height = screen->h;
+}
+
+ParticleSystem::~ParticleSystem()
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        delete *i;
+    }
+}
+
+void ParticleSystem::draw(float scrollx, float scrolly, int layer)
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        Particle* particle = *i;
+        if(particle->layer != layer)
+            continue;
+        
+        // remap x,y coordinates onto screencoordinates
+        float x = fmodf(particle->x - scrollx, virtual_width);
+        if(x < 0) x += virtual_width;
+        float y = fmodf(particle->y - scrolly, virtual_height);
+        if(y < 0) y += virtual_height;
+        float xmax = fmodf(x + particle->texture->w, virtual_width);
+        float ymax = fmodf(y + particle->texture->h, virtual_height);
+
+        // particle on screen
+        if(x >= screen->w && xmax >= screen->w)
+            continue;
+        if(y >= screen->h && ymax >= screen->h)
+            continue;
+        
+        if(x > screen->w) x -= virtual_width;
+        if(y > screen->h) y -= virtual_height;
+        texture_draw(particle->texture, x, y);
+    }
+}
+
+SnowParticleSystem::SnowParticleSystem()
+{
+    texture_load(&snowimages[0], datadir+"/images/shared/snow0.png", USE_ALPHA);
+    texture_load(&snowimages[1], datadir+"/images/shared/snow1.png", USE_ALPHA);
+    texture_load(&snowimages[2], datadir+"/images/shared/snow2.png", USE_ALPHA);
+
+    virtual_width = screen->w * 2;
+
+    // create some random snowflakes
+    size_t snowflakecount = size_t(virtual_width/10.0);
+    for(size_t i=0; i<snowflakecount; ++i) {
+        SnowParticle* particle = new SnowParticle;
+        particle->x = rand() % int(virtual_width);
+        particle->y = rand() % screen->h;
+        particle->layer = i % 2;
+        int snowsize = rand() % 3;
+        particle->texture = &snowimages[snowsize];
+        particle->speed = 0.01 + snowsize/50.0 + (rand()%(int)gravity/15.0);
+
+        particles.push_back(particle);
+    }
+}
+
+SnowParticleSystem::~SnowParticleSystem()
+{
+    for(int i=0;i<3;++i)
+        texture_free(&snowimages[i]);
+}
+
+void SnowParticleSystem::simulate(float elapsed_time)
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        SnowParticle* particle = (SnowParticle*) *i;
+        particle->y += particle->speed * elapsed_time;
+        if(particle->y > screen->h) {
+            particle->y = 0;
+            particle->x = rand() % int(virtual_width);
+        }
+    }
+}
+
+CloudParticleSystem::CloudParticleSystem()
+{
+    texture_load(&cloudimage, datadir + "/images/shared/cloud.png", USE_ALPHA);
+
+    virtual_width = 5000.0;
+
+    // create some random clouds
+    for(size_t i=0; i<15; ++i) {
+        CloudParticle* particle = new CloudParticle;
+        particle->x = rand() % int(virtual_width);
+        particle->y = rand() % int((float) screen->h * 0.3333);
+        particle->layer = 0;
+        particle->texture = &cloudimage;
+        particle->speed = -float(250 + rand() % 200) / 1000.0;
+
+        particles.push_back(particle);
+    }
+}
+
+CloudParticleSystem::~CloudParticleSystem()
+{
+    texture_free(&cloudimage);
+}
+
+void CloudParticleSystem::simulate(float elapsed_time)
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        CloudParticle* particle = (CloudParticle*) *i;
+        particle->x += particle->speed * elapsed_time;
+    }
+}
diff --git a/src/particlesystem.h b/src/particlesystem.h
new file mode 100644 (file)
index 0000000..8efdf95
--- /dev/null
@@ -0,0 +1,103 @@
+//  $Id$
+// 
+//  SuperTux
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_PARTICLESYSTEM_H
+#define SUPERTUX_PARTICLESYSTEM_H
+
+#include <vector>
+#include "texture.h"
+
+/**
+ * This is the base class for particle systems. It is responsible for storing a
+ * set of particles with each having an x- and y-coordinate the number of the
+ * layer where it should be drawn and a texture.
+ * The coordinate system used here is a virtual one. It would be a bad idea to
+ * populate whole levels with particles. So we're using a virtual rectangle
+ * here that is tiled onto the level when drawing. This rectangle has the size
+ * (virtual_width, virtual_height). We're using modulo on the particle
+ * coordinates, so when a particle leaves left, it'll reenter at the right
+ * side.
+ *
+ * Classes that implement a particle system should subclass from this class,
+ * initialize particles in the constructor and move them in the simulate
+ * function.
+ */
+class ParticleSystem
+{
+public:
+    ParticleSystem();
+    virtual ~ParticleSystem();
+    
+    void draw(float scrollx, float scrolly, int layer);
+
+    virtual void simulate(float elapsed_time) = 0;
+
+protected:
+    class Particle
+    {
+    public:
+        virtual ~Particle()
+        { }
+
+        float x, y;
+        int layer;
+        texture_type* texture;
+    };
+    
+    std::vector<Particle*> particles;
+    float virtual_width, virtual_height;
+};
+
+class SnowParticleSystem : public ParticleSystem
+{
+public:
+    SnowParticleSystem();
+    virtual ~SnowParticleSystem();
+
+    virtual void simulate(float elapsed_time);
+    
+private:
+    class SnowParticle : public Particle
+    {
+    public:
+        float speed;
+    };
+    
+    texture_type snowimages[3];
+};
+
+class CloudParticleSystem : public ParticleSystem
+{
+public:
+    CloudParticleSystem();
+    virtual ~CloudParticleSystem();
+
+    virtual void simulate(float elapsed_time);
+    
+private:
+    class CloudParticle : public Particle
+    {
+    public:
+        float speed;
+    };
+    
+    texture_type cloudimage;
+};
+
+#endif
+
index b75a934..1c1c137 100644 (file)
@@ -255,8 +255,8 @@ Player::action()
                     }
 
                   if (distro_counter <= 0)
-                    level_change(&current_level,base.x,base.y - 1, 'a');
-
+                    level_change(&current_level,base.x,base.y - 1, TM_IA, 'a');
+                   
                   play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
                   score = score + SCORE_DISTRO;
                   distros++;
@@ -274,7 +274,7 @@ Player::action()
                     }
 
                   if (distro_counter <= 0)
-                    level_change(&current_level,base.x+ 31, base.y, 'a');
+                    level_change(&current_level,base.x+ 31, base.y, TM_IA, 'a');
 
                   play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
                   score = score + SCORE_DISTRO;
index 7947d4d..4be33a1 100644 (file)
@@ -20,6 +20,7 @@
 #include "world.h"
 #include "special.h"
 #include "level.h"
+#include "particlesystem.h"
 
 #define FRAME_RATE 10 // 100 Frames per second (10ms)
 
@@ -36,7 +37,7 @@ extern int distro_counter;
 
 extern timer_type  super_bkgd_timer;
 extern float scroll_x;
-extern int global_frame_counter;
+extern unsigned int global_frame_counter;
 extern std::vector<bouncy_distro_type> bouncy_distros;
 extern std::vector<broken_brick_type> broken_bricks;
 extern std::vector<bouncy_brick_type> bouncy_bricks;
@@ -44,6 +45,7 @@ extern std::vector<BadGuy> bad_guys;
 extern std::vector<floating_score_type> floating_scores;
 extern std::vector<upgrade_type> upgrades;
 extern std::vector<bullet_type> bullets;
+extern std::vector<ParticleSystem*> particle_systems;
 extern Player tux;
 extern texture_type img_box_full, img_box_empty, img_mints, img_coffee, img_super_bkgd, img_red_glow;
 extern timer_type time_left;
index 49d530d..60b7760 100644 (file)
@@ -80,7 +80,7 @@ int fwriteable(const char *filename)
   return true;
 }
 
-/* Makes sure a directory is created in either the SuperTux base directory or the SuperTux base directory.*/
+/* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/
 int fcreatedir(const char* relative_dir)
 {
   char path[1024];
index f2e9253..febda97 100644 (file)
@@ -344,7 +344,6 @@ void texture_from_sdl_surface(texture_type* ptexture, SDL_Surface* sdl_surf, int
 
 void texture_draw_sdl(texture_type* ptexture, float x, float y, bool update)
 {
-
   SDL_Rect dest;
 
   dest.x = (int)x;
diff --git a/src/tile.cpp b/src/tile.cpp
new file mode 100644 (file)
index 0000000..4430e34
--- /dev/null
@@ -0,0 +1,102 @@
+//
+// C++ Implementation: tile
+//
+// Description: 
+//
+//
+// Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "tile.h"
+#include "assert.h"
+
+TileManager* TileManager::instance_  = 0;
+
+TileManager::TileManager()
+{
+  std::string filename = datadir +  "images/tilesets/main.stgt"; 
+  load_tileset(filename);
+}
+
+void TileManager::load_tileset(std::string filename)
+{
+  lisp_object_t* root_obj = lisp_read_from_file(filename);
+  
+  if (!root_obj)
+    st_abort("Couldn't load file", filename);
+
+  if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-tiles") == 0)
+    {
+      lisp_object_t* cur = lisp_cdr(root_obj);
+      int tileset_id = 0;
+
+      while(!lisp_nil_p(cur))
+        {
+          lisp_object_t* element = lisp_car(cur);
+
+          if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0)
+            {
+              int id = 0;
+              std::vector<std::string> filenames;
+
+              Tile* tile = new Tile;             
+              tile->solid = false;
+             tile->brick = false;
+             tile->ice = false;          
+             tile->fullbox = false;          
+              tile->alpha  = 0;
+              tile->anim_speed = 25;
+  
+              LispReader reader(lisp_cdr(element));
+              reader.read_int("id",  &id);
+              reader.read_bool("solid", &tile->solid);
+              reader.read_bool("brick", &tile->brick);
+              reader.read_bool("ice", &tile->ice);        
+              reader.read_bool("fullbox", &tile->fullbox);
+              reader.read_int("alpha",  (int*)&tile->alpha);
+              reader.read_int("anim-speed",  &tile->anim_speed);
+              reader.read_string_vector("images",  &filenames);
+
+             for(std::vector<std::string>::iterator it = filenames.begin(); it != filenames.end(); ++it)
+             {
+             texture_type cur_image;
+             tile->images.push_back(cur_image);
+              texture_load(&tile->images[tile->images.size()-1], 
+                           datadir +  "images/tilesets/" + (*it), 
+                           USE_ALPHA);
+                          }
+
+              if (id+tileset_id >= int(tiles.size()))
+                tiles.resize(id+tileset_id+1);
+
+              tiles[id+tileset_id] = tile;
+            }
+         else if (strcmp(lisp_symbol(lisp_car(element)), "tileset") == 0)
+            {
+             LispReader reader(lisp_cdr(element));
+             std::string filename;
+              reader.read_string("file",  &filename);
+             filename = datadir + "images/tilesets/" + filename; 
+             load_tileset(filename);
+           }
+         else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0)
+            {
+             LispReader reader(lisp_cdr(element));
+              reader.read_int("id",  &tileset_id);
+             tileset_id *= 1000;
+           }
+          else
+            {
+              puts("Unhandled symbol");
+            }
+
+          cur = lisp_cdr(cur);
+        }
+    }
+  else
+    {
+      assert(0);
+    }
+}
diff --git a/src/tile.h b/src/tile.h
new file mode 100644 (file)
index 0000000..31212c9
--- /dev/null
@@ -0,0 +1,49 @@
+//
+// C++ Interface: tile
+//
+// Description: 
+//
+//
+// Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef TILE_H
+#define TILE_H
+
+#include <vector>
+#include "texture.h"
+#include "globals.h"
+#include "lispreader.h"
+#include "setup.h"
+
+/**
+Tile Class
+*/
+struct Tile
+{
+std::vector<texture_type> images;
+bool solid;
+bool brick;
+bool ice;
+bool fullbox;
+int anim_speed;
+unsigned char alpha;
+};
+
+class TileManager
+{
+private:
+ TileManager();
+ std::vector<Tile*> tiles;
+ static TileManager* instance_ ;
+ void load_tileset(std::string filename);
+  
+public:
+ static TileManager* instance() { return instance_ ? instance_ : instance_ = new TileManager(); }
+ Tile* get(unsigned int id) { if( id < tiles.size()) { return tiles[id]; } else { return NULL; } } ;
+
+};
+
+#endif