-changed Level class to save tiles in a big 1 dimensional array instead of
authorMatthias Braun <matze@braunis.de>
Thu, 20 May 2004 19:56:37 +0000 (19:56 +0000)
committerMatthias Braun <matze@braunis.de>
Thu, 20 May 2004 19:56:37 +0000 (19:56 +0000)
 vector<vector>. You can access a tile like this now tiles[y * width + x] is the tile at place x,y
-introduced new Serializable interface that is implemented by all objects that
 are able to save themselfes to disk
-added new lispwriter class
-changed level laoding/save code to use new serializable/lispwriter stuff

SVN-Revision: 1282

15 files changed:
src/Makefile.am
src/badguy.cpp
src/badguy.h
src/button.cpp
src/button.h
src/level.cpp
src/level.h
src/leveleditor.cpp
src/lispreader.cpp
src/lispreader.h
src/player.h
src/tilemap.cpp
src/title.cpp
src/world.cpp
src/world.h

index 1b62893..485ade3 100644 (file)
@@ -1,6 +1,8 @@
 bin_PROGRAMS = supertux
 
 supertux_SOURCES = \
+lispwriter.h \
+lispwriter.cpp \
 badguy.cpp \
 badguy.h \
 bitmask.cpp \
@@ -87,6 +89,6 @@ background.cpp \
 tilemap.h \
 tilemap.cpp \
 moving_object.h \
-moving_object.cpp
+moving_object.cpp 
 
 # EOF #
index 9804627..57f147a 100644 (file)
@@ -33,6 +33,8 @@
 #include "resources.h"
 #include "sprite_manager.h"
 #include "gameloop.h"
+#include "display_manager.h"
+#include "lispwriter.h"
 
 Sprite* img_mriceblock_flat_left;
 Sprite* img_mriceblock_flat_right;
@@ -142,20 +144,56 @@ std::string badguykind_to_string(BadGuyKind kind)
     }
 }
 
-BadGuy::BadGuy(float x, float y, BadGuyKind kind_, bool stay_on_platform_)
+BadGuy::BadGuy(DisplayManager& display_manager, BadGuyKind kind_,
+    LispReader& lispreader)
   : removable(false), squishcount(0)
 {
-  base.x   = x;
-  base.y   = y;    
+  display_manager.add_drawable(this, LAYER_OBJECTS);
+
+  base.x = 0;
+  base.y = 0;
+  lispreader.read_float("x", &base.x);
+  lispreader.read_float("y", &base.y);
+  base.width  = 0;
+  base.height = 0;
+  base.xm  = 0;
+  base.ym  = 0;
+
+  kind     = kind_;
+
+  stay_on_platform = false;
+  lispreader.read_bool("stay-on-platform", &stay_on_platform);  
+
+  init();
+}
+
+BadGuy::BadGuy(DisplayManager& display_manager, BadGuyKind kind_,
+    float x, float y)
+{
+  display_manager.add_drawable(this, LAYER_OBJECTS);
+
+  base.x = x;
+  base.y = y;
   base.width  = 0;
   base.height = 0;
   base.xm  = 0;
   base.ym  = 0;
+  stay_on_platform = false;
+
+  kind     = kind_;
+  
+  init();
+}
+
+BadGuy::~BadGuy()
+{
+}
 
-  stay_on_platform = stay_on_platform_;
+void
+BadGuy::init()
+{
   mode     = NORMAL;
   dying    = DYING_NOT;
-  kind     = kind_;
   old_base = base;
   dir      = LEFT;
   seen     = false;
@@ -212,7 +250,19 @@ BadGuy::BadGuy(float x, float y, BadGuyKind kind_, bool stay_on_platform_)
 }
 
 void
-BadGuy::action_mriceblock(double frame_ratio)
+BadGuy::write(LispWriter& writer)
+{
+  writer.startList(badguykind_to_string(kind));
+
+  writer.writeFloat("x", base.x);
+  writer.writeFloat("y", base.y);
+  writer.writeBool("stay-on-platform", stay_on_platform);  
+
+  writer.endList(badguykind_to_string(kind));
+}
+
+void
+BadGuy::action_mriceblock(double elapsed_time)
 {
   Player& tux = *World::current()->get_tux();
 
@@ -223,7 +273,7 @@ BadGuy::action_mriceblock(double frame_ratio)
   if (mode != HELD)
     {
       // move
-      physic.apply(frame_ratio, base.x, base.y);
+      physic.apply(elapsed_time, base.x, base.y);
       if (dying != DYING_FALLING)
         collision_swept_object_map(&old_base,&base);
     }
@@ -383,13 +433,7 @@ BadGuy::fall()
 }
 
 void
-BadGuy::remove_me()
-{
-  removable = true;
-}
-
-void
-BadGuy::action_jumpy(double frame_ratio)
+BadGuy::action_jumpy(double elapsed_time)
 {
   if(frozen_timer.check())
     {
@@ -432,13 +476,13 @@ BadGuy::action_jumpy(double frame_ratio)
     dir = LEFT;
 
   // move
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
   if(dying == DYING_NOT)
     collision_swept_object_map(&old_base, &base);
 }
 
 void
-BadGuy::action_mrbomb(double frame_ratio)
+BadGuy::action_mrbomb(double elapsed_time)
 {
   if(frozen_timer.check())
     {
@@ -451,13 +495,13 @@ BadGuy::action_mrbomb(double frame_ratio)
 
   fall();
 
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
   if (dying != DYING_FALLING)
     collision_swept_object_map(&old_base,&base); 
 }
 
 void
-BadGuy::action_bomb(double frame_ratio)
+BadGuy::action_bomb(double elapsed_time)
 {
   static const int TICKINGTIME = 1000;
   static const int EXPLODETIME = 1000;
@@ -489,12 +533,12 @@ BadGuy::action_bomb(double frame_ratio)
   }
 
   // move
-  physic.apply(frame_ratio, base.x, base.y);                 
+  physic.apply(elapsed_time, base.x, base.y);                 
   collision_swept_object_map(&old_base,&base);
 }
 
 void
-BadGuy::action_stalactite(double frame_ratio)
+BadGuy::action_stalactite(double elapsed_time)
 {
   Player& tux = *World::current()->get_tux();
 
@@ -529,25 +573,25 @@ BadGuy::action_stalactite(double frame_ratio)
   }
 
   // move
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
 
   if(dying == DYING_SQUISHED && !timer.check())
     remove_me();
 }
 
 void
-BadGuy::action_flame(double frame_ratio)
+BadGuy::action_flame(double elapsed_time)
 {
     static const float radius = 100;
     static const float speed = 0.02;
     base.x = old_base.x + cos(base.ym) * radius;
     base.y = old_base.y + sin(base.ym) * radius;
 
-    base.ym = fmodf(base.ym + frame_ratio * speed, 2*M_PI);
+    base.ym = fmodf(base.ym + elapsed_time * speed, 2*M_PI);
 }
 
 void
-BadGuy::action_fish(double frame_ratio)
+BadGuy::action_fish(double elapsed_time)
 {
   if(frozen_timer.check())
     {
@@ -581,7 +625,7 @@ BadGuy::action_fish(double frame_ratio)
       physic.enable_gravity(true);
     }
 
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
   if(dying == DYING_NOT)
     collision_swept_object_map(&old_base, &base);
 
@@ -590,7 +634,7 @@ BadGuy::action_fish(double frame_ratio)
 }
 
 void
