Make sure that tiles are loaded before tilegroups are requested. This fixed a bug...
[supertux.git] / src / leveleditor.cpp
index c96e436..a45405d 100644 (file)
@@ -1,21 +1,28 @@
-/***************************************************************************
- *                                                                         *
- *   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.                                   *
- *                                                                         *
- ***************************************************************************/
-
-/*  December 28, 2003 - March 15, 2004 */
-
-/* leveleditor.c - A built-in level editor for SuperTux
- Ricardo Cruz <rick2@aeiou.pt>
- Tobias Glaesser <tobi.web@gmx.de>                      */
-
+//  $Id$
+//
+//  SuperTux
+//  Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
+//  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 <map>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 #include <errno.h>
 #include <unistd.h>
 #include <SDL.h>
 #include "setup.h"
 #include "menu.h"
 #include "level.h"
+#include "gameloop.h"
 #include "badguy.h"
 #include "scene.h"
 #include "button.h"
+#include "tile.h"
+#include "resources.h"
+#include "music_manager.h"
 
 /* definitions to aid development */
-#define DONE_LEVELEDITOR 1
-#define DONE_QUIT        2
-#define DONE_CHANGELEVEL 3
 
 /* definitions that affect gameplay */
 #define KEY_CURSOR_SPEED 32
 #define SELECT_W 2 // size of the selections lines
 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
 
-/* gameloop funcs declerations */
-
-void loadshared(void);
-void unloadshared(void);
-
 /* own declerations */
 /* crutial ones (main loop) */
 int le_init();
 void le_quit();
+int le_load_level(char *filename);
 void le_drawlevel();
 void le_drawinterface();
 void le_checkevents();
-void le_change(float x, float y, unsigned char c);
+void le_change(float x, float y, int tm, unsigned int c);
 void le_testlevel();
 void le_showhelp();
 void le_set_defaults(void);
@@ -77,78 +81,79 @@ void le_highlight_selection();
 void apply_level_settings_menu();
 void update_subset_settings_menu();
 void save_subset_settings_menu();
-void le_update_buttons(const char*);
+
+struct TileOrObject
+{
+  TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
+
+  void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
+  void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
+  //Returns true for a 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)
+  unsigned int tile;
+  GameObject* obj;
+};
 
 /* leveleditor internals */
 static string_list_type level_subsets;
-static int le_level_changed;  /* if changes, ask for saving, when quiting*/
+static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
+static bool show_minimap;
 static int pos_x, cursor_x, cursor_y, fire;
 static int le_level;
-static st_level* le_current_level;
-static st_subset le_level_subset;
+static World* le_world;
+static LevelSubset* le_level_subset;
 static int le_show_grid;
 static int le_frame;
-static texture_type le_selection;
+static Surface* le_selection;
 static int done;
-static char le_current_tile;
-static int le_mouse_pressed[2];
-static button_type le_save_level_bt;
-static button_type le_test_level_bt;
-static button_type le_next_level_bt;
-static button_type le_previous_level_bt;
-static button_type le_move_right_bt;
-static button_type le_move_left_bt;
-static button_type le_rubber_bt;
-static button_type le_select_mode_one_bt;
-static button_type le_select_mode_two_bt;
-static button_type le_settings_bt;
-static button_type le_bad_bt;
-static button_type le_bkgd_bt;
-static button_type le_fgd_bt;
-static button_panel_type le_bkgd_panel;
-static button_panel_type le_fgd_panel;
-static button_panel_type le_bad_panel;
-static menu_type leveleditor_menu;
-static menu_type subset_load_menu;
-static menu_type subset_new_menu;
-static menu_type subset_settings_menu;
-static menu_type level_settings_menu;
+static TileOrObject le_current;
+static bool le_mouse_pressed[2];
+static bool le_mouse_clicked[2];
+static Button* le_save_level_bt;
+static Button* le_exit_bt;
+static Button* le_test_level_bt;
+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_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 ButtonPanel* le_tilemap_panel;
+static Menu* leveleditor_menu;
+static Menu* subset_load_menu;
+static Menu* subset_new_menu;
+static Menu* subset_settings_menu;
+static Menu* level_settings_menu;
+static Menu* select_tilegroup_menu;
+static Menu* select_objects_menu;
+static Timer select_tilegroup_menu_effect;
+static Timer select_objects_menu_effect;
+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 square selection;
 static int le_selection_mode;
 static SDL_Event event;
+TileMapType active_tm;
 
-void le_activate_bad_guys(void)
-{
-  int x,y;
-
-  /* Activate bad guys: */
-
-  /* as oposed to the gameloop.c func, this one doesn't remove
-  the badguys from tiles                                    */
-
-  for (y = 0; y < 15; ++y)
-    for (x = 0; x < le_current_level->width; ++x)
-      if (le_current_level->tiles[y][x] >= '0' && le_current_level->tiles[y][x] <= '9')
-        add_bad_guy(x * 32, y * 32, le_current_level->tiles[y][x] - '0');
-}
-
-void le_set_defaults()
-{
-  if(le_current_level != NULL)
-    {
-      /* Set defaults: */
-
-      if(le_current_level->time_left == 0)
-        le_current_level->time_left = 255;
-    }
-}
-
-int leveleditor(int levelnb)
+int leveleditor(char* filename)
 {
   int last_time, now_time, i;
 
-  le_level = levelnb;
+  le_level = 1;
+
   if(le_init() != 0)
     return 1;
 
@@ -157,398 +162,406 @@ int leveleditor(int levelnb)
   clearscreen(0, 0, 0);
   updatescreen();
 
+  music_manager->halt_music();
+
   while (SDL_PollEvent(&event))
   {}
 
-  while(YES)
+  if(filename != NULL)
+    if(le_load_level(filename))
+      return 1;
+
+  while(true)
+  {
+    last_time = SDL_GetTicks();
+    le_frame++;
+
+    le_checkevents();
+
+    if(Menu::current() == select_tilegroup_menu)
     {
-      last_time = SDL_GetTicks();
-      le_frame++;
+      if(select_tilegroup_menu_effect.check())
+      {
+        select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
+                                       66,-0.5,0.5);
+      }
+      else
+        select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
+    }
+    else if(Menu::current() == select_objects_menu)
+    {
+      if(select_objects_menu_effect.check())
+      {
+        select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
+      }
+      else
+        select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
+    }
 
-      le_checkevents();
+    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();
+    }
+    else
+      clearscreen(0, 0, 0);
 
