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