-BadGuy::action_bouncingsnowball(double frame_ratio)
+BadGuy::action_bouncingsnowball(double elapsed_time)
 {
   static const float JUMPV = 4.5;
     
@@ -610,7 +654,7 @@ BadGuy::action_bouncingsnowball(double frame_ratio)
   // check for right/left collisions
   check_horizontal_bump();
 
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
   if(dying == DYING_NOT)
     collision_swept_object_map(&old_base, &base);
 
@@ -624,7 +668,7 @@ BadGuy::action_bouncingsnowball(double frame_ratio)
 }
 
 void
-BadGuy::action_flyingsnowball(double frame_ratio)
+BadGuy::action_flyingsnowball(double elapsed_time)
 {
   static const float FLYINGSPEED = 1;
   static const int DIRCHANGETIME = 1000;
@@ -650,7 +694,7 @@ BadGuy::action_flyingsnowball(double frame_ratio)
   if(dying != DYING_NOT)
     physic.enable_gravity(true);
 
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
   if(dying == DYING_NOT || dying == DYING_SQUISHED)
     collision_swept_object_map(&old_base, &base);
 
@@ -664,7 +708,7 @@ BadGuy::action_flyingsnowball(double frame_ratio)
 }
 
 void
-BadGuy::action_spiky(double frame_ratio)
+BadGuy::action_spiky(double elapsed_time)
 {
   if(frozen_timer.check())
     {
@@ -685,26 +729,26 @@ BadGuy::action_spiky(double frame_ratio)
   }
 #endif
 
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
   if (dying != DYING_FALLING)
     collision_swept_object_map(&old_base,&base);   
 }
 
 void
-BadGuy::action_snowball(double frame_ratio)
+BadGuy::action_snowball(double elapsed_time)
 {
   if (dying == DYING_NOT)
     check_horizontal_bump();
 
   fall();
 
-  physic.apply(frame_ratio, base.x, base.y);
+  physic.apply(elapsed_time, base.x, base.y);
   if (dying != DYING_FALLING)
     collision_swept_object_map(&old_base,&base);
 }
 
 void