-      if(le_current_level != NULL)
+    /* draw editor interface */
+    le_drawinterface();
+
+    Menu* menu = Menu::current();
+    if(menu)
+    {
+      menu->draw();
+      menu->action();
+
+      if(menu == leveleditor_menu)
+      {
+        switch (leveleditor_menu->check())
         {
-          /* making events results to be in order */
-          if(pos_x < 0)
-            pos_x = 0;
-          if(pos_x > (le_current_level->width * 32) - screen->w)
-            pos_x = (le_current_level->width * 32) - screen->w;
-
-          /* draw the level */
-          le_drawlevel();
+        case MNID_RETURNLEVELEDITOR:
+          Menu::set_current(0);
+          break;
+        case MNID_SUBSETSETTINGS:
+          update_subset_settings_menu();
+          break;
+        case MNID_QUITLEVELEDITOR:
+          done = 1;
+          break;
         }
-      else
-        clearscreen(0, 0, 0);
-
-      /* draw editor interface */
-      le_drawinterface();
+      }
+      else if(menu == level_settings_menu)
+      {
+        switch (level_settings_menu->check())
+        {
+        case MNID_APPLY:
+          apply_level_settings_menu();
+          Menu::set_current(NULL);
+          break;
 
-      if(show_menu)
+        default:
+          break;
+        }
+      }
+      else if(menu == select_tilegroup_menu)
+      {
+        int it = -1;
+        switch (it = select_tilegroup_menu->check())
         {
-          menu_process_current();
-          if(current_menu == &leveleditor_menu)
-            {
-              switch (menu_check(&leveleditor_menu))
-                {
-                case 2:
-                  show_menu = NO;
-                  break;
-                case 3:
-                  update_subset_settings_menu();
-                  break;
-                case 7:
-                  done = DONE_LEVELEDITOR;
-                  break;
-                }
-            }
-          else if(current_menu == &level_settings_menu)
-            {
-              switch (menu_check(&level_settings_menu))
-                {
-                case 13:
-                  apply_level_settings_menu();
-                  menu_set_current(&leveleditor_menu);
-                  break;
-                default:
-                  show_menu = YES;
-                  break;
-                }
-            }
-          else if(current_menu == &subset_load_menu)
-            {
-              switch (i = menu_check(&subset_load_menu))
-                {
-                case 0:
-                  break;
-                default:
-                  if(i != -1)
-                    {
-                      le_level_subset.load(level_subsets.item[i-2]);
-                      leveleditor_menu.item[3].kind = MN_GOTO;
-                      le_level = 1;
-                      arrays_init();
-                      loadshared();
-                      le_current_level = new st_level;
-                      if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
-                        {
-                          le_quit();
-                          return 1;
-                        }
-                     le_update_buttons(le_current_level->theme.c_str());
-                      le_set_defaults();
-                      level_load_gfx(le_current_level);
-                      le_activate_bad_guys();
-                      show_menu = YES;
-                    }
-                  break;
-                }
-            }
-          else if(current_menu == &subset_new_menu)
-            {
-              if(subset_new_menu.item[2].input[0] == '\0')
-                subset_new_menu.item[3].kind = MN_DEACTIVE;
-              else
-                {
-                  subset_new_menu.item[3].kind = MN_ACTION;
-
-                  switch (i = menu_check(&subset_new_menu))
-                    {
-                    case 3:
-                     st_subset::create(subset_new_menu.item[2].input);
-                      le_level_subset.load(subset_new_menu.item[2].input);
-                      leveleditor_menu.item[3].kind = MN_GOTO;
-                      le_level = 1;
-                      arrays_init();
-                      loadshared();
-                      le_current_level = (st_level*) malloc(sizeof(st_level));
-                      if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
-                        {
-                          le_quit();
-                          return 1;
-                        }
-                     le_update_buttons(le_current_level->theme.c_str());
-                      le_set_defaults();
-                      level_load_gfx(le_current_level);
-                      le_activate_bad_guys();
-                      menu_item_change_input(&subset_new_menu.item[2],"");
-                      show_menu = YES;
-                      break;
-                    }
-                }
-            }
-          else if(current_menu == &subset_settings_menu)
-            {
-              if(le_level_subset.title.compare(subset_settings_menu.item[2].input) == 0 && le_level_subset.description.compare(subset_settings_menu.item[3].input) == 0  )
-                subset_settings_menu.item[5].kind = MN_DEACTIVE;
-              else
-                subset_settings_menu.item[5].kind = MN_ACTION;
-
-              switch (i = menu_check(&subset_settings_menu))
-                {
-                case 5:
-                  save_subset_settings_menu();
-                  show_menu = YES;
-                  break;
-                }
-            }
+        default:
+          if(it >= 0)
+          {
+            cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
+            Menu::set_current(0);
+            cur_objects = "";
+
+          }
+          break;
         }
+      }
+      else if(menu == select_objects_menu)
+      {
+        int it = -1;
+        switch (it = select_objects_menu->check())
+        {
+        default:
+          if(it >= 0)
+          {
+            cur_objects = select_objects_menu->get_item_by_id(it).text;
+            cur_tilegroup = "";
 
-      if(done)
+            Menu::set_current(0);
+          }
+          break;
+        }
+      }
+      else if(menu == subset_load_menu)
+      {
+        switch (i = subset_load_menu->check())
         {
-          le_quit();
-          return 0;
+        case 0:
+          break;
+        default:
+          if(i >= 1)
+          {
+            if(le_load_level(level_subsets.item[i-1]))
+              return 1;
+          }
+          break;
         }
+      }
+      else if(menu == subset_new_menu)
+      {
+        if(subset_new_menu->item[2].input[0] == '\0')
+          subset_new_menu->item[3].kind = MN_DEACTIVE;
+        else
+        {
+          subset_new_menu->item[3].kind = MN_ACTION;
 
-      if(done == DONE_QUIT)
+          switch (i = subset_new_menu->check())
+          {
+          case MNID_CREATESUBSET:
+            LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
+            le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
+            leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
+           delete le_world;
+            le_world = new World(le_level_subset->name,1);
+            subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
+
+            Menu::set_current(subset_settings_menu);
+            break;
+          }
+        }
+      }
+      else if(menu == subset_settings_menu)
+      {
+        if(le_level_subset->title.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETTITLE).input) == 0 && le_level_subset->description.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETDESCRIPTION).input) == 0  )
+          subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
+        else
+          subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
+
+        switch (i = subset_settings_menu->check())
         {
-          le_quit();
-          return 1;
+        case MNID_SUBSETSAVECHANGES:
+          save_subset_settings_menu();
+          Menu::set_current(leveleditor_menu);
+          break;
         }
+      }
+    }
 
-      SDL_Delay(25);
-      now_time = SDL_GetTicks();
-      if (now_time < last_time + FPS)
-        SDL_Delay(last_time + FPS - now_time); /* delay some time */
+    mouse_cursor->draw();
 
-      flipscreen();
+    if(done)
+    {
+      le_quit();
+      return 0;
     }
 
+    ++global_frame_counter;
+
+    SDL_Delay(25);
+    now_time = SDL_GetTicks();
+    if (now_time < last_time + FPS)
+      SDL_Delay(last_time + FPS - now_time);   /* delay some time */
+
+    flipscreen();
+  }
+
   return done;
 }
 
+int le_load_level(char *filename)
+{
+  le_level_subset->load(filename);
+  leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
+  le_level = 1;
+  delete le_world;
+  le_world = new World(filename,le_level);
+  
+  //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
+
+  Menu::set_current(NULL);
+
+  return 0;
+}
 
-void le_update_buttons(const char *theme)
+void le_init_menus()
 {
   int i;
-  char filename[1024];
-  char pathname[1024];
-  SDLKey key;
-  string_list_type bkgd_files;
-  string_list_type fgd_files;
-
-  sprintf(pathname,"images/themes/%s",theme);
-  bkgd_files =  dfiles(pathname,"bkgd-", NULL);
-  string_list_sort(&bkgd_files);
+  
+  leveleditor_menu = new Menu();
+  subset_load_menu = new Menu();
+  subset_new_menu  = new Menu();
+  subset_settings_menu = new Menu();
+  level_settings_menu  = new Menu();
+  select_tilegroup_menu  = new Menu();
+  select_objects_menu = new Menu();
+
+  leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
+  leveleditor_menu->additem(MN_HL,"",0,0);
+  leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
+  leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
+  leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
+  leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
+  leveleditor_menu->additem(MN_HL,"",0,0);
+  leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
+
+  Menu::set_current(leveleditor_menu);
+
+  subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
+  subset_load_menu->additem(MN_HL, "", 0, 0);
 
-  le_bkgd_panel.hidden = YES;
-  key = SDLK_a;
-  for(i = 0; i < bkgd_files.num_items; ++i)
+  for(i = 0; i < level_subsets.num_items; ++i)
+  {
+    subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
+  }
+  subset_load_menu->additem(MN_HL,"",0,0);
+  subset_load_menu->additem(MN_BACK,"Back",0,0);
+
+  subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
+  subset_new_menu->additem(MN_HL,"",0,0);
+  subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
+  subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
+  subset_new_menu->additem(MN_HL,"",0,0);
+  subset_new_menu->additem(MN_BACK,"Back",0,0);
+
+  subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
+  subset_settings_menu->additem(MN_HL,"",0,0);
+  subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
+  subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
+  subset_settings_menu->additem(MN_HL,"",0,0);
+  subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
+  subset_settings_menu->additem(MN_HL,"",0,0);
+  subset_settings_menu->additem(MN_BACK,"Back",0,0);
+
+  level_settings_menu->arrange_left = true;
+  level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
+  level_settings_menu->additem(MN_HL,"",0,0);
+  level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
+  level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
+  level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
+  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,    "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,    "Bottom Green",0,0,MNID_BottomGreen);
+  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);
+  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();
+      it != tilegroups->end(); ++it )
+  {
+    select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
+    tileid++;
+    tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
+    i = 0;
+    
+    for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
+        sit != (*it).tiles.end(); ++sit, ++i)
     {
-      sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
-      button_change_icon(&le_bkgd_panel.item[i],filename);
+      std::string imagefile = "/images/tilesets/" ;
+      bool only_editor_image = false;
+      if(!TileManager::instance()->get(*sit)->filenames.empty())
+      {
+        imagefile += TileManager::instance()->get(*sit)->filenames[0];
+      }
+      else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
+      {
+        imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
+        only_editor_image = true;
+      }
+      else
+      {
+        imagefile += "notile.png";
+      }
+      Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
+                                  0, 0, 32, 32);
+      if(!only_editor_image)
+        if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
+        {
+          imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
+          button->add_icon(imagefile,32,32);
+        }
+      tilegroups_map[it->name]->additem(button, *sit);
     }
+  }
+  select_tilegroup_menu->additem(MN_HL,"",0,0);
 
