- beginnings of a wingling
[supertux.git] / src / leveleditor.cpp
index 2e24e8e..fdc3433 100644 (file)
@@ -19,6 +19,7 @@
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include <map>
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include <map>
+#include <typeinfo>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -27,6 +28,7 @@
 #include <unistd.h>
 #include <SDL.h>
 #include <SDL_image.h>
 #include <unistd.h>
 #include <SDL.h>
 #include <SDL_image.h>
+#include <algorithm>
 #include "leveleditor.h"
 
 #include "screen.h"
 #include "leveleditor.h"
 
 #include "screen.h"
@@ -42,6 +44,8 @@
 #include "tile.h"
 #include "resources.h"
 #include "music_manager.h"
 #include "tile.h"
 #include "resources.h"
 #include "music_manager.h"
+#include "background.h"
+#include "display_manager.h"
 
 /* definitions to aid development */
 
 
 /* definitions to aid development */
 
 
 #define MOUSE_LEFT_MARGIN 80
 #define MOUSE_RIGHT_MARGIN (560-32)
 
 #define MOUSE_LEFT_MARGIN 80
 #define MOUSE_RIGHT_MARGIN (560-32)
-/* right_margin should noticed that the cursor is 32 pixels,
-   so it should subtract that value */
-#define MOUSE_POS_SPEED 20
+
+/* scolling speed */
+#define KEYBOARD_SPEED 140
+#define MOUSE_SPEED    40
 
 /* look */
 #define SELECT_W 2 // size of the selections lines
 
 /* look */
 #define SELECT_W 2 // size of the selections lines
@@ -92,6 +97,8 @@ struct TileOrObject
   bool IsTile() { return is_tile; };
   //Returns true for a GameObject
   bool IsObject() { return !is_tile; };
   bool IsTile() { return is_tile; };
   //Returns true for a GameObject
   bool IsObject() { return !is_tile; };
+
+
   void Init() { tile = 0; obj = NULL; is_tile = true; };
 
   bool is_tile; //true for tile (false for object)
   void Init() { tile = 0; obj = NULL; is_tile = true; };
 
   bool is_tile; //true for tile (false for object)
@@ -105,7 +112,7 @@ static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
 static bool show_minimap;
 static bool show_selections;
 static bool le_help_shown;
 static bool show_minimap;
 static bool show_selections;
 static bool le_help_shown;
-static int pos_x, cursor_x, cursor_y, fire;
+static int pos_x, pos_y, cursor_x, cursor_y;
 static int le_level;
 static World* le_world;
 static LevelSubset* le_level_subset;
 static int le_level;
 static World* le_world;
 static LevelSubset* le_level_subset;
@@ -123,12 +130,16 @@ static Button* le_next_level_bt;
 static Button* le_previous_level_bt;
 static Button* le_move_right_bt;
 static Button* le_move_left_bt;
 static Button* le_previous_level_bt;
 static Button* le_move_right_bt;
 static Button* le_move_left_bt;
+static Button* le_move_up_bt;
+static Button* le_move_down_bt;
 static Button* le_rubber_bt;
 static Button* le_select_mode_one_bt;
 static Button* le_select_mode_two_bt;
 static Button* le_settings_bt;
 static Button* le_tilegroup_bt;
 static Button* le_objects_bt;
 static Button* le_rubber_bt;
 static Button* le_select_mode_one_bt;
 static Button* le_select_mode_two_bt;
 static Button* le_settings_bt;
 static Button* le_tilegroup_bt;
 static Button* le_objects_bt;
+static Button* le_object_select_bt;
+static Button* le_object_properties_bt;
 static ButtonPanel* le_tilemap_panel;
 static Menu* leveleditor_menu;
 static Menu* subset_load_menu;
 static ButtonPanel* le_tilemap_panel;
 static Menu* leveleditor_menu;
 static Menu* subset_load_menu;
@@ -139,14 +150,17 @@ static Menu* select_tilegroup_menu;
 static Menu* select_objects_menu;
 static Timer select_tilegroup_menu_effect;
 static Timer select_objects_menu_effect;
 static Menu* select_objects_menu;
 static Timer select_tilegroup_menu_effect;
 static Timer select_objects_menu_effect;
+static Timer display_level_info;
 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
 static ButtonPanelMap tilegroups_map;
 static ButtonPanelMap objects_map;
 static std::string cur_tilegroup;
 static std::string cur_objects;
 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
 static ButtonPanelMap tilegroups_map;
 static ButtonPanelMap objects_map;
 static std::string cur_tilegroup;
 static std::string cur_objects;
+static MouseCursor* mouse_select_object;
+static MovingObject* selected_game_object;
 
 static square selection;
 
 static square selection;
-static int le_selection_mode;
+static SelectionMode le_selection_mode;
 static SDL_Event event;
 TileMapType active_tm;
 
 static SDL_Event event;
 TileMapType active_tm;
 
@@ -203,10 +217,6 @@ int leveleditor(char* filename)
     if(le_world != NULL)
     {
       /* making events results to be in order */
     if(le_world != NULL)
     {
       /* making events results to be in order */
-      if(pos_x < 0)
-        pos_x = 0;
-      if(pos_x > (le_world->get_level()->width * 32) - screen->w)
-        pos_x = (le_world->get_level()->width * 32) - screen->w;
 
       /* draw the level */
       le_drawlevel();
 
       /* draw the level */
       le_drawlevel();
@@ -340,7 +350,7 @@ int leveleditor(char* filename)
       }
     }
 
       }
     }
 