-BadGuy::action(double frame_ratio)
+BadGuy::action(float elapsed_time)
 {
   // Remove if it's far off the screen:
   if (base.x < scroll_x - OFFSCREEN_DISTANCE)
@@ -740,47 +784,47 @@ BadGuy::action(double frame_ratio)
   switch (kind)
     {
     case BAD_MRICEBLOCK:
-      action_mriceblock(frame_ratio);
+      action_mriceblock(elapsed_time);
       break;
   
     case BAD_JUMPY:
-      action_jumpy(frame_ratio);
+      action_jumpy(elapsed_time);
       break;
 
     case BAD_MRBOMB:
-      action_mrbomb(frame_ratio);
+      action_mrbomb(elapsed_time);
       break;
     
     case BAD_BOMB:
-      action_bomb(frame_ratio);
+      action_bomb(elapsed_time);
       break;
 
     case BAD_STALACTITE:
-      action_stalactite(frame_ratio);
+      action_stalactite(elapsed_time);
       break;
 
     case BAD_FLAME:
-      action_flame(frame_ratio);
+      action_flame(elapsed_time);
       break;
 
     case BAD_FISH:
-      action_fish(frame_ratio);
+      action_fish(elapsed_time);
       break;
 
     case BAD_BOUNCINGSNOWBALL:
-      action_bouncingsnowball(frame_ratio);
+      action_bouncingsnowball(elapsed_time);
       break;
 
     case BAD_FLYINGSNOWBALL:
-      action_flyingsnowball(frame_ratio);
+      action_flyingsnowball(elapsed_time);
       break;
 
     case BAD_SPIKY:
-      action_spiky(frame_ratio);
+      action_spiky(elapsed_time);
       break;
 
     case BAD_SNOWBALL:
-      action_snowball(frame_ratio);
+      action_snowball(elapsed_time);
       break;
     default:
       break;
@@ -788,8 +832,11 @@ BadGuy::action(double frame_ratio)
 }
 
 void
-BadGuy::draw()
+BadGuy::draw(ViewPort& viewport, int)
 {
+  float scroll_x = viewport.get_translation().x;
+  float scroll_y = viewport.get_translation().y;
+
   // Don't try to draw stuff that is outside of the screen
   if(base.x <= scroll_x - base.width || base.x >= scroll_x + screen->w)
     return;
@@ -881,14 +928,13 @@ BadGuy::squish(Player* player)
     
   if(kind == BAD_MRBOMB) {
     // mrbomb transforms into a bomb now
-    World::current()->add_bad_guy(base.x, base.y, BAD_BOMB);
+    explode();
     
     make_player_jump(player);
     World::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++;
-    remove_me();
     return;
 
   } else if (kind == BAD_MRICEBLOCK) {
@@ -986,10 +1032,17 @@ BadGuy::kill_me(int score)
   play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
 }
 
-void BadGuy::explode(BadGuy *badguy)
+void
+BadGuy::explode()
+{
+  World::current()->add_bad_guy(base.x, base.y, BAD_BOMB);
+  remove_me();
+}
+
+void
+BadGuy::collision(const MovingObject&, int)
 {
-World::current()->add_bad_guy(badguy->base.x, badguy->base.y, BAD_BOMB);
-badguy->remove_me();
+  // later
 }
 
 void
@@ -1052,7 +1105,7 @@ BadGuy::collision(void *p_c_object, int c_object, CollisionType type)
         if (pbad_c->kind == BAD_MRBOMB)
         {
           // mrbomb transforms into a bomb now
-          explode(pbad_c);
+          pbad_c->explode();
           return;
         }
         else if (pbad_c->kind != BAD_MRBOMB)
@@ -1067,7 +1120,7 @@ BadGuy::collision(void *p_c_object, int c_object, CollisionType type)
         if (pbad_c->kind == BAD_MRBOMB)
         {
           // mrbomb transforms into a bomb now
-          explode(pbad_c);
+          pbad_c->explode();
           return;
         }
         else
index 0335351..b349c02 100644 (file)
@@ -32,6 +32,9 @@
 #include "physic.h"
 #include "collision.h"
 #include "sprite.h"
+#include "moving_object.h"
+#include "drawable.h"
+#include "serializable.h"
 
 /* Bad guy kinds: */
 enum BadGuyKind {
@@ -57,7 +60,7 @@ void free_badguy_gfx();
 class Player;
 
 /* Badguy type: */
-class BadGuy : public GameObject
+class BadGuy : public MovingObject, public Drawable, public Serializable
 {
 public:
   /* Enemy modes: */
@@ -107,13 +110,17 @@ private:
   int animation_offset;
 
 public:
-  BadGuy(float x, float y, BadGuyKind kind, bool stay_on_platform);
+  BadGuy(DisplayManager& display_manager, BadGuyKind kind, float x, float y);
+  BadGuy(DisplayManager& display_manager, BadGuyKind kind, LispReader& reader);
+  virtual ~BadGuy();
 
-  void action(double frame_ratio);
-  void draw();
-  std::string type() { return "BadGuy"; };
+  virtual void write(LispWriter& writer);
 
-  void explode(BadGuy* badguy);
+  virtual void action(float frame_ratio);
+  virtual void draw(ViewPort& viewport, int layer);
+  virtual void collision(const MovingObject& other, int type);
+  virtual std::string type() const
+  { return "BadGuy"; };
 
   void collision(void* p_c_object, int c_object,
                  CollisionType type = COLLISION_NORMAL);
@@ -123,14 +130,9 @@ public:
    */
   void kill_me(int score);
 
-  /** remove ourself from the list of badguys. WARNING! This function will
-   * invalidate all members. So don't do anything else with member after calling
-   * this.
-   */
-  void remove_me();  
-  bool is_removable() const { return removable; }
 private:
+  void init();
+  
   void action_mriceblock(double frame_ratio);
   void action_jumpy(double frame_ratio); 
   void action_bomb(double frame_ratio);
@@ -150,6 +152,8 @@ private:
   /** let the player jump a bit (used when you hit a badguy) */
   void make_player_jump(Player* player);
 
+  void explode();
+
   /** check if we're running left or right in a wall and eventually change
    * direction
    */
@@ -164,21 +168,6 @@ private:
   void set_sprite(Sprite* left, Sprite* right);
 };
 
-struct BadGuyData
-{
-  BadGuyKind kind;
-  int x;
-  int y;
-  bool stay_on_platform;
-
-  BadGuyData(BadGuy* pbadguy) : kind(pbadguy->kind), x((int)pbadguy->base.x), y((int)pbadguy->base.y), stay_on_platform(pbadguy->stay_on_platform)  {};
-  BadGuyData(BadGuyKind kind_, int x_, int y_, bool stay_on_platform_) 
-    : kind(kind_), x(x_), y(y_), stay_on_platform(stay_on_platform_) {}
-
-  BadGuyData()
-    : kind(BAD_SNOWBALL), x(0), y(0), stay_on_platform(false) {}
-};
-
 #endif /*SUPERTUX_BADGUY_H*/
 
 /* Local Variables: */
index 8bb8e50..6467474 100644 (file)
@@ -24,6 +24,7 @@
 #include "screen.h"
 #include "globals.h"
 #include "button.h"
+#include "viewport.h"
 
 Timer Button::popup_timer;
 
@@ -44,7 +45,7 @@ Button::Button(std::string icon_file, std::string ninfo, SDLKey nshortcut, int x
   tag = -1;
   state = BUTTON_NONE;
   show_info = false;
-  game_object = NULL;
+  drawable = NULL;
 }
 
 void Button::add_icon(std::string icon_file, int mw, int mh)
@@ -84,9 +85,11 @@ void Button::draw()
   for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
     (*it)->draw(rect.x,rect.y);
 
-  if(game_object != NULL)
+  if(drawable)
   {
-    game_object->draw_on_screen(rect.x,rect.y);
+    ViewPort viewport;
+    viewport.set_translation(Vector(rect.x, rect.y));
+    drawable->draw(viewport, 0);
   }
 
   if(show_info)
@@ -113,7 +116,7 @@ Button::~Button()
   for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
     delete (*it);
   icon.clear();
-  delete game_object;
+  delete drawable;
 }
 
 void Button::event(SDL_Event &event)
index af2d51b..950e898 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <vector>
 #include "texture.h"
+#include "drawable.h"
 
 enum ButtonState {
   BUTTON_NONE = -1,
@@ -50,12 +51,12 @@ public:
   void add_icon(std::string icon_file, int mw, int mh);
   SDL_Rect get_pos() { return rect; }
   int get_tag(){return tag; }
-  void set_game_object(GameObject* game_object_) { game_object = game_object_; }
-  GameObject* get_game_object() { return game_object; };
+  void set_drawable(Drawable* newdrawable)
+  { drawable = newdrawable; }
 
 private:
   static Timer popup_timer;
-  GameObject* game_object;
+  Drawable* drawable;
   std::vector<Surface*> icon;
   std::string info;
   SDLKey shortcut;
index 24deca6..e7ecdfd 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <iostream>
+#include <fstream>
 #include "globals.h"
 #include "setup.h"
 #include "screen.h"
@@ -34,6 +35,8 @@
 #include "resources.h"
 #include "music_manager.h"
 #include "gameobjs.h"
+#include "world.h"
+#include "lispwriter.h"
 
 using namespace std;
 
@@ -56,7 +59,7 @@ void LevelSubset::create(const std::string& subset_name)
   new_subset.description = "No description so far.";
   new_subset.save();
   new_lev.init_defaults();
-  new_lev.save(subset_name, 1);
+  new_lev.save(subset_name, 1, 0);
 }
 
 void LevelSubset::parse (lisp_object_t* cursor)
@@ -206,20 +209,6 @@ Level::Level()
   init_defaults();
 }
 
-Level::Level(const std::string& subset, int level)
-  : img_bkgd(0)
-{
-  if(load(subset, level) < 0)
-    st_abort("Couldn't load level from subset", subset.c_str());
-}
-
-Level::Level(const std::string& filename)
-  : img_bkgd(0)
-{
-  if(load(filename) < 0)
-    st_abort("Couldn't load level " , filename.c_str());
-}
-
 Level::~Level()
 {
   delete img_bkgd;
@@ -232,8 +221,8 @@ Level::init_defaults()
   author     = "UnNamed";
   song_title = "Mortimers_chipdisko.mod";
   bkgd_image = "arctis.png";
-  width      = 21;
-  height     = 19;
+  width      = 0;
+  height     = 0;
   start_pos_x = 100;
   start_pos_y = 170;
   time_left  = 100;
@@ -248,32 +237,11 @@ Level::init_defaults()
   bkgd_bottom.green = 255;
   bkgd_bottom.blue  = 255;
 
-  bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-  ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-  fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-
-  for(int i = 0; i < height; ++i)
-    {
-      ia_tiles[i].resize(width+1, 0);
-      ia_tiles[i][width] = (unsigned int) '\0';
-
-      for(int y = 0; y < width; ++y)
-        ia_tiles[i][y] = 0;
-
-      bg_tiles[i].resize(width+1, 0);
-      bg_tiles[i][width] = (unsigned int) '\0';
-      for(int y = 0; y < width; ++y)
-        bg_tiles[i][y] = 0;
-
-      fg_tiles[i].resize(width+1, 0);
-      fg_tiles[i][width] = (unsigned int) '\0';
-      for(int y = 0; y < width; ++y)
-        fg_tiles[i][y] = 0;
-    }
+  resize(21, 19);
 }
 
 int
-Level::load(const std::string& subset, int level)
+Level::load(const std::string& subset, int level, World* world)
 {
   char filename[1024];
 
@@ -282,11 +250,11 @@ Level::load(const std::string& subset, int level)
   if(!faccessible(filename))
     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level);
 
-  return load(filename);
+  return load(filename, world);
 }
 
 int 
-Level::load(const std::string& filename)
+Level::load(const std::string& filename, World* world)
 {
   lisp_object_t* root_obj = lisp_read_from_file(filename);
   if (!root_obj)
@@ -301,10 +269,6 @@ Level::load(const std::string& filename)
       return -1;
     }
 
-  vector<int> ia_tm;
-  vector<int> bg_tm;
-  vector<int> fg_tm;
-
   int version = 0;
   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
     {
@@ -356,12 +320,18 @@ Level::load(const std::string& filename)
       particle_system = "";
       reader.read_string("particle_system", &particle_system);
 
-      reader.read_int_vector("background-tm",  &bg_tm);
+      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_tm))
-        reader.read_int_vector("tilemap", &ia_tm);
+      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_tm);
+      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;
@@ -389,44 +359,12 @@ Level::load(const std::string& filename)
         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 = "";
-
-                LispReader reader(lisp_cdr(data));
-                reader.read_string("type", &object_type);
-
-                if (object_type == "badguy" || object_type == "")
-                {
-                  BadGuyData bg_data;
-                  bg_data.kind = badguykind_from_string(lisp_symbol(lisp_car(data)));
-                  reader.read_int("x", &bg_data.x);
-                  reader.read_int("y", &bg_data.y);
-                  reader.read_bool("stay-on-platform", &bg_data.stay_on_platform);
-
-                  badguy_data.push_back(bg_data);
-                }
-                else
-                {
-                    if (strcmp(lisp_symbol(lisp_car(data)),"trampoline") == 0)
-                    {
-                      ObjectData<TrampolineData> _trampoline_data;
-
-                      _trampoline_data.type = OBJ_TRAMPOLINE;
-                      reader.read_int("x", &_trampoline_data.x);
-                      reader.read_int("y", &_trampoline_data.y);
-                      reader.read_float("power", &_trampoline_data.type_specific.power);
-
-                      trampoline_data.push_back(_trampoline_data);
-                    }
-                }
-
-                cur = lisp_cdr(cur);
-              }
+            if(world)
+              world->parse_objects(cur);
           }
       }
 
