big refactoring of level and world class. A level is now basically a set of
authorMatthias Braun <matze@braunis.de>
Mon, 31 May 2004 02:40:30 +0000 (02:40 +0000)
committerMatthias Braun <matze@braunis.de>
Mon, 31 May 2004 02:40:30 +0000 (02:40 +0000)
sectors (or sublevels). The Sector class has been merged with the old world
class. Also I've rewritten some parts of the load/save code and changed the
fileformat a bit to support several sectors.
On the way I fixed some bugs (and maybe introduce new ones...)

SVN-Revision: 1371

46 files changed:
data/levels/misc/menu.stl
data/levels/test/level10.stl
data/levels/test/level11.stl [new file with mode: 0644]
data/levels/test/level4.stl
data/levels/test/level5.stl
data/levels/test/level7.stl
data/levels/world1/level10.stl
src/Makefile.am
src/background.cpp
src/background.h
src/badguy.cpp
src/badguy.h
src/camera.cpp
src/camera.h
src/collision.cpp
src/collision.h
src/configfile.cpp
src/gameloop.cpp
src/gameloop.h
src/gameobjs.cpp
src/gameobjs.h
src/high_scores.cpp
src/level.cpp
src/level.h
src/lispreader.cpp
src/lispreader.h
src/menu.cpp
src/mousecursor.cpp
src/particlesystem.cpp
src/particlesystem.h
src/physic.cpp
src/player.cpp
src/player.h
src/resources.cpp
src/sector.cpp [new file with mode: 0644]
src/sector.h [new file with mode: 0644]
src/special.cpp
src/sprite.cpp
src/supertux.cpp
src/tile.cpp
src/tilemap.cpp
src/tilemap.h
src/title.cpp
src/world.cpp [deleted file]
src/world.h [deleted file]
src/worldmap.cpp

index 6e5bdce..1914f73 100644 (file)
@@ -6,7 +6,7 @@
   (music "theme.mod")
   (background "arctis.jpg")
   (particle_system "")
-  (bkgd_speed "2")
+  (bkgd_speed 0.5)
   (bkgd_red_top 0)
   (bkgd_green_top 0)
   (bkgd_blue_top 0)
index 2948f6e..ae0b31d 100644 (file)
@@ -6,7 +6,7 @@
   (music "forest.mod")
   (background "cave2.jpg")
   (particle_system "")
-  (bkgd_speed 50)
+  (bkgd_speed 0.5)
   (bkgd_red_top 150)
   (bkgd_green_top 200)
   (bkgd_blue_top 255)