-    mouse_cursor->draw();
+    MouseCursor::current()->draw();
 
     if(done)
     {
 
     if(done)
     {
@@ -433,22 +443,22 @@ void le_init_menus()
   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
+  level_settings_menu->additem(MN_NUMFIELD,    "Height  ",0,0,MNID_HEIGHT);
   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
-  level_settings_menu->additem(MN_NUMFIELD,    "Top Red    ",0,0,MNID_TopRed);
-  level_settings_menu->additem(MN_NUMFIELD,    "Top Green  ",0,0,MNID_TopGreen);
-  level_settings_menu->additem(MN_NUMFIELD,    "Top Blue   ",0,0,MNID_TopBlue);
-  level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red ",0,0,MNID_BottomRed);
+  level_settings_menu->additem(MN_NUMFIELD,    "Top Red     ",0,0,MNID_TopRed);
+  level_settings_menu->additem(MN_NUMFIELD,    "Top Green   ",0,0,MNID_TopGreen);
+  level_settings_menu->additem(MN_NUMFIELD,    "Top Blue    ",0,0,MNID_TopBlue);
+  level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red  ",0,0,MNID_BottomRed);
   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
-  level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue",0,0,MNID_BottomBlue);
+  level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue ",0,0,MNID_BottomBlue);
   level_settings_menu->additem(MN_HL,"",0,0);
   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
 
   select_tilegroup_menu->arrange_left = true;
   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
   select_tilegroup_menu->additem(MN_HL,"",0,0);
   level_settings_menu->additem(MN_HL,"",0,0);
   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
 
   select_tilegroup_menu->arrange_left = true;
   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
   select_tilegroup_menu->additem(MN_HL,"",0,0);
-  select_tilegroup_menu->additem(MN_ACTION,"asd",0,0);
   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
   int tileid = 1;
   for(std::set<TileGroup>::iterator it = tilegroups->begin();
   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
   int tileid = 1;
   for(std::set<TileGroup>::iterator it = tilegroups->begin();
@@ -493,14 +503,21 @@ void le_init_menus()
   select_objects_menu->arrange_left = true;
   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
   select_objects_menu->additem(MN_HL,"",0,0);
   select_objects_menu->arrange_left = true;
   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
   select_objects_menu->additem(MN_HL,"",0,0);
+  // TODO fix this
   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
 
   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
 
+  DisplayManager dummy;
   for(int i = 0; i < NUM_BadGuyKinds; ++i)
   {
   for(int i = 0; i < NUM_BadGuyKinds; ++i)
   {
-    BadGuy bad_tmp(0,0,BadGuyKind(i),false);
+    BadGuy bad_tmp(dummy, BadGuyKind(i), 0, 0);
     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
-    objects_map["BadGuys"]->manipulate_button(i)->set_game_object(new BadGuy(objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,objects_map["BadGuys"]->manipulate_button(i)->get_pos().y,BadGuyKind(i),false));
+    objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
+        BadGuy(dummy,
+          BadGuyKind(i),
+          objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
+          objects_map["BadGuys"]->manipulate_button(i)->get_pos().y
+          ));
   }
 
   select_objects_menu->additem(MN_HL,"",0,0);
   }
 
   select_objects_menu->additem(MN_HL,"",0,0);
@@ -509,19 +526,16 @@ void le_init_menus()
 
 int le_init()
 {
 
 int le_init()
 {
-
-
   level_subsets = dsubdirs("/levels", "level1.stl");
   le_level_subset = new LevelSubset;
 
   le_world = NULL;
   level_subsets = dsubdirs("/levels", "level1.stl");
   le_level_subset = new LevelSubset;
 
   le_world = NULL;
+  selected_game_object = NULL;
 
   active_tm = TM_IA;
   le_show_grid = true;
   show_selections = true;
 
   active_tm = TM_IA;
   le_show_grid = true;
   show_selections = true;
-  scroll_x = 0;
 
 
-  fire = DOWN;
   done = 0;
   le_frame = 0;        /* support for frames in some tiles, like waves and bad guys */
   le_level_changed = false;
   done = 0;
   le_frame = 0;        /* support for frames in some tiles, like waves and bad guys */
   le_level_changed = false;
@@ -537,21 +551,30 @@ int le_init()
 
   select_tilegroup_menu_effect.init(false);
   select_objects_menu_effect.init(false);
 
   select_tilegroup_menu_effect.init(false);
   select_objects_menu_effect.init(false);
+  display_level_info.init(false);
 
   /* Load buttons */
   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
 
   /* Load buttons */
   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
-  le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F9,screen->w-32,32);
-  le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
-  le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
+  le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
+  le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
+  le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
-  le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
+  le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
+  le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
+  le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
   le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
   le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
+  le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
+  le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
+  le_object_properties_bt->set_active(false);
+
+  mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
+  mouse_select_object->set_mid(16,16);
 
   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
   le_tilemap_panel->set_button_size(32,10);
 
   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
   le_tilemap_panel->set_button_size(32,10);
@@ -595,6 +618,8 @@ void update_level_settings_menu()
 
   sprintf(str,"%d",le_world->get_level()->width);
   level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
 
   sprintf(str,"%d",le_world->get_level()->width);
   level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->height);
+  level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
   sprintf(str,"%d",le_world->get_level()->time_left);
   level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
   sprintf(str,"%2.0f",le_world->get_level()->gravity);
   sprintf(str,"%d",le_world->get_level()->time_left);
   level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
   sprintf(str,"%2.0f",le_world->get_level()->gravity);
@@ -625,6 +650,7 @@ void apply_level_settings_menu()
 {
   int i;
   i = false;
 {
   int i;
   i = false;
+  le_level_changed = true;
 
   le_world->get_level()->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
   le_world->get_level()->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
 
   le_world->get_level()->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
   le_world->get_level()->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
@@ -647,7 +673,9 @@ void apply_level_settings_menu()
 
   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
 
 
   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
 
-  le_world->get_level()->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
+  le_world->get_level()->resize(
+      atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input),
+      atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
@@ -664,6 +692,7 @@ void save_subset_settings_menu()
   le_level_subset->title = subset_settings_menu->item[2].input;
   le_level_subset->description = subset_settings_menu->item[3].input;
   le_level_subset->save();
   le_level_subset->title = subset_settings_menu->item[2].input;
   le_level_subset->description = subset_settings_menu->item[3].input;
   le_level_subset->save();
+  le_level_changed = false;
 }
 
 void le_unload_level()
 }
 
 void le_unload_level()
@@ -676,18 +705,21 @@ void le_unload_level()
     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
     if(confirm_dialog(str))
     {
     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
     if(confirm_dialog(str))
     {
-      le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
+      le_world->get_level()->save(le_level_subset->name.c_str(), le_level,
+          le_world);
     }
   }
 
   delete le_world;
     }
   }
 
   delete le_world;
-  le_level_changed = false;  
+  le_level_changed = false;
 }
 
 void le_goto_level(int levelnb)
 {
   le_unload_level();
   le_world = new World(le_level_subset->name, levelnb);
 }
 
 void le_goto_level(int levelnb)
 {
   le_unload_level();
   le_world = new World(le_level_subset->name, levelnb);
+  display_level_info.start(2500);
+  le_level = levelnb;
 }
 
 void le_quit(void)
 }
 
 void le_quit(void)