+#if 0 // TODO fix this or remove it
       // Convert old levels to the new tile numbers
       if (version == 0)
         {
@@ -496,53 +434,7 @@ Level::load(const std::string& filename)
                 }
             }
         }
-    }
-
-  bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-  ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-  fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-
-  for(int i = 0; i < height; ++i)
-    {
-      ia_tiles[i].resize(width + 1, 0);
-      bg_tiles[i].resize(width + 1, 0);
-      fg_tiles[i].resize(width + 1, 0);
-    }
-
-  int i = 0;
-  int j = 0;
-  for(vector<int>::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i)
-    {
-      ia_tiles[j][i] = (*it);
-      if(i == width - 1)
-        {
-          i = -1;
-          ++j;
-        }
-    }
-
-  i = j = 0;
-  for(vector<int>::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i)
-    {
-
-      bg_tiles[j][i] = (*it);
-      if(i == width - 1)
-        {
-          i = -1;
-          ++j;
-        }
-    }
-
-  i = j = 0;
-  for(vector<int>::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i)
-    {
-
-      fg_tiles[j][i] = (*it);
-      if(i == width - 1)
-        {
-          i = -1;
-          ++j;
-        }
+#endif
     }
 
   lisp_free(root_obj);
@@ -552,7 +444,7 @@ Level::load(const std::string& filename)
 /* Save data for level: */
 
 void 
-Level::save(const std::string& subset, int level)
+Level::save(const std::string& subset, int level, World* world)
 {
   char filename[1024];
   char str[80];
@@ -566,114 +458,77 @@ Level::save(const std::string& subset, int level)
     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
         subset.c_str(), level);
 
-  FILE * fi = fopen(filename, "w");
-  if (fi == NULL)
-    {
-      perror(filename);
-      st_shutdown();
-      exit(-1);
-    }
-
+  std::ofstream out(filename);
+  if(!out.good()) {
+    st_abort("Couldn't write file.", filename);
+  }
+  LispWriter writer(out);
 
   /* Write header: */
-  fprintf(fi,";SuperTux level made using the built-in leveleditor\n");
-  fprintf(fi,"(supertux-level\n");
-
-  fprintf(fi,"  (version %d)\n", 1);
-  fprintf(fi,"  (name \"%s\")\n", name.c_str());
-  fprintf(fi,"  (author \"%s\")\n", author.c_str());
-  fprintf(fi,"  (music \"%s\")\n", song_title.c_str());
-  fprintf(fi,"  (background \"%s\")\n", bkgd_image.c_str());
-  fprintf(fi,"  (particle_system \"%s\")\n", particle_system.c_str());
-  fprintf(fi,"  (bkgd_speed %d)\n", bkgd_speed);
-  fprintf(fi,"  (bkgd_red_top %d)\n", bkgd_top.red);
-  fprintf(fi,"  (bkgd_green_top %d)\n", bkgd_top.green);
-  fprintf(fi,"  (bkgd_blue_top %d)\n", bkgd_top.blue);
-  fprintf(fi,"  (bkgd_red_bottom %d)\n", bkgd_bottom.red);
-  fprintf(fi,"  (bkgd_green_bottom %d)\n", bkgd_bottom.green);
-  fprintf(fi,"  (bkgd_blue_bottom %d)\n", bkgd_bottom.blue);
-  fprintf(fi,"  (time %d)\n", time_left);
-  fprintf(fi,"  (width %d)\n", width);
-  fprintf(fi,"  (height %d)\n", height);
-  if(back_scrolling)
-    fprintf(fi,"  (back_scrolling #t)\n"); 
-  else
-    fprintf(fi,"  (back_scrolling #f)\n");
-  fprintf(fi,"  (hor_autoscroll_speed %2.1f)\n", hor_autoscroll_speed);
-  fprintf(fi,"  (gravity %2.1f)\n", gravity);
-  fprintf(fi,"  (background-tm ");
-
-  for(int y = 0; y < height; ++y)
-    {
-      for(int i = 0; i < width; ++i)
-        fprintf(fi," %d ", bg_tiles[y][i]);
-      fprintf(fi,"\n");
-    }
-
-  fprintf( fi,")\n");
-  fprintf(fi,"  (interactive-tm ");
-
-  for(int y = 0; y < height; ++y)
-    {
-      for(int i = 0; i < width; ++i)
-        fprintf(fi," %d ", ia_tiles[y][i]);
-      fprintf(fi,"\n");
-    }
-
-  fprintf( fi,")\n");
-  fprintf(fi,"  (foreground-tm ");
-
-  for(int y = 0; y < height; ++y)
-    {
-      for(int i = 0; i < width; ++i)
-        fprintf(fi," %d ", fg_tiles[y][i]);
-      fprintf(fi,"\n");
-    }
-
-  fprintf( fi,")\n");
-
-  fprintf( fi,"(reset-points\n");
+  writer.writeComment("SuperTux level made using the built-in leveleditor");
+  writer.startList("supertux-level");
+
+  writer.writeInt("version", 1);
+  writer.writeString("name", name);
+  writer.writeString("author", author);
+  writer.writeString("music", song_title);
+  writer.writeString("background", bkgd_image);
+  writer.writeString("particle_system", particle_system);
+  writer.writeInt("bkgd_speed", bkgd_speed);
+  writer.writeInt("bkgd_red_top", bkgd_top.red);
+  writer.writeInt("bkgd_green_top", bkgd_top.green);
+  writer.writeInt("bkgd_blue_top", bkgd_top.blue);
+  writer.writeInt("bkgd_red_bottom", bkgd_bottom.red);
+  writer.writeInt("bkgd_green_bottom", bkgd_bottom.green);
+  writer.writeInt("bkgd_blue_bottom", bkgd_bottom.blue);
+  writer.writeInt("time", time_left);
+  writer.writeInt("width", width);
+  writer.writeInt("height", height);
+  writer.writeBool("back_scrolling", back_scrolling);
+  writer.writeFloat("hor_autoscroll_speed", hor_autoscroll_speed);
+  writer.writeFloat("gravity", gravity);
+
+  writer.writeIntVector("background-tm", bg_tiles);
+  writer.writeIntVector("interactive-tm", ia_tiles);
+  writer.writeIntVector("foreground-tm", fg_tiles);
+
+  writer.startList("reset-points");
   for(std::vector<ResetPoint>::iterator i = reset_points.begin();
-      i != reset_points.end(); ++i)
-    fprintf( fi,"(point (x %d) (y %d))\n",i->x, i->y);
-  fprintf( fi,")\n");
-
-  fprintf( fi,"(objects\n");
-
-  for(std::vector<BadGuyData>::iterator it = badguy_data.begin();
-      it != badguy_data.end();
-      ++it)
-    fprintf( fi,"  (%s (x %d) (y %d) (stay-on-platform %s))\n",
-             badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y,
-             it->stay_on_platform ? "#t" : "#f");
-
-  fprintf( fi,")\n");
-
-  fprintf( fi,")\n");
+      i != reset_points.end(); ++i) {
+    writer.startList("point");
+    writer.writeInt("x", i->x);
+    writer.writeInt("y", i->y);
+  }
+  writer.endList("reset-points");
+
+  // write objects
+  writer.startList("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.endList("objects");
 
-  fclose(fi);
+  writer.endList("supertux-level");
+  out.close();
 }
 