-  sprintf(pathname,"images/themes/%s",theme);
-  fgd_files =  dfiles(pathname,"solid", NULL);
-  string_list_sort(&fgd_files);
-  key = SDLK_a;
-  for(i = 0; i < fgd_files.num_items; ++i)
-    {
-      sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
-      button_change_icon(&le_fgd_panel.item[i],filename);
-    }
+  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->additem(MN_ACTION,"BadGuys",0,0,1);
+  objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
 
-  string_list_free(&fgd_files);
-  fgd_files =  dfiles(pathname,"brick", NULL);
-  string_list_sort(&fgd_files);
+  for(int i = 0; i < NUM_BadGuyKinds; ++i)
+  {
+    BadGuy bad_tmp(0,0,BadGuyKind(i),false);
+    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));
+  }
+
+  select_objects_menu->additem(MN_HL,"",0,0);
 
-  for(i = 0; i < fgd_files.num_items; ++i)
-    {
-      sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
-      button_change_icon(&le_fgd_panel.item[i+14],filename);
-    }
 }
 
 int le_init()
 {
-  int i;
-  char filename[1024];
-  SDLKey key;
-  string_list_type fgd_files;
-  string_list_type bkgd_files;
-  string_list_type bad_files;
+
+
   level_subsets = dsubdirs("/levels", "info");
+  le_level_subset = new LevelSubset;
 
-  le_show_grid = YES;
+  le_world = NULL;
+  
+  active_tm = TM_IA;
+  le_show_grid = true;
+  scroll_x = 0;
 
-  /*  level_changed = NO;*/
   fire = DOWN;
   done = 0;
   le_frame = 0;        /* support for frames in some tiles, like waves and bad guys */
-  le_level_changed = NO;
-  le_current_level = NULL;
+  le_level_changed = false;
 
-  le_current_tile = '.';
-  le_mouse_pressed[LEFT] = NO;
-  le_mouse_pressed[RIGHT] = NO;
+  le_mouse_pressed[LEFT] = false;
+  le_mouse_pressed[RIGHT] = false;
 
-  texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
-
-  /* Load buttons */
-  button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
-  button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
-  button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
-  button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
-  button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
-  button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
-  button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
-  button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
-  button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
-  button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
-  button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
-  button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
-  button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
-
-  bkgd_files =  dfiles("images/themes/antarctica","bkgd-", NULL);
-  string_list_sort(&bkgd_files);
-
-  button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
-  le_bkgd_panel.hidden = YES;
-  key = SDLK_a;
-  for(i = 0; i < bkgd_files.num_items; ++i)
-    {
-      sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
-      button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
-    }
+  le_mouse_clicked[LEFT] = false;
+  le_mouse_clicked[RIGHT] = false;
 
-  string_list_free(&bkgd_files);
-  bkgd_files = dfiles("images/shared","cloud-", NULL);
-  string_list_sort(&bkgd_files);
+  le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
 
-  for(i = 0; i < bkgd_files.num_items; ++i)
-    {
-      sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
-      button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
-    }
+  select_tilegroup_menu_effect.init(false);
+  select_objects_menu_effect.init(false);
 
-  fgd_files =  dfiles("images/themes/antarctica","solid", NULL);
-  string_list_sort(&fgd_files);
-  key = SDLK_a;
-  button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
-  for(i = 0; i < fgd_files.num_items; ++i)
-    {
-      sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
-      button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
-    }
-
-  string_list_free(&fgd_files);
-  string_list_add_item(&fgd_files,"waves-0.png");
-  string_list_add_item(&fgd_files,"water.png");
-  string_list_add_item(&fgd_files,"pole.png");
-  string_list_add_item(&fgd_files,"poletop.png");
-  string_list_add_item(&fgd_files,"flag-0.png");
-  string_list_add_item(&fgd_files,"box-empty.png");
-  string_list_add_item(&fgd_files,"mints.png");
-  string_list_add_item(&fgd_files,"distro-0.png");
-  string_list_add_item(&fgd_files,"golden-herring.png");
-  string_list_add_item(&fgd_files,"distro-0.png");
-
-  for(i = 0; i < fgd_files.num_items; ++i)
-    {
-      sprintf(filename,"images/shared/%s",fgd_files.item[i]);
-      button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
-    }
-
-  string_list_free(&fgd_files);
-  fgd_files =  dfiles("images/themes/antarctica","brick", NULL);
-  string_list_sort(&fgd_files);
-
-  for(i = 0; i < fgd_files.num_items; ++i)
-    {
-      sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
-      button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
-    }
-
-  string_list_free(&fgd_files);
-  string_list_add_item(&fgd_files,"distro-0.png");
-  string_list_add_item(&fgd_files,"distro-0.png");
-  for(i = 0; i < fgd_files.num_items; ++i)
-    {
-      sprintf(filename,"images/shared/%s",fgd_files.item[i]);
-      button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
-    }
-
-  le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
-  le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
-  le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
-  le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
-  le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
-
-  string_list_init(&bad_files);
-  string_list_add_item(&bad_files,"bsod-left-0.png");
-  string_list_add_item(&bad_files,"laptop-left-0.png");
-  string_list_add_item(&bad_files,"bag-left-0.png");
-  button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
-  le_bad_panel.hidden = YES;
-  key = SDLK_a;
-  for(i = 0; i < bad_files.num_items; ++i)
-    {
-      sprintf(filename,"images/shared/%s",bad_files.item[i]);
-      button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
-    }
-
-  menu_init(&leveleditor_menu);
-  menu_additem(&leveleditor_menu,menu_item_create(MN_LABEL,"Level Editor Menu",0,0));
-  menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Return To Level Editor",0,0));
-  menu_additem(&leveleditor_menu,menu_item_create(MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu));
-  menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"Load Level Subset",0,&subset_load_menu));
-  menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"New Level Subset",0,&subset_new_menu));
-  menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Quit Level Editor",0,0));
-
-  menu_reset();
-  menu_set_current(&leveleditor_menu);
-  show_menu = YES;
-
-  menu_init(&subset_load_menu);
-  menu_additem(&subset_load_menu,menu_item_create(MN_LABEL,"Load Level Subset",0,0));
-  menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
-  for(i = 0; i < level_subsets.num_items; ++i)
-    {
-      menu_additem(&subset_load_menu,menu_item_create(MN_ACTION,level_subsets.item[i],0,0));
-    }
-  menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&subset_load_menu,menu_item_create(MN_BACK,"Back",0,0));
-
-  menu_init(&subset_new_menu);
-  menu_additem(&subset_new_menu,menu_item_create(MN_LABEL,"New Level Subset",0,0));
-  menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&subset_new_menu,menu_item_create(MN_TEXTFIELD,"Enter Name",0,0));
-  menu_additem(&subset_new_menu,menu_item_create(MN_ACTION,"Create",0,0));
-  menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&subset_new_menu,menu_item_create(MN_BACK,"Back",0,0));
-
-  menu_init(&subset_settings_menu);
-  menu_additem(&subset_settings_menu,menu_item_create(MN_LABEL,"Level Subset Settings",0,0));
-  menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Title",0,0));
-  menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Description",0,0));
-  menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&subset_settings_menu,menu_item_create(MN_ACTION,"Save Changes",0,0));
-  menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&subset_settings_menu,menu_item_create(MN_BACK,"Back",0,0));
-
-  menu_init(&level_settings_menu);
-  level_settings_menu.arrange_left = YES;
-  menu_additem(&level_settings_menu,menu_item_create(MN_LABEL,"Level Settings",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Name    ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Theme   ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Song    ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Bg-Image",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Length ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Time   ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Gravity",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Red    ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Green  ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Blue   ",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
-  menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Apply Changes",0,0));
+  /* 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_F6,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_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_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
+  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_F7,screen->w-64,80);
+
+  le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
+  le_tilemap_panel->set_button_size(32,10);
+  le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
+  le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0),TM_IA);
+  le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
+  le_tilemap_panel->highlight_last(true);
+
+  le_current.Init();
+
+  le_init_menus();
 
   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 
+
   return 0;
 }
 
@@ -557,166 +570,181 @@ void update_level_settings_menu()
   char str[80];
   int i;
 
-  menu_item_change_input(&level_settings_menu.item[2], le_current_level->name.c_str());
-  sprintf(str,"%d",le_current_level->width);
-
-  string_list_copy(level_settings_menu.item[3].list, dsubdirs("images/themes", "solid0.png"));
-  string_list_copy(level_settings_menu.item[4].list, dfiles("music/",NULL, "-fast"));
-  string_list_copy(level_settings_menu.item[5].list, dfiles("images/background",NULL, NULL));
-  string_list_add_item(level_settings_menu.item[5].list,"");
-  if((i = string_list_find(level_settings_menu.item[3].list,le_current_level->theme.c_str())) != -1)
-    level_settings_menu.item[3].list->active_item = i;
-  if((i = string_list_find(level_settings_menu.item[4].list,le_current_level->song_title.c_str())) != -1)
-    level_settings_menu.item[4].list->active_item = i;
-  if((i = string_list_find(level_settings_menu.item[5].list,le_current_level->bkgd_image.c_str())) != -1)
-    level_settings_menu.item[5].list->active_item = i;
-
-  menu_item_change_input(&level_settings_menu.item[6], str);
-  sprintf(str,"%d",le_current_level->time_left);
-  menu_item_change_input(&level_settings_menu.item[7], str);
-  sprintf(str,"%2.0f",le_current_level->gravity);
-  menu_item_change_input(&level_settings_menu.item[8], str);
-  sprintf(str,"%d",le_current_level->bkgd_red);
-  menu_item_change_input(&level_settings_menu.item[9], str);
-  sprintf(str,"%d",le_current_level->bkgd_green);
-  menu_item_change_input(&level_settings_menu.item[10], str);
-  sprintf(str,"%d",le_current_level->bkgd_blue);
-  menu_item_change_input(&level_settings_menu.item[11], str);
+  level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_world->get_level()->name.c_str());
+  level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_world->get_level()->author.c_str());
+
+  string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
+  string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
+  string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
+  string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
+  string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
+  string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
+
+  if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_world->get_level()->song_title.c_str())) != -1)
+    level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
+  if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_world->get_level()->bkgd_image.c_str())) != -1)
+    level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
+  if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_world->get_level()->particle_system.c_str())) != -1)
+    level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
+
+  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()->time_left);
+  level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
+  sprintf(str,"%2.0f",le_world->get_level()->gravity);
+  level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->bkgd_speed);
+  level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->bkgd_top.red);
+  level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->bkgd_top.green);
+  level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->bkgd_top.blue);
+  level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->bkgd_bottom.red);
+  level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->bkgd_bottom.green);
+  level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
+  sprintf(str,"%d",le_world->get_level()->bkgd_bottom.blue);
+  level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
 }
 
 void update_subset_settings_menu()
 {
-  menu_item_change_input(&subset_settings_menu.item[2], le_level_subset.title.c_str());
-  menu_item_change_input(&subset_settings_menu.item[3], le_level_subset.description.c_str());
+  subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
+  subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
 }
 
 void apply_level_settings_menu()
 {
-  int i,y,j;
-  i = NO;
-
-  le_current_level->name = level_settings_menu.item[2].input;
-
-  if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu.item[5].list)) != 0)
-    {
-      le_current_level->bkgd_image = string_list_active(level_settings_menu.item[5].list);
-      i = YES;
-    }
-
-  if(le_current_level->theme.compare(string_list_active(level_settings_menu.item[3].list)) != 0)
-    {
-      le_current_level->theme = string_list_active(level_settings_menu.item[3].list);
-      le_update_buttons(le_current_level->theme.c_str());
-      i = YES;
-    }
-
-  if(i == YES)
-    {
-      level_free_gfx();
-      level_load_gfx(le_current_level);
-    }
-
-  le_current_level->song_title = string_list_active(level_settings_menu.item[4].list);
-
-  i = le_current_level->width;
-  le_current_level->width = atoi(level_settings_menu.item[6].input);
-  if(le_current_level->width < i)
-    {
-      if(le_current_level->width < 21)
-        le_current_level->width = 21;
-      for(y = 0; y < 15; ++y)
-        {
-          le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
-          le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
-        }
-    }
-  else if(le_current_level->width > i)
-    {
-      for(y = 0; y < 15; ++y)
-        {
-          le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
-          for(j = 0; j < le_current_level->width - i; ++j)
-            le_current_level->tiles[y][i+j] = (unsigned int) '.';
-          le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
-        }
-    }
-  le_current_level->time_left = atoi(level_settings_menu.item[7].input);
-  le_current_level->gravity = atof(level_settings_menu.item[8].input);
-  le_current_level->bkgd_red = atoi(level_settings_menu.item[9].input);
-  le_current_level->bkgd_green = atoi(level_settings_menu.item[10].input);
-  le_current_level->bkgd_blue = atoi(level_settings_menu.item[11].input);
+  int i;
+  i = false;
+
+  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;
+
+  if(le_world->get_level()->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
+  {
+    le_world->get_level()->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
+    i = true;
+  }
+
+  if(le_world->get_level()->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
+  {
+    le_world->get_level()->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
+  }
+
+  if(i)
+  {
+    le_world->get_level()->load_gfx();
+  }
+
+  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()->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()->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
+  le_world->get_level()->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
+  le_world->get_level()->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
+  le_world->get_level()->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
+  le_world->get_level()->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
+  le_world->get_level()->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
 }
 
 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();
 }
 
 void le_goto_level(int levelnb)
 {
-  arrays_free();
-  arrays_init();
-
-  level_free(le_current_level);
-  if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
-    {
-      level_load(le_current_level, le_level_subset.name.c_str(), le_level);
-    }
-  else
-    {
-      le_level = levelnb;
-    }
-
-  le_set_defaults();
-
-  le_update_buttons(le_current_level->theme.c_str());
-
-  level_free_gfx();
-  level_load_gfx(le_current_level);
-
-  le_activate_bad_guys();
+  delete le_world;
+  le_world = new World(le_level_subset->name, levelnb);
 }
 
 void le_quit(void)
 {
-  /*if(level_changed == YES)
+  /*if(level_changed == true)
     if(askforsaving() == CANCEL)
       return;*/ //FIXME
 
   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
 
-  texture_free(&le_selection);
-  menu_free(&leveleditor_menu);
-  menu_free(&subset_load_menu);
-  menu_free(&subset_new_menu);
-  menu_free(&subset_settings_menu);
-  menu_free(&level_settings_menu);
-  button_panel_free(&le_bkgd_panel);
-  button_panel_free(&le_fgd_panel);
-  button_panel_free(&le_bad_panel);
-  button_free(&le_save_level_bt);
-  button_free(&le_test_level_bt);
-  button_free(&le_next_level_bt);
-  button_free(&le_previous_level_bt);
-  button_free(&le_move_right_bt);
-  button_free(&le_move_left_bt);
-  button_free(&le_rubber_bt);
-  button_free(&le_select_mode_one_bt);
-  button_free(&le_select_mode_two_bt);
-  button_free(&le_settings_bt);
-  button_free(&le_bad_bt);
-  button_free(&le_bkgd_bt);
-  button_free(&le_fgd_bt);
-
-  if(le_current_level != NULL)
+  delete le_selection;
+  delete leveleditor_menu;
+  delete subset_load_menu;
+  delete subset_new_menu;
+  delete subset_settings_menu;
+  delete level_settings_menu;
+  delete select_tilegroup_menu;
+  delete select_objects_menu;
+  delete le_save_level_bt;
+  delete le_exit_bt;
+  delete le_test_level_bt;
+  delete le_next_level_bt;
+  delete le_previous_level_bt;
+  delete le_move_right_bt;
+  delete le_move_left_bt;
+  delete le_rubber_bt;
+  delete le_select_mode_one_bt;
+  delete le_select_mode_two_bt;
+  delete le_settings_bt;
+  delete le_tilegroup_bt;
+  delete le_objects_bt;
+  delete le_tilemap_panel;
+
+  delete le_level_subset;
+  le_level_subset = 0;
+
+  for(ButtonPanelMap::iterator i = tilegroups_map.begin();
+      i != tilegroups_map.end(); ++i)
+  {
+    delete i->second;
+  }
+  for(ButtonPanelMap::iterator i = objects_map.begin();
+      i != objects_map.end(); ++i)
+  {
+    delete i->second;
+  }
+}
+
+void le_drawminimap()
+{
+  if(le_world == NULL)
+    return;
+
+  int mini_tile_width;
+  if(screen->w - 64 > le_world->get_level()->width * 4)
+    mini_tile_width = 4;
+  else if(screen->w - 64 > le_world->get_level()->width * 2)
+    mini_tile_width = 2;
+  else
+    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)
+    for (int x = 0; x < le_world->get_level()->width; ++x)
     {
-      level_free_gfx();
-      level_free(le_current_level);
-      unloadshared();
-      arrays_free();
+
+      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, le_world->get_level()->ia_tiles[y][x]);
+
+      Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
+
     }
