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