Added inverse functions for speed. Might be usefull for someone that wants to make...
[supertux.git] / src / leveleditor.cpp
index 6e8bbab..836158e 100644 (file)
  Ricardo Cruz <rick2@aeiou.pt>
  Tobias Glaesser <tobi.web@gmx.de>                      */
 
+#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"
 
 /* definitions to aid development */
 #define DONE_LEVELEDITOR 1
 #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();
@@ -66,7 +66,7 @@ void le_quit();
 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,61 +77,76 @@ 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*);
+
+static Level* le_current_level;
+
+struct LevelEditorWorld
+{
+  std::vector<BadGuy> bad_guys;
+  void arrays_free(void)
+  {
+    bad_guys.clear();
+  }
+
+  void add_bad_guy(float x, float y, BadGuyKind kind)
+  {
+    bad_guys.push_back(BadGuy());
+    BadGuy& new_bad_guy = bad_guys.back();
+  
+    new_bad_guy.init(x,y,kind);
+  }
+
+  void activate_bad_guys()
+  {
+    for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
+         i != le_current_level->badguy_data.end();
+         ++i)
+      {
+        add_bad_guy(i->x, i->y, i->kind);
+      }
+  }
+};
 
 /* leveleditor internals */
 static string_list_type level_subsets;
 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
 static int pos_x, cursor_x, cursor_y, fire;
 static int le_level;
-static st_level* le_current_level;
+static LevelEditorWorld le_world;
 static st_subset 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 unsigned int le_current_tile;
 static bool 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 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 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 Timer select_tilegroup_menu_effect;
+static std::map<std::string, ButtonPanel* > tilegroups_map;
+static std::string cur_tilegroup;
 
 static square selection;
 static int le_selection_mode;
 static SDL_Event event;
-
-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');
-}
+TileMapType active_tm;
 
 void le_set_defaults()
 {
@@ -167,6 +182,17 @@ int leveleditor(int levelnb)
 
       le_checkevents();
 
+      if(current_menu == select_tilegroup_menu)
+        {
+          if(select_tilegroup_menu_effect.check())
+            {
+              select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
+                                             82,-0.5,0.5);
+            }
+          else
+            select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
+        }
+
       if(le_current_level != NULL)
         {
           /* making events results to be in order */
@@ -187,9 +213,9 @@ int leveleditor(int levelnb)
       if(show_menu)
         {
           menu_process_current();
-          if(current_menu == &leveleditor_menu)
+          if(current_menu == leveleditor_menu)
             {
-              switch (menu_check(&leveleditor_menu))
+              switch (leveleditor_menu->check())
                 {
                 case 2:
                   show_menu = false;
@@ -202,22 +228,38 @@ int leveleditor(int levelnb)
                   break;
                 }
             }
-          else if(current_menu == &level_settings_menu)
+          else if(current_menu == level_settings_menu)
             {
-              switch (menu_check(&level_settings_menu))
+              switch (level_settings_menu->check())
                 {
-                case 13:
+                case 17:
                   apply_level_settings_menu();
-                  menu_set_current(&leveleditor_menu);
+                  Menu::set_current(leveleditor_menu);
                   break;
                 default:
                   show_menu = true;
                   break;
                 }
             }
-          else if(current_menu == &subset_load_menu)
+          else if(current_menu == select_tilegroup_menu)
+            {
+           int it = -1;
+              switch (it = select_tilegroup_menu->check())
+                {
+                default:
+                 if(it != -1)
+                 {
+                 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
+                 cur_tilegroup = select_tilegroup_menu->item[it].text;
+                 
+                  show_menu = false;
+                 }
+                  break;
+                }
+            }
+          else if(current_menu == subset_load_menu)
             {
-              switch (i = menu_check(&subset_load_menu))
+              switch (i = subset_load_menu->check())
                 {
                 case 0:
                   break;
@@ -225,66 +267,62 @@ int leveleditor(int levelnb)
                   if(i != -1)
                     {
                       le_level_subset.load(level_subsets.item[i-2]);
-                      leveleditor_menu.item[3].kind = MN_GOTO;
+                      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_world.arrays_free();
+                      le_current_level = new Level;
+                      if(le_current_level->load(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();
+                      le_current_level->load_gfx();
+                     le_world.activate_bad_guys();
                       show_menu = true;
                     }
                   break;
                 }
             }
-          else if(current_menu == &subset_new_menu)
+          else if(current_menu == subset_new_menu)
             {
-              if(subset_new_menu.item[2].input[0] == '\0')
-                subset_new_menu.item[3].kind = MN_DEACTIVE;
+              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;
+                  subset_new_menu->item[3].kind = MN_ACTION;
 
-                  switch (i = menu_check(&subset_new_menu))
+                  switch (i = subset_new_menu->check())
                     {
                     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;
+                      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 = new st_level;
-                      if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
+                      le_world.arrays_free();
+                      le_current_level = new Level;
+                      if(le_current_level->load(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],"");
+                      le_current_level->load_gfx();
+                     le_world.activate_bad_guys();
+                      subset_new_menu->item[2].change_input("");
                       show_menu = true;
                       break;
                     }
                 }
             }
-          else if(current_menu == &subset_settings_menu)
+          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;
+              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;
+                subset_settings_menu->item[5].kind = MN_ACTION;
 
-              switch (i = menu_check(&subset_settings_menu))
+              switch (i = subset_settings_menu->check())
                 {
                 case 5:
                   save_subset_settings_menu();
@@ -294,6 +332,8 @@ int leveleditor(int levelnb)
             }
         }
 
+      mouse_cursor->draw();
+
       if(done)
         {
           le_quit();
@@ -306,6 +346,8 @@ int leveleditor(int levelnb)
           return 1;
         }
 
+      ++global_frame_counter;
+       
       SDL_Delay(25);
       now_time = SDL_GetTicks();
       if (now_time < last_time + FPS)
@@ -317,59 +359,13 @@ int leveleditor(int levelnb)
   return done;
 }
 
-
-void le_update_buttons(const char *theme)
-{
-  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);
-
-  le_bkgd_panel.hidden = true;
-  key = SDLK_a;
-  for(i = 0; i < bkgd_files.num_items; ++i)
-    {
-      sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
-      button_change_icon(&le_bkgd_panel.item[i],filename);
-    }
-
-  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);
-    }
-
-  string_list_free(&fgd_files);
-  fgd_files =  dfiles(pathname,"brick", NULL);
-  string_list_sort(&fgd_files);
-
-  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");
 