+
+  fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, 15*4, 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, 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);
+
 }
 
 void le_drawinterface()
@@ -724,557 +752,639 @@ void le_drawinterface()
   int x,y;
   char str[80];
 
-  if(le_current_level != NULL)
+  if(le_world != NULL)
+  {
+    /* draw a grid (if selected) */
+    if(le_show_grid)
     {
-      /* draw a grid (if selected) */
-      if(le_show_grid)
-        {
-          for(x = 0; x < 19; x++)
-            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(x = 0; x < 19; x++)
+        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);
     }
+  }
+
+  if(show_minimap && use_gl) // 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(le_selection_mode == CURSOR)
-    texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
+    if(le_current.IsTile())
+      le_selection->draw( cursor_x - pos_x, cursor_y);
+    else
+      le_selection->draw( cursor_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);
-    }
+  {
+    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);
+  }
 
 
   /* draw button bar */
   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
-  drawshape(19 * 32, 14 * 32, le_current_tile);
-  switch(le_current_tile)
-    {
-    case 'B':
-      texture_draw(&img_mints, 19 * 32, 14 * 32, NO_UPDATE);
-      break;
-    case '!':
-      texture_draw(&img_golden_herring,19 * 32, 14 * 32, NO_UPDATE);
-      break;
-    case 'x':
-    case 'y':
-    case 'A':
-      texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32, NO_UPDATE);
-      break;
-    case '0':
-      texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32, NO_UPDATE);
-      break;
-    case '1':
-      texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32, NO_UPDATE);
-      break;
-    case '2':
-      texture_draw(&img_money_left[0],19 * 32, 14 * 32, NO_UPDATE);
-      break;
-    default:
-      break;
-    }
 
