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