Bug 100: Flip slopes properly.
[supertux.git] / src / supertux / sector.cpp
index 73dc1e7..e0ebde1 100644 (file)
 #include "object/brick.hpp"
 #include "object/bullet.hpp"
 #include "object/camera.hpp"
+#include "object/cloud_particle_system.hpp"
 #include "object/coin.hpp"
+#include "object/comet_particle_system.hpp"
 #include "object/display_effect.hpp"
+#include "object/ghost_particle_system.hpp"
 #include "object/gradient.hpp"
 #include "object/invisible_block.hpp"
 #include "object/particlesystem.hpp"
-#include "object/cloud_particle_system.hpp"
-#include "object/ghost_particle_system.hpp"
-#include "object/snow_particle_system.hpp"
 #include "object/particlesystem_interactive.hpp"
 #include "object/player.hpp"
 #include "object/portable.hpp"
 #include "object/pulsing_light.hpp"
+#include "object/rain_particle_system.hpp"
 #include "object/smoke_cloud.hpp"
+#include "object/snow_particle_system.hpp"
 #include "object/text_object.hpp"
 #include "object/tilemap.hpp"
-#include "physfs/physfs_stream.hpp"
+#include "physfs/ifile_stream.hpp"
 #include "scripting/squirrel_util.hpp"
 #include "supertux/collision.hpp"
 #include "supertux/constants.hpp"
+#include "supertux/game_session.hpp"
+#include "supertux/globals.hpp"
 #include "supertux/level.hpp"
-#include "supertux/main.hpp"
 #include "supertux/object_factory.hpp"
+#include "supertux/player_status.hpp"
 #include "supertux/spawn_point.hpp"
 #include "supertux/tile.hpp"
 #include "trigger/sequence_trigger.hpp"
@@ -81,32 +85,32 @@ Sector::Sector(Level* parent) :
   camera(0), 
   effect(0)
 {
-  add_object(new Player(player_status, "Tux"));
+  add_object(new Player(GameSession::current()->get_player_status(), "Tux"));
   add_object(new DisplayEffect("Effect"));
   add_object(new TextObject("Text"));
 
   sound_manager->preload("sounds/shoot.wav");
 
   // create a new squirrel table for the sector
-  using namespace Scripting;
+  using namespace scripting;
 
   sq_collectgarbage(global_vm);
 
   sq_newtable(global_vm);
   sq_pushroottable(global_vm);
   if(SQ_FAILED(sq_setdelegate(global_vm, -2)))
-    throw Scripting::SquirrelError(global_vm, "Couldn't set sector_table delegate");
+    throw scripting::SquirrelError(global_vm, "Couldn't set sector_table delegate");
 
   sq_resetobject(&sector_table);
   if(SQ_FAILED(sq_getstackobj(global_vm, -1, &sector_table)))
-    throw Scripting::SquirrelError(global_vm, "Couldn't get sector table");
+    throw scripting::SquirrelError(global_vm, "Couldn't get sector table");
   sq_addref(global_vm, &sector_table);
   sq_pop(global_vm, 1);
 }
 
 Sector::~Sector()
 {
-  using namespace Scripting;
+  using namespace scripting;
 
   deactivate();
 
@@ -168,15 +172,14 @@ Sector::parse_object(const std::string& name, const Reader& reader)
     return partsys;
   } else if(name == "money") { // for compatibility with old maps
     return new Jumpy(reader);
+  } else {
+    try {
+      return ObjectFactory::instance().create(name, reader);
+    } catch(std::exception& e) {
+      log_warning << e.what() << "" << std::endl;
+      return 0;
+    }
   }
-
-  try {
-    return create_object(name, reader);
-  } catch(std::exception& e) {
-    log_warning << e.what() << "" << std::endl;
-  }
-
-  return 0;
 }
 
 void
