attempt to tune badguy activation
[supertux.git] / src / camera.cpp
index 6ef8168..c25cc20 100644 (file)
@@ -18,6 +18,8 @@
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "camera.h"
 
+#include <stdexcept>
+#include <sstream>
 #include <math.h>
 #include "lispwriter.h"
 #include "player.h"
@@ -25,7 +27,8 @@
 #include "globals.h"
 
 Camera::Camera(Player* newplayer, Level* newlevel)
-  : player(newplayer), level(newlevel), scrollchange(NONE)
+  : player(newplayer), level(newlevel), do_backscrolling(true),
+    scrollchange(NONE), auto_idx(0), auto_t(0)
 {
   if(!player || !level)
     mode = MANUAL;
@@ -44,14 +47,74 @@ Camera::set_translation(const Vector& newtranslation)
 }
 
 void
+Camera::read(LispReader& reader)
+{
+  std::string modename;
+  
+  reader.read_string("mode", &modename);
+  if(modename == "normal") {
+    mode = NORMAL;
+
+    do_backscrolling = true;
+    reader.read_bool("backscrolling", &do_backscrolling);
+  } else if(modename == "autoscroll") {
+    mode = AUTOSCROLL;
+    
+    lisp_object_t* cur = 0;
+    reader.read_lisp("path", &cur);
+    if(cur == 0) {
+      throw std::runtime_error("No path specified in autoscroll camera.");
+    }
+    float speed = .5;
+    while(!lisp_nil_p(cur)) {
+      if(strcmp(lisp_symbol(lisp_car(lisp_car(cur))), "point") != 0) {
+        std::cerr << "Warning: unknown token in camera path.\n";
+        continue;
+      }
+           
+      LispReader reader(lisp_cdr(lisp_car(cur)));
+
+      ScrollPoint point;
+      if(!reader.read_float("x", &point.position.x) ||
+         !reader.read_float("y", &point.position.y)) {
+        throw std::runtime_error("x and y missing in point of camerapath");
+      }
+      reader.read_float("speed", &speed);
+      point.speed = speed;
+      scrollpoints.push_back(point);
+
+      cur = lisp_cdr(cur);
+    }
+  } else if(modename == "manual") {
+    mode = MANUAL;
+  } else {
+    std::stringstream str;
+    str << "invalid camera mode '" << modename << "'found in worldfile.";
+    throw std::runtime_error(str.str());
+  }
+}
+
+void
 Camera::write(LispWriter& writer)
 {
   writer.start_list("camera");
   
   if(mode == NORMAL) {
     writer.write_string("mode", "normal");
+    writer.write_bool("backscrolling", do_backscrolling);
   } else if(mode == AUTOSCROLL) {
     writer.write_string("mode", "autoscroll");
+    writer.start_list("path");
+    for(std::vector<ScrollPoint>::iterator i = scrollpoints.begin();
+        i != scrollpoints.end(); ++i) {
+      writer.start_list("point");
+      writer.write_float("x", i->position.x);
+      writer.write_float("y", i->position.y);
+      writer.write_float("speed", i->speed);
+      writer.end_list("point");
+    }
+
+    writer.end_list("path");
   } else if(mode == MANUAL) {
     writer.write_string("mode", "manual");
   }
@@ -72,6 +135,20 @@ Camera::action(float elapsed_time)
 }
 
 void
+Camera::keep_in_bounds()
+{
+  // don't scroll before the start or after the level's end
+  if(translation.y > level->height * 32 - screen->h)
+    translation.y = level->height * 32 - screen->h;
+  if(translation.y < 0)                                      
+    translation.y = 0; 
+  if(translation.x > level->width * 32 - screen->w)
+    translation.x = level->width * 32 - screen->w;
+  if(translation.x < 0)
+    translation.x = 0;                                         
+}
+
+void
 Camera::scroll_normal(float elapsed_time)
 {
   assert(level != 0 && player != 0);
@@ -112,12 +189,6 @@ Camera::scroll_normal(float elapsed_time)
 
     // finally scroll with calculated speed
     translation.y -= speed_y * elapsed_time;
-
-    // don't scroll before the start or after the level's end
-    if(translation.y > level->height * 32 - screen->h)
-      translation.y = level->height * 32 - screen->h;
-    if(translation.y < 0)
-      translation.y = 0; 
   }
 
   /****** Horizontal scrolling part *******/
@@ -131,7 +202,7 @@ Camera::scroll_normal(float elapsed_time)
       || (player->dir == ::RIGHT && scrollchange == LEFT))
     scrollchange = NONE;
   // when in left 1/3rd of screen scroll left
-  if(player->base.x < translation.x + screen->w/3 && level->back_scrolling)
+  if(player->base.x < translation.x + screen->w/3 && do_backscrolling)
     scrollchange = LEFT;
   // scroll right when in right 1/3rd of screen
   else if(player->base.x > translation.x + screen->w/3*2)
@@ -161,15 +232,39 @@ Camera::scroll_normal(float elapsed_time)
   // apply scrolling
   translation.x -= speed_x * elapsed_time;
 
-  // don't scroll before the start or after the level's end
-  if(translation.x > level->width * 32 - screen->w)
-    translation.x = level->width * 32 - screen->w;
-  if(translation.x < 0)
-    translation.x = 0;   
+  keep_in_bounds();
 }
 
 void
 Camera::scroll_autoscroll(float elapsed_time)
 {
-  // TODO
+  if(player->dying)
+    return;
+
+  if(auto_t - elapsed_time >= 0) {
+    translation += current_dir * elapsed_time;
+    auto_t -= elapsed_time;
+  } else {
+    // do the rest of the old movement
+    translation += current_dir * auto_t;
+    elapsed_time -= auto_t;
+    auto_t = 0;
+
+    // construct path for next point
+    if(auto_idx+1 >= scrollpoints.size()) {
+      keep_in_bounds();
+      return;
+    }
+    Vector distance = scrollpoints[auto_idx+1].position 
+                      - scrollpoints[auto_idx].position;
+    current_dir = distance.unit() * scrollpoints[auto_idx].speed;
+    auto_t = distance.norm() / scrollpoints[auto_idx].speed;
+
+    // do movement for the remaining time
+    translation += current_dir * elapsed_time;
+    auto_t -= elapsed_time;
+    auto_idx++;
+  }
+
+  keep_in_bounds();
 }