some cleanups memory leak fixes and moving of source files
authorMatthias Braun <matze@braunis.de>
Fri, 26 Nov 2004 14:45:42 +0000 (14:45 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 26 Nov 2004 14:45:42 +0000 (14:45 +0000)
SVN-Revision: 2202

39 files changed:
lib/special/sprite.cpp
src/background.cpp [deleted file]
src/background.h [deleted file]
src/badguy/badguy.cpp
src/badguy/badguy.h
src/camera.cpp [deleted file]
src/camera.h [deleted file]
src/gameloop.cpp
src/gameobjs.cpp [deleted file]
src/gameobjs.h [deleted file]
src/level.cpp
src/level.h
src/leveleditor.cpp
src/leveleditor.h
src/misc.h
src/object/background.cpp [new file with mode: 0644]
src/object/background.h [new file with mode: 0644]
src/object/camera.cpp [new file with mode: 0644]
src/object/camera.h [new file with mode: 0644]
src/object/gameobjs.cpp [new file with mode: 0644]
src/object/gameobjs.h [new file with mode: 0644]
src/object/particlesystem.cpp [new file with mode: 0644]
src/object/particlesystem.h [new file with mode: 0644]
src/object/player.cpp [new file with mode: 0644]
src/object/player.h [new file with mode: 0644]
src/object/tilemap.cpp [new file with mode: 0644]
src/object/tilemap.h [new file with mode: 0644]
src/particlesystem.cpp [deleted file]
src/particlesystem.h [deleted file]
src/player.cpp [deleted file]
src/player.h [deleted file]
src/resources.cpp
src/sector.cpp
src/sector.h
src/supertux.cpp
src/tilemap.cpp [deleted file]
src/tilemap.h [deleted file]
src/title.cpp
src/trigger/trigger_base.cpp

index 6ae6598..f07cfc1 100644 (file)
@@ -87,7 +87,7 @@ Sprite::update()
 
   frame += frame_inc;
 
-  if(frame > get_frames()) {
+  if(frame >= get_frames()) {
     frame = fmodf(frame+get_frames(), get_frames());
     
     animation_loops--;
diff --git a/src/background.cpp b/src/background.cpp
deleted file mode 100644 (file)
index 60d217c..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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 <config.h>
-
-#include "background.h"
-#include "app/globals.h"
-#include "camera.h"
-#include "video/drawing_context.h"
-#include "utils/lispwriter.h"
-
-Background::Background()
-  : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
-{
-}
-
-Background::Background(LispReader& reader)
-  : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
-{
-  reader.read_int("layer", layer);
-  if(reader.read_string("image", imagefile) 
-      && reader.read_float("speed", speed)) {
-    set_image(imagefile, speed);
-  }
-
-  std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
-  if(reader.read_int_vector("top_color", bkgd_top_color) &&
-     reader.read_int_vector("bottom_color", bkgd_bottom_color))
-    set_gradient(Color(bkgd_top_color), Color(bkgd_bottom_color));
-}
-
-Background::~Background()
-{
-  printf("bgfree.\n");
-  delete image;
-}
-
-void
-Background::write(LispWriter& writer)
-{
-  if(type == INVALID)
-    return;
-    
-  writer.start_list("background");
-
-  if(type == IMAGE) {
-    writer.write_string("image", imagefile);
-    writer.write_float("speed", speed);
-  } else if(type == GRADIENT) {
-    std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
-    bkgd_top_color.push_back(gradient_top.red);
-    bkgd_top_color.push_back(gradient_top.green);
-    bkgd_top_color.push_back(gradient_top.blue);
-    bkgd_bottom_color.push_back(gradient_top.red);
-    bkgd_bottom_color.push_back(gradient_top.green);
-    bkgd_bottom_color.push_back(gradient_top.blue);
-    writer.write_int_vector("top_color", bkgd_top_color);
-    writer.write_int_vector("bottom_color", bkgd_bottom_color);
-  }
-  writer.write_int("layer", layer);
-  
-  writer.end_list("background");
-}
-
-void
-Background::action(float)
-{
-}
-
-void
-Background::set_image(const std::string& name, float speed)
-{
-  this->type = IMAGE;
-  this->imagefile = name;
-  this->speed = speed;
-
-  printf("seti %p\n", this);
-  delete image;
-  image = new Surface(datadir + "/images/background/" + name, false);
-}
-
-void
-Background::set_gradient(Color top, Color bottom)
-{
-  type = GRADIENT;
-  gradient_top = top;
-  gradient_bottom = bottom;
-
-  delete image;
-  image = new Surface(top, bottom, screen->w, screen->h);
-}
-
-void
-Background::draw(DrawingContext& context)
-{
-  if(type == GRADIENT) {
-    context.push_transform();
-    context.set_translation(Vector(0, 0));
-    context.draw_surface(image, Vector(0, 0), layer);
-    context.pop_transform();
-  } else if(type == IMAGE) {
-    if(!image)
-      return;
-    
-    int sx = int(-context.get_translation().x * speed) % image->w - image->w;
-    int sy = int(-context.get_translation().y * speed) % image->h - image->h;
-    context.push_transform();
-    context.set_translation(Vector(0, 0));
-    for(int x = sx; x < screen->w; x += image->w)
-      for(int y = sy; y < screen->h; y += image->h)
-        context.draw_surface(image, Vector(x, y), layer);
-    context.pop_transform();
-  }
-}
-
diff --git a/src/background.h b/src/background.h
deleted file mode 100644 (file)
index 7ed3e83..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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.
-
-#ifndef SUPERTUX_BACKGROUND_H
-#define SUPERTUX_BACKGROUND_H
-
-#include "video/surface.h"
-#include "video/drawing_context.h"
-#include "special/game_object.h"
-#include "utils/lispreader.h"
-#include "serializable.h"
-
-class DisplayManager;
-
-class Background : public GameObject, public Serializable
-{
-public:
-  Background();
-  Background(LispReader& reader);
-  virtual ~Background();
-
-  virtual void write(LispWriter& writer);
-
-  void set_image(const std::string& name, float bkgd_speed);
-
-  void set_gradient(Color top, Color bottom);
-
-  std::string get_image() const
-        { return imagefile; }
-  float get_speed() const
-        { return speed; }
-  Color get_gradient_top() const
-        { return gradient_top; }
-  Color get_gradient_bottom() const
-        { return gradient_bottom; }
-
-  virtual void action(float elapsed_time);
-
-  virtual void draw(DrawingContext& context);
-
-private:
-  enum Type {
-    INVALID, GRADIENT, IMAGE      
-  };
-  
-  Type type;
-  int layer;
-  std::string imagefile;
-  float speed;
-  Surface* image;
-  Color gradient_top, gradient_bottom;
-};
-
-#endif /*SUPERTUX_BACKGROUND_H*/
-
index b075dd1..25825a4 100644 (file)
@@ -1,7 +1,7 @@
 #include <config.h>
 
 #include "badguy.h"
-#include "camera.h"
+#include "object/camera.h"
 
 static const float SQUISH_TIME = 2;
 static const float X_OFFSCREEN_DISTANCE = 1600;
index c090408..68cdb57 100644 (file)
@@ -7,7 +7,7 @@
 #include "special/moving_object.h"
 #include "special/sprite.h"
 #include "math/physic.h"
-#include "player.h"
+#include "object/player.h"
 #include "serializable.h"
 #include "resources.h"
 #include "sector.h"
diff --git a/src/camera.cpp b/src/camera.cpp
deleted file mode 100644 (file)
index b2f47ed..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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 <config.h>
-
-#include <stdexcept>
-#include <sstream>
-#include <cmath>
-
-#include "camera.h"
-#include "utils/lispreader.h"
-#include "utils/lispwriter.h"
-#include "player.h"
-#include "tilemap.h"
-#include "gameloop.h"
-#include "app/globals.h"
-#include "sector.h"
-
-using namespace SuperTux;
-
-Camera::Camera(Sector* newsector)
-  : sector(newsector), do_backscrolling(true), scrollchange(NONE),
-    auto_idx(0), auto_t(0)
-{
-  mode = NORMAL;
-}
-
-Camera::~Camera()
-{
-}
-
-const Vector&
-Camera::get_translation() const
-{
-  return translation;
-}
-
-void
-Camera::parse(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 = 50;
-    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");
-  }
-                     
-  writer.end_list("camera");
-}
-
-void
-Camera::reset(const Vector& tuxpos)
-{
-  translation.x = tuxpos.x - screen->w/3 * 2;
-  translation.y = tuxpos.y - screen->h/2;
-  keep_in_bounds();
-}
-
-static const float EPSILON = .00001;
-static const float max_speed_y = 140;
-
-void
-Camera::action(float elapsed_time)
-{
-  if(mode == NORMAL)
-    scroll_normal(elapsed_time);
-  else if(mode == AUTOSCROLL)
-    scroll_autoscroll(elapsed_time);
-}
-
-void
-Camera::keep_in_bounds()
-{
-  float width = sector->solids->get_width() * 32;
-  float height = sector->solids->get_height() * 32;
-
-  // don't scroll before the start or after the level's end
-  if(translation.y > height - screen->h)
-    translation.y = height - screen->h;
-  if(translation.y < 0)                                      
-    translation.y = 0; 
-  if(translation.x > width - screen->w)
-    translation.x = width - screen->w;
-  if(translation.x < 0)
-    translation.x = 0;                                         
-}
-
-void
-Camera::scroll_normal(float elapsed_time)
-{
-  assert(sector != 0);
-  Player* player = sector->player;
-  
-  // check that we don't have division by zero later
-  if(elapsed_time < EPSILON)
-    return;
-
-  /****** Vertical Scrolling part ******/
-  bool do_y_scrolling = true;
-
-  if(player->dying || sector->solids->get_height() == 19)
-    do_y_scrolling = false;
-
-  if(do_y_scrolling) {
-    // target_y is the high we target our scrolling at. This is not always the
-    // high of the player, but if he is jumping upwards we should use the
-    // position where he last touched the ground. (this probably needs
-    // exceptions for trampolines and similar things in the future)
-    float target_y;
-    if(player->fall_mode == Player::JUMPING)
-      target_y = player->last_ground_y + player->get_bbox().get_height();
-    else
-      target_y = player->get_bbox().p2.y;
-
-    // delta_y is the distance we'd have to travel to directly reach target_y
-    float delta_y = translation.y - (target_y - screen->h/2);
-    // speed is the speed the camera would need to reach target_y in this frame
-    float speed_y = delta_y / elapsed_time;
-
-    // limit the camera speed when jumping upwards
-    if(player->fall_mode != Player::FALLING 
-        && player->fall_mode != Player::TRAMPOLINE_JUMP) {
-      if(speed_y > max_speed_y)
-        speed_y = max_speed_y;
-      else if(speed_y < -max_speed_y)
-        speed_y = -max_speed_y;
-    }
-
-    // finally scroll with calculated speed
-    translation.y -= speed_y * elapsed_time;
-  }
-
-  /****** Horizontal scrolling part *******/
-
-  // our camera is either in leftscrolling, rightscrolling or nonscrollingmode.
-  
-  // when suddenly changing directions while scrolling into the other direction.
-  // abort scrolling, since tux might be going left/right at a relatively small
-  // part of the map (like when jumping upwards)
-  if((player->dir == ::LEFT && scrollchange == RIGHT)
-      || (player->dir == ::RIGHT && scrollchange == LEFT))
-    scrollchange = NONE;
-  // when in left 1/3rd of screen scroll left
-  if(player->get_bbox().get_middle().x < translation.x + screen->w/3 - 16
-      && do_backscrolling)
-    scrollchange = LEFT;
-  // scroll right when in right 1/3rd of screen
-  else if(player->get_bbox().get_middle().x > translation.x + screen->w/3*2+16)
-    scrollchange = RIGHT;
-
-  // calculate our scroll target depending on scroll mode
-  float target_x;
-  if(scrollchange == LEFT)
-    target_x = player->get_bbox().get_middle().x - screen->w/3*2;
-  else if(scrollchange == RIGHT)
-    target_x = player->get_bbox().get_middle().x - screen->w/3;
-  else
-    target_x = translation.x;
-
-  // that's the distance we would have to travel to reach target_x
-  float delta_x = translation.x - target_x;
-  // the speed we'd need to travel to reach target_x in this frame
-  float speed_x = delta_x / elapsed_time;
-
-  // limit our speed
-  float maxv = 130 + (fabsf(player->physic.get_velocity_x() * 1.3));
-  if(speed_x > maxv)
-    speed_x = maxv;
-  else if(speed_x < -maxv)
-    speed_x = -maxv;
-  // apply scrolling
-  translation.x -= speed_x * elapsed_time;
-
-  keep_in_bounds();
-}
-
-void
-Camera::scroll_autoscroll(float elapsed_time)
-{
-  Player* player = sector->player;
-  
-  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();
-}
diff --git a/src/camera.h b/src/camera.h
deleted file mode 100644 (file)
index 2294aa9..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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.
-
-#ifndef SUPERTUX_CAMERA_H
-#define SUPERTUX_CAMERA_H
-
-#include <vector>
-#include <cassert>
-
-#include "defines.h"
-#include "math/vector.h"
-#include "special/game_object.h"
-#include "video/drawing_context.h"
-#include "serializable.h"
-
-using namespace SuperTux;
-
-namespace SuperTux {
-class LispReader;
-}
-
-class Sector;
-
-class Camera : public GameObject, public Serializable
-{
-public:
-  Camera(Sector* sector);
-  virtual ~Camera();
-
-  /// parse camera mode from lisp file
-  void parse(LispReader& reader);
-  /// write camera mode to a lisp file
-  virtual void write(LispWriter& writer);
-
-  /// reset camera postion
-  virtual void reset(const Vector& tuxpos);
-
-  /** @deprecated@ */
-  const Vector& get_translation() const;
-
-  virtual void action(float elapsed_time);
-
-  virtual void draw(DrawingContext& )
-  {
-  }
-
-  void set_scrolling(int scroll_x, int scroll_y)
-  {
-    translation.x = scroll_x;
-    translation.y = scroll_y;
-  }
-
-  enum CameraMode
-  {
-    NORMAL, AUTOSCROLL, MANUAL
-  };
-  CameraMode mode;
-
-private:
-  void scroll_normal(float elapsed_time);
-  void scroll_autoscroll(float elapsed_time);
-  void keep_in_bounds();
-
-  enum LeftRightScrollChange
-  {
-    NONE, LEFT, RIGHT
-  };
-    
-  Vector translation;
-
-  Sector* sector;
-
-  // normal mode
-  bool do_backscrolling;
-  LeftRightScrollChange scrollchange;
-
-  // autoscroll mode
-  class ScrollPoint {
-  public:
-    Vector position;
-    float speed;
-  };
-  std::vector<ScrollPoint> scrollpoints;
-  size_t auto_idx;
-  float auto_t;
-  Vector current_dir;
-};
-
-#endif /*SUPERTUX_CAMERA_H*/
-
index 2947f84..a5933de 100644 (file)
 #include "high_scores.h"
 #include "gui/menu.h"
 #include "sector.h"
-#include "player.h"
 #include "level.h"
 #include "scene.h"
 #include "tile.h"
-#include "particlesystem.h"
+#include "object/particlesystem.h"
+#include "object/background.h"
+#include "object/tilemap.h"
+#include "object/camera.h"
+#include "object/player.h"
 #include "resources.h"
-#include "background.h"
-#include "tilemap.h"
 #include "app/gettext.h"
 #include "worldmap.h"
 #include "intro.h"
 #include "misc.h"
-#include "camera.h"
 #include "statistics.h"
 #include "timer.h"
 #include "object/fireworks.h"
diff --git a/src/gameobjs.cpp b/src/gameobjs.cpp
deleted file mode 100644 (file)
index 3201eb2..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-//  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-// 
-//  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 <config.h>
-
-#include <algorithm>
-#include <iostream>
-#include <cmath>
-
-#include "app/globals.h"
-#include "tile.h"
-#include "tile_manager.h"
-#include "gameloop.h"
-#include "gameobjs.h"
-#include "special/sprite_manager.h"
-#include "resources.h"
-#include "sector.h"
-#include "tilemap.h"
-#include "video/drawing_context.h"
-#include "camera.h"
-
-BouncyCoin::BouncyCoin(const Vector& pos)
-  : position(pos)
-{
-  timer.start(.3);
-  sprite = sprite_manager->create("coin");
-  sprite->set_action("still");
-}
-
-BouncyCoin::~BouncyCoin()
-{
-  delete sprite;
-}
-
-void
-BouncyCoin::action(float elapsed_time)
-{
-  position.y += -200 * elapsed_time;
-
-  if(timer.check())
-    remove_me();
-}
-
-void
-BouncyCoin::draw(DrawingContext& context)
-{
-  sprite->draw(context, position, LAYER_OBJECTS);
-}
-
-//---------------------------------------------------------------------------
-
-BrokenBrick::BrokenBrick(Sprite* nsprite,
-    const Vector& pos, const Vector& nmovement)
-  : sprite(new Sprite(*nsprite)), position(pos), movement(nmovement)
-{
-  timer.start(.2);
-}
-
-BrokenBrick::~BrokenBrick()
-{
-  delete sprite;
-}
-
-void
-BrokenBrick::action(float elapsed_time)
-{
-  position += movement * elapsed_time;
-
-  if (timer.check())
-    remove_me();
-}
-
-void
-BrokenBrick::draw(DrawingContext& context)
-{
-  sprite->draw_part(context,
-      Vector(rand() % 16, rand() % 16), Vector(16, 16),
-      position, LAYER_OBJECTS + 1);
-}
-
-//---------------------------------------------------------------------------
-
-FloatingText::FloatingText(const Vector& pos, const std::string& text_)
-  : position(pos), text(text_)
-{
-  timer.start(.1);
-  position.x -= text.size() * 8;
-}
-
-FloatingText::FloatingText(const Vector& pos, int score)
-  : position(pos)
-{
-  timer.start(.1);
-
-  // turn int into a string
-  char str[10];
-  snprintf(str, 10, "%d", score);
-  text = str;
-
-  position.x -= text.size() * 8;
-}
-
-void
-FloatingText::action(float elapsed_time)
-{
-  position.y -= 1.4 * elapsed_time;
-
-  if(timer.check())
-    remove_me();
-}
-
-#define FADING_TIME .350
-
-void
-FloatingText::draw(DrawingContext& context)
-{
-  // make an alpha animation when disapearing
-  int alpha;
-  if(timer.get_timeleft() < FADING_TIME)
-    alpha = int(timer.get_timeleft() * 255 / FADING_TIME);
-  else
-    alpha = 255;
-
-  context.push_transform();
-  context.set_alpha(alpha);
-
-  context.draw_text(gold_text, text, position, LEFT_ALLIGN, LAYER_OBJECTS+1);
-
-  context.pop_transform();
-}
-
-/* Trampoline */
-
-#if 0
-Sprite *img_trampoline;
-
-Trampoline::Trampoline(LispReader& reader)
-{
-  reader.read_float("x", base.x);
-  reader.read_float("y", base.y); 
-  base.width = 32;
-  base.height = 32;
-  power = 7.5;
-  reader.read_float("power", power);
-
-  frame = 0;
-  mode = M_NORMAL;
-  physic.reset();
-}
-
-Trampoline::Trampoline(float x, float y)
-{
-  base.x = x;
-  base.y = y;
-  base.width = 32;
-  base.height = 32;
-  power = 7.5;
-
-  frame = 0;
-  mode = M_NORMAL;
-  physic.reset();
-}
-
-void
-Trampoline::write(LispWriter& writer)
-{
-  writer.start_list("trampoline");
-
-  writer.write_float("x", base.x);
-  writer.write_float("y", base.y);
-  writer.write_float("power", power);
-
-  writer.end_list("trampoline");
-}
-
-void
-Trampoline::draw(DrawingContext& context)
-{
-  img_trampoline->set_frame(frame);
-  img_trampoline->draw(context, base, LAYER_OBJECTS);
-  frame = 0;
-}
-
-void
-Trampoline::action(float frame_ratio)
-{
-  // TODO: Remove if we're too far off the screen
-
-  // Falling
-  if (mode != M_HELD)
-  {
-    if (issolid(base.x + base.width/2, base.y + base.height))
-    {
-      base.y = int((base.y + base.height)/32) * 32 - base.height;
-
-      physic.enable_gravity(false);
-      physic.set_velocity_y(0.0f);
-
-      physic.set_velocity_x(0);
-    }
-    else
-    {
-      physic.enable_gravity(true);
-    }
-  }
-  else // Player is carrying us around
-  {
-    /* FIXME: The trampoline object shouldn't know about pplayer objects. */
-    /* If we're holding the iceblock */
-    Player& tux = *Sector::current()->player;
-    Direction dir = tux.dir;
-
-    if(dir == RIGHT)
-    {
-      base.x = tux.base.x + 16;
-      base.y = tux.base.y + tux.base.height/1.5 - base.height;
-    }
-    else /* facing left */
-    {
-      base.x = tux.base.x - 16;
-      base.y = tux.base.y + tux.base.height/1.5 - base.height;
-    }
-
-    if(collision_object_map(base))
-    {
-      base.x = tux.base.x;
-      base.y = tux.base.y + tux.base.height/1.5 - base.height;
-    }
-  }
-
-  physic.apply(frame_ratio, base.x, base.y, Sector::current()->gravity);
-  collision_swept_object_map(&old_base, &base);
-}
-
-void
-Trampoline::collision(const MovingObject&, int)
-{
-  // comes later
-}
-
-void
-Trampoline::collision(void *p_c_object, int c_object, CollisionType type)
-{
-  Player* pplayer_c = NULL;
-  switch (c_object)
-  {
-    case CO_PLAYER:
-      pplayer_c = (Player*) p_c_object;
-
-      if (type == COLLISION_NORMAL)
-      {
-        // Pick up if HELD (done in Player)
-      }
-
-      else if (type == COLLISION_SQUISH)
-      {
-        int squish_amount = (32 - (int)pplayer_c->base.y % 32);
-
-        if (squish_amount < 24)
-          frame = 3;
-        else if (squish_amount < 28)
-          frame = 2;
-        else if (squish_amount < 30)
-          frame = 1;
-        else
-          frame = 0;
-
-        if (squish_amount < 20) {
-          pplayer_c->physic.set_velocity_y(power);
-          pplayer_c->fall_mode = Player::TRAMPOLINE_JUMP;
-        }
-        else if (pplayer_c->physic.get_velocity_y() < 0)
-          pplayer_c->physic.set_velocity_y(-squish_amount/32);
-      }
-
-      break;
-
-    default:
-      break;
-    
-  }
-}
-#endif
-
-/* Flying Platform */
-
-#if 0
-Sprite *img_flying_platform;
-
-FlyingPlatform::FlyingPlatform(LispReader& reader)
-{
-  reader.read_int_vector("x", pos_x);
-  reader.read_int_vector("y", pos_y);
-
-  velocity = 2.0;
-  reader.read_float("velocity", velocity);
-
-  base.x = pos_x[0];
-  base.y = pos_y[0];
-  base.width = 96;
-  base.height = 40;
-
-  point = 0;
-  move = false;
-
-  float x = pos_x[point+1] - pos_x[point];
-  float y = pos_y[point+1] - pos_y[point];
-  vel_x = x*velocity / sqrt(x*x + y*y);
-  vel_y = -(velocity - vel_x);
-
-  frame = 0;
-}
-
-FlyingPlatform::FlyingPlatform(int x, int y)
-{
-base.x = x;
-base.y = y;
-point = 0;
-move = false;
-}
-
-void
-FlyingPlatform::write(LispWriter& writer)
-{
-  writer.start_list("flying-trampoline");
-
-  writer.write_int_vector("x", pos_x);
-  writer.write_int_vector("y", pos_y);
-  writer.write_float("velocity", velocity);
-
-  writer.end_list("flying-trampoline");
-}
-
-void
-FlyingPlatform::draw(DrawingContext& context)
-{
-  img_flying_platform->draw(context, base, LAYER_OBJECTS);
-}
-
-void
-FlyingPlatform::action(float frame_ratio)
-{
-  // TODO: Remove if we're too far off the screen
-
-if(!move)
-  return;
-
-if((unsigned)point+1 != pos_x.size())
-  {
-  if(((pos_x[point+1] > pos_x[point] && base.x >= pos_x[point+1]) ||
-      (pos_x[point+1] < pos_x[point] && base.x <= pos_x[point+1]) ||
-      pos_x[point] == pos_x[point+1]) &&
-    ((pos_y[point+1] > pos_y[point] && base.y >= pos_y[point+1]) ||
-      (pos_y[point+1] < pos_y[point] && base.y <= pos_y[point+1]) ||
-      pos_y[point] == pos_y[point+1]))
-    {
-    point++;
-
-    float x = pos_x[point+1] - pos_x[point];
-    float y = pos_y[point+1] - pos_y[point];
-    vel_x = x*velocity / sqrt(x*x + y*y);
-    vel_y = -(velocity - vel_x);
-    }
-  }
-else   // last point
-  {
-  // point = 0;
-  // reverse vector
-  return;
-  }
-/*
-if(pos_x[point+1] > base.x)
-  base.x += velocity * frame_ratio;
-else if(pos_x[point+1] < base.x)
-  base.x -= velocity * frame_ratio;
-
-if(pos_y[point+1] > base.y)
-  base.y += velocity * frame_ratio;
-else if(pos_y[point+1] < base.y)
-  base.y -= velocity * frame_ratio;
-*/
-
-base.x += vel_x * frame_ratio;
-base.y += vel_y * frame_ratio;
-}
-
-void
-FlyingPlatform::collision(const MovingObject&, int)
-{
-  // comes later
-}
-
-void
-FlyingPlatform::collision(void *p_c_object, int c_object, CollisionType type)
-{
-(void) p_c_object;
-(void) type;
-
-//  Player* pplayer_c = NULL;
-  switch (c_object)
-  {
-    case CO_PLAYER:
-//      pplayer_c = (Player*) p_c_object;
-      move = true;
-
-      break;
-
-    default:
-      break;
-    
-  }
-}
-#endif
-
-Sprite *img_smoke_cloud = 0;
-
-SmokeCloud::SmokeCloud(const Vector& pos)
-  : position(pos)
-{
-  timer.start(.3);
-}
-
-void
-SmokeCloud::action(float elapsed_time)
-{
-  position.y -= 120 * elapsed_time;
-
-  if(timer.check())
-    remove_me();
-}
-
-void
-SmokeCloud::draw(DrawingContext& context)
-{
-  img_smoke_cloud->draw(context, position, LAYER_OBJECTS+1);
-}
-
-Particles::Particles(const Vector& epicenter, int min_angle, int max_angle,
-        const Vector& initial_velocity, const Vector& acceleration, int number,
-        Color color_, int size_, float life_time, int drawing_layer_)
-  : accel(acceleration), color(color_), size(size_), drawing_layer(drawing_layer_)
-{
-  if(life_time == 0) {
-    live_forever = true;
-  } else {
-    live_forever = false;
-    timer.start(life_time);
-  }
-
-  // create particles
-  for(int p = 0; p < number; p++)
-    {
-    Particle* particle = new Particle;
-    particle->pos = epicenter;
-
-    float angle = ((rand() % (max_angle-min_angle))+min_angle)
-                      * (M_PI / 180);  // convert to radius
-    particle->vel.x = /*fabs*/(sin(angle)) * initial_velocity.x;
-//    if(angle >= M_PI && angle < M_PI*2)
-//      particle->vel.x *= -1;  // work around to fix signal
-    particle->vel.y = /*fabs*/(cos(angle)) * initial_velocity.y;
-//    if(angle >= M_PI_2 && angle < 3*M_PI_2)
-//      particle->vel.y *= -1;
-
-    particles.push_back(particle);
-    }
-}
-
-Particles::~Particles()
-{
-  // free particles
-  for(std::vector<Particle*>::iterator i = particles.begin();
-      i < particles.end(); i++)
-    delete (*i);
-}
-
-void
-Particles::action(float elapsed_time)
-{
-  Vector camera = Sector::current()->camera->get_translation();
-
-  // update particles
-  for(std::vector<Particle*>::iterator i = particles.begin();
-      i != particles.end(); ) {
-    (*i)->pos.x += (*i)->vel.x * elapsed_time;
-    (*i)->pos.y += (*i)->vel.y * elapsed_time;
-
-    (*i)->vel.x += accel.x * elapsed_time;
-    (*i)->vel.y += accel.y * elapsed_time;
-
-    if((*i)->pos.x < camera.x || (*i)->pos.x > screen->w + camera.x ||
-       (*i)->pos.y < camera.y || (*i)->pos.y > screen->h + camera.y) {
-      delete (*i);
-      i = particles.erase(i);
-    } else {
-      ++i;
-    }
-  }
-
-  if((timer.check() && !live_forever) || particles.size() == 0)
-    remove_me();
-}
-
-void
-Particles::draw(DrawingContext& context)
-{
-  // draw particles
-  for(std::vector<Particle*>::iterator i = particles.begin();
-      i != particles.end(); i++) {
-    context.draw_filled_rect((*i)->pos, Vector(size,size), color,drawing_layer);
-  }
-}
-
-void load_object_gfx()
-{
-#if 0
-  img_trampoline = sprite_manager->load("trampoline");
-  img_trampoline->start_animation(0);
-  img_flying_platform = sprite_manager->load("flying_platform");
-#endif
-  img_smoke_cloud = sprite_manager->create("stomp");
-}
-
-void free_object_gfx()
-{
-  delete img_smoke_cloud;
-}
-
diff --git a/src/gameobjs.h b/src/gameobjs.h
deleted file mode 100644 (file)
index 3d928be..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-//  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-// 
-//  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.
-
-#ifndef SUPERTUX_GAMEOBJS_H
-#define SUPERTUX_GAMEOBJS_H
-
-#include "video/surface.h"
-#include "timer.h"
-#include "scene.h"
-#include "math/physic.h"
-#include "special/game_object.h"
-#include "special/moving_object.h"
-#include "serializable.h"
-#include "utils/lispwriter.h"
-
-/* Bounciness of distros: */
-#define NO_BOUNCE 0
-#define BOUNCE 1
-
-namespace SuperTux {
-class Sprite;
-}
-
-class BouncyCoin : public GameObject
-{
-public:
-  BouncyCoin(const Vector& pos);
-  ~BouncyCoin();
-  virtual void action(float elapsed_time);
-  virtual void draw(DrawingContext& context);
-
-private:
-  Sprite* sprite;
-  Vector position;
-  Timer2 timer;
-};
-
-class BrokenBrick : public GameObject
-{
-public:
-  BrokenBrick(Sprite* sprite, const Vector& pos, const Vector& movement);
-  ~BrokenBrick();
-
-  virtual void action(float elapsed_time);
-  virtual void draw(DrawingContext& context);
-
-private:
-  Timer2 timer;
-  Sprite* sprite;
-  Vector position;
-  Vector movement;
-};
-
-class FloatingText : public GameObject
-{
-public:
-  FloatingText(const Vector& pos, const std::string& text_);
-  FloatingText(const Vector& pos, int s);  // use this for score, for instance
-  
-  virtual void action(float elapsed_time);
-  virtual void draw(DrawingContext& context);
-
-private:
-  Vector position;
-  std::string text;
-  Timer2 timer;  
-};
-
-#if 0
-extern Sprite *img_trampoline;
-
-class Trampoline : public MovingObject, public Serializable
-{
-public:
-  Trampoline(LispReader& reader);
-  Trampoline(float x, float y);
-  virtual void write(LispWriter& writer);
-  virtual void action(float frame_ratio);
-  virtual void draw(DrawingContext& context);
-
-  virtual void collision(const MovingObject& other, int);
-  void collision(void *p_c_object, int c_object, CollisionType type);
-
-  Physic physic;
-  enum { M_NORMAL, M_HELD } mode;
-
- private:
-  float power;
-  unsigned int frame;
-};
-#endif
-
-extern Sprite *img_smoke_cloud;
-
-class SmokeCloud : public GameObject
-{
-public:
-  SmokeCloud(const Vector& pos);
-  
-  virtual void action(float elapsed_time);
-  virtual void draw(DrawingContext& context);
-
-private:
-  Timer2 timer;
-  Vector position;
-};
-
-class Particles : public GameObject
-{
-public:
-  Particles(const Vector& epicenter, int min_angle, int max_angle,
-            const Vector& initial_velocity, const Vector& acceleration,
-            int number, Color color, int size, float life_time, int drawing_layer);
-  ~Particles();
-  
-  virtual void action(float elapsed_time);
-  virtual void draw(DrawingContext& context);
-
-private:
-  Vector accel;
-  Timer2 timer;
-  bool live_forever;
-
-  Color color;
-  float size;
-  int drawing_layer;
-
-  struct Particle {
-    Vector pos, vel;
-//     float angle;
-    };
-  std::vector <Particle*> particles;
-};
-
-void load_object_gfx();
-void free_object_gfx();
-
-#endif 
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
index 88f0063..6960828 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "app/globals.h"
 #include "app/setup.h"
-#include "camera.h"
 #include "video/screen.h"
 #include "level.h"
 #include "math/physic.h"
 #include "tile.h"
 #include "utils/lispreader.h"
 #include "resources.h"
-#include "gameobjs.h"
 #include "utils/lispwriter.h"
-#include "tilemap.h"
+#include "object/gameobjs.h"
+#include "object/camera.h"
+#include "object/tilemap.h"
 
 using namespace std;
 
@@ -52,16 +52,6 @@ Level::Level()
 }
 
 void
-Level::create(const std::string& filename)
-{
-  Level level;
-  const size_t width = 25;
-  const size_t height = 19;
-  level.add_sector(Sector::create("main", width, height));
-  level.save(filename);
-}
-
-void
 Level::load(const std::string& filepath)
 {
   LispReader* level = LispReader::load(filepath, "supertux-level");
@@ -167,8 +157,10 @@ Level::~Level()
 void
 Level::do_vertical_flip()
 {
+#if 0
   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
     i->second->do_vertical_flip();
+#endif
 }
 
 void
@@ -242,10 +234,7 @@ Level::get_total_coins()
   int total_coins = 0;
   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
     TileMap* solids = i->second->solids;
-    if(!solids) {
-      std::cerr << "Sector '" << i->first << "' contains no solids!?!\n";
-      continue;
-    }
+    assert(solids != 0);
     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);
index d627d82..a264353 100644 (file)
@@ -54,7 +54,6 @@ public:
   // loads a levelfile
   void load(const std::string& filename);
   void save(const std::string& filename);
-  static void create(const std::string& filename);
 
   EndSequenceType get_end_sequence_type() const
   { return end_sequence_type; }
index c9b2320..d6d8a2e 100644 (file)
 #include "leveleditor.h"
 #include "resources.h"
 #include "tile.h"
-#include "tilemap.h"
 #include "tile_manager.h"
 #include "sector.h"
-#include "background.h"
 #include "gameloop.h"
-#include "gameobjs.h"
-#include "camera.h"
+#include "object/gameobjs.h"
+#include "object/camera.h"
+#include "object/tilemap.h"
+#include "object/background.h"
 
 LevelEditor::LevelEditor()
 {
@@ -288,7 +288,9 @@ while(SDL_PollEvent(&event))
         level_subset->description = create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).input;
         //FIXME: generate better level filenames
         level_subset->add_level(subset_name+'/'+"new_level.stl");
-        Level::create(level_subset->get_level_filename(0));
+        Level* newlevel = new Level();
+        newlevel->add_sector(create_sector("main", 25, 19));
+        newlevel->save(level_subset->get_level_filename(0));
         level_subset->save();
         
         load_level(0);
@@ -368,7 +370,9 @@ while(SDL_PollEvent(&event))
           if(confirm_dialog(NULL, str))
             {
             level_subset->add_level("new_level.stl");
-            Level::create(level_subset->get_level_filename(level_nb + 1));
+            Level* newlevel = new Level();
+            newlevel->add_sector(create_sector("main", 25, 19));
+            newlevel->save(level_subset->get_level_filename(level_nb + 1));
             level_subset->save();
             load_level(level_nb + 1);
             }
@@ -780,7 +784,7 @@ if(sector_ == NULL)
   {
   if(!confirm_dialog(NULL, _("No more sectors exist. Create another?")))
     return;
-  sector_ = Sector::create("new_sector",25,19);
+  sector_ = create_sector("new_sector",25,19);
   level->add_sector(sector_);
   }
 
@@ -1033,3 +1037,19 @@ for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
 show_grid = show_grid_t;
 mouse_cursor->set_state(MC_NORMAL);
 }