@@ -193,7 +196,7 @@ Sector::parse(const Reader& sector)
     } else if(token == "music") {
       iter.value()->get(music);
     } else if(token == "spawnpoint") {
-      SpawnPoint* sp = new SpawnPoint(iter.lisp());
+      SpawnPoint* sp = new SpawnPoint(*iter.lisp());
       spawnpoints.push_back(sp);
     } else if(token == "init-script") {
       iter.value()->get(init_script);
@@ -464,7 +467,7 @@ Sector::fix_old_tiles()
 HSQUIRRELVM
 Sector::run_script(std::istream& in, const std::string& sourcename)
 {
-  using namespace Scripting;
+  using namespace scripting;
 
   // garbage collect thread list
   for(ScriptList::iterator i = scripts.begin();
@@ -503,7 +506,7 @@ void
 Sector::add_object(GameObject* object)
 {
   // make sure the object isn't already in the list
-#ifdef DEBUG
+#ifndef NDEBUG
   for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
       ++i) {
     if(*i == object) {
@@ -554,12 +557,12 @@ Sector::activate(const Vector& player_pos)
     _current = this;
 
     // register sectortable as sector in scripting
-    HSQUIRRELVM vm = Scripting::global_vm;
+    HSQUIRRELVM vm = scripting::global_vm;
     sq_pushroottable(vm);
     sq_pushstring(vm, "sector", -1);
     sq_pushobject(vm, sector_table);
     if(SQ_FAILED(sq_createslot(vm, -3)))
-      throw Scripting::SquirrelError(vm, "Couldn't set sector in roottable");
+      throw scripting::SquirrelError(vm, "Couldn't set sector in roottable");
     sq_pop(vm, 1);
 
     for(GameObjects::iterator i = gameobjects.begin();
@@ -615,11 +618,11 @@ Sector::deactivate()
     return;
 
   // remove sector entry from global vm
-  HSQUIRRELVM vm = Scripting::global_vm;
+  HSQUIRRELVM vm = scripting::global_vm;
   sq_pushroottable(vm);
   sq_pushstring(vm, "sector", -1);
   if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
-    throw Scripting::SquirrelError(vm, "Couldn't unset sector in roottable");
+    throw scripting::SquirrelError(vm, "Couldn't unset sector in roottable");
   sq_pop(vm, 1);
 
   for(GameObjects::iterator i = gameobjects.begin();
@@ -633,10 +636,10 @@ Sector::deactivate()
   _current = NULL;
 }
 
-Rect
+Rectf
 Sector::get_active_region()
 {
-  return Rect(
+  return Rectf(
     camera->get_translation() - Vector(1600, 1200),
     camera->get_translation() + Vector(1600, 1200) + Vector(SCREEN_WIDTH,SCREEN_HEIGHT));
 }
@@ -765,11 +768,11 @@ Sector::before_object_add(GameObject* object)
 void
 Sector::try_expose(GameObject* object)
 {
-  ScriptInterface* interface = dynamic_cast<ScriptInterface*> (object);
-  if(interface != NULL) {
-    HSQUIRRELVM vm = Scripting::global_vm;
+  ScriptInterface* object_ = dynamic_cast<ScriptInterface*> (object);
+  if(object_ != NULL) {
+    HSQUIRRELVM vm = scripting::global_vm;
     sq_pushobject(vm, sector_table);
-    interface->expose(vm, -1);
+    object_->expose(vm, -1);
     sq_pop(vm, 1);
   }
 }
@@ -777,10 +780,10 @@ Sector::try_expose(GameObject* object)
 void
 Sector::try_expose_me()
 {
-  HSQUIRRELVM vm = Scripting::global_vm;
+  HSQUIRRELVM vm = scripting::global_vm;
   sq_pushobject(vm, sector_table);
-  Scripting::SSector* interface = static_cast<Scripting::SSector*> (this);
-  expose_object(vm, -1, interface, "settings", false);
+  scripting::SSector* this_ = static_cast<scripting::SSector*> (this);
+  expose_object(vm, -1, this_, "settings", false);
   sq_pop(vm, 1);
 }
 
@@ -808,13 +811,13 @@ Sector::before_object_remove(GameObject* object)
 void
 Sector::try_unexpose(GameObject* object)
 {
-  ScriptInterface* interface = dynamic_cast<ScriptInterface*> (object);
-  if(interface != NULL) {
-    HSQUIRRELVM vm = Scripting::global_vm;
+  ScriptInterface* object_ = dynamic_cast<ScriptInterface*> (object);
+  if(object_ != NULL) {
+    HSQUIRRELVM vm = scripting::global_vm;
     SQInteger oldtop = sq_gettop(vm);
     sq_pushobject(vm, sector_table);
     try {
-      interface->unexpose(vm, -1);
+      object_->unexpose(vm, -1);
     } catch(std::exception& e) {
       log_warning << "Couldn't unregister object: " << e.what() << std::endl;
     }
@@ -825,11 +828,11 @@ Sector::try_unexpose(GameObject* object)
 void
 Sector::try_unexpose_me()
 {
-  HSQUIRRELVM vm = Scripting::global_vm;
+  HSQUIRRELVM vm = scripting::global_vm;
   SQInteger oldtop = sq_gettop(vm);
   sq_pushobject(vm, sector_table);
   try {
-    Scripting::unexpose_object(vm, -1, "settings");
+    scripting::unexpose_object(vm, -1, "settings");
   } catch(std::exception& e) {
     log_warning << "Couldn't unregister object: " << e.what() << std::endl;
   }
@@ -863,7 +866,7 @@ Sector::draw(DrawingContext& context)
     for(MovingObjects::iterator i = moving_objects.begin();
         i != moving_objects.end(); ++i) {
       MovingObject* object = *i;
-      const Rect& rect = object->get_bbox();
+      const Rectf& rect = object->get_bbox();
 
       context.draw_filled_rect(rect, col, LAYER_FOREGROUND1 + 10);
     }
@@ -878,7 +881,7 @@ Sector::draw(DrawingContext& context)
 
 /** r1 is supposed to be moving, r2 a solid object */
 void check_collisions(collision::Constraints* constraints,
-                      const Vector& movement, const Rect& r1, const Rect& r2,
+                      const Vector& movement, const Rectf& r1, const Rectf& r2,
                       GameObject* object = NULL, MovingObject* other = NULL, const Vector& addl_ground_movement = Vector(0,0))
 {
   if(!collision::intersects(r1, r2))
@@ -899,19 +902,19 @@ void check_collisions(collision::Constraints* constraints,
 
   if(fabsf(movement.y) > fabsf(movement.x)) {
     if(ileft < SHIFT_DELTA) {
-      constraints->right = std::min(constraints->right, r2.get_left());
+      constraints->min_right(r2.get_left());
       return;
     } else if(iright < SHIFT_DELTA) {
-      constraints->left = std::max(constraints->left, r2.get_right());
+      constraints->max_left(r2.get_right());
       return;
     }
   } else {
     // shiftout bottom/top
     if(itop < SHIFT_DELTA) {
-      constraints->bottom = std::min(constraints->bottom, r2.get_top());
+      constraints->min_bottom(r2.get_top());
       return;
     } else if(ibottom < SHIFT_DELTA) {
-      constraints->top = std::max(constraints->top, r2.get_bottom());
+      constraints->max_top(r2.get_bottom());
       return;
     }
   }
@@ -919,7 +922,7 @@ void check_collisions(collision::Constraints* constraints,
   constraints->ground_movement += addl_ground_movement;
   if(other != NULL) {
     HitResponse response = other->collision(*object, dummy);
-    if(response == PASSTHROUGH)
+    if(response == ABORT_MOVE)
       return;
 
     if(other->get_movement() != Vector(0, 0)) {
@@ -932,18 +935,18 @@ void check_collisions(collision::Constraints* constraints,
   float horiz_penetration = std::min(ileft, iright);
   if(vert_penetration < horiz_penetration) {
     if(itop < ibottom) {
-      constraints->bottom = std::min(constraints->bottom, r2.get_top());
+      constraints->min_bottom(r2.get_top());
       constraints->hit.bottom = true;
     } else {
-      constraints->top = std::max(constraints->top, r2.get_bottom());
+      constraints->max_top(r2.get_bottom());
       constraints->hit.top = true;
     }
   } else {
     if(ileft < iright) {
-      constraints->right = std::min(constraints->right, r2.get_left());
+      constraints->min_right(r2.get_left());
       constraints->hit.right = true;
     } else {
-      constraints->left = std::max(constraints->left, r2.get_right());
+      constraints->max_left(r2.get_right());
       constraints->hit.left = true;
     }
   }
@@ -951,7 +954,7 @@ void check_collisions(collision::Constraints* constraints,
 
 void
 Sector::collision_tilemap(collision::Constraints* constraints,
-                          const Vector& movement, const Rect& dest) const
+                          const Vector& movement, const Rectf& dest) const
 {
   // calculate rectangle where the object will move
   float x1 = dest.get_left();
@@ -987,11 +990,14 @@ Sector::collision_tilemap(collision::Constraints* constraints,
           AATriangle triangle;
           Vector p1(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset());
           Vector p2((x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
-          triangle = AATriangle(p1, p2, tile->getData());
+          int slope_data = tile->getData();
+          if (solids->get_drawing_effect() == VERTICAL_FLIP)
+            slope_data = AATriangle::vertical_flip(slope_data);
+          triangle = AATriangle(p1, p2, slope_data);
 
           collision::rectangle_aatriangle(constraints, dest, triangle, solids->get_movement());
         } else { // normal rectangular tile
-          Rect rect(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset(), (x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
+          Rectf rect(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset(), (x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
           check_collisions(constraints, movement, dest, rect, NULL, NULL, solids->get_movement());
         }
       }
@@ -1000,12 +1006,12 @@ Sector::collision_tilemap(collision::Constraints* constraints,
 }
 
 uint32_t
-Sector::collision_tile_attributes(const Rect& dest) const
+Sector::collision_tile_attributes(const Rectf& dest) const
 {
   float x1 = dest.p1.x;
   float y1 = dest.p1.y;
   float x2 = dest.p2.x;
-  float y2 = dest.p2.y + SHIFT_DELTA;
+  float y2 = dest.p2.y;
 
   uint32_t result = 0;
   for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
@@ -1016,14 +1022,22 @@ Sector::collision_tile_attributes(const Rect& dest) const
     int starttiley = int(y1 - solids->get_y_offset()) / 32;
     int max_x = int(x2 - solids->get_x_offset());
     int max_y = int(y2+1 - solids->get_y_offset());
+    int max_y_ice = int(max_y + SHIFT_DELTA);
 
     for(int x = starttilex; x*32 < max_x; ++x) {
-      for(int y = starttiley; y*32 < max_y; ++y) {
+      int y;
+      for(y = starttiley; y*32 < max_y; ++y) {
         const Tile* tile = solids->get_tile(x, y);
         if(!tile)
           continue;
         result |= tile->getAttributes();
       }
+      for(; y*32 < max_y_ice; ++y) {
+        const Tile* tile = solids->get_tile(x, y);
+        if(!tile)
+          continue;
+        result |= (tile->getAttributes() & Tile::ICE);
+      }
     }
   }
 
@@ -1031,7 +1045,7 @@ Sector::collision_tile_attributes(const Rect& dest) const
 }
 
 /** fills in CollisionHit and Normal vector of 2 intersecting rectangle */
-static void get_hit_normal(const Rect& r1, const Rect& r2, CollisionHit& hit,
+static void get_hit_normal(const Rectf& r1, const Rectf& r2, CollisionHit& hit,
                            Vector& normal)
 {
   float itop = r1.get_bottom() - r2.get_top();
@@ -1065,8 +1079,8 @@ Sector::collision_object(MovingObject* object1, MovingObject* object2) const
 {
   using namespace collision;
 
-  const Rect& r1 = object1->dest;
-  const Rect& r2 = object2->dest;
+  const Rectf& r1 = object1->dest;
+  const Rectf& r2 = object2->dest;
 
   CollisionHit hit;
   if(intersects(object1->dest, object2->dest)) {
@@ -1102,7 +1116,7 @@ Sector::collision_object(MovingObject* object1, MovingObject* object2) const
 
 void
 Sector::collision_static(collision::Constraints* constraints,
-                         const Vector& movement, const Rect& dest,
+                         const Vector& movement, const Rectf& dest,
                          GameObject& object)
 {
   collision_tilemap(constraints, movement, dest);
@@ -1131,7 +1145,7 @@ Sector::collision_static_constrains(MovingObject& object)
 
   Constraints constraints;
   Vector movement = object.get_movement();
-  Rect& dest = object.dest;
+  Rectf& dest = object.dest;
   float owidth = object.get_bbox().get_width();
   float oheight = object.get_bbox().get_height();
 
@@ -1173,8 +1187,8 @@ Sector::collision_static_constrains(MovingObject& object)
       break;
 
     // apply calculated vertical constraints
-    if(constraints.right < infinity) {
-      float width = constraints.right - constraints.left;
+    float width = constraints.right - constraints.left;
+    if(width < infinity) {
       if(width + SHIFT_DELTA < owidth) {
 #if 0
         printf("Object %p crushed horizontally... L:%f R:%f\n", &object,
@@ -1186,9 +1200,13 @@ Sector::collision_static_constrains(MovingObject& object)
         h.crush = true;
         object.collision_solid(h);
       } else {
-        dest.p2.x = constraints.right - DELTA;
-        dest.p1.x = dest.p2.x - owidth;
+        float xmid = (constraints.left + constraints.right) / 2;
+        dest.p1.x = xmid - owidth/2;
+        dest.p2.x = xmid + owidth/2;
       }
+    } else if(constraints.right < infinity) {
+      dest.p2.x = constraints.right - DELTA;
+      dest.p1.x = dest.p2.x - owidth;
     } else if(constraints.left > -infinity) {
       dest.p1.x = constraints.left + DELTA;
       dest.p2.x = dest.p1.x + owidth;
@@ -1269,7 +1287,7 @@ Sector::handle_collisions()
       continue;
 
     uint32_t tile_attributes = collision_tile_attributes(moving_object->dest);
-    if(tile_attributes > Tile::FIRST_INTERESTING_FLAG) {
+    if(tile_attributes >= Tile::FIRST_INTERESTING_FLAG) {
       moving_object->collision_tile(tile_attributes);
     }
   }
@@ -1339,7 +1357,7 @@ Sector::handle_collisions()
 }
 
 bool
-Sector::is_free_of_tiles(const Rect& rect, const bool ignoreUnisolid) const
+Sector::is_free_of_tiles(const Rectf& rect, const bool ignoreUnisolid) const
 {
   using namespace collision;
 
@@ -1373,7 +1391,7 @@ Sector::is_free_of_tiles(const Rect& rect, const bool ignoreUnisolid) const
 }
 
 bool
-Sector::is_free_of_statics(const Rect& rect, const MovingObject* ignore_object, const bool ignoreUnisolid) const
+Sector::is_free_of_statics(const Rectf& rect, const MovingObject* ignore_object, const bool ignoreUnisolid) const
 {
   using namespace collision;
 
@@ -1393,7 +1411,7 @@ Sector::is_free_of_statics(const Rect& rect, const MovingObject* ignore_object,
 }
 
 bool
-Sector::is_free_of_movingstatics(const Rect& rect, const MovingObject* ignore_object) const
+Sector::is_free_of_movingstatics(const Rectf& rect, const MovingObject* ignore_object) const
 {
   using namespace collision;
 
@@ -1415,7 +1433,7 @@ Sector::is_free_of_movingstatics(const Rect& rect, const MovingObject* ignore_ob
 }
 
 bool
-Sector::add_bullet(const Vector& pos, float xm, Direction dir)
+Sector::add_bullet(const Vector& pos, const PlayerStatus* player_status, float xm, Direction dir)
 {
   // TODO remove this function and move these checks elsewhere...
 
@@ -1481,7 +1499,7 @@ Sector::get_total_badguys()
 }
 
 bool
-Sector::inside(const Rect& rect) const
+Sector::inside(const Rectf& rect) const
 {
   for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
     TileMap* solids = *i;