New grow and skid sounds from remaxim
[supertux.git] / src / sector.cpp
index 57418fd..6b51f5b 100644 (file)
 #include "lisp/writer.hpp"
 #include "lisp/list_iterator.hpp"
 #include "tile.hpp"
+#include "file_system.hpp"
+#include "physfs/physfs_stream.hpp"
 #include "audio/sound_manager.hpp"
 #include "game_session.hpp"
+#include "constants.hpp"
 #include "resources.hpp"
 #include "statistics.hpp"
 #include "object_factory.hpp"
@@ -61,6 +64,7 @@
 #include "object/bullet.hpp"
 #include "object/text_object.hpp"
 #include "object/portable.hpp"
+#include "object/display_effect.hpp"
 #include "badguy/jumpy.hpp"
 #include "trigger/sequence_trigger.hpp"
 #include "player_status.hpp"
@@ -68,6 +72,7 @@
 #include "script_interface.hpp"
 #include "log.hpp"
 #include "main.hpp"
+#include "level.hpp"
 
 Sector* Sector::_current = 0;
 
@@ -76,12 +81,14 @@ bool Sector::draw_solids_only = false;
 
 Sector::Sector(Level* parent)
   : level(parent), currentmusic(LEVEL_MUSIC),
-  ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), gravity(10.0), player(0), camera(0)
+  ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), gravity(10.0), player(0), camera(0), effect(0)
 {
   add_object(new Player(player_status, "Tux"));
   add_object(new DisplayEffect("Effect"));
   add_object(new TextObject("Text"));
 
+  sound_manager->preload("sounds/shoot.wav");
+
   // create a new squirrel table for the sector
   using namespace Scripting;
 
@@ -194,7 +201,7 @@ Sector::parse(const lisp::Lisp& sector)
       iter.value()->get(init_script);
     } else if(token == "ambient-light") {
       std::vector<float> vColor;
-      sector.get_vector( "ambient-light", vColor );
+      sector.get( "ambient-light", vColor );
       if(vColor.size() < 3) {
         log_warning << "(ambient-light) requires a color as argument" << std::endl;
       } else {
@@ -311,16 +318,17 @@ Sector::parse_old_format(const lisp::Lisp& reader)
   reader.get("height", height);
 
   std::vector<unsigned int> tiles;
-  if(reader.get_vector("interactive-tm", tiles)
-      || reader.get_vector("tilemap", tiles)) {
-    TileMap* tilemap = new TileMap();
+  if(reader.get("interactive-tm", tiles)
+      || reader.get("tilemap", tiles)) {
+    TileMap* tilemap = new TileMap(level->get_tileset());
     tilemap->set(width, height, tiles, LAYER_TILES, true);
 
     // replace tile id 112 (old invisible tile) with 1311 (new invisible tile)
     for(size_t x=0; x < tilemap->get_width(); ++x) {
       for(size_t y=0; y < tilemap->get_height(); ++y) {
-        const Tile* tile = tilemap->get_tile(x, y);
-        if(tile->getID() == 112) tilemap->change(x, y, 1311);
+        uint32_t id = tilemap->get_tile_id(x, y);
+        if(id == 112)
+          tilemap->change(x, y, 1311);
       }
     }
 
@@ -328,15 +336,15 @@ Sector::parse_old_format(const lisp::Lisp& reader)
     add_object(tilemap);
   }
 
-  if(reader.get_vector("background-tm", tiles)) {
-    TileMap* tilemap = new TileMap();
+  if(reader.get("background-tm", tiles)) {
+    TileMap* tilemap = new TileMap(level->get_tileset());
     tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
     if (height < 19) tilemap->resize(width, 19);
     add_object(tilemap);
   }
 
-  if(reader.get_vector("foreground-tm", tiles)) {
-    TileMap* tilemap = new TileMap();
+  if(reader.get("foreground-tm", tiles)) {
+    TileMap* tilemap = new TileMap(level->get_tileset());
     tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
 
     // fill additional space in foreground with tiles of ID 2035 (lightmap/black)
@@ -398,26 +406,27 @@ Sector::fix_old_tiles()
     TileMap* solids = *i;
     for(size_t x=0; x < solids->get_width(); ++x) {
       for(size_t y=0; y < solids->get_height(); ++y) {
-       const Tile* tile = solids->get_tile(x, y);
-       Vector pos(solids->get_x_offset() + x*32, solids->get_y_offset() + y*32);
-
-       if(tile->getID() == 112) {
-         add_object(new InvisibleBlock(pos));
-         solids->change(x, y, 0);
-       } else if(tile->getAttributes() & Tile::COIN) {
-         add_object(new Coin(pos));
-         solids->change(x, y, 0);
-       } else if(tile->getAttributes() & Tile::FULLBOX) {
-         add_object(new BonusBlock(pos, tile->getData()));
-         solids->change(x, y, 0);
-       } else if(tile->getAttributes() & Tile::BRICK) {
-         add_object(new Brick(pos, tile->getData()));
-         solids->change(x, y, 0);
-       } else if(tile->getAttributes() & Tile::GOAL) {
-         std::string sequence = tile->getData() == 0 ? "endsequence" : "stoptux";
-         add_object(new SequenceTrigger(pos, sequence));
-         solids->change(x, y, 0);
-       }
+    uint32_t    id   = solids->get_tile_id(x, y);
+    const Tile *tile = solids->get_tile(x, y);
+    Vector pos(solids->get_x_offset() + x*32, solids->get_y_offset() + y*32);
+
+    if(id == 112) {
+      add_object(new InvisibleBlock(pos));
+      solids->change(x, y, 0);
+    } else if(tile->getAttributes() & Tile::COIN) {
+      add_object(new Coin(pos));
+      solids->change(x, y, 0);
+    } else if(tile->getAttributes() & Tile::FULLBOX) {
+      add_object(new BonusBlock(pos, tile->getData()));
+      solids->change(x, y, 0);
+    } else if(tile->getAttributes() & Tile::BRICK) {
+      add_object(new Brick(pos, tile->getData()));
+      solids->change(x, y, 0);
+    } else if(tile->getAttributes() & Tile::GOAL) {
+      std::string sequence = tile->getData() == 0 ? "endsequence" : "stoptux";
+      add_object(new SequenceTrigger(pos, sequence));
+      solids->change(x, y, 0);
+    }
       }
     }
   }
@@ -428,25 +437,25 @@ Sector::fix_old_tiles()
     if (!tm) continue;
     for(size_t x=0; x < tm->get_width(); ++x) {
       for(size_t y=0; y < tm->get_height(); ++y) {
-       const Tile* tile = tm->get_tile(x, y);
-       Vector pos(tm->get_x_offset() + x*32, tm->get_y_offset() + y*32);
-       Vector center(pos.x + 16, pos.y + 16);
-
-       // torch
-       if (tile->getID() == 1517) {
-         float pseudo_rnd = (float)((int)pos.x % 10) / 10;
-         add_object(new PulsingLight(center, 1.0f + pseudo_rnd, 0.9f, 1.0f, Color(1.0f, 1.0f, 0.6f, 1.0f)));
-       }
-       // lava or lavaflow
-       if ((tile->getID() == 173) || (tile->getID() == 1700) || (tile->getID() == 1705) || (tile->getID() == 1706)) {
-         // space lights a bit
-         if (((tm->get_tile(x-1, y)->getID() != tm->get_tile(x,y)->getID())
-             && (tm->get_tile(x, y-1)->getID() != tm->get_tile(x,y)->getID()))
-             || ((x % 3 == 0) && (y % 3 == 0))) {
-           float pseudo_rnd = (float)((int)pos.x % 10) / 10;
-           add_object(new PulsingLight(center, 1.0f + pseudo_rnd, 0.8f, 1.0f, Color(1.0f, 0.3f, 0.0f, 1.0f)));
-         }
-       }
+        uint32_t id = tm->get_tile_id(x, y);
+    Vector pos(tm->get_x_offset() + x*32, tm->get_y_offset() + y*32);
+    Vector center(pos.x + 16, pos.y + 16);
+
+    // torch
+    if (id == 1517) {
+      float pseudo_rnd = (float)((int)pos.x % 10) / 10;
+      add_object(new PulsingLight(center, 1.0f + pseudo_rnd, 0.9f, 1.0f, Color(1.0f, 1.0f, 0.6f, 1.0f)));
+    }
+    // lava or lavaflow
+    if ((id == 173) || (id == 1700) || (id == 1705) || (id == 1706)) {
+      // space lights a bit
+      if ((((tm->get_tile_id(x-1, y)) != tm->get_tile_id(x,y))
+          && (tm->get_tile_id(x, y-1) != tm->get_tile_id(x,y)))
+          || ((x % 3 == 0) && (y % 3 == 0))) {
+        float pseudo_rnd = (float)((int)pos.x % 10) / 10;
+        add_object(new PulsingLight(center, 1.0f + pseudo_rnd, 0.8f, 1.0f, Color(1.0f, 0.3f, 0.0f, 1.0f)));
+      }
+    }
 
       }
     }
@@ -458,18 +467,18 @@ Sector::fix_old_tiles()
 void
 Sector::write(lisp::Writer& writer)
 {
-  writer.write_string("name", name);
-  writer.write_float("gravity", gravity);
-  writer.write_string("music", music);
+  writer.write("name", name);
+  writer.write("gravity", gravity);
+  writer.write("music", music);
 
   // write spawnpoints
   for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
       ++i) {
     SpawnPoint* spawn = *i;
     writer.start_list("spawn-points");
-    writer.write_string("name", spawn->name);
-    writer.write_float("x", spawn->pos.x);
-    writer.write_float("y", spawn->pos.y);
+    writer.write("name", spawn->name);
+    writer.write("x", spawn->pos.x);
+    writer.write("y", spawn->pos.y);
     writer.end_list("spawn-points");
   }
 
@@ -511,7 +520,11 @@ Sector::run_script(std::istream& in, const std::string& sourcename)
   sq_pushobject(vm, sector_table);
   sq_setroottable(vm);
 
-  compile_and_run(vm, in, sourcename);
+  try {
+    compile_and_run(vm, in, "Sector " + name + " - " + sourcename);
+  } catch(std::exception& e) {
+    log_warning << "Error running script: " << e.what() << std::endl;
+  }
 
   return vm;
 }
@@ -606,10 +619,22 @@ Sector::activate(const Vector& player_pos)
   camera->reset(player->get_pos());
   update_game_objects();
 
+  //Run default.nut just before init script
+  //Check to see if it's in a levelset (info file)
+  std::string basedir = FileSystem::dirname(get_level()->filename);
+  if(PHYSFS_exists((basedir + "/info").c_str())) {
+    try {
+      IFileStream in(basedir + "/default.nut");
+      run_script(in, "default.nut");
+    } catch(std::exception& ) {
+      // doesn't exist or erroneous; do nothing
+    }
+  }
+
   // Run init script
   if(init_script != "") {
     std::istringstream in(init_script);
-    run_script(in, std::string("Sector(") + name + ") - init");
+    run_script(in, "init-script");
   }
 }
 
@@ -751,6 +776,15 @@ Sector::before_object_add(GameObject* object)
     this->player = player;
   }
 
+  DisplayEffect* effect = dynamic_cast<DisplayEffect*> (object);
+  if(effect != NULL) {
+    if(this->effect != 0) {
+      log_warning << "Multiple DisplayEffects added. Ignoring" << std::endl;
+      return false;
+    }
+    this->effect = effect;
+  }
+
   UsesPhysic *physic_object = dynamic_cast<UsesPhysic *>(object);
   if(physic_object)
   {
@@ -879,12 +913,10 @@ Sector::draw(DrawingContext& context)
  * Collision Detection
  *-------------------------------------------------------------------------*/
 
-static const float SHIFT_DELTA = 7.0f;
-
 /** r1 is supposed to be moving, r2 a solid object */
 void check_collisions(collision::Constraints* constraints,
                       const Vector& movement, const Rect& r1, const Rect& r2,
-                      GameObject* object = NULL, MovingObject* other = NULL)
+                      GameObject* object = NULL, MovingObject* other = NULL, const Vector& addl_ground_movement = Vector(0,0))
 {
   if(!collision::intersects(r1, r2))
     return;
@@ -921,6 +953,7 @@ void check_collisions(collision::Constraints* constraints,
     }
   }
 
+  constraints->ground_movement += addl_ground_movement;
   if(other != NULL) {
     HitResponse response = other->collision(*object, dummy);
     if(response == PASSTHROUGH)
@@ -953,8 +986,6 @@ void check_collisions(collision::Constraints* constraints,
   }
 }
 
-static const float DELTA = .001f;
-
 void
 Sector::collision_tilemap(collision::Constraints* constraints,
                           const Vector& movement, const Rect& dest) const
@@ -976,30 +1007,30 @@ Sector::collision_tilemap(collision::Constraints* constraints,
 
     for(int x = starttilex; x*32 < max_x; ++x) {
       for(int y = starttiley; y*32 < max_y; ++y) {
-       const Tile* tile = solids->get_tile(x, y);
-       if(!tile)
-         continue;
-       // skip non-solid tiles
-       if((tile->getAttributes() & Tile::SOLID) == 0)
-         continue;
-       // only handle unisolid when the player is falling down and when he was
-       // above the tile before
-       if(tile->getAttributes() & Tile::UNISOLID) {
-         if(movement.y <= 0 || dest.get_bottom() - movement.y - SHIFT_DELTA > y*32)
-           continue;
-       }
-
-       if(tile->getAttributes() & Tile::SLOPE) { // slope tile
-         AATriangle triangle;
-         Vector p1(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset());
-         Vector p2((x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
-         triangle = AATriangle(p1, p2, tile->getData());
-
-         collision::rectangle_aatriangle(constraints, dest, triangle);
-       } else { // normal rectangular tile
-         Rect rect(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset(), (x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
-         check_collisions(constraints, movement, dest, rect);
-       }
+    const Tile* tile = solids->get_tile(x, y);
+    if(!tile)
+      continue;
+    // skip non-solid tiles
+    if((tile->getAttributes() & Tile::SOLID) == 0)
+      continue;
+    // only handle unisolid when the player is falling down and when he was
+    // above the tile before
+    if(tile->getAttributes() & Tile::UNISOLID) {
+      if(movement.y <= 0 || dest.get_bottom() - movement.y - SHIFT_DELTA > y*32)
+        continue;
+    }
+
+    if(tile->getAttributes() & Tile::SLOPE) { // slope tile
+      AATriangle triangle;
+      Vector p1(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset());
+      Vector p2((x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
+      triangle = AATriangle(p1, p2, tile->getData());
+
+      collision::rectangle_aatriangle(constraints, dest, triangle, solids->get_movement());
+    } else { // normal rectangular tile
+      Rect rect(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset(), (x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
+      check_collisions(constraints, movement, dest, rect, NULL, NULL, solids->get_movement());
+    }
       }
     }
   }
@@ -1011,7 +1042,7 @@ Sector::collision_tile_attributes(const Rect& dest) const
   float x1 = dest.p1.x;
   float y1 = dest.p1.y;
   float x2 = dest.p2.x;
-  float y2 = dest.p2.y;
+  float y2 = dest.p2.y + SHIFT_DELTA;
 
   uint32_t result = 0;
   for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
@@ -1025,10 +1056,10 @@ Sector::collision_tile_attributes(const Rect& dest) const
 
     for(int x = starttilex; x*32 < max_x; ++x) {
       for(int y = starttiley; y*32 < max_y; ++y) {
-       const Tile* tile = solids->get_tile(x, y);
-       if(!tile)
-         continue;
-       result |= tile->getAttributes();
+    const Tile* tile = solids->get_tile(x, y);
+    if(!tile)
+      continue;
+    result |= tile->getAttributes();
       }
     }
   }
@@ -1361,18 +1392,17 @@ Sector::is_free_of_tiles(const Rect& rect, const bool ignoreUnisolid) const
 
     for(int x = starttilex; x*32 <= max_x; ++x) {
       for(int y = starttiley; y*32 <= max_y; ++y) {
-       const Tile* tile = solids->get_tile(x, y);
-       if(!tile) continue;
-       if(tile->getAttributes() & Tile::SLOPE) {
-         AATriangle triangle;
-         Vector p1(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset());
-         Vector p2((x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
-         triangle = AATriangle(p1, p2, tile->getData());
-         Constraints constraints;
-         return collision::rectangle_aatriangle(&constraints, rect, triangle);
-       }
-       if((tile->getAttributes() & Tile::SOLID) && !ignoreUnisolid) return false;
-       if((tile->getAttributes() & Tile::SOLID) && !(tile->getAttributes() & Tile::UNISOLID)) return false;
+    const Tile* tile = solids->get_tile(x, y);
+    if(!tile) continue;
+    if(tile->getAttributes() & Tile::SLOPE) {
+      AATriangle triangle;
+      Vector p1(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset());
+      Vector p2((x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
+      triangle = AATriangle(p1, p2, tile->getData());
+      Constraints constraints;
+      if(collision::rectangle_aatriangle(&constraints, rect, triangle) && (!ignoreUnisolid || !(tile->getAttributes() & Tile::UNISOLID))) return false;
+    }
+    if((tile->getAttributes() & Tile::SOLID) && (!ignoreUnisolid || !(tile->getAttributes() & Tile::UNISOLID))) return false;
       }
     }
   }
@@ -1457,7 +1487,7 @@ Sector::play_music(MusicType type)
       sound_manager->play_music(music);
       break;
     case HERRING_MUSIC:
-      sound_manager->play_music("music/salcon.ogg");
+      sound_manager->play_music("music/invincible.music");
       break;
     case HERRING_WARNING_MUSIC:
       sound_manager->stop_music(TUX_INVINCIBLE_TIME_WARNING);
@@ -1567,3 +1597,22 @@ Sector::get_ambient_blue()
 {
   return ambient_light.blue;
 }
+
+void
+Sector::set_gravity(float gravity)
+{
+  log_warning << "Changing a Sector's gravitational constant might have unforeseen side-effects" << std::endl;
+
+  this->gravity = gravity;
+
+  for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end(); ++i) {
+    GameObject* game_object = *i;
+    if(!game_object) continue;
+    if(!game_object->is_valid()) continue;
+    UsesPhysic *physics_object = dynamic_cast<UsesPhysic*>(game_object);
+    if (!physics_object) continue;
+
+    physics_object->physic.set_gravity(gravity);
+  }
+}
+