#303: Typo fixes from mathnerd314
[supertux.git] / src / worldmap / worldmap.cpp
index 473811e..2ed3783 100644 (file)
@@ -26,7 +26,7 @@
 #include <stdexcept>
 #include <sstream>
 #include <unistd.h>
-//#include <physfs.h>
+#include <physfs.h>
 
 #include "worldmap.hpp"
 
@@ -54,6 +54,9 @@
 #include "main.hpp"
 #include "spawn_point.hpp"
 #include "file_system.hpp"
+#include "physfs/physfs_stream.hpp"
+#include "tile_manager.hpp"
+#include "tile_set.hpp"
 #include "gui/menu.hpp"
 #include "gui/mousecursor.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
@@ -67,6 +70,8 @@
 #include "worldmap/tux.hpp"
 #include "worldmap/sprite_change.hpp"
 
+static const float CAMERA_PAN_SPEED = 5.0;
+
 namespace WorldMapNS {
 
 enum WorldMapMenuIDs {
@@ -134,10 +139,10 @@ string_to_direction(const std::string& directory)
 //---------------------------------------------------------------------------
 
 WorldMap::WorldMap(const std::string& filename, const std::string& force_spawnpoint)
-  : tux(0), ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), force_spawnpoint(force_spawnpoint), in_level(false)
+  : tux(0), tileset(NULL), free_tileset(false),
+    ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), force_spawnpoint(force_spawnpoint),
+    in_level(false), panning(false)
 {
-  tile_manager.reset(new TileManager("images/worldmap.strf"));
-
   tux = new Tux(this);
   add_object(tux);
 
@@ -169,6 +174,8 @@ WorldMap::WorldMap(const std::string& filename, const std::string& force_spawnpo
 
   sq_addref(global_vm, &worldmap_table);
   sq_pop(global_vm, 1);
+
+  sound_manager->preload("sounds/warp.wav");
   
   // load worldmap objects
   load(filename);
@@ -178,6 +185,9 @@ WorldMap::~WorldMap()
 {
   using namespace Scripting;
 
+  if(free_tileset)
+    delete tileset;
+
   for(GameObjects::iterator i = game_objects.begin();
       i != game_objects.end(); ++i) {
     GameObject* object = *i;
@@ -246,7 +256,7 @@ WorldMap::try_unexpose(GameObject* object)
 }
 
 void
-WorldMap::move_to_spawnpoint(const std::string& spawnpoint)
+WorldMap::move_to_spawnpoint(const std::string& spawnpoint, bool pan)
 {
   for(SpawnPoints::iterator i = spawn_points.begin(); i != spawn_points.end(); ++i) {
     SpawnPoint* sp = *i;
@@ -254,6 +264,11 @@ WorldMap::move_to_spawnpoint(const std::string& spawnpoint)
       Vector p = sp->pos;
       tux->set_tile_pos(p);
       tux->set_direction(sp->auto_dir);
+      if(pan) {
+        panning = true;
+        pan_pos = get_camera_pos_for_tux();
+        clamp_camera_position(pan_pos);
+      }
       return;
     }
   }
@@ -280,20 +295,39 @@ WorldMap::load(const std::string& filename)
     lisp::Parser parser;
     const lisp::Lisp* root = parser.parse(map_filename);
 
-    const lisp::Lisp* lisp = root->get_lisp("supertux-level");
-    if(!lisp)
+    const lisp::Lisp* level = root->get_lisp("supertux-level");
+    if(level == NULL)
       throw std::runtime_error("file isn't a supertux-level file.");
 
-    lisp->get("name", name);
+    level->get("name", name);
 
-    const lisp::Lisp* sector = lisp->get_lisp("sector");
+    const lisp::Lisp* sector = level->get_lisp("sector");
     if(!sector)
-      throw std::runtime_error("No sector sepcified in worldmap file.");
+      throw std::runtime_error("No sector specified in worldmap file.");
+
+    const lisp::Lisp* tilesets_lisp = level->get_lisp("tilesets");
+    if(tilesets_lisp != NULL) {
+      tileset      = tile_manager->parse_tileset_definition(*tilesets_lisp);
+      free_tileset = true;
+    }
+    std::string tileset_name;
+    if(level->get("tileset", tileset_name)) {
+      if(tileset != NULL) {
+        log_warning << "multiple tilesets specified in level" << std::endl;
+      } else {
+        tileset = tile_manager->get_tileset(tileset_name);
+      }
+    }
+    /* load default tileset */
+    if(tileset == NULL) {
+      tileset = tile_manager->get_tileset("images/worldmap.strf");
+    }
+    current_tileset = tileset;
 
     lisp::ListIterator iter(sector);
     while(iter.next()) {
       if(iter.item() == "tilemap") {
-        add_object(new TileMap(*(iter.lisp()), tile_manager.get()));
+        add_object(new TileMap(*(iter.lisp())));
       } else if(iter.item() == "background") {
         add_object(new Background(*(iter.lisp())));
       } else if(iter.item() == "music") {
@@ -333,6 +367,8 @@ WorldMap::load(const std::string& filename)
         log_warning << "Unknown token '" << iter.item() << "' in worldmap" << std::endl;
       }
     }
+    current_tileset = NULL;
+
     if(solid_tilemaps.size() == 0)
       throw std::runtime_error("No solid tilemap specified");
 
@@ -508,6 +544,33 @@ WorldMap::finished_level(Level* gamelevel)
   }
 }
 
+Vector
+WorldMap::get_camera_pos_for_tux() {
+  Vector camera_offset;
+  Vector tux_pos = tux->get_pos();
+  camera_offset.x = tux_pos.x - SCREEN_WIDTH/2;
+  camera_offset.y = tux_pos.y - SCREEN_HEIGHT/2;
+  return camera_offset;
+}
+
+void
+WorldMap::clamp_camera_position(Vector& c) {
+  if (c.x < 0)
+    c.x = 0;
+  if (c.y < 0)
+    c.y = 0;
+
+  if (c.x > (int)get_width()*32 - SCREEN_WIDTH)
+    c.x = (int)get_width()*32 - SCREEN_WIDTH;
+  if (c.y > (int)get_height()*32 - SCREEN_HEIGHT)
+    c.y = (int)get_height()*32 - SCREEN_HEIGHT;
+
+  if (int(get_width()*32) < SCREEN_WIDTH)
+    c.x = get_width()*16.0 - SCREEN_WIDTH/2.0;
+  if (int(get_height()*32) < SCREEN_HEIGHT)
+    c.y = get_height()*16.0 - SCREEN_HEIGHT/2.0;
+}
+
 void
 WorldMap::update(float delta)
 {
@@ -534,7 +597,9 @@ WorldMap::update(float delta)
     // update GameObjects
     for(size_t i = 0; i < game_objects.size(); ++i) {
       GameObject* object = game_objects[i];
-      object->update(delta);
+      if(!panning || object != tux) {
+          object->update(delta);
+      }
     }
 
     // remove old GameObjects
@@ -561,25 +626,34 @@ WorldMap::update(float delta)
       if (tm->is_solid()) solid_tilemaps.push_back(tm);
     }
 
-    // position "camera"
-    Vector tux_pos = tux->get_pos();
-    camera_offset.x = tux_pos.x - SCREEN_WIDTH/2;
-    camera_offset.y = tux_pos.y - SCREEN_HEIGHT/2;
+    Vector requested_pos;
 
-    if (camera_offset.x < 0)
-      camera_offset.x = 0;
-    if (camera_offset.y < 0)
-      camera_offset.y = 0;
+    // position "camera"
+    if(!panning) {
+      camera_offset = get_camera_pos_for_tux();
+    } else {
+      Vector delta = pan_pos - camera_offset;
+      float mag = delta.norm();
+      if(mag > CAMERA_PAN_SPEED) {
+        delta *= CAMERA_PAN_SPEED/mag;
+      }
+      camera_offset += delta;
+      if(camera_offset == pan_pos) {
+        panning = false;
+      }
+    }
 
-    if (camera_offset.x > (int)get_width()*32 - SCREEN_WIDTH)
-      camera_offset.x = (int)get_width()*32 - SCREEN_WIDTH;
-    if (camera_offset.y > (int)get_height()*32 - SCREEN_HEIGHT)
-      camera_offset.y = (int)get_height()*32 - SCREEN_HEIGHT;
+    requested_pos = camera_offset;
+    clamp_camera_position(camera_offset);
 
-    if (int(get_width()*32) < SCREEN_WIDTH)
-      camera_offset.x = get_width()*16.0 - SCREEN_WIDTH/2.0;
-    if (int(get_height()*32) < SCREEN_HEIGHT)
-      camera_offset.y = get_height()*16.0 - SCREEN_HEIGHT/2.0;
+    if(panning) {
+        if(requested_pos.x != camera_offset.x) {
+            pan_pos.x = camera_offset.x;
+        }
+        if(requested_pos.y != camera_offset.y) {
+            pan_pos.y = camera_offset.y;
+        }
+    }
 
     // handle input
     bool enter_level = false;
@@ -603,7 +677,7 @@ WorldMap::update(float delta)
         // TODO: an animation, camera scrolling or a fading would be a nice touch
         sound_manager->play("sounds/warp.wav");
         tux->back_direction = D_NONE;
-        move_to_spawnpoint(teleporter->spawnpoint);
+        move_to_spawnpoint(teleporter->spawnpoint, true);
       }
     }
 