diff --git a/data/levels/test/level11.stl b/data/levels/test/level11.stl
new file mode 100644 (file)
index 0000000..90c04b1
--- /dev/null
@@ -0,0 +1,54 @@
+(supertux-level
+  (version 2)
+  (name "Sector Test")
+  (author "Matthias Braun")
+  (time 500)
+  (sector
+    (name "main")
+    (gravity 10)
+    (camera
+      (mode "normal")
+    )
+    (playerspawn
+      (name "main")
+      (x 100)
+      (y 170)
+    )
+    (tilemap
+      (layer "interactive")
+      (solid #t)
+      (speed 1.)
+      (width 50)
+      (height 15)
+      (tiles
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  48 0  0  0  0  0  0  0  48 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  27 28 28 28 28 28 28 28 29 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  48 0  0  48 0  0  48 0  0  0  0  0  0  48 0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  48 48 48 48 48 48 48 48 0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   0  0  0  0  0  0  48 0  0  0  0  0  0  0  48 0  0  0  48 0  0  0  0  0  0  48 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
+   7  8  8  8  8  8  48 0  0  0  0  7  8  8  48 76 76 76 48 8  8  8  8  8  8  48 8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  
+   28 28 28 28 28 28 28 28 28 28 28 28 28 28 48 75 75 75 48 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 
+   10 11 11 11 11 11 11 11 11 11 11 11 11 11 48 48 48 48 48 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 
+   10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 
+      )
+    )
+    (background
+      (image "arctis.jpg")
+      (speed 0.5)
+    )
+    (fish  (x 509) (y 181))
+    (flyingsnowball  (x 941) (y 222))
+    (spiky  (x 656) (y 306))
+    (snowball  (x 259) (y 303))
+    (stalactite  (x 1159) (y 288))
+    (stalactite  (x 1235) (y 288))
+    (laptop  (x 1198) (y 186))
+    (mriceblock  (x 323) (y 74))
+  )
+)
index 33fc08a..625040c 100644 (file)
@@ -6,7 +6,7 @@
   (music "Mortimers_chipdisko.mod")
   (background "")
   (particle_system "")
-  (bkgd_speed 50)
+  (bkgd_speed 0.5)
   (bkgd_red_top 0)
   (bkgd_green_top 0)
   (bkgd_blue_top 255)
index 2163028..01c39ba 100644 (file)
@@ -6,8 +6,8 @@
   (music "Mortimers_chipdisko.mod")
   (background "")
   (particle_system "")
-  (bkgd_speed 50)
-  (bkgd_red_top 150)
+  (bkgd_speed 0.5)
+  (bkgd_red_top 50)
   (bkgd_green_top 150)
   (bkgd_blue_top 150)
   (bkgd_red_bottom 150)
index 7b02be7..5cd517f 100644 (file)
@@ -6,7 +6,7 @@
   (music "Mortimers_chipdisko.mod")
   (background "")
   (particle_system "")
-  (bkgd_speed 50)
+  (bkgd_speed 0.5)
   (bkgd_red_top 150)
   (bkgd_green_top 150)
   (bkgd_blue_top 150)
index 32623ab..1944e44 100644 (file)
     (point (x 7889) (y 327))
    )
   (objects
-    (mriceblock  (x 613) (y 367))
+    (mriceblock 
+     (x 613)
+     (y 367)
+    )
     (mrbomb  (x 5833) (y 353))
     (mrbomb  (x 6091) (y 334))
     (money  (x 6640) (y 288))
index bbe3130..023536d 100644 (file)
@@ -59,8 +59,6 @@ title.cpp \
 title.h \
 type.cpp \
 type.h \
-world.cpp \
-world.h \
 worldmap.cpp \
 worldmap.h \
 tile.h \
@@ -92,6 +90,8 @@ moving_object.h \
 moving_object.cpp \
 serializable.h \
 vector.cpp \
-vector.h
+vector.h \
+sector.cpp \
+sector.h 
 
 # EOF #
index 14584e9..1effc16 100644 (file)
 #include "globals.h"
 #include "camera.h"
 #include "screen/drawing_context.h"
+#include "lispwriter.h"
 
 Background::Background()
   : type(INVALID), image(0)
 {
 }
 
+Background::Background(LispReader& reader)
+  : type(INVALID), image(0)
+{
+  if(reader.read_string("image", imagefile) 
+      && reader.read_float("speed", speed)) {
+    set_image(imagefile, speed);
+  }
+
+  int tr, tg, tb, br, bg, bb;
+  if(reader.read_int("top_red", tr) && reader.read_int("top_green", tg)
+      && reader.read_int("top_blue", tb) && reader.read_int("bottom_red", br)
+      && reader.read_int("bottom_green", br)
+      && reader.read_int("bottom_blue", bb)) {
+    set_gradient(Color(tr, tg, tb), Color(br, bg, bb));
+  }
+}
+
 Background::~Background()
 {
   delete image;
 }
 
 void
+Background::write(LispWriter& writer)
+{
+  if(type == INVALID)
+    return;
+    
+  writer.start_list("background");
+
+  if(type == IMAGE) {
+    writer.write_string("image", imagefile);
+    writer.write_float("speed", speed);
+  } else if(type == GRADIENT) {
+    writer.write_int("top_red", gradient_top.red);
+    writer.write_int("top_green", gradient_top.green);
+    writer.write_int("top_blue", gradient_top.blue);
+    writer.write_int("bottom_red", gradient_bottom.red);
+    writer.write_int("bottom_green", gradient_bottom.green);
+    writer.write_int("bottom_blue", gradient_bottom.blue);
+  }
+  
+  writer.end_list("background");
+}
+
+void
 Background::action(float)
 {
 }
@@ -40,7 +81,8 @@ Background::action(float)
 void
 Background::set_image(const std::string& name, float speed)
 {
-  type = IMAGE;
+  this->type = IMAGE;
+  this->imagefile = name;
   this->speed = speed;
 
   delete image;
@@ -61,9 +103,9 @@ Background::draw(DrawingContext& context)
   if(type == GRADIENT) {
     context.draw_gradient(gradient_top, gradient_bottom, LAYER_BACKGROUND0);
   } else if(type == IMAGE) {
-    int sx = int(-context.get_translation().x * float(speed/100.))
+    int sx = int(-context.get_translation().x * speed)
       % image->w - image->w;
-    int sy = int(-context.get_translation().y * float(speed/100.))
+    int sy = int(-context.get_translation().y * speed)
       % image->h - image->h;
     context.push_transform();
     context.set_translation(Vector(0, 0));
index c441c50..07d33f1 100644 (file)
 #include "screen/texture.h"
 #include "screen/drawing_context.h"
 #include "game_object.h"
+#include "lispreader.h"
+#include "serializable.h"
 
 class DisplayManager;
 
-class Background : public GameObject
+class Background : public GameObject, public Serializable
 {
 public:
   Background();
+  Background(LispReader& reader);
   virtual ~Background();
 
+  virtual void write(LispWriter& writer);
+
   void set_image(const std::string& name, float bkgd_speed);
 
   void set_gradient(Color top, Color bottom);
@@ -45,6 +50,7 @@ private:
   };
   
   Type type;
+  std::string imagefile;
   float speed;
   Surface* image;
   Color gradient_top, gradient_bottom;
index 87ef1b7..97913c7 100644 (file)
 #include "tile.h"
 #include "resources.h"
 #include "sprite_manager.h"
-#include "world.h"
 #include "camera.h"
 #include "lispwriter.h"
 #include "level.h"
+#include "sector.h"
+#include "tilemap.h"
 
 Sprite* img_mriceblock_flat_left;
 Sprite* img_mriceblock_flat_right;
@@ -106,8 +107,7 @@ BadGuyKind  badguykind_from_string(const std::string& str)
     return BAD_WALKINGTREE;
   else
     {
-      printf("Couldn't convert badguy: '%s'\n", str.c_str());
-      return BAD_SNOWBALL;
+      return BAD_INVALID;
     }
 }
 
@@ -158,13 +158,13 @@ std::string badguykind_to_string(BadGuyKind kind)
 BadGuy::BadGuy(BadGuyKind kind_, LispReader& lispreader)
   : removable(false), squishcount(0)
 {
-  lispreader.read_float("x", &start_position.x);
-  lispreader.read_float("y", &start_position.y);
+  lispreader.read_float("x", start_position.x);
+  lispreader.read_float("y", start_position.y);
 
   kind     = kind_;
 
   stay_on_platform = false;
-  lispreader.read_bool("stay-on-platform", &stay_on_platform);  
+  lispreader.read_bool("stay-on-platform", stay_on_platform);
 
   init();
 }
@@ -214,8 +214,8 @@ BadGuy::init()
         --base.y;
     }
 
-  if(World::current()->camera) {
-    Vector scroll = World::current()->camera->get_translation();
+  if(Sector::current() && Sector::current()->camera) {
+    Vector scroll = Sector::current()->camera->get_translation();
 
     if(start_position.x > scroll.x - X_OFFSCREEN_DISTANCE &&
         start_position.x < scroll.x + screen->w + X_OFFSCREEN_DISTANCE &&
@@ -223,6 +223,10 @@ BadGuy::init()
         start_position.y < scroll.y + screen->h + Y_OFFSCREEN_DISTANCE) {
       activate(LEFT);
     }
+  } else {
+    if(start_position.x > 0 && start_position.x <= screen->w
+        && start_position.y > 0 && start_position.y <= screen->h)
+      activate(LEFT);
   }
 }
 
@@ -307,7 +311,7 @@ BadGuy::activate(Direction activation_dir)
 void
 BadGuy::action_mriceblock(double elapsed_time)
 {
-  Player& tux = *World::current()->get_tux();
+  Player& tux = *Sector::current()->player;
 
   if(mode != HELD)
     fall();
@@ -362,7 +366,7 @@ BadGuy::action_mriceblock(double elapsed_time)
       check_horizontal_bump();
       if(mode == KICK && changed != dir)
         {
-          float scroll_x = World::current()->camera->get_translation().x;
+          float scroll_x = Sector::current()->camera->get_translation().x;
           
           /* handle stereo sound (number 10 should be tweaked...)*/
           if (base.x < scroll_x + screen->w/2 - 10)
@@ -393,7 +397,7 @@ BadGuy::check_horizontal_bump(bool checkcliff)
     if (dir == LEFT && issolid( base.x, (int) base.y + halfheight))
     {
         if (kind == BAD_MRICEBLOCK && mode == KICK)
-            World::current()->trybreakbrick(base.x, (int) base.y + halfheight, false);
+            Sector::current()->trybreakbrick(Vector(base.x, base.y + halfheight), false);
             
         dir = RIGHT;
         physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
@@ -402,7 +406,8 @@ BadGuy::check_horizontal_bump(bool checkcliff)
     if (dir == RIGHT && issolid( base.x + base.width, (int)base.y + halfheight))
     {
         if (kind == BAD_MRICEBLOCK && mode == KICK)
-            World::current()->trybreakbrick(base.x + base.width, (int) base.y + halfheight, false);
+            Sector::current()->trybreakbrick(
+                Vector(base.x + base.width, (int) base.y + halfheight), false);
             
         dir = LEFT;
         physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
@@ -496,7 +501,7 @@ BadGuy::action_jumpy(double elapsed_time)
   else
     set_sprite(img_jumpy_left_up, img_jumpy_left_up);
 
-  Player& tux = *World::current()->get_tux();
+  Player& tux = *Sector::current()->player;
 
   static const float JUMPV = 6;
     
@@ -563,7 +568,7 @@ BadGuy::action_bomb(double elapsed_time)
       dying = DYING_NOT; // now the bomb hurts
       timer.start(EXPLODETIME);
 
-      float scroll_x = World::current()->camera->get_translation().x;                 
+      float scroll_x = Sector::current()->camera->get_translation().x;
 
       /* play explosion sound */  // FIXME: is the stereo all right? maybe we should use player cordinates...
       if (base.x < scroll_x + screen->w/2 - 10)
@@ -587,7 +592,7 @@ BadGuy::action_bomb(double elapsed_time)
 void
 BadGuy::action_stalactite(double elapsed_time)
 {
-  Player& tux = *World::current()->get_tux();
+  Player& tux = *Sector::current()->player;
 
   static const int SHAKETIME = 800;
   static const int RANGE = 40;
@@ -798,7 +803,7 @@ BadGuy::action_wingling(double elapsed_time)
     physic.enable_gravity(true);
   else
   {
-    Player& tux = *World::current()->get_tux();
+    Player& tux = *Sector::current()->player;
     int dirsign = physic.get_velocity_x() < 0 ? -1 : 1;
 
     if (fabsf(tux.base.x - base.x) < 150 && base.y < tux.base.y && tux.dying == DYING_NOT)
@@ -827,7 +832,7 @@ BadGuy::action_wingling(double elapsed_time)
 void
 BadGuy::action_walkingtree(double elapsed_time)
 {
-  Player& tux = *World::current()->get_tux();
+  Player& tux = *Sector::current()->player;
   Direction v_dir = physic.get_velocity_x() < 0 ? LEFT : RIGHT;
 
   if (dying == DYING_NOT)
@@ -862,11 +867,11 @@ BadGuy::action_walkingtree(double elapsed_time)
 void
 BadGuy::action(float elapsed_time)
 {
-  float scroll_x = World::current()->camera->get_translation().x;
-  float scroll_y = World::current()->camera->get_translation().y;
+  float scroll_x = Sector::current()->camera->get_translation().x;
+  float scroll_y = Sector::current()->camera->get_translation().y;
   
   // BadGuy fall below the ground
-  if (base.y > World::current()->get_level()->height * 32) {
+  if (base.y > Sector::current()->solids->get_height() * 32) {
     remove_me();
     return;
   }
@@ -1052,7 +1057,7 @@ BadGuy::squish_me(Player* player)
 {
   make_player_jump(player);
     
-  World::current()->add_score(Vector(base.x, base.y),
+  Sector::current()->add_score(Vector(base.x, base.y),
                               50 * player_status.score_multiplier);
   play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
   player_status.score_multiplier++;
@@ -1072,7 +1077,7 @@ BadGuy::squish(Player* player)
     explode(false);
     
     make_player_jump(player);
-    World::current()->add_score(Vector(base.x, base.y),
+    Sector::current()->add_score(Vector(base.x, base.y),
                                 50 * player_status.score_multiplier);
     play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
     player_status.score_multiplier++;
@@ -1124,7 +1129,7 @@ BadGuy::squish(Player* player)
       
     make_player_jump(player);
              
-    World::current()->add_score(Vector(base.x, base.y),
+    Sector::current()->add_score(Vector(base.x, base.y),
                                 25 * player_status.score_multiplier);
     player_status.score_multiplier++;
      
@@ -1156,7 +1161,7 @@ BadGuy::squish(Player* player)
       make_player_jump(player);
       base.y += 66 - base.height;
              
-      World::current()->add_score(Vector(base.x, base.y),
+      Sector::current()->add_score(Vector(base.x, base.y),
                                 25 * player_status.score_multiplier);
       player_status.score_multiplier++;
 
@@ -1178,7 +1183,7 @@ BadGuy::kill_me(int score)
     set_sprite(img_mriceblock_falling_left, img_mriceblock_falling_right);
     if(mode == HELD) {
       mode = NORMAL;
-      Player& tux = *World::current()->get_tux();  
+      Player& tux = *Sector::current()->player;
       tux.holding_something = false;
     }
   }
@@ -1187,7 +1192,7 @@ BadGuy::kill_me(int score)
 
   /* Gain some points: */
   if (score != 0)
-    World::current()->add_score(Vector(base.x, base.y),
+    Sector::current()->add_score(Vector(base.x, base.y),
                                 score * player_status.score_multiplier);
 
   /* Play death sound: */
@@ -1197,7 +1202,7 @@ BadGuy::kill_me(int score)
 void
 BadGuy::explode(bool right_way)
 {
-  BadGuy *badguy = World::current()->add_bad_guy(base.x, base.y, BAD_BOMB);
+  BadGuy *badguy = Sector::current()->add_bad_guy(base.x, base.y, BAD_BOMB);
   if(right_way)
     {
     badguy->timer.start(0);
index d1a6b84..c6b6eec 100644 (file)
@@ -28,6 +28,7 @@
 #include "screen/texture.h"
 #include "physic.h"
 #include "sprite.h"
+#include "defines.h"
 #include "moving_object.h"
 #include "collision.h"
 #include "serializable.h"
@@ -47,7 +48,9 @@ enum BadGuyKind {
   BAD_SNOWBALL,
   BAD_WINGLING,
   BAD_WALKINGTREE,
-  NUM_BadGuyKinds
+  NUM_BadGuyKinds,
+
+  BAD_INVALID
 };
 
 BadGuyKind  badguykind_from_string(const std::string& str);
index e8cd4f5..6985fd7 100644 (file)
 #include <math.h>
 #include "lispwriter.h"
 #include "player.h"
-#include "level.h"
+#include "tilemap.h"
+#include "gameloop.h"
 #include "globals.h"
-#include "world.h"
+#include "sector.h"
 
-Camera::Camera(Player* newplayer, Level* newlevel)
-  : player(newplayer), level(newlevel), do_backscrolling(true),
-    scrollchange(NONE), auto_idx(0), auto_t(0)
+Camera::Camera(Sector* newsector)
+  : sector(newsector), do_backscrolling(true), scrollchange(NONE),
+    auto_idx(0), auto_t(0)
 {
-  if(!player || !level)
-    mode = MANUAL;
-  else
-    mode = NORMAL;
+  mode = NORMAL;
 }
 
 Camera::~Camera()
@@ -44,7 +42,7 @@ Camera::~Camera()
 const Vector&
 Camera::get_translation() const
 {
-  return World::current()->context.get_translation();
+  return translation;
 }
 
 void
@@ -52,17 +50,17 @@ Camera::read(LispReader& reader)
 {
   std::string modename;
   
-  reader.read_string("mode", &modename);
+  reader.read_string("mode", modename);
   if(modename == "normal") {
     mode = NORMAL;
 
     do_backscrolling = true;
-    reader.read_bool("backscrolling", &do_backscrolling);
+    reader.read_bool("backscrolling", do_backscrolling);
   } else if(modename == "autoscroll") {
     mode = AUTOSCROLL;
     
     lisp_object_t* cur = 0;
-    reader.read_lisp("path", &cur);
+    reader.read_lisp("path", cur);
     if(cur == 0) {
       throw std::runtime_error("No path specified in autoscroll camera.");
     }
@@ -76,11 +74,11 @@ Camera::read(LispReader& reader)
       LispReader reader(lisp_cdr(lisp_car(cur)));
 
       ScrollPoint point;
-      if(!reader.read_float("x", &point.position.x) ||
-         !reader.read_float("y", &point.position.y)) {
+      if(!reader.read_float("x", point.position.x) ||
+         !reader.read_float("y", point.position.y)) {
         throw std::runtime_error("x and y missing in point of camerapath");
       }
-      reader.read_float("speed", &speed);
+      reader.read_float("speed", speed);
       point.speed = speed;
       scrollpoints.push_back(point);
 
@@ -123,30 +121,39 @@ Camera::write(LispWriter& writer)
   writer.end_list("camera");
 }
 
+void
+Camera::reset(const Vector& tuxpos)
+{
+  translation.x = tuxpos.x - screen->w/3 * 2;
+  translation.y = tuxpos.y - screen->h/2;
+  keep_in_bounds();
+}
+
 static const float EPSILON = .00001;
 static const float max_speed_y = 1.4;
 
 void
 Camera::action(float elapsed_time)
 {
-  translation = World::current()->context.get_translation();
   if(mode == NORMAL)
     scroll_normal(elapsed_time);
   else if(mode == AUTOSCROLL)
     scroll_autoscroll(elapsed_time);
-  World::current()->context.set_translation(translation);
 }
 
 void
 Camera::keep_in_bounds()
 {
+  float width = sector->solids->get_width() * 32;
+  float height = sector->solids->get_height() * 32;
+
   // don't scroll before the start or after the level's end
-  if(translation.y > level->height * 32 - screen->h)
-    translation.y = level->height * 32 - screen->h;
+  if(translation.y > height - screen->h)
+    translation.y = height - screen->h;
   if(translation.y < 0)                                      
     translation.y = 0; 
-  if(translation.x > level->width * 32 - screen->w)
-    translation.x = level->width * 32 - screen->w;
+  if(translation.x > width - screen->w)
+    translation.x = width - screen->w;
   if(translation.x < 0)
     translation.x = 0;                                         
 }
@@ -154,7 +161,8 @@ Camera::keep_in_bounds()
 void
 Camera::scroll_normal(float elapsed_time)
 {
-  assert(level != 0 && player != 0);
+  assert(sector != 0);
+  Player* player = sector->player;
   
   // check that we don't have division by zero later
   if(elapsed_time < EPSILON)
@@ -163,7 +171,7 @@ Camera::scroll_normal(float elapsed_time)
   /****** Vertical Scrolling part ******/
   bool do_y_scrolling = true;
 
-  if(player->dying || level->height == 19)
+  if(player->dying || sector->solids->get_height() == 19)
     do_y_scrolling = false;
 
   if(do_y_scrolling) {
@@ -241,6 +249,8 @@ Camera::scroll_normal(float elapsed_time)
 void
 Camera::scroll_autoscroll(float elapsed_time)
 {
+  Player* player = sector->player;
+  
   if(player->dying)
     return;
 
index b64e71d..648084e 100644 (file)
 #include <cassert>
 
 class LispReader;
-class Player;
-class Level;
+class Sector;
 
 class Camera : public GameObject, public Serializable
 {
 public:
-  Camera(Player* player = 0, Level* level = 0);
+  Camera(Sector* sector);
   virtual ~Camera();
 
   /// parse camera mode from lisp file
@@ -40,6 +39,9 @@ public:
   /// write camera mode to a lisp file
   virtual void write(LispWriter& writer);
 
+  /// reset camera postion
+  virtual void reset(const Vector& tuxpos);
+
   /** @deprecated@ */
   const Vector& get_translation() const;
 
@@ -68,8 +70,7 @@ private:
     
   Vector translation;
 
-  Player* player;
-  Level* level;
+  Sector* sector;
 
   // normal mode
   bool do_backscrolling;
index d431f40..e36327f 100644 (file)
@@ -22,8 +22,8 @@
 #include "collision.h"
 #include "bitmask.h"
 #include "scene.h"
-#include "world.h"
-#include "level.h"
+#include "sector.h"
+#include "tilemap.h"
 #include "tile.h"
 
 bool rectcollision(const base_type& one, const base_type& two)
@@ -44,11 +44,7 @@ bool rectcollision_offset(const base_type& one, const base_type& two, float off_
 
 bool collision_object_map(const base_type& base)
 {
-  if(!World::current())
-  return false;
-  
-  const Level& level = *World::current()->get_level();
-  TileManager& tilemanager = *TileManager::instance();
+  const TileMap& tilemap = *Sector::current()->solids;
 
   // we make the collision rectangle 1 pixel smaller
   int starttilex = int(base.x+1) / 32;
@@ -58,8 +54,8 @@ bool collision_object_map(const base_type& base)
 
   for(int x = starttilex; x*32 < max_x; ++x) {
     for(int y = starttiley; y*32 < max_y; ++y) {
-      Tile* tile = tilemanager.get(level.get_tile_at(x, y));
-      if(tile && (tile->attributes & Tile::SOLID))
+      Tile* tile = tilemap.get_tile(x, y);
+      if(tile->attributes & Tile::SOLID)
         return true;
     }
   }
@@ -69,8 +65,7 @@ bool collision_object_map(const base_type& base)
 
 void* collision_func(const base_type& base, tiletestfunction function)
 {
-  const Level& level = *World::current()->get_level();
-  TileManager& tilemanager = *TileManager::instance();
+  const TileMap& tilemap = *Sector::current()->solids;
   
   int starttilex = int(base.x) / 32;
   int starttiley = int(base.y) / 32;
@@ -79,7 +74,7 @@ void* collision_func(const base_type& base, tiletestfunction function)
 
   for(int x = starttilex; x*32 < max_x; ++x) {
     for(int y = starttiley; y*32 < max_y; ++y) {
-      Tile* tile = tilemanager.get(level.get_tile_at(x, y));
+      Tile* tile = tilemap.get_tile(x, y);
       void* result = function(tile);
       if(result != 0)
         return result;
@@ -242,7 +237,8 @@ void collision_swept_object_map(base_type* old, base_type* current)
 
 Tile* gettile(float x, float y)
 {
-  return TileManager::instance()->get(World::current()->get_level()->gettileid(x, y));
+  const TileMap& tilemap = *Sector::current()->solids;
+  return tilemap.get_tile_at(Vector(x, y));
 }
 
 bool issolid(float x, float y)
index b6c243e..3993665 100644 (file)
@@ -24,7 +24,6 @@
 #include "type.h"
 
 class Tile;
-class World;
 
 /* Collision objects */
 enum
index 5be9d1a..33447a1 100644 (file)
@@ -74,36 +74,36 @@ void loadconfig(void)
 
   LispReader reader(lisp_cdr(root_obj));
 
-  reader.read_bool("fullscreen", &use_fullscreen);
-  reader.read_bool("sound",      &use_sound);
-  reader.read_bool("music",      &use_music);
-  reader.read_bool("show_fps",   &show_fps);
+  reader.read_bool("fullscreen", use_fullscreen);
+  reader.read_bool("sound",      use_sound);
+  reader.read_bool("music",      use_music);
+  reader.read_bool("show_fps",   show_fps);
 
   std::string video;
-  reader.read_string ("video", &video);
+  reader.read_string ("video", video);
   if (video == "opengl")
     use_gl = true;
   else
     use_gl = false;
 
-  reader.read_int ("joystick", &joystick_num);
+  reader.read_int ("joystick", joystick_num);
   if (!(joystick_num >= 0))
     use_joystick = false;
   else
     use_joystick = true;
 
-  reader.read_int ("joystick-x", &joystick_keymap.x_axis);
-  reader.read_int ("joystick-y", &joystick_keymap.y_axis);
-  reader.read_int ("joystick-a", &joystick_keymap.a_button);
-  reader.read_int ("joystick-b", &joystick_keymap.b_button);
-  reader.read_int ("joystick-start", &joystick_keymap.start_button);
-  reader.read_int ("joystick-deadzone", &joystick_keymap.dead_zone);
+  reader.read_int ("joystick-x", joystick_keymap.x_axis);
+  reader.read_int ("joystick-y", joystick_keymap.y_axis);
+  reader.read_int ("joystick-a", joystick_keymap.a_button);
+  reader.read_int ("joystick-b", joystick_keymap.b_button);
+  reader.read_int ("joystick-start", joystick_keymap.start_button);
+  reader.read_int ("joystick-deadzone", joystick_keymap.dead_zone);
 
-  reader.read_int ("keyboard-jump", &keymap.jump);
-  reader.read_int ("keyboard-duck", &keymap.duck);
-  reader.read_int ("keyboard-left", &keymap.left);
-  reader.read_int ("keyboard-right", &keymap.right);
-  reader.read_int ("keyboard-fire", &keymap.fire);
+  reader.read_int ("keyboard-jump", keymap.jump);
+  reader.read_int ("keyboard-duck", keymap.duck);
+  reader.read_int ("keyboard-left", keymap.left);
+  reader.read_int ("keyboard-right", keymap.right);
+  reader.read_int ("keyboard-fire", keymap.fire);
 
   lisp_free(root_obj);
 }
@@ -111,7 +111,6 @@ void loadconfig(void)
 void saveconfig (void)
 {
   /* write settings to config file */
-
   FILE * config = opendata(config_filename, "w");
 
   if(config)
index ac9ad58..7b7afc9 100644 (file)
@@ -44,7 +44,7 @@
 #include "high_scores.h"
 #include "menu.h"
 #include "badguy.h"
-#include "world.h"
+#include "sector.h"
 #include "special.h"
 #include "player.h"
 #include "level.h"
 #include "particlesystem.h"
 #include "resources.h"
 #include "background.h"
+#include "tilemap.h"
 #include "music_manager.h"
 
 GameSession* GameSession::current_ = 0;
 
-GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
-  : world(0), st_gl_mode(mode), levelnb(levelnb_), end_sequence(NO_ENDSEQUENCE),
-    subset(subset_)
+GameSession::GameSession(const std::string& levelname_, int mode)
+  : level(0), currentsector(0), st_gl_mode(mode),
+    end_sequence(NO_ENDSEQUENCE), levelname(levelname_)
 {
   current_ = this;
   
@@ -71,6 +72,8 @@ GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
   fps_timer.init(true);            
   frame_timer.init(true);
 
+  context = new DrawingContext();
+
   restart_level();
 }
 
@@ -84,28 +87,25 @@ GameSession::restart_level()
   fps_timer.init(true);
   frame_timer.init(true);
 
+#if 0
   float old_x_pos = -1;
-
   if (world)
     { // Tux has lost a life, so we try to respawn him at the nearest reset point
       old_x_pos = world->get_tux()->base.x;
     }
+#endif
   
-  delete world;
+  delete level;
+  currentsector = 0;
 
-  if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
-    {
-      world = new World(subset);
-    }
-  else if (st_gl_mode == ST_GL_DEMO_GAME)
-    {
-      world = new World(subset);
-    }
-  else
-    {
-      world = new World(subset, levelnb);
-    }
+  level = new Level;
+  level->load(levelname);
+  currentsector = level->get_sector("main");
+  if(!currentsector)
+    st_abort("Level has no main sector.", "");
+  currentsector->activate("main");
 
+#if 0 // TODO
   // Set Tux to the nearest reset point
   if (old_x_pos != -1)
     {
@@ -123,6 +123,7 @@ GameSession::restart_level()
           world->get_tux()->base.y = best_reset_point.y;
         }
     }
+#endif
     
   if (st_gl_mode != ST_GL_DEMO_GAME)
     {
@@ -132,12 +133,13 @@ GameSession::restart_level()
 
   time_left.init(true);
   start_timers();
-  world->play_music(LEVEL_MUSIC);
+  currentsector->play_music(LEVEL_MUSIC);
 }
 
 GameSession::~GameSession()
 {
-  delete world;
+  delete level;
+  delete context;
 }
 
 void
@@ -148,16 +150,18 @@ GameSession::levelintro(void)
   char str[60];
 
   DrawingContext context;
-  world->background->draw(context);
+  currentsector->background->draw(context);
 
-  sprintf(str, "%s", world->get_level()->name.c_str());
-  context.draw_text_center(gold_text, str, Vector(0, 220), 0);
+  context.draw_text_center(gold_text, level->get_name(), Vector(0, 220),
+      LAYER_FOREGROUND1);
 
   sprintf(str, "TUX x %d", player_status.lives);
-  context.draw_text_center(white_text, str, Vector(0, 240), 0);
+  context.draw_text_center(white_text, str, Vector(0, 240),
+      LAYER_FOREGROUND1);
   
-  sprintf(str, "by %s", world->get_level()->author.c_str());
-  context.draw_text_center(white_small_text, str, Vector(0, 400), 0);
+  context.draw_text_center(white_small_text,
+      std::string("by ") + level->get_author(), 
+      Vector(0, 400), LAYER_FOREGROUND1);
 
   context.do_drawing();
 
@@ -169,7 +173,7 @@ GameSession::levelintro(void)
 void
 GameSession::start_timers()
 {
-  time_left.start(world->get_level()->time_left*1000);
+  time_left.start(level->time_left*1000);
   st_pause_ticks_init();
   update_time = st_get_ticks();
 }
@@ -177,8 +181,9 @@ GameSession::start_timers()
 void
 GameSession::on_escape_press()
 {
-  if(world->get_tux()->dying || end_sequence != NO_ENDSEQUENCE)
+  if(currentsector->player->dying || end_sequence != NO_ENDSEQUENCE)
     return;   // don't let the player open the menu, when he is dying
+  
   if(game_pause)
     return;
 
@@ -191,7 +196,7 @@ GameSession::on_escape_press()
       /* Tell Tux that the keys are all down, otherwise
         it could have nasty bugs, like going allways to the right
         or whatever that key does */
-      Player& tux = *world->get_tux();
+      Player& tux = *(currentsector->player);
       tux.key_event((SDLKey)keymap.jump, UP);
       tux.key_event((SDLKey)keymap.duck, UP);
       tux.key_event((SDLKey)keymap.left, UP);
@@ -208,7 +213,7 @@ GameSession::process_events()
 {
   if (end_sequence != NO_ENDSEQUENCE)
     {
-      Player& tux = *world->get_tux();
+      Player& tux = *currentsector->player;
          
       tux.input.fire  = UP;
       tux.input.left  = UP;
@@ -277,7 +282,7 @@ GameSession::process_events()
             }
           else
             {
-              Player& tux = *world->get_tux();
+              Player& tux = *currentsector->player;
   
               switch(event.type)
                 {
@@ -429,10 +434,10 @@ GameSession::process_events()
 void
 GameSession::check_end_conditions()
 {
-  Player* tux = world->get_tux();
+  Player* tux = currentsector->player;
 
   /* End of level? */
-  int endpos = (World::current()->get_level()->width-5) * 32;
+  int endpos = (currentsector->solids->get_width() - 5) * 32;
   Tile* endtile = collision_goal(tux->base);
 
   // fallback in case the other endpositions don't trigger
@@ -481,52 +486,45 @@ GameSession::check_end_conditions()
 void
 GameSession::action(double frame_ratio)
 {
-  if (exit_status == ES_NONE && !world->get_tux()->growing_timer.check())
+  if (exit_status == ES_NONE && !currentsector->player->growing_timer.check())
     {
       // Update Tux and the World
-      world->action(frame_ratio);
+      currentsector->action(frame_ratio);
     }
 }
 
 void 
 GameSession::draw()
 {
-  DrawingContext& context = world->context;
-  
-  world->draw();
-  drawstatus(context);
+  currentsector->draw(*context);
+  drawstatus(*context);
 
   if(game_pause)
     {
-      context.push_transform();
-      context.set_translation(Vector(0, 0));
-        
       int x = screen->h / 20;
       for(int i = 0; i < x; ++i)
         {
-          context.draw_filled_rect(
+          context->draw_filled_rect(
               Vector(i % 2 ? (pause_menu_frame * i)%screen->w :
                 -((pause_menu_frame * i)%screen->w)
                 ,(i*20+pause_menu_frame)%screen->h),
               Vector(screen->w,10),
               Color(20,20,20, rand() % 20 + 1), LAYER_FOREGROUND1+1);
         }
-      context.draw_filled_rect(
+      context->draw_filled_rect(
           Vector(0,0), Vector(screen->w, screen->h),
           Color(rand() % 50, rand() % 50, rand() % 50, 128), LAYER_FOREGROUND1);
-      world->context.draw_text_center(blue_text, "PAUSE - Press 'P' To Play",
+      context->draw_text_center(blue_text, "PAUSE - Press 'P' To Play",
           Vector(0, 230), LAYER_FOREGROUND1+2);
-
-      context.pop_transform();
     }
 
   if(Menu::current())
     {
-      Menu::current()->draw(context);
-      mouse_cursor->draw(context);
+      Menu::current()->draw(*context);
+      mouse_cursor->draw(*context);
     }
 
-  context.do_drawing();
+  context->do_drawing();
 }
 
 void
@@ -589,7 +587,8 @@ GameSession::run()
         }
 
       /* Handle events: */
-      world->get_tux()->input.old_fire = world->get_tux()->input.fire;
+      currentsector->player->input.old_fire 
+        = currentsector->player->input.fire;
 
       process_events();
       process_menu();
@@ -634,24 +633,24 @@ GameSession::run()
         }
 
       /* Handle time: */
-      if (!time_left.check() && world->get_tux()->dying == DYING_NOT
+      if (!time_left.check() && currentsector->player->dying == DYING_NOT
               && !end_sequence)
-        world->get_tux()->kill(Player::KILL);
+        currentsector->player->kill(Player::KILL);
 
       /* Handle music: */
-      if(world->get_tux()->invincible_timer.check() && !end_sequence)
+      if(currentsector->player->invincible_timer.check() && !end_sequence)
         {
-          world->play_music(HERRING_MUSIC);
+          currentsector->play_music(HERRING_MUSIC);
         }
       /* are we low on time ? */
       else if (time_left.get_left() < TIME_WARNING && !end_sequence)
         {
-          world->play_music(HURRYUP_MUSIC);
+          currentsector->play_music(HURRYUP_MUSIC);
         }
       /* or just normal music? */
-      else if(world->get_music_type() != LEVEL_MUSIC && !end_sequence)
+      else if(currentsector->get_music_type() != LEVEL_MUSIC && !end_sequence)
         {
-          world->play_music(LEVEL_MUSIC);
+          currentsector->play_music(LEVEL_MUSIC);
         }
 
       /* Calculate frames per second */
@@ -674,7 +673,7 @@ GameSession::run()
 /* Bounce a brick: */
 void bumpbrick(float x, float y)
 {
-  World::current()->add_bouncy_brick(Vector(((int)(x + 1) / 32) * 32,
+  Sector::current()->add_bouncy_brick(Vector(((int)(x + 1) / 32) * 32,
                          (int)(y / 32) * 32));
 
   play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
@@ -684,9 +683,6 @@ void bumpbrick(float x, float y)
 void
 GameSession::drawstatus(DrawingContext& context)
 {
-  context.push_transform();
-  context.set_translation(Vector(0, 0));
-  
   char str[60];
   
   snprintf(str, 60, "%d", player_status.score);
@@ -742,8 +738,6 @@ GameSession::drawstatus(DrawingContext& context)
       context.draw_text(gold_text, str,
           Vector(screen->w-4*16, 40), LAYER_FOREGROUND1);
     }
-
-  context.pop_transform();
 }
 
 void
@@ -752,7 +746,7 @@ GameSession::drawresultscreen(void)
   char str[80];
 
   DrawingContext context;
-  world->background->draw(context);  
+  currentsector->background->draw(context);  
 
   context.draw_text_center(blue_text, "Result:", Vector(0, 200),
       LAYER_FOREGROUND1);
@@ -780,7 +774,7 @@ std::string slotinfo(int slot)
   if (savegame)
     {
       LispReader reader(lisp_cdr(savegame));
-      reader.read_string("title", &title);
+      reader.read_string("title", title);
       lisp_free(savegame);
     }
 
index a2eb7c7..4e990f3 100644 (file)
@@ -24,8 +24,6 @@
 
 #include "sound.h"
 #include "type.h"
-#include "level.h"
-#include "world.h"
 
 /* GameLoop modes */
 
 
 extern int game_started;
 
-class World;
+class Level;
+class Sector;
+class DrawingContext;
 
 /** The GameSession class controlls the controll flow of a World, ie.
     present the menu on specifc keypresses, render and update it while
     keeping the speed and framerate sane, etc. */
 class GameSession
 {
- private:
+private:
   Timer fps_timer;
   Timer frame_timer;
   Timer endsequence_timer;
-  World* world;
+  Level* level;
+  Sector* currentsector;
+
   int st_gl_mode;
   int levelnb;
   float fps_fps;
@@ -69,18 +71,16 @@ class GameSession
 
   bool game_pause;
 
-  // FIXME: Hack for restarting the level
-  std::string subset;
-
- public:
+  std::string levelname;
+public:
   enum ExitStatus { ES_NONE, ES_LEVEL_FINISHED, ES_GAME_OVER, ES_LEVEL_ABORT };
- private:
+private:
   ExitStatus exit_status;
- public:
-
+public:
+  DrawingContext* context;
   Timer time_left;
 
-  GameSession(const std::string& subset, int levelnb, int mode);
+  GameSession(const std::string& level, int mode);
   ~GameSession();
 
   /** Enter the busy loop */
@@ -89,11 +89,14 @@ class GameSession
   void draw();
   void action(double frame_ratio);
 
-  Level* get_level() { return world->get_level(); }
-  World* get_world() { return world; }
-
+  void set_current()
+  { current_ = this; }
   static GameSession* current() { return current_; }
- private:
+
+  Sector* get_current_sector()
+  { return currentsector; }
+  
+private:
   static GameSession* current_;
 
   void restart_level();
@@ -107,7 +110,7 @@ class GameSession
   void drawendscreen();
   void drawresultscreen(void);
 
- private:
+private:
   void on_escape_press();
   void process_menu();
 };
index 9c8e79c..9075f2c 100644 (file)
 #include <algorithm>
 #include <iostream>
 #include <math.h>
-#include "world.h"
 #include "tile.h"
 #include "gameloop.h"
 #include "gameobjs.h"
 #include "sprite_manager.h"
 #include "resources.h"
-#include "level.h"
+#include "sector.h"
+#include "tilemap.h"
 
 BouncyDistro::BouncyDistro(const Vector& pos)
   : position(pos)
@@ -80,7 +80,7 @@ BrokenBrick::draw(DrawingContext& context)
 BouncyBrick::BouncyBrick(const Vector& pos)
   : position(pos), offset(0), offset_m(-BOUNCY_BRICK_SPEED)
 {
-  shape    = World::current()->get_level()->gettileid(pos.x, pos.y);
+  shape = Sector::current()->solids->get_tile_id_at(pos);
 }
 
 void
@@ -134,12 +134,12 @@ Sprite *img_trampoline[TRAMPOLINE_FRAMES];
 
 Trampoline::Trampoline(LispReader& reader)
 {
-  reader.read_float("x", &base.x);
-  reader.read_float("y", &base.y); 
+  reader.read_float("x", base.x);
+  reader.read_float("y", base.y); 
   base.width = 32;
   base.height = 32;
   power = 7.5;
-  reader.read_float("power", &power);
+  reader.read_float("power", power);
 
   frame = 0;
   mode = M_NORMAL;
@@ -191,7 +191,7 @@ Trampoline::action(float frame_ratio)
   {
     /* FIXME: The trampoline object shouldn't know about pplayer objects. */
     /* If we're holding the iceblock */
-    Player& tux = *World::current()->get_tux();
+    Player& tux = *Sector::current()->player;
     Direction dir = tux.dir;
 
     if(dir == RIGHT)
@@ -271,11 +271,11 @@ Sprite *img_flying_platform;
 
 FlyingPlatform::FlyingPlatform(LispReader& reader)
 {
-  reader.read_int_vector("x",  &pos_x);
-  reader.read_int_vector("y",  &pos_y);
+  reader.read_int_vector("x", pos_x);
+  reader.read_int_vector("y", pos_y);
 
   velocity = 2.0;
-  reader.read_float("velocity", &velocity);
+  reader.read_float("velocity", velocity);
 
   base.x = pos_x[0];
   base.y = pos_y[0];
index c4ce9ff..d9459f4 100644 (file)
@@ -30,6 +30,7 @@
 #include "collision.h"
 #include "game_object.h"
 #include "moving_object.h"
+#include "serializable.h"
 #include "lispwriter.h"
 
 /* Bounciness of distros: */
index 044c882..af4f754 100644 (file)
@@ -70,8 +70,8 @@ void load_hs(void)
   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-highscore") == 0)
     {
       LispReader reader(lisp_cdr(root_obj));
-      reader.read_int("score",  &hs_score);
-      reader.read_string("name", &hs_name);
+      reader.read_int("score",  hs_score);
+      reader.read_string("name", hs_name);
     }
  
   fclose(fi);
index ab90191..cc30db4 100644 (file)
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <iostream>
 #include <fstream>
+#include <stdexcept>
 #include "globals.h"
 #include "setup.h"
 #include "camera.h"
 #include "level.h"
 #include "physic.h"
 #include "scene.h"
+#include "sector.h"
 #include "tile.h"
 #include "lispreader.h"
 #include "resources.h"
 #include "music_manager.h"
 #include "gameobjs.h"
-#include "world.h"
-#include "background.h"
 #include "lispwriter.h"
 
 using namespace std;
@@ -60,8 +60,7 @@ void LevelSubset::create(const std::string& subset_name)
   new_subset.title = "Unknown Title";
   new_subset.description = "No description so far.";
   new_subset.save();
-  new_lev.init_defaults();
-  new_lev.save(subset_name, 1, 0);
+  //new_lev.save(subset_name, 1, 0);
 }
 
 void LevelSubset::parse (lisp_object_t* cursor)
@@ -96,7 +95,7 @@ void LevelSubset::parse (lisp_object_t* cursor)
     }
 }
 
-void LevelSubset::load(char *subset)
+void LevelSubset::load(const char* subset)
 {
   FILE* fi;
   char filename[1024];
@@ -169,7 +168,8 @@ void LevelSubset::load(char *subset)
   levels = --i;
 }
 
-void LevelSubset::save()
+void
+LevelSubset::save()
 {
   FILE* fi;
   string filename;
@@ -201,408 +201,99 @@ void LevelSubset::save()
 
       fprintf( fi,")");
       fclose(fi);
-
     }
 }
 
-Level::Level()
-  : img_bkgd(0)
-{
-  init_defaults();
-}
-
-Level::~Level()
-{
-  delete img_bkgd;
-}
-
-void
-Level::init_defaults()
-{
-  name       = "UnNamed";
-  author     = "UnNamed";
-  song_title = "Mortimers_chipdisko.mod";
-  width      = 0;
-  height     = 0;
-  start_pos.x = 100;
-  start_pos.y = 170;
-  time_left  = 100;
-  gravity    = 10.;
-
-  resize(21, 19);
-}
-
-int
-Level::load(const std::string& subset, int level, World* world)
+std::string
+LevelSubset::get_level_filename(unsigned int num)
 {
   char filename[1024];
-
+                                                                                
   // Load data file:
-  snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset.c_str(), level);
+  snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir,
+      name.c_str(), num);
   if(!faccessible(filename))
-    snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level);
-
-  return load(filename, world);
-}
+    snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
+        name.c_str(), num);
 
-int 
-Level::load(const std::string& filename, World* world)
-{
-  lisp_object_t* root_obj = lisp_read_from_file(filename);
-  if (!root_obj)
-    {
-      std::cout << "Level: Couldn't load file: " << filename << std::endl;
-      return -1;
-    }
-
-  if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
-    {
-      lisp_free(root_obj);
-      std::cout << "World: Parse Error in file '" << filename
-                << "'.\n";
-      return -1;
-    }
-
-  int version = 0;
-  if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
-    {
-      LispReader reader(lisp_cdr(root_obj));
-      version = 0;
-      reader.read_int("version",  &version);
-      if(!reader.read_int("width",  &width))
-        st_abort("No width specified for level.", "");
-      if (!reader.read_float("start_pos_x", &start_pos.x)) start_pos.x = 100;
-      if (!reader.read_float("start_pos_y", &start_pos.y)) start_pos.y = 170;
-      time_left = 500;
-      if(!reader.read_int("time",  &time_left)) {
-        printf("Warning: no time specified for level.\n");
-      }
-      
-      height = 15;
-      if(!reader.read_int("height",  &height)) {
-        printf("Warning: no height specified for level.\n");
-      }
-
-
-      // read old background stuff
-      int bkgd_speed = 50;
-      reader.read_int("bkgd_speed",  &bkgd_speed);
-      
-      Color bkgd_top, bkgd_bottom;
-      int r, g, b;
-      reader.read_int("bkgd_red_top", &r);
-      reader.read_int("bkgd_green_top",  &g);
-      reader.read_int("bkgd_blue_top",  &b);
-      bkgd_top.red = r;
-      bkgd_top.green = g;
-      bkgd_top.blue = b;
-
-      reader.read_int("bkgd_red_bottom",  &r);
-      reader.read_int("bkgd_green_bottom",  &g);
-      reader.read_int("bkgd_blue_bottom",  &b);
-      bkgd_bottom.red = r;
-      bkgd_bottom.green = g;
-      bkgd_bottom.blue = b;
-
-      std::string bkgd_image;
-      reader.read_string("background",  &bkgd_image);
-
-      if(world) {
-        Background* background = new Background();
-        if(bkgd_image != "")
-          background->set_image(bkgd_image, bkgd_speed);
-        else
-          background->set_gradient(bkgd_top, bkgd_bottom);
-
-        world->add_object(background);
-      }
-
-      gravity = 10;
-      reader.read_float("gravity",  &gravity);
-      name = "Noname";
-      reader.read_string("name",  &name);
-      author = "unknown author";
-      reader.read_string("author", &author);
-      song_title = "";
-      reader.read_string("music",  &song_title);
-      particle_system = "";
-      reader.read_string("particle_system", &particle_system);
-
-      reader.read_int_vector("background-tm",  &bg_tiles);
-      if(int(bg_tiles.size()) != width * height)
-        st_abort("Wrong size of backgroundtilemap", "");
-
-      if (!reader.read_int_vector("interactive-tm", &ia_tiles))
-        reader.read_int_vector("tilemap", &ia_tiles);
-      if(int(ia_tiles.size()) != width * height)
-        st_abort("Wrong size of interactivetilemap", "");      
-
-      reader.read_int_vector("foreground-tm",  &fg_tiles);
-      if(int(fg_tiles.size()) != width * height)
-        st_abort("Wrong size of foregroundtilemap", "");      
-
-      { // Read ResetPoints
-        lisp_object_t* cur = 0;
-        if (reader.read_lisp("reset-points",  &cur))
-          {
-            while (!lisp_nil_p(cur))
-              {
-                lisp_object_t* data = lisp_car(cur);
-
-                ResetPoint pos;
-
-                LispReader reader(lisp_cdr(data));
-                if (reader.read_int("x", &pos.x)
-                    && reader.read_int("y", &pos.y))
-                  {
-                    reset_points.push_back(pos);
-                  }
-
-                cur = lisp_cdr(cur);
-              }
-          }
-      }
-
-      { // Read Objects
-        lisp_object_t* cur = 0;
-        if (reader.read_lisp("objects",  &cur))
-          {
-            if(world)
-              world->parse_objects(cur);
-          }
-      }
-
-      { // Read Camera
-        lisp_object_t* cur = 0;
-        if (reader.read_lisp("camera", &cur))
-          {
-            LispReader reader(cur);
-            if(world) {
-              world->camera->read(reader);
-            }
-          }
-      }
-    }
-
-  lisp_free(root_obj);
-  return 0;
+  return std::string(filename);
 }
 
-/* Save data for level: */
+//---------------------------------------------------------------------------
 
-void 
-Level::save(const std::string& subset, int level, World* world)
+Level::Level()
+  : name("noname"), author("mr. x"), time_left(500)
 {
-  char filename[1024];
-  char str[80];
-
-  /* Save data file: */
-  snprintf(str, sizeof(str), "/levels/%s/", subset.c_str());
-  fcreatedir(str);
-  snprintf(filename, sizeof(filename),
-      "%s/levels/%s/level%d.stl", st_dir, subset.c_str(), level);
-  if(!fwriteable(filename))
-    snprintf(filename, sizeof(filename), "%s/levels/%s/level%d.stl",
-        datadir.c_str(), subset.c_str(), level);
-
-  std::ofstream out(filename);
-  if(!out.good()) {
-    st_abort("Couldn't write file.", filename);
-  }
-  LispWriter writer(out);
-
-  /* Write header: */
-  writer.write_comment("SuperTux level made using the built-in leveleditor");
-  writer.start_list("supertux-level");
-
-  writer.write_int("version", 1);
-  writer.write_string("name", name);
-  writer.write_string("author", author);
-  writer.write_string("music", song_title);
-  writer.write_string("background", bkgd_image);
-  writer.write_string("particle_system", particle_system);
-  writer.write_int("time", time_left);
-  writer.write_int("width", width);
-  writer.write_int("height", height);
-  writer.write_float("gravity", gravity);
-
-  writer.write_int_vector("background-tm", bg_tiles);
-  writer.write_int_vector("interactive-tm", ia_tiles);
-  writer.write_int_vector("foreground-tm", fg_tiles);
-
-  writer.start_list("reset-points");
-  for(std::vector<ResetPoint>::iterator i = reset_points.begin();
-      i != reset_points.end(); ++i) {
-    writer.start_list("point");
-    writer.write_int("x", i->x);
-    writer.write_int("y", i->y);
-    writer.end_list("point");
-  }
-  writer.end_list("reset-points");
-
-  // write objects
-  writer.start_list("objects");
-  // pick all objects that can be written into a levelfile
-  for(std::vector<GameObject*>::iterator it = world->gameobjects.begin();
-      it != world->gameobjects.end(); ++it) {
-    Serializable* serializable = dynamic_cast<Serializable*> (*it);
-    if(serializable)
-      serializable->write(writer);
-  }
-  writer.end_list("objects");
-
-  writer.end_list("supertux-level");
-  out.close();
 }
 
-/* Unload data for this level: */
 void
-Level::cleanup()
+Level::load(const std::string& filename)
 {
-  bg_tiles.clear();
-  ia_tiles.clear();
-  fg_tiles.clear();
-
-  reset_points.clear();
-  name = "";
-  author = "";
-  song_title = "";
-}
-
-/* Load a level-specific graphic... */
-void Level::load_image(Surface** ptexture, string theme,const  char * file, int use_alpha)
-{
-  char fname[1024];
-
-  snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
-  if(!faccessible(fname))
-    snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
-
-  *ptexture = new Surface(fname, use_alpha);
-}
+  LispReader* level = LispReader::load(filename, "supertux-level");
 
-/* Change the size of a level */
-void 
-Level::resize(int new_width, int new_height)
-{
-  if(new_width < width) {
-    // remap tiles for new width
-    for(int y = 0; y < height && y < new_height; ++y) {
-      for(int x = 0; x < new_width; ++x) {
-        ia_tiles[y * new_width + x] = ia_tiles[y * width + x];
-        bg_tiles[y * new_width + x] = bg_tiles[y * width + x];
-        fg_tiles[y * new_width + x] = fg_tiles[y * width + x];
-      }
-    }
+  int version = 1;
+  level->read_int("version", version);
+  if(version == 1) {
+    load_old_format(*level);
+    return;
   }
 
-  ia_tiles.resize(new_width * new_height);
-  bg_tiles.resize(new_width * new_height);
-  fg_tiles.resize(new_width * new_height); 
-
-  if(new_width > width) {
-    // remap tiles
-    for(int y = std::min(height, new_height)-1; y >= 0; --y) {
-      for(int x = new_width-1; x >= 0; --x) {
-        if(x >= width) {
-          ia_tiles[y * new_width + x] = 0;
-          bg_tiles[y * new_width + x] = 0;
-          fg_tiles[y * new_width + x] = 0;
-        } else {
-          ia_tiles[y * new_width + x] = ia_tiles[y * width + x];
-          bg_tiles[y * new_width + x] = bg_tiles[y * width + x];
-          fg_tiles[y * new_width + x] = fg_tiles[y * width + x];
-        }
-      }
+  for(lisp_object_t* cur = level->get_lisp(); !lisp_nil_p(cur);
+      cur = lisp_cdr(cur)) {
+    std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
+    lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
+    LispReader reader(lisp_cdr(lisp_car(cur)));
+
+    if(token == "name") {
+      name = lisp_string(data);
+    } else if(token == "author") {
+      author = lisp_string(data);
+    } else if(token == "time") {
+      time_left = lisp_integer(data);
+    } else if(token == "sector") {
+      Sector* sector = new Sector;
+      sector->parse(reader);
+      add_sector(sector);
+    } else {
+      std::cerr << "Unknown token '" << token << "' in level file.\n";
+      continue;
     }
   }
-
-  height = new_height;
-  width = new_width;
-}
-
-void
-Level::change(float x, float y, int tm, unsigned int c)
-{
-  int yy = ((int)y / 32);
-  int xx = ((int)x / 32);
-
-  if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
-    {
-      switch(tm)
-        {
-        case TM_BG:
-          bg_tiles[yy * width + xx] = c;
-          break;
-        case TM_IA:
-          ia_tiles[yy * width + xx] = c;
-          break;
-        case TM_FG:
-          fg_tiles[yy * width + xx] = c;
-          break;
-        }
-    }
+  
+  delete level;
 }
 
 void
-Level::load_song()
+Level::load_old_format(LispReader& reader)
 {
-  char* song_path;
-  char* song_subtitle;
-
-  level_song = music_manager->load_music(datadir + "/music/" + song_title);
-
-  song_path = (char *) malloc(sizeof(char) * datadir.length() +
-                              strlen(song_title.c_str()) + 8 + 5);
-  song_subtitle = strdup(song_title.c_str());
-  strcpy(strstr(song_subtitle, "."), "\0");
-  sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), 
-          song_subtitle, strstr(song_title.c_str(), "."));
-  if(!music_manager->exists_music(song_path)) {
-    level_song_fast = level_song;
-  } else {
-    level_song_fast = music_manager->load_music(song_path);
-  }
-  free(song_subtitle);
-  free(song_path);
-}
+  reader.read_string("name", name);
+  reader.read_string("author", author);
+  reader.read_int("time", time_left);
 
-MusicRef
-Level::get_level_music()
-{
-  return level_song;
+  Sector* sector = new Sector;
+  sector->parse_old_format(reader);
+  add_sector(sector);
 }
 
-MusicRef
-Level::get_level_music_fast()
+Level::~Level()
 {
-  return level_song_fast;
+  for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
+    delete i->second;
 }
 
-unsigned int 
-Level::gettileid(float x, float y) const
+void
+Level::add_sector(Sector* sector)
 {
-  int xx, yy;
-  unsigned int c;
-
-  yy = ((int)y / 32);
-  xx = ((int)x / 32);
-
-  if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
-    c = ia_tiles[yy * width + xx];
-  else
-    c = 0;
-
-  return c;
+  sectors.insert(std::make_pair(sector->get_name(), sector));       
 }
 
-unsigned int
-Level::get_tile_at(int x, int y) const
+Sector*
+Level::get_sector(const std::string& name)
 {
-  if(x < 0 || x >= width || y < 0 || y >= height)
+  Sectors::iterator i = sectors.find(name);
+  if(i == sectors.end())
     return 0;
-  
-  return ia_tiles[y * width + x];
+
+  return i->second;
 }
 
-/* EOF */
index be51d5a..17272ba 100644 (file)
 #ifndef SUPERTUX_LEVEL_H
 #define SUPERTUX_LEVEL_H
 
+#include <map>
 #include <string>
 #include "screen/texture.h"
 #include "lispreader.h"
 #include "musicref.h"
 
 class Tile;
-class World;
 
 /** This type holds meta-information about a level-subset. 
     It could be extended to handle manipulation of subsets. */
@@ -38,9 +38,11 @@ public:
   ~LevelSubset();
 
   static void create(const std::string& subset_name);
-  void load(char *subset);
+  void load(const char* subset);
   void save();
 
+  std::string get_level_filename(unsigned int i);
+
   std::string name;
   std::string title;
   std::string description;
@@ -51,89 +53,36 @@ private:
   void parse(lisp_object_t* cursor);
 };
 
-#define LEVEL_NAME_MAX 20
-
-enum TileMapType {
- TM_BG,
- TM_IA,
- TM_FG
-};
-
-struct ResetPoint
-{
-  int x;
-  int y;
-};
+class Sector;
 
-class Level 
+class Level
 {
 public:
-  Surface* img_bkgd;
-  MusicRef level_song;
-  MusicRef level_song_fast;
-
   std::string name;
   std::string author;
-  std::string song_title;
-  std::string bkgd_image;
-  std::string particle_system;
-  std::vector<unsigned int> bg_tiles; /* Tiles in the background */
-  std::vector<unsigned int> ia_tiles; /* solid Tiles in the game */
-  std::vector<unsigned int> fg_tiles; /* Tiles in the foreground */
   int time_left;
-  int width;
-  int height;
-  Vector start_pos;
-  float gravity;
-
-  /** A collection of points to which Tux can be reset after a lost live */
-  std::vector<ResetPoint> reset_points;
- public:
+  typedef std::map<std::string, Sector*> Sectors;
+  Sectors sectors;
+
+public:
   Level();
-  Level(const std::string& subset, int level, World* world);
-  Level(const std::string& filename, World* world);
   ~Level();
 
-  /** Will the Level structure with default values */
-  void init_defaults();
-  
-  /** Cleanup the level struct from allocated tile data and such */
-  void cleanup();
-
-  /** Load data for this level: 
-      Returns -1, if the loading of the level failed. 
-      XXX the world parameter is a temporary hack   
-  */
-  int  load(const std::string& subset, int level, World* world);
-
-  /** Load data for this level: 
-      Returns -1, if the loading of the level failed. 
-      XXX the world parameter is a temporary hack
-   */
-  int  load(const std::string& filename, World* world);
-
-  void load_song();
-  void free_song();
-  MusicRef get_level_music();
-  MusicRef get_level_music_fast();
-
-  // XXX the world parameter is a temporary hack
-  void save(const std::string& subset, int level, World* world);
-
-  /** Edit a piece of the map! */
-  void change(float x, float y, int tm, unsigned int c);
-
-  /** Resize the level to a new width/height */
-  void resize(int new_width, int new_height);
-
-  /** Return the id of the tile at position x/y */
-  unsigned int gettileid(float x, float y) const;
-  /** returns the id of the tile at position x,y
-   * (these are logical and not pixel coordinates)
-   */
-  unsigned int get_tile_at(int x, int y) const;
-
-  void load_image(Surface** ptexture, std::string theme, const char * file, int use_alpha);
+  void load(const std::string& filename);
+  void save(const std::string& filename);
+
+  const std::string& get_name() const
+  { return name; }
+
+  const std::string& get_author() const
+  { return author; }
+
+  void add_sector(Sector* sector);
+
+  Sector* get_sector(const std::string& name);
+
+private:
+  void load_old_format(LispReader& reader);
 };
 
 #endif /*SUPERTUX_LEVEL_H*/
index 7f9f7a5..51ff97c 100644 (file)
@@ -1015,11 +1015,36 @@ lisp_dump (lisp_object_t *obj, FILE *out)
 using namespace std;
 
 LispReader::LispReader (lisp_object_t* l)
-    : lst (l)
+    : owner(0), lst (l)
 {
-  //std::cout << "LispReader: " << std::flush;
-  //lisp_dump(lst, stdout);
-  //std::cout << std::endl;
+}
+
+LispReader::~LispReader()
+{
+  if(owner)
+    lisp_free(owner);
+}
+
+LispReader*
+LispReader::load(const std::string& filename, const std::string& toplevellist)
+{
+  lisp_object_t* obj = lisp_read_from_file(filename);
+
+  if(obj->type == LISP_TYPE_EOF || obj->type == LISP_TYPE_PARSE_ERROR) {
+    lisp_free(obj);
+    throw LispReaderException("LispReader::load", __FILE__, __LINE__);
+  }
+
+  if(toplevellist != lisp_symbol(lisp_car(obj))) {
+    lisp_car(obj);
+    throw LispReaderException("LispReader::load wrong toplevel symbol",
+        __FILE__, __LINE__);
+  }
+  
+  LispReader* reader = new LispReader(lisp_cdr(obj));  
+  reader->owner = obj;
+
+  return reader;
 }
 
 lisp_object_t*
@@ -1052,147 +1077,148 @@ LispReader::search_for(const char* name)
 }
 
 bool
-LispReader::read_int (const char* name, int* i)
+LispReader::read_int (const char* name, int& i)
 {
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      if (!lisp_integer_p(lisp_car(obj)))
-      {
-        //st_abort("LispReader expected type integer at token: ", name); /* Instead of giving up, we return with false now. */
-       return false;
-       }
-      *i = lisp_integer(lisp_car(obj));
-      return true;
-    }
-  return false;
+  if(!obj)
+    return false;
+      
+  if (!lisp_integer_p(lisp_car(obj)))
+    return false;
+  
+  i = lisp_integer(lisp_car(obj));
+  return true;
 }
 
 bool
-LispReader::read_lisp(const char* name, lisp_object_t** b)
+LispReader::read_lisp(const char* name, lisp_object_t*& b)
 {
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      *b = obj;
-      return true;
-    }
-  else
+  if (!obj)
     return false;
+  
+  b = obj;
+  return true;
+}
+
+LispReader*
+LispReader::read_lisp(const char* name)
+{
+  lisp_object_t* obj = search_for(name);
+  if(!obj)
+    return 0;
+
+  return new LispReader(obj);
 }
 
 bool
-LispReader::read_float (const char* name, float* f)
+LispReader::read_float (const char* name, float& f)
 {
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      if (!lisp_real_p(lisp_car(obj)) && !lisp_integer_p(lisp_car(obj)))
-        st_abort("LispReader expected type real at token: ", name);
-      *f = lisp_real(lisp_car(obj));
-      return true;
-    }
-  return false;
+  if (!obj)
+    return false;
+  
+  if (!lisp_real_p(lisp_car(obj)) && !lisp_integer_p(lisp_car(obj)))
+    st_abort("LispReader expected type real at token: ", name);
+  
+  f = lisp_real(lisp_car(obj));
+  return true;
 }
 
 bool
-LispReader::read_string_vector (const char* name, std::vector<std::string>* vec)
+LispReader::read_string_vector (const char* name, std::vector<std::string>& vec)
 {
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      while(!lisp_nil_p(obj))
-        {
-          if (!lisp_string_p(lisp_car(obj)))
-            st_abort("LispReader expected type string at token: ", name);
-          vec->push_back(lisp_string(lisp_car(obj)));
-          obj = lisp_cdr(obj);
-        }
-      return true;
-    }
-  return false;    
+  if (!obj)
+    return false;
+
+  vec.clear();
+  while(!lisp_nil_p(obj))
+  {
+    if (!lisp_string_p(lisp_car(obj)))
+      st_abort("LispReader expected type string at token: ", name);
+    vec.push_back(lisp_string(lisp_car(obj)));
+    obj = lisp_cdr(obj);
+  }
+  return true;
 }
 
 bool
-LispReader::read_int_vector (const char* name, std::vector<int>* vec)
+LispReader::read_int_vector (const char* name, std::vector<int>& vec)
 {
-  vec->clear();
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      while(!lisp_nil_p(obj))
-        {
-          if (!lisp_integer_p(lisp_car(obj)))
-            st_abort("LispReader expected type integer at token: ", name);
-          vec->push_back(lisp_integer(lisp_car(obj)));
-          obj = lisp_cdr(obj);
-        }
-      return true;
-    }
-  return false;    
+  if (!obj)
+    return false;
+
+  vec.clear();
+  while(!lisp_nil_p(obj))
+  {
+    if (!lisp_integer_p(lisp_car(obj)))
+      st_abort("LispReader expected type integer at token: ", name);
+    vec.push_back(lisp_integer(lisp_car(obj)));
+    obj = lisp_cdr(obj);
+  }
+  return true;
 }
 
 bool
-LispReader::read_int_vector (const char* name, std::vector<unsigned int>* vec)
+LispReader::read_int_vector (const char* name, std::vector<unsigned int>& vec)
 {
-  vec->clear();
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      while(!lisp_nil_p(obj))
-        {
-          if (!lisp_integer_p(lisp_car(obj)))
-            st_abort("LispReader expected type integer at token: ", name);
-          vec->push_back(lisp_integer(lisp_car(obj)));
-          obj = lisp_cdr(obj);
-        }
-      return true;
-    }
-  return false;    
+  if (!obj)
+    return false;
+
+  vec.clear();
+  while(!lisp_nil_p(obj))
+  {
+    if (!lisp_integer_p(lisp_car(obj)))
+      st_abort("LispReader expected type integer at token: ", name);
+    vec.push_back(lisp_integer(lisp_car(obj)));
+    obj = lisp_cdr(obj);
+  }
+  return true;
 }
 
 bool
-LispReader::read_char_vector (const char* name, std::vector<char>* vec)
+LispReader::read_char_vector (const char* name, std::vector<char>& vec)
 {
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      while(!lisp_nil_p(obj))
-        {
-          vec->push_back(*lisp_string(lisp_car(obj)));
-          obj = lisp_cdr(obj);
-        }
-      return true;
-    }
-  return false;    
+  if (!obj)
+    return false;
+  vec.clear();
+  while(!lisp_nil_p(obj))
+  {
+    vec.push_back(*lisp_string(lisp_car(obj)));
+    obj = lisp_cdr(obj);
+  }
+  return true;
 }
 
 bool
-LispReader::read_string (const char* name, std::string* str)
+LispReader::read_string (const char* name, std::string& str)
 {
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      if (!lisp_string_p(lisp_car(obj)))
-        st_abort("LispReader expected type string at token: ", name);
-     *str = lisp_string(lisp_car(obj));
-      return true;
-    }
-  return false;  
+  if (!obj)
+    return false;
+
+  if (!lisp_string_p(lisp_car(obj)))
+    st_abort("LispReader expected type string at token: ", name);
+  str = lisp_string(lisp_car(obj));
+  return true;
 }
 
 bool
-LispReader::read_bool (const char* name, bool* b)
+LispReader::read_bool (const char* name, bool& b)
 {
   lisp_object_t* obj = search_for (name);
-  if (obj)
-    {
-      if (!lisp_boolean_p(lisp_car(obj)))
-        st_abort("LispReader expected type bool at token: ", name);
-      *b = lisp_boolean(lisp_car(obj));
-      return true;
-    }
-  return false;
+  if (!obj)
+    return false;
+  
+  if (!lisp_boolean_p(lisp_car(obj)))
+    st_abort("LispReader expected type bool at token: ", name);
+  b = lisp_boolean(lisp_car(obj));
+  return true;
 }
 
 lisp_object_t*
@@ -1201,92 +1227,19 @@ LispReader::get_lisp()
   return lst;
 }
 
-lisp_object_t* lisp_read_from_gzfile(const char* filename)
-{
-  bool done = false;
-  lisp_object_t* root_obj = 0;
-  int chunk_size = 128 * 1024;
-  int buf_pos = 0;
-  int try_number = 1;
-  char* buf = static_cast<char*>(malloc(chunk_size));
-  if (!buf)
-    throw LispReaderException("lisp_read_from_gzfile()", __FILE__, __LINE__);
-
-  gzFile in = gzopen(filename, "r");
-
-  while (!done)
-    {
-      int ret = gzread(in, buf + buf_pos, chunk_size);
-      if (ret == -1)
-        {
-          free (buf);
-          throw LispReaderException("Error while reading from file", __FILE__, __LINE__);
-        }
-      else if (ret == chunk_size) // buffer got full, eof not yet there so resize
-        {
-          buf_pos = chunk_size * try_number;
-          try_number += 1;
-          buf = static_cast<char*>(realloc(buf, chunk_size * try_number));
-
-          if (!buf)
-            throw LispReaderException("lisp_read_from_gzfile()", __FILE__, __LINE__);
-        }
-      else 
-        {
-          // everything fine, encountered EOF 
-          done = true;
-        }
-    }
-      
-  lisp_stream_t stream;
-  lisp_stream_init_string (&stream, buf);
-  root_obj = lisp_read (&stream);
-      
-  free(buf);
-  gzclose(in);
-
-  return root_obj;
-}
-
-bool has_suffix(const char* data, const char* suffix)
-{
-  int suffix_len = strlen(suffix);
-  int data_len   = strlen(data);
-  
-  const char* data_suffix = (data + data_len - suffix_len);
-
-  if (data_suffix >= data)
-    {
-      return (strcmp(data_suffix, suffix) == 0);
-    }
-  else
-    {
-      return false;
-    }
-}
-
 lisp_object_t* lisp_read_from_file(const std::string& filename)
 {
-  lisp_stream_t stream;
+  FILE* in = fopen(filename.c_str(), "r");
 
-  if (has_suffix(filename.c_str(), ".gz"))
-    {
-      return lisp_read_from_gzfile(filename.c_str());
-    }
-  else
-    {
-      lisp_object_t* obj = 0;
-      FILE* in = fopen(filename.c_str(), "r");
+  if(!in)
+    return 0;
 
-      if (in)
-        {
-          lisp_stream_init_file(&stream, in);
-          obj = lisp_read(&stream);
-          fclose(in);
-        }
+  lisp_stream_t stream;
+  lisp_stream_init_file(&stream, in);
+  lisp_object_t* obj = lisp_read(&stream);
+  fclose(in);
 
-      return obj;
-    }
+  return obj;
 }
 
 // EOF //
index 81f2c40..3c3ba73 100644 (file)
@@ -117,7 +117,6 @@ struct _lisp_object_t
       } v;
   };
 
-lisp_stream_t* lisp_stream_init_gzfile (lisp_stream_t *stream, gzFile file);
 lisp_stream_t* lisp_stream_init_file (lisp_stream_t *stream, FILE *file);
 lisp_stream_t* lisp_stream_init_string (lisp_stream_t *stream, char *buf);
 lisp_stream_t* lisp_stream_init_any (lisp_stream_t *stream, void *data,
@@ -172,22 +171,29 @@ void lisp_dump (lisp_object_t *obj, FILE *out);
 class LispReader
 {
 private:
+  lisp_object_t* owner;
   lisp_object_t* lst;
 
   lisp_object_t* search_for(const char* name);
+  
 public:
   /** cur == ((pos 1 2 3) (id 12 3 4)...) */
-  LispReader (lisp_object_t* l);
-
-  bool read_int_vector (const char* name, std::vector<int>* vec);
-  bool read_int_vector (const char* name, std::vector<unsigned int>* vec);
-  bool read_char_vector (const char* name, std::vector<char>* vec);
-  bool read_string_vector (const char* name, std::vector<std::string>* vec);
-  bool read_string (const char* name, std::string* str);
-  bool read_int (const char* name, int* i);
-  bool read_float (const char* name, float* f);
-  bool read_bool (const char* name, bool* b);
-  bool read_lisp (const char* name, lisp_object_t** b);
+  LispReader(lisp_object_t* l);
+  ~LispReader();
+
+  bool read_int_vector(const char* name, std::vector<int>& vec);
+  bool read_int_vector(const char* name, std::vector<unsigned int>& vec);
+  bool read_char_vector(const char* name, std::vector<char>& vec);
+  bool read_string_vector(const char* name, std::vector<std::string>& vec);
+  bool read_string(const char* name, std::string& str);
+  bool read_int(const char* name, int& i);
+  bool read_float(const char* name, float& f);
+  bool read_bool(const char* name, bool& b);
+  bool read_lisp(const char* name, lisp_object_t*& b);
+  LispReader* read_lisp(const char* name);
+
+  static LispReader* load(const std::string& filename,
+      const std::string& toplevellist);
 
   lisp_object_t* get_lisp();
 };
index 34dd529..e79cd2c 100644 (file)
@@ -722,9 +722,6 @@ Menu::draw(DrawingContext& context)
   int menu_height = get_height();
   int menu_width  = get_width();
 
-  context.push_transform();
-  context.set_translation(Vector(0, 0));  
-
   /* Draw a transparent background */
   context.draw_filled_rect(
       Vector(pos_x - menu_width/2, pos_y - 24*item.size()/2 - 10),
@@ -735,7 +732,6 @@ Menu::draw(DrawingContext& context)
   {
     draw_item(context, i, menu_width, menu_height);
   }
-  context.pop_transform();
 }
 
 MenuItem&
index a073565..d279ee2 100644 (file)
@@ -87,9 +87,6 @@ void MouseCursor::draw(DrawingContext& context)
       timer.start(MC_FRAME_PERIOD);
     }
 
-  context.push_transform();
-  context.set_translation(Vector(0, 0));
   context.draw_surface_part(cursor, Vector(w*cur_frame, h*cur_state), Vector(w,
         h), Vector(x-mid_x, y-mid_y), LAYER_FOREGROUND1+100);
-  context.pop_transform();
 }
index 88b7288..c21d109 100644 (file)
 #include <iostream>
 #include <math.h>
 #include "globals.h"
-#include "world.h"
-#include "level.h"
-#include "scene.h"
-#include "camera.h"
+#include "lispreader.h"
+#include "lispwriter.h"
+#include "screen/drawing_context.h"
 
 ParticleSystem::ParticleSystem()
 {
     virtual_width = screen->w;
     virtual_height = screen->h;
+    layer = LAYER_BACKGROUND1;
 }
 
 ParticleSystem::~ParticleSystem()
@@ -62,7 +62,7 @@ void ParticleSystem::draw(DrawingContext& context)
 
         if(pos.x > screen->w) pos.x -= virtual_width;
         if(pos.y > screen->h) pos.y -= virtual_height;
-        context.draw_surface(particle->texture, pos, LAYER_BACKGROUND1);
+        context.draw_surface(particle->texture, pos, layer);
     }
 
     context.pop_transform();
@@ -87,12 +87,25 @@ SnowParticleSystem::SnowParticleSystem()
         do {
             particle->speed = snowsize/60.0 + (float(rand()%10)/300.0);
         } while(particle->speed < 0.01);
-        particle->speed *= World::current()->get_level()->gravity;
 
         particles.push_back(particle);
     }
 }
 
+void
+SnowParticleSystem::parse(LispReader& reader)
+{
+  reader.read_int("layer", layer);
+}
+
+void
+SnowParticleSystem::write(LispWriter& writer)
+{
+  writer.start_list("particles-snow");
+  writer.write_int("layer", layer);
+  writer.end_list("particles-snow");
+}
+
 SnowParticleSystem::~SnowParticleSystem()
 {
   for(int i=0;i<3;++i)
@@ -130,6 +143,20 @@ CloudParticleSystem::CloudParticleSystem()
     }
 }
 
+void
+CloudParticleSystem::parse(LispReader& reader)
+{
+  reader.read_int("layer", layer);
+}
+
+void
+CloudParticleSystem::write(LispWriter& writer)
+{
+  writer.start_list("particles-clouds");
+  writer.write_int("layer", layer);
+  writer.end_list("particles-clouds");
+}
+
 CloudParticleSystem::~CloudParticleSystem()
 {
   delete cloudimage;
index 11bff4a..e2a7f1a 100644 (file)
@@ -23,7 +23,9 @@
 #include <vector>
 #include "screen/texture.h"
 #include "game_object.h"
+#include "serializable.h"
 
+class LispReader;
 class DisplayManager;
 
 /**
@@ -50,6 +52,8 @@ public:
     virtual void draw(DrawingContext& context);
 
 protected:
+    int layer;
+
     class Particle
     {
     public:
@@ -64,12 +68,15 @@ protected:
     float virtual_width, virtual_height;
 };
 
-class SnowParticleSystem : public ParticleSystem
+class SnowParticleSystem : public ParticleSystem, public Serializable
 {
 public:
     SnowParticleSystem();
     virtual ~SnowParticleSystem();
 
+    void parse(LispReader& reader);
+    void write(LispWriter& writer);
+
     virtual void action(float elapsed_time);
 
     std::string type() const
@@ -85,12 +92,15 @@ private:
     Surface* snowimages[3];
 };
 
-class CloudParticleSystem : public ParticleSystem
+class CloudParticleSystem : public ParticleSystem, public Serializable
 {
 public:
     CloudParticleSystem();
     virtual ~CloudParticleSystem();
 
+    void parse(LispReader& reader);
+    void write(LispWriter& writer);
+
     virtual void action(float elapsed_time);
 
     std::string type() const
index aecc01e..ef6d94c 100644 (file)
@@ -24,7 +24,7 @@
 #include "defines.h"
 #include "physic.h"
 #include "timer.h"
-#include "world.h"
+#include "sector.h"
 #include "level.h"
 
 Physic::Physic()
@@ -124,7 +124,7 @@ Physic::enable_gravity(bool enable_gravity)
 void
 Physic::apply(float frame_ratio, float &x, float &y)
 {
-  float gravity = World::current()->get_level()->gravity;
+  float gravity = Sector::current()->gravity;
   float grav;
   if(gravity_enabled)
     grav = gravity / 100.0;
index df8571b..c25b395 100644 (file)
@@ -27,6 +27,9 @@
 #include "scene.h"
 #include "tile.h"
 #include "sprite.h"
+#include "sector.h"
+#include "tilemap.h"
+#include "camera.h"
 #include "gameobjs.h"
 #include "screen/screen.h"
 
@@ -261,26 +264,30 @@ Player::action(float elapsed_time)
           if (isbrick(base.x, base.y) ||
               isfullbox(base.x, base.y))
             {
-              World::current()->trygrabdistro(base.x, base.y - 32, BOUNCE);
-              World::current()->trybumpbadguy(base.x, base.y - 64);
+              Sector::current()->trygrabdistro(
+                  Vector(base.x, base.y - 32), BOUNCE);
+              Sector::current()->trybumpbadguy(Vector(base.x, base.y - 64));
 
-              World::current()->trybreakbrick(base.x, base.y, size == SMALL);
+              Sector::current()->trybreakbrick(
+                  Vector(base.x, base.y), size == SMALL);
 
               bumpbrick(base.x, base.y);
-              World::current()->tryemptybox(base.x, base.y, RIGHT);
+              Sector::current()->tryemptybox(Vector(base.x, base.y), RIGHT);
             }
 
           if (isbrick(base.x+ 31, base.y) ||
               isfullbox(base.x+ 31, base.y))
             {
-              World::current()->trygrabdistro(base.x+ 31, base.y - 32,BOUNCE);
-              World::current()->trybumpbadguy(base.x+ 31, base.y - 64);
+              Sector::current()->trygrabdistro(
+                  Vector(base.x+ 31, base.y - 32), BOUNCE);
+              Sector::current()->trybumpbadguy(Vector(base.x+ 31, base.y - 64));
 
               if(size == BIG)
-                World::current()->trybreakbrick(base.x+ 31, base.y, size == SMALL);
+                Sector::current()->trybreakbrick(
+                    Vector(base.x+ 31, base.y), size == SMALL);
 
               bumpbrick(base.x+ 31, base.y);
-              World::current()->tryemptybox(base.x+ 31, base.y, LEFT);
+              Sector::current()->tryemptybox(Vector(base.x+ 31, base.y), LEFT);
             }
         }
 
@@ -480,16 +487,17 @@ Player::handle_vertical_input()
     butt_jump = false;
 
     // Break bricks beneath Tux
-    if(World::current()->trybreakbrick(base.x + 1, base.y + base.height, false)
-        || World::current()->trybreakbrick(
-           base.x + base.width - 1, base.y + base.height, false))
+    if(Sector::current()->trybreakbrick(
+          Vector(base.x + 1, base.y + base.height), false)
+        || Sector::current()->trybreakbrick(
+           Vector(base.x + base.width - 1, base.y + base.height), false))
     {
       physic.set_velocity_y(2);
       butt_jump = true;
     }
 
     // Kill nearby badguys
-    std::vector<GameObject*> gameobjects = World::current()->gameobjects;
+    std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
     for (std::vector<GameObject*>::iterator i = gameobjects.begin();
          i != gameobjects.end();
          i++)
@@ -538,7 +546,7 @@ Player::handle_input()
   /* Shoot! */
   if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER)
     {
-      if(World::current()->add_bullet(Vector(base.x, base.y + (base.height/2)),
+      if(Sector::current()->add_bullet(Vector(base.x, base.y + (base.height/2)),
           physic.get_velocity_x(), dir))
         shooting_timer.start(SHOOTING_TIME);
       input.old_fire = DOWN;
@@ -615,16 +623,20 @@ Player::grabdistros()
   /* Grab distros: */
   if (!dying)
     {
-      World::current()->trygrabdistro(base.x, base.y, NO_BOUNCE);
-      World::current()->trygrabdistro(base.x+ 31, base.y, NO_BOUNCE);
+      Sector::current()->trygrabdistro(Vector(base.x, base.y), NO_BOUNCE);
+      Sector::current()->trygrabdistro(Vector(base.x+ 31, base.y), NO_BOUNCE);
 
-      World::current()->trygrabdistro(base.x, base.y + base.height, NO_BOUNCE);
-      World::current()->trygrabdistro(base.x+ 31, base.y + base.height, NO_BOUNCE);
+      Sector::current()->trygrabdistro(
+          Vector(base.x, base.y + base.height), NO_BOUNCE);
+      Sector::current()->trygrabdistro(
+          Vector(base.x+ 31, base.y + base.height), NO_BOUNCE);
 
       if(size == BIG)
         {
-          World::current()->trygrabdistro(base.x, base.y + base.height / 2, NO_BOUNCE);
-          World::current()->trygrabdistro(base.x+ 31, base.y + base.height / 2, NO_BOUNCE);
+          Sector::current()->trygrabdistro(
+              Vector(base.x, base.y + base.height / 2), NO_BOUNCE);
+          Sector::current()->trygrabdistro(
+              Vector(base.x+ 31, base.y + base.height / 2), NO_BOUNCE);
         }
 
     }
@@ -924,7 +936,7 @@ Player::move(const Vector& vector)
 }
 
 void
-Player::check_bounds(DrawingContext& viewport)
+Player::check_bounds(Camera* camera)
 {
   /* Keep tux in bounds: */
   if (base.x < 0)
@@ -934,7 +946,7 @@ Player::check_bounds(DrawingContext& viewport)
     }
 
   /* Keep in-bounds, vertically: */
-  if (base.y > World::current()->get_level()->height * /*TILE_HEIGHT*/ 32)
+  if (base.y > Sector::current()->solids->get_height() * 32)
     {
       kill(KILL);
       return;
@@ -942,12 +954,12 @@ Player::check_bounds(DrawingContext& viewport)
 
   bool adjust = false;
   // can happen if back scrolling is disabled
-  if(base.x < viewport.get_translation().x) {
-    base.x = viewport.get_translation().x;
+  if(base.x < camera->get_translation().x) {
+    base.x = camera->get_translation().x;
     adjust = true;
   }
-  if(base.x >= viewport.get_translation().x + screen->w - base.width) {
-    base.x = viewport.get_translation().x + screen->w - base.width;
+  if(base.x >= camera->get_translation().x + screen->w - base.width) {
+    base.x = camera->get_translation().x + screen->w - base.width;
     adjust = true;
   }
 
@@ -960,5 +972,3 @@ Player::check_bounds(DrawingContext& viewport)
   }
 }
 
-// EOF //
-
index b3496eb..5296af1 100644 (file)
@@ -76,6 +76,7 @@ struct player_input_type
 void player_input_init(player_input_type* pplayer_input);
 
 class Sprite;
+class Camera;
 
 extern Surface* tux_life;
 
@@ -163,7 +164,7 @@ public:
   void collision(void* p_c_object, int c_object);
   void kill(HurtMode mode);
   void player_remove_powerups();
-  void check_bounds(DrawingContext& context);
+  void check_bounds(Camera* camera);
   bool on_ground();
   bool under_solid();
   bool tiles_on_air(int tiles);
index fcd4d62..62928e4 100644 (file)
@@ -33,6 +33,7 @@ Surface* img_pole;
 Surface* img_poletop;
 Surface* img_flag[2];
 Surface* img_cloud[2][4];
+Surface* img_distro[4];
 
 MusicRef herring_song;
 MusicRef level_end_song;
diff --git a/src/sector.cpp b/src/sector.cpp
new file mode 100644 (file)
index 0000000..401e6b6
--- /dev/null
@@ -0,0 +1,788 @@
+#include "sector.h"
+
+#include <memory>
+#include <stdexcept>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include "lispreader.h"
+
+#include "badguy.h"
+#include "special.h"
+#include "gameobjs.h"
+#include "camera.h"
+#include "background.h"
+#include "particlesystem.h"
+#include "tile.h"
+#include "tilemap.h"
+#include "music_manager.h"
+#include "gameloop.h"
+#include "resources.h"
+
+Sector* Sector::_current = 0;
+
+Sector::Sector()
+  : gravity(10), player(0), solids(0), background(0), camera(0),
+    currentmusic(LEVEL_MUSIC)
+{
+  song_title = "Mortimers_chipdisko.mod";
+  player = new Player();
+  add_object(player);
+}
+
+Sector::~Sector()
+{
+  for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
+      ++i)
+    delete *i;
+
+  for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
+      ++i)
+    delete *i;
+    
+  if(_current == this)
+    _current = 0;
+}
+
+void
+Sector::parse(LispReader& lispreader)
+{
+  _current = this;
+  
+  for(lisp_object_t* cur = lispreader.get_lisp(); !lisp_nil_p(cur);
+      cur = lisp_cdr(cur)) {
+    std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
+    lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
+    LispReader reader(lisp_cdr(lisp_car(cur)));
+
+    if(token == "name") {
+      name = lisp_string(data);
+    } else if(token == "gravity") {
+      gravity = lisp_integer(data);
+    } else if(token == "music") {
+      song_title = lisp_string(data);
+      load_music();
+    } else if(token == "camera") {
+      if(camera) {
+        std::cerr << "Warning: More than 1 camera defined in sector.\n";
+        continue;
+      }
+      camera = new Camera(this);
+      camera->read(reader);
+      add_object(camera);
+    } else if(token == "background") {
+      background = new Background(reader);
+      add_object(background);
+    } else if(token == "playerspawn") {
+      SpawnPoint* sp = new SpawnPoint;
+      reader.read_string("name", sp->name);
+      reader.read_float("x", sp->pos.x);
+      reader.read_float("y", sp->pos.y);
+    } else if(token == "tilemap") {
+      TileMap* tilemap = new TileMap(reader);
+      add_object(tilemap);
+
+      if(tilemap->is_solid()) {
+        if(solids) {
+          std::cerr << "Warning multiple solid tilemaps in sector.\n";
+          continue;
+        }
+        solids = tilemap;
+      }
+    } else if(badguykind_from_string(token) != BAD_INVALID) {
+      add_object(new BadGuy(badguykind_from_string(token), reader));
+    } else if(token == "trampoline") {
+      add_object(new Trampoline(reader));
+    } else if(token == "flying-platform") {
+      add_object(new FlyingPlatform(reader));
+    } else if(token == "particles-snow") {
+      SnowParticleSystem* partsys = new SnowParticleSystem();
+      partsys->parse(reader);
+      add_object(partsys);
+    } else if(token == "particles-clouds") {
+      CloudParticleSystem* partsys = new CloudParticleSystem();
+      partsys->parse(reader);
+      add_object(partsys);
+    }
+  }
+
+  if(!camera) {
+    std::cerr << "sector does not contain a camera.\n";
+    camera = new Camera(this);
+  }
+  if(!solids)
+    throw std::runtime_error("sector does not contain a solid tile layer.");
+}
+
+void
+Sector::parse_old_format(LispReader& reader)
+{
+  _current = this;
+  
+  name = "main";
+  reader.read_float("gravity", gravity);
+
+  std::string backgroundimage;
+  reader.read_string("background", backgroundimage);
+  float bgspeed = .5;
+  reader.read_float("bkgd_speed", bgspeed);
+
+  Color bkgd_top, bkgd_bottom;
+  int r = 0, g = 0, b = 128;
+  reader.read_int("bkgd_red_top", r);
+  reader.read_int("bkgd_green_top",  g);
+  reader.read_int("bkgd_blue_top",  b);
+  bkgd_top.red = r;
+  bkgd_top.green = g;
+  bkgd_top.blue = b;
+  
+  reader.read_int("bkgd_red_bottom",  r);
+  reader.read_int("bkgd_green_bottom", g);
+  reader.read_int("bkgd_blue_bottom", b);
+  bkgd_bottom.red = r;
+  bkgd_bottom.green = g;
+  bkgd_bottom.blue = b;
+  
+  if(backgroundimage != "") {
+    background = new Background;
+    background->set_image(backgroundimage, bgspeed);
+    add_object(background);
+  } else {
+    background = new Background;
+    background->set_gradient(bkgd_top, bkgd_bottom);
+    add_object(background);
+  }
+
+  std::string particlesystem;
+  reader.read_string("particle_system", particlesystem);
+  if(particlesystem == "clouds")
+    add_object(new CloudParticleSystem());
+  else if(particlesystem == "snow")
+    add_object(new SnowParticleSystem());
+
+  Vector startpos(100, 170);
+  reader.read_float("start_pos_x", startpos.x);
+  reader.read_float("start_pos_y", startpos.y);
+
+  SpawnPoint* spawn = new SpawnPoint;
+  spawn->pos = startpos;
+  spawn->name = "main";
+  spawnpoints.push_back(spawn);
+
+  song_title = "Mortimers_chipdisko.mod";
+  reader.read_string("music", song_title);
+  load_music();
+
+  int width, height = 15;
+  reader.read_int("width", width);
+  reader.read_int("height", height);
+  
+  std::vector<unsigned int> tiles;
+  if(reader.read_int_vector("interactive-tm", tiles)
+      || reader.read_int_vector("tilemap", tiles)) {
+    TileMap* tilemap = new TileMap();
+    tilemap->set(width, height, tiles, LAYER_TILES, true);
+    solids = tilemap;
+    add_object(tilemap);
+  }
+
+  if(reader.read_int_vector("background-tm", tiles)) {
+    TileMap* tilemap = new TileMap();
+    tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
+    add_object(tilemap);
+  }
+
+  if(reader.read_int_vector("foreground-tm", tiles)) {
+    TileMap* tilemap = new TileMap();
+    tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
+    add_object(tilemap);
+  }
+
+  // TODO read resetpoints
+
+  // read objects
+  {
+    lisp_object_t* cur = 0;
+    if(reader.read_lisp("objects", cur)) {
+      while(!lisp_nil_p(cur)) {
+        lisp_object_t* data = lisp_car(cur);
+        std::string object_type = lisp_symbol(lisp_car(data));
+                                                                                
+        LispReader reader(lisp_cdr(data));
+                                                                                
+        if(object_type == "trampoline") {
+          add_object(new Trampoline(reader));
+        }
+        else if(object_type == "flying-platform") {
+          add_object(new FlyingPlatform(reader));
+        }
+        else {
+          BadGuyKind kind = badguykind_from_string(object_type);
+          add_object(new BadGuy(kind, reader));
+        }
+                                                                                
+        cur = lisp_cdr(cur);
+      }
+    }
+  }
+
+  // add a camera
+  camera = new Camera(this);
+  add_object(camera);
+}
+
+void
+Sector::write(LispWriter& writer)
+{
+  writer.write_string("name", name);
+  writer.write_float("gravity", gravity);
+
+  for(GameObjects::iterator i = gameobjects.begin();
+      i != gameobjects.end(); ++i) {
+    Serializable* serializable = dynamic_cast<Serializable*> (*i);
+    if(serializable)
+      serializable->write(writer);
+  }
+}
+
+void
+Sector::add_object(GameObject* object)
+{
+  // XXX a bit hackish, at least try to keep the number of these things down...
+  BadGuy* badguy = dynamic_cast<BadGuy*> (object);
+  if(badguy)
+    badguys.push_back(badguy);
+  Bullet* bullet = dynamic_cast<Bullet*> (object);
+  if(bullet)
+    bullets.push_back(bullet);
+  Upgrade* upgrade = dynamic_cast<Upgrade*> (object);
+  if(upgrade)
+    upgrades.push_back(upgrade);
+  Trampoline* trampoline = dynamic_cast<Trampoline*> (object);
+  if(trampoline)
+    trampolines.push_back(trampoline);
+  FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (object);
+  if(flying_platform)
+    flying_platforms.push_back(flying_platform);
+  Background* background = dynamic_cast<Background*> (object);
+  if(background)
+    this->background = background;
+
+  gameobjects.push_back(object);
+}
+
+void
+Sector::activate(const std::string& spawnpoint)
+{
+  _current = this;
+
+  // Apply bonuses from former levels
+  switch (player_status.bonus)
+    {
+    case PlayerStatus::NO_BONUS:
+      break;
+                                                                                
+    case PlayerStatus::FLOWER_BONUS:
+      player->got_power = Player::FIRE_POWER;  // FIXME: add ice power to here
+      // fall through
+                                                                                
+    case PlayerStatus::GROWUP_BONUS:
+      player->grow(false);
+      break;
+    }
+
+  SpawnPoint* sp = 0;
+  for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
+      ++i) {
+    if((*i)->name == spawnpoint) {
+      sp = *i;
+      break;
+    }
+  }
+  if(!sp) {
+    std::cerr << "Spawnpoint '" << spawnpoint << "' not found.\n";
+  } else {
+    player->move(sp->pos);
+  }
+
+  camera->reset(Vector(player->base.x, player->base.y));
+}
+
+void
+Sector::action(float elapsed_time)
+{
+  player->check_bounds(camera);
+                                                                                
+  /* update objects (don't use iterators here, because the list might change
+   * during the iteration)
+   */
+  for(size_t i = 0; i < gameobjects.size(); ++i)
+    if(gameobjects[i]->is_valid())
+      gameobjects[i]->action(elapsed_time);
+                                                                                
+  /* Handle all possible collisions. */
+  collision_handler();
+                                                                                
+  /** cleanup marked objects */
+  for(std::vector<GameObject*>::iterator i = gameobjects.begin();
+      i != gameobjects.end(); /* nothing */) {
+    if((*i)->is_valid() == false) {
+      BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
+      if(badguy) {
+        badguys.erase(std::remove(badguys.begin(), badguys.end(), badguy),
+            badguys.end());
+      }
+      Bullet* bullet = dynamic_cast<Bullet*> (*i);
+      if(bullet) {
+        bullets.erase(
+            std::remove(bullets.begin(), bullets.end(), bullet),
+            bullets.end());
+      }
+      Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
+      if(upgrade) {
+        upgrades.erase(
+            std::remove(upgrades.begin(), upgrades.end(), upgrade),
+            upgrades.end());
+      }
+      Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
+      if(trampoline) {
+        trampolines.erase(
+            std::remove(trampolines.begin(), trampolines.end(), trampoline),
+            trampolines.end());
+      }
+      FlyingPlatform* flying_platform= dynamic_cast<FlyingPlatform*> (*i);
+      if(flying_platform) {
+        flying_platforms.erase(
+            std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform),
+            flying_platforms.end());
+      }
+                                                                                
+      delete *i;
+      i = gameobjects.erase(i);
+    } else {
+      ++i;
+    }
+  }
+}
+
+void
+Sector::draw(DrawingContext& context)
+{
+  context.push_transform();
+  context.set_translation(camera->get_translation());
+  
+  for(GameObjects::iterator i = gameobjects.begin();
+      i != gameobjects.end(); ++i) {
+    if( (*i)->is_valid() )
+      (*i)->draw(context);
+  }
+
+  context.pop_transform();
+}
+
+void
+Sector::collision_handler()
+{
+  // CO_BULLET & CO_BADGUY check
+  for(unsigned int i = 0; i < bullets.size(); ++i)
+    {
+      for (BadGuys::iterator j = badguys.begin(); j != badguys.end(); ++j)
+        {
+          if((*j)->dying != DYING_NOT)
+            continue;
+                                                                                
+          if(rectcollision(bullets[i]->base, (*j)->base))
+            {
+              // We have detected a collision and now call the
+              // collision functions of the collided objects.
+              (*j)->collision(bullets[i], CO_BULLET, COLLISION_NORMAL);
+              bullets[i]->collision(CO_BADGUY);
+              break; // bullet is invalid now, so break
+            }
+        }
+    }
+                                                                                
+  /* CO_BADGUY & CO_BADGUY check */
+  for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
+    {
+      if((*i)->dying != DYING_NOT)
+        continue;
+                                                                                
+      BadGuys::iterator j = i;
+      ++j;
+      for (; j != badguys.end(); ++j)
+        {
+          if(j == i || (*j)->dying != DYING_NOT)
+            continue;
+                                                                                
+          if(rectcollision((*i)->base, (*j)->base))
+            {
+              // We have detected a collision and now call the
+              // collision functions of the collided objects.
+              (*j)->collision(*i, CO_BADGUY);
+              (*i)->collision(*j, CO_BADGUY);
+            }
+        }
+    }
+  if(player->dying != DYING_NOT) return;
+                                                                                
+  // CO_BADGUY & CO_PLAYER check
+  for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
+    {
+      if((*i)->dying != DYING_NOT)
+        continue;
+                                                                                
+      if(rectcollision_offset((*i)->base, player->base, 0, 0))
+        {
+          // We have detected a collision and now call the collision
+          // functions of the collided objects.
+          if (player->previous_base.y < player->base.y &&
+              player->previous_base.y + player->previous_base.height
+              < (*i)->base.y + (*i)->base.height/2
+              && !player->invincible_timer.started())
+            {
+              (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
+            }
+          else
+            {
+              player->collision(*i, CO_BADGUY);
+              (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
+            }
+        }
+    }
+                                                                                
+  // CO_UPGRADE & CO_PLAYER check
+  for(unsigned int i = 0; i < upgrades.size(); ++i)
+    {
+      if(rectcollision(upgrades[i]->base, player->base))
+        {
+          // We have detected a collision and now call the collision
+          // functions of the collided objects.
+          upgrades[i]->collision(player, CO_PLAYER, COLLISION_NORMAL);
+        }
+    }
+                                                                                
+  // CO_TRAMPOLINE & (CO_PLAYER or CO_BADGUY)
+  for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
+  {
+    if (rectcollision((*i)->base, player->base))
+    {
+      if (player->previous_base.y < player->base.y &&
+          player->previous_base.y + player->previous_base.height
+          < (*i)->base.y + (*i)->base.height/2)
+      {
+        (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
+      }
+      else if (player->previous_base.y <= player->base.y)
+      {
+        player->collision(*i, CO_TRAMPOLINE);
+        (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
+      }
+    }
+  }
+                                                                                
+  // CO_FLYING_PLATFORM & (CO_PLAYER or CO_BADGUY)
+  for (FlyingPlatforms::iterator i = flying_platforms.begin(); i != flying_platforms.end(); ++i)
+  {
+    if (rectcollision((*i)->base, player->base))
+    {
+      if (player->previous_base.y < player->base.y &&
+          player->previous_base.y + player->previous_base.height
+          < (*i)->base.y + (*i)->base.height/2)
+      {
+        (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
+        player->collision(*i, CO_FLYING_PLATFORM);
+      }
+/*      else if (player->previous_base.y <= player->base.y)
+      {
+      }*/
+    }
+  }
+}
+
+void
+Sector::add_score(const Vector& pos, int s)
+{
+  player_status.score += s;
+                                                                                
+  add_object(new FloatingScore(pos, s));
+}
+                                                                                
+void
+Sector::add_bouncy_distro(const Vector& pos)
+{
+  add_object(new BouncyDistro(pos));
+}
+                                                                                
+void
+Sector::add_broken_brick(const Vector& pos, Tile* tile)
+{
+  add_broken_brick_piece(pos, Vector(-1, -4), tile);
+  add_broken_brick_piece(pos + Vector(0, 16), Vector(-1.5, -3), tile);
+                                                                                
+  add_broken_brick_piece(pos + Vector(16, 0), Vector(1, -4), tile);
+  add_broken_brick_piece(pos + Vector(16, 16), Vector(1.5, -3), tile);
+}
+                                                                                
+void
+Sector::add_broken_brick_piece(const Vector& pos, const Vector& movement,
+    Tile* tile)
+{
+  add_object(new BrokenBrick(tile, pos, movement));
+}
+                                                                                
+void
+Sector::add_bouncy_brick(const Vector& pos)
+{
+  add_object(new BouncyBrick(pos));
+}
+
+BadGuy*
+Sector::add_bad_guy(float x, float y, BadGuyKind kind)
+{
+  BadGuy* badguy = new BadGuy(kind, x, y);
+  add_object(badguy);
+  return badguy;
+}
+                                                                                
+void
+Sector::add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind)
+{
+  add_object(new Upgrade(pos, dir, kind));
+}
+                                                                                
+bool
+Sector::add_bullet(const Vector& pos, float xm, Direction dir)
+{
+  if(player->got_power == Player::FIRE_POWER)
+    {
+    if(bullets.size() > MAX_FIRE_BULLETS-1)
+      return false;
+    }
+  else if(player->got_power == Player::ICE_POWER)
+    {
+    if(bullets.size() > MAX_ICE_BULLETS-1)
+      return false;
+    }
+                                                                                
+  Bullet* new_bullet = 0;
+  if(player->got_power == Player::FIRE_POWER)
+    new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
+  else if(player->got_power == Player::ICE_POWER)
+    new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
+  else
+    throw std::runtime_error("wrong bullet type.");
+  add_object(new_bullet);
+                                                                                
+  play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER);
+                                                                                
+  return true;
+}
+
+/* Break a brick: */
+bool
+Sector::trybreakbrick(const Vector& pos, bool small)
+{
+  Tile* tile = solids->get_tile_at(pos);
+  if (tile->attributes & Tile::BRICK)
+    {
+      if (tile->data > 0)
+        {
+          /* Get a distro from it: */
+          add_bouncy_distro(
+              Vector(((int)(pos.x + 1) / 32) * 32, (int)(pos.y / 32) * 32));
+                                                                                
+          // TODO: don't handle this in a global way but per-tile...
+          if (!counting_distros)
+            {
+              counting_distros = true;
+              distro_counter = 5;
+            }
+          else
+            {
+              distro_counter--;
+            }
+                                                                                
+          if (distro_counter <= 0)
+            {
+              counting_distros = false;
+              solids->change_at(pos, tile->next_tile);
+            }
+                                                                                
+          play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+          player_status.score = player_status.score + SCORE_DISTRO;
+          player_status.distros++;
+          return true;
+        }
+      else if (!small)
+        {
+          /* Get rid of it: */
+          solids->change_at(pos, tile->next_tile);
+                                                                                
+          /* Replace it with broken bits: */
+          add_broken_brick(Vector(
+                                 ((int)(pos.x + 1) / 32) * 32,
+                                 (int)(pos.y / 32) * 32), tile);
+                                                                                
+          /* Get some score: */
+          play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
+          player_status.score = player_status.score + SCORE_BRICK;
+                                                                                
+          return true;
+        }
+    }
+                                                                                
+  return false;
+}
+                                                                                
+/* Empty a box: */
+void
+Sector::tryemptybox(const Vector& pos, Direction col_side)
+{
+  Tile* tile = solids->get_tile_at(pos);
+  if (!(tile->attributes & Tile::FULLBOX))
+    return;
+                                                                                
+  // according to the collision side, set the upgrade direction
+  if(col_side == LEFT)
+    col_side = RIGHT;
+  else
+    col_side = LEFT;
+                                                                                
+  int posx = ((int)(pos.x+1) / 32) * 32;
+  int posy = (int)(pos.y/32) * 32 - 32;
+  switch(tile->data)
+    {
+    case 1: // Box with a distro!
+      add_bouncy_distro(Vector(posx, posy));
+      play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+      player_status.score = player_status.score + SCORE_DISTRO;
+      player_status.distros++;
+      break;
+                                                                                
+    case 2: // Add a fire flower upgrade!
+      if (player->size == SMALL)     /* Tux is small, add mints! */
+        add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
+      else     /* Tux is big, add a fireflower: */
+        add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER);
+      play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
+      break;
+                                                                                
+    case 5: // Add an ice flower upgrade!
+      if (player->size == SMALL)     /* Tux is small, add mints! */
+        add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
+      else     /* Tux is big, add an iceflower: */
+        add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER);
+      play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
+      break;
+                                                                                
+    case 3: // Add a golden herring
+      add_upgrade(Vector(posx, posy), col_side, UPGRADE_HERRING);
+      break;
+                                                                                
+    case 4: // Add a 1up extra
+      add_upgrade(Vector(posx, posy), col_side, UPGRADE_1UP);
+      break;
+    default:
+      break;
+    }
+                                                                                
+  /* Empty the box: */
+  solids->change_at(pos, tile->next_tile);
+}
+                                                                                
+/* Try to grab a distro: */
+void
+Sector::trygrabdistro(const Vector& pos, int bounciness)
+{
+  Tile* tile = solids->get_tile_at(pos);
+  if (!(tile->attributes & Tile::COIN))
+    return;
+
+  solids->change_at(pos, tile->next_tile);
+  play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+                                                                            
+  if (bounciness == BOUNCE)
+    {
+      add_bouncy_distro(Vector(((int)(pos.x + 1) / 32) * 32,
+                              (int)(pos.y / 32) * 32));
+    }
+                                                                            
+  player_status.score = player_status.score + SCORE_DISTRO;
+  player_status.distros++;
+}
+                                                                                
+/* Try to bump a bad guy from below: */
+void
+Sector::trybumpbadguy(const Vector& pos)
+{
+  // Bad guys:
+  for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
+    {
+      if ((*i)->base.x >= pos.x - 32 && (*i)->base.x <= pos.x + 32 &&
+          (*i)->base.y >= pos.y - 16 && (*i)->base.y <= pos.y + 16)
+        {
+          (*i)->collision(player, CO_PLAYER, COLLISION_BUMP);
+        }
+    }
+                                                                                
+  // Upgrades:
+  for (unsigned int i = 0; i < upgrades.size(); i++)
+    {
+      if (upgrades[i]->base.height == 32 &&
+          upgrades[i]->base.x >= pos.x - 32 && upgrades[i]->base.x <= pos.x + 32 &&
+          upgrades[i]->base.y >= pos.y - 16 && upgrades[i]->base.y <= pos.y + 16)
+        {
+          upgrades[i]->collision(player, CO_PLAYER, COLLISION_BUMP);
+        }
+    }
+}
+
+void
+Sector::load_music()
+{
+  char* song_path;
+  char* song_subtitle;
+                                                                                
+  level_song = music_manager->load_music(datadir + "/music/" + song_title);
+                                                                                
+  song_path = (char *) malloc(sizeof(char) * datadir.length() +
+                              strlen(song_title.c_str()) + 8 + 5);
+  song_subtitle = strdup(song_title.c_str());
+  strcpy(strstr(song_subtitle, "."), "\0");
+  sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(),
+          song_subtitle, strstr(song_title.c_str(), "."));
+  if(!music_manager->exists_music(song_path)) {
+    level_song_fast = level_song;
+  } else {
+    level_song_fast = music_manager->load_music(song_path);
+  }
+  free(song_subtitle);
+  free(song_path);
+}
+
+void
+Sector::play_music(int type)
+{
+  currentmusic = type;
+  switch(currentmusic) {
+    case HURRYUP_MUSIC:
+      music_manager->play_music(level_song_fast);
+      break;
+    case LEVEL_MUSIC:
+      music_manager->play_music(level_song);
+      break;
+    case HERRING_MUSIC:
+      music_manager->play_music(herring_song);
+      break;
+    default:
+      music_manager->halt_music();
+      break;
+  }
+}
+
+int
+Sector::get_music_type()
+{
+  return currentmusic;
+}
diff --git a/src/sector.h b/src/sector.h
new file mode 100644 (file)
index 0000000..1676749
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef __SECTOR_H__
+#define __SECTOR_H__
+
+#include <string>
+#include <vector>
+#include "vector.h"
+#include "badguy.h"
+#include "special.h"
+#include "musicref.h"
+#include "screen/drawing_context.h"
+
+class GameObject;
+class Background;
+class Player;
+class Camera;
+class Trampoline;
+class FlyingPlatform;
+class TileMap;
+class Upgrade;
+class Bullet;
+class BadGuy;
+class Vector;
+class LispReader;
+class Tile;
+
+struct SpawnPoint
+{
+  std::string name;
+  Vector pos;
+};
+
+/** This class holds a sector (a part of a level) and all the game objects
+ * (badguys, player, background, tilemap, ...)
+ */
+class Sector
+{
+public:
+  Sector();
+  ~Sector();
+
+  /// read sector from lisp file
+  void parse(LispReader& reader);
+  void parse_old_format(LispReader& reader);
+  /// write sector to lisp file
+  void write(LispWriter& writer);
+
+  /// activates this sector (change music, intialize player class, ...)
+  void activate(const std::string& spawnpoint = "main");
+
+  void action(float elapsed_time);
+  void draw(DrawingContext& context);
+
+  /// adds a gameobject
+  void add_object(GameObject* object);
+
+  const std::string& get_name() const
+  { return name; }
+
+  void play_music(int musictype);
+  int get_music_type();
+  
+  /** Checks for all possible collisions. And calls the
+      collision_handlers, which the collision_objects provide for this
+      case (or not). */
+  void collision_handler();
+                                                                                
+  void add_score(const Vector& pos, int s);
+  void add_bouncy_distro(const Vector& pos);
+  void add_broken_brick(const Vector& pos, Tile* tile);
+  void add_broken_brick_piece(const Vector& pos,
+      const Vector& movement, Tile* tile);
+  void add_bouncy_brick(const Vector& pos);
+                                                                                
+  BadGuy* add_bad_guy(float x, float y, BadGuyKind kind);
+                                                                                
+  void add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind);
+  bool add_bullet(const Vector& pos, float xm, Direction dir);
+                                                                                
+  /** Try to grab the coin at the given coordinates */
+  void trygrabdistro(const Vector& pos, int bounciness);
+                                                                                
+  /** Try to break the brick at the given coordinates */
+  bool trybreakbrick(const Vector& pos, bool small);
+                                                                                
+  /** Try to get the content out of a bonus box, thus emptying it */
+  void tryemptybox(const Vector& pos, Direction col_side);
+                                                                                
+  /** Try to bumb a badguy that might we walking above Tux, thus shaking
+      the tile which the badguy is walking on an killing him this way */
+  void trybumpbadguy(const Vector& pos);
+
+  /** @evil@ */
+  static Sector* current()
+  { return _current; }
+
+private:
+  void load_music();
+  
+  static Sector* _current;
+  
+  std::string name;
+
+  std::string song_title;
+  MusicRef level_song;
+  MusicRef level_song_fast;
+
+public:
+  float gravity;
+
+  // some special objects, where we need direct access
+  Player* player;
+  TileMap* solids;
+  Background* background;
+  Camera* camera;
+  
+private:
+  typedef std::vector<BadGuy*> BadGuys;
+  BadGuys badguys;
+  typedef std::vector<Trampoline*> Trampolines;
+  Trampolines trampolines;
+  typedef std::vector<FlyingPlatform*> FlyingPlatforms;
+  FlyingPlatforms flying_platforms;
+
+  std::vector<Upgrade*> upgrades;
+  std::vector<Bullet*> bullets;
+
+public: // ugly
+  typedef std::vector<GameObject*> GameObjects;
+  GameObjects gameobjects;
+
+private:
+  typedef std::vector<SpawnPoint*> SpawnPoints;
+  SpawnPoints spawnpoints;
+
+  int distro_counter;
+  bool counting_distros;
+  int currentmusic;        
+};
+
+#endif
+
index 8dd89ae..0c88288 100644 (file)
@@ -29,6 +29,7 @@
 #include "scene.h"
 #include "globals.h"
 #include "player.h"
+#include "sector.h"
 #include "sprite_manager.h"
 #include "resources.h"
 
@@ -94,9 +95,9 @@ Bullet::action(float elapsed_time)
     physic.set_velocity_y(-9);
 
   float scroll_x =
-    World::current()->camera->get_translation().x;
+    Sector::current()->camera->get_translation().x;
   float scroll_y =
-    World::current()->camera->get_translation().y;
+    Sector::current()->camera->get_translation().y;
   if (base.x < scroll_x ||
       base.x > scroll_x + screen->w ||
       base.y < scroll_y ||
@@ -181,9 +182,9 @@ Upgrade::action(float elapsed_time)
 
   /* Away from the screen? Kill it! */
   float scroll_x =
-    World::current()->camera->get_translation().x;
+    Sector::current()->camera->get_translation().x;
   float scroll_y =                                                        
-    World::current()->camera->get_translation().y;
+    Sector::current()->camera->get_translation().y;
   
   if(base.x < scroll_x - X_OFFSCREEN_DISTANCE ||
       base.x > scroll_x + screen->w + X_OFFSCREEN_DISTANCE ||
@@ -332,7 +333,7 @@ Upgrade::collision(void* p_c_object, int c_object, CollisionType type)
         {
           play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER);
           pplayer->invincible_timer.start(TUX_INVINCIBLE_TIME);
-          World::current()->play_music(HERRING_MUSIC);
+          Sector::current()->play_music(HERRING_MUSIC);
         }
       else if (kind == UPGRADE_1UP)
         {
index c4d552f..3e8a553 100644 (file)
@@ -30,14 +30,14 @@ Sprite::Sprite(lisp_object_t* cur)
 
   LispReader reader(cur);
 
-  if(!reader.read_string("name",   &name))
+  if(!reader.read_string("name", name))
     st_abort("Sprite wihtout name", "");
-  reader.read_int("x-hotspot", &x_hotspot);
-  reader.read_int("y-hotspot", &y_hotspot);
-  reader.read_float("fps",     &fps);
+  reader.read_int("x-hotspot", x_hotspot);
+  reader.read_int("y-hotspot", y_hotspot);
+  reader.read_float("fps",     fps);
 
   std::vector<std::string> images;
-  if(!reader.read_string_vector("images", &images))
+  if(!reader.read_string_vector("images", images))
     st_abort("Sprite contains no images: ", name.c_str());
 
   for(std::vector<std::string>::size_type i = 0; i < images.size(); ++i)
index 6d17be6..62f96b8 100644 (file)
@@ -40,7 +40,9 @@
 
 int main(int argc, char * argv[])
 {
+#ifndef DEBUG
   try {
+#endif
     st_directory_setup();
     parseargs(argc, argv);
 
@@ -58,7 +60,7 @@ int main(int argc, char * argv[])
     }
     else if (level_startup_file)
     {
-      GameSession session(level_startup_file, 1, ST_GL_LOAD_LEVEL_FILE);
+      GameSession session(level_startup_file, ST_GL_LOAD_LEVEL_FILE);
       session.run();
     }
     else
@@ -76,6 +78,7 @@ int main(int argc, char * argv[])
     Surface::debug_check();
     #endif
     st_shutdown();
+#ifndef DEBUG  // we want to see the backtrace in gdb when in debug mode
   }
   catch (SuperTuxException &e)
   {
@@ -85,6 +88,7 @@ int main(int argc, char * argv[])
   {
     std:: cerr << "Unhandled exception: " << e.what() << std::endl;
   }
+#endif
 
   return 0;
 }
index d38ff62..0955b61 100644 (file)
@@ -47,41 +47,41 @@ Tile::~Tile()
 int
 Tile::read(LispReader& reader)
 {
-  if(!reader.read_int("id", &id)) {
+  if(!reader.read_int("id", id)) {
     std::cerr << "Missing tile-id.\n";
     return -1;
   }
   
   bool value;
-  if(reader.read_bool("solid", &value) && value)
+  if(reader.read_bool("solid", value) && value)
     attributes |= SOLID;
-  if(reader.read_bool("unisolid", &value) && value)
+  if(reader.read_bool("unisolid", value) && value)
     attributes |= GOAL;                            
-  if(reader.read_bool("brick", &value) && value)
+  if(reader.read_bool("brick", value) && value)
     attributes |= BRICK;
-  if(reader.read_bool("ice", &value) && value)
+  if(reader.read_bool("ice", value) && value)
     attributes |= ICE;
-  if(reader.read_bool("water", &value) && value)
+  if(reader.read_bool("water", value) && value)
     attributes |= WATER;
-  if(reader.read_bool("spike", &value) && value)
+  if(reader.read_bool("spike", value) && value)
     attributes |= SPIKE;
-  if(reader.read_bool("fullbox", &value) && value)
+  if(reader.read_bool("fullbox", value) && value)
     attributes |= FULLBOX;
-  if(reader.read_bool("distro", &value) && value)
+  if(reader.read_bool("distro", value) && value)
     attributes |= COIN;
-  if(reader.read_bool("coin", &value) && value)
+  if(reader.read_bool("coin", value) && value)
     attributes |= COIN;
-  if(reader.read_bool("goal", &value) && value)
+  if(reader.read_bool("goal", value) && value)
     attributes |= GOAL;
 
-  reader.read_int("data", &data);
-  reader.read_int("anim-speed", &anim_speed);
-  reader.read_int("next-tile", &next_tile);
+  reader.read_int("data", data);
+  reader.read_int("anim-speed", anim_speed);
+  reader.read_int("next-tile", next_tile);
 
   std::vector<std::string> filenames;
-  reader.read_string_vector("images", &filenames);
+  reader.read_string_vector("images", filenames);
   std::vector<std::string> editor_filenames;
-  reader.read_string_vector("editor-images", &editor_filenames);
+  reader.read_string_vector("editor-images", editor_filenames);
 
   // read images
   for(std::vector<std::string>::iterator i = filenames.begin();
@@ -162,7 +162,7 @@ void TileManager::load_tileset(std::string filename)
             {
               LispReader reader(lisp_cdr(element));
               std::string filename;
-              reader.read_string("file",  &filename);
+              reader.read_string("file", filename);
               filename = datadir + "/images/tilesets/" + filename;
               load_tileset(filename);
             }
@@ -170,8 +170,8 @@ void TileManager::load_tileset(std::string filename)
             {
               TileGroup new_;
               LispReader reader(lisp_cdr(element));
-              reader.read_string("name",  &new_.name);
-              reader.read_int_vector("tiles", &new_.tiles);          
+              reader.read_string("name", new_.name);
+              reader.read_int_vector("tiles", new_.tiles);           
               if(!tilegroups_)
                 tilegroups_ = new std::set<TileGroup>;
               tilegroups_->insert(new_).first;
@@ -179,7 +179,7 @@ void TileManager::load_tileset(std::string filename)
           else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0)
             {
               LispReader reader(lisp_cdr(element));
-              reader.read_int("id",  &tileset_id);
+              reader.read_int("id", tileset_id);
               tileset_id *= 1000;
             }
           else
index 45b2bb3..5eb1020 100644 (file)
 
 #include <assert.h>
 #include <algorithm>
+#include <iostream>
+#include <stdexcept>
 #include <math.h>
 #include "screen/drawing_context.h"
 #include "level.h"
 #include "tile.h"
 #include "globals.h"
+#include "lispreader.h"
+#include "lispwriter.h"
 
-TileMap::TileMap(Level* newlevel)
-  : level(newlevel)
+TileMap::TileMap()
+  : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES)
 {
   tilemanager = TileManager::instance();
 }
 
+TileMap::TileMap(LispReader& reader)
+  : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES)
+{
+  tilemanager = TileManager::instance();
+
+  std::string layer;
+  if(reader.read_string("layer", layer)) {
+    if(layer == "background")
+      layer = LAYER_BACKGROUNDTILES;
+    else if(layer == "interactive")
+      layer = LAYER_TILES;
+    else if(layer == "foreground")
+      layer = LAYER_FOREGROUNDTILES;
+    else
+      std::cout << "Unknown layer '" << layer << "' in tilemap.\n";
+  }
+
+  reader.read_bool("solid", solid);
+  reader.read_float("speed", speed);
+
+  if(solid && speed != 1) {
+    std::cout << "Speed of solid tilemap is not 1. fixing.\n";
+    speed = 1;
+  }
+  
+  if(!reader.read_int("width", width) ||
+     !reader.read_int("height", height))
+    throw std::runtime_error("No width or height specified in tilemap.");
+  
+  if(!reader.read_int_vector("tiles", tiles))
+    throw std::runtime_error("No tiles in tilemap.");
+  if(int(tiles.size()) != width*height)
+    throw std::runtime_error("wrong number of tiles in tilemap.");
+}
+
 TileMap::~TileMap()
 {
 }
 
 void
+TileMap::write(LispWriter& writer)
+{
+  writer.start_list("tilemap");
+
+  if(layer == LAYER_BACKGROUNDTILES)
+    writer.write_string("layer", "background");
+  else if(layer == LAYER_TILES)
+    writer.write_string("layer", "interactive");
+  else if(layer == LAYER_FOREGROUNDTILES)
+    writer.write_string("layer", "foreground");
+  else {
+    std::cout << "Warning unknown layer in tilemap.\n";
+  }
+
+  writer.write_bool("solid", solid);
+  writer.write_float("speed", speed);
+  writer.write_int("width", width);
+  writer.write_int("height", height);
+  writer.write_int_vector("tiles", tiles);
+  
+  writer.end_list("tilemap");
+}
+
+void
 TileMap::action(float )
 {
 }
 
 void
-TileMap::draw(const std::vector<unsigned int>& tiles, DrawingContext& context,
-    int layer)
+TileMap::draw(DrawingContext& context)
 {
   /** if we don't round here, we'll have a 1 pixel gap on screen sometimes.
    * I have no idea why */
-  float start_x = roundf(context.get_translation().x);
-  float start_y = roundf(context.get_translation().y);
-  float end_x = std::min(start_x + screen->w, float(level->width * 32));
-  float end_y = std::min(start_y + screen->h, float(level->height * 32));
+  float start_x = roundf(context.get_translation().x * speed);
+  float start_y = roundf(context.get_translation().y * speed);
+  float end_x = std::min(start_x + screen->w, float(width * 32));
+  float end_y = std::min(start_y + screen->h, float(height * 32));
   start_x -= int(start_x) % 32;
   start_y -= int(start_y) % 32;  
   int tsx = int(start_x / 32); // tilestartindex x
@@ -60,15 +122,87 @@ TileMap::draw(const std::vector<unsigned int>& tiles, DrawingContext& context,
   int tx, ty;
   for(pos.x = start_x, tx = tsx; pos.x < end_x; pos.x += 32, ++tx) {
     for(pos.y = start_y, ty = tsy; pos.y < end_y; pos.y += 32, ++ty) {
-      tilemanager->draw_tile(context, tiles[ty*level->width + tx], pos, layer);
+      tilemanager->draw_tile(context, tiles[ty*width + tx], pos, layer);
     }
   }
 }
 
 void
-TileMap::draw(DrawingContext& context)
+TileMap::set(int newwidth, int newheight, const std::vector<unsigned int>&newt,
+    int newlayer, bool newsolid)
+{
+  assert(int(newt.size()) == newwidth * newheight);
+
+  width = newwidth;
+  height = newheight;
+  tiles = newt;
+  layer = newlayer;
+  solid = newsolid;
+}
+
+void
+TileMap::resize(int new_width, int new_height)
+{
+  if(new_width < width) {
+    // remap tiles for new width
+    for(int y = 0; y < height && y < new_height; ++y) {
+      for(int x = 0; x < new_width; ++x) {
+        tiles[y * new_width + x] = tiles[y * width + x];
+      }
+    }
+  }
+                                                                                
+  tiles.resize(new_width * new_height);
+                                                                                
+  if(new_width > width) {
+    // remap tiles
+    for(int y = std::min(height, new_height)-1; y >= 0; --y) {
+      for(int x = new_width-1; x >= 0; --x) {
+        if(x >= width) {
+          tiles[y * new_width + x] = 0;
+        } else {
+          tiles[y * new_width + x] = tiles[y * width + x];
+        }
+      }
+    }
+  }
+
+  height = new_height;
+  width = new_width;
+}
+
+Tile*
+TileMap::get_tile(int x, int y) const
+{
+  if(x < 0 || x >= width || y < 0 || y >= height)
+    return tilemanager->get(0);
+
+  return tilemanager->get(tiles[y*width + x]);
+}
+
+Tile*
+TileMap::get_tile_at(const Vector& pos) const
+{
+  return get_tile(int(pos.x)/32, int(pos.y)/32);
+}
+
+unsigned int
+TileMap::get_tile_id_at(const Vector& pos) const
+{
+  int x = int(pos.x)/32;
+  int y = int(pos.y)/32;
+  return tiles[y*width + x];
+}
+
+void
+TileMap::change(int x, int y, unsigned int newtile)
+{
+  assert(x >= 0 && x < width && y >= 0 && y < height);
+  tiles[y*width + x] = newtile;
+}
+
+void
+TileMap::change_at(const Vector& pos, unsigned int newtile)
 {
-  draw(level->bg_tiles, context, LAYER_BACKGROUNDTILES);
-  draw(level->ia_tiles, context, LAYER_TILES);
-  draw(level->fg_tiles, context, LAYER_FOREGROUNDTILES);
+  change(int(pos.x)/32, int(pos.y)/32, newtile);
 }
index 8d8f291..b629ccd 100644 (file)
 #include <vector>
 #include "game_object.h"
 #include "serializable.h"
+#include "vector.h"
 
 class Level;
 class TileManager;
+class LispReader;
+class Tile;
 
 /**
  * This class is reponsible for drawing the level tiles
  */
-class TileMap : public GameObject
+class TileMap : public GameObject, public Serializable
 {
 public:
-  TileMap(Level* level);
+  TileMap();
+  TileMap(LispReader& reader);
   virtual ~TileMap();
 
+  virtual void write(LispWriter& writer);
+
   virtual void action(float elapsed_time);
-  virtual void draw(const std::vector<unsigned int>& tiles,
-      DrawingContext& context, int layer);
   virtual void draw(DrawingContext& context);
+
+  void set(int width, int height, const std::vector<unsigned int>& vec,
+      int layer, bool solid);
+
+  /** resizes the tilemap to a new width and height (tries to not destroy the
+   * existing map)
+   */
+  void resize(int newwidth, int newheight);
+
+  size_t get_width() const
+  { return width; }
+
+  size_t get_height() const
+  { return height; }
+  
+  bool is_solid() const
+  { return solid; }
+
+  unsigned int get_tile_id_at(const Vector& pos) const;
+
+  /// returns tile in row y and column y (of the tilemap)
+  Tile* get_tile(int x, int y) const;
+  /// returns tile at position pos (in world coordinates)
+  Tile* get_tile_at(const Vector& pos) const;
+
+  void change(int x, int y, unsigned int newtile);
+
+  void change_at(const Vector& pos, unsigned int newtile);
+
+public:
+  std::vector<unsigned int> tiles;
   
 private:
   TileManager* tilemanager;
-  Level* level;
+  bool solid;
+  float speed;
+  int width, height;
+  int layer;
 };
 
 #endif
index 9ef6a6d..21cd918 100644 (file)
@@ -49,6 +49,8 @@
 #include "player.h"
 #include "math.h"
 #include "tile.h"
+#include "sector.h"
+#include "tilemap.h"
 #include "resources.h"
 
 static Surface* bkg_title;
@@ -62,8 +64,10 @@ static int frame;
 static unsigned int last_update_time;
 static unsigned int update_time;
 
-std::vector<LevelSubset*> contrib_subsets;
-std::string current_contrib_subset;
+static GameSession* titlesession;
+
+static std::vector<LevelSubset*> contrib_subsets;
+static LevelSubset* current_contrib_subset = 0;
 
 void free_contrib_menu()
 {
@@ -115,20 +119,26 @@ void check_contrib_menu()
               // FIXME: This shouln't be busy looping
               LevelSubset& subset = * (contrib_subsets[index]);
           
-              current_contrib_subset = subset.name;
+              current_contrib_subset = &subset;
 
               contrib_subset_menu->clear();
 
               contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
               contrib_subset_menu->additem(MN_HL,"",0,0);
+              
               for (int i = 1; i <= subset.levels; ++i)
                 {
-                  Level level;
-                  level.load(subset.name, i, 0);
-                  contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i);
+                  Level* level = new Level;
+                  level->load(subset.get_level_filename(i));
+                  contrib_subset_menu->additem(MN_ACTION, level->get_name(), 0, 0, i);
+                  delete level;
                 }
+              
               contrib_subset_menu->additem(MN_HL,"",0,0);      
               contrib_subset_menu->additem(MN_BACK, "Back", 0, 0);
+
+              titlesession->get_current_sector()->activate();
+              titlesession->set_current();
             }
         }
       else
@@ -146,20 +156,22 @@ void check_contrib_subset_menu()
       if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION)
         {
           std::cout << "Starting level: " << index << std::endl;
-          GameSession session(current_contrib_subset, index, ST_GL_PLAY);
+          
+          GameSession session(
+              current_contrib_subset->get_level_filename(index), ST_GL_PLAY);
           session.run();
           player_status.reset();
           Menu::set_current(main_menu);
+          titlesession->get_current_sector()->activate();
+          titlesession->set_current();
         }
     }  
 }
 
-void draw_demo(GameSession* session, double frame_ratio)
+void draw_demo(double frame_ratio)
 {
-  World* world  = session->get_world();
-  World::set_current(world);
-  Level* plevel = session->get_level();
-  Player* tux = world->get_tux();
+  Sector* world  = titlesession->get_current_sector();
+  Player* tux = world->player;
 
   world->play_music(LEVEL_MUSIC);
   
@@ -180,7 +192,7 @@ void draw_demo(GameSession* session, double frame_ratio)
     }
 
   // Wrap around at the end of the level back to the beginnig
-  if(plevel->width * 32 - 320 < tux->base.x)
+  if(world->solids->get_width() * 32 - 320 < tux->base.x)
     {
       tux->level_begin();
     }
@@ -198,7 +210,7 @@ void draw_demo(GameSession* session, double frame_ratio)
       walking = false;
     }
 
-  world->draw();
+  world->draw(*titlesession->context);
 }
 
 /* --- TITLE SCREEN --- */
@@ -210,7 +222,7 @@ void title(void)
 
   st_pause_ticks_init();
 
-  GameSession session(datadir + "/levels/misc/menu.stl", 0, ST_GL_DEMO_GAME);
+  titlesession = new GameSession(datadir + "/levels/misc/menu.stl", ST_GL_DEMO_GAME);
 
   /* Load images: */
   bkg_title = new Surface(datadir + "/images/background/arctis.jpg", IGNORE_ALPHA);
@@ -224,7 +236,7 @@ void title(void)
   random_timer.start(rand() % 2000 + 2000);
 
   Menu::set_current(main_menu);
-  DrawingContext& context = World::current()->context;
+  DrawingContext& context = *titlesession->context;
   while (Menu::current())
     {
       // if we spent to much time on a menu entry
@@ -251,10 +263,8 @@ void title(void)
         }
 
       /* Draw the background: */
-      draw_demo(&session, frame_ratio);
+      draw_demo(frame_ratio);
      
-      context.push_transform();
-      context.set_translation(Vector(0, 0));
       if (Menu::current() == main_menu)
         context.draw_surface(logo, Vector(screen->w/2 - logo->w/2, 30),
             LAYER_FOREGROUND1+1);
@@ -265,7 +275,6 @@ void title(void)
           "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
           "are welcome to redistribute it under certain conditions; see the file COPYING\n"
           "for details.\n", Vector(0, screen->h - 70), LAYER_FOREGROUND1);
-      context.pop_transform();
 
       /* Don't draw menu, if quit is true */
       Menu* menu = Menu::current();
@@ -327,6 +336,8 @@ void title(void)
               else if (process_load_game_menu())
                 {
                   // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
+                  titlesession->get_current_sector()->activate();
+                  titlesession->set_current();
                   //titletux.level_begin();
                   update_time = st_get_ticks();
                 }
@@ -356,6 +367,7 @@ void title(void)
   /* Free surfaces: */
 
   free_contrib_menu();
+  delete titlesession;
   delete bkg_title;
   delete logo;
   delete img_choose_subset;
diff --git a/src/world.cpp b/src/world.cpp
deleted file mode 100644 (file)
index 3f63a2e..0000000
+++ /dev/null
@@ -1,642 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-//  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.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 <iostream>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include "globals.h"
-#include "scene.h"
-#include "screen/screen.h"
-#include "defines.h"
-#include "world.h"
-#include "level.h"
-#include "tile.h"
-#include "resources.h"
-#include "gameobjs.h"
-#include "camera.h"
-#include "background.h"
-#include "tilemap.h"
-
-Surface* img_distro[4];
-
-World* World::current_ = 0;
-
-World::World(const std::string& filename, int level_nr)
-  : level(0), tux(0), background(0), camera(0)
-{
-  // FIXME: Move this to action and draw and everywhere else where the
-  // world calls child functions
-  current_ = this;
-
-  tux = new Player;
-  add_object(tux);
-  
-  level = new Level;
-  camera = new Camera(tux, level);
-  add_object(camera);                 
-
-  if(level_nr >= 0) {
-    level->load(filename, level_nr, this);
-  } else {
-    level->load(filename, this);
-  }
-  tux->move(level->start_pos);
-  
-  set_defaults();
-
-  // add background
-  activate_particle_systems();
-
-  // add tilemap
-  add_object(new TileMap(level));
-  level->load_song();
-
-  apply_bonuses();
-}
-
-void
-World::apply_bonuses()
-{
-  // Apply bonuses from former levels
-  switch (player_status.bonus)
-    {
-    case PlayerStatus::NO_BONUS:
-      break;
-                                                                                
-    case PlayerStatus::FLOWER_BONUS:
-      tux->got_power = Player::FIRE_POWER;  // FIXME: add ice power to here
-      // fall through
-                                                                                
-    case PlayerStatus::GROWUP_BONUS:
-      tux->grow(false);
-      break;
-    }
-}
-
-World::~World()
-{
-  for (std::vector<GameObject*>::iterator i = gameobjects.begin();
-          i != gameobjects.end(); ++i) {
-    delete *i;
-  }
-
-  delete level;
-
-  current_ = 0;
-}
-
-void
-World::set_defaults()
-{
-  player_status.score_multiplier = 1;
-
-  counting_distros = false;
-  distro_counter = 0;
-
-  /* set current song/music */
-  currentmusic = LEVEL_MUSIC;
-}
-
-void
-World::add_object(GameObject* object)
-{
-  // XXX hack for now until new collision code is ready
-  BadGuy* badguy = dynamic_cast<BadGuy*> (object);
-  if(badguy)
-    bad_guys.push_back(badguy);
-  Bullet* bullet = dynamic_cast<Bullet*> (object);
-  if(bullet)
-    bullets.push_back(bullet);
-  Upgrade* upgrade = dynamic_cast<Upgrade*> (object);
-  if(upgrade)
-    upgrades.push_back(upgrade);
-  Trampoline* trampoline = dynamic_cast<Trampoline*> (object);
-  if(trampoline)
-    trampolines.push_back(trampoline);
-  FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (object);
-  if(flying_platform)
-    flying_platforms.push_back(flying_platform);
-  Background* background = dynamic_cast<Background*> (object);
-  if(background)
-    this->background = background;
-
-  gameobjects.push_back(object);
-}
-
-void
-World::parse_objects(lisp_object_t* cur)
-{
-  while(!lisp_nil_p(cur)) {
-    lisp_object_t* data = lisp_car(cur);
-    std::string object_type = lisp_symbol(lisp_car(data));
-    
-    LispReader reader(lisp_cdr(data));
-
-    if(object_type == "trampoline") {
-      add_object(new Trampoline(reader));
-    }
-    else if(object_type == "flying-platform") {
-      add_object(new FlyingPlatform(reader));
-    }
-    else {
-      BadGuyKind kind = badguykind_from_string(object_type);
-      add_object(new BadGuy(kind, reader));
-    }
-      
-    cur = lisp_cdr(cur);
-  } 
-}
-
-void
-World::activate_particle_systems()
-{
-  if (level->particle_system == "clouds")
-    {
-      add_object(new CloudParticleSystem);
-    }
-  else if (level->particle_system == "snow")
-    {
-      add_object(new SnowParticleSystem);
-    }
-  else if (level->particle_system != "")
-    {
-      st_abort("unknown particle system specified in level", "");
-    }
-}
-
-void
-World::draw()
-{
-  /* Draw objects */
-  for(std::vector<GameObject*>::iterator i = gameobjects.begin();
-      i != gameobjects.end(); ++i)
-    if((*i)->is_valid())
-      (*i)->draw(context);
-}
-
-void
-World::action(float elapsed_time)
-{
-  tux->check_bounds(context);
-    
-  /* update objects (don't use iterators here, because the list might change
-   * during the iteration)
-   */
-  for(size_t i = 0; i < gameobjects.size(); ++i)
-    if(gameobjects[i]->is_valid())
-      gameobjects[i]->action(elapsed_time);
-
-  /* Handle all possible collisions. */
-  collision_handler();
-  /** cleanup marked objects */
-  for(std::vector<GameObject*>::iterator i = gameobjects.begin();
-      i != gameobjects.end(); /* nothing */) {
-    if((*i)->is_valid() == false) {
-      BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
-      if(badguy) {
-        bad_guys.erase(std::remove(bad_guys.begin(), bad_guys.end(), badguy),
-            bad_guys.end());
-      }
-      Bullet* bullet = dynamic_cast<Bullet*> (*i);
-      if(bullet) {
-        bullets.erase(
-            std::remove(bullets.begin(), bullets.end(), bullet),
-            bullets.end());
-      }
-      Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
-      if(upgrade) {
-        upgrades.erase(
-            std::remove(upgrades.begin(), upgrades.end(), upgrade),
-            upgrades.end());
-      }
-      Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
-      if(trampoline) {
-        trampolines.erase(
-            std::remove(trampolines.begin(), trampolines.end(), trampoline),
-            trampolines.end());
-      }
-      FlyingPlatform* flying_platform= dynamic_cast<FlyingPlatform*> (*i);
-      if(flying_platform) {
-        flying_platforms.erase(
-            std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform),
-            flying_platforms.end());
-      }
-      
-      delete *i;
-      i = gameobjects.erase(i);
-    } else {
-      ++i;
-    }
-  }
-}
-
-void
-World::collision_handler()
-{
-  // CO_BULLET & CO_BADGUY check
-  for(unsigned int i = 0; i < bullets.size(); ++i)
-    {
-      for (BadGuys::iterator j = bad_guys.begin(); j != bad_guys.end(); ++j)
-        {
-          if((*j)->dying != DYING_NOT)
-            continue;
-          
-          if(rectcollision(bullets[i]->base, (*j)->base))
-            {
-              // We have detected a collision and now call the
-              // collision functions of the collided objects.
-              (*j)->collision(bullets[i], CO_BULLET, COLLISION_NORMAL);
-              bullets[i]->collision(CO_BADGUY);
-              break; // bullet is invalid now, so break
-            }
-        }
-    }
-
-  /* CO_BADGUY & CO_BADGUY check */
-  for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
-    {
-      if((*i)->dying != DYING_NOT)
-        continue;
-      
-      BadGuys::iterator j = i;
-      ++j;
-      for (; j != bad_guys.end(); ++j)
-        {
-          if(j == i || (*j)->dying != DYING_NOT)
-            continue;
-
-          if(rectcollision((*i)->base, (*j)->base))
-            {
-              // We have detected a collision and now call the
-              // collision functions of the collided objects.
-              (*j)->collision(*i, CO_BADGUY);
-              (*i)->collision(*j, CO_BADGUY);
-            }
-        }
-    }
-
-  if(tux->dying != DYING_NOT) return;
-    
-  // CO_BADGUY & CO_PLAYER check 
-  for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
-    {
-      if((*i)->dying != DYING_NOT)
-        continue;
-      
-      if(rectcollision_offset((*i)->base, tux->base, 0, 0))
-        {
-          // We have detected a collision and now call the collision
-          // functions of the collided objects.
-          if (tux->previous_base.y < tux->base.y &&
-              tux->previous_base.y + tux->previous_base.height 
-              < (*i)->base.y + (*i)->base.height/2
-              && !tux->invincible_timer.started())
-            {
-              (*i)->collision(tux, CO_PLAYER, COLLISION_SQUISH);
-            }
-          else
-            {
-              tux->collision(*i, CO_BADGUY);
-              (*i)->collision(tux, CO_PLAYER, COLLISION_NORMAL);
-            }
-        }
-    }
-
-  // CO_UPGRADE & CO_PLAYER check
-  for(unsigned int i = 0; i < upgrades.size(); ++i)
-    {
-      if(rectcollision(upgrades[i]->base, tux->base))
-        {
-          // We have detected a collision and now call the collision
-          // functions of the collided objects.
-          upgrades[i]->collision(tux, CO_PLAYER, COLLISION_NORMAL);
-        }
-    }
-
-  // CO_TRAMPOLINE & (CO_PLAYER or CO_BADGUY)
-  for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
-  {
-    if (rectcollision((*i)->base, tux->base))
-    {
-      if (tux->previous_base.y < tux->base.y &&
-          tux->previous_base.y + tux->previous_base.height 
-          < (*i)->base.y + (*i)->base.height/2)
-      {
-        (*i)->collision(tux, CO_PLAYER, COLLISION_SQUISH);
-      }
-      else if (tux->previous_base.y <= tux->base.y)
-      {
-        tux->collision(*i, CO_TRAMPOLINE);
-        (*i)->collision(tux, CO_PLAYER, COLLISION_NORMAL);
-      }
-    }
-  }
-
-  // CO_FLYING_PLATFORM & (CO_PLAYER or CO_BADGUY)
-  for (FlyingPlatforms::iterator i = flying_platforms.begin(); i != flying_platforms.end(); ++i)
-  {
-    if (rectcollision((*i)->base, tux->base))
-    {
-      if (tux->previous_base.y < tux->base.y &&
-          tux->previous_base.y + tux->previous_base.height 
-          < (*i)->base.y + (*i)->base.height/2)
-      {
-        (*i)->collision(tux, CO_PLAYER, COLLISION_SQUISH);
-        tux->collision(*i, CO_FLYING_PLATFORM);
-      }
-/*      else if (tux->previous_base.y <= tux->base.y)
-      {
-      }*/
-    }
-  }
-}
-
-void
-World::add_score(const Vector& pos, int s)
-{
-  player_status.score += s;
-
-  add_object(new FloatingScore(pos, s));
-}
-
-void
-World::add_bouncy_distro(const Vector& pos)
-{
-  add_object(new BouncyDistro(pos));
-}
-
-void
-World::add_broken_brick(const Vector& pos, Tile* tile)
-{
-  add_broken_brick_piece(pos, Vector(-1, -4), tile);
-  add_broken_brick_piece(pos + Vector(0, 16), Vector(-1.5, -3), tile);
-
-  add_broken_brick_piece(pos + Vector(16, 0), Vector(1, -4), tile);
-  add_broken_brick_piece(pos + Vector(16, 16), Vector(1.5, -3), tile);
-}
-
-void
-World::add_broken_brick_piece(const Vector& pos, const Vector& movement,
-    Tile* tile)
-{
-  add_object(new BrokenBrick(tile, pos, movement));
-}
-
-void
-World::add_bouncy_brick(const Vector& pos)
-{
-  add_object(new BouncyBrick(pos));
-}
-
-BadGuy*
-World::add_bad_guy(float x, float y, BadGuyKind kind)
-{
-  BadGuy* badguy = new BadGuy(kind, x, y);
-  add_object(badguy);
-  return badguy;
-}
-
-void
-World::add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind)
-{
-  add_object(new Upgrade(pos, dir, kind));
-}
-
-bool
-World::add_bullet(const Vector& pos, float xm, Direction dir)
-{
-  if(tux->got_power == Player::FIRE_POWER)
-    {
-    if(bullets.size() > MAX_FIRE_BULLETS-1)
-      return false;
-    }
-  else if(tux->got_power == Player::ICE_POWER)
-    {
-    if(bullets.size() > MAX_ICE_BULLETS-1)
-      return false;
-    }
-
-  Bullet* new_bullet = 0;
-  if(tux->got_power == Player::FIRE_POWER)
-    new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
-  else if(tux->got_power == Player::ICE_POWER)
-    new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
-  else
-    st_abort("wrong bullet type.", "");
-  add_object(new_bullet);
-  
-  play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER);
-
-  return true;
-}
-
-void
-World::play_music(int musictype)
-{
-  currentmusic = musictype;
-  switch(currentmusic) {
-    case HURRYUP_MUSIC:
-      music_manager->play_music(get_level()->get_level_music_fast());
-      break;
-    case LEVEL_MUSIC:
-      music_manager->play_music(get_level()->get_level_music());
-      break;
-    case HERRING_MUSIC:
-      music_manager->play_music(herring_song);
-      break;
-    default:
-      music_manager->halt_music();
-      break;
-  }
-}
-
-int
-World::get_music_type()
-{
-  return currentmusic;
-}
-
-/* Break a brick: */
-bool
-World::trybreakbrick(float x, float y, bool small)
-{
-  Level* plevel = get_level();
-  
-  Tile* tile = gettile(x, y);
-  if (tile->attributes & Tile::BRICK)
-    {
-      if (tile->data > 0)
-        {
-          /* Get a distro from it: */
-          add_bouncy_distro(
-              Vector(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32));
-
-          // TODO: don't handle this in a global way but per-tile...
-          if (!counting_distros)
-            {
-              counting_distros = true;
-              distro_counter = 5;
-            }
-          else
-            {
-              distro_counter--;
-            }
-
-          if (distro_counter <= 0)
-            {
-              counting_distros = false;
-              plevel->change(x, y, TM_IA, tile->next_tile);
-            }
-
-          play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
-          player_status.score = player_status.score + SCORE_DISTRO;
-          player_status.distros++;
-          return true;
-        }
-      else if (!small)
-        {
-          /* Get rid of it: */
-          plevel->change(x, y, TM_IA, tile->next_tile);
-          
-          /* Replace it with broken bits: */
-          add_broken_brick(Vector(
-                                 ((int)(x + 1) / 32) * 32,
-                                 (int)(y / 32) * 32), tile);
-          
-          /* Get some score: */
-          play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
-          player_status.score = player_status.score + SCORE_BRICK;
-          
-          return true;
-        }
-    }
-
-  return false;
-}
-
-/* Empty a box: */
-void
-World::tryemptybox(float x, float y, Direction col_side)
-{
-  Tile* tile = gettile(x,y);
-  if (!(tile->attributes & Tile::FULLBOX))
-    return;
-
-  // according to the collision side, set the upgrade direction
-  if(col_side == LEFT)
-    col_side = RIGHT;
-  else
-    col_side = LEFT;
-
-  int posx = ((int)(x+1) / 32) * 32;
-  int posy = (int)(y/32) * 32 - 32;
-  switch(tile->data)
-    {
-    case 1: // Box with a distro!
-      add_bouncy_distro(Vector(posx, posy));
-      play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
-      player_status.score = player_status.score + SCORE_DISTRO;
-      player_status.distros++;
-      break;
-
-    case 2: // Add a fire flower upgrade!
-      if (tux->size == SMALL)     /* Tux is small, add mints! */
-        add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
-      else     /* Tux is big, add a fireflower: */
-        add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER);
-      play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
-      break;
-    
-    case 5: // Add an ice flower upgrade!
-      if (tux->size == SMALL)     /* Tux is small, add mints! */
-        add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
-      else     /* Tux is big, add an iceflower: */
-        add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER);
-      play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
-      break;
-
-    case 3: // Add a golden herring
-      add_upgrade(Vector(posx, posy), col_side, UPGRADE_HERRING);
-      break;
-
-    case 4: // Add a 1up extra
-      add_upgrade(Vector(posx, posy), col_side, UPGRADE_1UP);
-      break;
-    default:
-      break;
-    }
-
-  /* Empty the box: */
-  level->change(x, y, TM_IA, tile->next_tile);
-}
-
-/* Try to grab a distro: */
-void
-World::trygrabdistro(float x, float y, int bounciness)
-{
-  Tile* tile = gettile(x, y);
-  if (tile && (tile->attributes & Tile::COIN))
-    {
-      level->change(x, y, TM_IA, tile->next_tile);
-      play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
-
-      if (bounciness == BOUNCE)
-        {
-          add_bouncy_distro(Vector(((int)(x + 1) / 32) * 32,
-                                  (int)(y / 32) * 32));
-        }
-
-      player_status.score = player_status.score + SCORE_DISTRO;
-      player_status.distros++;
-    }
-}
-
-/* Try to bump a bad guy from below: */
-void
-World::trybumpbadguy(float x, float y)
-{
-  // Bad guys: 
-  for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
-    {
-      if ((*i)->base.x >= x - 32 && (*i)->base.x <= x + 32 &&
-          (*i)->base.y >= y - 16 && (*i)->base.y <= y + 16)
-        {
-          (*i)->collision(tux, CO_PLAYER, COLLISION_BUMP);
-        }
-    }
-
-  // Upgrades:
-  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 &&
-          upgrades[i]->base.y >= y - 16 && upgrades[i]->base.y <= y + 16)
-        {
-          upgrades[i]->collision(tux, CO_PLAYER, COLLISION_BUMP);
-        }
-    }
-}
-
-/* EOF */
-
diff --git a/src/world.h b/src/world.h
deleted file mode 100644 (file)
index d886cd3..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-//  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.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_WORLD_H
-#define SUPERTUX_WORLD_H
-
-#include <vector>
-#include <SDL.h>
-#include "type.h"
-#include "scene.h"
-#include "special.h"
-#include "badguy.h"
-#include "particlesystem.h"
-#include "screen/drawing_context.h"
-
-class Camera;
-class Level;
-class Background;
-class Trampoline;
-class FlyingPlatform;
-
-/** The World class holds a level and all the game objects (badguys,
-    bouncy distros, etc) that are needed to run a game. */
-class World
-{
-private:
-  typedef std::list<BadGuy*> BadGuys;
-  BadGuys bad_guys_to_add;
-  typedef std::list<Trampoline*> Trampolines;
-  Trampolines trampolines;
-  typedef std::list<FlyingPlatform*> FlyingPlatforms;
-  FlyingPlatforms flying_platforms;
-  Level* level;
-  Player* tux;
-
-  int distro_counter;
-  bool counting_distros;
-  int currentmusic;
-
-  static World* current_;
-public:
-  Background* background;
-  BadGuys bad_guys;
-
-  std::vector<Upgrade*> upgrades;
-  std::vector<Bullet*> bullets;
-  std::vector<GameObject*> gameobjects;
-
-  Camera* camera;
-  DrawingContext context;
-
-public:
-  static World* current()
-  { return current_; }
-  static void set_current(World* w)
-  { current_ = w; }
-
-  World(const std::string& filename, int level_nr = -1);
-  ~World();
-  
-  Level*  get_level()
-  { return level; }
-  Player* get_tux()
-  { return tux; }
-
-  void add_object(GameObject* object);
-
-  void set_defaults();
-
-  void draw();
-  void action(float elapsed_time);
-
-  void play_music(int musictype);
-  int get_music_type();
-
-  /** Checks for all possible collisions. And calls the
-      collision_handlers, which the collision_objects provide for this
-      case (or not). */
-  void collision_handler();
-
-  void parse_objects(lisp_object_t* cur);
-  
-  void activate_particle_systems();
-
-  void add_score(const Vector& pos, int s);
-  void add_bouncy_distro(const Vector& pos);
-  void add_broken_brick(const Vector& pos, Tile* tile);
-  void add_broken_brick_piece(const Vector& pos,
-      const Vector& movement, Tile* tile);
-  void add_bouncy_brick(const Vector& pos);
-
-  BadGuy* add_bad_guy(float x, float y, BadGuyKind kind);
-
-  void add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind);
-  bool add_bullet(const Vector& pos, float xm, Direction dir);
-
-  /** Try to grab the coin at the given coordinates */
-  void trygrabdistro(float x, float y, int bounciness);
-
-  /** Try to break the brick at the given coordinates */
-  bool trybreakbrick(float x, float y, bool small);
-
-  /** Try to get the content out of a bonus box, thus emptying it */
-  void tryemptybox(float x, float y, Direction col_side);
-
-  /** Try to bumb a badguy that might we walking above Tux, thus shaking
-      the tile which the badguy is walking on an killing him this way */
-  void trybumpbadguy(float x, float y);
-
-  /** Apply bonuses active in the player status, used to reactivate
-      bonuses from former levels */
-  void apply_bonuses();
-};
-
-/** FIMXE: Workaround for the leveleditor mainly */
-extern World global_world;
-
-#endif /*SUPERTUX_WORLD_H*/
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
-
index 944a39c..3f529e0 100644 (file)
@@ -29,6 +29,7 @@
 #include "lispreader.h"
 #include "gameloop.h"
 #include "setup.h"
