fixed butt jump to work even when up-key is not pressed, added a little jump after...
[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
58 /* scolling speed */
59 #define KEYBOARD_SPEED 140
60 #define MOUSE_SPEED    40
61
62 /* look */
63 #define SELECT_W 2 // size of the selections lines
64 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
65
66 /* own declerations */
67 /* crutial ones (main loop) */
68 int le_init();
69 void le_quit();
70 int le_load_level_subset(char *filename);
71 void le_drawlevel();
72 void le_drawinterface();
73 void le_checkevents();
74 void le_change(float x, float y, int tm, unsigned int c);
75 void le_testlevel();
76 void le_showhelp();
77 void le_set_defaults(void);
78 void le_activate_bad_guys(void);
79 void le_goto_level(int levelnb);
80 void le_highlight_selection();
81
82 void apply_level_settings_menu();
83 void update_subset_settings_menu();
84 void save_subset_settings_menu();
85
86 struct TileOrObject
87 {
88   TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
89
90   void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
91   void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
92   //Returns true for a tile
93   bool IsTile() { return is_tile; };
94   //Returns true for a GameObject
95   bool IsObject() { return !is_tile; };
96
97
98   void Init() { tile = 0; obj = NULL; is_tile = true; };
99
100   bool is_tile; //true for tile (false for object)
101   unsigned int tile;
102   GameObject* obj;
103 };
104
105 /* leveleditor internals */
106 static string_list_type level_subsets;
107 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
108 static bool show_minimap;
109 static bool show_selections;
110 static bool le_help_shown;
111 static int pos_x, pos_y, cursor_x, cursor_y;
112 static int le_level;
113 static World* le_world;
114 static LevelSubset* le_level_subset;
115 static int le_show_grid;
116 static int le_frame;
117 static Surface* le_selection;
118 static int done;
119 static TileOrObject le_current;
120 static bool le_mouse_pressed[2];
121 static bool le_mouse_clicked[2];
122 static Button* le_save_level_bt;
123 static Button* le_exit_bt;
124 static Button* le_test_level_bt;
125 static Button* le_next_level_bt;
126 static Button* le_previous_level_bt;
127 static Button* le_move_right_bt;
128 static Button* le_move_left_bt;
129 static Button* le_move_up_bt;
130 static Button* le_move_down_bt;
131 static Button* le_rubber_bt;
132 static Button* le_select_mode_one_bt;
133 static Button* le_select_mode_two_bt;
134 static Button* le_settings_bt;
135 static Button* le_tilegroup_bt;
136 static Button* le_objects_bt;
137 static Button* le_object_select_bt;
138 static Button* le_object_properties_bt;
139 static ButtonPanel* le_tilemap_panel;
140 static Menu* leveleditor_menu;
141 static Menu* subset_load_menu;
142 static Menu* subset_new_menu;
143 static Menu* subset_settings_menu;
144 static Menu* level_settings_menu;
145 static Menu* select_tilegroup_menu;
146 static Menu* select_objects_menu;
147 static Timer select_tilegroup_menu_effect;
148 static Timer select_objects_menu_effect;
149 static Timer display_level_info;
150 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
151 static ButtonPanelMap tilegroups_map;
152 static ButtonPanelMap objects_map;
153 static std::string cur_tilegroup;
154 static std::string cur_objects;
155 static MouseCursor* mouse_select_object;
156 static GameObject* selected_game_object;
157
158 static square selection;
159 static SelectionMode le_selection_mode;
160 static SDL_Event event;
161 TileMapType active_tm;
162
163 int leveleditor(char* filename)
164 {
165   int last_time, now_time, i;
166
167   le_level = 1;
168
169   if(le_init() != 0)
170     return 1;
171
172   /* Clear screen: */
173
174   clearscreen(0, 0, 0);
175   updatescreen();
176
177   music_manager->halt_music();
178
179   while (SDL_PollEvent(&event))
180   {}
181
182   if(filename != NULL)
183     if(le_load_level_subset(filename))
184       return 1;
185
186   while(true)
187   {
188     last_time = SDL_GetTicks();
189     le_frame++;
190
191     le_checkevents();
192
193     if(Menu::current() == select_tilegroup_menu)
194     {
195       if(select_tilegroup_menu_effect.check())
196       {
197         select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
198                                        66,-0.5,0.5);
199       }
200       else
201         select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
202     }
203     else if(Menu::current() == select_objects_menu)
204     {
205       if(select_objects_menu_effect.check())
206       {
207         select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
208       }
209       else
210         select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
211     }
212
213     if(le_world != NULL)
214     {
215       /* making events results to be in order */
216
217       /* draw the level */
218       le_drawlevel();
219     }
220     else
221       clearscreen(0, 0, 0);
222
223     /* draw editor interface */
224     le_drawinterface();
225
226     Menu* menu = Menu::current();
227     if(menu)
228     {
229       menu->draw();
230       menu->action();
231
232       if(menu == leveleditor_menu)
233       {
234         switch (leveleditor_menu->check())
235         {
236         case MNID_RETURNLEVELEDITOR:
237           if(le_world != NULL)
238             Menu::set_current(0);
239           else
240             Menu::set_current(leveleditor_menu);
241           break;
242         case MNID_SUBSETSETTINGS:
243           update_subset_settings_menu();
244           break;
245         case MNID_QUITLEVELEDITOR:
246           done = 1;
247           break;
248         }
249       }
250       else if(menu == level_settings_menu)
251       {
252         switch (level_settings_menu->check())
253         {
254         case MNID_APPLY:
255           apply_level_settings_menu();
256           Menu::set_current(NULL);
257           break;
258
259         default:
260           break;
261         }
262       }
263       else if(menu == select_tilegroup_menu)
264       {
265         int it = -1;
266         switch (it = select_tilegroup_menu->check())
267         {
268         default:
269           if(it >= 0)
270           {
271             cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
272             Menu::set_current(0);
273             cur_objects = "";
274
275           }
276           break;
277         }
278       }
279       else if(menu == select_objects_menu)
280       {
281         int it = -1;
282         switch (it = select_objects_menu->check())
283         {
284         default:
285           if(it >= 0)
286           {
287             cur_objects = select_objects_menu->get_item_by_id(it).text;
288             cur_tilegroup = "";
289
290             Menu::set_current(0);
291           }
292           break;
293         }
294       }
295       else if(menu == subset_load_menu)
296       {
297         switch (i = subset_load_menu->check())
298         {
299         case 0:
300           break;
301         default:
302           if(i >= 1)
303           {
304             if(le_load_level_subset(level_subsets.item[i-1]))
305               return 1;
306           }
307           break;
308         }
309       }
310       else if(menu == subset_new_menu)
311       {
312         if(subset_new_menu->item[2].input[0] == '\0')
313           subset_new_menu->item[3].kind = MN_DEACTIVE;
314         else
315         {
316           subset_new_menu->item[3].kind = MN_ACTION;
317
318           switch (i = subset_new_menu->check())
319           {
320           case MNID_CREATESUBSET:
321             LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
322             le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
323             leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
324             le_goto_level(1);
325             subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
326
327             Menu::set_current(subset_settings_menu);
328             break;
329           }
330         }
331       }
332       else if(menu == subset_settings_menu)
333       {
334         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  )
335           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
336         else
337           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
338
339         switch (i = subset_settings_menu->check())
340         {
341         case MNID_SUBSETSAVECHANGES:
342           save_subset_settings_menu();
343           Menu::set_current(leveleditor_menu);
344           break;
345         }
346       }
347     }
348
349     MouseCursor::current()->draw();
350
351     if(done)
352     {
353       le_quit();
354       return 0;
355     }
356
357     ++global_frame_counter;
358
359     SDL_Delay(25);
360     now_time = SDL_GetTicks();
361     if (now_time < last_time + FPS)
362       SDL_Delay(last_time + FPS - now_time);    /* delay some time */
363
364     flipscreen();
365   }
366
367   return done;
368 }
369
370 int le_load_level_subset(char *filename)
371 {
372   le_level_subset->load(filename);
373   leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
374   le_level = 1;
375   le_goto_level(1);
376
377   //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
378
379   Menu::set_current(NULL);
380
381   return 0;
382 }
383
384 void le_init_menus()
385 {
386   int i;
387
388   leveleditor_menu = new Menu();
389   subset_load_menu = new Menu();
390   subset_new_menu  = new Menu();
391   subset_settings_menu = new Menu();
392   level_settings_menu  = new Menu();
393   select_tilegroup_menu  = new Menu();
394   select_objects_menu = new Menu();
395
396   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
397   leveleditor_menu->additem(MN_HL,"",0,0);
398   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
399   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
400   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
401   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
402   leveleditor_menu->additem(MN_HL,"",0,0);
403   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
404
405   Menu::set_current(leveleditor_menu);
406
407   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
408   subset_load_menu->additem(MN_HL, "", 0, 0);
409
410   for(i = 0; i < level_subsets.num_items; ++i)
411   {
412     subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
413   }
414   subset_load_menu->additem(MN_HL,"",0,0);
415   subset_load_menu->additem(MN_BACK,"Back",0,0);
416
417   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
418   subset_new_menu->additem(MN_HL,"",0,0);
419   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
420   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
421   subset_new_menu->additem(MN_HL,"",0,0);
422   subset_new_menu->additem(MN_BACK,"Back",0,0);
423
424   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
425   subset_settings_menu->additem(MN_HL,"",0,0);
426   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
427   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
428   subset_settings_menu->additem(MN_HL,"",0,0);
429   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
430   subset_settings_menu->additem(MN_HL,"",0,0);
431   subset_settings_menu->additem(MN_BACK,"Back",0,0);
432
433   level_settings_menu->arrange_left = true;
434   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
435   level_settings_menu->additem(MN_HL,"",0,0);
436   level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
437   level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
438   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
439   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
440   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
441   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
442   level_settings_menu->additem(MN_NUMFIELD,    "Height  ",0,0,MNID_HEIGHT);
443   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
444   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
445   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
446   level_settings_menu->additem(MN_NUMFIELD,    "Top Red     ",0,0,MNID_TopRed);
447   level_settings_menu->additem(MN_NUMFIELD,    "Top Green   ",0,0,MNID_TopGreen);
448   level_settings_menu->additem(MN_NUMFIELD,    "Top Blue    ",0,0,MNID_TopBlue);
449   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red  ",0,0,MNID_BottomRed);
450   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
451   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue ",0,0,MNID_BottomBlue);
452   level_settings_menu->additem(MN_HL,"",0,0);
453   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
454
455   select_tilegroup_menu->arrange_left = true;
456   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
457   select_tilegroup_menu->additem(MN_HL,"",0,0);
458   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
459   int tileid = 1;
460   for(std::set<TileGroup>::iterator it = tilegroups->begin();
461         it != tilegroups->end(); ++it )
462     {
463       select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
464       tileid++;
465       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
466       i = 0;
467
468       for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
469           sit != (*it).tiles.end(); ++sit, ++i)
470       {
471         std::string imagefile = "/images/tilesets/" ;
472         bool only_editor_image = false;
473         if(!TileManager::instance()->get(*sit)->filenames.empty())
474         {
475           imagefile += TileManager::instance()->get(*sit)->filenames[0];
476         }
477         else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
478         {
479           imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
480           only_editor_image = true;
481         }
482         else
483         {
484           imagefile += "notile.png";
485         }
486         Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
487                                     0, 0, 32, 32);
488         if(!only_editor_image)
489           if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
490           {
491             imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
492             button->add_icon(imagefile,32,32);
493           }
494         tilegroups_map[it->name]->additem(button, *sit);
495       }
496     }
497   select_tilegroup_menu->additem(MN_HL,"",0,0);
498
499   select_objects_menu->arrange_left = true;
500   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
501   select_objects_menu->additem(MN_HL,"",0,0);
502   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
503   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
504
505   for(int i = 0; i < NUM_BadGuyKinds; ++i)
506   {
507     BadGuy bad_tmp(0,0,BadGuyKind(i),false);
508     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
509     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));
510   }
511
512   select_objects_menu->additem(MN_HL,"",0,0);
513
514 }
515
516 int le_init()
517 {
518
519
520   level_subsets = dsubdirs("/levels", "level1.stl");
521   le_level_subset = new LevelSubset;
522
523   le_world = NULL;
524   selected_game_object = NULL;
525
526   active_tm = TM_IA;
527   le_show_grid = true;
528   show_selections = true;
529   scroll_x = 0;
530
531   done = 0;
532   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
533   le_level_changed = false;
534   le_help_shown = false;
535
536   le_mouse_pressed[LEFT] = false;
537   le_mouse_pressed[RIGHT] = false;
538
539   le_mouse_clicked[LEFT] = false;
540   le_mouse_clicked[RIGHT] = false;
541
542   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
543
544   select_tilegroup_menu_effect.init(false);
545   select_objects_menu_effect.init(false);
546   display_level_info.init(false);
547
548   /* Load buttons */
549   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
550   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
551   le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
552   le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
553   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
554   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
555   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
556   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
557   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
558   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
559   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
560   le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
561   le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
562   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
563   le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
564   le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
565   le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
566   le_object_properties_bt->set_active(false);
567
568   mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
569   mouse_select_object->set_mid(16,16);
570
571   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
572   le_tilemap_panel->set_button_size(32,10);
573   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
574   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0),TM_IA);
575   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
576   le_tilemap_panel->highlight_last(true);
577   le_tilemap_panel->set_last_clicked(TM_IA);
578
579   le_current.Init();
580
581   le_init_menus();
582
583   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
584
585
586   return 0;
587 }
588
589 void update_level_settings_menu()
590 {
591   char str[80];
592   int i;
593
594   level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_world->get_level()->name.c_str());
595   level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_world->get_level()->author.c_str());
596
597   string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
598   string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
599   string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
600   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
601   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
602   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
603
604   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_world->get_level()->song_title.c_str())) != -1)
605     level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
606   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_world->get_level()->bkgd_image.c_str())) != -1)
607     level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
608   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_world->get_level()->particle_system.c_str())) != -1)
609     level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
610
611   sprintf(str,"%d",le_world->get_level()->width);
612   level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
613   sprintf(str,"%d",le_world->get_level()->height);
614   level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
615   sprintf(str,"%d",le_world->get_level()->time_left);
616   level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
617   sprintf(str,"%2.0f",le_world->get_level()->gravity);
618   level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
619   sprintf(str,"%d",le_world->get_level()->bkgd_speed);
620   level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
621   sprintf(str,"%d",le_world->get_level()->bkgd_top.red);
622   level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
623   sprintf(str,"%d",le_world->get_level()->bkgd_top.green);
624   level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
625   sprintf(str,"%d",le_world->get_level()->bkgd_top.blue);
626   level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
627   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.red);
628   level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
629   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.green);
630   level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
631   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.blue);
632   level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
633 }
634
635 void update_subset_settings_menu()
636 {
637   subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
638   subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
639 }
640
641 void apply_level_settings_menu()
642 {
643   int i;
644   i = false;
645   le_level_changed = true;
646
647   le_world->get_level()->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
648   le_world->get_level()->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
649
650   if(le_world->get_level()->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
651   {
652     le_world->get_level()->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
653     i = true;
654   }
655
656   if(le_world->get_level()->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
657   {
658     le_world->get_level()->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
659   }
660
661   if(i)
662   {
663     le_world->get_level()->load_gfx();
664   }
665
666   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
667
668   le_world->get_level()->change_width(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
669   le_world->get_level()->change_height(atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
670   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
671   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
672   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
673   le_world->get_level()->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
674   le_world->get_level()->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
675   le_world->get_level()->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
676   le_world->get_level()->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
677   le_world->get_level()->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
678   le_world->get_level()->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
679 }
680
681 void save_subset_settings_menu()
682 {
683   le_level_subset->title = subset_settings_menu->item[2].input;
684   le_level_subset->description = subset_settings_menu->item[3].input;
685   le_level_subset->save();
686   le_level_changed = false;
687 }
688
689 void le_unload_level()
690 {
691   if(le_level_changed)
692   {
693     le_drawlevel();
694     le_drawinterface();
695     char str[1024];
696     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
697     if(confirm_dialog(str))
698     {
699       le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
700     }
701   }
702
703   delete le_world;
704   le_level_changed = false;
705 }
706
707 void le_goto_level(int levelnb)
708 {
709   le_unload_level();
710   le_world = new World(le_level_subset->name, levelnb);
711   display_level_info.start(2500);
712   le_level = levelnb;
713 }
714
715 void le_quit(void)
716 {
717   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
718
719   le_unload_level();
720   delete le_selection;
721   delete leveleditor_menu;
722   delete subset_load_menu;
723   delete subset_new_menu;
724   delete subset_settings_menu;
725   delete level_settings_menu;
726   delete select_tilegroup_menu;
727   delete select_objects_menu;
728   delete le_save_level_bt;
729   delete le_exit_bt;
730   delete le_test_level_bt;
731   delete le_next_level_bt;
732   delete le_previous_level_bt;
733   delete le_move_right_bt;
734   delete le_move_left_bt;
735   delete le_move_up_bt;
736   delete le_move_down_bt;
737   delete le_rubber_bt;
738   delete le_select_mode_one_bt;
739   delete le_select_mode_two_bt;
740   delete le_settings_bt;
741   delete le_tilegroup_bt;
742   delete le_objects_bt;
743   delete le_tilemap_panel;
744   delete le_object_select_bt;
745   delete le_object_properties_bt;
746   delete mouse_select_object;
747
748   delete le_level_subset;
749   le_level_subset = 0;
750
751   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
752       i != tilegroups_map.end(); ++i)
753   {
754     delete i->second;
755   }
756   for(ButtonPanelMap::iterator i = objects_map.begin();
757       i != objects_map.end(); ++i)
758   {
759     delete i->second;
760   }
761 }
762
763 void le_drawminimap()
764 {
765   if(le_world == NULL)
766     return;
767
768   int mini_tile_width;
769   if(screen->w - 64 > le_world->get_level()->width * 4)
770     mini_tile_width = 4;
771   else if(screen->w - 64 > le_world->get_level()->width * 2)
772     mini_tile_width = 2;
773   else
774     mini_tile_width = 1;
775   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
776
777   int mini_tile_height;
778   if(screen->h - 64 > le_world->get_level()->height * 4)
779     mini_tile_height = 4;
780   else if(screen->h - 64 > le_world->get_level()->height * 2)
781     mini_tile_height = 2;
782   else
783     mini_tile_height = 1;
784
785   for (int y = 0; y < le_world->get_level()->height; ++y)
786     for (int x = 0; x < le_world->get_level()->width; ++x)
787     {
788
789       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
790
791       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
792
793       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
794
795     }
796
797   fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 128);
798
799   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
800   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 200);
801   fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 200);
802   fillrect(left_offset + (pos_x/32)*mini_tile_width, le_world->get_level()->height*mini_tile_height-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
803
804 }
805
806 void le_drawinterface()
807 {
808   int x,y;
809   char str[80];
810
811   if(le_world != NULL)
812   {
813     /* draw a grid (if selected) */
814     if(le_show_grid)
815     {
816       for(x = 0; x < VISIBLE_TILES_X; x++)
817         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
818       for(y = 0; y < VISIBLE_TILES_Y; y++)
819         fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
820     }
821   }
822
823   if(show_minimap) // use_gl because the minimap isn't shown correctly in software mode. Any idea? FIXME Possible reasons: SDL_SoftStretch is a hack itsself || an alpha blitting issue SDL can't handle in software mode
824     le_drawminimap();
825
826   if(show_selections && MouseCursor::current() != mouse_select_object)
827   {
828     if(le_selection_mode == CURSOR)
829     {
830       if(le_current.IsTile())
831         le_selection->draw(cursor_x - pos_x, cursor_y - pos_y);
832     }
833     else if(le_selection_mode == SQUARE)
834     {
835       int w, h;
836       le_highlight_selection();
837       /* draw current selection */
838       w = selection.x2 - selection.x1;
839       h = selection.y2 - selection.y1;
840       fillrect(selection.x1 - pos_x, selection.y1 - pos_y, w, SELECT_W, SELECT_CLR);
841       fillrect(selection.x1 - pos_x + w, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
842       fillrect(selection.x1 - pos_x, selection.y1 - pos_y + h, w, SELECT_W, SELECT_CLR);
843       fillrect(selection.x1 - pos_x, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
844     }
845   }
846
847
848   /* draw button bar */
849   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
850
851   if(le_current.IsTile())
852   {
853     Tile::draw(screen->w - 32, screen->h - 32, le_current.tile);
854     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
855       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);
856   }
857   if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
858   {
859     le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
860     le_current.obj->draw_on_screen(cursor_x,cursor_y);
861   }
862
863   if(mouse_select_object && selected_game_object != NULL)
864   {
865     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,selected_game_object->base.width,3,255,0,0,255);
866     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
867     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y+selected_game_object->base.height,selected_game_object->base.width,3,255,0,0,255);
868     fillrect(selected_game_object->base.x-pos_x+selected_game_object->base.width,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
869   }
870
871   if(le_world != NULL)
872   {
873     le_save_level_bt->draw();
874     le_exit_bt->draw();
875     le_test_level_bt->draw();
876     le_next_level_bt->draw();
877     le_previous_level_bt->draw();
878     le_rubber_bt->draw();
879     if(le_selection_mode == SQUARE)
880       le_select_mode_one_bt->draw();
881     else if(le_selection_mode == CURSOR)
882       le_select_mode_two_bt->draw();
883     le_settings_bt->draw();
884     le_move_right_bt->draw();
885     le_move_left_bt->draw();
886     le_move_up_bt->draw();
887     le_move_down_bt->draw();
888     le_tilegroup_bt->draw();
889     le_objects_bt->draw();
890     if(!cur_tilegroup.empty())
891       tilegroups_map[cur_tilegroup]->draw();
892     else if(!cur_objects.empty())
893     {
894       objects_map[cur_objects]->draw();
895     }
896
897     le_tilemap_panel->draw();
898
899     if(!cur_objects.empty())
900     {
901       le_object_select_bt->draw();
902       le_object_properties_bt->draw();
903     }
904
905     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
906     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
907
908     if(!le_help_shown)
909       white_small_text->draw("F1 for Help", 10, 430, 1);
910
911     if(display_level_info.check())
912       white_text->drawf(le_world->get_level()->name.c_str(), 0, 0, A_HMIDDLE, A_TOP, 0);
913   }
914   else
915   {
916     if(!Menu::current())
917       white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
918     else
919       white_small_text->draw("No Level Subset loaded", 10, 430, 1);
920   }
921
922 }
923
924 void le_drawlevel()
925 {
926   unsigned int y,x;
927   Uint8 a;
928
929   /* Draw the real background */
930   if (le_world->get_level()->img_bkgd)
931     le_world->get_level()->draw_bg();
932   else
933     drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
934
935   if(le_current.IsTile())
936   {
937     Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
938     if(!TileManager::instance()->get(le_current.tile)->images.empty())
939       fillrect(cursor_x-pos_x,cursor_y-pos_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);
940   }
941   if(le_current.IsObject())
942   {
943     le_current.obj->move_to(cursor_x, cursor_y);
944   }
945
946   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
947
948   for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_world->get_level()->height; ++y)
949     for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
950     {
951
952       if(active_tm == TM_BG)
953         a = 255;
954       else
955         a = 128;
956
957       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->bg_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
958
959       if(active_tm == TM_IA)
960         a = 255;
961       else
962         a = 128;
963
964       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
965
966       if(active_tm == TM_FG)
967         a = 255;
968       else
969         a = 128;
970
971       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->fg_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
972
973       /* draw whats inside stuff when cursor is selecting those */
974       /* (draw them all the time - is this the right behaviour?) */
975       Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)]);
976       if(edit_image && !edit_image->editor_images.empty())
977         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
978
979     }
980
981   /* Draw the Bad guys: */
982   for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
983   {
984     /* to support frames: img_bsod_left[(frame / 5) % 4] */
985
986     scroll_x = pos_x;
987     scroll_y = pos_y;
988     (*it)->draw();
989   }
990
991
992   /* Draw the player: */
993   /* for now, the position is fixed at (100, 240) */
994   largetux.walk_right->draw( 100 - pos_x, 240 - pos_y);
995 }
996
997 void le_change_object_properties(GameObject *pobj)
998 {
999   Surface* cap_screen = Surface::CaptureScreen();
1000   Menu* object_properties_menu = new Menu();
1001   bool loop = true;
1002
1003   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
1004   object_properties_menu->additem(MN_HL,"",0,0);
1005
1006   if(pobj->type() == "BadGuy")
1007   {
1008     BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1009     object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
1010     for(int i = 0; i < NUM_BadGuyKinds; ++i)
1011     {
1012       string_list_add_item(object_properties_menu->get_item_by_id(1).list,badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
1013       if(pbad->kind == i)
1014         object_properties_menu->get_item_by_id(1).list->active_item = i;
1015     }
1016     object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
1017   }
1018
1019   object_properties_menu->additem(MN_HL,"",0,0);
1020   object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
1021
1022   Menu::set_current(object_properties_menu);
1023
1024   while(loop)
1025   {
1026     SDL_Event event;
1027
1028     while (SDL_PollEvent(&event))
1029     {
1030       object_properties_menu->event(event);
1031     }
1032
1033     cap_screen->draw(0,0);
1034
1035     object_properties_menu->draw();
1036     object_properties_menu->action();
1037
1038     switch (object_properties_menu->check())
1039     {
1040     case 3:
1041       if(pobj->type() == "BadGuy")
1042       {
1043         BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1044         pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
1045         pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
1046         int i = 0;
1047         std::list<BadGuy*>::iterator it;
1048         for(it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1049           if((*it) == pbad)
1050             break;
1051         le_world->get_level()->badguy_data[i].kind = pbad->kind;
1052         le_world->get_level()->badguy_data[i].stay_on_platform = pbad->stay_on_platform;
1053         delete (*it);
1054         (*it) = new BadGuy(le_world->get_level()->badguy_data[i].x,le_world->get_level()->badguy_data[i].y,le_world->get_level()->badguy_data[i].kind,le_world->get_level()->badguy_data[i].stay_on_platform);
1055       }
1056       loop = false;
1057       break;
1058     default:
1059       break;
1060     }
1061
1062     if(Menu::current() == NULL)
1063       loop = false;
1064
1065     mouse_cursor->draw();
1066     flipscreen();
1067     SDL_Delay(25);
1068   }
1069
1070   delete cap_screen;
1071   Menu::set_current(0);
1072   delete object_properties_menu;
1073 }
1074
1075
1076 void le_checkevents()
1077 {
1078   SDLKey key;
1079   SDLMod keymod;
1080   Button* pbutton;
1081   int x,y;
1082
1083   keymod = SDL_GetModState();
1084
1085   while(SDL_PollEvent(&event))
1086   {
1087     if (Menu::current())
1088     {
1089       Menu::current()->event(event);
1090       if(!le_world && !Menu::current())
1091         Menu::set_current(leveleditor_menu);
1092     }
1093     else
1094     {
1095       mouse_cursor->set_state(MC_NORMAL);
1096
1097       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1098       if(event.type == SDL_KEYDOWN
1099           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1100               && (event.motion.x > 0
1101                   && event.motion.x < screen->w - 64 &&
1102                   event.motion.y > 0 && event.motion.y < screen->h)))
1103       {
1104         switch(event.type)
1105         {
1106         case SDL_KEYDOWN:       // key pressed
1107           key = event.key.keysym.sym;
1108           switch(key)
1109           {
1110           case SDLK_ESCAPE:
1111             Menu::set_current(leveleditor_menu);
1112             break;
1113           case SDLK_F1:
1114             if(le_world != NULL)
1115               le_showhelp();
1116             break;
1117           case SDLK_HOME:
1118             cursor_x = 0;
1119             pos_x = cursor_x;
1120             break;
1121           case SDLK_END:
1122             cursor_x = (le_world->get_level()->width * 32) - 32;
1123             pos_x = cursor_x;
1124             break;
1125           case SDLK_F9:
1126             le_show_grid = !le_show_grid;
1127             break;
1128           default:
1129             break;
1130           }
1131           break;
1132         case SDL_MOUSEBUTTONDOWN:
1133           if(event.button.button == SDL_BUTTON_LEFT)
1134           {
1135             le_mouse_pressed[LEFT] = true;
1136
1137             selection.x1 = event.motion.x + pos_x;
1138             selection.y1 = event.motion.y + pos_y;
1139             selection.x2 = event.motion.x + pos_x;
1140             selection.y2 = event.motion.y + pos_y;
1141           }
1142           else if(event.button.button == SDL_BUTTON_RIGHT)
1143           {
1144             le_mouse_pressed[RIGHT] = true;
1145           }
1146           break;
1147         case SDL_MOUSEBUTTONUP:
1148           if(event.button.button == SDL_BUTTON_LEFT)
1149           {
1150             le_mouse_pressed[LEFT] = false;
1151             le_mouse_clicked[LEFT] = true;
1152           }
1153           else if(event.button.button == SDL_BUTTON_RIGHT)
1154           {
1155             le_mouse_pressed[RIGHT] = false;
1156             le_mouse_clicked[RIGHT] = true;
1157           }
1158           break;
1159         case SDL_MOUSEMOTION:
1160
1161           if(!Menu::current())
1162           {
1163             x = event.motion.x;
1164             y = event.motion.y;
1165
1166             if(le_current.IsTile())
1167             {
1168               cursor_x = ((int)(pos_x + x) / 32) * 32;
1169               cursor_y = ((int)(pos_y + y) / 32) * 32;
1170             }
1171             else
1172             {
1173               cursor_x = x;
1174               cursor_y = y;
1175             }
1176
1177             if(le_mouse_pressed[LEFT])
1178             {
1179               selection.x2 = x + pos_x;
1180               selection.y2 = y + pos_y;
1181             }
1182
1183             if(le_mouse_pressed[RIGHT])
1184             {
1185               pos_x += -1 * event.motion.xrel;
1186               pos_y += -1 * event.motion.yrel;
1187             }
1188           }
1189           break;
1190         default:
1191           break;
1192         }
1193       }
1194       else if(event.type == SDL_QUIT) /* window closing */
1195       {
1196       done = 1;
1197       }
1198     }
1199
1200     if(le_world != NULL)
1201     {
1202       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 &&
1203           event.motion.y > 0 && event.motion.y < screen->h)))
1204       {
1205         le_mouse_pressed[LEFT] = false;
1206         le_mouse_pressed[RIGHT] = false;
1207
1208         if(!Menu::current())
1209         {
1210           /* Check for button events */
1211           le_test_level_bt->event(event);
1212           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1213             le_testlevel();
1214           le_save_level_bt->event(event);
1215           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1216             le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
1217           le_exit_bt->event(event);
1218           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1219           {
1220             Menu::set_current(leveleditor_menu);
1221           }
1222           le_next_level_bt->event(event);
1223           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1224           {
1225             if(le_level < le_level_subset->levels)
1226             {
1227               le_goto_level(le_level+1);
1228             }
1229             else
1230             {
1231               Level new_lev;
1232               char str[1024];
1233               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1234               if(confirm_dialog(str))
1235               {
1236                 new_lev.init_defaults();
1237                 new_lev.save(le_level_subset->name.c_str(),le_level+1);
1238                 le_level_subset->levels = le_level;
1239                 le_goto_level(le_level);
1240               }
1241             }
1242           }
1243           le_previous_level_bt->event(event);
1244           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1245           {
1246             if(le_level > 1)
1247               le_goto_level(le_level -1);
1248           }
1249           le_rubber_bt->event(event);
1250           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1251             le_current.Tile(0);
1252
1253           if(!cur_objects.empty())
1254           {
1255             le_object_select_bt->event(event);
1256             if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1257             {
1258               MouseCursor::set_current(mouse_select_object);
1259             }
1260
1261             le_object_properties_bt->event(event);
1262             if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1263             {
1264               le_change_object_properties(selected_game_object);
1265             }
1266           }
1267
1268
1269           if(le_selection_mode == SQUARE)
1270           {
1271             le_select_mode_one_bt->event(event);
1272             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1273               le_selection_mode = CURSOR;
1274           }
1275           else
1276           {
1277             le_select_mode_two_bt->event(event);
1278             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1279               le_selection_mode = SQUARE;
1280           }
1281           ButtonPanelMap::iterator it;
1282           le_tilegroup_bt->event(event);
1283           switch (le_tilegroup_bt->get_state())
1284           {
1285           case BUTTON_CLICKED:
1286             Menu::set_current(select_tilegroup_menu);
1287             select_tilegroup_menu_effect.start(200);
1288             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1289             break;
1290           case BUTTON_WHEELUP:
1291             if(cur_tilegroup.empty())
1292             {
1293               cur_tilegroup = tilegroups_map.begin()->first;
1294             }
1295             else
1296             {
1297               it = tilegroups_map.find(cur_tilegroup);
1298               if((++it) == tilegroups_map.end())
1299               {
1300                 cur_tilegroup = tilegroups_map.begin()->first;
1301               }
1302               else
1303               {
1304                 cur_tilegroup = (*it).first;
1305               }
1306             }
1307
1308             cur_objects = "";
1309             break;
1310           case BUTTON_WHEELDOWN:
1311             it = tilegroups_map.find(cur_tilegroup);
1312             if(it == tilegroups_map.begin())
1313             {
1314               cur_tilegroup = tilegroups_map.rbegin()->first;
1315               cur_objects = "";
1316               break;
1317             }
1318             if(--it != --tilegroups_map.begin())
1319               cur_tilegroup = (*it).first;
1320             else
1321               cur_tilegroup = tilegroups_map.rbegin()->first;
1322
1323             cur_objects = "";
1324             break;
1325           default:
1326             break;
1327           }
1328
1329           le_objects_bt->event(event);
1330           switch (le_objects_bt->get_state())
1331           {
1332           case BUTTON_CLICKED:
1333             Menu::set_current(select_objects_menu);
1334             select_objects_menu_effect.start(200);
1335             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1336             break;
1337           case BUTTON_WHEELUP:
1338             it = objects_map.find(cur_objects);
1339             if(it == objects_map.end())
1340             {
1341               cur_objects = objects_map.begin()->first;
1342               cur_tilegroup = "";
1343               break;
1344             }
1345             if(++it != objects_map.end())
1346               cur_objects = (*it).first;
1347             else
1348               cur_objects = objects_map.begin()->first;
1349
1350             cur_tilegroup = "";
1351             break;
1352           case BUTTON_WHEELDOWN:
1353             it = objects_map.find(cur_objects);
1354             if(it == objects_map.begin())
1355             {
1356               cur_objects = objects_map.rbegin()->first;
1357               cur_tilegroup = "";
1358               break;
1359             }
1360             if(--it != --objects_map.begin())
1361               cur_objects = (*it).first;
1362             else
1363               cur_objects = objects_map.rbegin()->first;
1364
1365             cur_tilegroup = "";
1366             break;
1367             break;
1368           default:
1369             break;
1370           }
1371
1372           le_settings_bt->event(event);
1373           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1374           {
1375             update_level_settings_menu();
1376             Menu::set_current(level_settings_menu);
1377           }
1378           if(!cur_tilegroup.empty())
1379           {
1380             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1381             {
1382               if(pbutton->get_state() == BUTTON_CLICKED)
1383               {
1384                 le_current.Tile(pbutton->get_tag());
1385               }
1386             }
1387           }
1388           else if(!cur_objects.empty())
1389           {
1390             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1391             {
1392               if(pbutton->get_state() == BUTTON_CLICKED)
1393               {
1394                 le_current.Object(pbutton->get_game_object());
1395               }
1396             }
1397           }
1398
1399           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1400           {
1401             if(pbutton->get_state() == BUTTON_CLICKED)
1402             {
1403               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1404             }
1405           }
1406         }
1407         else
1408         {
1409           le_settings_bt->event(event);
1410           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1411           {
1412             Menu::set_current(0);
1413           }
1414           le_tilegroup_bt->event(event);
1415           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1416           {
1417             Menu::set_current(0);
1418           }
1419           le_objects_bt->event(event);
1420           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1421           {
1422             Menu::set_current(0);
1423           }
1424         }
1425       }
1426
1427       if(!Menu::current() && !show_minimap)
1428       {
1429         if(le_mouse_pressed[LEFT])
1430         {
1431           if(MouseCursor::current() != mouse_select_object)
1432           {
1433             if(le_current.IsTile())
1434               le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1435           }
1436         }
1437         else if(le_mouse_clicked[LEFT])
1438         {
1439           if(MouseCursor::current() == mouse_select_object)
1440           {
1441             int i = 0;
1442             bool object_got_hit = false;
1443             base_type cursor_base;
1444             if(le_current.IsTile())
1445             {
1446             cursor_base.x = cursor_x;
1447             cursor_base.y = cursor_y;
1448             }
1449             else if(le_current.IsObject())
1450             {
1451             cursor_base.x = cursor_x + pos_x;
1452             cursor_base.y = cursor_y + pos_y;       
1453             }
1454             cursor_base.width = 32;
1455             cursor_base.height = 32;
1456
1457             for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1458               if(rectcollision(cursor_base,(*it)->base))
1459               {
1460                 selected_game_object = (*it);
1461                 object_got_hit = true;
1462                 break;
1463               }
1464
1465             if(!object_got_hit)
1466             {
1467               selected_game_object = NULL;
1468               le_object_properties_bt->set_active(false);
1469             }
1470             else
1471               le_object_properties_bt->set_active(true);
1472
1473             MouseCursor::set_current(mouse_cursor);
1474
1475           }
1476           else
1477           {
1478             if(le_current.IsObject())
1479             {
1480               le_level_changed  = true;
1481               std::string type = le_current.obj->type();
1482               if(type == "BadGuy")
1483               {
1484                 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1485
1486                 le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1487                 le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1488               }
1489             }
1490           }
1491           
1492           le_mouse_clicked[LEFT] = false;
1493
1494         }
1495       }
1496     }
1497   }
1498   if(!Menu::current())
1499   {
1500     show_minimap = false;
1501
1502     le_move_left_bt->event(event);
1503     le_move_right_bt->event(event);
1504     le_move_up_bt->event(event);
1505     le_move_down_bt->event(event);
1506     switch(le_move_left_bt->get_state())
1507     {
1508     case BUTTON_PRESSED:
1509       pos_x -= KEYBOARD_SPEED;
1510       show_minimap = true;
1511       break;
1512     case BUTTON_HOVER:
1513       pos_x -= MOUSE_SPEED;
1514       show_minimap = true;
1515       break;
1516     case BUTTON_CLICKED:
1517       show_minimap = true;
1518       break;
1519     default:
1520       break;
1521     }
1522
1523     switch(le_move_right_bt->get_state())
1524     {
1525     case BUTTON_PRESSED:
1526       pos_x += KEYBOARD_SPEED;
1527       show_minimap = true;
1528       break;
1529     case BUTTON_HOVER:
1530       pos_x += MOUSE_SPEED;
1531       show_minimap = true;
1532       break;
1533     case BUTTON_CLICKED:
1534       show_minimap = true;
1535       break;
1536     default:
1537       break;
1538     }
1539
1540     switch(le_move_up_bt->get_state())
1541     {
1542     case BUTTON_PRESSED:
1543       pos_y -= KEYBOARD_SPEED;
1544       show_minimap = true;
1545       break;
1546     case BUTTON_HOVER:
1547       pos_y -= MOUSE_SPEED;
1548       show_minimap = true;
1549       break;
1550     case BUTTON_CLICKED:
1551       show_minimap = true;
1552       break;
1553     default:
1554       break;
1555     }
1556
1557     switch(le_move_down_bt->get_state())
1558     {
1559     case BUTTON_PRESSED:
1560       pos_y += KEYBOARD_SPEED;
1561       show_minimap = true;
1562       break;
1563     case BUTTON_HOVER:
1564       pos_y += MOUSE_SPEED;
1565       show_minimap = true;
1566       break;
1567     case BUTTON_CLICKED:
1568       show_minimap = true;
1569       break;
1570     default:
1571       break;
1572     }
1573
1574       /* checking if pos_x and pos_y is within the limits... */
1575       if(pos_x > (le_world->get_level()->width * 32 + 32*2) - screen->w)
1576         pos_x = (le_world->get_level()->width * 32 + 32*2) - screen->w;
1577       if(pos_x < 0)
1578         pos_x = 0;
1579
1580       if(pos_y > (le_world->get_level()->height * 32) - screen->h)
1581         pos_y = (le_world->get_level()->height * 32) - screen->h;
1582       if(pos_y < 0)
1583         pos_y = 0;
1584
1585   }
1586
1587 }
1588
1589 void le_highlight_selection()
1590 {
1591   int x1, x2, y1, y2;
1592
1593   if(selection.x1 < selection.x2)
1594   {
1595     x1 = selection.x1;
1596     x2 = selection.x2;
1597   }
1598   else
1599   {
1600     x1 = selection.x2;
1601     x2 = selection.x1;
1602   }
1603   if(selection.y1 < selection.y2)
1604   {
1605     y1 = selection.y1;
1606     y2 = selection.y2;
1607   }
1608   else
1609   {
1610     y1 = selection.y2;
1611     y2 = selection.y1;
1612   }
1613
1614   x1 /= 32;
1615   x2 /= 32;
1616   y1 /= 32;
1617   y2 /= 32;
1618
1619   fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1620 }
1621
1622 void le_change(float x, float y, int tm, unsigned int c)
1623 {
1624   if(le_world != NULL)
1625   {
1626     int xx,yy;
1627     int x1, x2, y1, y2;
1628     unsigned int i = 0;
1629
1630     le_level_changed = true;
1631
1632     switch(le_selection_mode)
1633     {
1634     case CURSOR:
1635       le_world->get_level()->change(x,y,tm,c);
1636
1637       base_type cursor_base;
1638       cursor_base.x = x;
1639       cursor_base.y = y;
1640       cursor_base.width = 32;
1641       cursor_base.height = 32;
1642
1643       /* if there is a bad guy over there, remove it */
1644       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1645         if(rectcollision(cursor_base,(*it)->base))
1646         {
1647           delete (*it);
1648           le_world->bad_guys.erase(it);
1649           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1650           break;
1651         }
1652
1653       break;
1654     case SQUARE:
1655       if(selection.x1 < selection.x2)
1656       {
1657         x1 = selection.x1;
1658         x2 = selection.x2;
1659       }
1660       else
1661       {
1662         x1 = selection.x2;
1663         x2 = selection.x1;
1664       }
1665       if(selection.y1 < selection.y2)
1666       {
1667         y1 = selection.y1;
1668         y2 = selection.y2;
1669       }
1670       else
1671       {
1672         y1 = selection.y2;
1673         y2 = selection.y1;
1674       }
1675
1676       x1 /= 32;
1677       x2 /= 32;
1678       y1 /= 32;
1679       y2 /= 32;
1680
1681       /* if there is a bad guy over there, remove it */
1682       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
1683           it != le_world->bad_guys.end(); /* will be at end of loop */)
1684       {
1685         if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
1686             && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
1687         {
1688           delete (*it);
1689           it = le_world->bad_guys.erase(it);
1690           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1691           continue;
1692         }
1693         else
1694         {
1695           ++i;
1696           ++it;
1697         }
1698       }
1699
1700       for(xx = x1; xx <= x2; xx++)
1701         for(yy = y1; yy <= y2; yy++)
1702         {
1703           le_world->get_level()->change(xx*32, yy*32, tm, c);
1704
1705         }
1706       break;
1707     default:
1708       break;
1709     }
1710   }
1711 }
1712
1713 void le_testlevel()
1714 {
1715   //Make sure a time value is set when testing the level
1716   if(le_world->get_level()->time_left == 0)
1717     le_world->get_level()->time_left = 250;
1718
1719   le_world->get_level()->save("test", le_level);
1720
1721   GameSession session("test",le_level, ST_GL_TEST);
1722   session.run();
1723   player_status.reset();
1724
1725   music_manager->halt_music();
1726
1727   Menu::set_current(NULL);
1728   World::set_current(le_world);
1729 }
1730
1731 void le_showhelp()
1732 {
1733   bool tmp_show_grid = le_show_grid;
1734   SelectionMode temp_le_selection_mode = le_selection_mode;
1735   le_selection_mode = NONE;
1736   show_selections = true;
1737   le_show_grid = false;
1738   le_help_shown = true;
1739
1740   drawgradient(Color(0,0,0), Color(255,255,255));
1741   le_drawinterface();
1742
1743   SDL_Event event;
1744   unsigned int i, done_;
1745   char *text[] = {
1746
1747                    " - Supertux level editor tutorial - ",
1748                    "",
1749                    "To make your map, click the       ",
1750                    "tilegroup button and choose a     ",
1751                    "tilegroup.",
1752                    "Pick a tile and simply hold down  ",
1753                    "the left mouse button over the map",
1754                    "to \"paint\" your selection over",
1755                    "the screen.",
1756                    "",
1757                    "There are three layers for painting",
1758                    "tiles upon, Background layer,",
1759                    "the Interactive layer, and the",
1760                    "Foreground layer, which can be",
1761                    "toggled by the BkGrd, IntAct and",
1762                    "FrGrd buttons. The Foreground and",
1763                    "Background layers do not effect",
1764                    "Tux in the gameplay, but lie in",
1765                    "front of him or lie behind him in",
1766                    "his adventures.",
1767                  };
1768
1769   char *text2[] = {
1770
1771                     " - Supertux level editor tutorial - ",
1772                     "",
1773                     "The tiles placed on",
1774                     "the Interactive layer are those",
1775                     "which actually effect Tux in the",
1776                     "game.",
1777                     "",
1778                     "Click the objects menu to put ",
1779                     "bad guys and other objects in the",
1780                     "game. Unlike placing tiles, you",
1781                     "cannot \"paint\" enemies. Click",
1782                     "them onto the screen one at a time.",
1783                     "",
1784                     "To change the settings of your",
1785                     "level, click the button with the",
1786                     "screwdriver and wrench. From here",
1787                     "you can change the background,",
1788                     "music, length of the level,",
1789                     "and more."
1790                   };
1791
1792   char *text3[] = {
1793
1794                     " - Supertux level editor tutorial - ",
1795                     "",
1796                     "You may have more than one level.",
1797                     "Pressing the up and down buttons",
1798                     "above the button bar lets you",
1799                     "choose which one you are working on.",
1800                     "",
1801                     "If you would like to speed up your",
1802                     "level editing, a useful trick is",
1803                     "to learn the keyboard shortcuts.",
1804                     "They are easy to learn, just right-",
1805                     "click on the buttons.",
1806                     "",
1807                     "Have fun making levels! If you make",
1808                     "some good ones, send them to us on",
1809                     "the SuperTux mailing list!",
1810                     "- SuperTux team"
1811                   };
1812
1813
1814
1815   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1816
1817   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1818     white_text->draw(text[i], 5, 80+(i*white_text->h), 1);
1819
1820   gold_text->drawf("Press Anything to Continue - Page 1/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1821
1822   flipscreen();
1823
1824   done_ = 0;
1825
1826   while(done_ == 0)
1827   {
1828     done_ = wait_for_event(event);
1829     SDL_Delay(50);
1830   }
1831
1832   drawgradient(Color(0,0,0), Color(255,255,255));
1833   le_drawinterface();
1834
1835
1836   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1837
1838   for(i = 0; i < sizeof(text2)/sizeof(char *); i++)
1839     white_text->draw(text2[i], 5, 80+(i*white_text->h), 1);
1840
1841   gold_text->drawf("Press Anything to Continue - Page 2/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1842
1843   flipscreen();
1844
1845   done_ = 0;
1846
1847   while(done_ == 0)
1848   {
1849     done_ = wait_for_event(event);
1850     SDL_Delay(50);
1851   }
1852
1853   drawgradient(Color(0,0,0), Color(255,255,255));
1854   le_drawinterface();
1855
1856
1857   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1858
1859   for(i = 0; i < sizeof(text3)/sizeof(char *); i++)
1860     white_text->draw(text3[i], 5, 80+(i*white_text->h), 1);
1861
1862   gold_text->drawf("Press Anything to Continue - Page 3/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1863
1864   flipscreen();
1865
1866   done_ = 0;
1867
1868   while(done_ == 0)
1869   {
1870     done_ = wait_for_event(event);
1871     SDL_Delay(50);
1872   }
1873
1874   show_selections = true;
1875   le_show_grid = tmp_show_grid;
1876   le_selection_mode = temp_le_selection_mode;
1877   le_help_shown = false;
1878 }