@@ -710,6 +742,8 @@ void le_quit(void)
   delete le_previous_level_bt;
   delete le_move_right_bt;
   delete le_move_left_bt;
   delete le_previous_level_bt;
   delete le_move_right_bt;
   delete le_move_left_bt;
+  delete le_move_up_bt;
+  delete le_move_down_bt;
   delete le_rubber_bt;
   delete le_select_mode_one_bt;
   delete le_select_mode_two_bt;
   delete le_rubber_bt;
   delete le_select_mode_one_bt;
   delete le_select_mode_two_bt;
@@ -717,6 +751,9 @@ void le_quit(void)
   delete le_tilegroup_bt;
   delete le_objects_bt;
   delete le_tilemap_panel;
   delete le_tilegroup_bt;
   delete le_objects_bt;
   delete le_tilemap_panel;
+  delete le_object_select_bt;
+  delete le_object_properties_bt;
+  delete mouse_select_object;
 
   delete le_level_subset;
   le_level_subset = 0;
 
   delete le_level_subset;
   le_level_subset = 0;
@@ -747,24 +784,36 @@ void le_drawminimap()
     mini_tile_width = 1;
   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
 
     mini_tile_width = 1;
   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
 
-  for (int y = 0; y < 15; ++y)
+  int mini_tile_height;
+  if(screen->h - 64 > le_world->get_level()->height * 4)
+    mini_tile_height = 4;
+  else if(screen->h - 64 > le_world->get_level()->height * 2)
+    mini_tile_height = 2;
+  else
+    mini_tile_height = 1;
+
+  Level* level = le_world->get_level();
+  for (int y = 0; y < le_world->get_level()->height; ++y)
     for (int x = 0; x < le_world->get_level()->width; ++x)
     {
 
     for (int x = 0; x < le_world->get_level()->width; ++x)
     {
 
-      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
+      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
+          mini_tile_width , 4, level->bg_tiles[y * level->width + x]);
 
 
-      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
+      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
+          mini_tile_width , 4, level->ia_tiles[y * level->width + x]);
 
 
-      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
+      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
+          mini_tile_width , 4, level->fg_tiles[y + level->width + x]);
 
     }
 
 
     }
 
-  fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, 15*4, 200, 200, 200, 128);
+  fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 128);
 
   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
 
   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
-  fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, 15*4, 200, 200, 200, 200);
-  fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, 15*4, 200, 200, 200, 200);
-  fillrect(left_offset + (pos_x/32)*mini_tile_width, 15*4-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
+  fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 200);
+  fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 200);
+  fillrect(left_offset + (pos_x/32)*mini_tile_width, le_world->get_level()->height*mini_tile_height-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
 
 }
 
 
 }
 
@@ -778,35 +827,35 @@ void le_drawinterface()
     /* draw a grid (if selected) */
     if(le_show_grid)
     {
     /* draw a grid (if selected) */
     if(le_show_grid)
     {
-      for(x = 0; x < 19; x++)
+      for(x = 0; x < VISIBLE_TILES_X; x++)
         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
-      for(y = 0; y < 15; y++)
-        fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
+      for(y = 0; y < VISIBLE_TILES_Y; y++)
+        fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
     }
   }
 
   if(show_minimap) // use_gl because the minimap isn't shown correctly in software mode. Any idea? FIXME Possible reasons: SDL_SoftStretch is a hack itsself || an alpha blitting issue SDL can't handle in software mode
     le_drawminimap();
 
     }
   }
 
   if(show_minimap) // use_gl because the minimap isn't shown correctly in software mode. Any idea? FIXME Possible reasons: SDL_SoftStretch is a hack itsself || an alpha blitting issue SDL can't handle in software mode
     le_drawminimap();
 
