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