+  active_tm = TM_IA;
+  
   le_show_grid = true;
 
   /*  level_changed = NO;*/
@@ -379,173 +375,114 @@ int le_init()
   le_level_changed = false;
   le_current_level = NULL;
 
-  le_current_tile = '.';
+  le_current_tile = 0;
   le_mouse_pressed[LEFT] = false;
   le_mouse_pressed[RIGHT] = false;
 
-  texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
+  le_selection = new Surface(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 = true;
-  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);
-    }
-
-  string_list_free(&bkgd_files);
-  bkgd_files = dfiles("images/shared","cloud-", NULL);
-  string_list_sort(&bkgd_files);
-
-  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);
 
-  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);
-    }
+  /* 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,64);
+  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,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_F4,0,0),TM_BG);
+  le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
+  le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG); 
+  
+  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();
+
+  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);
+  leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
+  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);
 
-  string_list_free(&fgd_files);
-  fgd_files =  dfiles("images/themes/antarctica","brick", NULL);
-  string_list_sort(&fgd_files);
+  menu_reset();
+  Menu::set_current(leveleditor_menu);
+  show_menu = true;
 
-  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);
-    }
+  subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
+  subset_load_menu->additem(MN_HL, "", 0, 0);
 
-  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)
+  for(i = 0; i < level_subsets.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);
+      subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
     }
-
-  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 = true;
-  key = SDLK_a;
-  for(i = 0; i < bad_files.num_items; ++i)
+  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);
+  subset_new_menu->additem(MN_ACTION,"Create",0,0);
+  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);
+  subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
+  subset_settings_menu->additem(MN_HL,"",0,0);
+  subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
+  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);
+  level_settings_menu->additem(MN_TEXTFIELD,"Author  ",0,0);
+  level_settings_menu->additem(MN_STRINGSELECT,"Theme   ",0,0);
+  level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0);
+  level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Time   ",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Top Red    ",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Top Green  ",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Top Blue   ",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
+  level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
+  level_settings_menu->additem(MN_HL,"",0,0);
+  level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
+
+  select_tilegroup_menu->arrange_left = true;
+  select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
+  select_tilegroup_menu->additem(MN_HL,"",0,0);
+  std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
+  for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
     {
-      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, MN_LABEL,"Level Editor Menu",0,0);
-  menu_additem(&leveleditor_menu, MN_HL,"",0,0);
-  menu_additem(&leveleditor_menu, MN_ACTION,"Return To Level Editor",0,0);
-  menu_additem(&leveleditor_menu, MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu);
-  menu_additem(&leveleditor_menu, MN_GOTO,"Load Level Subset",0,&subset_load_menu);
-  menu_additem(&leveleditor_menu, MN_GOTO,"New Level Subset",0,&subset_new_menu);
-  menu_additem(&leveleditor_menu, MN_HL,"",0,0);
-  menu_additem(&leveleditor_menu, MN_ACTION,"Quit Level Editor",0,0);
-
-  menu_reset();
-  menu_set_current(&leveleditor_menu);
-  show_menu = true;
 
-  menu_init(&subset_load_menu);
-  menu_additem(&subset_load_menu,MN_LABEL,"Load Level Subset",0,0);
-  menu_additem(&subset_load_menu,MN_HL,"",0,0);
-  for(i = 0; i < level_subsets.num_items; ++i)
-    {
-      menu_additem(&subset_load_menu,MN_ACTION,level_subsets.item[i],0,0);
+      select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
+      tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
+      i = 0;
+      for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
+        tilegroups_map[(*it).name]->additem(new Button(const_cast<char*>(("images/tilesets/" + TileManager::instance()->get(*sit)->filenames[0]).c_str()), const_cast<char*>((*it).name.c_str()),(SDLKey)(i+'a'),0,0,32,32),(*sit));
     }
-  menu_additem(&subset_load_menu,MN_HL,"",0,0);
-  menu_additem(&subset_load_menu,MN_BACK,"Back",0,0);
-
-  menu_init(&subset_new_menu);
-  menu_additem(&subset_new_menu,MN_LABEL,"New Level Subset",0,0);
-  menu_additem(&subset_new_menu,MN_HL,"",0,0);
-  menu_additem(&subset_new_menu,MN_TEXTFIELD,"Enter Name",0,0);
-  menu_additem(&subset_new_menu,MN_ACTION,"Create",0,0);
-  menu_additem(&subset_new_menu,MN_HL,"",0,0);
-  menu_additem(&subset_new_menu,MN_BACK,"Back",0,0);
-
-  menu_init(&subset_settings_menu);
-  menu_additem(&subset_settings_menu,MN_LABEL,"Level Subset Settings",0,0);
-  menu_additem(&subset_settings_menu,MN_HL,"",0,0);
-  menu_additem(&subset_settings_menu,MN_TEXTFIELD,"Title",0,0);
-  menu_additem(&subset_settings_menu,MN_TEXTFIELD,"Description",0,0);
-  menu_additem(&subset_settings_menu,MN_HL,"",0,0);
-  menu_additem(&subset_settings_menu,MN_ACTION,"Save Changes",0,0);
-  menu_additem(&subset_settings_menu,MN_HL,"",0,0);
-  menu_additem(&subset_settings_menu,MN_BACK,"Back",0,0);
-
-  menu_init(&level_settings_menu);
-  level_settings_menu.arrange_left = true;
-  menu_additem(&level_settings_menu,MN_LABEL,"Level Settings",0,0);
-  menu_additem(&level_settings_menu,MN_HL,"",0,0);
-  menu_additem(&level_settings_menu,MN_TEXTFIELD,"Name    ",0,0);
-  menu_additem(&level_settings_menu,MN_STRINGSELECT,"Theme   ",0,0);
-  menu_additem(&level_settings_menu,MN_STRINGSELECT,"Song    ",0,0);
-  menu_additem(&level_settings_menu,MN_STRINGSELECT,"Bg-Image",0,0);
-  menu_additem(&level_settings_menu,MN_NUMFIELD,"Length ",0,0);
-  menu_additem(&level_settings_menu,MN_NUMFIELD,"Time   ",0,0);
-  menu_additem(&level_settings_menu,MN_NUMFIELD,"Gravity",0,0);
-  menu_additem(&level_settings_menu,MN_NUMFIELD,"Red    ",0,0);
-  menu_additem(&level_settings_menu,MN_NUMFIELD,"Green  ",0,0);
-  menu_additem(&level_settings_menu,MN_NUMFIELD,"Blue   ",0,0);
-  menu_additem(&level_settings_menu,MN_HL,"",0,0);
-  menu_additem(&level_settings_menu,MN_ACTION,"Apply Changes",0,0);
+  select_tilegroup_menu->additem(MN_HL,"",0,0);
 
   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 
@@ -557,112 +494,100 @@ 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());
+  level_settings_menu->item[2].change_input(le_current_level->name.c_str());
+  level_settings_menu->item[3].change_input(le_current_level->author.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);
+  string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
+  string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
+  string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
+  string_list_add_item(level_settings_menu->item[6].list,"");
+  if((i = string_list_find(level_settings_menu->item[4].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[5].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[6].list,le_current_level->bkgd_image.c_str())) != -1)
+    level_settings_menu->item[5].list->active_item = i;
+
+  level_settings_menu->item[7].change_input(str);
   sprintf(str,"%d",le_current_level->time_left);
-  menu_item_change_input(&level_settings_menu.item[7], str);
+  level_settings_menu->item[8].change_input(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->item[9].change_input(str);
+  sprintf(str,"%d",le_current_level->bkgd_top.red);
+  level_settings_menu->item[10].change_input(str);
+  sprintf(str,"%d",le_current_level->bkgd_top.green);
+  level_settings_menu->item[11].change_input(str);
+  sprintf(str,"%d",le_current_level->bkgd_top.blue);
+  level_settings_menu->item[12].change_input(str);
+  sprintf(str,"%d",le_current_level->bkgd_bottom.red);
+  level_settings_menu->item[13].change_input(str);
+  sprintf(str,"%d",le_current_level->bkgd_bottom.green);
+  level_settings_menu->item[14].change_input(str);
+  sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
+  level_settings_menu->item[15].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;
+  int i;
   i = false;
 
-  le_current_level->name = level_settings_menu.item[2].input;
+  le_current_level->name = level_settings_menu->item[2].input;
+  le_current_level->author = level_settings_menu->item[3].input;
 
-  if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu.item[5].list)) != 0)
+  if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
     {
-      le_current_level->bkgd_image = string_list_active(level_settings_menu.item[5].list);
+      le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
       i = true;
     }
 
-  if(le_current_level->theme.compare(string_list_active(level_settings_menu.item[3].list)) != 0)
+  if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
     {
-      le_current_level->theme = string_list_active(level_settings_menu.item[3].list);
-      le_update_buttons(le_current_level->theme.c_str());
+      le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
       i = true;
     }
 
-  if(i == true)
+  if(i)
     {
-      level_free_gfx();
-      level_load_gfx(le_current_level);
+      le_current_level->free_gfx();
+      le_current_level->load_gfx();
     }
 
-  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);
+  le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
+
+  le_current_level->change_size(atoi(level_settings_menu->item[7].input));
+  le_current_level->time_left = atoi(level_settings_menu->item[8].input);
+  le_current_level->gravity = atof(level_settings_menu->item[9].input);
+  le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
+  le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
+  le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
+  le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
+  le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
+  le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].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.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();
+  le_world.arrays_free();
 
-  level_free(le_current_level);
-  if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
+  le_current_level->cleanup();
+  if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
     {
-      level_load(le_current_level, le_level_subset.name.c_str(), le_level);
+      le_current_level->load(le_level_subset.name.c_str(), le_level);
     }
   else
     {
@@ -671,12 +596,10 @@ void le_goto_level(int levelnb)
 
   le_set_defaults();
 
-  le_update_buttons(le_current_level->theme.c_str());
+  le_current_level->free_gfx();
+  le_current_level->load_gfx();
 
-  level_free_gfx();
-  level_load_gfx(le_current_level);
-
-  le_activate_bad_guys();
+  le_world.activate_bad_guys();
 }
 
 void le_quit(void)
@@ -687,35 +610,32 @@ void le_quit(void)
 
   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);
+  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 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_tilemap_panel;
 
   if(le_current_level != NULL)
     {
-      level_free_gfx();
-      level_free(le_current_level);
-      unloadshared();
-      arrays_free();
+      le_current_level->free_gfx();
+      le_current_level->cleanup();
+      le_world.arrays_free();
     }
 }
 
@@ -737,7 +657,7 @@ void le_drawinterface()
     }
 
   if(le_selection_mode == CURSOR)
-    texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
+    le_selection->draw( cursor_x - pos_x, cursor_y);
   else if(le_selection_mode == SQUARE)
     {
       int w, h;
@@ -754,63 +674,40 @@ void le_drawinterface()
 
   /* 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;
-    }
+  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_level != NULL)
     {
-      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);
+      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();
+      le_select_mode_one_bt->draw();
+      le_select_mode_two_bt->draw();
+      le_settings_bt->draw();
+      le_move_right_bt->draw();
+      le_move_left_bt->draw();
+      le_tilegroup_bt->draw();
+      if(!cur_tilegroup.empty())
+      tilegroups_map[cur_tilegroup]->draw();
+      le_tilemap_panel->draw();
 
       sprintf(str, "%d/%d", le_level,le_level_subset.levels);
-      text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1, NO_UPDATE);
+      white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
 
-      text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
+      white_small_text->draw("F1 for Help", 10, 430, 1);
     }
   else
     {
       if(show_menu == false)
-        text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
+        white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
       else
-        text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
+        white_small_text->draw("No Level Subset loaded", 10, 430, 1);
     }
 
 }
@@ -818,17 +715,20 @@ void le_drawinterface()
 void le_drawlevel()
 {
   unsigned int y,x,i,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);
+      le_current_level->img_bkgd->draw_part(s,0,0,0,
+                                            le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
+      le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
+                                            le_current_level->img_bkgd->h);
     }
   else
     {
-      clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
+          drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
     }
 
   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
@@ -836,73 +736,80 @@ void le_drawlevel()
   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)]);
-
+      
+       if(active_tm == TM_BG)
+       a = 255;
+       else
+       a = 128;
+      
+       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_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_current_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_current_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?) */
-        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(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
+       TileManager::instance()->get(le_current_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 < bad_guys.size(); ++i)
+  for (i = 0; i < le_world.bad_guys.size(); ++i)
     {
       /* 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);
+      
+      scroll_x = pos_x;
+      le_world.bad_guys[i].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) */
+  tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
 }
 
 void le_checkevents()
 {
   SDLKey key;
   SDLMod keymod;
-  button_type* pbutton;
+  Button* pbutton;
   int x,y;
 
   keymod = SDL_GetModState();
 
   while(SDL_PollEvent(&event))
     {
+      if(show_menu)
+        current_menu->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)))
         {
-
           switch(event.type)
             {
             case SDL_KEYDOWN:  // key pressed
               key = event.key.keysym.sym;
               if(show_menu)
                 {
-                  menu_event(&event.key.keysym);
                   if(key == SDLK_ESCAPE)
                     {
                       show_menu = false;
-                      menu_set_current(&leveleditor_menu);
+                      Menu::set_current(leveleditor_menu);
                     }
                   break;
                 }
@@ -994,7 +901,9 @@ void le_checkevents()
                   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)
@@ -1011,13 +920,13 @@ void le_checkevents()
                   cursor_x = ((int)(pos_x + x) / 32) * 32;
                   cursor_y = ((int) y / 32) * 32;
 
-                  if(le_mouse_pressed[LEFT] == true)
+                  if(le_mouse_pressed[LEFT])
                     {
                       selection.x2 = x + pos_x;
                       selection.y2 = y;
                     }
 
-                  if(le_mouse_pressed[RIGHT] == true)
+                  if(le_mouse_pressed[RIGHT])
                     {
                       pos_x += -1 * event.motion.xrel;
                     }
@@ -1042,14 +951,20 @@ void le_checkevents()
               if(show_menu == false)
                 {
                   /* Check for button events */
-                  button_event(&le_test_level_bt,&event);
-                  if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
+                  le_test_level_bt->event(event);
+                  if(le_test_level_bt->get_state() == BUTTON_CLICKED)
                     le_testlevel();
-                  button_event(&le_save_level_bt,&event);
-                  if(button_get_state(&le_save_level_bt) == BUTTON_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) == BUTTON_CLICKED)
+                  le_save_level_bt->event(event);
+                  if(le_save_level_bt->get_state() == BUTTON_CLICKED)
+                    le_current_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);
+                   show_menu = true;
+                   }
+                  le_next_level_bt->event(event);
+                  if(le_next_level_bt->get_state() == BUTTON_CLICKED)
                     {
                       if(le_level < le_level_subset.levels)
                         {
@@ -1057,13 +972,13 @@ void le_checkevents()
                         }
                       else
                         {
-                          st_level new_lev;
+                          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);
+                          white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
+                          white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
+                          red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
                           flipscreen();
                           while(d == 0)
                             {
@@ -1074,16 +989,16 @@ void le_checkevents()
                                     switch(event.key.keysym.sym)
                                       {
                                       case SDLK_y:
-                                        level_default(&new_lev);
-                                        level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
+                                        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);
                                         d = 1;
                                         break;
                                       case SDLK_n:
                                         d = 1;
-                                       break;
-                                     default:
+                                        break;
+                                      default:
                                         break;
                                       }
                                     break;
@@ -1094,182 +1009,100 @@ void le_checkevents()
                             }
                         }
                     }