-  if(le_current_level != NULL)
+  if(le_current.IsTile())
+  {
+    Tile::draw(19 * 32, 14 * 32, le_current.tile);
+    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);
+  }
+  if(le_current.IsObject())
+  {
+    le_current.obj->draw_on_screen(19 * 32, 14 * 32);
+    le_current.obj->draw_on_screen(cursor_x,cursor_y);
+  }
+
+  if(le_world != NULL)
+  {
+    le_save_level_bt->draw();
+    le_exit_bt->draw();
+    le_test_level_bt->draw();
+    le_next_level_bt->draw();
+    le_previous_level_bt->draw();
+    le_rubber_bt->draw();
+    if(le_selection_mode == SQUARE)
+      le_select_mode_one_bt->draw();
+    else if(le_selection_mode == CURSOR)
+      le_select_mode_two_bt->draw();
+    le_settings_bt->draw();
+    le_move_right_bt->draw();
+    le_move_left_bt->draw();
+    le_tilegroup_bt->draw();
+    le_objects_bt->draw();
+    if(!cur_tilegroup.empty())
+      tilegroups_map[cur_tilegroup]->draw();
+    else if(!cur_objects.empty())
     {
-      button_draw(&le_save_level_bt);
-      button_draw(&le_test_level_bt);
-      button_draw(&le_next_level_bt);
-      button_draw(&le_previous_level_bt);
-      button_draw(&le_rubber_bt);
-      button_draw(&le_select_mode_one_bt);
-      button_draw(&le_select_mode_two_bt);
-      button_draw(&le_settings_bt);
-      button_draw(&le_move_right_bt);
-      button_draw(&le_move_left_bt);
-      button_draw(&le_bad_bt);
-      button_draw(&le_bkgd_bt);
-      button_draw(&le_fgd_bt);
-      button_panel_draw(&le_bkgd_panel);
-      button_panel_draw(&le_fgd_panel);
-      button_panel_draw(&le_bad_panel);
-
-      sprintf(str, "%d/%d", le_level,le_level_subset.levels);
-      text_drawf(&white_text, str, -8, 16, A_RIGHT, A_NONE, 1, NO_UPDATE);
-
-      text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
+      objects_map[cur_objects]->draw();
     }
+
+    le_tilemap_panel->draw();
+
+    sprintf(str, "%d/%d", le_level,le_level_subset->levels);
+    white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
+
+    white_small_text->draw("F1 for Help", 10, 430, 1);
+  }
   else
-    {
-      if(show_menu == NO)
-        text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
-      else
-        text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
-    }
+  {
+    if(!Menu::current())
+      white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
+    else
+      white_small_text->draw("No Level Subset loaded", 10, 430, 1);
+  }
 
 }
 
 void le_drawlevel()
 {
-  int y,x,i,s;
+  unsigned int y,x,s;
+  Uint8 a;
 
   /* Draw the real background */
-  if(le_current_level->bkgd_image[0] != '\0')
-    {
-      s = pos_x / 30;
-      texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h, NO_UPDATE);
-      texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h, NO_UPDATE);
-    }
+  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
-    {
-      clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
-    }
+  {
+    drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
+  }
+
+  if(le_current.IsTile())
+  {
+    Tile::draw(cursor_x-pos_x, cursor_y,le_current.tile,128);
+    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);
+  }
+  if(le_current.IsObject())
+  {
+    le_current.obj->move_to(cursor_x, cursor_y);
+  }
 
   /*       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)
-      {
-        drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
+    {
 
-        /* draw whats inside stuff when cursor is selecting those */
-        /* (draw them all the time - is this the right behaviour?) */
-        switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
-          {
-          case 'B':
-            texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
-            break;
-          case '!':
-            texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
-            break;
-          case 'x':
-          case 'y':
-          case 'A':
-            texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
-            break;
-          default:
-            break;
-          }
-      }
+      if(active_tm == TM_BG)
+        a = 255;
+      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);
+
+      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);
+
+      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);
+
+      /* draw whats inside stuff when cursor is selecting those */
+      /* (draw them all the time - is this the right behaviour?) */
+      if(!TileManager::instance()->get(le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.empty())
+        TileManager::instance()->get(le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
 
-  /* Draw the Bad guys: */
-  for (i = 0; i < num_bad_guys; ++i)
-    {
-      if(bad_guys[i].base.alive == NO)
-        continue;
-      /* to support frames: img_bsod_left[(frame / 5) % 4] */
-      if(bad_guys[i].kind == BAD_BSOD)
-        texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
-      else if(bad_guys[i].kind == BAD_LAPTOP)
-        texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
-      else if (bad_guys[i].kind == BAD_MONEY)
-        texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
     }
 
+  /* Draw the Bad guys: */
+  for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
+  {
+    /* to support frames: img_bsod_left[(frame / 5) % 4] */
+
+    scroll_x = pos_x;
+    (*it)->draw();
+  }
+
 
   /* Draw the player: */
-  /* for now, the position is fixed at (0, 240) */
-  texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240, NO_UPDATE);
+  /* for now, the position is fixed at (100, 240) */
+  largetux.walk_right->draw( 100 - pos_x, 240);
+}
+
+void le_change_object_properties(GameObject *pobj)
+{
+Menu* object_properties_menu = new Menu();
+
+  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);
+  object_properties_menu->additem(MN_HL,"",0,0);
+  object_properties_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);*/
+  object_properties_menu->additem(MN_HL,"",0,0);
+  object_properties_menu->additem(MN_BACK,"Apply",0,0);
+
+delete object_properties_menu;
 }
 