@@ -632,14 +706,14 @@ WorldMap::update(float delta)
         if (level->pos == tux->get_tile_pos()) {
           try {
             Vector shrinkpos = Vector(level->pos.x*32 + 16 - camera_offset.x,
-                                      level->pos.y*32 + 16 - camera_offset.y);
+                                      level->pos.y*32 +  8 - camera_offset.y);
             std::string levelfile = levels_path + level->get_name();
 
             // update state and savegame
             save_state();
 
             main_loop->push_screen(new GameSession(levelfile, &level->statistics),
-                                   new ShrinkFade(shrinkpos, 0.5));
+                                   new ShrinkFade(shrinkpos, 1.0f));
             in_level = true;
           } catch(std::exception& e) {
             log_fatal << "Couldn't load level: " << e.what() << std::endl;
@@ -737,7 +811,9 @@ WorldMap::draw(DrawingContext& context)
   for(GameObjects::iterator i = game_objects.begin();
       i != game_objects.end(); ++i) {
     GameObject* object = *i;
-    object->draw(context);
+    if(!panning || object != tux) {
+      object->draw(context);
+    }
   }
 
 /*
@@ -864,6 +940,15 @@ WorldMap::setup()
     throw SquirrelError(global_vm, "Couldn't set worldmap in roottable");
   sq_pop(global_vm, 1);
 
+  //Run default.nut just before init script
+  try {
+    IFileStream in(levels_path + "/default.nut");
+    run_script(in, "WorldMap::default.nut");
+  } catch(std::exception& ) {
+    // doesn't exist or erroneous; do nothing
+  }
+
+
   if(init_script != "") {
     std::istringstream in(init_script);
     run_script(in, "WorldMap::init");