-                  button_event(&le_previous_level_bt,&event);
-                  if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
+                  le_previous_level_bt->event(event);
+                  if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
                     {
                       if(le_level > 1)
                         le_goto_level(--le_level);
                     }
-                  button_event(&le_rubber_bt,&event);
-                  if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
-                    le_current_tile = '.';
-                  button_event(&le_select_mode_one_bt,&event);
-                  if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
+                  le_rubber_bt->event(event);
+                  if(le_rubber_bt->get_state() == BUTTON_CLICKED)
+                    le_current_tile = 0;
+                  le_select_mode_one_bt->event(event);
+                  if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
                     le_selection_mode = CURSOR;
-                  button_event(&le_select_mode_two_bt,&event);
-                  if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
+                  le_select_mode_two_bt->event(event);
+                  if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
                     le_selection_mode = SQUARE;
 
-                  button_event(&le_bad_bt,&event);
-                  if(button_get_state(&le_bad_bt) == BUTTON_CLICKED)
+                  le_tilegroup_bt->event(event);
+                  if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
                     {
-                      le_bad_panel.hidden = false;
-                      le_fgd_panel.hidden = true;
-                      le_bkgd_panel.hidden = true;
+                      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);
+                      show_menu = true;
                     }
 
-                  button_event(&le_fgd_bt,&event);
-                  if(button_get_state(&le_fgd_bt) == BUTTON_CLICKED)
+                  le_settings_bt->event(event);
+                  if(le_settings_bt->get_state() == BUTTON_CLICKED)
                     {
-                      le_bad_panel.hidden = true;
-                      le_fgd_panel.hidden = false;
-                      le_bkgd_panel.hidden = true;
-                    }
-                  button_event(&le_bkgd_bt,&event);
-                  if(button_get_state(&le_bkgd_bt) == BUTTON_CLICKED)
-                    {
-                      le_bad_panel.hidden = true;
-                      le_fgd_panel.hidden = true;
-                      le_bkgd_panel.hidden = false;
-                    }
-                  button_event(&le_settings_bt,&event);
-                  if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
-                    {
-                      if(show_menu == false)
-                        {
-                          update_level_settings_menu();
-                          menu_set_current(&level_settings_menu);
-                          show_menu = true;
-                        }
-                      else
-                        {
-                          menu_set_current(&leveleditor_menu);
-                          show_menu = false;
-                        }
-                    }
-                  if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
-                    {
-                      if(button_get_state(pbutton) == BUTTON_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) == BUTTON_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) == BUTTON_CLICKED)
-                        {
-                          char c = '\0';
-                          if(pbutton->tag >= 0 && pbutton->tag <= 2)
-                            c = '0' + pbutton->tag;
-                          if(c != '\0')
-                            le_current_tile = c;
-                        }
+                      update_level_settings_menu();
+                      Menu::set_current(level_settings_menu);
+                      show_menu = true;
                     }