+
 void le_checkevents()
 {
   SDLKey key;
   SDLMod keymod;
-  button_type* pbutton;
+  Button* pbutton;
   int x,y;
 
   keymod = SDL_GetModState();
 
   while(SDL_PollEvent(&event))
+  {
+    if (Menu::current())
+    {
+      Menu::current()->event(event);
+    }
+    else
     {
+      mouse_cursor->set_state(MC_NORMAL);
+
       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
-      if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
-                                       event.motion.y > 0 && event.motion.y < screen->h)))
+      if(event.type == SDL_KEYDOWN
+          || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
+              && (event.motion.x > 0
+                  && event.motion.x < screen->w - 64 &&
+                  event.motion.y > 0 && event.motion.y < screen->h)))
+      {
+        switch(event.type)
         {
+        case SDL_KEYDOWN:      // key pressed
+          key = event.key.keysym.sym;
+          switch(key)
+          {
+          case SDLK_ESCAPE:
+            Menu::set_current(leveleditor_menu);
+          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;
 
-          switch(event.type)
+            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:
+            le_showhelp();
+            break;
+          case SDLK_HOME:
+            cursor_x = 0;
+            pos_x = cursor_x;
+            break;
+          case SDLK_END:
+            cursor_x = (le_world->get_level()->width * 32) - 32;
+            pos_x = cursor_x;
+            break;
+          case SDLK_F9:
+            le_show_grid = !le_show_grid;
+            break;
+          default:
+            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;
+            selection.y1 = event.motion.y;
+            selection.x2 = event.motion.x + pos_x;
+            selection.y2 = event.motion.y;
+          }
+          else if(event.button.button == SDL_BUTTON_RIGHT)
+          {
+            le_mouse_pressed[RIGHT] = true;
+          }
+          break;
+        case SDL_MOUSEBUTTONUP:
+          if(event.button.button == SDL_BUTTON_LEFT)
+          {
+            le_mouse_pressed[LEFT] = false;
+            le_mouse_clicked[LEFT] = true;
+          }
+          else if(event.button.button == SDL_BUTTON_RIGHT)
+          {
+            le_mouse_pressed[RIGHT] = false;
+            le_mouse_clicked[RIGHT] = true;
+          }
+          break;
+        case SDL_MOUSEMOTION:
+
+          if(!Menu::current())
+          {
+            x = event.motion.x;
+            y = event.motion.y;
+
+            if(le_current.IsTile())
             {
-            case SDL_KEYDOWN:  // key pressed
-              key = event.key.keysym.sym;
-              if(show_menu)
-                {
-                  menu_event(&event.key.keysym);
-                  if(key == SDLK_ESCAPE)
-                    {
-                      show_menu = NO;
-                      menu_set_current(&leveleditor_menu);
-                    }
-                  break;
-                }
-              switch(key)
-                {
-                case SDLK_ESCAPE:
-                  if(!show_menu)
-                    show_menu = YES;
-                  else
-                    show_menu = NO;
-                  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:
-                  le_showhelp();
-                  break;
-                case SDLK_HOME:
-                  cursor_x = 0;
-                  pos_x = cursor_x;
-                  break;
-                case SDLK_END:
-                  cursor_x = (le_current_level->width * 32) - 32;
-                  pos_x = cursor_x;
-                  break;
-                case SDLK_F9:
-                  le_show_grid = !le_show_grid;
-                  break;
-                default:
-                  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] = YES;
-
-                  selection.x1 = event.motion.x + pos_x;
-                  selection.y1 = event.motion.y;
-                  selection.x2 = event.motion.x + pos_x;
-                  selection.y2 = event.motion.y;
-                }
-              else if(event.button.button == SDL_BUTTON_RIGHT)
-                le_mouse_pressed[RIGHT] = YES;
-              break;
-            case SDL_MOUSEBUTTONUP:
-              if(event.button.button == SDL_BUTTON_LEFT)
-                le_mouse_pressed[LEFT] = NO;
-              else if(event.button.button == SDL_BUTTON_RIGHT)
-                le_mouse_pressed[RIGHT] = NO;
-              break;
-            case SDL_MOUSEMOTION:
-              if(!show_menu)
-                {
-                  x = event.motion.x;
-                  y = event.motion.y;
-
-                  cursor_x = ((int)(pos_x + x) / 32) * 32;
-                  cursor_y = ((int) y / 32) * 32;
-
-                  if(le_mouse_pressed[LEFT] == YES)
-                    {
-                      selection.x2 = x + pos_x;
-                      selection.y2 = y;
-                    }
-
-                  if(le_mouse_pressed[RIGHT] == YES)
-                    {
-                      pos_x += -1 * event.motion.xrel;
-                    }
-                }
-              break;
-            case SDL_QUIT:     // window closed
-              done = DONE_QUIT;
-              break;
-            default:
-              break;
+              cursor_x = ((int)(pos_x + x) / 32) * 32;
+              cursor_y = ((int) y / 32) * 32;
             }
-        }
-
-      if(le_current_level != NULL)
-        {
-          if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > screen->w-64 && event.motion.x < screen->w &&
-              event.motion.y > 0 && event.motion.y < screen->h)))
+            else
             {
-              le_mouse_pressed[LEFT] = NO;
-              le_mouse_pressed[RIGHT] = NO;
-
-              if(show_menu == NO)
-                {
-                  /* Check for button events */
-                  button_event(&le_test_level_bt,&event);
-                  if(button_get_state(&le_test_level_bt) == BN_CLICKED)
-                    le_testlevel();
-                  button_event(&le_save_level_bt,&event);
-                  if(button_get_state(&le_save_level_bt) == BN_CLICKED)
-                    level_save(le_current_level,le_level_subset.name.c_str(),le_level);
-                  button_event(&le_next_level_bt,&event);
-                  if(button_get_state(&le_next_level_bt) == BN_CLICKED)
-                    {
-                      if(le_level < le_level_subset.levels)
-                        {
-                          le_goto_level(++le_level);
-                        }
-                      else
-                        {
-                          st_level new_lev;
-                          char str[1024];
-                          int d = 0;
-                          sprintf(str,"Level %d doesn't exist.",le_level+1);
-                          text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
-                          text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
-                          text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
-                          flipscreen();
-                          while(d == 0)
-                            {
-                              while(SDL_PollEvent(&event))
-                                switch(event.type)
-                                  {
-                                  case SDL_KEYDOWN:            // key pressed
-                                    switch(event.key.keysym.sym)
-                                      {
-                                      case SDLK_y:
-                                        level_default(&new_lev);
-                                        level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
-                                        le_level_subset.levels = le_level;
-                                        le_goto_level(le_level);
-                                        d = 1;
-                                        break;
-                                      case SDLK_n:
-                                        d = 1;
-                                       break;
-                                     default:
-                                        break;
-                                      }
-                                    break;
-                                  default:
-                                    break;
-                                  }
-                              SDL_Delay(50);
-                            }
-                        }
-                    }
-                  button_event(&le_previous_level_bt,&event);
-                  if(button_get_state(&le_previous_level_bt) == BN_CLICKED)
-                    {
-                      if(le_level > 1)
-                        le_goto_level(--le_level);
-                    }
-                  button_event(&le_rubber_bt,&event);
-                  if(button_get_state(&le_rubber_bt) == BN_CLICKED)
-                    le_current_tile = '.';
-                  button_event(&le_select_mode_one_bt,&event);
-                  if(button_get_state(&le_select_mode_one_bt) == BN_CLICKED)
-                    le_selection_mode = CURSOR;
-                  button_event(&le_select_mode_two_bt,&event);
-                  if(button_get_state(&le_select_mode_two_bt) == BN_CLICKED)
-                    le_selection_mode = SQUARE;
-
-                  button_event(&le_bad_bt,&event);
-                  if(button_get_state(&le_bad_bt) == BN_CLICKED)
-                    {
-                      le_bad_panel.hidden = NO;
-                      le_fgd_panel.hidden = YES;
-                      le_bkgd_panel.hidden = YES;
-                    }
-
-                  button_event(&le_fgd_bt,&event);
-                  if(button_get_state(&le_fgd_bt) == BN_CLICKED)
-                    {
-                      le_bad_panel.hidden = YES;
-                      le_fgd_panel.hidden = NO;
-                      le_bkgd_panel.hidden = YES;
-                    }
-                  button_event(&le_bkgd_bt,&event);
-                  if(button_get_state(&le_bkgd_bt) == BN_CLICKED)
-                    {
-                      le_bad_panel.hidden = YES;
-                      le_fgd_panel.hidden = YES;
-                      le_bkgd_panel.hidden = NO;
-                    }
-                  button_event(&le_settings_bt,&event);
-                  if(button_get_state(&le_settings_bt) == BN_CLICKED)
-                    {
-                      if(show_menu == NO)
-                        {
-                          update_level_settings_menu();
-                          menu_set_current(&level_settings_menu);
-                          show_menu = YES;
-                        }
-                      else
-                        {
-                          menu_set_current(&leveleditor_menu);
-                          show_menu = NO;
-                        }
-                    }
-                  if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
-                    {
-                      if(button_get_state(pbutton) == BN_CLICKED)
-                        {
-                          char c = '\0';
-                          if(pbutton->tag >= 0 && pbutton->tag <= 3)
-                            c = 'G' + pbutton->tag;
-                          else if(pbutton->tag >= 4 && pbutton->tag <= 7)
-                            c = 'g' + pbutton->tag - 4;
-                          else if(pbutton->tag >= 8 && pbutton->tag <= 11)
-                            c = 'C' + pbutton->tag - 8;
-                          else if(pbutton->tag >= 12 && pbutton->tag <= 15)
-                            c = 'c' + pbutton->tag - 12;
-                          if(c != '\0')
-                            le_current_tile = c;
-                        }
-                    }
-                  if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
-                    {
-                      if(button_get_state(pbutton) == BN_CLICKED)
-                        {
-                          char c = '\0';
-                          if(pbutton->tag == 0)
-                            c = '#' ;
-                          else if(pbutton->tag == 1)
-                            c = '[';
-                          else if(pbutton->tag == 2)
-                            c = '=';
-                          else if(pbutton->tag == 3)
-                            c = ']';
-                          else if(pbutton->tag == 4)
-                            c = '^';
-                          else if(pbutton->tag == 5)
-                            c = '&';
-                          else if(pbutton->tag == 6)
-                            c = '|';
-                          else if(pbutton->tag == 7)
-                            c = '*';
-                          else if(pbutton->tag == 8)
-                            c = '\\';
-                          else if(pbutton->tag == 9)
-                            c = 'a';
-                          else if(pbutton->tag == 10)
-                            c = 'B';
-                          else if(pbutton->tag == 11)
-                            c = 'A';
-                          else if(pbutton->tag == 12)
-                            c = '!';
-                          else if(pbutton->tag == 13)
-                            c = '$';
-                          else if(pbutton->tag == 14)
-                            c = 'X';
-                          else if(pbutton->tag == 15)
-                            c = 'Y';
-                          else if(pbutton->tag == 16)
-                            c = 'x';
-                          else if(pbutton->tag == 17)
-                            c = 'y';
-                          if(c != '\0')
-                            le_current_tile = c;
-                        }
-                    }
-                  if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
-                    {
-                      if(button_get_state(pbutton) == BN_CLICKED)
-                        {
-                          char c = '\0';
-                          if(pbutton->tag >= 0 && pbutton->tag <= 2)
-                            c = '0' + pbutton->tag;
-                          if(c != '\0')
-                            le_current_tile = c;
-                        }
-                    }
-                }
-              else
-                {
-                  button_event(&le_settings_bt,&event);
-                  if(button_get_state(&le_settings_bt) == BN_CLICKED)
-                    {
-                      if(show_menu == NO)
-                        {
-                          update_level_settings_menu();
-                          menu_set_current(&level_settings_menu);
-                          show_menu = YES;
-                        }
-                      else
-                        {
-                          menu_set_current(&leveleditor_menu);
-                          show_menu = NO;
-                        }
-                    }
-                }
+              cursor_x = x;
+              cursor_y = y;
             }