-  if(show_selections)
-  {
-  if(le_selection_mode == CURSOR)
+  if(show_selections && MouseCursor::current() != mouse_select_object)
   {
   {
-    if(le_current.IsTile())
-      le_selection->draw( cursor_x - pos_x, cursor_y);
-  }
-  else if(le_selection_mode == SQUARE)
-  {
-    int w, h;
-    le_highlight_selection();
-    /* draw current selection */
-    w = selection.x2 - selection.x1;
-    h = selection.y2 - selection.y1;
-    fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
-    fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
-    fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
-    fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
-  }
+    if(le_selection_mode == CURSOR)
+    {
+      if(le_current.IsTile())
+        le_selection->draw(cursor_x - pos_x, cursor_y - pos_y);
+    }
+    else if(le_selection_mode == SQUARE)
+    {
+      int w, h;
+      le_highlight_selection();
+      /* draw current selection */
+      w = selection.x2 - selection.x1;
+      h = selection.y2 - selection.y1;
+      fillrect(selection.x1 - pos_x, selection.y1 - pos_y, w, SELECT_W, SELECT_CLR);
+      fillrect(selection.x1 - pos_x + w, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
+      fillrect(selection.x1 - pos_x, selection.y1 - pos_y + h, w, SELECT_W, SELECT_CLR);
+      fillrect(selection.x1 - pos_x, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
+    }
   }
 
 
   }
 
 
@@ -815,15 +864,25 @@ void le_drawinterface()
 
   if(le_current.IsTile())
   {
 
   if(le_current.IsTile())
   {
-    Tile::draw(19 * 32, 14 * 32, le_current.tile);
+    Tile::draw(screen->w - 32, screen->h - 32, le_current.tile);
     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
-      TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
+      TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);
   }
   }
-  if(le_current.IsObject())
+#if 0 // XXX FIXME TODO: Do we have a new solution for draw_on_screen()?
+  if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
   {
   {
-    le_current.obj->draw_on_screen(19 * 32, 14 * 32);
+    le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
     le_current.obj->draw_on_screen(cursor_x,cursor_y);
   }
     le_current.obj->draw_on_screen(cursor_x,cursor_y);
   }
+#endif
+
+  if(mouse_select_object && selected_game_object != NULL)
+  {
+    fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,selected_game_object->base.width,3,255,0,0,255);
+    fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
+    fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y+selected_game_object->base.height,selected_game_object->base.width,3,255,0,0,255);
+    fillrect(selected_game_object->base.x-pos_x+selected_game_object->base.width,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
+  }
 
   if(le_world != NULL)
   {
 
   if(le_world != NULL)
   {
@@ -840,6 +899,8 @@ void le_drawinterface()
     le_settings_bt->draw();
     le_move_right_bt->draw();
     le_move_left_bt->draw();
     le_settings_bt->draw();
     le_move_right_bt->draw();
     le_move_left_bt->draw();
+    le_move_up_bt->draw();
+    le_move_down_bt->draw();
     le_tilegroup_bt->draw();
     le_objects_bt->draw();
     if(!cur_tilegroup.empty())
     le_tilegroup_bt->draw();
     le_objects_bt->draw();
     if(!cur_tilegroup.empty())
@@ -851,11 +912,20 @@ void le_drawinterface()
 
     le_tilemap_panel->draw();
 
 
     le_tilemap_panel->draw();
 
+    if(!cur_objects.empty())
+    {
+      le_object_select_bt->draw();
+      le_object_properties_bt->draw();
+    }
+
     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
 
     if(!le_help_shown)
       white_small_text->draw("F1 for Help", 10, 430, 1);
     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
 
     if(!le_help_shown)
       white_small_text->draw("F1 for Help", 10, 430, 1);
+
+    if(display_level_info.check())
+      white_text->drawf(le_world->get_level()->name.c_str(), 0, 0, A_HMIDDLE, A_TOP, 0);
   }
   else
   {
   }
   else
   {
@@ -869,38 +939,30 @@ void le_drawinterface()
 
 void le_drawlevel()
 {
 
 void le_drawlevel()
 {
-  unsigned int y,x,s;
+  unsigned int y,x;
   Uint8 a;
 
   /* Draw the real background */
   Uint8 a;
 
   /* Draw the real background */
-  if(le_world->get_level()->bkgd_image[0] != '\0')
-  {
-    s = (int)((float)pos_x * ((float)le_world->get_level()->bkgd_speed/60.)) % screen->w;
-    le_world->get_level()->img_bkgd->draw_part(s,0,0,0,
-        le_world->get_level()->img_bkgd->w - s - 32, le_world->get_level()->img_bkgd->h);
-    le_world->get_level()->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
-        le_world->get_level()->img_bkgd->h);
-  }
-  else
-  {
-    drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
-  }
+  le_world->background->draw(*le_world->camera, LAYER_BACKGROUND0);
 
   if(le_current.IsTile())
   {
 
   if(le_current.IsTile())
   {
-    Tile::draw(cursor_x-pos_x, cursor_y,le_current.tile,128);
+    Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
     if(!TileManager::instance()->get(le_current.tile)->images.empty())
     if(!TileManager::instance()->get(le_current.tile)->images.empty())
-      fillrect(cursor_x-pos_x,cursor_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);
+      fillrect(cursor_x-pos_x,cursor_y-pos_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);
   }
   }
+#if 0 // XXX FIXME TODO: Do we have a new solution for move_to()?
   if(le_current.IsObject())
   {
     le_current.obj->move_to(cursor_x, cursor_y);
   }
   if(le_current.IsObject())
   {
     le_current.obj->move_to(cursor_x, cursor_y);
   }
+#endif
 
   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
 
 
   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
 
-  for (y = 0; y < 15; ++y)
-    for (x = 0; x < 20; ++x)
+  Level* level = le_world->get_level();
+  for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_world->get_level()->height; ++y)
+    for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
     {
 
       if(active_tm == TM_BG)
     {
 
       if(active_tm == TM_BG)
@@ -908,58 +970,128 @@ void le_drawlevel()
       else
         a = 128;
 
       else
         a = 128;
 
-      Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->bg_tiles[y][x + (int)(pos_x / 32)],a);
+      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
+          level->bg_tiles[ (y + (int)(pos_y / 32)) * level->width + 
+          (x + (int)(pos_x / 32))],a);
 
       if(active_tm == TM_IA)
         a = 255;
       else
         a = 128;
 
 
       if(active_tm == TM_IA)
         a = 255;
       else
         a = 128;
 
-      Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)],a);
+      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
+          level->ia_tiles[ (y + (int)(pos_y / 32)) * level->width +       
+          (x + (int)(pos_x / 32))],a);
 
 
+      
       if(active_tm == TM_FG)
         a = 255;
       else
         a = 128;
 
       if(active_tm == TM_FG)
         a = 255;
       else
         a = 128;
 
-      Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->fg_tiles[y][x + (int)(pos_x / 32)],a);
+      Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
+          level->fg_tiles[ (y + (int)(pos_y / 32)) * level->width +       
+          (x + (int)(pos_x / 32))],a);
 
       /* draw whats inside stuff when cursor is selecting those */
       /* (draw them all the time - is this the right behaviour?) */
 
       /* draw whats inside stuff when cursor is selecting those */
       /* (draw them all the time - is this the right behaviour?) */
-      Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)]);
+      Tile* edit_image = TileManager::instance()->get(
+          level->ia_tiles
+          [ (y + (int)(pos_y / 32)) * level->width + (x + (int)(pos_x / 32))]);
       if(edit_image && !edit_image->editor_images.empty())
       if(edit_image && !edit_image->editor_images.empty())