+                 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();
+                     }
+                 }
+                 if((pbutton = le_tilemap_panel->event(event)) != NULL)
+                 {
+                   if(pbutton->get_state() == BUTTON_CLICKED)
+                     {
+                     active_tm = static_cast<TileMapType>(pbutton->get_tag());
+                     }
+                 }
                 }
               else
                 {
-                  button_event(&le_settings_bt,&event);
-                  if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
+                  le_settings_bt->event(event);
+                  if(le_settings_bt->get_state() == BUTTON_CLICKED)
                     {
-                      if(show_menu == false)
-                        {
-                          update_level_settings_menu();
-                          menu_set_current(&level_settings_menu);
-                          show_menu = true;
-                        }
-                      else
-                        {
-                          menu_set_current(&leveleditor_menu);
-                          show_menu = false;
-                        }
+                      Menu::set_current(leveleditor_menu);
+                      show_menu = false;
+                    }
+                  le_tilegroup_bt->event(event);
+                  if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
+                    {
+                      Menu::set_current(leveleditor_menu);
+                      show_menu = false;
                     }
                 }
             }
           if(show_menu == false)
             {
-              button_event(&le_move_left_bt,&event);
-              button_event(&le_move_right_bt,&event);
+              le_move_left_bt->event(event);
+              le_move_right_bt->event(event);
 
               if(le_mouse_pressed[LEFT])
                 {
-                  le_change(cursor_x, cursor_y, le_current_tile);
+                  le_change(cursor_x, cursor_y, active_tm, le_current_tile);
                 }
             }
         }
     }
   if(show_menu == false)
     {
-      if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
+      if(le_move_left_bt->get_state() == BUTTON_PRESSED)
         {
           pos_x -= 192;
         }
-      else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
+      else if(le_move_left_bt->get_state() == BUTTON_HOVER)
         {
-          pos_x -= 96;
+          pos_x -= 64;
         }
 
-      if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
+      if(le_move_right_bt->get_state() == BUTTON_PRESSED)
         {
           pos_x += 192;
         }
-      else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
+      else if(le_move_right_bt->get_state() == BUTTON_HOVER)
         {
-          pos_x += 96;
+          pos_x += 64;
         }
     }
 