-
 /* Unload data for this level: */
-
 void
 Level::cleanup()
 {
-  for(int i=0; i < 15; ++i)
-    {
-      bg_tiles[i].clear();
-      ia_tiles[i].clear();
-      fg_tiles[i].clear();
-    }
+  bg_tiles.clear();
+  ia_tiles.clear();
+  fg_tiles.clear();
 
   reset_points.clear();
   name = "";
   author = "";
   song_title = "";
   bkgd_image = "";
-
-  badguy_data.clear();
 }
 
 void 
@@ -709,34 +564,32 @@ void Level::load_image(Surface** ptexture, string theme,const  char * file, int
 
 /* Change the size of a level */
 void 
-Level::change_width (int new_width)
+Level::resize(int new_width, int new_height)
 {
-  if(new_width < 21)
-    new_width = 21;
+  // first: resize height
+  ia_tiles.resize(new_height * width, 0);
+  bg_tiles.resize(new_height * width, 0);
+  fg_tiles.resize(new_height * width, 0);
+  height = new_height;
 
-  for(int y = 0; y < height; ++y)
-    {
-      ia_tiles[y].resize(new_width, 0);
-      bg_tiles[y].resize(new_width, 0);
-      fg_tiles[y].resize(new_width, 0);
+  // remap horizontal tiles for new width
+  int np = 0;
+  for(int y = 0; y < height; ++y) {
+    for(int x = 0; x < new_width && x < width; ++x) {
+      ia_tiles[np] = ia_tiles[y * width + x];
+      bg_tiles[np] = bg_tiles[y * width + x];
+      fg_tiles[np] = fg_tiles[y * width + x];
+      np++;
     }
+  }
 
+  ia_tiles.resize(new_height * new_width);
+  bg_tiles.resize(new_height * new_width);
+  fg_tiles.resize(new_height * new_width); 
+  
   width = new_width;
 }
 
-void 
-Level::change_height (int new_height)
-{
-  if(new_height < 15)
-    new_height = 15;
-
-  bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-  ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-  fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
-
-  height = new_height;
-}
-
 void
 Level::change(float x, float y, int tm, unsigned int c)
 {
@@ -748,13 +601,13 @@ Level::change(float x, float y, int tm, unsigned int c)
       switch(tm)
         {
         case TM_BG:
-          bg_tiles[yy][xx] = c;
+          bg_tiles[yy * width + xx] = c;
           break;
         case TM_IA:
-          ia_tiles[yy][xx] = c;
+          ia_tiles[yy * width + xx] = c;
           break;
         case TM_FG:
-          fg_tiles[yy][xx] = c;
+          fg_tiles[yy * width + xx] = c;
           break;
         }
     }
@@ -824,7 +677,7 @@ Level::gettileid(float x, float y) const
   xx = ((int)x / 32);
 
   if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
-    c = ia_tiles[yy][xx];
+    c = ia_tiles[yy * width + xx];
   else
     c = 0;
 
@@ -834,10 +687,10 @@ Level::gettileid(float x, float y) const
 unsigned int
 Level::get_tile_at(int x, int y) const
 {
-  if(x < 0 || x > width || y < 0 || y > height)
+  if(x < 0 || x >= width || y < 0 || y >= height)
     return 0;
   
-  return ia_tiles[y][x];
+  return ia_tiles[y * width + x];
 }
 
 /* EOF */
index 8e70354..ed27b8e 100644 (file)
@@ -29,6 +29,7 @@
 #include "gameobjs.h"
 
 class Tile;
+class World;
 
 /** This type holds meta-information about a level-subset. 
     It could be extended to handle manipulation of subsets. */
@@ -79,9 +80,9 @@ class Level
   std::string song_title;
   std::string bkgd_image;
   std::string particle_system;
-  std::vector<std::vector<unsigned int> > bg_tiles; /* Tiles in the background */
-  std::vector<std::vector<unsigned int> > ia_tiles; /* Tiles which can interact in the game (solids for example)*/
-  std::vector<std::vector<unsigned int> > fg_tiles; /* Tiles in the foreground */
+  std::vector<unsigned int> bg_tiles; /* Tiles in the background */
+  std::vector<unsigned int> ia_tiles; /* Tiles which can interact in the game (solids for example)*/
+  std::vector<unsigned int> fg_tiles; /* Tiles in the foreground */
 //  std::vector<unsigned int> bg_tiles[15]; /* Tiles in the background */
 //  std::vector<unsigned int> ia_tiles[15]; /* Tiles which can interact in the game (solids for example)*/
 //  std::vector<unsigned int> fg_tiles[15]; /* Tiles in the foreground */
@@ -97,15 +98,14 @@ class Level
   bool back_scrolling;
   float hor_autoscroll_speed;
 
-  std::vector<BadGuyData> badguy_data;
   std::vector< ObjectData<TrampolineData> > trampoline_data;
 
   /** A collection of points to which Tux can be reset after a lost live */
   std::vector<ResetPoint> reset_points;
  public:
   Level();
-  Level(const std::string& subset, int level);
-  Level(const std::string& filename);
+  Level(const std::string& subset, int level, World* world);
+  Level(const std::string& filename, World* world);
   ~Level();
 
   /** Will the Level structure with default values */
@@ -115,12 +115,16 @@ class Level
   void cleanup();
 
   /** Load data for this level: 
-      Returns -1, if the loading of the level failed. */
-  int  load(const std::string& subset, int 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. */
-  int  load(const std::string& filename);
+      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_gfx();
   
@@ -129,14 +133,14 @@ class Level
   MusicRef get_level_music();
   MusicRef get_level_music_fast();
 
-  void save(const std::string& subset, int level);
+  // 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 change_width (int new_width);
-  void change_height (int new_height);
+  void resize(int new_width, int new_height);
 
   /* Draw background */
   void draw_bg();
index 47a39ab..1c7f3e3 100644 (file)
@@ -42,6 +42,7 @@
 #include "tile.h"
 #include "resources.h"
 #include "music_manager.h"
+#include "display_manager.h"
 
 /* definitions to aid development */
 
@@ -153,7 +154,7 @@ static ButtonPanelMap objects_map;
 static std::string cur_tilegroup;
 static std::string cur_objects;
 static MouseCursor* mouse_select_object;
-static GameObject* selected_game_object;
+static MovingObject* selected_game_object;
 
 static square selection;
 static SelectionMode le_selection_mode;
@@ -499,15 +500,23 @@ void le_init_menus()
   select_objects_menu->arrange_left = true;
   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
   select_objects_menu->additem(MN_HL,"",0,0);
+  // TODO fix this
+#if 0
   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
 
+  DisplayManager dummy;
   for(int i = 0; i < NUM_BadGuyKinds; ++i)
   {
-    BadGuy bad_tmp(0,0,BadGuyKind(i),false);
+    BadGuy bad_tmp(dummy, 0,0,BadGuyKind(i),false);
     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
-    objects_map["BadGuys"]->manipulate_button(i)->set_game_object(new BadGuy(objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,objects_map["BadGuys"]->manipulate_button(i)->get_pos().y,BadGuyKind(i),false));
+    objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
+        BadGuy(dummy,
+          objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
+          objects_map["BadGuys"]->manipulate_button(i)->get_pos().y,
+          BadGuyKind(i), false));
   }
+#endif
 
   select_objects_menu->additem(MN_HL,"",0,0);
 
@@ -665,8 +674,9 @@ void apply_level_settings_menu()
 
   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
 
-  le_world->get_level()->change_width(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
-  le_world->get_level()->change_height(atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
+  le_world->get_level()->resize(
+      atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input),
+      atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
@@ -696,7 +706,8 @@ void le_unload_level()
     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
     if(confirm_dialog(str))
     {
-      le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
+      le_world->get_level()->save(le_level_subset->name.c_str(), le_level,
+          le_world);
     }
   }
 
@@ -782,15 +793,19 @@ void le_drawminimap()
   else
     mini_tile_height = 1;
 
+  Level* level = le_world->get_level();
   for (int y = 0; y < le_world->get_level()->height; ++y)
     for (int x = 0; x < le_world->get_level()->width; ++x)
     {
 
-      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
+      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
+          mini_tile_width , 4, level->bg_tiles[y * level->width + x]);
 
-      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
+      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
+          mini_tile_width , 4, level->ia_tiles[y * level->width + x]);
 
-      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
+      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
+          mini_tile_width , 4, level->fg_tiles[y + level->width + x]);
 
     }
 