-        edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
+        edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
 
     }
 
   /* Draw the Bad guys: */
 
     }
 
   /* Draw the Bad guys: */
-  for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
+  for (std::vector<GameObject*>::iterator it = le_world->gameobjects.begin();
+       it != le_world->gameobjects.end(); ++it)
   {
   {
+    BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
+    if(badguy == 0)
+      continue;
+    
     /* to support frames: img_bsod_left[(frame / 5) % 4] */
     /* to support frames: img_bsod_left[(frame / 5) % 4] */
-
-    scroll_x = pos_x;
-    (*it)->draw();
+    Camera viewport;
+    viewport.set_translation(Vector(pos_x, pos_y));
+    badguy->draw(viewport, 0);
   }
 
   }
 
-
   /* Draw the player: */
   /* for now, the position is fixed at (100, 240) */
   /* Draw the player: */
   /* for now, the position is fixed at (100, 240) */
-  largetux.walk_right->draw( 100 - pos_x, 240);
+  largetux.walk_right->draw( 100 - pos_x, 240 - pos_y);
 }
 
 void le_change_object_properties(GameObject *pobj)
 {
 }
 
 void le_change_object_properties(GameObject *pobj)
 {
+  Surface* cap_screen = Surface::CaptureScreen();
   Menu* object_properties_menu = new Menu();
   Menu* object_properties_menu = new Menu();
+  bool loop = true;
 
 
-  object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
-  object_properties_menu->additem(MN_HL,"",0,0);
-  /*object_properties_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
-  object_properties_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
+  std::string type = typeid(pobj).name();
+  object_properties_menu->additem(MN_LABEL, type + " Properties",0,0);
   object_properties_menu->additem(MN_HL,"",0,0);
   object_properties_menu->additem(MN_HL,"",0,0);
-  object_properties_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);*/
+
+  BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
+  if(pobj != 0)
+  {
+    object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
+    for(int i = 0; i < NUM_BadGuyKinds; ++i)
+    {
+      string_list_add_item(object_properties_menu->get_item_by_id(1).list,
+          badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
+      if(pbad->kind == i)
+        object_properties_menu->get_item_by_id(1).list->active_item = i;
+    }
+    object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
+  }
+
   object_properties_menu->additem(MN_HL,"",0,0);
   object_properties_menu->additem(MN_HL,"",0,0);
-  object_properties_menu->additem(MN_BACK,"Apply",0,0);
+  object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
 
 
+  Menu::set_current(object_properties_menu);
+
+  while(loop)
+  {
+    SDL_Event event;
+
+    while (SDL_PollEvent(&event))
+    {
+      object_properties_menu->event(event);
+    }
+
+    cap_screen->draw(0,0);
+
+    object_properties_menu->draw();
+    object_properties_menu->action();
+
+    switch (object_properties_menu->check())
+    {
+    case 3:
+      {
+      BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
+      if(pbad != 0) {
+        BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
+        pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
+        pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
+      }
+      loop = false;
+      break;
+      }
+    default:
+      break;
+    }
+
+    if(Menu::current() == NULL)
+      loop = false;
+
+    mouse_cursor->draw();
+    flipscreen();
+    SDL_Delay(25);
+  }
+
+  delete cap_screen;
+  Menu::set_current(0);
   delete object_properties_menu;
 }
 
   delete object_properties_menu;
 }
 
@@ -1001,47 +1133,6 @@ void le_checkevents()
           case SDLK_ESCAPE:
             Menu::set_current(leveleditor_menu);
             break;
           case SDLK_ESCAPE:
             Menu::set_current(leveleditor_menu);
             break;
-          case SDLK_LEFT:
-            if(fire == DOWN)
-              cursor_x -= KEY_CURSOR_SPEED;
-            else
-              cursor_x -= KEY_CURSOR_FASTSPEED;
-
-            if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
-              pos_x = cursor_x - MOUSE_LEFT_MARGIN;
-
-            break;
-          case SDLK_RIGHT:
-            if(fire == DOWN)
-              cursor_x += KEY_CURSOR_SPEED;
-            else
-              cursor_x += KEY_CURSOR_FASTSPEED;
-
-            if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
-              pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
-
-            break;
-          case SDLK_UP:
-            if(fire == DOWN)
-              cursor_y -= KEY_CURSOR_SPEED;
-            else
-              cursor_y -= KEY_CURSOR_FASTSPEED;
-
-            if(cursor_y < 0)
-              cursor_y = 0;
-            break;
-          case SDLK_DOWN:
-            if(fire == DOWN)
-              cursor_y += KEY_CURSOR_SPEED;
-            else
-              cursor_y += KEY_CURSOR_FASTSPEED;
-
-            if(cursor_y > screen->h-32)
-              cursor_y = screen->h-32;
-            break;
-          case SDLK_LCTRL:
-            fire =UP;
-            break;
           case SDLK_F1:
             if(le_world != NULL)
               le_showhelp();
           case SDLK_F1:
             if(le_world != NULL)
               le_showhelp();
@@ -1061,25 +1152,15 @@ void le_checkevents()
             break;
           }
           break;
             break;
           }
           break;