@@ -1308,7 +1141,7 @@ 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)
     {
@@ -1321,22 +1154,22 @@ void le_change(float x, float y, unsigned char c)
       switch(le_selection_mode)
         {
         case CURSOR:
-          level_change(le_current_level,x,y,c);
+          le_current_level->change(x,y,tm,c);
 
           yy = ((int)y / 32);
           xx = ((int)x / 32);
 
           /* if there is a bad guy over there, remove it */
-          for(i = 0; i < bad_guys.size(); ++i)
-              if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
-                  bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(&bad_guys[i]));
+          for(i = 0; i < le_world.bad_guys.size(); ++i)
+            if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
+              le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
 
           if(c == '0')  /* if it's a bad guy */
-            add_bad_guy(xx*32, yy*32, BAD_BSOD);
+            le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
           else if(c == '1')
-            add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
+            le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
           else if(c == '2')
-            add_bad_guy(xx*32, yy*32, BAD_MONEY);
+            le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
 
           break;
         case SQUARE:
@@ -1367,22 +1200,22 @@ void le_change(float x, float y, unsigned char c)
           y2 /= 32;
 
           /* if there is a bad guy over there, remove it */
-          for(i = 0; i < bad_guys.size(); ++i)
-              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.erase(static_cast<std::vector<bad_guy_type>::iterator>(&bad_guys[i]));
+          for(i = 0; i < le_world.bad_guys.size(); ++i)
+            if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
+               && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
+              le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
 
           for(xx = x1; xx <= x2; xx++)
             for(yy = y1; yy <= y2; yy++)
               {
-                level_change(le_current_level, xx*32, yy*32, c);
+                le_current_level->change(xx*32, yy*32, tm, c);
 
                 if(c == '0')  // if it's a bad guy
-                  add_bad_guy(xx*32, yy*32, BAD_BSOD);
+                  le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
                 else if(c == '1')
-                  add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
+                  le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
                 else if(c == '2')
-                  add_bad_guy(xx*32, yy*32, BAD_MONEY);
+                  le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
               }
           break;
         default:
@@ -1393,13 +1226,15 @@ void le_change(float x, float y, unsigned char c)
 
 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_current_level->save("test", le_level);
+  
+  GameSession session("test",le_level, ST_GL_TEST);
+  session.run();
+
+  Menu::set_current(leveleditor_menu);
+  le_world.arrays_free();
+  le_current_level->load_gfx();
+  le_world.activate_bad_guys();
 }
 
 void le_showhelp()
@@ -1428,22 +1263,22 @@ 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_text->draw(text[i], 5, 80+(i*18), 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();
 
@@ -1451,16 +1286,7 @@ void le_showhelp()
 
   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;
-          }
+      done = wait_for_event(event);
       SDL_Delay(50);
     }
 }