Instead of setting the level to be flipped from the level file, it is now passed...
[supertux.git] / src / sector.cpp
index 0976bb8..4972ecc 100644 (file)
 //  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 "sector.h"
 
 #include <memory>
+#include <algorithm>
 #include <stdexcept>
 #include <iostream>
 #include <fstream>
 #include <stdexcept>
-#include "lispreader.h"
 
+#include "globals.h"
+#include "sector.h"
+#include "lispreader.h"
 #include "badguy.h"
 #include "special.h"
 #include "gameobjs.h"
@@ -33,7 +35,7 @@
 #include "particlesystem.h"
 #include "tile.h"
 #include "tilemap.h"
-#include "music_manager.h"
+#include "sound_manager.h"
 #include "gameloop.h"
 #include "resources.h"
 #include "interactive_object.h"
@@ -72,13 +74,14 @@ Sector::parse(LispReader& lispreader)
   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)));
+    // FIXME: doesn't handle empty data
     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);
+      gravity = lisp_real(data);
     } else if(token == "music") {
       song_title = lisp_string(data);
       load_music();
@@ -262,7 +265,20 @@ Sector::write(LispWriter& writer)
 {
   writer.write_string("name", name);
   writer.write_float("gravity", gravity);
+  writer.write_string("music", song_title);
 
+  // write spawnpoints
+  for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
+      ++i) {
+    SpawnPoint* spawn = *i;
+    writer.start_list("playerspawn");
+    writer.write_string("name", spawn->name);
+    writer.write_float("x", spawn->pos.x);
+    writer.write_float("y", spawn->pos.y);
+    writer.end_list("playerspawn");
+  }
+
+  // write objects
   for(GameObjects::iterator i = gameobjects.begin();
       i != gameobjects.end(); ++i) {
     Serializable* serializable = dynamic_cast<Serializable*> (*i);
@@ -272,30 +288,41 @@ Sector::write(LispWriter& writer)
 }
 
 void
+Sector::do_vertical_flip()
+{
+  for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i)
+    {
+    TileMap* tilemap = dynamic_cast<TileMap*> (*i);
+    if(tilemap)
+      {
+      tilemap->do_vertical_flip();
+      }
+
+    BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
+    if(badguy)
+      badguy->start_position.y = solids->get_height()*32 - badguy->start_position.y - 32;
+    Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
+    if(trampoline)
+      trampoline->base.y = solids->get_height()*32 - trampoline->base.y - 32;
+    FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
+    if(flying_platform)
+      flying_platform->base.y = solids->get_height()*32 - flying_platform->base.y - 32;
+    Door* door = dynamic_cast<Door*> (*i);
+    if(door)
+      door->set_area(door->get_area().x, solids->get_height()*32 - door->get_area().y - 32);
+    }
+
+  for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
+      ++i) {
+    SpawnPoint* spawn = *i;
+    spawn->pos.y = solids->get_height()*32 - spawn->pos.y - 32;
+  }
+}
+
+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);
-  InteractiveObject* interactive_object 
-      = dynamic_cast<InteractiveObject*> (object);
-  if(interactive_object)
-    interactive_objects.push_back(interactive_object);
-
-  gameobjects.push_back(object);
+  gameobjects_new.push_back(object);
 }
 
 void
@@ -350,6 +377,12 @@ Sector::action(float elapsed_time)
   /* Handle all possible collisions. */
   collision_handler();
                                                                                 
+  update_game_objects();
+}
+
+void
+Sector::update_game_objects()
+{
   /** cleanup marked objects */
   for(std::vector<GameObject*>::iterator i = gameobjects.begin();
       i != gameobjects.end(); /* nothing */) {
@@ -397,6 +430,34 @@ Sector::action(float elapsed_time)
       ++i;
     }
   }
+
+  /* add newly created objects */
+  for(std::vector<GameObject*>::iterator i = gameobjects_new.begin();
+      i != gameobjects_new.end(); ++i)
+  {
+          BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
+          if(badguy)
+            badguys.push_back(badguy);
+          Bullet* bullet = dynamic_cast<Bullet*> (*i);
+          if(bullet)
+            bullets.push_back(bullet);
+          Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
+          if(upgrade)
+            upgrades.push_back(upgrade);
+          Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
+          if(trampoline)
+            trampolines.push_back(trampoline);
+          FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
+          if(flying_platform)
+            flying_platforms.push_back(flying_platform);
+          InteractiveObject* interactive_object 
+              = dynamic_cast<InteractiveObject*> (*i);
+          if(interactive_object)
+            interactive_objects.push_back(interactive_object);
+
+          gameobjects.push_back(*i);
+  }
+  gameobjects_new.clear();
 }
 
 void
@@ -608,7 +669,7 @@ Sector::add_bullet(const Vector& pos, float xm, Direction dir)
     throw std::runtime_error("wrong bullet type.");
   add_object(new_bullet);
                                                                                 
-  play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER);
+  sound_manager->play_sound(sounds[SND_SHOOT]);
                                                                                 
   return true;
 }
