Fixed creating level-subset again.
[supertux.git] / src / leveleditor.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
5 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 #include <map>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <SDL.h>
29 #include <SDL_image.h>
30 #include "leveleditor.h"
31
32 #include "screen.h"
33 #include "defines.h"
34 #include "globals.h"
35 #include "setup.h"
36 #include "menu.h"
37 #include "level.h"
38 #include "gameloop.h"
39 #include "badguy.h"
40 #include "scene.h"
41 #include "button.h"
42 #include "tile.h"
43 #include "resources.h"
44 #include "music_manager.h"
45
46 /* definitions to aid development */
47
48 /* definitions that affect gameplay */
49 #define KEY_CURSOR_SPEED 32
50 #define KEY_CURSOR_FASTSPEED 64
51
52 /* when pagedown/up pressed speed:*/
53 #define PAGE_CURSOR_SPEED 13*32
54
55 #define MOUSE_LEFT_MARGIN 80
56 #define MOUSE_RIGHT_MARGIN (560-32)
57 /* right_margin should noticed that the cursor is 32 pixels,
58    so it should subtract that value */
59 #define MOUSE_POS_SPEED 20
60
61 /* look */
62 #define SELECT_W 2 // size of the selections lines
63 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
64
65 /* own declerations */
66 /* crutial ones (main loop) */
67 int le_init();
68 void le_quit();
69 int le_load_level(char *filename);
70 void le_drawlevel();
71 void le_drawinterface();
72 void le_checkevents();
73 void le_change(float x, float y, int tm, unsigned int c);
74 void le_testlevel();
75 void le_showhelp();
76 void le_set_defaults(void);
77 void le_activate_bad_guys(void);
78
79 void le_highlight_selection();
80
81 void apply_level_settings_menu();
82 void update_subset_settings_menu();
83 void save_subset_settings_menu();
84
85 struct TileOrObject
86 {
87   TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
88
89   void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
90   void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
91   //Returns true for a tile
92   bool IsTile() { return is_tile; };
93   //Returns true for a GameObject
94   bool IsObject() { return !is_tile; };
95   void Init() { tile = 0; obj = NULL; is_tile = true; };
96
97   bool is_tile; //true for tile (false for object)
98   unsigned int tile;
99   GameObject* obj;
100 };
101
102 /* leveleditor internals */
103 static string_list_type level_subsets;
104 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
105 static bool show_minimap;
106 static int pos_x, cursor_x, cursor_y, fire;
107 static int le_level;
108 static World* le_world;
109 static LevelSubset* le_level_subset;
110 static int le_show_grid;
111 static int le_frame;
112 static Surface* le_selection;
113 static int done;
114 static TileOrObject le_current;
115 static bool le_mouse_pressed[2];
116 static bool le_mouse_clicked[2];
117 static Button* le_save_level_bt;
118 static Button* le_exit_bt;
119 static Button* le_test_level_bt;
120 static Button* le_next_level_bt;
121 static Button* le_previous_level_bt;
122 static Button* le_move_right_bt;
123 static Button* le_move_left_bt;
124 static Button* le_rubber_bt;
125 static Button* le_select_mode_one_bt;
126 static Button* le_select_mode_two_bt;
127 static Button* le_settings_bt;
128 static Button* le_tilegroup_bt;
129 static Button* le_objects_bt;
130 static ButtonPanel* le_tilemap_panel;
131 static Menu* leveleditor_menu;
132 static Menu* subset_load_menu;
133 static Menu* subset_new_menu;
134 static Menu* subset_settings_menu;
135 static Menu* level_settings_menu;
136 static Menu* select_tilegroup_menu;
137 static Menu* select_objects_menu;
138 static Timer select_tilegroup_menu_effect;
139 static Timer select_objects_menu_effect;
140 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
141 static ButtonPanelMap tilegroups_map;
142 static ButtonPanelMap objects_map;
143 static std::string cur_tilegroup;
144 static std::string cur_objects;
145
146 static square selection;
147 static int le_selection_mode;
148 static SDL_Event event;
149 TileMapType active_tm;
150
151 int leveleditor(char* filename)
152 {
153   int last_time, now_time, i;
154
155   le_level = 1;
156
157   if(le_init() != 0)
158     return 1;
159
160   /* Clear screen: */
161
162   clearscreen(0, 0, 0);
163   updatescreen();
164
165   music_manager->halt_music();
166
167   while (SDL_PollEvent(&event))
168   {}
169
170   if(filename != NULL)
171     if(le_load_level(filename))
172       return 1;
173
174   while(true)
175   {
176     last_time = SDL_GetTicks();
177     le_frame++;
178
179     le_checkevents();
180
181     if(Menu::current() == select_tilegroup_menu)
182     {
183       if(select_tilegroup_menu_effect.check())
184       {
185         select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
186                                        66,-0.5,0.5);
187       }
188       else
189         select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
190     }
191     else if(Menu::current() == select_objects_menu)
192     {
193       if(select_objects_menu_effect.check())
194       {
195         select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
196       }
197       else
198         select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
199     }
200
201     if(le_world != NULL)
202     {
203       /* making events results to be in order */
204       if(pos_x < 0)
205         pos_x = 0;
206       if(pos_x > (le_world->get_level()->width * 32) - screen->w)
207         pos_x = (le_world->get_level()->width * 32) - screen->w;
208
209       /* draw the level */
210       le_drawlevel();
211     }
212     else
213       clearscreen(0, 0, 0);
214
215     /* draw editor interface */
216     le_drawinterface();
217
218     Menu* menu = Menu::current();
219     if(menu)
220     {
221       menu->draw();
222       menu->action();
223
224       if(menu == leveleditor_menu)
225       {
226         switch (leveleditor_menu->check())
227         {
228         case MNID_RETURNLEVELEDITOR:
229           Menu::set_current(0);
230           break;
231         case MNID_SUBSETSETTINGS:
232           update_subset_settings_menu();
233           break;
234         case MNID_QUITLEVELEDITOR:
235           done = 1;
236           break;
237         }
238       }
239       else if(menu == level_settings_menu)
240       {
241         switch (level_settings_menu->check())
242         {
243         case MNID_APPLY:
244           apply_level_settings_menu();
245           Menu::set_current(NULL);
246           break;
247
248         default:
249           //show_menu = true;
250           break;
251         }
252       }
253       else if(menu == select_tilegroup_menu)
254       {
255         int it = -1;
256         switch (it = select_tilegroup_menu->check())
257         {
258         default:
259           if(it >= 0)
260           {
261             cur_tilegroup
262             = select_tilegroup_menu->get_item_by_id(it).text;
263             Menu::set_current(0);
264             cur_objects = "";
265
266           }
267           break;
268         }
269       }
270       else if(menu == select_objects_menu)
271       {
272         int it = -1;
273         switch (it = select_objects_menu->check())
274         {
275         default:
276           if(it >= 0)
277           {
278             cur_objects = select_objects_menu->get_item_by_id(it).text;
279             cur_tilegroup = "";
280
281             Menu::set_current(0);
282           }
283           break;
284         }
285       }
286       else if(menu == subset_load_menu)
287       {
288         switch (i = subset_load_menu->check())
289         {
290         case 0:
291           break;
292         default:
293           if(i >= 1)
294           {
295             if(le_load_level(level_subsets.item[i-1]))
296               return 1;
297           }
298           break;
299         }
300       }
301       else if(menu == subset_new_menu)
302       {
303         if(subset_new_menu->item[2].input[0] == '\0')
304           subset_new_menu->item[3].kind = MN_DEACTIVE;
305         else
306         {
307           subset_new_menu->item[3].kind = MN_ACTION;
308
309           switch (i = subset_new_menu->check())
310           {
311           case MNID_CREATESUBSET:
312             LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
313             le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
314             leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
315             delete le_world;
316             le_world = new World(le_level_subset->name,1);
317             subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
318
319             Menu::set_current(subset_settings_menu);
320             break;
321           }
322         }
323       }
324       else if(menu == subset_settings_menu)
325       {
326         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  )
327           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
328         else
329           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
330
331         switch (i = subset_settings_menu->check())
332         {
333         case MNID_SUBSETSAVECHANGES:
334           save_subset_settings_menu();
335           Menu::set_current(leveleditor_menu);
336           break;
337         }
338       }
339     }
340
341     mouse_cursor->draw();
342
343     if(done)
344     {
345       le_quit();
346       return 0;
347     }
348
349     ++global_frame_counter;
350
351     SDL_Delay(25);
352     now_time = SDL_GetTicks();
353     if (now_time < last_time + FPS)
354       SDL_Delay(last_time + FPS - now_time);    /* delay some time */
355
356     flipscreen();
357   }
358
359   return done;
360 }
361
362 int le_load_level(char *filename)
363 {
364   le_level_subset->load(filename);
365   leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
366   le_level = 1;
367   delete le_world;
368   le_world = new World(filename,le_level);
369   
370   //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
371
372   Menu::set_current(NULL);
373
374   return 0;
375 }
376
377 void le_init_menus()
378 {
379   int i;
380   
381   leveleditor_menu = new Menu();
382   subset_load_menu = new Menu();
383   subset_new_menu  = new Menu();
384   subset_settings_menu = new Menu();
385   level_settings_menu  = new Menu();
386   select_tilegroup_menu  = new Menu();
387   select_objects_menu = new Menu();
388
389   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
390   leveleditor_menu->additem(MN_HL,"",0,0);
391   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
392   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
393   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
394   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
395   leveleditor_menu->additem(MN_HL,"",0,0);
396   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
397
398   Menu::set_current(leveleditor_menu);
399
400   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
401   subset_load_menu->additem(MN_HL, "", 0, 0);
402
403   for(i = 0; i < level_subsets.num_items; ++i)
404   {
405     subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
406   }
407   subset_load_menu->additem(MN_HL,"",0,0);
408   subset_load_menu->additem(MN_BACK,"Back",0,0);
409
410   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
411   subset_new_menu->additem(MN_HL,"",0,0);
412   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
413   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
414   subset_new_menu->additem(MN_HL,"",0,0);
415   subset_new_menu->additem(MN_BACK,"Back",0,0);
416
417   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
418   subset_settings_menu->additem(MN_HL,"",0,0);
419   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
420   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
421   subset_settings_menu->additem(MN_HL,"",0,0);
422   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
423   subset_settings_menu->additem(MN_HL,"",0,0);
424   subset_settings_menu->additem(MN_BACK,"Back",0,0);
425
426   level_settings_menu->arrange_left = true;
427   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
428   level_settings_menu->additem(MN_HL,"",0,0);
429   level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
430   level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
431   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
432   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
433   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
434   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
435   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
436   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
437   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
438   level_settings_menu->additem(MN_NUMFIELD,    "Top Red    ",0,0,MNID_TopRed);
439   level_settings_menu->additem(MN_NUMFIELD,    "Top Green  ",0,0,MNID_TopGreen);
440   level_settings_menu->additem(MN_NUMFIELD,    "Top Blue   ",0,0,MNID_TopBlue);
441   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red ",0,0,MNID_BottomRed);
442   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
443   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue",0,0,MNID_BottomBlue);
444   level_settings_menu->additem(MN_HL,"",0,0);
445   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
446
447   select_tilegroup_menu->arrange_left = true;
448   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
449   select_tilegroup_menu->additem(MN_HL,"",0,0);
450   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
451   int tileid = 1;
452   for(std::set<TileGroup>::iterator it = tilegroups->begin();
453       it != tilegroups->end(); ++it )
454   {
455     select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
456     tileid++;
457     tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
458     i = 0;
459     
460     for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
461         sit != (*it).tiles.end(); ++sit, ++i)
462     {
463       std::string imagefile = "/images/tilesets/" ;
464       bool only_editor_image = false;
465       if(!TileManager::instance()->get(*sit)->filenames.empty())
466       {
467         imagefile += TileManager::instance()->get(*sit)->filenames[0];
468       }
469       else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
470       {
471         imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
472         only_editor_image = true;
473       }
474       else
475       {
476         imagefile += "notile.png";
477       }
478       Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
479                                   0, 0, 32, 32);
480       if(!only_editor_image)
481         if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
482         {
483           imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
484           button->add_icon(imagefile,32,32);
485         }
486       tilegroups_map[it->name]->additem(button, *sit);
487     }
488   }
489   select_tilegroup_menu->additem(MN_HL,"",0,0);
490
491   select_objects_menu->arrange_left = true;
492   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
493   select_objects_menu->additem(MN_HL,"",0,0);
494   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
495   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
496
497   for(int i = 0; i < NUM_BadGuyKinds; ++i)
498   {
499     BadGuy bad_tmp(0,0,BadGuyKind(i),false);
500     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
501     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));
502   }
503
504   select_objects_menu->additem(MN_HL,"",0,0);
505
506 }
507
508 int le_init()
509 {
510
511
512   level_subsets = dsubdirs("/levels", "info");
513   le_level_subset = new LevelSubset;
514
515   le_world = NULL;
516   
517   active_tm = TM_IA;
518   le_show_grid = true;
519   scroll_x = 0;
520
521   fire = DOWN;
522   done = 0;
523   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
524   le_level_changed = false;
525
526   le_mouse_pressed[LEFT] = false;
527   le_mouse_pressed[RIGHT] = false;
528
529   le_mouse_clicked[LEFT] = false;
530   le_mouse_clicked[RIGHT] = false;
531
532   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
533
534   select_tilegroup_menu_effect.init(false);
535   select_objects_menu_effect.init(false);
536
537   /* Load buttons */
538   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
539   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
540   le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
541   le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
542   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
543   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
544   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
545   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
546   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
547   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
548   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
549   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
550   le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
551
552   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
553   le_tilemap_panel->set_button_size(32,10);
554   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
555   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0),TM_IA);
556   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
557   le_tilemap_panel->highlight_last(true);
558
559   le_current.Init();
560
561   le_init_menus();
562
563   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
564
565
566   return 0;
567 }
568
569 void update_level_settings_menu()
570 {
571   char str[80];
572   int i;
573
574   level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_world->get_level()->name.c_str());
575   level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_world->get_level()->author.c_str());
576
577   string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
578   string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
579   string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
580   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
581   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
582   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
583
584   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_world->get_level()->song_title.c_str())) != -1)
585     level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
586   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_world->get_level()->bkgd_image.c_str())) != -1)
587     level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
588   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_world->get_level()->particle_system.c_str())) != -1)
589     level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
590
591   sprintf(str,"%d",le_world->get_level()->width);
592   level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
593   sprintf(str,"%d",le_world->get_level()->time_left);
594   level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
595   sprintf(str,"%2.0f",le_world->get_level()->gravity);
596   level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
597   sprintf(str,"%d",le_world->get_level()->bkgd_speed);
598   level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
599   sprintf(str,"%d",le_world->get_level()->bkgd_top.red);
600   level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
601   sprintf(str,"%d",le_world->get_level()->bkgd_top.green);
602   level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
603   sprintf(str,"%d",le_world->get_level()->bkgd_top.blue);
604   level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
605   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.red);
606   level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
607   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.green);
608   level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
609   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.blue);
610   level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
611 }
612
613 void update_subset_settings_menu()
614 {
615   subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
616   subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
617 }
618
619 void apply_level_settings_menu()
620 {
621   int i;
622   i = false;
623
624   le_world->get_level()->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
625   le_world->get_level()->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
626
627   if(le_world->get_level()->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
628   {
629     le_world->get_level()->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
630     i = true;
631   }
632
633   if(le_world->get_level()->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
634   {
635     le_world->get_level()->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
636   }
637
638   if(i)
639   {
640     le_world->get_level()->load_gfx();
641   }
642
643   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
644
645   le_world->get_level()->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
646   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
647   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
648   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
649   le_world->get_level()->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
650   le_world->get_level()->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
651   le_world->get_level()->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
652   le_world->get_level()->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
653   le_world->get_level()->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
654   le_world->get_level()->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
655 }
656
657 void save_subset_settings_menu()
658 {
659   le_level_subset->title = subset_settings_menu->item[2].input;
660   le_level_subset->description = subset_settings_menu->item[3].input;
661   le_level_subset->save();
662 }
663
664 void le_goto_level(int levelnb)
665 {
666   delete le_world;
667   le_world = new World(le_level_subset->name, levelnb);
668 }
669
670 void le_quit(void)
671 {
672   /*if(level_changed == true)
673     if(askforsaving() == CANCEL)
674       return;*/ //FIXME
675
676   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
677
678   delete le_selection;
679   delete leveleditor_menu;
680   delete subset_load_menu;
681   delete subset_new_menu;
682   delete subset_settings_menu;
683   delete level_settings_menu;
684   delete select_tilegroup_menu;
685   delete select_objects_menu;
686   delete le_save_level_bt;
687   delete le_exit_bt;
688   delete le_test_level_bt;
689   delete le_next_level_bt;
690   delete le_previous_level_bt;
691   delete le_move_right_bt;
692   delete le_move_left_bt;
693   delete le_rubber_bt;
694   delete le_select_mode_one_bt;
695   delete le_select_mode_two_bt;
696   delete le_settings_bt;
697   delete le_tilegroup_bt;
698   delete le_objects_bt;
699   delete le_tilemap_panel;
700
701   delete le_level_subset;
702   le_level_subset = 0;
703
704   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
705       i != tilegroups_map.end(); ++i)
706   {
707     delete i->second;
708   }
709   for(ButtonPanelMap::iterator i = objects_map.begin();
710       i != objects_map.end(); ++i)
711   {
712     delete i->second;
713   }
714 }
715
716 void le_drawminimap()
717 {
718   if(le_world == NULL)
719     return;
720
721   int mini_tile_width;
722   if(screen->w - 64 > le_world->get_level()->width * 4)
723     mini_tile_width = 4;
724   else if(screen->w - 64 > le_world->get_level()->width * 2)
725     mini_tile_width = 2;
726   else
727     mini_tile_width = 1;
728   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
729
730   for (int y = 0; y < 15; ++y)
731     for (int x = 0; x < le_world->get_level()->width; ++x)
732     {
733
734       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
735
736       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
737
738       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
739
740     }
741
742   fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, 15*4, 200, 200, 200, 128);
743
744   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
745   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, 15*4, 200, 200, 200, 200);
746   fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, 15*4, 200, 200, 200, 200);
747   fillrect(left_offset + (pos_x/32)*mini_tile_width, 15*4-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
748
749 }
750
751 void le_drawinterface()
752 {
753   int x,y;
754   char str[80];
755
756   if(le_world != NULL)
757   {
758     /* draw a grid (if selected) */
759     if(le_show_grid)
760     {
761       for(x = 0; x < 19; x++)
762         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
763       for(y = 0; y < 15; y++)
764         fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
765     }
766   }
767
768   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
769     le_drawminimap();
770
771   if(le_selection_mode == CURSOR)
772     if(le_current.IsTile())
773       le_selection->draw( cursor_x - pos_x, cursor_y);
774     else
775       le_selection->draw( cursor_x, cursor_y);
776   else if(le_selection_mode == SQUARE)
777   {
778     int w, h;
779     le_highlight_selection();
780     /* draw current selection */
781     w = selection.x2 - selection.x1;
782     h = selection.y2 - selection.y1;
783     fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
784     fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
785     fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
786     fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
787   }
788
789
790   /* draw button bar */
791   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
792
793   if(le_current.IsTile())
794   {
795     Tile::draw(19 * 32, 14 * 32, le_current.tile);
796     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
797       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
798   }
799   if(le_current.IsObject())
800   {
801     le_current.obj->draw_on_screen(19 * 32, 14 * 32);
802     le_current.obj->draw_on_screen(cursor_x,cursor_y);
803   }
804
805   if(le_world != NULL)
806   {
807     le_save_level_bt->draw();
808     le_exit_bt->draw();
809     le_test_level_bt->draw();
810     le_next_level_bt->draw();
811     le_previous_level_bt->draw();
812     le_rubber_bt->draw();
813     if(le_selection_mode == SQUARE)
814       le_select_mode_one_bt->draw();
815     else if(le_selection_mode == CURSOR)
816       le_select_mode_two_bt->draw();
817     le_settings_bt->draw();
818     le_move_right_bt->draw();
819     le_move_left_bt->draw();
820     le_tilegroup_bt->draw();
821     le_objects_bt->draw();
822     if(!cur_tilegroup.empty())
823       tilegroups_map[cur_tilegroup]->draw();
824     else if(!cur_objects.empty())
825     {
826       objects_map[cur_objects]->draw();
827     }
828
829     le_tilemap_panel->draw();
830
831     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
832     white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
833
834     white_small_text->draw("F1 for Help", 10, 430, 1);
835   }
836   else
837   {
838     if(!Menu::current())
839       white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
840     else
841       white_small_text->draw("No Level Subset loaded", 10, 430, 1);
842   }
843
844 }
845
846 void le_drawlevel()
847 {
848   unsigned int y,x,s;
849   Uint8 a;
850
851   /* Draw the real background */
852   if(le_world->get_level()->bkgd_image[0] != '\0')
853   {
854     s = (int)((float)pos_x * ((float)le_world->get_level()->bkgd_speed/60.)) % screen->w;
855     le_world->get_level()->img_bkgd->draw_part(s,0,0,0,
856                                           le_world->get_level()->img_bkgd->w - s - 32, le_world->get_level()->img_bkgd->h);
857     le_world->get_level()->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
858                                           le_world->get_level()->img_bkgd->h);
859   }
860   else
861   {
862     drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
863   }
864
865   if(le_current.IsTile())
866   {
867     Tile::draw(cursor_x-pos_x, cursor_y,le_current.tile,128);
868     if(!TileManager::instance()->get(le_current.tile)->images.empty())
869       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);
870   }
871   if(le_current.IsObject())
872   {
873     le_current.obj->move_to(cursor_x, cursor_y);
874   }
875
876   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
877
878   for (y = 0; y < 15; ++y)
879     for (x = 0; x < 20; ++x)
880     {
881
882       if(active_tm == TM_BG)
883         a = 255;
884       else
885         a = 128;
886
887       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->bg_tiles[y][x + (int)(pos_x / 32)],a);
888
889       if(active_tm == TM_IA)
890         a = 255;
891       else
892         a = 128;
893
894       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)],a);
895
896       if(active_tm == TM_FG)
897         a = 255;
898       else
899         a = 128;
900
901       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->fg_tiles[y][x + (int)(pos_x / 32)],a);
902
903       /* draw whats inside stuff when cursor is selecting those */
904       /* (draw them all the time - is this the right behaviour?) */
905       if(TileManager::instance()->get(le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
906         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);
907
908     }
909
910   /* Draw the Bad guys: */
911   for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
912   {
913     /* to support frames: img_bsod_left[(frame / 5) % 4] */
914
915     scroll_x = pos_x;
916     (*it)->draw();
917   }
918
919
920   /* Draw the player: */
921   /* for now, the position is fixed at (100, 240) */
922   largetux.walk_right->draw( 100 - pos_x, 240);
923 }
924
925 void le_change_object_properties(GameObject *pobj)
926 {
927 Menu* object_properties_menu = new Menu();
928
929   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
930   object_properties_menu->additem(MN_HL,"",0,0);
931   /*object_properties_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
932   object_properties_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
933   object_properties_menu->additem(MN_HL,"",0,0);
934   object_properties_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);*/
935   object_properties_menu->additem(MN_HL,"",0,0);
936   object_properties_menu->additem(MN_BACK,"Apply",0,0);
937
938 delete object_properties_menu;
939 }
940
941
942 void le_checkevents()
943 {
944   SDLKey key;
945   SDLMod keymod;
946   Button* pbutton;
947   int x,y;
948
949   keymod = SDL_GetModState();
950
951   while(SDL_PollEvent(&event))
952   {
953     if (Menu::current())
954     {
955       Menu::current()->event(event);
956     }
957     else
958     {
959       mouse_cursor->set_state(MC_NORMAL);
960
961       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
962       if(event.type == SDL_KEYDOWN
963           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
964               && (event.motion.x > 0
965                   && event.motion.x < screen->w - 64 &&
966                   event.motion.y > 0 && event.motion.y < screen->h)))
967       {
968         switch(event.type)
969         {
970         case SDL_KEYDOWN:       // key pressed
971           key = event.key.keysym.sym;
972           switch(key)
973           {
974           case SDLK_ESCAPE:
975             Menu::set_current(leveleditor_menu);
976           case SDLK_LEFT:
977             if(fire == DOWN)
978               cursor_x -= KEY_CURSOR_SPEED;
979             else
980               cursor_x -= KEY_CURSOR_FASTSPEED;
981
982             if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
983               pos_x = cursor_x - MOUSE_LEFT_MARGIN;
984
985             break;
986           case SDLK_RIGHT:
987             if(fire == DOWN)
988               cursor_x += KEY_CURSOR_SPEED;
989             else
990               cursor_x += KEY_CURSOR_FASTSPEED;
991
992             if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
993               pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
994
995             break;
996           case SDLK_UP:
997             if(fire == DOWN)
998               cursor_y -= KEY_CURSOR_SPEED;
999             else
1000               cursor_y -= KEY_CURSOR_FASTSPEED;
1001
1002             if(cursor_y < 0)
1003               cursor_y = 0;
1004             break;
1005           case SDLK_DOWN:
1006             if(fire == DOWN)
1007               cursor_y += KEY_CURSOR_SPEED;
1008             else
1009               cursor_y += KEY_CURSOR_FASTSPEED;
1010
1011             if(cursor_y > screen->h-32)
1012               cursor_y = screen->h-32;
1013             break;
1014           case SDLK_LCTRL:
1015             fire =UP;
1016             break;
1017           case SDLK_F1:
1018             le_showhelp();
1019             break;
1020           case SDLK_HOME:
1021             cursor_x = 0;
1022             pos_x = cursor_x;
1023             break;
1024           case SDLK_END:
1025             cursor_x = (le_world->get_level()->width * 32) - 32;
1026             pos_x = cursor_x;
1027             break;
1028           case SDLK_F9:
1029             le_show_grid = !le_show_grid;
1030             break;
1031           default:
1032             break;
1033           }
1034           break;
1035         case SDL_KEYUP: /* key released */
1036           switch(event.key.keysym.sym)
1037           {
1038           case SDLK_LCTRL:
1039             fire = DOWN;
1040             break;
1041           default:
1042             break;
1043           }
1044           break;
1045         case SDL_MOUSEBUTTONDOWN:
1046           if(event.button.button == SDL_BUTTON_LEFT)
1047           {
1048             le_mouse_pressed[LEFT] = true;
1049
1050             selection.x1 = event.motion.x + pos_x;
1051             selection.y1 = event.motion.y;
1052             selection.x2 = event.motion.x + pos_x;
1053             selection.y2 = event.motion.y;
1054           }
1055           else if(event.button.button == SDL_BUTTON_RIGHT)
1056           {
1057             le_mouse_pressed[RIGHT] = true;
1058           }
1059           break;
1060         case SDL_MOUSEBUTTONUP:
1061           if(event.button.button == SDL_BUTTON_LEFT)
1062           {
1063             le_mouse_pressed[LEFT] = false;
1064             le_mouse_clicked[LEFT] = true;
1065           }
1066           else if(event.button.button == SDL_BUTTON_RIGHT)
1067           {
1068             le_mouse_pressed[RIGHT] = false;
1069             le_mouse_clicked[RIGHT] = true;
1070           }
1071           break;
1072         case SDL_MOUSEMOTION:
1073
1074           if(!Menu::current())
1075           {
1076             x = event.motion.x;
1077             y = event.motion.y;
1078
1079             if(le_current.IsTile())
1080             {
1081               cursor_x = ((int)(pos_x + x) / 32) * 32;
1082               cursor_y = ((int) y / 32) * 32;
1083             }
1084             else
1085             {
1086               cursor_x = x;
1087               cursor_y = y;
1088             }
1089
1090             if(le_mouse_pressed[LEFT])
1091             {
1092               selection.x2 = x + pos_x;
1093               selection.y2 = y;
1094             }
1095
1096             if(le_mouse_pressed[RIGHT])
1097             {
1098               pos_x += -1 * event.motion.xrel;
1099             }
1100           }
1101           break;
1102         case SDL_QUIT:  // window closed
1103           done = 1;
1104           break;
1105         default:
1106           break;
1107         }
1108       }
1109     }
1110
1111     if(le_world != NULL)
1112     {
1113       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 &&
1114           event.motion.y > 0 && event.motion.y < screen->h)))
1115       {
1116         le_mouse_pressed[LEFT] = false;
1117         le_mouse_pressed[RIGHT] = false;
1118
1119         if(!Menu::current())
1120         {
1121           /* Check for button events */
1122           le_test_level_bt->event(event);
1123           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1124             le_testlevel();
1125           le_save_level_bt->event(event);
1126           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1127             le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
1128           le_exit_bt->event(event);
1129           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1130           {
1131             Menu::set_current(leveleditor_menu);
1132           }
1133           le_next_level_bt->event(event);
1134           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1135           {
1136             if(le_level < le_level_subset->levels)
1137             {
1138               le_goto_level(++le_level);
1139             }
1140             else
1141             {
1142               Level new_lev;
1143               char str[1024];
1144               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1145               if(confirm_dialog(str))
1146               {
1147                 new_lev.init_defaults();
1148                 new_lev.save(le_level_subset->name.c_str(),++le_level);
1149                 le_level_subset->levels = le_level;
1150                 le_goto_level(le_level);
1151               }
1152             }
1153           }
1154           le_previous_level_bt->event(event);
1155           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1156           {
1157             if(le_level > 1)
1158               le_goto_level(--le_level);
1159           }
1160           le_rubber_bt->event(event);
1161           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1162             le_current.Tile(0);
1163
1164           if(le_selection_mode == SQUARE)
1165           {
1166             le_select_mode_one_bt->event(event);
1167             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1168               le_selection_mode = CURSOR;
1169           }
1170           else
1171           {
1172             le_select_mode_two_bt->event(event);
1173             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1174               le_selection_mode = SQUARE;
1175           }
1176           ButtonPanelMap::iterator it;
1177           le_tilegroup_bt->event(event);
1178           switch (le_tilegroup_bt->get_state())
1179           {
1180           case BUTTON_CLICKED:
1181             Menu::set_current(select_tilegroup_menu);
1182             select_tilegroup_menu_effect.start(200);
1183             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1184             break;
1185           case BUTTON_WHEELUP:
1186             if(cur_tilegroup.empty())
1187             {
1188               cur_tilegroup = tilegroups_map.begin()->first;
1189             }
1190             else
1191             {
1192               it = tilegroups_map.find(cur_tilegroup);
1193               if((++it) == tilegroups_map.end())
1194               {
1195                 cur_tilegroup = tilegroups_map.begin()->first;
1196               }
1197               else
1198               {
1199                 cur_tilegroup = (*it).first;
1200               }
1201             }
1202
1203             cur_objects = "";
1204             break;
1205           case BUTTON_WHEELDOWN:
1206             it = tilegroups_map.find(cur_tilegroup);
1207             if(it == tilegroups_map.begin())
1208             {
1209               cur_tilegroup = tilegroups_map.rbegin()->first;
1210               cur_objects = "";
1211               break;
1212             }
1213             if(--it != --tilegroups_map.begin())
1214               cur_tilegroup = (*it).first;
1215             else
1216               cur_tilegroup = tilegroups_map.rbegin()->first;
1217
1218             cur_objects = "";
1219             break;
1220           default:
1221             break;
1222           }
1223
1224           le_objects_bt->event(event);
1225           switch (le_objects_bt->get_state())
1226           {
1227           case BUTTON_CLICKED:
1228             Menu::set_current(select_objects_menu);
1229             select_objects_menu_effect.start(200);
1230             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1231             break;
1232           case BUTTON_WHEELUP:
1233             it = objects_map.find(cur_objects);
1234             if(it == objects_map.end())
1235             {
1236               cur_objects = objects_map.begin()->first;
1237               cur_tilegroup = "";
1238               break;
1239             }
1240             if(++it != objects_map.end())
1241               cur_objects = (*it).first;
1242             else
1243               cur_objects = objects_map.begin()->first;
1244
1245             cur_tilegroup = "";
1246             break;
1247           case BUTTON_WHEELDOWN:
1248             it = objects_map.find(cur_objects);
1249             if(it == objects_map.begin())
1250             {
1251               cur_objects = objects_map.rbegin()->first;
1252               cur_tilegroup = "";
1253               break;
1254             }
1255             if(--it != --objects_map.begin())
1256               cur_objects = (*it).first;
1257             else
1258               cur_objects = objects_map.rbegin()->first;
1259
1260             cur_tilegroup = "";
1261             break;
1262             break;
1263           default:
1264             break;
1265           }
1266
1267           le_settings_bt->event(event);
1268           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1269           {
1270             update_level_settings_menu();
1271             Menu::set_current(level_settings_menu);
1272           }
1273           if(!cur_tilegroup.empty())
1274           {
1275             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1276             {
1277               if(pbutton->get_state() == BUTTON_CLICKED)
1278               {
1279                 le_current.Tile(pbutton->get_tag());
1280               }
1281             }
1282           }
1283           else if(!cur_objects.empty())
1284           {
1285             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1286             {
1287               if(pbutton->get_state() == BUTTON_CLICKED)
1288               {
1289                 le_current.Object(pbutton->get_game_object());
1290               }
1291             }
1292           }
1293
1294           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1295           {
1296             if(pbutton->get_state() == BUTTON_CLICKED)
1297             {
1298               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1299             }
1300           }
1301         }
1302         else
1303         {
1304           le_settings_bt->event(event);
1305           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1306           {
1307             Menu::set_current(0);
1308           }
1309           le_tilegroup_bt->event(event);
1310           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1311           {
1312             Menu::set_current(0);
1313           }
1314         }
1315       }
1316
1317       if(!Menu::current() && !show_minimap)
1318       {
1319         if(le_mouse_pressed[LEFT])
1320         {
1321           if(le_current.IsTile())
1322             le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1323         }
1324         else if(le_mouse_clicked[LEFT])
1325         {
1326           if(le_current.IsObject())
1327           {
1328             std::string type = le_current.obj->type();
1329             if(type == "BadGuy")
1330             {
1331               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1332
1333               le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1334               le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1335             }
1336           }
1337           le_mouse_clicked[LEFT] = false;
1338         }
1339       }
1340     }
1341   }
1342   if(!Menu::current())
1343   {
1344     show_minimap = false;
1345
1346     le_move_left_bt->event(event);
1347     le_move_right_bt->event(event);
1348     switch(le_move_left_bt->get_state())
1349     {
1350     case BUTTON_PRESSED:
1351       pos_x -= 192;
1352       show_minimap = true;
1353       break;
1354     case BUTTON_HOVER:
1355       pos_x -= 32;
1356       show_minimap = true;
1357       break;
1358     case BUTTON_CLICKED:
1359       show_minimap = true;
1360       break;
1361     default:
1362       break;
1363     }
1364
1365     switch(le_move_right_bt->get_state())
1366     {
1367     case BUTTON_PRESSED:
1368       pos_x += 192;
1369       show_minimap = true;
1370       break;
1371     case BUTTON_HOVER:
1372       pos_x += 32;
1373       show_minimap = true;
1374       break;
1375     case BUTTON_CLICKED:
1376       show_minimap = true;
1377       break;
1378     default:
1379       break;
1380     }
1381
1382   }
1383
1384 }
1385
1386 void le_highlight_selection()
1387 {
1388   int x1, x2, y1, y2;
1389
1390   if(selection.x1 < selection.x2)
1391   {
1392     x1 = selection.x1;
1393     x2 = selection.x2;
1394   }
1395   else
1396   {
1397     x1 = selection.x2;
1398     x2 = selection.x1;
1399   }
1400   if(selection.y1 < selection.y2)
1401   {
1402     y1 = selection.y1;
1403     y2 = selection.y2;
1404   }
1405   else
1406   {
1407     y1 = selection.y2;
1408     y2 = selection.y1;
1409   }
1410
1411   x1 /= 32;
1412   x2 /= 32;
1413   y1 /= 32;
1414   y2 /= 32;
1415
1416   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1417 }
1418
1419 void le_change(float x, float y, int tm, unsigned int c)
1420 {
1421   if(le_world != NULL)
1422   {
1423     int xx,yy;
1424     int x1, x2, y1, y2;
1425     unsigned int i;
1426
1427     /*  level_changed = true; */
1428
1429     switch(le_selection_mode)
1430     {
1431     case CURSOR:
1432       le_world->get_level()->change(x,y,tm,c);
1433
1434       base_type cursor_base;
1435       cursor_base.x = x;
1436       cursor_base.y = y;
1437       cursor_base.width = 32;
1438       cursor_base.height = 32;
1439
1440       /* if there is a bad guy over there, remove it */
1441       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
1442         if(rectcollision(cursor_base,(*it)->base))
1443         {
1444           le_world->bad_guys.erase(le_world->bad_guys.begin(),it);
1445           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1446         }
1447
1448       break;
1449     case SQUARE:
1450       if(selection.x1 < selection.x2)
1451       {
1452         x1 = selection.x1;
1453         x2 = selection.x2;
1454       }
1455       else
1456       {
1457         x1 = selection.x2;
1458         x2 = selection.x1;
1459       }
1460       if(selection.y1 < selection.y2)
1461       {
1462         y1 = selection.y1;
1463         y2 = selection.y2;
1464       }
1465       else
1466       {
1467         y1 = selection.y2;
1468         y2 = selection.y1;
1469       }
1470
1471       x1 /= 32;
1472       x2 /= 32;
1473       y1 /= 32;
1474       y2 /= 32;
1475
1476       /* if there is a bad guy over there, remove it */
1477       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
1478           it != le_world->bad_guys.end(); /* will be at end of loop */)
1479       {
1480         if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
1481             && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
1482         {
1483           it = le_world->bad_guys.erase(it);
1484           continue;
1485         }
1486         else
1487         {
1488           ++it;
1489         }
1490       }
1491
1492       for(xx = x1; xx <= x2; xx++)
1493         for(yy = y1; yy <= y2; yy++)
1494         {
1495           le_world->get_level()->change(xx*32, yy*32, tm, c);
1496
1497         }
1498       break;
1499     default:
1500       break;
1501     }
1502   }
1503 }
1504
1505 void le_testlevel()
1506 {
1507   le_world->get_level()->save("test", le_level);
1508
1509   GameSession session("test",le_level, ST_GL_TEST);
1510   session.run();
1511   player_status.reset();
1512
1513   music_manager->halt_music();
1514
1515   Menu::set_current(NULL);
1516   /*delete le_world.arrays_free();
1517   le_current_level->load_gfx();
1518   le_world.activate_bad_guys();*/
1519 }
1520
1521 void le_showhelp()
1522 {
1523   SDL_Event event;
1524   unsigned int i, done_;
1525   char *text[] = {
1526                    "  - This is SuperTux's built-in level editor -",
1527                    "It has been designed to be light and easy to use from the start.",
1528                    "",
1529                    "When you first load the level editor you are given a menu where you",
1530                    "can load level subsets, create a new level subset, edit the current",
1531                    "subset's settings, or simply quit the editor. You can access this menu",
1532                    "from the level editor at any time by pressing the escape key.",
1533                    "",
1534                    "To your right is your button bar. The center of this contains many",
1535                    "tiles you can use to make your level. To select a tile, click on it",
1536                    "with your left mouse button; your selection will be shown in the",
1537                    "bottom right corner of the button box. Click anywhere on your level",
1538                    "with the left mouse button to place that tile down. If you right click",
1539                    "a tile in the button bar, you can find out what its keyboard shortcut",
1540                    "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1541                    "background, and enemy tiles. The eraser lets you remove tiles.",
1542                    "The left and right arrow keys scroll back and forth through your level.",
1543                    "The button with the wrench and screwdriver, lets you change the",
1544                    "settings of your level, including how long it is or what music it will",
1545                    "play. When you are ready to give your level a test, click on the little",
1546                    "running Tux. If you like the changes you have made to your level,",
1547                    "press the red save key to keep them.",
1548                    "To change which level in your subset you are editing, press the white",
1549                    "up and down arrow keys at the top of the button box.",
1550                    "",
1551                    "Have fun making levels! If you make some good ones, send them to us on",
1552                    "the SuperTux mailing list!",
1553                    "- SuperTux team"
1554                  };
1555
1556
1557   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1558
1559   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1560     white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1561
1562   gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1563
1564   flipscreen();
1565
1566   done_ = 0;
1567
1568   while(done_ == 0)
1569   {
1570     done_ = wait_for_event(event);
1571     SDL_Delay(50);
1572   }
1573 }