Let Tux bounce off badguys when he's invincible. This let's us bounce off guys like...
[supertux.git] / src / worldmap / worldmap.cpp
index 946b21f..8ae1a65 100644 (file)
@@ -150,6 +150,22 @@ WorldMap::WorldMap(const std::string& filename)
   worldmap_menu->add_entry(MNID_QUITWORLDMAP, _("Quit World"));
 
   load(filename);
+
+  // create a new squirrel table for the worldmap
+  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 worldmap_table delegate");
+
+  sq_resetobject(&worldmap_table);
+  if(SQ_FAILED(sq_getstackobj(global_vm, -1, &worldmap_table)))
+    throw Scripting::SquirrelError(global_vm, "Couldn't get table from stack");
+
+  sq_addref(global_vm, &worldmap_table);
+  sq_pop(global_vm, 1);              
 }
 
 WorldMap::~WorldMap()
@@ -161,13 +177,18 @@ WorldMap::~WorldMap()
     HSQOBJECT& object = *i;
     sq_release(global_vm, &object);
   }
+  sq_release(global_vm, &worldmap_table);
+
+  sq_collectgarbage(global_vm);
   
   if(current_ == this)
     current_ = NULL;
 
   for(GameObjects::iterator i = game_objects.begin();
-      i != game_objects.end(); ++i)
-    delete *i;
+      i != game_objects.end(); ++i) {
+    GameObject* object = *i;
+    object->unref();
+  }
 
   for(SpawnPoints::iterator i = spawn_points.begin();
       i != spawn_points.end(); ++i) {
@@ -183,6 +204,7 @@ WorldMap::add_object(GameObject* object)
     solids = tilemap;
   }
 
+  object->ref();
   game_objects.push_back(object);
 }
 
@@ -214,21 +236,23 @@ WorldMap::load(const std::string& filename)
         add_object(new Background(*(iter.lisp())));
       } else if(iter.item() == "music") {
         iter.value()->get(music);
+      } else if(iter.item() == "init-script") {
+        iter.value()->get(init_script);
       } else if(iter.item() == "worldmap-spawnpoint") {
         SpawnPoint* sp = new SpawnPoint(iter.lisp());
         spawn_points.push_back(sp);
       } else if(iter.item() == "level") {
         LevelTile* level = new LevelTile(levels_path, iter.lisp());
         levels.push_back(level);
-        game_objects.push_back(level);
+        add_object(level);
       } else if(iter.item() == "special-tile") {
         SpecialTile* special_tile = new SpecialTile(iter.lisp());
         special_tiles.push_back(special_tile);
-        game_objects.push_back(special_tile);
+        add_object(special_tile);
       } else if(iter.item() == "sprite-change") {
         SpriteChange* sprite_change = new SpriteChange(iter.lisp());
         sprite_changes.push_back(sprite_change);
-        game_objects.push_back(sprite_change);
+        add_object(sprite_change);
       } else if(iter.item() == "name") {
         // skip
       } else {
@@ -441,9 +465,8 @@ WorldMap::update(float delta)
   }
 
   // update GameObjects
-  for(GameObjects::iterator i = game_objects.begin();
-      i != game_objects.end(); ++i) {
-    GameObject* object = *i;
+  for(size_t i = 0; i < game_objects.size(); ++i) {
+    GameObject* object = game_objects[i];
     object->update(delta);
   }
 
@@ -452,7 +475,7 @@ WorldMap::update(float delta)
       i != game_objects.end(); ) {
     GameObject* object = *i;
     if(!object->is_valid()) {
-      delete object;
+      object->unref();
       i = game_objects.erase(i);
     } else {
       ++i;
@@ -643,6 +666,34 @@ WorldMap::setup()
 
   current_ = this;
   load_state();
+
+  // register worldmap_table as worldmap in scripting
+  using namespace Scripting;
+  
+  sq_pushroottable(global_vm);
+  sq_pushstring(global_vm, "worldmap", -1);
+  sq_pushobject(global_vm, worldmap_table);
+  if(SQ_FAILED(sq_createslot(global_vm, -3)))
+    throw SquirrelError(global_vm, "Couldn't set worldmap in roottable");
+  sq_pop(global_vm, 1);
+
+  if(init_script != "") {
+    std::istringstream in(init_script);
+    run_script(in, "WorldMap::init");
+  }
+}
+
+void
+WorldMap::leave()
+{
+  // remove worldmap_table from roottable
+  using namespace Scripting;
+
+  sq_pushroottable(global_vm);
+  sq_pushstring(global_vm, "worldmap", -1);
+  if(SQ_FAILED(sq_deleteslot(global_vm, -2, SQFalse)))
+    throw SquirrelError(global_vm, "Couldn't unset worldmap in roottable");
+  sq_pop(global_vm, 1);
 }
 
 static void store_float(HSQUIRRELVM vm, const char* name, float val)
@@ -922,6 +973,10 @@ WorldMap::run_script(std::istream& in, const std::string& sourcename)
 
   HSQUIRRELVM vm = object_to_vm(object);
 
+  // set worldmap_table as roottable for the thread
+  sq_pushobject(vm, worldmap_table);
+  sq_setroottable(vm);
+
   compile_and_run(vm, in, sourcename);
 
   return vm;