+#include "sector.h"
 #include "worldmap.h"
 #include "resources.h"
 
@@ -115,14 +116,14 @@ TileManager::TileManager()
               tile->auto_walk = false;
   
               LispReader reader(lisp_cdr(element));
-              reader.read_int("id",  &id);
-              reader.read_bool("north", &tile->north);
-              reader.read_bool("south", &tile->south);
-              reader.read_bool("west",  &tile->west);
-              reader.read_bool("east",  &tile->east);
-              reader.read_bool("stop",  &tile->stop);
-              reader.read_bool("auto-walk",  &tile->auto_walk);
-              reader.read_string("image",  &filename);
+              reader.read_int("id", id);
+              reader.read_bool("north", tile->north);
+              reader.read_bool("south", tile->south);
+              reader.read_bool("west",  tile->west);
+              reader.read_bool("east",  tile->east);
+              reader.read_bool("stop",  tile->stop);
+              reader.read_bool("auto-walk",  tile->auto_walk);
+              reader.read_string("image", filename);
 
               tile->sprite = new Surface(
                            datadir +  "/images/worldmap/" + filename, 
@@ -393,15 +394,15 @@ WorldMap::load_map()
           if (strcmp(lisp_symbol(lisp_car(element)), "tilemap") == 0)
             {
               LispReader reader(lisp_cdr(element));
-              reader.read_int("width",  &width);
-              reader.read_int("height", &height);
-              reader.read_int_vector("data", &tilemap);
+              reader.read_int("width",  width);
+              reader.read_int("height", height);
+              reader.read_int_vector("data", tilemap);
             }
           else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0)
             {
               LispReader reader(lisp_cdr(element));
-              reader.read_string("name",  &name);
-              reader.read_string("music", &music);
+              reader.read_string("name", name);
+              reader.read_string("music", music);
             }
           else if (strcmp(lisp_symbol(lisp_car(element)), "levels") == 0)
             {
@@ -422,10 +423,10 @@ WorldMap::load_map()
                       level.south = true;
                       level.west  = true;
 
-                      reader.read_string("extro-filename",  &level.extro_filename);
-                      reader.read_string("name",  &level.name);
-                      reader.read_int("x", &level.x);
-                      reader.read_int("y", &level.y);
+                      reader.read_string("extro-filename", level.extro_filename);
+                      reader.read_string("name", level.name);
+                      reader.read_int("x", level.x);
+                      reader.read_int("y", level.y);
 
                       levels.push_back(level);
                     }