@@ -942,6 +957,7 @@ void le_drawlevel()
 
   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
 
+  Level* level = le_world->get_level();
   for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_world->get_level()->height; ++y)
     for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
     {
@@ -951,47 +967,59 @@ void le_drawlevel()
       else
         a = 128;
 
-      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->bg_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
+      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
+          level->bg_tiles[ (y + (int)(pos_y / 32)) * level->width + 
+          (x + (int)(pos_x / 32))],a);
 
       if(active_tm == TM_IA)
         a = 255;
       else
         a = 128;
 
-      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
+      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
+          level->ia_tiles[ (y + (int)(pos_y / 32)) * level->width +       
+          (x + (int)(pos_x / 32))],a);
 
+      
       if(active_tm == TM_FG)
         a = 255;
       else
         a = 128;
 
-      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->fg_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
+      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
+          level->fg_tiles[ (y + (int)(pos_y / 32)) * level->width +       
+          (x + (int)(pos_x / 32))],a);
 
       /* draw whats inside stuff when cursor is selecting those */
       /* (draw them all the time - is this the right behaviour?) */
-      Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)]);
+      Tile* edit_image = TileManager::instance()->get(
+          level->ia_tiles
+          [ (y + (int)(pos_y / 32)) * level->width + (x + (int)(pos_x / 32))]);
       if(edit_image && !edit_image->editor_images.empty())
         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
 
     }
 
   /* Draw the Bad guys: */
-  for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
+  for (std::vector<_GameObject*>::iterator it = le_world->gameobjects.begin();
+       it != le_world->gameobjects.end(); ++it)
   {
+    BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
+    if(badguy == 0)
+      continue;
+    
     /* to support frames: img_bsod_left[(frame / 5) % 4] */
-
-    scroll_x = pos_x;
-    scroll_y = pos_y;
-    (*it)->draw();
+    ViewPort viewport;
+    viewport.set_translation(Vector(pos_x, pos_y));
+    badguy->draw(viewport, 0);
   }
 
-
   /* Draw the player: */
   /* for now, the position is fixed at (100, 240) */
   largetux.walk_right->draw( 100 - pos_x, 240 - pos_y);
 }
 