-          if(show_menu == NO)
+
+            if(le_mouse_pressed[LEFT])
             {
-              button_event(&le_move_left_bt,&event);
-              button_event(&le_move_right_bt,&event);
+              selection.x2 = x + pos_x;
+              selection.y2 = y;
+            }
 
-              if(le_mouse_pressed[LEFT])
-                {
-                  le_change(cursor_x, cursor_y, le_current_tile);
-                }
+            if(le_mouse_pressed[RIGHT])
+            {
+              pos_x += -1 * event.motion.xrel;
             }
+          }
+          break;
+        case SDL_QUIT: // window closed
+          done = 1;
+          break;
+        default:
+          break;
         }
+      }
     }
-  if(show_menu == NO)
+
+    if(le_world != NULL)
     {
-      if(button_get_state(&le_move_left_bt) == BN_PRESSED)
+      if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > screen->w-64 && event.motion.x < screen->w &&
+          event.motion.y > 0 && event.motion.y < screen->h)))
+      {
+        le_mouse_pressed[LEFT] = false;
+        le_mouse_pressed[RIGHT] = false;
+
+        if(!Menu::current())
         {
-          pos_x -= 192;
+          /* Check for button events */
+          le_test_level_bt->event(event);
+          if(le_test_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_exit_bt->event(event);
+          if(le_exit_bt->get_state() == BUTTON_CLICKED)
+          {
+            Menu::set_current(leveleditor_menu);
+          }
+          le_next_level_bt->event(event);
+          if(le_next_level_bt->get_state() == BUTTON_CLICKED)
+          {
+            if(le_level < le_level_subset->levels)
+            {
+              le_goto_level(++le_level);
+            }
+            else
+            {
+              Level new_lev;
+              char str[1024];
+              sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
+              if(confirm_dialog(str))
+              {
+                new_lev.init_defaults();
+                new_lev.save(le_level_subset->name.c_str(),++le_level);
+                le_level_subset->levels = le_level;
+                le_goto_level(le_level);
+              }
+            }
+          }
+          le_previous_level_bt->event(event);
+          if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
+          {
+            if(le_level > 1)
+              le_goto_level(--le_level);
+          }
+          le_rubber_bt->event(event);
+          if(le_rubber_bt->get_state() == BUTTON_CLICKED)
+            le_current.Tile(0);
+
+          if(le_selection_mode == SQUARE)
+          {
+            le_select_mode_one_bt->event(event);
+            if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
+              le_selection_mode = CURSOR;
+          }
+          else
+          {
+            le_select_mode_two_bt->event(event);
+            if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
+              le_selection_mode = SQUARE;
+          }
+          ButtonPanelMap::iterator it;
+          le_tilegroup_bt->event(event);
+          switch (le_tilegroup_bt->get_state())
+          {
+          case BUTTON_CLICKED:
+            Menu::set_current(select_tilegroup_menu);
+            select_tilegroup_menu_effect.start(200);
+            select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
+            break;
+          case BUTTON_WHEELUP:
+            if(cur_tilegroup.empty())
+            {
+              cur_tilegroup = tilegroups_map.begin()->first;
+            }
+            else
+            {
+              it = tilegroups_map.find(cur_tilegroup);
+              if((++it) == tilegroups_map.end())
+              {
+                cur_tilegroup = tilegroups_map.begin()->first;
+              }
+              else
+              {
+                cur_tilegroup = (*it).first;
+              }
+            }
+
+            cur_objects = "";
+            break;
+          case BUTTON_WHEELDOWN:
+            it = tilegroups_map.find(cur_tilegroup);
+            if(it == tilegroups_map.begin())
+            {
+              cur_tilegroup = tilegroups_map.rbegin()->first;
+              cur_objects = "";
+              break;
+            }
+            if(--it != --tilegroups_map.begin())
+              cur_tilegroup = (*it).first;
+            else
+              cur_tilegroup = tilegroups_map.rbegin()->first;
+
+            cur_objects = "";
+            break;
+          default:
+            break;
+          }
+
+          le_objects_bt->event(event);
+          switch (le_objects_bt->get_state())
+          {
+          case BUTTON_CLICKED:
+            Menu::set_current(select_objects_menu);
+            select_objects_menu_effect.start(200);
+            select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
+            break;
+          case BUTTON_WHEELUP:
+            it = objects_map.find(cur_objects);
+            if(it == objects_map.end())
+            {
+              cur_objects = objects_map.begin()->first;
+              cur_tilegroup = "";
+              break;
+            }
+            if(++it != objects_map.end())
+              cur_objects = (*it).first;
+            else
+              cur_objects = objects_map.begin()->first;
+
+            cur_tilegroup = "";
+            break;
+          case BUTTON_WHEELDOWN:
+            it = objects_map.find(cur_objects);
+            if(it == objects_map.begin())
+            {
+              cur_objects = objects_map.rbegin()->first;
+              cur_tilegroup = "";
+              break;
+            }
+            if(--it != --objects_map.begin())
+              cur_objects = (*it).first;
+            else
+              cur_objects = objects_map.rbegin()->first;
+
+            cur_tilegroup = "";
+            break;
+            break;
+          default:
+            break;
+          }
+
+          le_settings_bt->event(event);
+          if(le_settings_bt->get_state() == BUTTON_CLICKED)
+          {
+            update_level_settings_menu();
+            Menu::set_current(level_settings_menu);
+          }
+          if(!cur_tilegroup.empty())
+          {
+            if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
+            {
+              if(pbutton->get_state() == BUTTON_CLICKED)
+              {
+                le_current.Tile(pbutton->get_tag());
+              }
+            }
+          }
+          else if(!cur_objects.empty())
+          {
+            if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
+            {
+              if(pbutton->get_state() == BUTTON_CLICKED)
+              {
+                le_current.Object(pbutton->get_game_object());
+              }
+            }
+          }
+
+          if((pbutton = le_tilemap_panel->event(event)) != NULL)
+          {
+            if(pbutton->get_state() == BUTTON_CLICKED)
+            {
+              active_tm = static_cast<TileMapType>(pbutton->get_tag());
+            }
+          }
         }
-      else if(button_get_state(&le_move_left_bt) == BN_HOVER)
+        else
         {
-          pos_x -= 96;
+          le_settings_bt->event(event);
+          if(le_settings_bt->get_state() == BUTTON_CLICKED)
+          {
+            Menu::set_current(0);
+          }
+          le_tilegroup_bt->event(event);
+          if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
+          {
+            Menu::set_current(0);
+          }
+          le_objects_bt->event(event);
+          if(le_objects_bt->get_state() == BUTTON_CLICKED)
+          {
+            Menu::set_current(0);
+          }      
         }
+      }
 
-      if(button_get_state(&le_move_right_bt) == BN_PRESSED)
+      if(!Menu::current() && !show_minimap)
+      {
+        if(le_mouse_pressed[LEFT])
         {
-          pos_x += 192;
+          if(le_current.IsTile())
+            le_change(cursor_x, cursor_y, active_tm, le_current.tile);
         }
-      else if(button_get_state(&le_move_right_bt) == BN_HOVER)
+        else if(le_mouse_clicked[LEFT])
         {
-          pos_x += 96;
+          if(le_current.IsObject())
+          {
+            std::string type = le_current.obj->type();
+            if(type == "BadGuy")
+            {
+              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());
+            }
+          }
+          le_mouse_clicked[LEFT] = false;
         }
+      }
+    }
+  }
+  if(!Menu::current())
+  {
+    show_minimap = false;
+
+    le_move_left_bt->event(event);
+    le_move_right_bt->event(event);
+    switch(le_move_left_bt->get_state())
+    {
+    case BUTTON_PRESSED:
+      pos_x -= 192;
+      show_minimap = true;
+      break;
+    case BUTTON_HOVER:
+      pos_x -= 32;
+      show_minimap = true;
+      break;
+    case BUTTON_CLICKED:
+      show_minimap = true;
+      break;
+    default:
+      break;
     }
 
+    switch(le_move_right_bt->get_state())
+    {
+    case BUTTON_PRESSED:
+      pos_x += 192;
+      show_minimap = true;
+      break;
+    case BUTTON_HOVER:
+      pos_x += 32;
+      show_minimap = true;
+      break;
+    case BUTTON_CLICKED:
+      show_minimap = true;
+      break;
+    default:
+      break;
+    }
+
+  }
+
 }
 
 void le_highlight_selection()