@@ -471,7 +472,7 @@ void WorldMap::get_level_title(Level& level)
   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
   {
     LispReader reader(lisp_cdr(root_obj));
-    reader.read_string("name",  &level.title);
+    reader.read_string("name", level.title);
   }
 
   lisp_free(root_obj);
@@ -644,7 +645,7 @@ WorldMap::update(float delta)
               shrink_fade(Vector((level->x*32 + 16 + offset.x),(level->y*32 + 16
                       + offset.y)), 500);
               GameSession session(datadir +  "/levels/" + level->name,
-                                  1, ST_GL_LOAD_LEVEL_FILE);
+                                  ST_GL_LOAD_LEVEL_FILE);
 
               switch (session.run())
                 {
@@ -653,10 +654,10 @@ WorldMap::update(float delta)
                     bool old_level_state = level->solved;
                     level->solved = true;
 
-                    if (session.get_world()->get_tux()->got_power !=
-                          session.get_world()->get_tux()->NONE_POWER)
+                    if (session.get_current_sector()->player->got_power !=
+                          session.get_current_sector()->player->NONE_POWER)
                       player_status.bonus = PlayerStatus::FLOWER_BONUS;
-                    else if (session.get_world()->get_tux()->size == BIG)
+                    else if (session.get_current_sector()->player->size == BIG)
                       player_status.bonus = PlayerStatus::GROWUP_BONUS;
                     else
                       player_status.bonus = PlayerStatus::NO_BONUS;
@@ -841,9 +842,6 @@ WorldMap::draw(DrawingContext& context, const Vector& offset)
 void
 WorldMap::draw_status(DrawingContext& context)
 {
-  context.push_transform();
-  context.set_translation(Vector(0, 0));
-  
   char str[80];
   sprintf(str, "%d", player_status.score);
 
@@ -1014,25 +1012,25 @@ WorldMap::loadgame(const std::string& filename)
   cur = lisp_cdr(cur);
   LispReader reader(cur);
 
-  reader.read_int("lives",  &player_status.lives);
-  reader.read_int("score",  &player_status.score);
-  reader.read_int("distros", &player_status.distros);
+  reader.read_int("lives", player_status.lives);
+  reader.read_int("score", player_status.score);
+  reader.read_int("distros", player_status.distros);
 
   if (player_status.lives < 0)
     player_status.lives = START_LIVES;
 
   lisp_object_t* tux_cur = 0;
-  if (reader.read_lisp("tux", &tux_cur))
+  if (reader.read_lisp("tux", tux_cur))
     {
       Vector p;
       std::string back_str = "none";
       std::string bonus_str = "none";
 
       LispReader tux_reader(tux_cur);
-      tux_reader.read_float("x", &p.x);
-      tux_reader.read_float("y", &p.y);
-      tux_reader.read_string("back", &back_str);
-      tux_reader.read_string("bonus", &bonus_str);
+      tux_reader.read_float("x", p.x);
+      tux_reader.read_float("y", p.y);
+      tux_reader.read_string("back", back_str);
+      tux_reader.read_string("bonus", bonus_str);
       
       player_status.bonus = string_to_bonus(bonus_str);
       tux->back_direction = string_to_direction(back_str);      
@@ -1040,7 +1038,7 @@ WorldMap::loadgame(const std::string& filename)
     }
 
   lisp_object_t* level_cur = 0;
-  if (reader.read_lisp("levels", &level_cur))
+  if (reader.read_lisp("levels", level_cur))
     {
       while(level_cur)
         {
@@ -1053,8 +1051,8 @@ WorldMap::loadgame(const std::string& filename)
               bool solved = false;
 
               LispReader level_reader(data);
-              level_reader.read_string("name",   &name);
-              level_reader.read_bool("solved", &solved);
+              level_reader.read_string("name", name);
+              level_reader.read_bool("solved", solved);
 
               for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
                 {