+
+Sector*
+LevelEditor::create_sector(const std::string& name, size_t width, size_t height)
+{
+  Sector* sector = new Sector;
+  sector->set_name(name);
+  
+  sector->add_object(new TileMap(LAYER_BACKGROUNDTILES, false, width, height));
+  sector->add_object(new TileMap(LAYER_TILES, true, width, height));
+  sector->add_object(new TileMap(LAYER_FOREGROUNDTILES, false, width, height));
+  sector->add_object(new Camera(sector));
+  sector->update_game_objects();
+  
+  return sector;
+}
+
index 32099a2..5867d88 100644 (file)
@@ -143,6 +143,9 @@ private:
   Vector selection_ini, selection_end;
 
   bool level_changed;
+
+private:
+  Sector* create_sector(const std::string& name, size_t width, size_t height);
 };
 
 #endif
index e74a854..bef8878 100644 (file)
 #define SUPERTUX_MISC_H
 
 #include "app/setup.h"
-#include "resources.h"
+#include "app/gettext.h"
 #include "gui/menu.h"
 #include "utils/configfile.h"
-#include "player.h"
 #include "title.h"
+#include "resources.h"
 #include "worldmap.h"
 #include "gameloop.h"
-#include "app/gettext.h"
+#include "object/player.h"
 
 class MyConfig : public Config
 {
diff --git a/src/object/background.cpp b/src/object/background.cpp
new file mode 100644 (file)
index 0000000..2d6cc41
--- /dev/null
@@ -0,0 +1,129 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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 <config.h>
+
+#include "background.h"
+#include "app/globals.h"
+#include "camera.h"
+#include "video/drawing_context.h"
+#include "utils/lispwriter.h"
+
+Background::Background()
+  : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
+{
+}
+
+Background::Background(LispReader& reader)
+  : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
+{
+  reader.read_int("layer", layer);
+  if(reader.read_string("image", imagefile) 
+      && reader.read_float("speed", speed)) {
+    set_image(imagefile, speed);
+  }
+
+  std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
+  if(reader.read_int_vector("top_color", bkgd_top_color) &&
+     reader.read_int_vector("bottom_color", bkgd_bottom_color))
+    set_gradient(Color(bkgd_top_color), Color(bkgd_bottom_color));
+}
+
+Background::~Background()
+{
+  delete image;
+}
+
+void
+Background::write(LispWriter& writer)
+{
+  if(type == INVALID)
+    return;
+    
+  writer.start_list("background");
+
+  if(type == IMAGE) {
+    writer.write_string("image", imagefile);
+    writer.write_float("speed", speed);
+  } else if(type == GRADIENT) {
+    std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
+    bkgd_top_color.push_back(gradient_top.red);
+    bkgd_top_color.push_back(gradient_top.green);
+    bkgd_top_color.push_back(gradient_top.blue);
+    bkgd_bottom_color.push_back(gradient_top.red);
+    bkgd_bottom_color.push_back(gradient_top.green);
+    bkgd_bottom_color.push_back(gradient_top.blue);
+    writer.write_int_vector("top_color", bkgd_top_color);
+    writer.write_int_vector("bottom_color", bkgd_bottom_color);
+  }
+  writer.write_int("layer", layer);
+  
+  writer.end_list("background");
+}
+
+void
+Background::action(float)
+{
+}
+
+void
+Background::set_image(const std::string& name, float speed)
+{
+  this->type = IMAGE;
+  this->imagefile = name;
+  this->speed = speed;
+
+  delete image;
+  image = new Surface(datadir + "/images/background/" + name, false);
+}
+
+void
+Background::set_gradient(Color top, Color bottom)
+{
+  type = GRADIENT;
+  gradient_top = top;
+  gradient_bottom = bottom;
+
+  delete image;
+  image = new Surface(top, bottom, screen->w, screen->h);
+}
+
+void
+Background::draw(DrawingContext& context)
+{
+  if(type == GRADIENT) {
+    context.push_transform();
+    context.set_translation(Vector(0, 0));
+    context.draw_surface(image, Vector(0, 0), layer);
+    context.pop_transform();
+  } else if(type == IMAGE) {
+    if(!image)
+      return;
+    
+    int sx = int(-context.get_translation().x * speed) % image->w - image->w;
+    int sy = int(-context.get_translation().y * speed) % image->h - image->h;
+    context.push_transform();
+    context.set_translation(Vector(0, 0));
+    for(int x = sx; x < screen->w; x += image->w)
+      for(int y = sy; y < screen->h; y += image->h)
+        context.draw_surface(image, Vector(x, y), layer);
+    context.pop_transform();
+  }
+}
+
diff --git a/src/object/background.h b/src/object/background.h
new file mode 100644 (file)
index 0000000..7ed3e83
--- /dev/null
@@ -0,0 +1,71 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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.
+
+#ifndef SUPERTUX_BACKGROUND_H
+#define SUPERTUX_BACKGROUND_H
+
+#include "video/surface.h"
+#include "video/drawing_context.h"
+#include "special/game_object.h"
+#include "utils/lispreader.h"
+#include "serializable.h"
+
+class DisplayManager;
+
+class Background : public GameObject, public Serializable
+{
+public:
+  Background();
+  Background(LispReader& reader);
+  virtual ~Background();
+
+  virtual void write(LispWriter& writer);
+
+  void set_image(const std::string& name, float bkgd_speed);
+
+  void set_gradient(Color top, Color bottom);
+
+  std::string get_image() const
+        { return imagefile; }
+  float get_speed() const
+        { return speed; }
+  Color get_gradient_top() const
+        { return gradient_top; }
+  Color get_gradient_bottom() const
+        { return gradient_bottom; }
+
+  virtual void action(float elapsed_time);
+
+  virtual void draw(DrawingContext& context);
+
+private:
+  enum Type {
+    INVALID, GRADIENT, IMAGE      
+  };
+  
+  Type type;
+  int layer;
+  std::string imagefile;
+  float speed;
+  Surface* image;
+  Color gradient_top, gradient_bottom;
+};
+
+#endif /*SUPERTUX_BACKGROUND_H*/
+
diff --git a/src/object/camera.cpp b/src/object/camera.cpp
new file mode 100644 (file)
index 0000000..b2f47ed
--- /dev/null
@@ -0,0 +1,291 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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 <config.h>
+
+#include <stdexcept>
+#include <sstream>
+#include <cmath>
+
+#include "camera.h"
+#include "utils/lispreader.h"
+#include "utils/lispwriter.h"
+#include "player.h"
+#include "tilemap.h"
+#include "gameloop.h"
+#include "app/globals.h"
+#include "sector.h"
+
+using namespace SuperTux;
+
+Camera::Camera(Sector* newsector)
+  : sector(newsector), do_backscrolling(true), scrollchange(NONE),
+    auto_idx(0), auto_t(0)
+{
+  mode = NORMAL;
+}
+
+Camera::~Camera()
+{
+}
+
+const Vector&
+Camera::get_translation() const
+{
+  return translation;
+}
+
+void
+Camera::parse(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 = 50;
+    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");
+  }
+                     
+  writer.end_list("camera");
+}
+
+void
+Camera::reset(const Vector& tuxpos)
+{
+  translation.x = tuxpos.x - screen->w/3 * 2;
+  translation.y = tuxpos.y - screen->h/2;
+  keep_in_bounds();
+}
+
+static const float EPSILON = .00001;
+static const float max_speed_y = 140;
+
+void
+Camera::action(float elapsed_time)
+{
+  if(mode == NORMAL)
+    scroll_normal(elapsed_time);
+  else if(mode == AUTOSCROLL)
+    scroll_autoscroll(elapsed_time);
+}
+
+void
+Camera::keep_in_bounds()
+{
+  float width = sector->solids->get_width() * 32;
+  float height = sector->solids->get_height() * 32;
+
+  // don't scroll before the start or after the level's end
+  if(translation.y > height - screen->h)
+    translation.y = height - screen->h;
+  if(translation.y < 0)                                      
+    translation.y = 0; 
+  if(translation.x > width - screen->w)
+    translation.x = width - screen->w;
+  if(translation.x < 0)
+    translation.x = 0;                                         
+}
+
+void
+Camera::scroll_normal(float elapsed_time)
+{
+  assert(sector != 0);
+  Player* player = sector->player;
+  
+  // check that we don't have division by zero later
+  if(elapsed_time < EPSILON)
+    return;
+
+  /****** Vertical Scrolling part ******/
+  bool do_y_scrolling = true;
+
+  if(player->dying || sector->solids->get_height() == 19)
+    do_y_scrolling = false;
+
+  if(do_y_scrolling) {
+    // target_y is the high we target our scrolling at. This is not always the
+    // high of the player, but if he is jumping upwards we should use the
+    // position where he last touched the ground. (this probably needs
+    // exceptions for trampolines and similar things in the future)
+    float target_y;
+    if(player->fall_mode == Player::JUMPING)
+      target_y = player->last_ground_y + player->get_bbox().get_height();
+    else
+      target_y = player->get_bbox().p2.y;
+
+    // delta_y is the distance we'd have to travel to directly reach target_y
+    float delta_y = translation.y - (target_y - screen->h/2);
+    // speed is the speed the camera would need to reach target_y in this frame
+    float speed_y = delta_y / elapsed_time;
+
+    // limit the camera speed when jumping upwards
+    if(player->fall_mode != Player::FALLING 
+        && player->fall_mode != Player::TRAMPOLINE_JUMP) {
+      if(speed_y > max_speed_y)
+        speed_y = max_speed_y;
+      else if(speed_y < -max_speed_y)
+        speed_y = -max_speed_y;
+    }
+
+    // finally scroll with calculated speed
+    translation.y -= speed_y * elapsed_time;
+  }
+
+  /****** Horizontal scrolling part *******/
+
+  // our camera is either in leftscrolling, rightscrolling or nonscrollingmode.
+  
+  // when suddenly changing directions while scrolling into the other direction.
+  // abort scrolling, since tux might be going left/right at a relatively small
+  // part of the map (like when jumping upwards)
+  if((player->dir == ::LEFT && scrollchange == RIGHT)
+      || (player->dir == ::RIGHT && scrollchange == LEFT))
+    scrollchange = NONE;
+  // when in left 1/3rd of screen scroll left
+  if(player->get_bbox().get_middle().x < translation.x + screen->w/3 - 16
+      && do_backscrolling)
+    scrollchange = LEFT;
+  // scroll right when in right 1/3rd of screen
+  else if(player->get_bbox().get_middle().x > translation.x + screen->w/3*2+16)
+    scrollchange = RIGHT;
+
+  // calculate our scroll target depending on scroll mode
+  float target_x;
+  if(scrollchange == LEFT)
+    target_x = player->get_bbox().get_middle().x - screen->w/3*2;
+  else if(scrollchange == RIGHT)
+    target_x = player->get_bbox().get_middle().x - screen->w/3;
+  else
+    target_x = translation.x;
+
+  // that's the distance we would have to travel to reach target_x
+  float delta_x = translation.x - target_x;
+  // the speed we'd need to travel to reach target_x in this frame
+  float speed_x = delta_x / elapsed_time;
+
+  // limit our speed
+  float maxv = 130 + (fabsf(player->physic.get_velocity_x() * 1.3));
+  if(speed_x > maxv)
+    speed_x = maxv;
+  else if(speed_x < -maxv)
+    speed_x = -maxv;
+  // apply scrolling
+  translation.x -= speed_x * elapsed_time;
+
+  keep_in_bounds();
+}
+
+void
+Camera::scroll_autoscroll(float elapsed_time)
+{
+  Player* player = sector->player;
+  
+  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();
+}
diff --git a/src/object/camera.h b/src/object/camera.h
new file mode 100644 (file)
index 0000000..2294aa9
--- /dev/null
@@ -0,0 +1,106 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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.
+
+#ifndef SUPERTUX_CAMERA_H
+#define SUPERTUX_CAMERA_H
+
+#include <vector>
+#include <cassert>
+
+#include "defines.h"
+#include "math/vector.h"
+#include "special/game_object.h"
+#include "video/drawing_context.h"
+#include "serializable.h"
+
+using namespace SuperTux;
+
+namespace SuperTux {
+class LispReader;
+}
+
+class Sector;
+
+class Camera : public GameObject, public Serializable
+{
+public:
+  Camera(Sector* sector);
+  virtual ~Camera();
+
+  /// parse camera mode from lisp file
+  void parse(LispReader& reader);
+  /// write camera mode to a lisp file
+  virtual void write(LispWriter& writer);
+
+  /// reset camera postion
+  virtual void reset(const Vector& tuxpos);
+
+  /** @deprecated@ */
+  const Vector& get_translation() const;
+
+  virtual void action(float elapsed_time);
+
+  virtual void draw(DrawingContext& )
+  {
+  }
+
+  void set_scrolling(int scroll_x, int scroll_y)
+  {
+    translation.x = scroll_x;
+    translation.y = scroll_y;
+  }
+
+  enum CameraMode
+  {
+    NORMAL, AUTOSCROLL, MANUAL
+  };
+  CameraMode mode;
+
+private:
+  void scroll_normal(float elapsed_time);
+  void scroll_autoscroll(float elapsed_time);
+  void keep_in_bounds();
+
+  enum LeftRightScrollChange
+  {
+    NONE, LEFT, RIGHT
+  };
+    
+  Vector translation;
+
+  Sector* sector;
+
+  // normal mode
+  bool do_backscrolling;
+  LeftRightScrollChange scrollchange;
+
+  // autoscroll mode
+  class ScrollPoint {
+  public:
+    Vector position;
+    float speed;
+  };
+  std::vector<ScrollPoint> scrollpoints;
+  size_t auto_idx;
+  float auto_t;
+  Vector current_dir;
+};
+
+#endif /*SUPERTUX_CAMERA_H*/
+
diff --git a/src/object/gameobjs.cpp b/src/object/gameobjs.cpp
new file mode 100644 (file)
index 0000000..3201eb2
--- /dev/null
@@ -0,0 +1,545 @@
+//  $Id$
+// 
+//  SuperTux
+//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  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 <config.h>
+
+#include <algorithm>
+#include <iostream>
+#include <cmath>
+
+#include "app/globals.h"
+#include "tile.h"
+#include "tile_manager.h"
+#include "gameloop.h"
+#include "gameobjs.h"
+#include "special/sprite_manager.h"
+#include "resources.h"
+#include "sector.h"
+#include "tilemap.h"
+#include "video/drawing_context.h"
+#include "camera.h"
+
+BouncyCoin::BouncyCoin(const Vector& pos)
+  : position(pos)
+{
+  timer.start(.3);
+  sprite = sprite_manager->create("coin");
+  sprite->set_action("still");
+}
+
+BouncyCoin::~BouncyCoin()
+{
+  delete sprite;
+}
+
+void
+BouncyCoin::action(float elapsed_time)
+{
+  position.y += -200 * elapsed_time;
+
+  if(timer.check())
+    remove_me();
+}
+
+void
+BouncyCoin::draw(DrawingContext& context)
+{
+  sprite->draw(context, position, LAYER_OBJECTS);
+}
+
+//---------------------------------------------------------------------------
+
+BrokenBrick::BrokenBrick(Sprite* nsprite,
+    const Vector& pos, const Vector& nmovement)
+  : sprite(new Sprite(*nsprite)), position(pos), movement(nmovement)
+{
+  timer.start(.2);
+}
+
+BrokenBrick::~BrokenBrick()
+{
+  delete sprite;
+}
+
+void
+BrokenBrick::action(float elapsed_time)
+{
+  position += movement * elapsed_time;
+
+  if (timer.check())
+    remove_me();
+}
+
+void
+BrokenBrick::draw(DrawingContext& context)
+{
+  sprite->draw_part(context,
+      Vector(rand() % 16, rand() % 16), Vector(16, 16),
+      position, LAYER_OBJECTS + 1);
+}
+
+//---------------------------------------------------------------------------
+
+FloatingText::FloatingText(const Vector& pos, const std::string& text_)
+  : position(pos), text(text_)
+{
+  timer.start(.1);
+  position.x -= text.size() * 8;
+}
+
+FloatingText::FloatingText(const Vector& pos, int score)
+  : position(pos)
+{
+  timer.start(.1);
+
+  // turn int into a string
+  char str[10];
+  snprintf(str, 10, "%d", score);
+  text = str;
+
+  position.x -= text.size() * 8;
+}
+
+void
+FloatingText::action(float elapsed_time)
+{
+  position.y -= 1.4 * elapsed_time;
+
+  if(timer.check())
+    remove_me();
+}
+
+#define FADING_TIME .350
+
+void
+FloatingText::draw(DrawingContext& context)
+{
+  // make an alpha animation when disapearing
+  int alpha;
+  if(timer.get_timeleft() < FADING_TIME)
+    alpha = int(timer.get_timeleft() * 255 / FADING_TIME);
+  else
+    alpha = 255;
+
+  context.push_transform();
+  context.set_alpha(alpha);
+
+  context.draw_text(gold_text, text, position, LEFT_ALLIGN, LAYER_OBJECTS+1);
+
+  context.pop_transform();
+}
+
+/* Trampoline */
+
+#if 0
+Sprite *img_trampoline;
+
+Trampoline::Trampoline(LispReader& reader)
+{
+  reader.read_float("x", base.x);
+  reader.read_float("y", base.y); 
+  base.width = 32;
+  base.height = 32;
+  power = 7.5;
+  reader.read_float("power", power);
+
+  frame = 0;
+  mode = M_NORMAL;
+  physic.reset();
+}
+
+Trampoline::Trampoline(float x, float y)
+{
+  base.x = x;
+  base.y = y;
+  base.width = 32;
+  base.height = 32;
+  power = 7.5;
+
+  frame = 0;
+  mode = M_NORMAL;
+  physic.reset();
+}
+
+void
+Trampoline::write(LispWriter& writer)
+{
+  writer.start_list("trampoline");
+
+  writer.write_float("x", base.x);
+  writer.write_float("y", base.y);
+  writer.write_float("power", power);
+
+  writer.end_list("trampoline");
+}
+
+void
+Trampoline::draw(DrawingContext& context)
+{
+  img_trampoline->set_frame(frame);
+  img_trampoline->draw(context, base, LAYER_OBJECTS);
+  frame = 0;
+}
+
+void
+Trampoline::action(float frame_ratio)
+{
+  // TODO: Remove if we're too far off the screen
+
+  // Falling
+  if (mode != M_HELD)
+  {
+    if (issolid(base.x + base.width/2, base.y + base.height))
+    {
+      base.y = int((base.y + base.height)/32) * 32 - base.height;
+
+      physic.enable_gravity(false);
+      physic.set_velocity_y(0.0f);
+
+      physic.set_velocity_x(0);
+    }
+    else
+    {
+      physic.enable_gravity(true);
+    }
+  }
+  else // Player is carrying us around
+  {
+    /* FIXME: The trampoline object shouldn't know about pplayer objects. */
+    /* If we're holding the iceblock */
+    Player& tux = *Sector::current()->player;
+    Direction dir = tux.dir;
+
+    if(dir == RIGHT)
+    {
+      base.x = tux.base.x + 16;
+      base.y = tux.base.y + tux.base.height/1.5 - base.height;
+    }
+    else /* facing left */
+    {
+      base.x = tux.base.x - 16;
+      base.y = tux.base.y + tux.base.height/1.5 - base.height;
+    }
+
+    if(collision_object_map(base))
+    {
+      base.x = tux.base.x;
+      base.y = tux.base.y + tux.base.height/1.5 - base.height;
+    }
+  }
+
+  physic.apply(frame_ratio, base.x, base.y, Sector::current()->gravity);
+  collision_swept_object_map(&old_base, &base);
+}
+
+void
+Trampoline::collision(const MovingObject&, int)
+{
+  // comes later
+}
+
+void
+Trampoline::collision(void *p_c_object, int c_object, CollisionType type)
+{
+  Player* pplayer_c = NULL;
+  switch (c_object)
+  {
+    case CO_PLAYER:
+      pplayer_c = (Player*) p_c_object;
+
+      if (type == COLLISION_NORMAL)
+      {
+        // Pick up if HELD (done in Player)
+      }
+
+      else if (type == COLLISION_SQUISH)
+      {
+        int squish_amount = (32 - (int)pplayer_c->base.y % 32);
+
+        if (squish_amount < 24)
+          frame = 3;
+        else if (squish_amount < 28)
+          frame = 2;
+        else if (squish_amount < 30)
+          frame = 1;
+        else
+          frame = 0;
+
+        if (squish_amount < 20) {
+          pplayer_c->physic.set_velocity_y(power);
+          pplayer_c->fall_mode = Player::TRAMPOLINE_JUMP;
+        }
+        else if (pplayer_c->physic.get_velocity_y() < 0)
+          pplayer_c->physic.set_velocity_y(-squish_amount/32);
+      }
+
+      break;
+
+    default:
+      break;
+    
+  }
+}
+#endif
+
+/* Flying Platform */
+
+#if 0
+Sprite *img_flying_platform;
+
+FlyingPlatform::FlyingPlatform(LispReader& reader)
+{
+  reader.read_int_vector("x", pos_x);
+  reader.read_int_vector("y", pos_y);
+
+  velocity = 2.0;
+  reader.read_float("velocity", velocity);
+
+  base.x = pos_x[0];
+  base.y = pos_y[0];
+  base.width = 96;
+  base.height = 40;
+
+  point = 0;
+  move = false;
+
+  float x = pos_x[point+1] - pos_x[point];
+  float y = pos_y[point+1] - pos_y[point];
+  vel_x = x*velocity / sqrt(x*x + y*y);
+  vel_y = -(velocity - vel_x);
+
+  frame = 0;
+}
+
+FlyingPlatform::FlyingPlatform(int x, int y)
+{
+base.x = x;
+base.y = y;
+point = 0;
+move = false;
+}
+
+void
+FlyingPlatform::write(LispWriter& writer)
+{
+  writer.start_list("flying-trampoline");
+
+  writer.write_int_vector("x", pos_x);
+  writer.write_int_vector("y", pos_y);
+  writer.write_float("velocity", velocity);
+
+  writer.end_list("flying-trampoline");
+}
+
+void
+FlyingPlatform::draw(DrawingContext& context)
+{
+  img_flying_platform->draw(context, base, LAYER_OBJECTS);
+}
+
+void
+FlyingPlatform::action(float frame_ratio)
+{
+  // TODO: Remove if we're too far off the screen
+
+if(!move)
+  return;
+
+if((unsigned)point+1 != pos_x.size())
+  {
+  if(((pos_x[point+1] > pos_x[point] && base.x >= pos_x[point+1]) ||
+      (pos_x[point+1] < pos_x[point] && base.x <= pos_x[point+1]) ||
+      pos_x[point] == pos_x[point+1]) &&
+    ((pos_y[point+1] > pos_y[point] && base.y >= pos_y[point+1]) ||
+      (pos_y[point+1] < pos_y[point] && base.y <= pos_y[point+1]) ||
+      pos_y[point] == pos_y[point+1]))
+    {
+    point++;
+
+    float x = pos_x[point+1] - pos_x[point];
+    float y = pos_y[point+1] - pos_y[point];
+    vel_x = x*velocity / sqrt(x*x + y*y);
+    vel_y = -(velocity - vel_x);
+    }
+  }
+else   // last point
+  {
+  // point = 0;
+  // reverse vector
+  return;
+  }
+/*
+if(pos_x[point+1] > base.x)
+  base.x += velocity * frame_ratio;
+else if(pos_x[point+1] < base.x)
+  base.x -= velocity * frame_ratio;
+
+if(pos_y[point+1] > base.y)
+  base.y += velocity * frame_ratio;
+else if(pos_y[point+1] < base.y)
+  base.y -= velocity * frame_ratio;
+*/
+
+base.x += vel_x * frame_ratio;
+base.y += vel_y * frame_ratio;
+}
+
+void
+FlyingPlatform::collision(const MovingObject&, int)
+{
+  // comes later
+}
+
+void
+FlyingPlatform::collision(void *p_c_object, int c_object, CollisionType type)
+{
+(void) p_c_object;
+(void) type;
+
+//  Player* pplayer_c = NULL;
+  switch (c_object)
+  {
+    case CO_PLAYER:
+//      pplayer_c = (Player*) p_c_object;
+      move = true;
+
+      break;
+
+    default:
+      break;
+    
+  }
+}
+#endif
+
+Sprite *img_smoke_cloud = 0;
+
+SmokeCloud::SmokeCloud(const Vector& pos)
+  : position(pos)
+{
+  timer.start(.3);
+}
+
+void
+SmokeCloud::action(float elapsed_time)
+{
+  position.y -= 120 * elapsed_time;
+
+  if(timer.check())
+    remove_me();
+}
+
+void
+SmokeCloud::draw(DrawingContext& context)
+{
+  img_smoke_cloud->draw(context, position, LAYER_OBJECTS+1);
+}
+
+Particles::Particles(const Vector& epicenter, int min_angle, int max_angle,
+        const Vector& initial_velocity, const Vector& acceleration, int number,
+        Color color_, int size_, float life_time, int drawing_layer_)
+  : accel(acceleration), color(color_), size(size_), drawing_layer(drawing_layer_)
+{
+  if(life_time == 0) {
+    live_forever = true;
+  } else {
+    live_forever = false;
+    timer.start(life_time);
+  }
+
+  // create particles
+  for(int p = 0; p < number; p++)
+    {
+    Particle* particle = new Particle;
+    particle->pos = epicenter;
+
+    float angle = ((rand() % (max_angle-min_angle))+min_angle)
+                      * (M_PI / 180);  // convert to radius
+    particle->vel.x = /*fabs*/(sin(angle)) * initial_velocity.x;
+//    if(angle >= M_PI && angle < M_PI*2)
+//      particle->vel.x *= -1;  // work around to fix signal
+    particle->vel.y = /*fabs*/(cos(angle)) * initial_velocity.y;
+//    if(angle >= M_PI_2 && angle < 3*M_PI_2)
+//      particle->vel.y *= -1;
+
+    particles.push_back(particle);
+    }
+}
+
+Particles::~Particles()
+{
+  // free particles
+  for(std::vector<Particle*>::iterator i = particles.begin();
+      i < particles.end(); i++)
+    delete (*i);
+}
+
+void
+Particles::action(float elapsed_time)
+{
+  Vector camera = Sector::current()->camera->get_translation();
+
+  // update particles
+  for(std::vector<Particle*>::iterator i = particles.begin();
+      i != particles.end(); ) {
+    (*i)->pos.x += (*i)->vel.x * elapsed_time;
+    (*i)->pos.y += (*i)->vel.y * elapsed_time;
+
+    (*i)->vel.x += accel.x * elapsed_time;
+    (*i)->vel.y += accel.y * elapsed_time;
+
+    if((*i)->pos.x < camera.x || (*i)->pos.x > screen->w + camera.x ||
+       (*i)->pos.y < camera.y || (*i)->pos.y > screen->h + camera.y) {
+      delete (*i);
+      i = particles.erase(i);
+    } else {
+      ++i;
+    }
+  }
+
+  if((timer.check() && !live_forever) || particles.size() == 0)
+    remove_me();
+}
+
+void
+Particles::draw(DrawingContext& context)
+{
+  // draw particles
+  for(std::vector<Particle*>::iterator i = particles.begin();
+      i != particles.end(); i++) {
+    context.draw_filled_rect((*i)->pos, Vector(size,size), color,drawing_layer);
+  }
+}
+
+void load_object_gfx()
+{
+#if 0
+  img_trampoline = sprite_manager->load("trampoline");
+  img_trampoline->start_animation(0);
+  img_flying_platform = sprite_manager->load("flying_platform");
+#endif
+  img_smoke_cloud = sprite_manager->create("stomp");
+}
+
+void free_object_gfx()
+{
+  delete img_smoke_cloud;
+}
+
diff --git a/src/object/gameobjs.h b/src/object/gameobjs.h
new file mode 100644 (file)
index 0000000..3d928be
--- /dev/null
@@ -0,0 +1,161 @@
+//  $Id$
+// 
+//  SuperTux
+//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  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.
+
+#ifndef SUPERTUX_GAMEOBJS_H
+#define SUPERTUX_GAMEOBJS_H
+
+#include "video/surface.h"
+#include "timer.h"
+#include "scene.h"
+#include "math/physic.h"
+#include "special/game_object.h"
+#include "special/moving_object.h"
+#include "serializable.h"
+#include "utils/lispwriter.h"
+
+/* Bounciness of distros: */
+#define NO_BOUNCE 0
+#define BOUNCE 1
+
+namespace SuperTux {
+class Sprite;
+}
+
+class BouncyCoin : public GameObject
+{
+public:
+  BouncyCoin(const Vector& pos);
+  ~BouncyCoin();
+  virtual void action(float elapsed_time);
+  virtual void draw(DrawingContext& context);
+
+private:
+  Sprite* sprite;
+  Vector position;
+  Timer2 timer;
+};
+
+class BrokenBrick : public GameObject
+{
+public:
+  BrokenBrick(Sprite* sprite, const Vector& pos, const Vector& movement);
+  ~BrokenBrick();
+
+  virtual void action(float elapsed_time);
+  virtual void draw(DrawingContext& context);
+
+private:
+  Timer2 timer;
+  Sprite* sprite;
+  Vector position;
+  Vector movement;
+};
+
+class FloatingText : public GameObject
+{
+public:
+  FloatingText(const Vector& pos, const std::string& text_);
+  FloatingText(const Vector& pos, int s);  // use this for score, for instance
+  
+  virtual void action(float elapsed_time);
+  virtual void draw(DrawingContext& context);
+
+private:
+  Vector position;
+  std::string text;
+  Timer2 timer;  
+};
+
+#if 0
+extern Sprite *img_trampoline;
+
+class Trampoline : public MovingObject, public Serializable
+{
+public:
+  Trampoline(LispReader& reader);
+  Trampoline(float x, float y);
+  virtual void write(LispWriter& writer);
+  virtual void action(float frame_ratio);
+  virtual void draw(DrawingContext& context);
+
+  virtual void collision(const MovingObject& other, int);
+  void collision(void *p_c_object, int c_object, CollisionType type);
+
+  Physic physic;
+  enum { M_NORMAL, M_HELD } mode;
+
+ private:
+  float power;
+  unsigned int frame;
+};
+#endif
+
+extern Sprite *img_smoke_cloud;
+
+class SmokeCloud : public GameObject
+{
+public:
+  SmokeCloud(const Vector& pos);
+  
+  virtual void action(float elapsed_time);
+  virtual void draw(DrawingContext& context);
+
+private:
+  Timer2 timer;
+  Vector position;
+};
+
+class Particles : public GameObject
+{
+public:
+  Particles(const Vector& epicenter, int min_angle, int max_angle,
+            const Vector& initial_velocity, const Vector& acceleration,
+            int number, Color color, int size, float life_time, int drawing_layer);
+  ~Particles();
+  
+  virtual void action(float elapsed_time);
+  virtual void draw(DrawingContext& context);
+
+private:
+  Vector accel;
+  Timer2 timer;
+  bool live_forever;
+
+  Color color;
+  float size;
+  int drawing_layer;
+
+  struct Particle {
+    Vector pos, vel;
+//     float angle;
+    };
+  std::vector <Particle*> particles;
+};
+
+void load_object_gfx();
+void free_object_gfx();
+
+#endif 
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
diff --git a/src/object/particlesystem.cpp b/src/object/particlesystem.cpp
new file mode 100644 (file)
index 0000000..b82152a
--- /dev/null
@@ -0,0 +1,176 @@
+//  $Id$
+// 
+//  SuperTux
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  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 <config.h>
+
+#include <iostream>
+#include <cmath>
+
+#include "particlesystem.h"
+#include "app/globals.h"
+#include "utils/lispreader.h"
+#include "utils/lispwriter.h"
+#include "video/drawing_context.h"
+
+ParticleSystem::ParticleSystem()
+{
+    virtual_width = screen->w;
+    virtual_height = screen->h;
+    layer = LAYER_BACKGROUND1;
+}
+
+ParticleSystem::~ParticleSystem()
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        delete *i;
+    }
+}
+
+void ParticleSystem::draw(DrawingContext& context)
+{
+  float scrollx = context.get_translation().x;
+  float scrolly = context.get_translation().y;
+
+  context.push_transform();
+  context.set_translation(Vector(0,0));
+  
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        Particle* particle = *i;
+
+        // remap x,y coordinates onto screencoordinates
+        Vector pos;
+        pos.x = fmodf(particle->pos.x - scrollx, virtual_width);
+        if(pos.x < 0) pos.x += virtual_width;
+        pos.y = fmodf(particle->pos.y - scrolly, virtual_height);
+        if(pos.y < 0) pos.y += virtual_height;
+
+        if(pos.x > screen->w) pos.x -= virtual_width;
+        if(pos.y > screen->h) pos.y -= virtual_height;
+        context.draw_surface(particle->texture, pos, layer);
+    }
+
+    context.pop_transform();
+}
+
+SnowParticleSystem::SnowParticleSystem()
+{
+    snowimages[0] = new Surface(datadir+"/images/shared/snow0.png", true);
+    snowimages[1] = new Surface(datadir+"/images/shared/snow1.png", true);
+    snowimages[2] = new Surface(datadir+"/images/shared/snow2.png", true);
+
+    virtual_width = screen->w * 2;
+
+    // create some random snowflakes
+    size_t snowflakecount = size_t(virtual_width/10.0);
+    for(size_t i=0; i<snowflakecount; ++i) {
+        SnowParticle* particle = new SnowParticle;
+        particle->pos.x = rand() % int(virtual_width);
+        particle->pos.y = rand() % screen->h;
+        int snowsize = rand() % 3;
+        particle->texture = snowimages[snowsize];
+        do {
+            particle->speed = snowsize*.2 + (float(rand()%10)*.4);
+        } while(particle->speed < 1);
+        particle->speed *= 10; // gravity
+
+        particles.push_back(particle);
+    }
+}
+
+void
+SnowParticleSystem::parse(LispReader& reader)
+{
+  reader.read_int("layer", layer);
+}
+
+void
+SnowParticleSystem::write(LispWriter& writer)
+{
+  writer.start_list("particles-snow");
+  writer.write_int("layer", layer);
+  writer.end_list("particles-snow");
+}
+
+SnowParticleSystem::~SnowParticleSystem()
+{
+  for(int i=0;i<3;++i)
+    delete snowimages[i];
+}
+
+void SnowParticleSystem::action(float elapsed_time)
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        SnowParticle* particle = (SnowParticle*) *i;
+        particle->pos.y += particle->speed * elapsed_time;
+        if(particle->pos.y > screen->h) {
+            particle->pos.y = fmodf(particle->pos.y , virtual_height);
+            particle->pos.x = rand() % int(virtual_width);
+        }
+    }
+}
+
+CloudParticleSystem::CloudParticleSystem()
+{
+    cloudimage = new Surface(datadir + "/images/shared/cloud.png", true);
+
+    virtual_width = 2000.0;
+
+    // create some random clouds
+    for(size_t i=0; i<15; ++i) {
+        CloudParticle* particle = new CloudParticle;
+        particle->pos.x = rand() % int(virtual_width);
+        particle->pos.y = rand() % int(virtual_height);
+        particle->texture = cloudimage;
+        particle->speed = -float(25 + rand() % 30);
+
+        particles.push_back(particle);
+    }
+}
+
+void
+CloudParticleSystem::parse(LispReader& reader)
+{
+  reader.read_int("layer", layer);
+}
+
+void
+CloudParticleSystem::write(LispWriter& writer)
+{
+  writer.start_list("particles-clouds");
+  writer.write_int("layer", layer);
+  writer.end_list("particles-clouds");
+}
+
+CloudParticleSystem::~CloudParticleSystem()
+{
+  delete cloudimage;
+}
+
+void CloudParticleSystem::action(float elapsed_time)
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        CloudParticle* particle = (CloudParticle*) *i;
+        particle->pos.x += particle->speed * elapsed_time;
+    }
+}
diff --git a/src/object/particlesystem.h b/src/object/particlesystem.h
new file mode 100644 (file)
index 0000000..d11c5c1
--- /dev/null
@@ -0,0 +1,126 @@
+//  $Id$
+// 
+//  SuperTux
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  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.
+
+#ifndef SUPERTUX_PARTICLESYSTEM_H
+#define SUPERTUX_PARTICLESYSTEM_H
+
+#include <vector>
+
+#include "video/surface.h"
+#include "special/game_object.h"
+#include "serializable.h"
+
+using namespace SuperTux;
+
+namespace SuperTux {
+class LispReader;
+}
+
+class DisplayManager;
+
+/**
+ * This is the base class for particle systems. It is responsible for storing a
+ * set of particles with each having an x- and y-coordinate the number of the
+ * layer where it should be drawn and a texture.
+ * The coordinate system used here is a virtual one. It would be a bad idea to
+ * populate whole levels with particles. So we're using a virtual rectangle
+ * here that is tiled onto the level when drawing. This rectangle has the size
+ * (virtual_width, virtual_height). We're using modulo on the particle
+ * coordinates, so when a particle leaves left, it'll reenter at the right
+ * side.
+ *
+ * Classes that implement a particle system should subclass from this class,
+ * initialize particles in the constructor and move them in the simulate
+ * function.
+ */
+class ParticleSystem : public GameObject
+{
+public:
+    ParticleSystem();
+    virtual ~ParticleSystem();
+    
+    virtual void draw(DrawingContext& context);
+
+protected:
+    int layer;
+
+    class Particle
+    {
+    public:
+        virtual ~Particle()
+        { }
+
+        Vector pos;
+        Surface* texture;
+    };
+    
+    std::vector<Particle*> particles;
+    float virtual_width, virtual_height;
+};
+
+class SnowParticleSystem : public ParticleSystem, public Serializable
+{
+public:
+    SnowParticleSystem();
+    virtual ~SnowParticleSystem();
+
+    void parse(LispReader& reader);
+    void write(LispWriter& writer);
+
+    virtual void action(float elapsed_time);
+
+    std::string type() const
+    { return "SnowParticleSystem"; }
+    
+private:
+    class SnowParticle : public Particle
+    {
+    public:
+        float speed;
+    };
+    
+    Surface* snowimages[3];
+};
+
+class CloudParticleSystem : public ParticleSystem, public Serializable
+{
+public:
+    CloudParticleSystem();
+    virtual ~CloudParticleSystem();
+
+    void parse(LispReader& reader);
+    void write(LispWriter& writer);
+
+    virtual void action(float elapsed_time);
+
+    std::string type() const
+    { return "SnowParticleSystem"; }    
+    
+private:
+    class CloudParticle : public Particle
+    {
+    public:
+        float speed;
+    };
+    
+    Surface* cloudimage;
+};
+
+#endif
+
diff --git a/src/object/player.cpp b/src/object/player.cpp
new file mode 100644 (file)
index 0000000..11a6ae2
--- /dev/null
@@ -0,0 +1,1018 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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 <config.h>
+
+#include <typeinfo>
+#include <cmath>
+#include <iostream>
+#include <cassert>
+
+#include "app/globals.h"
+#include "app/gettext.h"
+#include "player.h"
+#include "defines.h"
+#include "scene.h"
+#include "tile.h"
+#include "special/sprite.h"
+#include "sector.h"
+#include "resources.h"
+#include "video/screen.h"
+#include "statistics.h"
+#include "gameloop.h"
+#include "object/tilemap.h"
+#include "object/camera.h"
+#include "object/gameobjs.h"
+#include "trigger/trigger_base.h"
+
+static const int TILES_FOR_BUTTJUMP = 3;
+static const float SHOOTING_TIME = .150;
+/// time before idle animation starts
+static const float IDLE_TIME = 2.5;
+
+static const float WALK_ACCELERATION_X = 300;
+static const float RUN_ACCELERATION_X = 400;
+static const float SKID_XM = 200;
+static const float SKID_TIME = .3;
+static const float MAX_WALK_XM = 230;
+static const float MAX_RUN_XM = 320;
+static const float WALK_SPEED = 100;
+
+// growing animation
+Surface* growingtux_left[GROWING_FRAMES];
+Surface* growingtux_right[GROWING_FRAMES];
+
+Surface* tux_life = 0;
+
+Sprite* smalltux_gameover = 0;
+Sprite* smalltux_star = 0;
+Sprite* bigtux_star = 0;
+
+TuxBodyParts* small_tux = 0;
+TuxBodyParts* big_tux = 0;
+TuxBodyParts* fire_tux = 0;
+TuxBodyParts* ice_tux = 0;
+
+PlayerKeymap keymap;
+
+PlayerKeymap::PlayerKeymap()
+{
+  keymap.up    = SDLK_UP;
+  keymap.down  = SDLK_DOWN;
+  keymap.left  = SDLK_LEFT;
+  keymap.right = SDLK_RIGHT;
+
+  keymap.power = SDLK_LCTRL;
+  keymap.jump  = SDLK_SPACE;
+}
+
+void player_input_init(player_input_type* pplayer_input)
+{
+  pplayer_input->up = UP;
+  pplayer_input->old_up = UP;
+  pplayer_input->down = UP;
+  pplayer_input->fire = UP;
+  pplayer_input->left = UP;
+  pplayer_input->old_fire = UP;
+  pplayer_input->right = UP;
+  pplayer_input->jump = UP;
+  pplayer_input->old_jump = UP;
+  pplayer_input->activate = UP;
+}
+
+void
+TuxBodyParts::set_action(std::string action, int loops)
+{
+  if(head != NULL)
+    head->set_action(action, loops);
+  if(body != NULL)
+    body->set_action(action, loops);
+  if(arms != NULL)
+    arms->set_action(action, loops);
+  if(feet != NULL)
+    feet->set_action(action, loops);
+}
+
+void
+TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer,
+                  Uint32 drawing_effect)
+{
+  if(head != NULL)
+    head->draw(context, pos, layer-1, drawing_effect);
+  if(body != NULL)
+    body->draw(context, pos, layer-3, drawing_effect);
+  if(arms != NULL)
+    arms->draw(context, pos, layer,   drawing_effect);
+  if(feet != NULL)
+    feet->draw(context, pos, layer-2, drawing_effect);
+}
+
+Player::Player()
+{
+  init();
+}
+
+Player::~Player()
+{
+}
+
+void
+Player::init()
+{
+  holding_something = false;
+
+  bbox.set_size(31.8, 31.8);
+
+  size = SMALL;
+  got_power = NONE_POWER;
+
+  dir = RIGHT;
+  old_dir = dir;
+  duck = false;
+  dead = false;
+
+  dying   = DYING_NOT;
+  last_ground_y = 0;
+  fall_mode = ON_GROUND;
+  jumping = false;
+  flapping = false;
+  can_jump = true;
+  can_flap = false;
+  falling_from_flap = false;
+  enable_hover = false;
+  butt_jump = false;
+  
+  flapping_velocity = 0;
+
+  // temporary to help player's choosing a flapping
+  flapping_mode = MAREK_FLAP;
+
+  // Ricardo's flapping
+  flaps_nb = 0;
+
+  on_ground_flag = false;
+
+  player_input_init(&input);
+
+  physic.reset();
+}
+
+int
+Player::key_event(SDLKey key, int state)
+{
+  idle_timer.start(IDLE_TIME, true);
+
+  if(key == keymap.right)
+    {
+      input.right = state;
+      return true;
+    }
+  else if(key == keymap.left)
+    {
+      input.left = state;
+      return true;
+    }
+  else if(key == keymap.up)
+    {
+      if(state == UP)
+        input.old_up = UP;
+      input.up = state;
+      /* Up key also opens activates stuff */
+      input.activate = state;
+      return true;
+    }
+  else if(key == keymap.down)
+    {
+      input.down = state;
+      return true;
+    }
+  else if(key == keymap.power)
+    {
+      if (state == UP)
+        input.old_fire = UP;
+      input.fire = state;
+
+      return true;
+    }
+  else if(key == keymap.jump)
+    {
+      if (state == UP)
+        input.old_jump = UP;
+      input.jump = state;
+      return true;
+    }
+  else
+    return false;
+}
+
+void
+Player::level_begin()
+{
+  move(Vector(100, 170));
+  duck = false;
+
+  dying = DYING_NOT;
+
+  player_input_init(&input);
+
+  on_ground_flag = false;
+
+  physic.reset();
+}
+
+PlayerStatus&
+Player::get_status()
+{
+  return player_status;
+}
+
+void
+Player::action(float elapsed_time)
+{
+  if(dying && dying_timer.check()) {
+    dead = true;
+    return;
+  }
+
+  if (input.fire == UP)
+    holding_something = false;
+
+  if(dying == DYING_NOT)
+    handle_input();
+
+  movement = physic.get_movement(elapsed_time);
+
+#if 0
+      // special exception for cases where we're stuck under tiles after
+      // being ducked. In this case we drift out
+      if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
+         && collision_object_map(base))
+        {
+          base.x += elapsed_time * WALK_SPEED * (dir ? 1: -1);
+          previous_base = old_base = base;
+        }
+
+      /* Reset score multiplier (for multi-hits): */
+      if (!invincible_timer.started())
+            {
+            if(player_status.score_multiplier > player_status.max_score_multiplier)
+              {
+              player_status.max_score_multiplier = player_status.score_multiplier;
+
+              // show a message
+              char str[124];
+              sprintf(str, _("New max combo: %d"), player_status.max_score_multiplier-1);
+              Sector::current()->add_floating_text(base, str);
+              }
+            player_status.score_multiplier = 1;
+            }
+        }
+
+    }
+#endif
+
+  on_ground_flag = false;
+}
+
+bool
+Player::on_ground()
+{
+  return on_ground_flag;
+}
+
+void
+Player::handle_horizontal_input()
+{
+  float vx = physic.get_velocity_x();
+  float vy = physic.get_velocity_y();
+  float ax = physic.get_acceleration_x();
+  float ay = physic.get_acceleration_y();
+
+  float dirsign = 0;
+  if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
+      old_dir = dir;
+      dir = LEFT;
+      dirsign = -1;
+  } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
+      old_dir = dir;
+      dir = RIGHT;
+      dirsign = 1;
+  }
+
+  if (input.fire == UP) {
+      ax = dirsign * WALK_ACCELERATION_X;
+      // limit speed
+      if(vx >= MAX_WALK_XM && dirsign > 0) {
+        vx = MAX_WALK_XM;
+        ax = 0;
+      } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
+        vx = -MAX_WALK_XM;
+        ax = 0;
+      }
+  } else {
+      ax = dirsign * RUN_ACCELERATION_X;
+      // limit speed
+      if(vx >= MAX_RUN_XM && dirsign > 0) {
+        vx = MAX_RUN_XM;
+        ax = 0;
+      } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
+        vx = -MAX_RUN_XM;
+        ax = 0;
+      }
+  }
+
+  // we can reach WALK_SPEED without any acceleration
+  if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
+    vx = dirsign * WALK_SPEED;
+  }
+
+  // changing directions?
+  if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0)))
+    {
+      // let's skid!
+      if(fabs(vx)>SKID_XM && !skidding_timer.started())
+        {
+          skidding_timer.start(SKID_TIME);
+          SoundManager::get()->play_sound(IDToSound(SND_SKID));
+          // dust some partcles
+          Sector::current()->add_object(
+              new Particles(
+                Vector(bbox.p1.x + (dir == RIGHT ? bbox.get_width() : 0),
+                bbox.p2.y),
+              dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
+              Vector(280,-260), Vector(0,0.030), 3, Color(100,100,100), 3, .8,
+              LAYER_OBJECTS+1));
+
+          ax *= 2.5;
+        }
+      else
+        {
+          ax *= 2;
+        }
+    }
+
+  // we get slower when not pressing any keys
+  if(dirsign == 0) {
+      if(fabs(vx) < WALK_SPEED) {
+          vx = 0;
+          ax = 0;
+      } else if(vx < 0) {
+          ax = WALK_ACCELERATION_X * 1.5;
+      } else {
+          ax = WALK_ACCELERATION_X * -1.5;
+      }
+  }
+
+#if 0
+  // if we're on ice slow down acceleration or deceleration
+  if (isice(base.x, base.y + base.height))
+  {
+    /* the acceleration/deceleration rate on ice is inversely proportional to
+     * the current velocity.
+     */
+
+    // increasing 1 will increase acceleration/deceleration rate
+    // decreasing 1 will decrease acceleration/deceleration rate
+    //  must stay above zero, though
+    if (ax != 0) ax *= 1 / fabs(vx);
+  }
+#endif
+
+  // extend/shrink tux collision rectangle so that we fall through/walk over 1
+  // tile holes
+  if(fabsf(vx) > MAX_WALK_XM) {
+    bbox.set_width(33);
+  } else {
+    bbox.set_width(31.8);
+  }
+
+  physic.set_velocity(vx, vy);
+  physic.set_acceleration(ax, ay);
+}
+
+void
+Player::handle_vertical_input()
+{
+  // set fall mode...
+  if(on_ground()) {
+    fall_mode = ON_GROUND;
+    last_ground_y = get_pos().y;
+  } else {
+    if(get_pos().y > last_ground_y)
+      fall_mode = FALLING;
+    else if(fall_mode == ON_GROUND)
+      fall_mode = JUMPING;
+  }
+
+  if(on_ground()) { /* Make sure jumping is off. */
+    jumping = false;
+    flapping = false;
+    falling_from_flap = false;
+    if (flapping_timer.started()) {
+      flapping_timer.start(0);
+    }
+
+    physic.set_acceleration_y(0); //for flapping
+  }
+
+  // Press jump key
+  if(input.jump == DOWN && can_jump && on_ground())
+    {
+      if(duck) { // only jump a little bit when in duck mode {
+        physic.set_velocity_y(300);
+      } else {
+        // jump higher if we are running
+        if (fabs(physic.get_velocity_x()) > MAX_WALK_XM)
+          physic.set_velocity_y(580);
+        else
+          physic.set_velocity_y(520);
+      }
+
+      //bbox.move(Vector(0, -1));
+      jumping = true;
+      flapping = false;
+      can_jump = false;
+      can_flap = false;
+      flaps_nb = 0; // Ricardo's flapping
+      if (size == SMALL)
+        SoundManager::get()->play_sound(IDToSound(SND_JUMP));
+      else
+        SoundManager::get()->play_sound(IDToSound(SND_BIGJUMP));
+    }
+  // Let go of jump key
+  else if(input.jump == UP)
+    {
+      if (!flapping && !duck && !falling_from_flap && !on_ground())
+         {
+            can_flap = true;
+         }
+      if (jumping && physic.get_velocity_y() > 0)
+         {
+            jumping = false;
+            physic.set_velocity_y(0);
+         }
+    }
+
+ // temporary to help player's choosing a flapping
+ if(flapping_mode == RICARDO_FLAP)
+   {
+   // Flapping, Ricardo's version
+   // similar to SM3 Fox
+   if(input.jump == DOWN && input.old_jump == UP && can_flap &&
+     flaps_nb < 3)
+     {
+       physic.set_velocity_y(350);
+       physic.set_velocity_x(physic.get_velocity_x() * 35);
+       flaps_nb++;
+     }
+   }
+  else if(flapping_mode == MAREK_FLAP)
+   {
+   // Flapping, Marek's version
+   if (input.jump == DOWN && can_flap)
+     {
+         if (!flapping_timer.started())
+            {
+               flapping_timer.start(TUX_FLAPPING_TIME);
+               flapping_velocity = physic.get_velocity_x();
+            }
+         if (flapping_timer.check()) 
+            {
+               can_flap = false;
+               falling_from_flap = true;
+            }
+         jumping = true;
+         flapping = true;
+         if (!flapping_timer.check()) {
+           float cv = flapping_velocity * sqrt(
+               TUX_FLAPPING_TIME - flapping_timer.get_timegone() 
+               / TUX_FLAPPING_TIME);
+
+           //Handle change of direction while flapping
+           if (((dir == LEFT) && (cv > 0)) || (dir == RIGHT) && (cv < 0)) {
+             cv *= (-1);
+           }
+           physic.set_velocity_x(cv);
+           physic.set_velocity_y(
+               flapping_timer.get_timegone()/.850);
+         }
+     }
+   }
+  else if(flapping_mode == RYAN_FLAP)
+   {
+   // Flapping, Ryan's version
+   if (input.jump == DOWN && can_flap)
+     {
+         if (!flapping_timer.started())
+            {
+               flapping_timer.start(TUX_FLAPPING_TIME);
+            }
+         if (flapping_timer.check()) 
+            {
+               can_flap = false;
+               falling_from_flap = true;
+            }
+         jumping = true;
+         flapping = true;
+         if (flapping && flapping_timer.get_timegone() <= TUX_FLAPPING_TIME
+                && physic.get_velocity_y() < 0)
+            {
+               float gravity = Sector::current()->gravity;
+               (void)gravity;
+               float xr = (fabsf(physic.get_velocity_x()) / MAX_RUN_XM);
+
+               // XXX: magic numbers. should be a percent of gravity
+               //      gravity is (by default) -0.1f
+               physic.set_acceleration_y(12 + 1*xr);
+
+#if 0
+               // To slow down x-vel when flapping (not working)
+               if (fabsf(physic.get_velocity_x()) > MAX_WALK_XM)
+               {
+                   if (physic.get_velocity_x() < 0)
+                       physic.set_acceleration_x(1.0f);
+                   else if (physic.get_velocity_x() > 0)
+                       physic.set_acceleration_x(-1.0f);
+               }
+#endif
+            }
+     }
+    else
+     {
+        physic.set_acceleration_y(0);
+     }
+   }
+
+   // Hover
+   //(disabled by default, use cheat code "hover" to toggle on/off)
+   //TODO: needs some tweaking, especially when used together with double jump and jumping off badguys
+   if (enable_hover && input.jump == DOWN && !jumping && !butt_jump && physic.get_velocity_y() <= 0)
+      {
+         physic.set_velocity_y(-100);
+      }
+
+#if 0
+   /* In case the player has pressed Down while in a certain range of air,
+      enable butt jump action */
+  if (input.down == DOWN && !butt_jump && !duck)
+    if(tiles_on_air(TILES_FOR_BUTTJUMP) && jumping)
+      butt_jump = true;
+#endif
+
+   /* When Down is not held anymore, disable butt jump */
+  if(butt_jump && input.down == UP)
+    butt_jump = false;
+
+  // Do butt jump
+  if (butt_jump && on_ground() && size == BIG)
+  {
+    // Add a smoke cloud
+    if (duck) 
+      Sector::current()->add_smoke_cloud(Vector(get_pos().x - 32, get_pos().y));
+    else 
+      Sector::current()->add_smoke_cloud(
+          Vector(get_pos().x - 32, get_pos().y + 32));
+    
+    butt_jump = false;
+
+#if 0
+    // Break bricks beneath Tux
+    if(Sector::current()->trybreakbrick(
+          Vector(base.x + 1, base.y + base.height), false)
+        || Sector::current()->trybreakbrick(
+           Vector(base.x + base.width - 1, base.y + base.height), false))
+    {
+      physic.set_velocity_y(2);
+      butt_jump = true;
+    }
+#endif
+
+#if 0
+    // Kill nearby badguys
+    std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
+    for (std::vector<GameObject*>::iterator i = gameobjects.begin();
+         i != gameobjects.end();
+         i++)
+    {
+      BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
+      if(badguy)
+      {
+        // don't kill when badguys are already dying or in a certain mode
+        if(badguy->dying == DYING_NOT && badguy->mode != BadGuy::BOMB_TICKING &&
+           badguy->mode != BadGuy::BOMB_EXPLODE)
+          {
+            if (fabsf(base.x - badguy->base.x) < 96 &&
+                fabsf(base.y - badguy->base.y) < 64)
+              badguy->kill_me(25);
+          }
+      }
+    }
+#endif
+  }
+
+  /** jumping is only allowed if we're about to touch ground soon and if the
+   * button has been up in between the last jump
+   */
+  // FIXME
+#if 0
+  if ( (issolid(get_pos().x + bbox.get_width() / 2,
+          get_pos().y + bbox.get_height() + 64) ||
+        issolid(get_pos().x + 1, get_pos().y + bbox.get_height() + 64) ||
+        issolid(get_pos().x + bbox.get_width() - 1,
+          get_pos().y + bbox.get_height() + 64))
+       && jumping  == false
+       && can_jump == false
+       && input.jump == DOWN
+       && input.old_jump == UP)
+    {
+      can_jump = true;
+    }
+#endif
+
+  input.old_jump = input.jump;
+}
+
+void
+Player::handle_input()
+{
+  /* Handle horizontal movement: */
+  handle_horizontal_input();
+
+  /* Jump/jumping? */
+  if (on_ground() && input.jump == UP)
+    can_jump = true;
+  handle_vertical_input();
+
+  /* Shoot! */
+  if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER) {
+    if(Sector::current()->add_bullet(
+          get_pos() + Vector(0, bbox.get_height()/2),
+          physic.get_velocity_x(), dir))
+      shooting_timer.start(SHOOTING_TIME);
+    input.old_fire = DOWN;
+  }
+
+  /* Duck! */
+  if (input.down == DOWN && size == BIG && !duck 
+      && physic.get_velocity_y() == 0 && on_ground())
+    {
+      duck = true;
+      bbox.move(Vector(0, 32));
+      bbox.set_height(31.8);
+    }
+  else if(input.down == UP && size == BIG && duck)
+    {
+      // try if we can really unduck
+      bbox.move(Vector(0, -32));
+      bbox.set_height(63.8);
+      duck = false;
+      // FIXME
+#if 0
+      // when unducking in air we need some space to do so
+      if(on_ground() || !collision_object_map(bbox)) {
+        duck = false;
+      } else {
+        // undo the ducking changes
+        bbox.move(Vector(0, 32));
+        bbox.set_height(31.8);
+      }
+#endif
+    }
+}
+
+void
+Player::grow(bool animate)
+{
+  if(size == BIG)
+    return;
+  
+  size = BIG;
+  bbox.set_height(63.8);
+  bbox.move(Vector(0, -32));
+
+  if(animate)
+    growing_timer.start(GROWING_TIME);
+}
+
+void
+Player::grabdistros()
+{
+}
+
+void
+Player::draw(DrawingContext& context)
+{
+  TuxBodyParts* tux_body;
+          
+  if (size == SMALL)
+    tux_body = small_tux;
+  else if (got_power == FIRE_POWER)
+    tux_body = fire_tux;
+  else if (got_power == ICE_POWER)
+    tux_body = ice_tux;
+  else
+    tux_body = big_tux;
+
+  int layer = LAYER_OBJECTS + 10;
+
+  /* Set Tux sprite action */
+  if (duck && size == BIG)
+    {
+    if(dir == LEFT)
+      tux_body->set_action("duck-left");
+    else // dir == RIGHT
+      tux_body->set_action("duck-right");
+    }
+  else if (skidding_timer.started() && !skidding_timer.check())
+    {
+    if(dir == LEFT)
+      tux_body->set_action("skid-left");
+    else // dir == RIGHT
+      tux_body->set_action("skid-right");
+    }
+  else if (kick_timer.started() && !kick_timer.check())
+    {
+    if(dir == LEFT)
+      tux_body->set_action("kick-left");
+    else // dir == RIGHT
+      tux_body->set_action("kick-right");
+    }
+  else if (butt_jump && size == BIG)
+    {
+    if(dir == LEFT)
+      tux_body->set_action("buttjump-left");
+    else // dir == RIGHT
+      tux_body->set_action("buttjump-right");
+    }
+  else if (physic.get_velocity_y() != 0)
+    {
+    if(dir == LEFT)
+      tux_body->set_action("jump-left");
+    else // dir == RIGHT
+      tux_body->set_action("jump-right");
+    }
+  else
+    {
+    if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
+      {
+      if(dir == LEFT)
+        tux_body->set_action("stand-left");
+      else // dir == RIGHT
+        tux_body->set_action("stand-right");
+      }
+    else // moving
+      {
+      if(dir == LEFT)
+        tux_body->set_action("walk-left");
+      else // dir == RIGHT
+        tux_body->set_action("walk-right");
+      }
+    }
+
+  if(idle_timer.check())
+    {
+    if(size == BIG)
+      {
+      if(dir == LEFT)
+        tux_body->head->set_action("idle-left", 1);
+      else // dir == RIGHT
+        tux_body->head->set_action("idle-right", 1);
+      }
+
+    }
+
+  // Tux is holding something
+  if ((holding_something && physic.get_velocity_y() == 0) ||
+      (shooting_timer.get_timeleft() > 0 && !shooting_timer.check()))
+    {
+    if (duck)
+      {
+      if(dir == LEFT)
+        tux_body->arms->set_action("duck+grab-left");
+      else // dir == RIGHT
+        tux_body->arms->set_action("duck+grab-right");
+      }
+    else
+      {
+      if(dir == LEFT)
+        tux_body->arms->set_action("grab-left");
+      else // dir == RIGHT
+        tux_body->arms->set_action("grab-right");
+      }
+    }
+
+  /* Draw Tux */
+  if (dying == DYING_SQUISHED) {
+    smalltux_gameover->draw(context, get_pos(), LAYER_FOREGROUNDTILES+1);
+  } else if(growing_timer.get_timeleft() > 0) {
+    if(size == SMALL)
+      {
+      if (dir == RIGHT)
+        context.draw_surface(growingtux_right[GROWING_FRAMES-1 - 
+                 int((growing_timer.get_timegone() *
+                 GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
+      else
+        context.draw_surface(growingtux_left[GROWING_FRAMES-1 - 
+                int((growing_timer.get_timegone() *
+                GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
+      }
+    else
+      {
+      if (dir == RIGHT)
+        context.draw_surface(growingtux_right[
+            int((growing_timer.get_timegone() *
+                GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
+      else
+        context.draw_surface(growingtux_left[
+            int((growing_timer.get_timegone() *
+                             GROWING_FRAMES) / GROWING_TIME)],
+            get_pos(), layer);
+      }
+    }
+  else if (safe_timer.started() && size_t(global_time*40)%2)
+    ;  // don't draw Tux
+  else
+    tux_body->draw(context, get_pos(), layer);
+
+  // Draw blinking star overlay
+  if (invincible_timer.started() &&
+     (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING
+      || size_t(global_time*20)%2)
+     && !dying)
+  {
+    if (size == SMALL || duck)
+      smalltux_star->draw(context, get_pos(), layer + 5);
+    else
+      bigtux_star->draw(context, get_pos(), layer + 5);
+  }
+  if (debug_mode)
+    context.draw_filled_rect(get_pos(),
+        Vector(bbox.get_width(), bbox.get_height()),
+        Color(75,75,75, 150), LAYER_OBJECTS+20);
+}
+
+HitResponse
+Player::collision(GameObject& other, const CollisionHit& hit)
+{
+  if(other.get_flags() & FLAG_SOLID) {
+    if(hit.normal.y < 0) { // landed on floor?
+      if (physic.get_velocity_y() < 0)
+        physic.set_velocity_y(0);
+      on_ground_flag = true;
+    } else if(hit.normal.y > 0) { // bumped against the roof
+      physic.set_velocity_y(.1);
+    }
+    
+    if(fabsf(hit.normal.x) > .9) { // hit on the side?
+      physic.set_velocity_x(0);
+    }
+
+    return CONTINUE;
+  }
+
+  TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
+  if(trigger) {
+    if(input.up == DOWN && input.old_up == UP)
+      trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
+  }
+
+  return FORCE_MOVE;
+}
+
+void
+Player::make_invincible()
+{
+  SoundManager::get()->play_sound(IDToSound(SND_HERRING));
+  invincible_timer.start(TUX_INVINCIBLE_TIME);
+  Sector::current()->play_music(HERRING_MUSIC);               
+}
+
+/* Kill Player! */
+void
+Player::kill(HurtMode mode)
+{
+  if(dying)
+    return;
+
+  if(safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0)
+    return;                          
+  
+  SoundManager::get()->play_sound(IDToSound(SND_HURT));
+
+  physic.set_velocity_x(0);
+
+  if (mode == SHRINK && size == BIG)
+    {
+      if (got_power != NONE_POWER)
+        {
+          safe_timer.start(TUX_SAFE_TIME);
+          got_power = NONE_POWER;
+        }
+      else
+        {
+          growing_timer.start(GROWING_TIME);
+          safe_timer.start(TUX_SAFE_TIME + GROWING_TIME);
+          size = SMALL;
+          bbox.set_height(31.8);
+          duck = false;
+        }
+    }
+  else
+    {
+      physic.enable_gravity(true);
+      physic.set_acceleration(0, 0);
+      physic.set_velocity(0, 700);
+      --player_status.lives;
+      dying = DYING_SQUISHED;
+      dying_timer.start(3.0);
+      flags |= FLAG_NO_COLLDET;
+    }
+}
+
+/* Remove Tux's power ups */
+void
+Player::remove_powerups()
+{
+  got_power = NONE_POWER;
+  size = SMALL;
+  bbox.set_height(31.8);
+}
+
+void
+Player::move(const Vector& vector)
+{
+  bbox.set_pos(vector);
+}
+
+void
+Player::check_bounds(Camera* camera)
+{
+  /* Keep tux in bounds: */
+  if (get_pos().x < 0)
+    { // Lock Tux to the size of the level, so that he doesn't fall of
+      // on the left side
+      bbox.set_pos(Vector(0, get_pos().y));
+    }
+
+  /* Keep in-bounds, vertically: */
+  if (get_pos().y > Sector::current()->solids->get_height() * 32)
+    {
+      kill(KILL);
+      return;
+    }
+
+  bool adjust = false;
+  // can happen if back scrolling is disabled
+  if(get_pos().x < camera->get_translation().x) {
+    bbox.set_pos(Vector(camera->get_translation().x, get_pos().y));
+    adjust = true;
+  }
+  if(get_pos().x >= camera->get_translation().x + screen->w - bbox.get_width())
+  {
+    bbox.set_pos(Vector(
+          camera->get_translation().x + screen->w - bbox.get_width(),
+          get_pos().y));
+    adjust = true;
+  }
+
+  if(adjust) {
+    // FIXME
+#if 0
+    // squished now?
+    if(collision_object_map(bbox)) {
+      kill(KILL);
+      return;
+    }
+#endif
+  }
+}
+
+void
+Player::bounce(BadGuy& )
+{
+  //Make sure we stopped flapping
+  flapping = false;
+  falling_from_flap = false;
+  
+  if (input.jump)
+    physic.set_velocity_y(520);
+  else
+    physic.set_velocity_y(200);
+}
+
diff --git a/src/object/player.h b/src/object/player.h
new file mode 100644 (file)
index 0000000..be6398c
--- /dev/null
@@ -0,0 +1,224 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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.
+#ifndef SUPERTUX_PLAYER_H
+#define SUPERTUX_PLAYER_H
+
+#include "SDL.h"
+
+#include "timer.h"
+#include "video/surface.h"
+#include "special/moving_object.h"
+#include "special/sprite.h"
+#include "math/physic.h"
+#include "defines.h"
+
+using namespace SuperTux;
+
+class BadGuy;
+
+/* Times: */
+
+#define TUX_SAFE_TIME 1.250
+#define TUX_INVINCIBLE_TIME 10.0
+#define TUX_INVINCIBLE_TIME_WARNING 2.0
+#define TUX_FLAPPING_TIME 1 /* How long Tux can flap his wings to gain additional jump height */
+#define TIME_WARNING 20     /* When to alert player they're low on time! */
+
+/* Scores: */
+
+#define SCORE_BRICK 5
+#define SCORE_DISTRO 20
+
+/* Sizes: */
+
+#define SMALL 0
+#define BIG 1
+
+#include <vector>
+
+struct PlayerKeymap
+{
+public:
+  int jump;
+  int up;
+  int down;
+  int left;
+  int right;
+  int power;
+  
+  PlayerKeymap();
+};
+
+extern PlayerKeymap keymap;
+
+struct player_input_type
+{
+  int right;
+  int left;
+  int up;
+  int old_up;
+  int down;
+  int fire;
+  int old_fire;
+  int activate;
+  int jump;
+  int old_jump;
+};
+
+void player_input_init(player_input_type* pplayer_input);
+
+class Camera;
+class PlayerStatus;
+
+extern Surface* tux_life;
+
+extern Sprite* smalltux_gameover;
+extern Sprite* smalltux_star;
+extern Sprite* bigtux_star;
+
+#define GROWING_TIME 1.0
+#define GROWING_FRAMES 7
+extern Surface* growingtux_left[GROWING_FRAMES];
+extern Surface* growingtux_right[GROWING_FRAMES];
+
+class TuxBodyParts
+{
+public:
+  TuxBodyParts()
+    : head(0), body(0), arms(0), feet(0)
+  { }
+  ~TuxBodyParts() {
+    delete head;
+    delete body;
+    delete arms;
+    delete feet;
+  }
+
+  void set_action(std::string action, int loops = -1);
+  void one_time_animation();
+  void draw(DrawingContext& context, const Vector& pos, int layer,
+                Uint32 drawing_effect = NONE_EFFECT);
+
+  Sprite* head;
+  Sprite* body;
+  Sprite* arms;
+  Sprite* feet;
+};
+
+extern TuxBodyParts* small_tux;
+extern TuxBodyParts* big_tux;
+extern TuxBodyParts* fire_tux;
+extern TuxBodyParts* ice_tux;
+
+class Player : public MovingObject
+{
+public:
+  enum HurtMode { KILL, SHRINK };
+  enum Power { NONE_POWER, FIRE_POWER, ICE_POWER };
+  enum FallMode { ON_GROUND, JUMPING, TRAMPOLINE_JUMP, FALLING };
+
+  player_input_type  input;
+  int got_power;
+  int size;
+  bool duck;
+  bool holding_something;
+  bool dead;
+  DyingType dying;
+
+  Direction dir;
+  Direction old_dir;
+
+  float last_ground_y;
+  FallMode fall_mode;
+
+  bool on_ground_flag;
+  bool jumping;
+  bool flapping;
+  bool can_jump;
+  bool can_flap;
+  bool falling_from_flap;
+  bool enable_hover;
+  bool butt_jump;
+  
+  float flapping_velocity;
+
+  // Ricardo's flapping
+  int flaps_nb;
+
+  // temporary to help player's choosing a flapping
+  enum { MAREK_FLAP, RICARDO_FLAP, RYAN_FLAP, NONE_FLAP };
+  int flapping_mode;
+
+  Timer2 invincible_timer;
+  Timer2 skidding_timer;
+  Timer2 safe_timer;
+  Timer2 kick_timer;
+  Timer2 shooting_timer;   // used to show the arm when Tux is shooting
+  Timer2 dying_timer;
+  Timer2 growing_timer;
+  Timer2 idle_timer;
+  Timer2 flapping_timer;
+  Physic physic;
+  
+public:
+  Player();
+  virtual ~Player();
+  
+  int  key_event(SDLKey key, int state);
+  void level_begin();
+  void handle_input();
+  void grabdistros();
+
+  PlayerStatus& get_status();
+
+  virtual void action(float elapsed_time);
+  virtual void draw(DrawingContext& context);
+  virtual HitResponse collision(GameObject& other, const CollisionHit& hit);
+
+  void make_invincible();
+  bool is_invincible() const
+  {
+      return invincible_timer.started();
+  }
+  void kill(HurtMode mode);
+  void player_remove_powerups();
+  void check_bounds(Camera* camera);
+  bool on_ground();
+  bool under_solid();
+  void grow(bool animate = false);
+  void move(const Vector& vector);
+
+  void bounce(BadGuy& badguy);
+
+  bool is_dead() const
+  { return dead; }
+  
+private:
+  void init();
+  
+  void handle_horizontal_input();
+  void handle_vertical_input();
+  void remove_powerups();
+};
+
+#endif /*SUPERTUX_PLAYER_H*/
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp
new file mode 100644 (file)
index 0000000..0878441
--- /dev/null
@@ -0,0 +1,274 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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 <config.h>
+
+#include <cassert>
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+#include <cmath>
+
+#include "tilemap.h"
+#include "video/drawing_context.h"
+#include "level.h"
+#include "tile.h"
+#include "tile_manager.h"
+#include "app/globals.h"
+#include "utils/lispreader.h"
+#include "utils/lispwriter.h"
+
+TileMap::TileMap()
+  : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
+    vertical_flip(false)
+{
+  tilemanager = TileManager::instance();
+
+  if(solid)
+    flags |= FLAG_SOLID;
+}
+
+TileMap::TileMap(LispReader& reader)
+  : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
+    vertical_flip(false)
+{
+  tilemanager = TileManager::instance();
+
+  std::string layer_str;
+  if(reader.read_string("layer", layer_str)) {
+    if(layer_str == "background")
+      layer = LAYER_BACKGROUNDTILES;
+    else if(layer_str == "interactive")
+      layer = LAYER_TILES;
+    else if(layer_str == "foreground")
+      layer = LAYER_FOREGROUNDTILES;
+    else
+      std::cerr << "Unknown layer '" << layer_str << "' in tilemap.\n";
+  }
+
+  reader.read_bool("solid", solid);
+  reader.read_float("speed", speed);
+
+  if(solid && speed != 1) {
+    std::cout << "Speed of solid tilemap is not 1. fixing.\n";
+    speed = 1;
+  }
+  if(solid)
+    flags |= FLAG_SOLID;
+  
+  if(!reader.read_int("width", width) ||
+     !reader.read_int("height", height))
+    throw std::runtime_error("No width or height specified in tilemap.");
+
+  if(!reader.read_int_vector("tiles", tiles))
+    throw std::runtime_error("No tiles in tilemap.");
+
+  if(int(tiles.size()) != width*height)
+    throw std::runtime_error("wrong number of tiles in tilemap.");
+}
+
+TileMap::TileMap(int layer_, bool solid_, size_t width_, size_t height_)
+  : solid(solid_), speed(1), width(0), height(0), layer(layer_),
+    vertical_flip(false)
+{
+  tilemanager = TileManager::instance();
+  
+  resize(width_, height_);
+
+  if(solid)
+    flags |= FLAG_SOLID;  
+}
+
+TileMap::~TileMap()
+{
+}
+
+void
+TileMap::write(LispWriter& writer)
+{
+  writer.start_list("tilemap");
+
+  if(layer == LAYER_BACKGROUNDTILES)
+    writer.write_string("layer", "background");
+  else if(layer == LAYER_TILES)
+    writer.write_string("layer", "interactive");
+  else if(layer == LAYER_FOREGROUNDTILES)
+    writer.write_string("layer", "foreground");
+  else {
+    writer.write_string("layer", "unknown");
+    std::cerr << "Warning unknown layer in tilemap.\n";
+  }
+
+  writer.write_bool("solid", solid);
+  writer.write_float("speed", speed);
+  writer.write_int("width", width);
+  writer.write_int("height", height);
+  writer.write_int_vector("tiles", tiles);
+  
+  writer.end_list("tilemap");
+}
+
+void
+TileMap::action(float )
+{
+}
+
+void
+TileMap::draw(DrawingContext& context)
+{
+  context.push_transform();
+
+  if(vertical_flip)
+    context.set_drawing_effect(VERTICAL_FLIP); 
+  float trans_x = roundf(context.get_translation().x);
+  float trans_y = roundf(context.get_translation().y);
+  context.set_translation(Vector(trans_x * speed, trans_y * speed));
+
+  /** if we don't round here, we'll have a 1 pixel gap on screen sometimes.
+   * I have no idea why */
+  float start_x = roundf(context.get_translation().x);
+  float start_y = roundf(context.get_translation().y);
+  float end_x = std::min(start_x + screen->w, float(width * 32));
+  float end_y = std::min(start_y + screen->h, float(height * 32));
+  start_x -= int(start_x) % 32;
+  start_y -= int(start_y) % 32;  
+  int tsx = int(start_x / 32); // tilestartindex x
+  int tsy = int(start_y / 32); // tilestartindex y
+
+  Vector pos;
+  int tx, ty;
+  for(pos.x = start_x, tx = tsx; pos.x < end_x; pos.x += 32, ++tx) {
+    for(pos.y = start_y, ty = tsy; pos.y < end_y; pos.y += 32, ++ty) {
+      const Tile* tile = tilemanager->get(tiles[ty*width + tx]);
+      assert(tile != 0);
+      tile->draw(context, pos, layer);
+    }
+  }
+
+  if (debug_grid)
+  {
+    for (pos.x = start_x; pos.x < end_x; pos.x += 32)
+    {
+       context.draw_filled_rect(Vector (pos.x, start_y), Vector(1, fabsf(start_y - end_y)),
+                  Color(225, 225, 225), LAYER_GUI-50);
+    }
+
+    for (pos.y = start_y; pos.y < end_y; pos.y += 32)
+    {
+       context.draw_filled_rect(Vector (start_x, pos.y), Vector(fabsf(start_x - end_x), 1),
+                  Color(225, 225, 225), LAYER_GUI-50);
+    }
+  }
+
+  context.pop_transform();
+}
+
+void
+TileMap::set(int newwidth, int newheight, const std::vector<unsigned int>&newt,
+    int newlayer, bool newsolid)
+{
+  assert(int(newt.size()) == newwidth * newheight);
+
+  width  = newwidth;
+  height = newheight;
+
+  tiles.resize(newt.size());
+  tiles = newt;
+
+  layer  = newlayer;
+  solid  = newsolid;
+  if(solid)
+    flags |= FLAG_SOLID;
+}
+
+void
+TileMap::resize(int new_width, int new_height)
+{
+  if(new_width < width) {
+    // remap tiles for new width
+    for(int y = 0; y < height && y < new_height; ++y) {
+      for(int x = 0; x < new_width; ++x) {
+        tiles[y * new_width + x] = tiles[y * width + x];
+      }
+    }
+  }
+                                                                                
+  tiles.resize(new_width * new_height);
+                                                                                
+  if(new_width > width) {
+    // remap tiles
+    for(int y = std::min(height, new_height)-1; y >= 0; --y) {
+      for(int x = new_width-1; x >= 0; --x) {
+        if(x >= width) {
+          tiles[y * new_width + x] = 0;
+          continue;
+        }
+        
+        tiles[y * new_width + x] = tiles[y * width + x];
+      }
+    }
+  }
+
+  height = new_height;
+  width = new_width;
+}
+
+void
+TileMap::do_vertical_flip()
+{
+  // remap tiles vertically flipped
+  for(int y = 0; y < height / 2; ++y) {
+    for(int x = 0; x < width; ++x) {
+      std::swap(tiles[y*width + x], tiles[(((height-1)*width) - (y*width)) + x]);
+    }
+  }
+
+  vertical_flip = true;
+}
+
+const Tile*
+TileMap::get_tile(int x, int y) const
+{
+  if(x < 0 || x >= width || y < 0 || y >= height) {
+#ifdef DEBUG
+    //std::cout << "Warning: tile outside tilemap requested!\n";
+#endif
+    return tilemanager->get(0);
+  }
+
+  return tilemanager->get(tiles[y*width + x]);
+}
+
+const Tile*
+TileMap::get_tile_at(const Vector& pos) const
+{
+  return get_tile(int(pos.x)/32, int(pos.y)/32);
+}
+
+void
+TileMap::change(int x, int y, uint32_t newtile)
+{
+  assert(x >= 0 && x < width && y >= 0 && y < height);
+  tiles[y*width + x] = newtile;
+}
+
+void
+TileMap::change_at(const Vector& pos, uint32_t newtile)
+{
+  change(int(pos.x)/32, int(pos.y)/32, newtile);
+}
diff --git a/src/object/tilemap.h b/src/object/tilemap.h
new file mode 100644 (file)
index 0000000..8aa2b48
--- /dev/null
@@ -0,0 +1,103 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  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.
+
+#ifndef SUPERTUX_TILEMAP_H
+#define SUPERTUX_TILEMAP_H
+
+#include <vector>
+#include <stdint.h>
+
+#include "special/game_object.h"
+#include "serializable.h"
+#include "math/vector.h"
+
+using namespace SuperTux;
+
+namespace SuperTux {
+class LispReader;
+}
+
+class Level;
+class TileManager;
+class Tile;
+
+/**
+ * This class is reponsible for drawing the level tiles
+ */
+class TileMap : public GameObject, public Serializable
+{
+public:
+  TileMap();
+  TileMap(LispReader& reader);
+  TileMap(int layer_, bool solid_, size_t width_, size_t height_);
+  virtual ~TileMap();
+
+  virtual void write(LispWriter& writer);
+
+  virtual void action(float elapsed_time);
+  virtual void draw(DrawingContext& context);
+
+  void set(int width, int height, const std::vector<unsigned int>& vec,
+      int layer, bool solid);
+
+  /** resizes the tilemap to a new width and height (tries to not destroy the
+   * existing map)
+   */
+  void resize(int newwidth, int newheight);
+
+  /** Flip the all tile map vertically. The purpose of this is to let
+      player to play the same level in a different way :) */
+  void do_vertical_flip();
+
+  size_t get_width() const
+  { return width; }
+
+  size_t get_height() const
+  { return height; }
+
+  int get_layer() const
+  { return layer; }
+  
+  bool is_solid() const
+  { return solid; }
+
+  /// returns tile in row y and column y (of the tilemap)
+  const Tile* get_tile(int x, int y) const;
+  /// returns tile at position pos (in world coordinates)
+  const Tile* get_tile_at(const Vector& pos) const;
+
+  void change(int x, int y, uint32_t newtile);
+
+  void change_at(const Vector& pos, uint32_t newtile);
+
+private:
+  std::vector<uint32_t> tiles;
+  
+private:
+  TileManager* tilemanager;
+  bool solid;
+  float speed;
+  int width, height;
+  int layer;
+
+  bool vertical_flip;
+};
+
+#endif /*SUPERTUX_TILEMAP_H*/
+
diff --git a/src/particlesystem.cpp b/src/particlesystem.cpp
deleted file mode 100644 (file)
index b82152a..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-// 
-//  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 <config.h>
-
-#include <iostream>
-#include <cmath>
-
-#include "particlesystem.h"
-#include "app/globals.h"
-#include "utils/lispreader.h"
-#include "utils/lispwriter.h"
-#include "video/drawing_context.h"
-
-ParticleSystem::ParticleSystem()
-{
-    virtual_width = screen->w;
-    virtual_height = screen->h;
-    layer = LAYER_BACKGROUND1;
-}
-
-ParticleSystem::~ParticleSystem()
-{
-    std::vector<Particle*>::iterator i;
-    for(i = particles.begin(); i != particles.end(); ++i) {
-        delete *i;
-    }
-}
-
-void ParticleSystem::draw(DrawingContext& context)
-{
-  float scrollx = context.get_translation().x;
-  float scrolly = context.get_translation().y;
-
-  context.push_transform();
-  context.set_translation(Vector(0,0));
-  
-    std::vector<Particle*>::iterator i;
-    for(i = particles.begin(); i != particles.end(); ++i) {
-        Particle* particle = *i;
-
-        // remap x,y coordinates onto screencoordinates
-        Vector pos;
-        pos.x = fmodf(particle->pos.x - scrollx, virtual_width);
-        if(pos.x < 0) pos.x += virtual_width;
-        pos.y = fmodf(particle->pos.y - scrolly, virtual_height);
-        if(pos.y < 0) pos.y += virtual_height;
-
-        if(pos.x > screen->w) pos.x -= virtual_width;
-        if(pos.y > screen->h) pos.y -= virtual_height;
-        context.draw_surface(particle->texture, pos, layer);
-    }
-
-    context.pop_transform();
-}
-
-SnowParticleSystem::SnowParticleSystem()
-{
-    snowimages[0] = new Surface(datadir+"/images/shared/snow0.png", true);
-    snowimages[1] = new Surface(datadir+"/images/shared/snow1.png", true);
-    snowimages[2] = new Surface(datadir+"/images/shared/snow2.png", true);
-
-    virtual_width = screen->w * 2;
-
-    // create some random snowflakes
-    size_t snowflakecount = size_t(virtual_width/10.0);
-    for(size_t i=0; i<snowflakecount; ++i) {
-        SnowParticle* particle = new SnowParticle;
-        particle->pos.x = rand() % int(virtual_width);
-        particle->pos.y = rand() % screen->h;
-        int snowsize = rand() % 3;
-        particle->texture = snowimages[snowsize];
-        do {
-            particle->speed = snowsize*.2 + (float(rand()%10)*.4);
-        } while(particle->speed < 1);
-        particle->speed *= 10; // gravity
-
-        particles.push_back(particle);
-    }
-}
-
-void
-SnowParticleSystem::parse(LispReader& reader)
-{
-  reader.read_int("layer", layer);
-}
-
-void
-SnowParticleSystem::write(LispWriter& writer)
-{
-  writer.start_list("particles-snow");
-  writer.write_int("layer", layer);
-  writer.end_list("particles-snow");
-}
-
-SnowParticleSystem::~SnowParticleSystem()
-{
-  for(int i=0;i<3;++i)
-    delete snowimages[i];
-}
-
-void SnowParticleSystem::action(float elapsed_time)
-{
-    std::vector<Particle*>::iterator i;
-    for(i = particles.begin(); i != particles.end(); ++i) {
-        SnowParticle* particle = (SnowParticle*) *i;
-        particle->pos.y += particle->speed * elapsed_time;
-        if(particle->pos.y > screen->h) {
-            particle->pos.y = fmodf(particle->pos.y , virtual_height);
-            particle->pos.x = rand() % int(virtual_width);
-        }
-    }
-}
-
-CloudParticleSystem::CloudParticleSystem()
-{
-    cloudimage = new Surface(datadir + "/images/shared/cloud.png", true);
-
-    virtual_width = 2000.0;
-
-    // create some random clouds
-    for(size_t i=0; i<15; ++i) {
-        CloudParticle* particle = new CloudParticle;
-        particle->pos.x = rand() % int(virtual_width);
-        particle->pos.y = rand() % int(virtual_height);
-        particle->texture = cloudimage;
-        particle->speed = -float(25 + rand() % 30);
-
-        particles.push_back(particle);
-    }
-}
-
-void
-CloudParticleSystem::parse(LispReader& reader)
-{
-  reader.read_int("layer", layer);
-}
-
-void
-CloudParticleSystem::write(LispWriter& writer)
-{
-  writer.start_list("particles-clouds");
-  writer.write_int("layer", layer);
-  writer.end_list("particles-clouds");
-}
-
-CloudParticleSystem::~CloudParticleSystem()
-{
-  delete cloudimage;
-}
-
-void CloudParticleSystem::action(float elapsed_time)
-{
-    std::vector<Particle*>::iterator i;
-    for(i = particles.begin(); i != particles.end(); ++i) {
-        CloudParticle* particle = (CloudParticle*) *i;
-        particle->pos.x += particle->speed * elapsed_time;
-    }
-}
diff --git a/src/particlesystem.h b/src/particlesystem.h
deleted file mode 100644 (file)
index d11c5c1..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-// 
-//  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.
-
-#ifndef SUPERTUX_PARTICLESYSTEM_H
-#define SUPERTUX_PARTICLESYSTEM_H
-
-#include <vector>
-
-#include "video/surface.h"
-#include "special/game_object.h"
-#include "serializable.h"
-
-using namespace SuperTux;
-
-namespace SuperTux {
-class LispReader;
-}
-
-class DisplayManager;
-
-/**
- * This is the base class for particle systems. It is responsible for storing a
- * set of particles with each having an x- and y-coordinate the number of the
- * layer where it should be drawn and a texture.
- * The coordinate system used here is a virtual one. It would be a bad idea to
- * populate whole levels with particles. So we're using a virtual rectangle
- * here that is tiled onto the level when drawing. This rectangle has the size
- * (virtual_width, virtual_height). We're using modulo on the particle
- * coordinates, so when a particle leaves left, it'll reenter at the right
- * side.
- *
- * Classes that implement a particle system should subclass from this class,
- * initialize particles in the constructor and move them in the simulate
- * function.
- */
-class ParticleSystem : public GameObject
-{
-public:
-    ParticleSystem();
-    virtual ~ParticleSystem();
-    
-    virtual void draw(DrawingContext& context);
-
-protected:
-    int layer;
-
-    class Particle
-    {
-    public:
-        virtual ~Particle()
-        { }
-
-        Vector pos;
-        Surface* texture;
-    };
-    
-    std::vector<Particle*> particles;
-    float virtual_width, virtual_height;
-};
-
-class SnowParticleSystem : public ParticleSystem, public Serializable
-{
-public:
-    SnowParticleSystem();
-    virtual ~SnowParticleSystem();
-
-    void parse(LispReader& reader);
-    void write(LispWriter& writer);
-
-    virtual void action(float elapsed_time);
-
-    std::string type() const
-    { return "SnowParticleSystem"; }
-    
-private:
-    class SnowParticle : public Particle
-    {
-    public:
-        float speed;
-    };
-    
-    Surface* snowimages[3];
-};
-
-class CloudParticleSystem : public ParticleSystem, public Serializable
-{
-public:
-    CloudParticleSystem();
-    virtual ~CloudParticleSystem();
-
-    void parse(LispReader& reader);
-    void write(LispWriter& writer);
-
-    virtual void action(float elapsed_time);
-
-    std::string type() const
-    { return "SnowParticleSystem"; }    
-    
-private:
-    class CloudParticle : public Particle
-    {
-    public:
-        float speed;
-    };
-    
-    Surface* cloudimage;
-};
-
-#endif
-
diff --git a/src/player.cpp b/src/player.cpp
deleted file mode 100644 (file)
index 6608f8c..0000000
+++ /dev/null
@@ -1,1018 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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 <config.h>
-
-#include <typeinfo>
-#include <cmath>
-#include <iostream>
-#include <cassert>
-
-#include "app/globals.h"
-#include "app/gettext.h"
-#include "player.h"
-#include "defines.h"
-#include "scene.h"
-#include "tile.h"
-#include "special/sprite.h"
-#include "sector.h"
-#include "tilemap.h"
-#include "camera.h"
-#include "gameobjs.h"
-#include "resources.h"
-#include "video/screen.h"
-#include "statistics.h"
-#include "gameloop.h"
-#include "trigger/trigger_base.h"
-
-static const int TILES_FOR_BUTTJUMP = 3;
-static const float SHOOTING_TIME = .150;
-/// time before idle animation starts
-static const float IDLE_TIME = 2.5;
-
-static const float WALK_ACCELERATION_X = 300;
-static const float RUN_ACCELERATION_X = 400;
-static const float SKID_XM = 200;
-static const float SKID_TIME = .3;
-static const float MAX_WALK_XM = 230;
-static const float MAX_RUN_XM = 320;
-static const float WALK_SPEED = 100;
-
-// growing animation
-Surface* growingtux_left[GROWING_FRAMES];
-Surface* growingtux_right[GROWING_FRAMES];
-
-Surface* tux_life = 0;
-
-Sprite* smalltux_gameover = 0;
-Sprite* smalltux_star = 0;
-Sprite* bigtux_star = 0;
-
-TuxBodyParts* small_tux = 0;
-TuxBodyParts* big_tux = 0;
-TuxBodyParts* fire_tux = 0;
-TuxBodyParts* ice_tux = 0;
-
-PlayerKeymap keymap;
-
-PlayerKeymap::PlayerKeymap()
-{
-  keymap.up    = SDLK_UP;
-  keymap.down  = SDLK_DOWN;
-  keymap.left  = SDLK_LEFT;
-  keymap.right = SDLK_RIGHT;
-
-  keymap.power = SDLK_LCTRL;
-  keymap.jump  = SDLK_SPACE;
-}
-
-void player_input_init(player_input_type* pplayer_input)
-{
-  pplayer_input->up = UP;
-  pplayer_input->old_up = UP;
-  pplayer_input->down = UP;
-  pplayer_input->fire = UP;
-  pplayer_input->left = UP;
-  pplayer_input->old_fire = UP;
-  pplayer_input->right = UP;
-  pplayer_input->jump = UP;
-  pplayer_input->old_jump = UP;
-  pplayer_input->activate = UP;
-}
-
-void
-TuxBodyParts::set_action(std::string action, int loops)
-{
-  if(head != NULL)
-    head->set_action(action, loops);
-  if(body != NULL)
-    body->set_action(action, loops);
-  if(arms != NULL)
-    arms->set_action(action, loops);
-  if(feet != NULL)
-    feet->set_action(action, loops);
-}
-
-void
-TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer,
-                  Uint32 drawing_effect)
-{
-  if(head != NULL)
-    head->draw(context, pos, layer-1, drawing_effect);
-  if(body != NULL)
-    body->draw(context, pos, layer-3, drawing_effect);
-  if(arms != NULL)
-    arms->draw(context, pos, layer,   drawing_effect);
-  if(feet != NULL)
-    feet->draw(context, pos, layer-2, drawing_effect);
-}
-
-Player::Player()
-{
-  init();
-}
-
-Player::~Player()
-{
-}
-
-void
-Player::init()
-{
-  holding_something = false;
-
-  bbox.set_size(31.8, 31.8);
-
-  size = SMALL;
-  got_power = NONE_POWER;
-
-  dir = RIGHT;
-  old_dir = dir;
-  duck = false;
-  dead = false;
-
-  dying   = DYING_NOT;
-  last_ground_y = 0;
-  fall_mode = ON_GROUND;
-  jumping = false;
-  flapping = false;
-  can_jump = true;
-  can_flap = false;
-  falling_from_flap = false;
-  enable_hover = false;
-  butt_jump = false;
-  
-  flapping_velocity = 0;
-
-  // temporary to help player's choosing a flapping
-  flapping_mode = MAREK_FLAP;
-
-  // Ricardo's flapping
-  flaps_nb = 0;
-
-  on_ground_flag = false;
-
-  player_input_init(&input);
-
-  physic.reset();
-}
-
-int
-Player::key_event(SDLKey key, int state)
-{
-  idle_timer.start(IDLE_TIME, true);
-
-  if(key == keymap.right)
-    {
-      input.right = state;
-      return true;
-    }
-  else if(key == keymap.left)
-    {
-      input.left = state;
-      return true;
-    }
-  else if(key == keymap.up)
-    {
-      if(state == UP)
-        input.old_up = UP;
-      input.up = state;
-      /* Up key also opens activates stuff */
-      input.activate = state;
-      return true;
-    }
-  else if(key == keymap.down)
-    {
-      input.down = state;
-      return true;
-    }
-  else if(key == keymap.power)
-    {
-      if (state == UP)
-        input.old_fire = UP;
-      input.fire = state;
-
-      return true;
-    }
-  else if(key == keymap.jump)
-    {
-      if (state == UP)
-        input.old_jump = UP;
-      input.jump = state;
-      return true;
-    }
-  else
-    return false;
-}
-
-void
-Player::level_begin()
-{
-  move(Vector(100, 170));
-  duck = false;
-
-  dying = DYING_NOT;
-
-  player_input_init(&input);
-
-  on_ground_flag = false;
-
-  physic.reset();
-}
-
-PlayerStatus&
-Player::get_status()
-{
-  return player_status;
-}
-
-void
-Player::action(float elapsed_time)
-{
-  if(dying && dying_timer.check()) {
-    dead = true;
-    return;
-  }
-
-  if (input.fire == UP)
-    holding_something = false;
-
-  if(dying == DYING_NOT)
-    handle_input();
-
-  movement = physic.get_movement(elapsed_time);
-
-#if 0
-      // special exception for cases where we're stuck under tiles after
-      // being ducked. In this case we drift out
-      if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
-         && collision_object_map(base))
-        {
-          base.x += elapsed_time * WALK_SPEED * (dir ? 1: -1);
-          previous_base = old_base = base;
-        }
-
-      /* Reset score multiplier (for multi-hits): */
-      if (!invincible_timer.started())
-            {
-            if(player_status.score_multiplier > player_status.max_score_multiplier)
-              {
-              player_status.max_score_multiplier = player_status.score_multiplier;
-
-              // show a message
-              char str[124];
-              sprintf(str, _("New max combo: %d"), player_status.max_score_multiplier-1);
-              Sector::current()->add_floating_text(base, str);
-              }
-            player_status.score_multiplier = 1;
-            }
-        }
-
-    }
-#endif
-
-  on_ground_flag = false;
-}
-
-bool
-Player::on_ground()
-{
-  return on_ground_flag;
-}
-
-void
-Player::handle_horizontal_input()
-{
-  float vx = physic.get_velocity_x();
-  float vy = physic.get_velocity_y();
-  float ax = physic.get_acceleration_x();
-  float ay = physic.get_acceleration_y();
-
-  float dirsign = 0;
-  if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
-      old_dir = dir;
-      dir = LEFT;
-      dirsign = -1;
-  } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
-      old_dir = dir;
-      dir = RIGHT;
-      dirsign = 1;
-  }
-
-  if (input.fire == UP) {
-      ax = dirsign * WALK_ACCELERATION_X;
-      // limit speed
-      if(vx >= MAX_WALK_XM && dirsign > 0) {
-        vx = MAX_WALK_XM;
-        ax = 0;
-      } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
-        vx = -MAX_WALK_XM;
-        ax = 0;
-      }
-  } else {
-      ax = dirsign * RUN_ACCELERATION_X;
-      // limit speed
-      if(vx >= MAX_RUN_XM && dirsign > 0) {
-        vx = MAX_RUN_XM;
-        ax = 0;
-      } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
-        vx = -MAX_RUN_XM;
-        ax = 0;
-      }
-  }
-
-  // we can reach WALK_SPEED without any acceleration
-  if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
-    vx = dirsign * WALK_SPEED;
-  }
-
-  // changing directions?
-  if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0)))
-    {
-      // let's skid!
-      if(fabs(vx)>SKID_XM && !skidding_timer.started())
-        {
-          skidding_timer.start(SKID_TIME);
-          SoundManager::get()->play_sound(IDToSound(SND_SKID));
-          // dust some partcles
-          Sector::current()->add_object(
-              new Particles(
-                Vector(bbox.p1.x + (dir == RIGHT ? bbox.get_width() : 0),
-                bbox.p2.y),
-              dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
-              Vector(280,-260), Vector(0,0.030), 3, Color(100,100,100), 3, .8,
-              LAYER_OBJECTS+1));
-
-          ax *= 2.5;
-        }
-      else
-        {
-          ax *= 2;
-        }
-    }
-
-  // we get slower when not pressing any keys
-  if(dirsign == 0) {
-      if(fabs(vx) < WALK_SPEED) {
-          vx = 0;
-          ax = 0;
-      } else if(vx < 0) {
-          ax = WALK_ACCELERATION_X * 1.5;
-      } else {
-          ax = WALK_ACCELERATION_X * -1.5;
-      }
-  }
-
-#if 0
-  // if we're on ice slow down acceleration or deceleration
-  if (isice(base.x, base.y + base.height))
-  {
-    /* the acceleration/deceleration rate on ice is inversely proportional to
-     * the current velocity.
-     */
-
-    // increasing 1 will increase acceleration/deceleration rate
-    // decreasing 1 will decrease acceleration/deceleration rate
-    //  must stay above zero, though
-    if (ax != 0) ax *= 1 / fabs(vx);
-  }
-#endif
-
-  // extend/shrink tux collision rectangle so that we fall through/walk over 1
-  // tile holes
-  if(fabsf(vx) > MAX_WALK_XM) {
-    bbox.set_width(33);
-  } else {
-    bbox.set_width(31.8);
-  }
-
-  physic.set_velocity(vx, vy);
-  physic.set_acceleration(ax, ay);
-}
-
-void
-Player::handle_vertical_input()
-{
-  // set fall mode...
-  if(on_ground()) {
-    fall_mode = ON_GROUND;
-    last_ground_y = get_pos().y;
-  } else {
-    if(get_pos().y > last_ground_y)
-      fall_mode = FALLING;
-    else if(fall_mode == ON_GROUND)
-      fall_mode = JUMPING;
-  }
-
-  if(on_ground()) { /* Make sure jumping is off. */
-    jumping = false;
-    flapping = false;
-    falling_from_flap = false;
-    if (flapping_timer.started()) {
-      flapping_timer.start(0);
-    }
-
-    physic.set_acceleration_y(0); //for flapping
-  }
-
-  // Press jump key
-  if(input.jump == DOWN && can_jump && on_ground())
-    {
-      if(duck) { // only jump a little bit when in duck mode {
-        physic.set_velocity_y(300);
-      } else {
-        // jump higher if we are running
-        if (fabs(physic.get_velocity_x()) > MAX_WALK_XM)
-          physic.set_velocity_y(580);
-        else
-          physic.set_velocity_y(520);
-      }
-
-      //bbox.move(Vector(0, -1));
-      jumping = true;
-      flapping = false;
-      can_jump = false;
-      can_flap = false;
-      flaps_nb = 0; // Ricardo's flapping
-      if (size == SMALL)
-        SoundManager::get()->play_sound(IDToSound(SND_JUMP));
-      else
-        SoundManager::get()->play_sound(IDToSound(SND_BIGJUMP));
-    }
-  // Let go of jump key
-  else if(input.jump == UP)
-    {
-      if (!flapping && !duck && !falling_from_flap && !on_ground())
-         {
-            can_flap = true;
-         }
-      if (jumping && physic.get_velocity_y() > 0)
-         {
-            jumping = false;
-            physic.set_velocity_y(0);
-         }
-    }
-
- // temporary to help player's choosing a flapping
- if(flapping_mode == RICARDO_FLAP)
-   {
-   // Flapping, Ricardo's version
-   // similar to SM3 Fox
-   if(input.jump == DOWN && input.old_jump == UP && can_flap &&
-     flaps_nb < 3)
-     {
-       physic.set_velocity_y(350);
-       physic.set_velocity_x(physic.get_velocity_x() * 35);
-       flaps_nb++;
-     }
-   }
-  else if(flapping_mode == MAREK_FLAP)
-   {
-   // Flapping, Marek's version
-   if (input.jump == DOWN && can_flap)
-     {
-         if (!flapping_timer.started())
-            {
-               flapping_timer.start(TUX_FLAPPING_TIME);
-               flapping_velocity = physic.get_velocity_x();
-            }
-         if (flapping_timer.check()) 
-            {
-               can_flap = false;
-               falling_from_flap = true;
-            }
-         jumping = true;
-         flapping = true;
-         if (!flapping_timer.check()) {
-           float cv = flapping_velocity * sqrt(
-               TUX_FLAPPING_TIME - flapping_timer.get_timegone() 
-               / TUX_FLAPPING_TIME);
-
-           //Handle change of direction while flapping
-           if (((dir == LEFT) && (cv > 0)) || (dir == RIGHT) && (cv < 0)) {
-             cv *= (-1);
-           }
-           physic.set_velocity_x(cv);
-           physic.set_velocity_y(
-               flapping_timer.get_timegone()/.850);
-         }
-     }
-   }
-  else if(flapping_mode == RYAN_FLAP)
-   {
-   // Flapping, Ryan's version
-   if (input.jump == DOWN && can_flap)
-     {
-         if (!flapping_timer.started())
-            {
-               flapping_timer.start(TUX_FLAPPING_TIME);
-            }
-         if (flapping_timer.check()) 
-            {
-               can_flap = false;
-               falling_from_flap = true;
-            }
-         jumping = true;
-         flapping = true;
-         if (flapping && flapping_timer.get_timegone() <= TUX_FLAPPING_TIME
-                && physic.get_velocity_y() < 0)
-            {
-               float gravity = Sector::current()->gravity;
-               (void)gravity;
-               float xr = (fabsf(physic.get_velocity_x()) / MAX_RUN_XM);
-
-               // XXX: magic numbers. should be a percent of gravity
-               //      gravity is (by default) -0.1f
-               physic.set_acceleration_y(12 + 1*xr);
-
-#if 0
-               // To slow down x-vel when flapping (not working)
-               if (fabsf(physic.get_velocity_x()) > MAX_WALK_XM)
-               {
-                   if (physic.get_velocity_x() < 0)
-                       physic.set_acceleration_x(1.0f);
-                   else if (physic.get_velocity_x() > 0)
-                       physic.set_acceleration_x(-1.0f);
-               }
-#endif
-            }
-     }
-    else
-     {
-        physic.set_acceleration_y(0);
-     }
-   }
-
-   // Hover
-   //(disabled by default, use cheat code "hover" to toggle on/off)
-   //TODO: needs some tweaking, especially when used together with double jump and jumping off badguys
-   if (enable_hover && input.jump == DOWN && !jumping && !butt_jump && physic.get_velocity_y() <= 0)
-      {
-         physic.set_velocity_y(-100);
-      }
-
-#if 0
-   /* In case the player has pressed Down while in a certain range of air,
-      enable butt jump action */
-  if (input.down == DOWN && !butt_jump && !duck)
-    if(tiles_on_air(TILES_FOR_BUTTJUMP) && jumping)
-      butt_jump = true;
-#endif
-
-   /* When Down is not held anymore, disable butt jump */
-  if(butt_jump && input.down == UP)
-    butt_jump = false;
-
-  // Do butt jump
-  if (butt_jump && on_ground() && size == BIG)
-  {
-    // Add a smoke cloud
-    if (duck) 
-      Sector::current()->add_smoke_cloud(Vector(get_pos().x - 32, get_pos().y));
-    else 
-      Sector::current()->add_smoke_cloud(
-          Vector(get_pos().x - 32, get_pos().y + 32));
-    
-    butt_jump = false;
-
-#if 0
-    // Break bricks beneath Tux
-    if(Sector::current()->trybreakbrick(
-          Vector(base.x + 1, base.y + base.height), false)
-        || Sector::current()->trybreakbrick(
-           Vector(base.x + base.width - 1, base.y + base.height), false))
-    {
-      physic.set_velocity_y(2);
-      butt_jump = true;
-    }
-#endif
-
-#if 0
-    // Kill nearby badguys
-    std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
-    for (std::vector<GameObject*>::iterator i = gameobjects.begin();
-         i != gameobjects.end();
-         i++)
-    {
-      BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
-      if(badguy)
-      {
-        // don't kill when badguys are already dying or in a certain mode
-        if(badguy->dying == DYING_NOT && badguy->mode != BadGuy::BOMB_TICKING &&
-           badguy->mode != BadGuy::BOMB_EXPLODE)
-          {
-            if (fabsf(base.x - badguy->base.x) < 96 &&
-                fabsf(base.y - badguy->base.y) < 64)
-              badguy->kill_me(25);
-          }
-      }
-    }
-#endif
-  }
-
-  /** jumping is only allowed if we're about to touch ground soon and if the
-   * button has been up in between the last jump
-   */
-  // FIXME
-#if 0
-  if ( (issolid(get_pos().x + bbox.get_width() / 2,
-          get_pos().y + bbox.get_height() + 64) ||
-        issolid(get_pos().x + 1, get_pos().y + bbox.get_height() + 64) ||
-        issolid(get_pos().x + bbox.get_width() - 1,
-          get_pos().y + bbox.get_height() + 64))
-       && jumping  == false
-       && can_jump == false
-       && input.jump == DOWN
-       && input.old_jump == UP)
-    {
-      can_jump = true;
-    }
-#endif
-
-  input.old_jump = input.jump;
-}
-
-void
-Player::handle_input()
-{
-  /* Handle horizontal movement: */
-  handle_horizontal_input();
-
-  /* Jump/jumping? */
-  if (on_ground() && input.jump == UP)
-    can_jump = true;
-  handle_vertical_input();
-
-  /* Shoot! */
-  if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER) {
-    if(Sector::current()->add_bullet(
-          get_pos() + Vector(0, bbox.get_height()/2),
-          physic.get_velocity_x(), dir))
-      shooting_timer.start(SHOOTING_TIME);
-    input.old_fire = DOWN;
-  }
-
-  /* Duck! */
-  if (input.down == DOWN && size == BIG && !duck 
-      && physic.get_velocity_y() == 0 && on_ground())
-    {
-      duck = true;
-      bbox.move(Vector(0, 32));
-      bbox.set_height(31.8);
-    }
-  else if(input.down == UP && size == BIG && duck)
-    {
-      // try if we can really unduck
-      bbox.move(Vector(0, -32));
-      bbox.set_height(63.8);
-      duck = false;
-      // FIXME
-#if 0
-      // when unducking in air we need some space to do so
-      if(on_ground() || !collision_object_map(bbox)) {
-        duck = false;
-      } else {
-        // undo the ducking changes
-        bbox.move(Vector(0, 32));
-        bbox.set_height(31.8);
-      }
-#endif
-    }
-}
-
-void
-Player::grow(bool animate)
-{
-  if(size == BIG)
-    return;
-  
-  size = BIG;
-  bbox.set_height(63.8);
-  bbox.move(Vector(0, -32));
-
-  if(animate)
-    growing_timer.start(GROWING_TIME);
-}
-
-void
-Player::grabdistros()
-{
-}
-
-void
-Player::draw(DrawingContext& context)
-{
-  TuxBodyParts* tux_body;
-          
-  if (size == SMALL)
-    tux_body = small_tux;
-  else if (got_power == FIRE_POWER)
-    tux_body = fire_tux;
-  else if (got_power == ICE_POWER)
-    tux_body = ice_tux;
-  else
-    tux_body = big_tux;
-
-  int layer = LAYER_OBJECTS + 10;
-
-  /* Set Tux sprite action */
-  if (duck && size == BIG)
-    {
-    if(dir == LEFT)
-      tux_body->set_action("duck-left");
-    else // dir == RIGHT
-      tux_body->set_action("duck-right");
-    }
-  else if (skidding_timer.started() && !skidding_timer.check())
-    {
-    if(dir == LEFT)
-      tux_body->set_action("skid-left");
-    else // dir == RIGHT
-      tux_body->set_action("skid-right");
-    }
-  else if (kick_timer.started() && !kick_timer.check())
-    {
-    if(dir == LEFT)
-      tux_body->set_action("kick-left");
-    else // dir == RIGHT
-      tux_body->set_action("kick-right");
-    }
-  else if (butt_jump && size == BIG)
-    {
-    if(dir == LEFT)
-      tux_body->set_action("buttjump-left");
-    else // dir == RIGHT
-      tux_body->set_action("buttjump-right");
-    }
-  else if (physic.get_velocity_y() != 0)
-    {
-    if(dir == LEFT)
-      tux_body->set_action("jump-left");
-    else // dir == RIGHT
-      tux_body->set_action("jump-right");
-    }
-  else
-    {
-    if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
-      {
-      if(dir == LEFT)
-        tux_body->set_action("stand-left");
-      else // dir == RIGHT
-        tux_body->set_action("stand-right");
-      }
-    else // moving
-      {
-      if(dir == LEFT)
-        tux_body->set_action("walk-left");
-      else // dir == RIGHT
-        tux_body->set_action("walk-right");
-      }
-    }
-
-  if(idle_timer.check())
-    {
-    if(size == BIG)
-      {
-      if(dir == LEFT)
-        tux_body->head->set_action("idle-left", 1);
-      else // dir == RIGHT
-        tux_body->head->set_action("idle-right", 1);
-      }
-
-    }
-
-  // Tux is holding something
-  if ((holding_something && physic.get_velocity_y() == 0) ||
-      (shooting_timer.get_timeleft() > 0 && !shooting_timer.check()))
-    {
-    if (duck)
-      {
-      if(dir == LEFT)
-        tux_body->arms->set_action("duck+grab-left");
-      else // dir == RIGHT
-        tux_body->arms->set_action("duck+grab-right");
-      }
-    else
-      {
-      if(dir == LEFT)
-        tux_body->arms->set_action("grab-left");
-      else // dir == RIGHT
-        tux_body->arms->set_action("grab-right");
-      }
-    }
-
-  /* Draw Tux */
-  if (dying == DYING_SQUISHED) {
-    smalltux_gameover->draw(context, get_pos(), LAYER_FOREGROUNDTILES+1);
-  } else if(growing_timer.get_timeleft() > 0) {
-    if(size == SMALL)
-      {
-      if (dir == RIGHT)
-        context.draw_surface(growingtux_right[GROWING_FRAMES-1 - 
-                 int((growing_timer.get_timegone() *
-                 GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
-      else
-        context.draw_surface(growingtux_left[GROWING_FRAMES-1 - 
-                int((growing_timer.get_timegone() *
-                GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
-      }
-    else
-      {
-      if (dir == RIGHT)
-        context.draw_surface(growingtux_right[
-            int((growing_timer.get_timegone() *
-                GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
-      else
-        context.draw_surface(growingtux_left[
-            int((growing_timer.get_timegone() *
-                             GROWING_FRAMES) / GROWING_TIME)],
-            get_pos(), layer);
-      }
-    }
-  else if (safe_timer.started() && size_t(global_time*40)%2)
-    ;  // don't draw Tux
-  else
-    tux_body->draw(context, get_pos(), layer);
-
-  // Draw blinking star overlay
-  if (invincible_timer.started() &&
-     (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING
-      || size_t(global_time*20)%2)
-     && !dying)
-  {
-    if (size == SMALL || duck)
-      smalltux_star->draw(context, get_pos(), layer + 5);
-    else
-      bigtux_star->draw(context, get_pos(), layer + 5);
-  }
-  if (debug_mode)
-    context.draw_filled_rect(get_pos(),
-        Vector(bbox.get_width(), bbox.get_height()),
-        Color(75,75,75, 150), LAYER_OBJECTS+20);
-}
-
-HitResponse
-Player::collision(GameObject& other, const CollisionHit& hit)
-{
-  if(other.get_flags() & FLAG_SOLID) {
-    if(hit.normal.y < 0) { // landed on floor?
-      if (physic.get_velocity_y() < 0)
-        physic.set_velocity_y(0);
-      on_ground_flag = true;
-    } else if(hit.normal.y > 0) { // bumped against the roof
-      physic.set_velocity_y(.1);
-    }
-    
-    if(fabsf(hit.normal.x) > .9) { // hit on the side?
-      physic.set_velocity_x(0);
-    }
-
-    return CONTINUE;
-  }
-
-  TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
-  if(trigger) {
-    if(input.up == DOWN && input.old_up == UP)
-      trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
-  }
-
-  return FORCE_MOVE;
-}
-
-void
-Player::make_invincible()
-{
-  SoundManager::get()->play_sound(IDToSound(SND_HERRING));
-  invincible_timer.start(TUX_INVINCIBLE_TIME);
-  Sector::current()->play_music(HERRING_MUSIC);               
-}
-
-/* Kill Player! */
-void
-Player::kill(HurtMode mode)
-{
-  if(dying)
-    return;
-
-  if(safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0)
-    return;                          
-  
-  SoundManager::get()->play_sound(IDToSound(SND_HURT));
-
-  physic.set_velocity_x(0);
-
-  if (mode == SHRINK && size == BIG)
-    {
-      if (got_power != NONE_POWER)
-        {
-          safe_timer.start(TUX_SAFE_TIME);
-          got_power = NONE_POWER;
-        }
-      else
-        {
-          growing_timer.start(GROWING_TIME);
-          safe_timer.start(TUX_SAFE_TIME + GROWING_TIME);
-          size = SMALL;
-          bbox.set_height(31.8);
-          duck = false;
-        }
-    }
-  else
-    {
-      physic.enable_gravity(true);
-      physic.set_acceleration(0, 0);
-      physic.set_velocity(0, 700);
-      --player_status.lives;
-      dying = DYING_SQUISHED;
-      dying_timer.start(3.0);
-      flags |= FLAG_NO_COLLDET;
-    }
-}
-
-/* Remove Tux's power ups */
-void
-Player::remove_powerups()
-{
-  got_power = NONE_POWER;
-  size = SMALL;
-  bbox.set_height(31.8);
-}
-
-void
-Player::move(const Vector& vector)
-{
-  bbox.set_pos(vector);
-}
-
-void
-Player::check_bounds(Camera* camera)
-{
-  /* Keep tux in bounds: */
-  if (get_pos().x < 0)
-    { // Lock Tux to the size of the level, so that he doesn't fall of
-      // on the left side
-      bbox.set_pos(Vector(0, get_pos().y));
-    }
-
-  /* Keep in-bounds, vertically: */
-  if (get_pos().y > Sector::current()->solids->get_height() * 32)
-    {
-      kill(KILL);
-      return;
-    }
-
-  bool adjust = false;
-  // can happen if back scrolling is disabled
-  if(get_pos().x < camera->get_translation().x) {
-    bbox.set_pos(Vector(camera->get_translation().x, get_pos().y));
-    adjust = true;
-  }
-  if(get_pos().x >= camera->get_translation().x + screen->w - bbox.get_width())
-  {
-    bbox.set_pos(Vector(
-          camera->get_translation().x + screen->w - bbox.get_width(),
-          get_pos().y));
-    adjust = true;
-  }
-
-  if(adjust) {
-    // FIXME
-#if 0
-    // squished now?
-    if(collision_object_map(bbox)) {
-      kill(KILL);
-      return;
-    }
-#endif
-  }
-}
-
-void
-Player::bounce(BadGuy& )
-{
-  //Make sure we stopped flapping
-  flapping = false;
-  falling_from_flap = false;
-  
-  if (input.jump)
-    physic.set_velocity_y(520);
-  else
-    physic.set_velocity_y(200);
-}
-
diff --git a/src/player.h b/src/player.h
deleted file mode 100644 (file)
index be6398c..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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.
-#ifndef SUPERTUX_PLAYER_H
-#define SUPERTUX_PLAYER_H
-
-#include "SDL.h"
-
-#include "timer.h"
-#include "video/surface.h"
-#include "special/moving_object.h"
-#include "special/sprite.h"
-#include "math/physic.h"
-#include "defines.h"
-
-using namespace SuperTux;
-
-class BadGuy;
-
-/* Times: */
-
-#define TUX_SAFE_TIME 1.250
-#define TUX_INVINCIBLE_TIME 10.0
-#define TUX_INVINCIBLE_TIME_WARNING 2.0
-#define TUX_FLAPPING_TIME 1 /* How long Tux can flap his wings to gain additional jump height */
-#define TIME_WARNING 20     /* When to alert player they're low on time! */
-
-/* Scores: */
-
-#define SCORE_BRICK 5
-#define SCORE_DISTRO 20
-
-/* Sizes: */
-
-#define SMALL 0
-#define BIG 1
-
-#include <vector>
-
-struct PlayerKeymap
-{
-public:
-  int jump;
-  int up;
-  int down;
-  int left;
-  int right;
-  int power;
-  
-  PlayerKeymap();
-};
-
-extern PlayerKeymap keymap;
-
-struct player_input_type
-{
-  int right;
-  int left;
-  int up;
-  int old_up;
-  int down;
-  int fire;
-  int old_fire;
-  int activate;
-  int jump;
-  int old_jump;
-};
-
-void player_input_init(player_input_type* pplayer_input);
-
-class Camera;
-class PlayerStatus;
-
-extern Surface* tux_life;
-
-extern Sprite* smalltux_gameover;
-extern Sprite* smalltux_star;
-extern Sprite* bigtux_star;
-
-#define GROWING_TIME 1.0
-#define GROWING_FRAMES 7
-extern Surface* growingtux_left[GROWING_FRAMES];
-extern Surface* growingtux_right[GROWING_FRAMES];
-
-class TuxBodyParts
-{
-public:
-  TuxBodyParts()
-    : head(0), body(0), arms(0), feet(0)
-  { }
-  ~TuxBodyParts() {
-    delete head;
-    delete body;
-    delete arms;
-    delete feet;
-  }
-
-  void set_action(std::string action, int loops = -1);
-  void one_time_animation();
-  void draw(DrawingContext& context, const Vector& pos, int layer,
-                Uint32 drawing_effect = NONE_EFFECT);
-
-  Sprite* head;
-  Sprite* body;
-  Sprite* arms;
-  Sprite* feet;
-};
-
-extern TuxBodyParts* small_tux;
-extern TuxBodyParts* big_tux;
-extern TuxBodyParts* fire_tux;
-extern TuxBodyParts* ice_tux;
-
-class Player : public MovingObject
-{
-public:
-  enum HurtMode { KILL, SHRINK };
-  enum Power { NONE_POWER, FIRE_POWER, ICE_POWER };
-  enum FallMode { ON_GROUND, JUMPING, TRAMPOLINE_JUMP, FALLING };
-
-  player_input_type  input;
-  int got_power;
-  int size;
-  bool duck;
-  bool holding_something;
-  bool dead;
-  DyingType dying;
-
-  Direction dir;
-  Direction old_dir;
-
-  float last_ground_y;
-  FallMode fall_mode;
-
-  bool on_ground_flag;
-  bool jumping;
-  bool flapping;
-  bool can_jump;
-  bool can_flap;
-  bool falling_from_flap;
-  bool enable_hover;
-  bool butt_jump;
-  
-  float flapping_velocity;
-
-  // Ricardo's flapping
-  int flaps_nb;
-
-  // temporary to help player's choosing a flapping
-  enum { MAREK_FLAP, RICARDO_FLAP, RYAN_FLAP, NONE_FLAP };
-  int flapping_mode;
-
-  Timer2 invincible_timer;
-  Timer2 skidding_timer;
-  Timer2 safe_timer;
-  Timer2 kick_timer;
-  Timer2 shooting_timer;   // used to show the arm when Tux is shooting
-  Timer2 dying_timer;
-  Timer2 growing_timer;
-  Timer2 idle_timer;
-  Timer2 flapping_timer;
-  Physic physic;
-  
-public:
-  Player();
-  virtual ~Player();
-  
-  int  key_event(SDLKey key, int state);
-  void level_begin();
-  void handle_input();
-  void grabdistros();
-
-  PlayerStatus& get_status();
-
-  virtual void action(float elapsed_time);
-  virtual void draw(DrawingContext& context);
-  virtual HitResponse collision(GameObject& other, const CollisionHit& hit);
-
-  void make_invincible();
-  bool is_invincible() const
-  {
-      return invincible_timer.started();
-  }
-  void kill(HurtMode mode);
-  void player_remove_powerups();
-  void check_bounds(Camera* camera);
-  bool on_ground();
-  bool under_solid();
-  void grow(bool animate = false);
-  void move(const Vector& vector);
-
-  void bounce(BadGuy& badguy);
-
-  bool is_dead() const
-  { return dead; }
-  
-private:
-  void init();
-  
-  void handle_horizontal_input();
-  void handle_vertical_input();
-  void remove_powerups();
-};
-
-#endif /*SUPERTUX_PLAYER_H*/
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
index da92958..5267f4b 100644 (file)
@@ -25,9 +25,9 @@
 #include "gui/menu.h"
 #include "gui/button.h"
 #include "scene.h"
-#include "player.h"
-#include "gameobjs.h"
 #include "resources.h"
+#include "object/gameobjs.h"
+#include "object/player.h"
 
 Surface* img_waves[3]; 
 Surface* img_water;
index fedeee5..9873100 100644 (file)
 #include "app/globals.h"
 #include "sector.h"
 #include "utils/lispreader.h"
-#include "gameobjs.h"
-#include "camera.h"
-#include "background.h"
-#include "particlesystem.h"
+#include "object/gameobjs.h"
+#include "object/camera.h"
+#include "object/background.h"
+#include "object/particlesystem.h"
+#include "object/tilemap.h"
 #include "tile.h"
-#include "tilemap.h"
 #include "audio/sound_manager.h"
 #include "gameloop.h"
 #include "resources.h"
@@ -69,13 +69,13 @@ Sector::Sector()
   song_title = "Mortimers_chipdisko.mod";
   player = new Player();
   add_object(player);
-
-  printf("seccreated: %p.\n", this);
 }
 
 Sector::~Sector()
 {
-  printf("secdel: %p.\n", this);
+  update_game_objects();
+  assert(gameobjects_new.size() == 0);
+
   for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
       ++i) {
     delete *i;
@@ -89,23 +89,6 @@ Sector::~Sector()
     _current = 0;
 }
 
-Sector *Sector::create(const std::string& name, size_t width, size_t height)
-{
-  Sector *sector = new Sector;
-  sector->name = name;
-  TileMap *background = new TileMap(LAYER_BACKGROUNDTILES, false, width, height);
-  TileMap *interactive = new TileMap(LAYER_TILES, true, width, height);
-  TileMap *foreground = new TileMap(LAYER_FOREGROUNDTILES, false, width, height);
-  sector->add_object(background);
-  sector->add_object(interactive);
-  sector->add_object(foreground);
-  sector->solids = interactive;
-  sector->camera = new Camera(sector);
-  sector->add_object(sector->camera);
-  sector->update_game_objects();
-  return sector;
-}
-
 GameObject*
 Sector::parse_object(const std::string& name, LispReader& reader)
 {
@@ -151,14 +134,6 @@ Sector::parse_object(const std::string& name, LispReader& reader)
   } else if(name == "nolok_01") {
     return new Nolok_01(reader);
   }
-#if 0
-    else if(badguykind_from_string(name) != BAD_INVALID) {
-      return new BadGuy(badguykind_from_string(name), reader);
-    } else if(name == "trampoline") {
-      return new Trampoline(reader);
-    } else if(name == "flying-platform") {
-      return new FlyingPlatform(reader);
-#endif
 
   std::cerr << "Unknown object type '" << name << "'.\n";
   return 0;
@@ -197,6 +172,9 @@ Sector::parse(LispReader& lispreader)
     }
   }
 
+  update_game_objects();
+  fix_old_tiles();
+  update_game_objects();
   if(!camera) {
     std::cerr << "sector '" << name << "' does not contain a camera.\n";
     camera = new Camera(this);
@@ -237,11 +215,11 @@ Sector::parse_old_format(LispReader& reader)
   bkgd_bottom.blue = b;
   
   if(backgroundimage != "") {
-    background = new Background;
+    Background* background = new Background;
     background->set_image(backgroundimage, bgspeed);
     add_object(background);
   } else {
-    background = new Background;
+    Background* background = new Background;
     background->set_gradient(bkgd_top, bkgd_bottom);
     add_object(background);
   }
@@ -275,10 +253,7 @@ Sector::parse_old_format(LispReader& reader)
       || reader.read_int_vector("tilemap", tiles)) {
     TileMap* tilemap = new TileMap();
     tilemap->set(width, height, tiles, LAYER_TILES, true);
-    solids = tilemap;
     add_object(tilemap);
-
-    fix_old_tiles();
   }
 
   if(reader.read_int_vector("background-tm", tiles)) {
@@ -338,8 +313,14 @@ Sector::parse_old_format(LispReader& reader)
   }
 
   // add a camera
-  camera = new Camera(this);
+  Camera* camera = new Camera(this);
   add_object(camera);
+
+  update_game_objects();
+  fix_old_tiles();
+  update_game_objects();
+  if(solids == 0)
+    throw std::runtime_error("sector does not contain a solid tile layer.");  
 }
 
 void
@@ -411,41 +392,6 @@ Sector::write(LispWriter& writer)
 }
 
 void
-Sector::do_vertical_flip()
-{
-  // remove or fix later
-#if 0
-  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;
-  }
-#endif
-}
-
-void
 Sector::add_object(GameObject* object)
 {
   // make sure the object isn't already in the list
@@ -536,8 +482,7 @@ Sector::action(float elapsed_time)
   }
                                                                                 
   /* Handle all possible collisions. */
-  collision_handler();
-                                                                                
+  collision_handler();                                                                              
   update_game_objects();
 }
 
@@ -573,7 +518,6 @@ Sector::update_game_objects()
     if(tilemap && tilemap->is_solid()) {
       if(solids == 0) {
         solids = tilemap;
-        fix_old_tiles();
       } else {
         std::cerr << "Another solid tilemaps added. Ignoring.";
       }
@@ -774,14 +718,6 @@ Sector::collision_handler()
   }
 }
 
-void
-Sector::add_score(const Vector& pos, int s)
-{
-  global_stats.add_points(SCORE_STAT, s);
-                                                                                
-  add_object(new FloatingText(pos, s));
-}
-                                                                                
 bool
 Sector::add_bullet(const Vector& pos, float xm, Direction dir)
 {
index 598842b..a30e5d4 100644 (file)
@@ -67,8 +67,6 @@ public:
   Sector();
   ~Sector();
 
-  /// create new sector
-  static Sector *create(const std::string& name, size_t width, size_t height);
   /// read sector from lisp file
   void parse(LispReader& reader);
   void parse_old_format(LispReader& reader);
@@ -88,6 +86,8 @@ public:
   /// adds a gameobject
   void add_object(GameObject* object);
 
+  void set_name(const std::string& name)
+  { this->name = name; }
   const std::string& get_name() const
   { return name; }
 
@@ -102,16 +102,10 @@ public:
       case (or not). */
   void collision_handler();
 
-  void add_score(const Vector& pos, int s);
   bool add_bullet(const Vector& pos, float xm, Direction dir);
   bool add_smoke_cloud(const Vector& pos);
   void add_floating_text(const Vector& pos, const std::string& text);
                                                                                 
-  /** Flip the all the sector vertically. The purpose of this is to let
-      player to play the same level in a different way :) */
-  void do_vertical_flip();
-
   /** @evil@ but can#t always be avoided in current design... */
   static Sector* current()
   { return _current; }
index 23a3fcf..77ea138 100644 (file)
@@ -39,7 +39,6 @@
 #include "video/surface.h"
 #include "tile_manager.h"
 #include "app/gettext.h"
-#include "player.h"
 #include "misc.h"
 #include "utils/configfile.h"
 
diff --git a/src/tilemap.cpp b/src/tilemap.cpp
deleted file mode 100644 (file)
index 0878441..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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 <config.h>
-
-#include <cassert>
-#include <algorithm>
-#include <iostream>
-#include <stdexcept>
-#include <cmath>
-
-#include "tilemap.h"
-#include "video/drawing_context.h"
-#include "level.h"
-#include "tile.h"
-#include "tile_manager.h"
-#include "app/globals.h"
-#include "utils/lispreader.h"
-#include "utils/lispwriter.h"
-
-TileMap::TileMap()
-  : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
-    vertical_flip(false)
-{
-  tilemanager = TileManager::instance();
-
-  if(solid)
-    flags |= FLAG_SOLID;
-}
-
-TileMap::TileMap(LispReader& reader)
-  : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
-    vertical_flip(false)
-{
-  tilemanager = TileManager::instance();
-
-  std::string layer_str;
-  if(reader.read_string("layer", layer_str)) {
-    if(layer_str == "background")
-      layer = LAYER_BACKGROUNDTILES;
-    else if(layer_str == "interactive")
-      layer = LAYER_TILES;
-    else if(layer_str == "foreground")
-      layer = LAYER_FOREGROUNDTILES;
-    else
-      std::cerr << "Unknown layer '" << layer_str << "' in tilemap.\n";
-  }
-
-  reader.read_bool("solid", solid);
-  reader.read_float("speed", speed);
-
-  if(solid && speed != 1) {
-    std::cout << "Speed of solid tilemap is not 1. fixing.\n";
-    speed = 1;
-  }
-  if(solid)
-    flags |= FLAG_SOLID;
-  
-  if(!reader.read_int("width", width) ||
-     !reader.read_int("height", height))
-    throw std::runtime_error("No width or height specified in tilemap.");
-
-  if(!reader.read_int_vector("tiles", tiles))
-    throw std::runtime_error("No tiles in tilemap.");
-
-  if(int(tiles.size()) != width*height)
-    throw std::runtime_error("wrong number of tiles in tilemap.");
-}
-
-TileMap::TileMap(int layer_, bool solid_, size_t width_, size_t height_)
-  : solid(solid_), speed(1), width(0), height(0), layer(layer_),
-    vertical_flip(false)
-{
-  tilemanager = TileManager::instance();
-  
-  resize(width_, height_);
-
-  if(solid)
-    flags |= FLAG_SOLID;  
-}
-
-TileMap::~TileMap()
-{
-}
-
-void
-TileMap::write(LispWriter& writer)
-{
-  writer.start_list("tilemap");
-
-  if(layer == LAYER_BACKGROUNDTILES)
-    writer.write_string("layer", "background");
-  else if(layer == LAYER_TILES)
-    writer.write_string("layer", "interactive");
-  else if(layer == LAYER_FOREGROUNDTILES)
-    writer.write_string("layer", "foreground");
-  else {
-    writer.write_string("layer", "unknown");
-    std::cerr << "Warning unknown layer in tilemap.\n";
-  }
-
-  writer.write_bool("solid", solid);
-  writer.write_float("speed", speed);
-  writer.write_int("width", width);
-  writer.write_int("height", height);
-  writer.write_int_vector("tiles", tiles);
-  
-  writer.end_list("tilemap");
-}
-
-void
-TileMap::action(float )
-{
-}
-
-void
-TileMap::draw(DrawingContext& context)
-{
-  context.push_transform();
-
-  if(vertical_flip)
-    context.set_drawing_effect(VERTICAL_FLIP); 
-  float trans_x = roundf(context.get_translation().x);
-  float trans_y = roundf(context.get_translation().y);
-  context.set_translation(Vector(trans_x * speed, trans_y * speed));
-
-  /** if we don't round here, we'll have a 1 pixel gap on screen sometimes.
-   * I have no idea why */
-  float start_x = roundf(context.get_translation().x);
-  float start_y = roundf(context.get_translation().y);
-  float end_x = std::min(start_x + screen->w, float(width * 32));
-  float end_y = std::min(start_y + screen->h, float(height * 32));
-  start_x -= int(start_x) % 32;
-  start_y -= int(start_y) % 32;  
-  int tsx = int(start_x / 32); // tilestartindex x
-  int tsy = int(start_y / 32); // tilestartindex y
-
-  Vector pos;
-  int tx, ty;
-  for(pos.x = start_x, tx = tsx; pos.x < end_x; pos.x += 32, ++tx) {
-    for(pos.y = start_y, ty = tsy; pos.y < end_y; pos.y += 32, ++ty) {
-      const Tile* tile = tilemanager->get(tiles[ty*width + tx]);
-      assert(tile != 0);
-      tile->draw(context, pos, layer);
-    }
-  }
-
-  if (debug_grid)
-  {
-    for (pos.x = start_x; pos.x < end_x; pos.x += 32)
-    {
-       context.draw_filled_rect(Vector (pos.x, start_y), Vector(1, fabsf(start_y - end_y)),
-                  Color(225, 225, 225), LAYER_GUI-50);
-    }
-
-    for (pos.y = start_y; pos.y < end_y; pos.y += 32)
-    {
-       context.draw_filled_rect(Vector (start_x, pos.y), Vector(fabsf(start_x - end_x), 1),
-                  Color(225, 225, 225), LAYER_GUI-50);
-    }
-  }
-
-  context.pop_transform();
-}
-
-void
-TileMap::set(int newwidth, int newheight, const std::vector<unsigned int>&newt,
-    int newlayer, bool newsolid)
-{
-  assert(int(newt.size()) == newwidth * newheight);
-
-  width  = newwidth;
-  height = newheight;
-
-  tiles.resize(newt.size());
-  tiles = newt;
-
-  layer  = newlayer;
-  solid  = newsolid;
-  if(solid)
-    flags |= FLAG_SOLID;
-}
-
-void
-TileMap::resize(int new_width, int new_height)
-{
-  if(new_width < width) {
-    // remap tiles for new width
-    for(int y = 0; y < height && y < new_height; ++y) {
-      for(int x = 0; x < new_width; ++x) {
-        tiles[y * new_width + x] = tiles[y * width + x];
-      }
-    }
-  }
-                                                                                
-  tiles.resize(new_width * new_height);
-                                                                                
-  if(new_width > width) {
-    // remap tiles
-    for(int y = std::min(height, new_height)-1; y >= 0; --y) {
-      for(int x = new_width-1; x >= 0; --x) {
-        if(x >= width) {
-          tiles[y * new_width + x] = 0;
-          continue;
-        }
-        
-        tiles[y * new_width + x] = tiles[y * width + x];
-      }
-    }
-  }
-
-  height = new_height;
-  width = new_width;
-}
-
-void
-TileMap::do_vertical_flip()
-{
-  // remap tiles vertically flipped
-  for(int y = 0; y < height / 2; ++y) {
-    for(int x = 0; x < width; ++x) {
-      std::swap(tiles[y*width + x], tiles[(((height-1)*width) - (y*width)) + x]);
-    }
-  }
-
-  vertical_flip = true;
-}
-
-const Tile*
-TileMap::get_tile(int x, int y) const
-{
-  if(x < 0 || x >= width || y < 0 || y >= height) {
-#ifdef DEBUG
-    //std::cout << "Warning: tile outside tilemap requested!\n";
-#endif
-    return tilemanager->get(0);
-  }
-
-  return tilemanager->get(tiles[y*width + x]);
-}
-
-const Tile*
-TileMap::get_tile_at(const Vector& pos) const
-{
-  return get_tile(int(pos.x)/32, int(pos.y)/32);
-}
-
-void
-TileMap::change(int x, int y, uint32_t newtile)
-{
-  assert(x >= 0 && x < width && y >= 0 && y < height);
-  tiles[y*width + x] = newtile;
-}
-
-void
-TileMap::change_at(const Vector& pos, uint32_t newtile)
-{
-  change(int(pos.x)/32, int(pos.y)/32, newtile);
-}
diff --git a/src/tilemap.h b/src/tilemap.h
deleted file mode 100644 (file)
index 8aa2b48..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  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.
-
-#ifndef SUPERTUX_TILEMAP_H
-#define SUPERTUX_TILEMAP_H
-
-#include <vector>
-#include <stdint.h>
-
-#include "special/game_object.h"
-#include "serializable.h"
-#include "math/vector.h"
-
-using namespace SuperTux;
-
-namespace SuperTux {
-class LispReader;
-}
-
-class Level;
-class TileManager;
-class Tile;
-
-/**
- * This class is reponsible for drawing the level tiles
- */
-class TileMap : public GameObject, public Serializable
-{
-public:
-  TileMap();
-  TileMap(LispReader& reader);
-  TileMap(int layer_, bool solid_, size_t width_, size_t height_);
-  virtual ~TileMap();
-
-  virtual void write(LispWriter& writer);
-
-  virtual void action(float elapsed_time);
-  virtual void draw(DrawingContext& context);
-
-  void set(int width, int height, const std::vector<unsigned int>& vec,
-      int layer, bool solid);
-
-  /** resizes the tilemap to a new width and height (tries to not destroy the
-   * existing map)
-   */
-  void resize(int newwidth, int newheight);
-
-  /** Flip the all tile map vertically. The purpose of this is to let
-      player to play the same level in a different way :) */
-  void do_vertical_flip();
-
-  size_t get_width() const
-  { return width; }
-
-  size_t get_height() const
-  { return height; }
-
-  int get_layer() const
-  { return layer; }
-  
-  bool is_solid() const
-  { return solid; }
-
-  /// returns tile in row y and column y (of the tilemap)
-  const Tile* get_tile(int x, int y) const;
-  /// returns tile at position pos (in world coordinates)
-  const Tile* get_tile_at(const Vector& pos) const;
-
-  void change(int x, int y, uint32_t newtile);
-
-  void change_at(const Vector& pos, uint32_t newtile);
-
-private:
-  std::vector<uint32_t> tiles;
-  
-private:
-  TileManager* tilemanager;
-  bool solid;
-  float speed;
-  int width, height;
-  int layer;
-
-  bool vertical_flip;
-};
-
-#endif /*SUPERTUX_TILEMAP_H*/
-
index 4874916..714f9bd 100644 (file)
 #include "worldmap.h"
 #include "leveleditor.h"
 #include "scene.h"
-#include "player.h"
 #include "tile.h"
 #include "sector.h"
-#include "tilemap.h"
+#include "object/tilemap.h"
+#include "object/camera.h"
+#include "object/player.h"
 #include "resources.h"
 #include "app/gettext.h"
 #include "misc.h"
-#include "camera.h"
 
 static Surface* bkg_title;
 static Surface* logo;
index e6b143a..608b784 100644 (file)
@@ -19,8 +19,8 @@
 #include <config.h>
 
 #include "trigger_base.h"
-#include "player.h"
 #include "video/drawing_context.h"
+#include "object/player.h"
 
 TriggerBase::TriggerBase()
   : sprite(0)