-        case SDL_KEYUP:        /* key released */
-          switch(event.key.keysym.sym)
-          {
-          case SDLK_LCTRL:
-            fire = DOWN;
-            break;
-          default:
-            break;
-          }
-          break;
         case SDL_MOUSEBUTTONDOWN:
           if(event.button.button == SDL_BUTTON_LEFT)
           {
             le_mouse_pressed[LEFT] = true;
 
             selection.x1 = event.motion.x + pos_x;
         case SDL_MOUSEBUTTONDOWN:
           if(event.button.button == SDL_BUTTON_LEFT)
           {
             le_mouse_pressed[LEFT] = true;
 
             selection.x1 = event.motion.x + pos_x;
-            selection.y1 = event.motion.y;
+            selection.y1 = event.motion.y + pos_y;
             selection.x2 = event.motion.x + pos_x;
             selection.x2 = event.motion.x + pos_x;
-            selection.y2 = event.motion.y;
+            selection.y2 = event.motion.y + pos_y;
           }
           else if(event.button.button == SDL_BUTTON_RIGHT)
           {
           }
           else if(event.button.button == SDL_BUTTON_RIGHT)
           {
@@ -1108,7 +1189,7 @@ void le_checkevents()
             if(le_current.IsTile())
             {
               cursor_x = ((int)(pos_x + x) / 32) * 32;
             if(le_current.IsTile())
             {
               cursor_x = ((int)(pos_x + x) / 32) * 32;
-              cursor_y = ((int) y / 32) * 32;
+              cursor_y = ((int)(pos_y + y) / 32) * 32;
             }
             else
             {
             }
             else
             {
@@ -1119,22 +1200,24 @@ void le_checkevents()
             if(le_mouse_pressed[LEFT])
             {
               selection.x2 = x + pos_x;
             if(le_mouse_pressed[LEFT])
             {
               selection.x2 = x + pos_x;
-              selection.y2 = y;
+              selection.y2 = y + pos_y;
             }
 
             if(le_mouse_pressed[RIGHT])
             {
               pos_x += -1 * event.motion.xrel;
             }
 
             if(le_mouse_pressed[RIGHT])
             {
               pos_x += -1 * event.motion.xrel;
+              pos_y += -1 * event.motion.yrel;
             }
           }
           break;
             }
           }
           break;
-        case SDL_QUIT: // window closed
-          done = 1;
-          break;
         default:
           break;
         }
       }
         default:
           break;
         }
       }
+      else if(event.type == SDL_QUIT) /* window closing */
+      {
+      done = 1;
+      }
     }
 
     if(le_world != NULL)
     }
 
     if(le_world != NULL)
@@ -1153,7 +1236,8 @@ void le_checkevents()
             le_testlevel();
           le_save_level_bt->event(event);
           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
             le_testlevel();
           le_save_level_bt->event(event);
           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
