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