Take cursor out of the help screen.
[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_subset(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 void le_goto_level(int levelnb);
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 show_selections;
107 static bool le_help_shown;
108 static int pos_x, cursor_x, cursor_y, fire;
109 static int le_level;
110 static World* le_world;
111 static LevelSubset* le_level_subset;
112 static int le_show_grid;
113 static int le_frame;
114 static Surface* le_selection;
115 static int done;
116 static TileOrObject le_current;
117 static bool le_mouse_pressed[2];
118 static bool le_mouse_clicked[2];
119 static Button* le_save_level_bt;
120 static Button* le_exit_bt;
121 static Button* le_test_level_bt;
122 static Button* le_next_level_bt;
123 static Button* le_previous_level_bt;
124 static Button* le_move_right_bt;
125 static Button* le_move_left_bt;
126 static Button* le_rubber_bt;
127 static Button* le_select_mode_one_bt;
128 static Button* le_select_mode_two_bt;
129 static Button* le_settings_bt;
130 static Button* le_tilegroup_bt;
131 static Button* le_objects_bt;
132 static ButtonPanel* le_tilemap_panel;
133 static Menu* leveleditor_menu;
134 static Menu* subset_load_menu;
135 static Menu* subset_new_menu;
136 static Menu* subset_settings_menu;
137 static Menu* level_settings_menu;
138 static Menu* select_tilegroup_menu;
139 static Menu* select_objects_menu;
140 static Timer select_tilegroup_menu_effect;
141 static Timer select_objects_menu_effect;
142 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
143 static ButtonPanelMap tilegroups_map;
144 static ButtonPanelMap objects_map;
145 static std::string cur_tilegroup;
146 static std::string cur_objects;
147
148 static square selection;
149 static int le_selection_mode;
150 static SDL_Event event;
151 TileMapType active_tm;
152
153 int leveleditor(char* filename)
154 {
155   int last_time, now_time, i;
156
157   le_level = 1;
158
159   if(le_init() != 0)
160     return 1;
161
162   /* Clear screen: */
163
164   clearscreen(0, 0, 0);
165   updatescreen();
166
167   music_manager->halt_music();
168
169   while (SDL_PollEvent(&event))
170   {}
171
172   if(filename != NULL)
173     if(le_load_level_subset(filename))
174       return 1;
175
176   while(true)
177   {
178     last_time = SDL_GetTicks();
179     le_frame++;
180
181     le_checkevents();
182
183     if(Menu::current() == select_tilegroup_menu)
184     {
185       if(select_tilegroup_menu_effect.check())
186       {
187         select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
188                                        66,-0.5,0.5);
189       }
190       else
191         select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
192     }
193     else if(Menu::current() == select_objects_menu)
194     {
195       if(select_objects_menu_effect.check())
196       {
197         select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
198       }
199       else
200         select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
201     }
202
203     if(le_world != NULL)
204     {
205       /* making events results to be in order */
206       if(pos_x < 0)
207         pos_x = 0;
208       if(pos_x > (le_world->get_level()->width * 32) - screen->w)
209         pos_x = (le_world->get_level()->width * 32) - screen->w;
210
211       /* draw the level */
212       le_drawlevel();
213     }
214     else
215       clearscreen(0, 0, 0);
216
217     /* draw editor interface */
218     le_drawinterface();
219
220     Menu* menu = Menu::current();
221     if(menu)
222     {
223       menu->draw();
224       menu->action();
225
226       if(menu == leveleditor_menu)
227       {
228         switch (leveleditor_menu->check())
229         {
230         case MNID_RETURNLEVELEDITOR:
231           if(le_world != NULL)
232             Menu::set_current(0);
233           else
234             Menu::set_current(leveleditor_menu);
235           break;
236         case MNID_SUBSETSETTINGS:
237           update_subset_settings_menu();
238           break;
239         case MNID_QUITLEVELEDITOR:
240           done = 1;
241           break;
242         }
243       }
244       else if(menu == level_settings_menu)
245       {
246         switch (level_settings_menu->check())
247         {
248         case MNID_APPLY:
249           apply_level_settings_menu();
250           Menu::set_current(NULL);
251           break;
252
253         default:
254           break;
255         }
256       }
257       else if(menu == select_tilegroup_menu)
258       {
259         int it = -1;
260         switch (it = select_tilegroup_menu->check())
261         {
262         default:
263           if(it >= 0)
264           {
265             cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
266             Menu::set_current(0);
267             cur_objects = "";
268
269           }
270           break;
271         }
272       }
273       else if(menu == select_objects_menu)
274       {
275         int it = -1;
276         switch (it = select_objects_menu->check())
277         {
278         default:
279           if(it >= 0)
280           {
281             cur_objects = select_objects_menu->get_item_by_id(it).text;
282             cur_tilegroup = "";
283
284             Menu::set_current(0);
285           }
286           break;
287         }
288       }
289       else if(menu == subset_load_menu)
290       {
291         switch (i = subset_load_menu->check())
292         {
293         case 0:
294           break;
295         default:
296           if(i >= 1)
297           {
298             if(le_load_level_subset(level_subsets.item[i-1]))
299               return 1;
300           }
301           break;
302         }
303       }
304       else if(menu == subset_new_menu)
305       {
306         if(subset_new_menu->item[2].input[0] == '\0')
307           subset_new_menu->item[3].kind = MN_DEACTIVE;
308         else
309         {
310           subset_new_menu->item[3].kind = MN_ACTION;
311
312           switch (i = subset_new_menu->check())
313           {
314           case MNID_CREATESUBSET:
315             LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
316             le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
317             leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
318             le_goto_level(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_subset(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   le_goto_level(1);
370
371   //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
372
373   Menu::set_current(NULL);
374
375   return 0;
376 }
377
378 void le_init_menus()
379 {
380   int i;
381
382   leveleditor_menu = new Menu();
383   subset_load_menu = new Menu();
384   subset_new_menu  = new Menu();
385   subset_settings_menu = new Menu();
386   level_settings_menu  = new Menu();
387   select_tilegroup_menu  = new Menu();
388   select_objects_menu = new Menu();
389
390   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
391   leveleditor_menu->additem(MN_HL,"",0,0);
392   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
393   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
394   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
395   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
396   leveleditor_menu->additem(MN_HL,"",0,0);
397   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
398
399   Menu::set_current(leveleditor_menu);
400
401   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
402   subset_load_menu->additem(MN_HL, "", 0, 0);
403
404   for(i = 0; i < level_subsets.num_items; ++i)
405   {
406     subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
407   }
408   subset_load_menu->additem(MN_HL,"",0,0);
409   subset_load_menu->additem(MN_BACK,"Back",0,0);
410
411   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
412   subset_new_menu->additem(MN_HL,"",0,0);
413   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
414   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
415   subset_new_menu->additem(MN_HL,"",0,0);
416   subset_new_menu->additem(MN_BACK,"Back",0,0);
417
418   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
419   subset_settings_menu->additem(MN_HL,"",0,0);
420   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
421   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
422   subset_settings_menu->additem(MN_HL,"",0,0);
423   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
424   subset_settings_menu->additem(MN_HL,"",0,0);
425   subset_settings_menu->additem(MN_BACK,"Back",0,0);
426
427   level_settings_menu->arrange_left = true;
428   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
429   level_settings_menu->additem(MN_HL,"",0,0);
430   level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
431   level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
432   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
433   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
434   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
435   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
436   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
437   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
438   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
439   level_settings_menu->additem(MN_NUMFIELD,    "Top Red    ",0,0,MNID_TopRed);
440   level_settings_menu->additem(MN_NUMFIELD,    "Top Green  ",0,0,MNID_TopGreen);
441   level_settings_menu->additem(MN_NUMFIELD,    "Top Blue   ",0,0,MNID_TopBlue);
442   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red ",0,0,MNID_BottomRed);
443   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
444   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue",0,0,MNID_BottomBlue);
445   level_settings_menu->additem(MN_HL,"",0,0);
446   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
447
448   select_tilegroup_menu->arrange_left = true;
449   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
450   select_tilegroup_menu->additem(MN_HL,"",0,0);
451   select_tilegroup_menu->additem(MN_ACTION,"asd",0,0);
452   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
453   int tileid = 1;
454   for(std::set<TileGroup>::iterator it = tilegroups->begin();
455         it != tilegroups->end(); ++it )
456     {
457       select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
458       tileid++;
459       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
460       i = 0;
461
462       for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
463           sit != (*it).tiles.end(); ++sit, ++i)
464       {
465         std::string imagefile = "/images/tilesets/" ;
466         bool only_editor_image = false;
467         if(!TileManager::instance()->get(*sit)->filenames.empty())
468         {
469           imagefile += TileManager::instance()->get(*sit)->filenames[0];
470         }
471         else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
472         {
473           imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
474           only_editor_image = true;
475         }
476         else
477         {
478           imagefile += "notile.png";
479         }
480         Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
481                                     0, 0, 32, 32);
482         if(!only_editor_image)
483           if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
484           {
485             imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
486             button->add_icon(imagefile,32,32);
487           }
488         tilegroups_map[it->name]->additem(button, *sit);
489       }
490     }
491   select_tilegroup_menu->additem(MN_HL,"",0,0);
492
493   select_objects_menu->arrange_left = true;
494   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
495   select_objects_menu->additem(MN_HL,"",0,0);
496   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
497   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
498
499   for(int i = 0; i < NUM_BadGuyKinds; ++i)
500   {
501     BadGuy bad_tmp(0,0,BadGuyKind(i),false);
502     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
503     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));
504   }
505
506   select_objects_menu->additem(MN_HL,"",0,0);
507
508 }
509
510 int le_init()
511 {
512
513
514   level_subsets = dsubdirs("/levels", "level1.stl");
515   le_level_subset = new LevelSubset;
516
517   le_world = NULL;
518
519   active_tm = TM_IA;
520   le_show_grid = true;
521   show_selections = 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_F9,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_F8,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_unload_level()
670 {
671   if(le_level_changed)
672   {
673     le_drawlevel();
674     le_drawinterface();
675     char str[1024];
676     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
677     if(confirm_dialog(str))
678     {
679       le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
680     }
681   }
682
683   delete le_world;
684   le_level_changed = false;  
685 }
686
687 void le_goto_level(int levelnb)
688 {
689   le_unload_level();
690   le_world = new World(le_level_subset->name, levelnb);
691 }
692
693 void le_quit(void)
694 {
695   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
696
697   le_unload_level();
698   delete le_selection;
699   delete leveleditor_menu;
700   delete subset_load_menu;
701   delete subset_new_menu;
702   delete subset_settings_menu;
703   delete level_settings_menu;
704   delete select_tilegroup_menu;
705   delete select_objects_menu;
706   delete le_save_level_bt;
707   delete le_exit_bt;
708   delete le_test_level_bt;
709   delete le_next_level_bt;
710   delete le_previous_level_bt;
711   delete le_move_right_bt;
712   delete le_move_left_bt;
713   delete le_rubber_bt;
714   delete le_select_mode_one_bt;
715   delete le_select_mode_two_bt;
716   delete le_settings_bt;
717   delete le_tilegroup_bt;
718   delete le_objects_bt;
719   delete le_tilemap_panel;
720
721   delete le_level_subset;
722   le_level_subset = 0;
723
724   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
725       i != tilegroups_map.end(); ++i)
726   {
727     delete i->second;
728   }
729   for(ButtonPanelMap::iterator i = objects_map.begin();
730       i != objects_map.end(); ++i)
731   {
732     delete i->second;
733   }
734 }
735
736 void le_drawminimap()
737 {
738   if(le_world == NULL)
739     return;
740
741   int mini_tile_width;
742   if(screen->w - 64 > le_world->get_level()->width * 4)
743     mini_tile_width = 4;
744   else if(screen->w - 64 > le_world->get_level()->width * 2)
745     mini_tile_width = 2;
746   else
747     mini_tile_width = 1;
748   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
749
750   for (int y = 0; y < 15; ++y)
751     for (int x = 0; x < le_world->get_level()->width; ++x)
752     {
753
754       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
755
756       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
757
758       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
759
760     }
761
762   fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, 15*4, 200, 200, 200, 128);
763
764   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
765   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, 15*4, 200, 200, 200, 200);
766   fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, 15*4, 200, 200, 200, 200);
767   fillrect(left_offset + (pos_x/32)*mini_tile_width, 15*4-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
768
769 }
770
771 void le_drawinterface()
772 {
773   int x,y;
774   char str[80];
775
776   if(le_world != NULL)
777   {
778     /* draw a grid (if selected) */
779     if(le_show_grid)
780     {
781       for(x = 0; x < 19; x++)
782         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
783       for(y = 0; y < 15; y++)
784         fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
785     }
786   }
787
788   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
789     le_drawminimap();
790
791   if(show_selections)
792   {
793   if(le_selection_mode == CURSOR)
794   {
795     if(le_current.IsTile())
796       le_selection->draw( cursor_x - pos_x, cursor_y);
797   }
798   else if(le_selection_mode == SQUARE)
799   {
800     int w, h;
801     le_highlight_selection();
802     /* draw current selection */
803     w = selection.x2 - selection.x1;
804     h = selection.y2 - selection.y1;
805     fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
806     fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
807     fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
808     fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
809   }
810   }
811
812
813   /* draw button bar */
814   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
815
816   if(le_current.IsTile())
817   {
818     Tile::draw(19 * 32, 14 * 32, le_current.tile);
819     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
820       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
821   }
822   if(le_current.IsObject())
823   {
824     le_current.obj->draw_on_screen(19 * 32, 14 * 32);
825     le_current.obj->draw_on_screen(cursor_x,cursor_y);
826   }
827
828   if(le_world != NULL)
829   {
830     le_save_level_bt->draw();
831     le_exit_bt->draw();
832     le_test_level_bt->draw();
833     le_next_level_bt->draw();
834     le_previous_level_bt->draw();
835     le_rubber_bt->draw();
836     if(le_selection_mode == SQUARE)
837       le_select_mode_one_bt->draw();
838     else if(le_selection_mode == CURSOR)
839       le_select_mode_two_bt->draw();
840     le_settings_bt->draw();
841     le_move_right_bt->draw();
842     le_move_left_bt->draw();
843     le_tilegroup_bt->draw();
844     le_objects_bt->draw();
845     if(!cur_tilegroup.empty())
846       tilegroups_map[cur_tilegroup]->draw();
847     else if(!cur_objects.empty())
848     {
849       objects_map[cur_objects]->draw();
850     }
851
852     le_tilemap_panel->draw();
853
854     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
855     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
856
857     if(!le_help_shown)
858       white_small_text->draw("F1 for Help", 10, 430, 1);
859   }
860   else
861   {
862     if(!Menu::current())
863       white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
864     else
865       white_small_text->draw("No Level Subset loaded", 10, 430, 1);
866   }
867
868 }
869
870 void le_drawlevel()
871 {
872   unsigned int y,x,s;
873   Uint8 a;
874
875   /* Draw the real background */
876   if(le_world->get_level()->bkgd_image[0] != '\0')
877   {
878     s = (int)((float)pos_x * ((float)le_world->get_level()->bkgd_speed/60.)) % screen->w;
879     le_world->get_level()->img_bkgd->draw_part(s,0,0,0,
880         le_world->get_level()->img_bkgd->w - s - 32, le_world->get_level()->img_bkgd->h);
881     le_world->get_level()->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
882         le_world->get_level()->img_bkgd->h);
883   }
884   else
885   {
886     drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
887   }
888
889   if(le_current.IsTile())
890   {
891     Tile::draw(cursor_x-pos_x, cursor_y,le_current.tile,128);
892     if(!TileManager::instance()->get(le_current.tile)->images.empty())
893       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);
894   }
895   if(le_current.IsObject())
896   {
897     le_current.obj->move_to(cursor_x, cursor_y);
898   }
899
900   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
901
902   for (y = 0; y < 15; ++y)
903     for (x = 0; x < 20; ++x)
904     {
905
906       if(active_tm == TM_BG)
907         a = 255;
908       else
909         a = 128;
910
911       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->bg_tiles[y][x + (int)(pos_x / 32)],a);
912
913       if(active_tm == TM_IA)
914         a = 255;
915       else
916         a = 128;
917
918       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)],a);
919
920       if(active_tm == TM_FG)
921         a = 255;
922       else
923         a = 128;
924
925       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->fg_tiles[y][x + (int)(pos_x / 32)],a);
926
927       /* draw whats inside stuff when cursor is selecting those */
928       /* (draw them all the time - is this the right behaviour?) */
929       Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)]);
930       if(edit_image && !edit_image->editor_images.empty())
931         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
932
933     }
934
935   /* Draw the Bad guys: */
936   for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
937   {
938     /* to support frames: img_bsod_left[(frame / 5) % 4] */
939
940     scroll_x = pos_x;
941     (*it)->draw();
942   }
943
944
945   /* Draw the player: */
946   /* for now, the position is fixed at (100, 240) */
947   largetux.walk_right->draw( 100 - pos_x, 240);
948 }
949
950 void le_change_object_properties(GameObject *pobj)
951 {
952   Menu* object_properties_menu = new Menu();
953
954   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
955   object_properties_menu->additem(MN_HL,"",0,0);
956   /*object_properties_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
957   object_properties_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
958   object_properties_menu->additem(MN_HL,"",0,0);
959   object_properties_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);*/
960   object_properties_menu->additem(MN_HL,"",0,0);
961   object_properties_menu->additem(MN_BACK,"Apply",0,0);
962
963   delete object_properties_menu;
964 }
965
966
967 void le_checkevents()
968 {
969   SDLKey key;
970   SDLMod keymod;
971   Button* pbutton;
972   int x,y;
973
974   keymod = SDL_GetModState();
975
976   while(SDL_PollEvent(&event))
977   {
978     if (Menu::current())
979     {
980       Menu::current()->event(event);
981       if(!le_world && !Menu::current())
982         Menu::set_current(leveleditor_menu);
983     }
984     else
985     {
986       mouse_cursor->set_state(MC_NORMAL);
987
988       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
989       if(event.type == SDL_KEYDOWN
990           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
991               && (event.motion.x > 0
992                   && event.motion.x < screen->w - 64 &&
993                   event.motion.y > 0 && event.motion.y < screen->h)))
994       {
995         switch(event.type)
996         {
997         case SDL_KEYDOWN:       // key pressed
998           key = event.key.keysym.sym;
999           switch(key)
1000           {
1001           case SDLK_ESCAPE:
1002             Menu::set_current(leveleditor_menu);
1003             break;
1004           case SDLK_LEFT:
1005             if(fire == DOWN)
1006               cursor_x -= KEY_CURSOR_SPEED;
1007             else
1008               cursor_x -= KEY_CURSOR_FASTSPEED;
1009
1010             if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
1011               pos_x = cursor_x - MOUSE_LEFT_MARGIN;
1012
1013             break;
1014           case SDLK_RIGHT:
1015             if(fire == DOWN)
1016               cursor_x += KEY_CURSOR_SPEED;
1017             else
1018               cursor_x += KEY_CURSOR_FASTSPEED;
1019
1020             if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
1021               pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
1022
1023             break;
1024           case SDLK_UP:
1025             if(fire == DOWN)
1026               cursor_y -= KEY_CURSOR_SPEED;
1027             else
1028               cursor_y -= KEY_CURSOR_FASTSPEED;
1029
1030             if(cursor_y < 0)
1031               cursor_y = 0;
1032             break;
1033           case SDLK_DOWN:
1034             if(fire == DOWN)
1035               cursor_y += KEY_CURSOR_SPEED;
1036             else
1037               cursor_y += KEY_CURSOR_FASTSPEED;
1038
1039             if(cursor_y > screen->h-32)
1040               cursor_y = screen->h-32;
1041             break;
1042           case SDLK_LCTRL:
1043             fire =UP;
1044             break;
1045           case SDLK_F1:
1046             if(le_world != NULL)
1047               le_showhelp();
1048             break;
1049           case SDLK_HOME:
1050             cursor_x = 0;
1051             pos_x = cursor_x;
1052             break;
1053           case SDLK_END:
1054             cursor_x = (le_world->get_level()->width * 32) - 32;
1055             pos_x = cursor_x;
1056             break;
1057           case SDLK_F9:
1058             le_show_grid = !le_show_grid;
1059             break;
1060           default:
1061             break;
1062           }
1063           break;
1064         case SDL_KEYUP: /* key released */
1065           switch(event.key.keysym.sym)
1066           {
1067           case SDLK_LCTRL:
1068             fire = DOWN;
1069             break;
1070           default:
1071             break;
1072           }
1073           break;
1074         case SDL_MOUSEBUTTONDOWN:
1075           if(event.button.button == SDL_BUTTON_LEFT)
1076           {
1077             le_mouse_pressed[LEFT] = true;
1078
1079             selection.x1 = event.motion.x + pos_x;
1080             selection.y1 = event.motion.y;
1081             selection.x2 = event.motion.x + pos_x;
1082             selection.y2 = event.motion.y;
1083           }
1084           else if(event.button.button == SDL_BUTTON_RIGHT)
1085           {
1086             le_mouse_pressed[RIGHT] = true;
1087           }
1088           break;
1089         case SDL_MOUSEBUTTONUP:
1090           if(event.button.button == SDL_BUTTON_LEFT)
1091           {
1092             le_mouse_pressed[LEFT] = false;
1093             le_mouse_clicked[LEFT] = true;
1094           }
1095           else if(event.button.button == SDL_BUTTON_RIGHT)
1096           {
1097             le_mouse_pressed[RIGHT] = false;
1098             le_mouse_clicked[RIGHT] = true;
1099           }
1100           break;
1101         case SDL_MOUSEMOTION:
1102
1103           if(!Menu::current())
1104           {
1105             x = event.motion.x;
1106             y = event.motion.y;
1107
1108             if(le_current.IsTile())
1109             {
1110               cursor_x = ((int)(pos_x + x) / 32) * 32;
1111               cursor_y = ((int) y / 32) * 32;
1112             }
1113             else
1114             {
1115               cursor_x = x;
1116               cursor_y = y;
1117             }
1118
1119             if(le_mouse_pressed[LEFT])
1120             {
1121               selection.x2 = x + pos_x;
1122               selection.y2 = y;
1123             }
1124
1125             if(le_mouse_pressed[RIGHT])
1126             {
1127               pos_x += -1 * event.motion.xrel;
1128             }
1129           }
1130           break;
1131         case SDL_QUIT:  // window closed
1132           done = 1;
1133           break;
1134         default:
1135           break;
1136         }
1137       }
1138     }
1139
1140     if(le_world != NULL)
1141     {
1142       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 &&
1143           event.motion.y > 0 && event.motion.y < screen->h)))
1144       {
1145         le_mouse_pressed[LEFT] = false;
1146         le_mouse_pressed[RIGHT] = false;
1147
1148         if(!Menu::current())
1149         {
1150           /* Check for button events */
1151           le_test_level_bt->event(event);
1152           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1153             le_testlevel();
1154           le_save_level_bt->event(event);
1155           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1156             le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
1157           le_exit_bt->event(event);
1158           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1159           {
1160             Menu::set_current(leveleditor_menu);
1161           }
1162           le_next_level_bt->event(event);
1163           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1164           {
1165             if(le_level < le_level_subset->levels)
1166             {
1167               le_goto_level(++le_level);
1168             }
1169             else
1170             {
1171               Level new_lev;
1172               char str[1024];
1173               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1174               if(confirm_dialog(str))
1175               {
1176                 new_lev.init_defaults();
1177                 new_lev.save(le_level_subset->name.c_str(),++le_level);
1178                 le_level_subset->levels = le_level;
1179                 le_goto_level(le_level);
1180               }
1181             }
1182           }
1183           le_previous_level_bt->event(event);
1184           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1185           {
1186             if(le_level > 1)
1187               le_goto_level(--le_level);
1188           }
1189           le_rubber_bt->event(event);
1190           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1191             le_current.Tile(0);
1192
1193           if(le_selection_mode == SQUARE)
1194           {
1195             le_select_mode_one_bt->event(event);
1196             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1197               le_selection_mode = CURSOR;
1198           }
1199           else
1200           {
1201             le_select_mode_two_bt->event(event);
1202             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1203               le_selection_mode = SQUARE;
1204           }
1205           ButtonPanelMap::iterator it;
1206           le_tilegroup_bt->event(event);
1207           switch (le_tilegroup_bt->get_state())
1208           {
1209           case BUTTON_CLICKED:
1210             Menu::set_current(select_tilegroup_menu);
1211             select_tilegroup_menu_effect.start(200);
1212             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1213             break;
1214           case BUTTON_WHEELUP:
1215             if(cur_tilegroup.empty())
1216             {
1217               cur_tilegroup = tilegroups_map.begin()->first;
1218             }
1219             else
1220             {
1221               it = tilegroups_map.find(cur_tilegroup);
1222               if((++it) == tilegroups_map.end())
1223               {
1224                 cur_tilegroup = tilegroups_map.begin()->first;
1225               }
1226               else
1227               {
1228                 cur_tilegroup = (*it).first;
1229               }
1230             }
1231
1232             cur_objects = "";
1233             break;
1234           case BUTTON_WHEELDOWN:
1235             it = tilegroups_map.find(cur_tilegroup);
1236             if(it == tilegroups_map.begin())
1237             {
1238               cur_tilegroup = tilegroups_map.rbegin()->first;
1239               cur_objects = "";
1240               break;
1241             }
1242             if(--it != --tilegroups_map.begin())
1243               cur_tilegroup = (*it).first;
1244             else
1245               cur_tilegroup = tilegroups_map.rbegin()->first;
1246
1247             cur_objects = "";
1248             break;
1249           default:
1250             break;
1251           }
1252
1253           le_objects_bt->event(event);
1254           switch (le_objects_bt->get_state())
1255           {
1256           case BUTTON_CLICKED:
1257             Menu::set_current(select_objects_menu);
1258             select_objects_menu_effect.start(200);
1259             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1260             break;
1261           case BUTTON_WHEELUP:
1262             it = objects_map.find(cur_objects);
1263             if(it == objects_map.end())
1264             {
1265               cur_objects = objects_map.begin()->first;
1266               cur_tilegroup = "";
1267               break;
1268             }
1269             if(++it != objects_map.end())
1270               cur_objects = (*it).first;
1271             else
1272               cur_objects = objects_map.begin()->first;
1273
1274             cur_tilegroup = "";
1275             break;
1276           case BUTTON_WHEELDOWN:
1277             it = objects_map.find(cur_objects);
1278             if(it == objects_map.begin())
1279             {
1280               cur_objects = objects_map.rbegin()->first;
1281               cur_tilegroup = "";
1282               break;
1283             }
1284             if(--it != --objects_map.begin())
1285               cur_objects = (*it).first;
1286             else
1287               cur_objects = objects_map.rbegin()->first;
1288
1289             cur_tilegroup = "";
1290             break;
1291             break;
1292           default:
1293             break;
1294           }
1295
1296           le_settings_bt->event(event);
1297           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1298           {
1299             update_level_settings_menu();
1300             Menu::set_current(level_settings_menu);
1301           }
1302           if(!cur_tilegroup.empty())
1303           {
1304             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1305             {
1306               if(pbutton->get_state() == BUTTON_CLICKED)
1307               {
1308                 le_current.Tile(pbutton->get_tag());
1309               }
1310             }
1311           }
1312           else if(!cur_objects.empty())
1313           {
1314             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1315             {
1316               if(pbutton->get_state() == BUTTON_CLICKED)
1317               {
1318                 le_current.Object(pbutton->get_game_object());
1319               }
1320             }
1321           }
1322
1323           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1324           {
1325             if(pbutton->get_state() == BUTTON_CLICKED)
1326             {
1327               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1328             }
1329           }
1330         }
1331         else
1332         {
1333           le_settings_bt->event(event);
1334           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1335           {
1336             Menu::set_current(0);
1337           }
1338           le_tilegroup_bt->event(event);
1339           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1340           {
1341             Menu::set_current(0);
1342           }
1343           le_objects_bt->event(event);
1344           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1345           {
1346             Menu::set_current(0);
1347           }
1348         }
1349       }
1350
1351       if(!Menu::current() && !show_minimap)
1352       {
1353         if(le_mouse_pressed[LEFT])
1354         {
1355           if(le_current.IsTile())
1356             le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1357         }
1358         else if(le_mouse_clicked[LEFT])
1359         {
1360           if(le_current.IsObject())
1361           {
1362             le_level_changed  = true;
1363             std::string type = le_current.obj->type();
1364             if(type == "BadGuy")
1365             {
1366               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1367
1368               le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1369               le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1370             }
1371           }
1372           le_mouse_clicked[LEFT] = false;
1373         }
1374       }
1375     }
1376   }
1377   if(!Menu::current())
1378   {
1379     show_minimap = false;
1380
1381     le_move_left_bt->event(event);
1382     le_move_right_bt->event(event);
1383     switch(le_move_left_bt->get_state())
1384     {
1385     case BUTTON_PRESSED:
1386       pos_x -= 192;
1387       show_minimap = true;
1388       break;
1389     case BUTTON_HOVER:
1390       pos_x -= 32;
1391       show_minimap = true;
1392       break;
1393     case BUTTON_CLICKED:
1394       show_minimap = true;
1395       break;
1396     default:
1397       break;
1398     }
1399
1400     switch(le_move_right_bt->get_state())
1401     {
1402     case BUTTON_PRESSED:
1403       pos_x += 192;
1404       show_minimap = true;
1405       break;
1406     case BUTTON_HOVER:
1407       pos_x += 32;
1408       show_minimap = true;
1409       break;
1410     case BUTTON_CLICKED:
1411       show_minimap = true;
1412       break;
1413     default:
1414       break;
1415     }
1416
1417   }
1418
1419 }
1420
1421 void le_highlight_selection()
1422 {
1423   int x1, x2, y1, y2;
1424
1425   if(selection.x1 < selection.x2)
1426   {
1427     x1 = selection.x1;
1428     x2 = selection.x2;
1429   }
1430   else
1431   {
1432     x1 = selection.x2;
1433     x2 = selection.x1;
1434   }
1435   if(selection.y1 < selection.y2)
1436   {
1437     y1 = selection.y1;
1438     y2 = selection.y2;
1439   }
1440   else
1441   {
1442     y1 = selection.y2;
1443     y2 = selection.y1;
1444   }
1445
1446   x1 /= 32;
1447   x2 /= 32;
1448   y1 /= 32;
1449   y2 /= 32;
1450
1451   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1452 }
1453
1454 void le_change(float x, float y, int tm, unsigned int c)
1455 {
1456   if(le_world != NULL)
1457   {
1458     int xx,yy;
1459     int x1, x2, y1, y2;
1460     unsigned int i = 0;
1461
1462     le_level_changed = true;
1463     
1464     switch(le_selection_mode)
1465     {
1466     case CURSOR:
1467       le_world->get_level()->change(x,y,tm,c);
1468
1469       base_type cursor_base;
1470       cursor_base.x = x;
1471       cursor_base.y = y;
1472       cursor_base.width = 32;
1473       cursor_base.height = 32;
1474
1475       /* if there is a bad guy over there, remove it */
1476       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1477         if(rectcollision(cursor_base,(*it)->base))
1478         {
1479           delete (*it);
1480           le_world->bad_guys.erase(it);
1481           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1482           break;
1483         }
1484
1485       break;
1486     case SQUARE:
1487       if(selection.x1 < selection.x2)
1488       {
1489         x1 = selection.x1;
1490         x2 = selection.x2;
1491       }
1492       else
1493       {
1494         x1 = selection.x2;
1495         x2 = selection.x1;
1496       }
1497       if(selection.y1 < selection.y2)
1498       {
1499         y1 = selection.y1;
1500         y2 = selection.y2;
1501       }
1502       else
1503       {
1504         y1 = selection.y2;
1505         y2 = selection.y1;
1506       }
1507
1508       x1 /= 32;
1509       x2 /= 32;
1510       y1 /= 32;
1511       y2 /= 32;
1512
1513       /* if there is a bad guy over there, remove it */
1514       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
1515           it != le_world->bad_guys.end(); /* will be at end of loop */)
1516       {
1517         if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
1518             && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
1519         {
1520           delete (*it);
1521           it = le_world->bad_guys.erase(it);
1522           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1523           continue;
1524         }
1525         else
1526         {
1527           ++i;
1528           ++it;
1529         }
1530       }
1531
1532       for(xx = x1; xx <= x2; xx++)
1533         for(yy = y1; yy <= y2; yy++)
1534         {
1535           le_world->get_level()->change(xx*32, yy*32, tm, c);
1536
1537         }
1538       break;
1539     default:
1540       break;
1541     }
1542   }
1543 }
1544
1545 void le_testlevel()
1546 {
1547   //Make sure a time value is set when testing the level
1548   if(le_world->get_level()->time_left == 0)
1549     le_world->get_level()->time_left = 250;
1550
1551   le_world->get_level()->save("test", le_level);
1552
1553   GameSession session("test",le_level, ST_GL_TEST);
1554   session.run();
1555   player_status.reset();
1556
1557   music_manager->halt_music();
1558
1559   Menu::set_current(NULL);
1560   World::set_current(le_world);
1561 }
1562
1563 void le_showhelp()
1564 {
1565   bool tmp_show_grid = le_show_grid;
1566   int temp_le_selection_mode = le_selection_mode;
1567   le_selection_mode = NONE;
1568   show_selections = true;
1569   le_show_grid = false;
1570   le_help_shown = true;
1571
1572   drawgradient(Color(0,0,0), Color(255,255,255));
1573   le_drawinterface();
1574
1575   SDL_Event event;
1576   unsigned int i, done_;
1577   char *text[] = {
1578
1579                    " - Supertux level editor tutorial - ",
1580                    "",
1581                    "To make your map, click the       ",
1582                    "tilegroup button and choose a     ",
1583                    "tilegroup.",
1584                    "Pick a tile and simply hold down  ",
1585                    "the left mouse button over the map",
1586                    "to \"paint\" your selection over",
1587                    "the screen.",
1588                    "",
1589                    "There are three layers for painting",
1590                    "tiles upon, Background layer,",
1591                    "the Interactive layer, and the",
1592                    "Foreground layer, which can be",
1593                    "toggled by the BkGrd, IntAct and",
1594                    "FrGrd buttons. The Foreground and",
1595                    "Background layers do not effect",
1596                    "Tux in the gameplay, but lie in",
1597                    "front of him or lie behind him in",
1598                    "his adventures.",
1599                  };
1600
1601   char *text2[] = {
1602
1603                     " - Supertux level editor tutorial - ",
1604                     "",
1605                     "The tiles placed on",
1606                     "the Interactive layer are those",
1607                     "which actually effect Tux in the",
1608                     "game.",
1609                     "",
1610                     "Click the objects menu to put ",
1611                     "bad guys and other objects in the",
1612                     "game. Unlike placing tiles, you",
1613                     "cannot \"paint\" enemies. Click",
1614                     "them onto the screen one at a time.",
1615                     "",
1616                     "To change the settings of your",
1617                     "level, click the button with the",
1618                     "screwdriver and wrench. From here",
1619                     "you can change the background,",
1620                     "music, length of the level,",
1621                     "and more."
1622                   };
1623
1624   char *text3[] = {
1625
1626                     " - Supertux level editor tutorial - ",
1627                     "",
1628                     "You may have more than one level.",
1629                     "Pressing the up and down buttons",
1630                     "above the button bar lets you",
1631                     "choose which one you are working on.",
1632                     "",
1633                     "If you would like to speed up your",
1634                     "level editing, a useful trick is",
1635                     "to learn the keyboard shortcuts.",
1636                     "They are easy to learn, just right-",
1637                     "click on the buttons.",
1638                     "",
1639                     "Have fun making levels! If you make",
1640                     "some good ones, send them to us on",
1641                     "the SuperTux mailing list!",
1642                     "- SuperTux team"
1643                   };
1644                 
1645                   
1646
1647   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1648
1649   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1650     white_text->draw(text[i], 5, 80+(i*white_text->h), 1);
1651
1652   gold_text->drawf("Press Anything to Continue - Page 1/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1653
1654   flipscreen();
1655
1656   done_ = 0;
1657
1658   while(done_ == 0)
1659   {
1660     done_ = wait_for_event(event);
1661     SDL_Delay(50);
1662   }
1663
1664   drawgradient(Color(0,0,0), Color(255,255,255));
1665   le_drawinterface();
1666
1667
1668   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1669
1670   for(i = 0; i < sizeof(text2)/sizeof(char *); i++)
1671     white_text->draw(text2[i], 5, 80+(i*white_text->h), 1);
1672
1673   gold_text->drawf("Press Anything to Continue - Page 2/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1674
1675   flipscreen();
1676
1677   done_ = 0;
1678
1679   while(done_ == 0)
1680   {
1681     done_ = wait_for_event(event);
1682     SDL_Delay(50);
1683   }
1684   
1685     drawgradient(Color(0,0,0), Color(255,255,255));
1686   le_drawinterface();
1687
1688
1689   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1690
1691   for(i = 0; i < sizeof(text3)/sizeof(char *); i++)
1692     white_text->draw(text3[i], 5, 80+(i*white_text->h), 1);
1693
1694   gold_text->drawf("Press Anything to Continue - Page 3/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1695
1696   flipscreen();
1697
1698   done_ = 0;
1699
1700   while(done_ == 0)
1701   {
1702     done_ = wait_for_event(event);
1703     SDL_Delay(50);
1704   }
1705
1706   show_selections = true;
1707   le_show_grid = tmp_show_grid;
1708   le_selection_mode = temp_le_selection_mode;
1709   le_help_shown = false;
1710 }