-void le_change_object_properties(GameObject *pobj)
+void le_change_object_properties(_GameObject *pobj)
 {
   Surface* cap_screen = Surface::CaptureScreen();
   Menu* object_properties_menu = new Menu();
@@ -1000,13 +1028,14 @@ void le_change_object_properties(GameObject *pobj)
   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
   object_properties_menu->additem(MN_HL,"",0,0);
 
-  if(pobj->type() == "BadGuy")
+  BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
+  if(pobj != 0)
   {
-    BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
     object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
     for(int i = 0; i < NUM_BadGuyKinds; ++i)
     {
-      string_list_add_item(object_properties_menu->get_item_by_id(1).list,badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
+      string_list_add_item(object_properties_menu->get_item_by_id(1).list,
+          badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
       if(pbad->kind == i)
         object_properties_menu->get_item_by_id(1).list->active_item = i;
     }
@@ -1035,23 +1064,16 @@ void le_change_object_properties(GameObject *pobj)
     switch (object_properties_menu->check())
     {
     case 3:
-      if(pobj->type() == "BadGuy")
       {
+      BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
+      if(pbad != 0) {
         BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
         pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
         pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
-       int i = 0;
-       std::list<BadGuy*>::iterator it;
-        for(it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
-          if((*it) == pbad)
-            break;
-        le_world->get_level()->badguy_data[i].kind = pbad->kind;
-       le_world->get_level()->badguy_data[i].stay_on_platform = pbad->stay_on_platform;
-       delete (*it);
-       (*it) = new BadGuy(le_world->get_level()->badguy_data[i].x,le_world->get_level()->badguy_data[i].y,le_world->get_level()->badguy_data[i].kind,le_world->get_level()->badguy_data[i].stay_on_platform);
       }
       loop = false;
       break;
+      }
     default:
       break;
     }
@@ -1210,7 +1232,8 @@ void le_checkevents()
             le_testlevel();
           le_save_level_bt->event(event);
           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
-            le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
+            le_world->get_level()->save(le_level_subset->name.c_str(),le_level,
+                le_world);
           le_exit_bt->event(event);
           if(le_exit_bt->get_state() == BUTTON_CLICKED)
           {
@@ -1231,7 +1254,7 @@ void le_checkevents()
               if(confirm_dialog(str))
               {
                 new_lev.init_defaults();
-                new_lev.save(le_level_subset->name.c_str(),le_level+1);
+                new_lev.save(le_level_subset->name.c_str(),le_level+1, le_world);
                 le_level_subset->levels = le_level;
                 le_goto_level(le_level);
               }
@@ -1388,7 +1411,9 @@ void le_checkevents()
             {
               if(pbutton->get_state() == BUTTON_CLICKED)
               {
-                le_current.Object(pbutton->get_game_object());
+#if 0   // TODO fixme!!
+                le_current.Object(pbutton->get_drawable());
+#endif
               }
             }
           }
@@ -1435,7 +1460,6 @@ void le_checkevents()
         {
           if(MouseCursor::current() == mouse_select_object)
           {
-            int i = 0;
             bool object_got_hit = false;
             base_type cursor_base;
            if(le_current.IsTile())
@@ -1451,13 +1475,20 @@ void le_checkevents()
             cursor_base.width = 32;
             cursor_base.height = 32;
 
-            for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
-              if(rectcollision(cursor_base,(*it)->base))
+            for(std::vector<_GameObject*>::iterator it =
+                le_world->gameobjects.begin();
+                it != le_world->gameobjects.end(); ++it) {
+              MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
+              if(!mobj)
+                continue;
+
+              if(rectcollision(cursor_base, mobj->base))
               {
-                selected_game_object = (*it);
+                selected_game_object = mobj;
                 object_got_hit = true;
                 break;
               }
+            }
 
             if(!object_got_hit)
             {
@@ -1472,6 +1503,7 @@ void le_checkevents()
           }
           else
           {
+#if 0 // FIXME TODO
             if(le_current.IsObject())
             {
               le_level_changed  = true;
@@ -1484,6 +1516,7 @@ void le_checkevents()
                 le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
               }
             }
+#endif
           }
          
           le_mouse_clicked[LEFT] = false;
@@ -1622,7 +1655,6 @@ void le_change(float x, float y, int tm, unsigned int c)
   {
     int xx,yy;
     int x1, x2, y1, y2;
-    unsigned int i = 0;
 
     le_level_changed = true;
 
@@ -1638,6 +1670,8 @@ void le_change(float x, float y, int tm, unsigned int c)
       cursor_base.height = 32;
 
       /* if there is a bad guy over there, remove it */
+      // XXX TODO
+#if 0
       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
         if(rectcollision(cursor_base,(*it)->base))
         {
@@ -1646,6 +1680,7 @@ void le_change(float x, float y, int tm, unsigned int c)
           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
           break;
         }
+#endif
 
       break;
     case SQUARE:
@@ -1676,6 +1711,8 @@ void le_change(float x, float y, int tm, unsigned int c)
       y2 /= 32;
 
       /* if there is a bad guy over there, remove it */
+      // TODO FIXME
+#if 0
       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
           it != le_world->bad_guys.end(); /* will be at end of loop */)
       {
@@ -1693,6 +1730,7 @@ void le_change(float x, float y, int tm, unsigned int c)
           ++it;
         }
       }
+#endif
 
       for(xx = x1; xx <= x2; xx++)
         for(yy = y1; yy <= y2; yy++)
@@ -1713,7 +1751,7 @@ void le_testlevel()
   if(le_world->get_level()->time_left == 0)
     le_world->get_level()->time_left = 250;
 
-  le_world->get_level()->save("test", le_level);
+  le_world->get_level()->save("test", le_level, le_world);
 
   GameSession session("test",le_level, ST_GL_TEST);
   session.run();
index 4eb9242..3edb5ca 100644 (file)
@@ -1116,6 +1116,26 @@ LispReader::read_string_vector (const char* name, std::vector<std::string>* vec)
 bool
 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;    
+}
+
+bool
+LispReader::read_int_vector (const char* name, std::vector<unsigned int>* vec)
+{
+  vec->clear();
   lisp_object_t* obj = search_for (name);
   if (obj)
     {
@@ -1175,86 +1195,6 @@ LispReader::read_bool (const char* name, bool* b)
   return false;
 }
 
-LispWriter::LispWriter (const char* name)
-{
-  lisp_objs.push_back(lisp_make_symbol (name));
-}
-
-void
-LispWriter::append (lisp_object_t* obj)
-{
-  lisp_objs.push_back(obj);
-}
-
-lisp_object_t*
-LispWriter::make_list3 (lisp_object_t* a, lisp_object_t* b, lisp_object_t* c)
-{
-  return lisp_make_cons (a, lisp_make_cons(b, lisp_make_cons(c, lisp_nil())));
-}
-
-lisp_object_t*
-LispWriter::make_list2 (lisp_object_t* a, lisp_object_t* b)
-{
-  return lisp_make_cons (a, lisp_make_cons(b, lisp_nil()));
-}
-
-void
-LispWriter::write_float (const char* name, float f)
-{
-  append(make_list2 (lisp_make_symbol (name),
-                     lisp_make_real(f)));
-}
-
-void
-LispWriter::write_int (const char* name, int i)
-{
-  append(make_list2 (lisp_make_symbol (name),
-                     lisp_make_integer(i)));
-}
-
-void
-LispWriter::write_string (const char* name, const char* str)
-{
-  append(make_list2 (lisp_make_symbol (name),
-                     lisp_make_string(str)));
-}
-
-void
-LispWriter::write_symbol (const char* name, const char* symname)
-{
-  append(make_list2 (lisp_make_symbol (name),
-                     lisp_make_symbol(symname)));
-}
-
-void
-LispWriter::write_lisp_obj(const char* name, lisp_object_t* lst)
-{
-  append(make_list2 (lisp_make_symbol (name),
-                     lst));
-}
-
-void
-LispWriter::write_boolean (const char* name, bool b)
-{
-  append(make_list2 (lisp_make_symbol (name),
-                     lisp_make_boolean(b)));
-}
-
-lisp_object_t*
-LispWriter::create_lisp ()
-{
-  lisp_object_t* lisp_obj = lisp_nil();
-
-  for(std::vector<lisp_object_t*>::reverse_iterator i = lisp_objs.rbegin ();
-      i != lisp_objs.rend (); ++i)
-    {
-      lisp_obj = lisp_make_cons (*i, lisp_obj);
-    }
-  lisp_objs.clear();
-
-  return lisp_obj;
-}
-
 #if 0
 void mygzungetc(char c, void* file)
 {
index f319afc..bde266c 100644 (file)
@@ -180,6 +180,7 @@ class LispReader
     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);
@@ -189,26 +190,4 @@ class LispReader
     bool read_lisp (const char* name, lisp_object_t** b);
   };
 
-/** */
-class LispWriter
-  {
-  private:
-    std::vector<lisp_object_t*> lisp_objs;
-
-    void append (lisp_object_t* obj);
-    lisp_object_t* make_list3 (lisp_object_t*, lisp_object_t*, lisp_object_t*);
-    lisp_object_t* make_list2 (lisp_object_t*, lisp_object_t*);
-  public:
-    LispWriter (const char* name);
-    void write_float (const char* name, float f);
-    void write_int (const char* name, int i);
-    void write_boolean (const char* name, bool b);
-    void write_string (const char* name, const char* str);
-    void write_symbol (const char* name, const char* symname);
-    void write_lisp_obj(const char* name, lisp_object_t* lst);
-
-    /** caller is responible to free the returned lisp_object_t */
-    lisp_object_t* create_lisp ();
-  };
-
 #endif
index d80daf2..d1e5b4a 100644 (file)
@@ -141,7 +141,6 @@ public:
   Player(DisplayManager& display_manager);
   virtual ~Player();
   
-  void init();
   int  key_event(SDLKey key, int state);
   void level_begin();
   void handle_input();
@@ -165,6 +164,8 @@ public:
   void grow();
   
 private:
+  void init();
+  
   void handle_horizontal_input();
   void handle_vertical_input();
   void remove_powerups();
index 67b3f4d..a00bce4 100644 (file)
@@ -26,7 +26,7 @@ TileMap::action(float )
 void
 TileMap::draw(ViewPort& viewport, int layer)
 {
-  std::vector<std::vector<unsigned int> >* tiles;
+  std::vector<unsigned int>* tiles;
   switch(layer) {
     case LAYER_BACKGROUNDTILES:
       tiles = &level->bg_tiles; break;
@@ -42,11 +42,11 @@ TileMap::draw(ViewPort& viewport, int layer)
   int tsy = int(viewport.get_translation().y / 32); // tilestartindex y
   int sx = - (int(viewport.get_translation().x) % 32);
   int sy = - (int(viewport.get_translation().y) % 32);
-  for(int x = sx, tx = tsx; x < screen->w && tx < int((*tiles)[0].size());
+  for(int x = sx, tx = tsx; x < screen->w && tx < level->width;
       x += 32, ++tx) {
-    for(int y = sy, ty = tsy; y < screen->h && ty < int(tiles->size());
+    for(int y = sy, ty = tsy; y < screen->h && ty < level->height;
           y += 32, ++ty) {
-      Tile::draw(x, y, (*tiles) [ty][tx]);
+      Tile::draw(x, y, (*tiles) [ty * level->width + tx]);
     }
   }
 }
index 3b14759..9639caf 100644 (file)
@@ -126,7 +126,7 @@ void check_contrib_menu()
               for (int i = 1; i <= subset.levels; ++i)
                 {
                   Level level;
-                  level.load(subset.name, i);
+                  level.load(subset.name, i, 0);
                   contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i);
                 }
               contrib_subset_menu->additem(MN_HL,"",0,0);      
index 257b71b..f3a9142 100644 (file)
@@ -48,7 +48,8 @@ World::World(const std::string& filename)
   // world calls child functions
   current_ = this;
 
-  level = new Level(filename);
+  level = new Level();
+  level->load(filename, this);
 
   tux = new Player(displaymanager);
   gameobjects.push_back(tux);
@@ -56,7 +57,6 @@ World::World(const std::string& filename)
   set_defaults();
 
   get_level()->load_gfx();
-  activate_bad_guys();
   // add background
   activate_particle_systems();
   Background* bg = new Background(displaymanager);
@@ -83,13 +83,15 @@ World::World(const std::string& subset, int level_nr)
   // world calls child functions
   current_ = this;
 
-  level = new Level(subset, level_nr);
-  tux->init();
+  level = new Level();
+  level->load(subset, level_nr, this);
+
+  tux = new Player(displaymanager);
+  gameobjects.push_back(tux);        
 
   set_defaults();
 
   get_level()->load_gfx();
-  activate_bad_guys();
   activate_objects();
   activate_particle_systems();
   Background* bg = new Background(displaymanager);
@@ -111,32 +113,24 @@ World::World(const std::string& subset, int level_nr)
 void
 World::apply_bonuses()
 {
-#if 0
   // Apply bonuses from former levels
   switch (player_status.bonus)
     {
     case PlayerStatus::NO_BONUS:
       break;
-
+                                                                                
     case PlayerStatus::FLOWER_BONUS:
-      tux->got_power = tux.FIRE_POWER;  // FIXME: add ice power to here
+      tux->got_power = Player::FIRE_POWER;  // FIXME: add ice power to here
       // fall through
-
+                                                                                
     case PlayerStatus::GROWUP_BONUS:
-      // FIXME: Move this to Player class
-      tux->size = BIG;
-      tux->base.height = 64;
-      tux->base.y -= 32;
+      tux->grow();
       break;
     }
-#endif
 }
 
 World::~World()
 {
-  for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
-    delete *i;
-
   for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
     delete *i;
 
@@ -147,6 +141,7 @@ World::~World()
       displaymanager.remove_drawable(drawable);
     delete *i;
   }
+  bad_guys.clear();
 
   delete level;
 }
@@ -167,14 +162,36 @@ World::set_defaults()
 }
 
 void
-World::activate_bad_guys()
+World::add_object(_GameObject* object)
 {
-  for (std::vector<BadGuyData>::iterator i = level->badguy_data.begin();
-       i != level->badguy_data.end();
-       ++i)
+  // XXX hack for now until new collision code is ready
+  BadGuy* badguy = dynamic_cast<BadGuy*> (object);
+  if(badguy)
+    bad_guys.push_back(badguy);
+
+  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 = "";
+    
+    LispReader reader(lisp_cdr(data));
+    reader.read_string("type", &object_type);
+
+    if(object_type == "badguy" || object_type == "")
     {
-      add_bad_guy(i->x, i->y, i->kind, i->stay_on_platform);
+      BadGuyKind kind = badguykind_from_string(
+          lisp_symbol(lisp_car(data)));
+      add_object(new BadGuy(displaymanager, kind, reader));
     }
+    // TODO add parsing code for trampolines
+
+    cur = lisp_cdr(cur);
+  } 
 }
 
 void
@@ -193,11 +210,11 @@ World::activate_particle_systems()
 {
   if (level->particle_system == "clouds")
     {
-      gameobjects.push_back(new CloudParticleSystem(displaymanager));
+      add_object(new CloudParticleSystem(displaymanager));
     }
   else if (level->particle_system == "snow")
     {
-      gameobjects.push_back(new SnowParticleSystem(displaymanager));
+      add_object(new SnowParticleSystem(displaymanager));
     }
   else if (level->particle_system != "")
     {
@@ -212,9 +229,6 @@ World::draw()
   displaymanager.get_viewport().set_translation(Vector(scroll_x, scroll_y));
   displaymanager.draw();
   
-  for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
-    (*i)->draw();
-
   for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
     (*i)->draw();
 
@@ -237,9 +251,6 @@ World::action(double frame_ratio)
   for (unsigned int i = 0; i < upgrades.size(); i++)
     upgrades[i].action(frame_ratio);
 
-  for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
-    (*i)->action(frame_ratio);
-
   for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
      (*i)->action(frame_ratio);
 
@@ -251,24 +262,18 @@ World::action(double frame_ratio)
 
   /* Handle all possible collisions. */
   collision_handler();
-  
-  // Cleanup marked badguys
-  for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end();
-      /* ++i handled at end of the loop */) {
-    if ((*i)->is_removable()) {
-      delete *i;
-      i =  bad_guys.erase(i);
-    } else {
-      ++i;
-    }
-  }
-
+  /** cleanup marked objects */
   for(std::vector<_GameObject*>::iterator i = gameobjects.begin();
       i != gameobjects.end(); /* nothing */) {
     if((*i)->is_valid() == false) {
       Drawable* drawable = dynamic_cast<Drawable*> (*i);
       if(drawable)
         displaymanager.remove_drawable(drawable);
+      BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
+      if(badguy) {
+        std::remove(bad_guys.begin(), bad_guys.end(), badguy);
+      } 
       
       delete *i;
       i = gameobjects.erase(i);
@@ -497,13 +502,13 @@ World::add_score(const Vector& pos, int s)
 {
   player_status.score += s;
 
-  gameobjects.push_back(new FloatingScore(displaymanager, pos, s));
+  add_object(new FloatingScore(displaymanager, pos, s));
 }
 
 void
 World::add_bouncy_distro(const Vector& pos)
 {
-  gameobjects.push_back(new BouncyDistro(displaymanager, pos));
+  add_object(new BouncyDistro(displaymanager, pos));
 }
 
 void
@@ -520,20 +525,20 @@ void
 World::add_broken_brick_piece(const Vector& pos, const Vector& movement,
     Tile* tile)
 {
-  gameobjects.push_back(new BrokenBrick(displaymanager, tile, pos, movement));
+  add_object(new BrokenBrick(displaymanager, tile, pos, movement));
 }
 
 void
 World::add_bouncy_brick(const Vector& pos)
 {
-  gameobjects.push_back(new BouncyBrick(displaymanager, pos));
+  add_object(new BouncyBrick(displaymanager, pos));
 }
 
 BadGuy*
-World::add_bad_guy(float x, float y, BadGuyKind kind, bool stay_on_platform)
+World::add_bad_guy(float x, float y, BadGuyKind kind)
 {
-  BadGuy* badguy = new BadGuy(x,y,kind, stay_on_platform);
-  bad_guys.push_back(badguy);
+  BadGuy* badguy = new BadGuy(displaymanager, kind, x, y);
+  add_object(badguy);
   return badguy;
 }
 
index 0f82244..e68ed41 100644 (file)
@@ -68,12 +68,14 @@ public:
 
   World(const std::string& filename);
   World(const std::string& subset, int level_nr);
-  World() {};
+  //World() {};
   ~World();
   
   Level*  get_level() { return level; }
   Player* get_tux() { return tux; }
 
+  void add_object(_GameObject* object);
+
   void set_defaults();
 
   void draw();
@@ -82,15 +84,15 @@ public:
 
   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 activate_bad_guys();
   void activate_objects();
 
   void add_score(const Vector& pos, int s);
@@ -100,7 +102,7 @@ public:
       const Vector& movement, Tile* tile);
   void add_bouncy_brick(const Vector& pos);
 
-  BadGuy* add_bad_guy(float x, float y, BadGuyKind kind, bool stay_on_platform = false);
+  BadGuy* add_bad_guy(float x, float y, BadGuyKind kind);
   template <class T, class U> T* add_object(U data);
 
   void add_upgrade(float x, float y, Direction dir, UpgradeKind kind);