@@ -1282,25 +1392,25 @@ void le_highlight_selection()
   int x1, x2, y1, y2;
 
   if(selection.x1 < selection.x2)
-    {
-      x1 = selection.x1;
-      x2 = selection.x2;
-    }
+  {
+    x1 = selection.x1;
+    x2 = selection.x2;
+  }
   else
-    {
-      x1 = selection.x2;
-      x2 = selection.x1;
-    }
+  {
+    x1 = selection.x2;
+    x2 = selection.x1;
+  }
   if(selection.y1 < selection.y2)
-    {
-      y1 = selection.y1;
-      y2 = selection.y2;
-    }
+  {
+    y1 = selection.y1;
+    y2 = selection.y2;
+  }
   else
-    {
-      y1 = selection.y2;
-      y2 = selection.y1;
-    }
+  {
+    y1 = selection.y2;
+    y2 = selection.y1;
+  }
 
   x1 /= 32;
   x2 /= 32;
@@ -1310,105 +1420,117 @@ void le_highlight_selection()
   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
 }
 
-void le_change(float x, float y, unsigned char c)
+void le_change(float x, float y, int tm, unsigned int c)
 {
-  if(le_current_level != NULL)
-    {
-      int xx,yy,i;
-      int x1, x2, y1, y2;
+  if(le_world != NULL)
+  {
+    int xx,yy;
+    int x1, x2, y1, y2;
+    unsigned int i = 0;
 
-      /*  level_changed = YES; */
+    /*  level_changed = true; */
 
-      switch(le_selection_mode)
+    switch(le_selection_mode)
+    {
+    case CURSOR:
+      le_world->get_level()->change(x,y,tm,c);
+
+      base_type cursor_base;
+      cursor_base.x = x;
+      cursor_base.y = y;
+      cursor_base.width = 32;
+      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))
         {
-        case CURSOR:
-          level_change(le_current_level,x,y,c);
-
-          yy = ((int)y / 32);
-          xx = ((int)x / 32);
+         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 there is a bad guy over there, remove it */
-          for(i = 0; i < num_bad_guys; ++i)
-            if (bad_guys[i].base.alive)
-              if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
-                bad_guys[i].base.alive = NO;
+      break;
+    case SQUARE:
+      if(selection.x1 < selection.x2)
+      {
+        x1 = selection.x1;
+        x2 = selection.x2;
+      }
+      else
+      {
+        x1 = selection.x2;
+        x2 = selection.x1;
+      }
+      if(selection.y1 < selection.y2)
+      {
+        y1 = selection.y1;
+        y2 = selection.y2;
+      }
+      else
+      {
+        y1 = selection.y2;
+        y2 = selection.y1;
+      }
 
-          if(c == '0')  /* if it's a bad guy */
-            add_bad_guy(xx*32, yy*32, BAD_BSOD);
-          else if(c == '1')
-            add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
-          else if(c == '2')
-            add_bad_guy(xx*32, yy*32, BAD_MONEY);
+      x1 /= 32;
+      x2 /= 32;
+      y1 /= 32;
+      y2 /= 32;
 
-          break;
-        case SQUARE:
-          if(selection.x1 < selection.x2)
-            {
-              x1 = selection.x1;
-              x2 = selection.x2;
-            }
-          else
-            {
-              x1 = selection.x2;
-              x2 = selection.x1;
-            }
-          if(selection.y1 < selection.y2)
-            {
-              y1 = selection.y1;
-              y2 = selection.y2;
-            }
-          else
-            {
-              y1 = selection.y2;
-              y2 = selection.y1;
-            }
-
-          x1 /= 32;
-          x2 /= 32;
-          y1 /= 32;
-          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 */)
+      {
+        if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
+            && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
+        {
+         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 there is a bad guy over there, remove it */
-          for(i = 0; i < num_bad_guys; ++i)
-            if(bad_guys[i].base.alive)
-              if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
-                  && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
-                bad_guys[i].base.alive = NO;
+      for(xx = x1; xx <= x2; xx++)
+        for(yy = y1; yy <= y2; yy++)
+        {
+          le_world->get_level()->change(xx*32, yy*32, tm, c);
 
-          for(xx = x1; xx <= x2; xx++)
-            for(yy = y1; yy <= y2; yy++)
-              {
-                level_change(le_current_level, xx*32, yy*32, c);
-
-                if(c == '0')  // if it's a bad guy
-                  add_bad_guy(xx*32, yy*32, BAD_BSOD);
-                else if(c == '1')
-                  add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
-                else if(c == '2')
-                  add_bad_guy(xx*32, yy*32, BAD_MONEY);
-              }
-          break;
-        default:
-          break;
         }
+      break;
+    default:
+      break;
     }
+  }
 }
 
 void le_testlevel()
 {
-  level_save(le_current_level,"test",le_level);
-  gameloop("test",le_level, ST_GL_TEST);
-  menu_set_current(&leveleditor_menu);
-  arrays_init();
-  level_load_gfx(le_current_level);
-  loadshared();
-  le_activate_bad_guys();
+  le_world->get_level()->save("test", le_level);
+
+  GameSession session("test",le_level, ST_GL_TEST);
+  session.run();
+  player_status.reset();
+
+  music_manager->halt_music();
+
+  Menu::set_current(NULL);
+  /*delete le_world.arrays_free();
+  le_current_level->load_gfx();
+  le_world.activate_bad_guys();*/
 }
 
 void le_showhelp()
 {
   SDL_Event event;
-  unsigned int i, done;
+  unsigned int i, done_;
   char *text[] = {
                    "  - This is SuperTux's built-in level editor -",
                    "It has been designed to be light and easy to use from the start.",
@@ -1431,39 +1553,30 @@ void le_showhelp()
                    "settings of your level, including how long it is or what music it will",
                    "play. When you are ready to give your level a test, click on the little",
                    "running Tux. If you like the changes you have made to your level,",
-                                  "press the red save key to keep them.",
+                   "press the red save key to keep them.",
                    "To change which level in your subset you are editing, press the white",
                    "up and down arrow keys at the top of the button box.",
-                                  "",
+                   "",
                    "Have fun making levels! If you make some good ones, send them to us on",
-                                  "the SuperTux mailing list!",
+                   "the SuperTux mailing list!",
                    "- SuperTux team"
                  };
 
 
-  text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2, NO_UPDATE);
+  blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
 
   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
-    text_draw(&white_small_text, text[i], 5, 80+(i*12), 1, NO_UPDATE);
+    white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
 
-  text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
+  gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
 
   flipscreen();
 
-  done = 0;
+  done_ = 0;
 
-  while(done == 0)
-    {
-      while(SDL_PollEvent(&event))
-        switch(event.type)
-          {
-          case SDL_MOUSEBUTTONDOWN:            // mouse pressed
-          case SDL_KEYDOWN:            // key pressed
-            done = 1;
-            break;
-          default:
-            break;
-          }
-      SDL_Delay(50);
-    }
+  while(done_ == 0)
+  {
+    done_ = wait_for_event(event);
+    SDL_Delay(50);
+  }
 }