@@ -618,6 +679,13 @@ bool
 Sector::trybreakbrick(const Vector& pos, bool small)
 {
   Tile* tile = solids->get_tile_at(pos);
+  if (!tile)
+  {
+    char errmsg[64];
+    sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
+    throw SuperTuxException(errmsg, __FILE__, __LINE__);
+  }
+
   if (tile->attributes & Tile::BRICK)
     {
       if (tile->data > 0)
@@ -643,7 +711,7 @@ Sector::trybreakbrick(const Vector& pos, bool small)
               solids->change_at(pos, tile->next_tile);
             }
                                                                                 
-          play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+          sound_manager->play_sound(sounds[SND_DISTRO]);
           player_status.score = player_status.score + SCORE_DISTRO;
           player_status.distros++;
           return true;
@@ -659,7 +727,7 @@ Sector::trybreakbrick(const Vector& pos, bool small)
                                  (int)(pos.y / 32) * 32), tile);
                                                                                 
           /* Get some score: */
-          play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
+          sound_manager->play_sound(sounds[SND_BRICK]);
           player_status.score = player_status.score + SCORE_BRICK;
                                                                                 
           return true;
@@ -674,6 +742,14 @@ void
 Sector::tryemptybox(const Vector& pos, Direction col_side)
 {
   Tile* tile = solids->get_tile_at(pos);
+  if (!tile)
+  {
+    char errmsg[64];
+    sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
+    throw SuperTuxException(errmsg, __FILE__, __LINE__);
+  }
+
+
   if (!(tile->attributes & Tile::FULLBOX))
     return;
                                                                                 
@@ -689,7 +765,7 @@ Sector::tryemptybox(const Vector& pos, Direction col_side)
     {
     case 1: // Box with a distro!
       add_bouncy_distro(Vector(posx, posy));
-      play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+      sound_manager->play_sound(sounds[SND_DISTRO]);
       player_status.score = player_status.score + SCORE_DISTRO;
       player_status.distros++;
       break;
@@ -699,7 +775,7 @@ Sector::tryemptybox(const Vector& pos, Direction col_side)
         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);
+      sound_manager->play_sound(sounds[SND_UPGRADE]);
       break;
                                                                                 
     case 5: // Add an ice flower upgrade!
@@ -707,7 +783,7 @@ Sector::tryemptybox(const Vector& pos, Direction col_side)
         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);
+      sound_manager->play_sound(sounds[SND_UPGRADE]);
       break;
                                                                                 
     case 3: // Add a golden herring
@@ -730,11 +806,24 @@ void
 Sector::trygrabdistro(const Vector& pos, int bounciness)
 {
   Tile* tile = solids->get_tile_at(pos);
+  if (!tile)
+  {
+    /*char errmsg[64];
+    sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
+    throw SuperTuxException(errmsg, __FILE__, __LINE__); */
+    
+    //Bad tiles (i.e. tiles that are not defined in supertux.stgt but appear in the map) are changed to ID 0 (blank tile)
+    std::cout << "Warning: Undefined tile at " <<(int)pos.x/32 << "/" << (int)pos.y/32 << " (ID: " << (int)solids->get_tile_id_at(pos).id << ")" << std::endl;
+    solids->change_at(pos,0);
+    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);
+  sound_manager->play_sound(sounds[SND_DISTRO]);
                                                                             
   if (bounciness == BOUNCE)
     {
@@ -744,6 +833,7 @@ Sector::trygrabdistro(const Vector& pos, int bounciness)
                                                                             
   player_status.score = player_status.score + SCORE_DISTRO;
   player_status.distros++;
+
 }
                                                                                 
 /* Try to bump a bad guy from below: */
@@ -778,7 +868,7 @@ Sector::load_music()
   char* song_path;
   char* song_subtitle;
                                                                                 
-  level_song = music_manager->load_music(datadir + "/music/" + song_title);
+  level_song = sound_manager->load_music(datadir + "/music/" + song_title);
                                                                                 
   song_path = (char *) malloc(sizeof(char) * datadir.length() +
                               strlen(song_title.c_str()) + 8 + 5);
@@ -786,10 +876,10 @@ Sector::load_music()
   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)) {
+  if(!sound_manager->exists_music(song_path)) {
     level_song_fast = level_song;
   } else {
-    level_song_fast = music_manager->load_music(song_path);
+    level_song_fast = sound_manager->load_music(song_path);
   }
   free(song_subtitle);
   free(song_path);
@@ -801,16 +891,16 @@ Sector::play_music(int type)
   currentmusic = type;
   switch(currentmusic) {
     case HURRYUP_MUSIC:
-      music_manager->play_music(level_song_fast);
+      sound_manager->play_music(level_song_fast);
       break;
     case LEVEL_MUSIC:
-      music_manager->play_music(level_song);
+      sound_manager->play_music(level_song);
       break;
     case HERRING_MUSIC:
-      music_manager->play_music(herring_song);
+      sound_manager->play_music(herring_song);
       break;
     default:
-      music_manager->halt_music();
+      sound_manager->halt_music();
       break;
   }
 }