- made supertux g++295 friendly
[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 = "";
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 = "";
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::set<TileGroup>* tilegroups = TileManager::tilegroups();
505   int tileid = 1;
506   for(std::set<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>::const_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             if(cur_tilegroup.empty())
1240             {
1241               cur_tilegroup = tilegroups_map.begin()->first;
1242             }
1243             else
1244             {
1245               it = tilegroups_map.find(cur_tilegroup);
1246               if((++it) == tilegroups_map.end())
1247               {
1248                 cur_tilegroup = tilegroups_map.begin()->first;
1249               }
1250               else
1251               {
1252                 cur_tilegroup = (*it).first;
1253               }
1254             }
1255
1256             cur_objects = "";
1257             break;
1258           case BUTTON_WHEELDOWN:
1259             it = tilegroups_map.find(cur_tilegroup);
1260             if(it == tilegroups_map.begin())
1261             {
1262               cur_tilegroup = tilegroups_map.rbegin()->first;
1263               cur_objects = "";
1264               break;
1265             }
1266             if(--it != --tilegroups_map.begin())
1267               cur_tilegroup = (*it).first;
1268             else
1269               cur_tilegroup = tilegroups_map.rbegin()->first;
1270
1271             cur_objects = "";
1272             break;
1273           default:
1274             break;
1275           }
1276
1277           le_objects_bt->event(event);
1278           switch (le_objects_bt->get_state())
1279           {
1280           case BUTTON_CLICKED:
1281             Menu::set_current(select_objects_menu);
1282             select_objects_menu_effect.start(200);
1283             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1284             break;
1285           case BUTTON_WHEELUP:
1286             it = objects_map.find(cur_objects);
1287             if(it == objects_map.end())
1288             {
1289               cur_objects = objects_map.begin()->first;
1290               cur_tilegroup = "";
1291               break;
1292             }
1293             if(++it != objects_map.end())
1294               cur_objects = (*it).first;
1295             else
1296               cur_objects = objects_map.begin()->first;
1297
1298             cur_tilegroup = "";
1299             break;
1300           case BUTTON_WHEELDOWN:
1301             it = objects_map.find(cur_objects);
1302             if(it == objects_map.begin())
1303             {
1304               cur_objects = objects_map.rbegin()->first;
1305               cur_tilegroup = "";
1306               break;
1307             }
1308             if(--it != --objects_map.begin())
1309               cur_objects = (*it).first;
1310             else
1311               cur_objects = objects_map.rbegin()->first;
1312
1313             cur_tilegroup = "";
1314             break;
1315             break;
1316           default:
1317             break;
1318           }
1319
1320           le_settings_bt->event(event);
1321           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1322           {
1323             update_level_settings_menu();
1324             Menu::set_current(level_settings_menu);
1325           }
1326           if(!cur_tilegroup.empty())
1327           {
1328             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1329             {
1330               if(pbutton->get_state() == BUTTON_CLICKED)
1331               {
1332                 le_current.Tile(pbutton->get_tag());
1333               }
1334             }
1335           }
1336           else if(!cur_objects.empty())
1337           {
1338             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1339             {
1340               if(pbutton->get_state() == BUTTON_CLICKED)
1341               {
1342                 le_current.Object(pbutton->get_game_object());
1343               }
1344             }
1345           }
1346
1347           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1348           {
1349             if(pbutton->get_state() == BUTTON_CLICKED)
1350             {
1351               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1352             }
1353           }
1354         }
1355         else
1356         {
1357           le_settings_bt->event(event);
1358           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1359           {
1360             Menu::set_current(0);
1361           }
1362           le_tilegroup_bt->event(event);
1363           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1364           {
1365             Menu::set_current(0);
1366           }
1367         }
1368       }
1369
1370       if(!Menu::current() && !show_minimap)
1371       {
1372         if(le_mouse_pressed[LEFT])
1373         {
1374           if(le_current.IsTile())
1375             le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1376         }
1377         else if(le_mouse_clicked[LEFT])
1378         {
1379           if(le_current.IsObject())
1380           {
1381             std::string type = le_current.obj->type();
1382             if(type == "BadGuy")
1383             {
1384               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1385
1386               le_world.bad_guys.push_back(BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1387               le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1388             }
1389           }
1390           le_mouse_clicked[LEFT] = false;
1391         }
1392       }
1393     }
1394   }
1395   if(!Menu::current())
1396   {
1397     show_minimap = false;
1398
1399     le_move_left_bt->event(event);
1400     le_move_right_bt->event(event);
1401     switch(le_move_left_bt->get_state())
1402     {
1403     case BUTTON_PRESSED:
1404       pos_x -= 192;
1405       show_minimap = true;
1406       break;
1407     case BUTTON_HOVER:
1408       pos_x -= 32;
1409       show_minimap = true;
1410       break;
1411     case BUTTON_CLICKED:
1412       show_minimap = true;
1413       break;
1414     default:
1415       break;
1416     }
1417
1418     switch(le_move_right_bt->get_state())
1419     {
1420     case BUTTON_PRESSED:
1421       pos_x += 192;
1422       show_minimap = true;
1423       break;
1424     case BUTTON_HOVER:
1425       pos_x += 32;
1426       show_minimap = true;
1427       break;
1428     case BUTTON_CLICKED:
1429       show_minimap = true;
1430       break;
1431     default:
1432       break;
1433     }
1434
1435   }
1436
1437 }
1438
1439 void le_highlight_selection()
1440 {
1441   int x1, x2, y1, y2;
1442
1443   if(selection.x1 < selection.x2)
1444   {
1445     x1 = selection.x1;
1446     x2 = selection.x2;
1447   }
1448   else
1449   {
1450     x1 = selection.x2;
1451     x2 = selection.x1;
1452   }
1453   if(selection.y1 < selection.y2)
1454   {
1455     y1 = selection.y1;
1456     y2 = selection.y2;
1457   }
1458   else
1459   {
1460     y1 = selection.y2;
1461     y2 = selection.y1;
1462   }
1463
1464   x1 /= 32;
1465   x2 /= 32;
1466   y1 /= 32;
1467   y2 /= 32;
1468
1469   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1470 }
1471
1472 void le_change(float x, float y, int tm, unsigned int c)
1473 {
1474   if(le_current_level != NULL)
1475   {
1476     int xx,yy;
1477     int x1, x2, y1, y2;
1478     unsigned int i;
1479
1480     /*  level_changed = true; */
1481
1482     switch(le_selection_mode)
1483     {
1484     case CURSOR:
1485       le_current_level->change(x,y,tm,c);
1486
1487       base_type cursor_base;
1488       cursor_base.x = x;
1489       cursor_base.y = y;
1490       cursor_base.width = 32;
1491       cursor_base.height = 32;
1492
1493       /* if there is a bad guy over there, remove it */
1494       for(i = 0; i < le_world.bad_guys.size(); ++i)
1495         if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1496         {
1497           le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1498           le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1499         }
1500
1501       break;
1502     case SQUARE:
1503       if(selection.x1 < selection.x2)
1504       {
1505         x1 = selection.x1;
1506         x2 = selection.x2;
1507       }
1508       else
1509       {
1510         x1 = selection.x2;
1511         x2 = selection.x1;
1512       }
1513       if(selection.y1 < selection.y2)
1514       {
1515         y1 = selection.y1;
1516         y2 = selection.y2;
1517       }
1518       else
1519       {
1520         y1 = selection.y2;
1521         y2 = selection.y1;
1522       }
1523
1524       x1 /= 32;
1525       x2 /= 32;
1526       y1 /= 32;
1527       y2 /= 32;
1528
1529       /* if there is a bad guy over there, remove it */
1530       for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1531           i != le_world.bad_guys.end(); /* will be at end of loop */)
1532       {
1533         if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1534             && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1535         {
1536           i = le_world.bad_guys.erase(i);
1537           continue;
1538         }
1539         else
1540         {
1541           ++i;
1542         }
1543       }
1544
1545       for(xx = x1; xx <= x2; xx++)
1546         for(yy = y1; yy <= y2; yy++)
1547         {
1548           le_current_level->change(xx*32, yy*32, tm, c);
1549
1550         }
1551       break;
1552     default:
1553       break;
1554     }
1555   }
1556 }
1557
1558 void le_testlevel()
1559 {
1560   le_current_level->save("test", le_level);
1561
1562   GameSession session("test",le_level, ST_GL_TEST);
1563   session.run();
1564   player_status.reset();
1565
1566   music_manager->halt_music();
1567
1568   Menu::set_current(NULL);
1569   le_world.arrays_free();
1570   le_current_level->load_gfx();
1571   le_world.activate_bad_guys();
1572 }
1573
1574 void le_showhelp()
1575 {
1576   SDL_Event event;
1577   unsigned int i, done_;
1578   char *text[] = {
1579                    "  - This is SuperTux's built-in level editor -",
1580                    "It has been designed to be light and easy to use from the start.",
1581                    "",
1582                    "When you first load the level editor you are given a menu where you",
1583                    "can load level subsets, create a new level subset, edit the current",
1584                    "subset's settings, or simply quit the editor. You can access this menu",
1585                    "from the level editor at any time by pressing the escape key.",
1586                    "",
1587                    "To your right is your button bar. The center of this contains many",
1588                    "tiles you can use to make your level. To select a tile, click on it",
1589                    "with your left mouse button; your selection will be shown in the",
1590                    "bottom right corner of the button box. Click anywhere on your level",
1591                    "with the left mouse button to place that tile down. If you right click",
1592                    "a tile in the button bar, you can find out what its keyboard shortcut",
1593                    "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1594                    "background, and enemy tiles. The eraser lets you remove tiles.",
1595                    "The left and right arrow keys scroll back and forth through your level.",
1596                    "The button with the wrench and screwdriver, lets you change the",
1597                    "settings of your level, including how long it is or what music it will",
1598                    "play. When you are ready to give your level a test, click on the little",
1599                    "running Tux. If you like the changes you have made to your level,",
1600                    "press the red save key to keep them.",
1601                    "To change which level in your subset you are editing, press the white",
1602                    "up and down arrow keys at the top of the button box.",
1603                    "",
1604                    "Have fun making levels! If you make some good ones, send them to us on",
1605                    "the SuperTux mailing list!",
1606                    "- SuperTux team"
1607                  };
1608
1609
1610   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1611
1612   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1613     white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1614
1615   gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1616
1617   flipscreen();
1618
1619   done_ = 0;
1620
1621   while(done_ == 0)
1622   {
1623     done_ = wait_for_event(event);
1624     SDL_Delay(50);
1625   }
1626 }