-            le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
+            le_world->get_level()->save(le_level_subset->name.c_str(),le_level,
+                le_world);
           le_exit_bt->event(event);
           if(le_exit_bt->get_state() == BUTTON_CLICKED)
           {
           le_exit_bt->event(event);
           if(le_exit_bt->get_state() == BUTTON_CLICKED)
           {
@@ -1164,7 +1248,7 @@ void le_checkevents()
           {
             if(le_level < le_level_subset->levels)
             {
           {
             if(le_level < le_level_subset->levels)
             {
-              le_goto_level(++le_level);
+              le_goto_level(le_level+1);
             }
             else
             {
             }
             else
             {
@@ -1174,7 +1258,7 @@ void le_checkevents()
               if(confirm_dialog(str))
               {
                 new_lev.init_defaults();
               if(confirm_dialog(str))
               {
                 new_lev.init_defaults();
-                new_lev.save(le_level_subset->name.c_str(),++le_level);
+                new_lev.save(le_level_subset->name.c_str(),le_level+1, le_world);
                 le_level_subset->levels = le_level;
                 le_goto_level(le_level);
               }
                 le_level_subset->levels = le_level;
                 le_goto_level(le_level);
               }
@@ -1184,12 +1268,28 @@ void le_checkevents()
           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
           {
             if(le_level > 1)
           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
           {
             if(le_level > 1)
-              le_goto_level(--le_level);
+              le_goto_level(le_level -1);
           }
           le_rubber_bt->event(event);
           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
             le_current.Tile(0);
 
           }
           le_rubber_bt->event(event);
           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
             le_current.Tile(0);
 
+          if(!cur_objects.empty())
+          {
+            le_object_select_bt->event(event);
+            if(le_object_select_bt->get_state() == BUTTON_CLICKED)
+            {
+              MouseCursor::set_current(mouse_select_object);
+            }
+
+            le_object_properties_bt->event(event);
+            if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
+            {
+              le_change_object_properties(selected_game_object);
+            }
+          }
+
+
           if(le_selection_mode == SQUARE)
           {
             le_select_mode_one_bt->event(event);
           if(le_selection_mode == SQUARE)
           {
             le_select_mode_one_bt->event(event);
@@ -1315,7 +1415,9 @@ void le_checkevents()
             {
               if(pbutton->get_state() == BUTTON_CLICKED)
               {
             {
               if(pbutton->get_state() == BUTTON_CLICKED)
               {
-                le_current.Object(pbutton->get_game_object());
+#if 0   // TODO FIXME XXX: New solution for this?
+                le_current.Object(pbutton->get_drawable());
+#endif
               }
             }
           }
               }
             }
           }
@@ -1352,24 +1454,82 @@ void le_checkevents()
       {
         if(le_mouse_pressed[LEFT])
         {
       {
         if(le_mouse_pressed[LEFT])
         {
-          if(le_current.IsTile())
-            le_change(cursor_x, cursor_y, active_tm, le_current.tile);
+          if(MouseCursor::current() != mouse_select_object)
+          {
+            if(le_current.IsTile())
+              le_change(cursor_x, cursor_y, active_tm, le_current.tile);
+          }
         }
         else if(le_mouse_clicked[LEFT])
         {
         }
         else if(le_mouse_clicked[LEFT])
         {
-          if(le_current.IsObject())
+          if(MouseCursor::current() == mouse_select_object)
+          {
+            bool object_got_hit = false;
+            base_type cursor_base;
+           if(le_current.IsTile())
+           {
+            cursor_base.x = cursor_x;
+            cursor_base.y = cursor_y;
+           }
+           else if(le_current.IsObject())
+           {
+            cursor_base.x = cursor_x + pos_x;
+            cursor_base.y = cursor_y + pos_y;      
+           }
+            cursor_base.width = 32;
+            cursor_base.height = 32;
+
+            for(std::vector<GameObject*>::iterator it =
+                le_world->gameobjects.begin();
+                it != le_world->gameobjects.end(); ++it) {
+              MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
+              if(!mobj)
+                continue;
+
+              if(rectcollision(cursor_base, mobj->base))
+              {
+                selected_game_object = mobj;
+                object_got_hit = true;
+                break;
+              }
+            }
+
+            if(!object_got_hit)
+            {
+              selected_game_object = NULL;
+              le_object_properties_bt->set_active(false);
+            }
+            else
+              le_object_properties_bt->set_active(true);
+
+            MouseCursor::set_current(mouse_cursor);
+
+          }
+          else
           {
           {
-           le_level_changed  = true;
-            std::string type = le_current.obj->type();
-            if(type == "BadGuy")
+            // FIXME TODO
+            if(le_current.IsObject())
             {
             {
+              le_level_changed  = true;
               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
 
               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
 
-              le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
-              le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
+              if(pbadguy)
+              {
+                Camera& camera = *le_world->camera;
+                DisplayManager dummy;
+
+                le_world->bad_guys.push_back(
+                    new BadGuy(dummy, pbadguy->kind,
+                      cursor_x + camera.get_translation().x,
+                      cursor_y + camera.get_translation().y));
+                le_world->gameobjects.push_back(le_world->bad_guys.back());
+              }
             }
             }
+
           }
           }
+         
           le_mouse_clicked[LEFT] = false;
           le_mouse_clicked[LEFT] = false;
+
         }
       }
     }
         }
       }
     }
@@ -1380,14 +1540,16 @@ void le_checkevents()
 
     le_move_left_bt->event(event);
     le_move_right_bt->event(event);
 
     le_move_left_bt->event(event);
     le_move_right_bt->event(event);
+    le_move_up_bt->event(event);
+    le_move_down_bt->event(event);
     switch(le_move_left_bt->get_state())
     {
     case BUTTON_PRESSED:
     switch(le_move_left_bt->get_state())
     {
     case BUTTON_PRESSED:
-      pos_x -= 192;
+      pos_x -= KEYBOARD_SPEED;
       show_minimap = true;
       break;
     case BUTTON_HOVER:
       show_minimap = true;
       break;
     case BUTTON_HOVER:
-      pos_x -= 32;
+      pos_x -= MOUSE_SPEED;
       show_minimap = true;
       break;
     case BUTTON_CLICKED:
       show_minimap = true;
       break;
     case BUTTON_CLICKED:
@@ -1400,11 +1562,45 @@ void le_checkevents()
     switch(le_move_right_bt->get_state())
     {
     case BUTTON_PRESSED:
     switch(le_move_right_bt->get_state())
     {
     case BUTTON_PRESSED:
-      pos_x += 192;
+      pos_x += KEYBOARD_SPEED;
+      show_minimap = true;
+      break;
+    case BUTTON_HOVER:
+      pos_x += MOUSE_SPEED;
+      show_minimap = true;
+      break;
+    case BUTTON_CLICKED:
+      show_minimap = true;
+      break;
+    default:
+      break;
+    }
+
+    switch(le_move_up_bt->get_state())
+    {
+    case BUTTON_PRESSED:
+      pos_y -= KEYBOARD_SPEED;
+      show_minimap = true;
+      break;
+    case BUTTON_HOVER:
+      pos_y -= MOUSE_SPEED;
+      show_minimap = true;
+      break;
+    case BUTTON_CLICKED:
+      show_minimap = true;
+      break;
+    default:
+      break;
+    }
+
+    switch(le_move_down_bt->get_state())
+    {
+    case BUTTON_PRESSED:
+      pos_y += KEYBOARD_SPEED;
       show_minimap = true;
       break;
     case BUTTON_HOVER:
       show_minimap = true;
       break;
     case BUTTON_HOVER:
-      pos_x += 32;
+      pos_y += MOUSE_SPEED;
       show_minimap = true;
       break;
     case BUTTON_CLICKED:
       show_minimap = true;
       break;
     case BUTTON_CLICKED:
@@ -1414,6 +1610,17 @@ void le_checkevents()
       break;
     }
 
       break;
     }
 
+      /* checking if pos_x and pos_y is within the limits... */
+      if(pos_x > (le_world->get_level()->width * 32 + 32*2) - screen->w)
+        pos_x = (le_world->get_level()->width * 32 + 32*2) - screen->w;
+      if(pos_x < 0)
+        pos_x = 0;
+
+      if(pos_y > (le_world->get_level()->height * 32) - screen->h)
+        pos_y = (le_world->get_level()->height * 32) - screen->h;
+      if(pos_y < 0)
+        pos_y = 0;
+
   }
 
 }
   }
 
 }
@@ -1448,7 +1655,7 @@ void le_highlight_selection()
   y1 /= 32;
   y2 /= 32;
 
   y1 /= 32;
   y2 /= 32;
 
-  fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
+  fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
 }
 
 void le_change(float x, float y, int tm, unsigned int c)
 }
 
 void le_change(float x, float y, int tm, unsigned int c)
