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