@@ -1457,10 +1664,9 @@ void le_change(float x, float y, int tm, unsigned int c)
   {
     int xx,yy;
     int x1, x2, y1, y2;
   {
     int xx,yy;
     int x1, x2, y1, y2;
-    unsigned int i = 0;
 
     le_level_changed = true;
 
     le_level_changed = true;
-    
+
     switch(le_selection_mode)
     {
     case CURSOR:
     switch(le_selection_mode)
     {
     case CURSOR:
@@ -1473,14 +1679,21 @@ void le_change(float x, float y, int tm, unsigned int c)
       cursor_base.height = 32;
 
       /* if there is a bad guy over there, remove it */
       cursor_base.height = 32;
 
       /* if there is a bad guy over there, remove it */
-      for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
-        if(rectcollision(cursor_base,(*it)->base))
+      // XXX TODO
+      for(std::vector<GameObject*>::iterator it = le_world->gameobjects.begin();
+            it != le_world->gameobjects.end(); ++it) {
+        BadGuy* badguy = dynamic_cast<BadGuy*>((*it));
+        if (badguy)
         {
         {
-          delete (*it);
-          le_world->bad_guys.erase(it);
-          le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
-          break;
+          if(rectcollision(cursor_base, badguy->base))
+          {
+            delete (*it);
+            //le_world->bad_guys.erase(it);
+            le_world->gameobjects.erase(std::remove(le_world->gameobjects.begin(), le_world->gameobjects.end(), *it), le_world->gameobjects.end());
+            break;
+          }
         }
         }
+      }
 
       break;
     case SQUARE:
 
       break;
     case SQUARE:
@@ -1511,21 +1724,25 @@ void le_change(float x, float y, int tm, unsigned int c)
       y2 /= 32;
 
       /* if there is a bad guy over there, remove it */
       y2 /= 32;
 
       /* if there is a bad guy over there, remove it */
-      for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
-          it != le_world->bad_guys.end(); /* will be at end of loop */)
+      // TODO FIXME
+      for(std::vector<GameObject*>::iterator it = le_world->gameobjects.begin();
+          it != le_world->gameobjects.end(); ++it /* will be at end of loop */)
       {
       {
-        if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
-            && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
+        MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);       
+        if (pmobject)
         {
         {
-          delete (*it);
-          it = le_world->bad_guys.erase(it);
-          le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
-          continue;
-        }
-        else
-        {
-          ++i;
-          ++it;
+          if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
+              && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
+          {
+            delete (*it);
+            //it = le_world->gameobjects.erase(it);
+            le_world->gameobjects.erase(std::remove(le_world->gameobjects.begin(), le_world->gameobjects.end(), *it), le_world->gameobjects.end());
+            continue;
+          }
+          else
+          {
+            ++it;
+          }
         }
       }
 
         }
       }
 
@@ -1548,7 +1765,7 @@ void le_testlevel()
   if(le_world->get_level()->time_left == 0)
     le_world->get_level()->time_left = 250;
 
   if(le_world->get_level()->time_left == 0)
     le_world->get_level()->time_left = 250;
 
-  le_world->get_level()->save("test", le_level);
+  le_world->get_level()->save("test", le_level, le_world);
 
   GameSession session("test",le_level, ST_GL_TEST);
   session.run();
 
   GameSession session("test",le_level, ST_GL_TEST);
   session.run();
@@ -1563,6 +1780,8 @@ void le_testlevel()
 void le_showhelp()
 {
   bool tmp_show_grid = le_show_grid;
 void le_showhelp()
 {
   bool tmp_show_grid = le_show_grid;
+  SelectionMode temp_le_selection_mode = le_selection_mode;
+  le_selection_mode = NONE;
   show_selections = true;
   le_show_grid = false;
   le_help_shown = true;
   show_selections = true;
   le_show_grid = false;
   le_help_shown = true;
@@ -1583,7 +1802,7 @@ void le_showhelp()
                    "the left mouse button over the map",
                    "to \"paint\" your selection over",
                    "the screen.",
                    "the left mouse button over the map",
                    "to \"paint\" your selection over",
                    "the screen.",
-                  "",
+                   "",
                    "There are three layers for painting",
                    "tiles upon, Background layer,",
                    "the Interactive layer, and the",
                    "There are three layers for painting",
                    "tiles upon, Background layer,",
                    "the Interactive layer, and the",
@@ -1604,43 +1823,43 @@ void le_showhelp()
                     "the Interactive layer are those",
                     "which actually effect Tux in the",
                     "game.",
                     "the Interactive layer are those",
                     "which actually effect Tux in the",
                     "game.",
-                   "",
+                    "",
                     "Click the objects menu to put ",
                     "bad guys and other objects in the",
                     "game. Unlike placing tiles, you",
                     "cannot \"paint\" enemies. Click",
                     "them onto the screen one at a time.",
                     "Click the objects menu to put ",
                     "bad guys and other objects in the",
                     "game. Unlike placing tiles, you",
                     "cannot \"paint\" enemies. Click",
                     "them onto the screen one at a time.",
-                   "",
+                    "",
                     "To change the settings of your",
                     "level, click the button with the",
                     "screwdriver and wrench. From here",
                     "you can change the background,",
                     "music, length of the level,",
                     "To change the settings of your",
                     "level, click the button with the",
                     "screwdriver and wrench. From here",
                     "you can change the background,",
                     "music, length of the level,",
-                   "and more."
+                    "and more."
                   };
 
   char *text3[] = {
 
                     " - Supertux level editor tutorial - ",
                     "",
                   };
 
   char *text3[] = {
 
                     " - Supertux level editor tutorial - ",
                     "",
-                   "You may have more than one level.",
+                    "You may have more than one level.",
                     "Pressing the up and down buttons",
                     "above the button bar lets you",
                     "Pressing the up and down buttons",
                     "above the button bar lets you",
-                   "choose which one you are working on.",
-                   "",
+                    "choose which one you are working on.",
+                    "",
                     "If you would like to speed up your",
                     "level editing, a useful trick is",
                     "to learn the keyboard shortcuts.",
                     "If you would like to speed up your",
                     "level editing, a useful trick is",
                     "to learn the keyboard shortcuts.",
-                   "They are easy to learn, just right-",
-                   "click on the buttons.",
-                   "",
+                    "They are easy to learn, just right-",
+                    "click on the buttons.",
+                    "",
                     "Have fun making levels! If you make",
                     "some good ones, send them to us on",
                     "the SuperTux mailing list!",
                     "- SuperTux team"
                   };
                     "Have fun making levels! If you make",
                     "some good ones, send them to us on",
                     "the SuperTux mailing list!",
                     "- SuperTux team"
                   };
-               
-                 
+
+
 
   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
 
 
   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
 
@@ -1679,8 +1898,8 @@ void le_showhelp()
     done_ = wait_for_event(event);
     SDL_Delay(50);
   }
     done_ = wait_for_event(event);
     SDL_Delay(50);
   }
-  
-    drawgradient(Color(0,0,0), Color(255,255,255));
+
+  drawgradient(Color(0,0,0), Color(255,255,255));
   le_drawinterface();
 
 
   le_drawinterface();
 
 
@@ -1703,5 +1922,6 @@ void le_showhelp()
 
   show_selections = true;
   le_show_grid = tmp_show_grid;
 
   show_selections = true;
   le_show_grid = tmp_show_grid;
+  le_selection_mode = temp_le_selection_mode;
   le_help_shown = false;
 }
   le_help_shown = false;
 }