- fixed level editor crash
[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
646   le_world->get_level()->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
647   le_world->get_level()->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
648
649   if(le_world->get_level()->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
650   {
651     le_world->get_level()->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
652     i = true;
653   }
654
655   if(le_world->get_level()->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
656   {
657     le_world->get_level()->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
658   }
659
660   if(i)
661   {
662     le_world->get_level()->load_gfx();
663   }
664
665   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
666
667   le_world->get_level()->change_width(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
668   le_world->get_level()->change_height(atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
669   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
670   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
671   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
672   le_world->get_level()->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
673   le_world->get_level()->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
674   le_world->get_level()->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
675   le_world->get_level()->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
676   le_world->get_level()->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
677   le_world->get_level()->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
678 }
679
680 void save_subset_settings_menu()
681 {
682   le_level_subset->title = subset_settings_menu->item[2].input;
683   le_level_subset->description = subset_settings_menu->item[3].input;
684   le_level_subset->save();
685   le_level_changed = false;
686 }
687
688 void le_unload_level()
689 {
690   if(le_level_changed)
691   {
692     le_drawlevel();
693     le_drawinterface();
694     char str[1024];
695     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
696     if(confirm_dialog(str))
697     {
698       le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
699     }
700   }
701
702   delete le_world;
703   le_level_changed = false;
704 }
705
706 void le_goto_level(int levelnb)
707 {
708   le_unload_level();
709   le_world = new World(le_level_subset->name, levelnb);
710   display_level_info.start(2500);
711   le_level = levelnb;
712 }
713
714 void le_quit(void)
715 {
716   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
717
718   le_unload_level();
719   delete le_selection;
720   delete leveleditor_menu;
721   delete subset_load_menu;
722   delete subset_new_menu;
723   delete subset_settings_menu;
724   delete level_settings_menu;
725   delete select_tilegroup_menu;
726   delete select_objects_menu;
727   delete le_save_level_bt;
728   delete le_exit_bt;
729   delete le_test_level_bt;
730   delete le_next_level_bt;
731   delete le_previous_level_bt;
732   delete le_move_right_bt;
733   delete le_move_left_bt;
734   delete le_move_up_bt;
735   delete le_move_down_bt;
736   delete le_rubber_bt;
737   delete le_select_mode_one_bt;
738   delete le_select_mode_two_bt;
739   delete le_settings_bt;
740   delete le_tilegroup_bt;
741   delete le_objects_bt;
742   delete le_tilemap_panel;
743   delete le_object_select_bt;
744   delete le_object_properties_bt;
745   delete mouse_select_object;
746
747   delete le_level_subset;
748   le_level_subset = 0;
749
750   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
751       i != tilegroups_map.end(); ++i)
752   {
753     delete i->second;
754   }
755   for(ButtonPanelMap::iterator i = objects_map.begin();
756       i != objects_map.end(); ++i)
757   {
758     delete i->second;
759   }
760 }
761
762 void le_drawminimap()
763 {
764   if(le_world == NULL)
765     return;
766
767   int mini_tile_width;
768   if(screen->w - 64 > le_world->get_level()->width * 4)
769     mini_tile_width = 4;
770   else if(screen->w - 64 > le_world->get_level()->width * 2)
771     mini_tile_width = 2;
772   else
773     mini_tile_width = 1;
774   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
775
776   int mini_tile_height;
777   if(screen->h - 64 > le_world->get_level()->height * 4)
778     mini_tile_height = 4;
779   else if(screen->h - 64 > le_world->get_level()->height * 2)
780     mini_tile_height = 2;
781   else
782     mini_tile_height = 1;
783
784   for (int y = 0; y < le_world->get_level()->height; ++y)
785     for (int x = 0; x < le_world->get_level()->width; ++x)
786     {
787
788       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
789
790       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
791
792       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
793
794     }
795
796   fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 128);
797
798   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
799   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 200);
800   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);
801   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);
802
803 }
804
805 void le_drawinterface()
806 {
807   int x,y;
808   char str[80];
809
810   if(le_world != NULL)
811   {
812     /* draw a grid (if selected) */
813     if(le_show_grid)
814     {
815       for(x = 0; x < VISIBLE_TILES_X; x++)
816         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
817       for(y = 0; y < VISIBLE_TILES_Y; y++)
818         fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
819     }
820   }
821
822   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
823     le_drawminimap();
824
825   if(show_selections && MouseCursor::current() != mouse_select_object)
826   {
827     if(le_selection_mode == CURSOR)
828     {
829       if(le_current.IsTile())
830         le_selection->draw(cursor_x - pos_x, cursor_y - pos_y);
831     }
832     else if(le_selection_mode == SQUARE)
833     {
834       int w, h;
835       le_highlight_selection();
836       /* draw current selection */
837       w = selection.x2 - selection.x1;
838       h = selection.y2 - selection.y1;
839       fillrect(selection.x1 - pos_x, selection.y1 - pos_y, w, SELECT_W, SELECT_CLR);
840       fillrect(selection.x1 - pos_x + w, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
841       fillrect(selection.x1 - pos_x, selection.y1 - pos_y + h, w, SELECT_W, SELECT_CLR);
842       fillrect(selection.x1 - pos_x, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
843     }
844   }
845
846
847   /* draw button bar */
848   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
849
850   if(le_current.IsTile())
851   {
852     Tile::draw(screen->w - 32, screen->h - 32, le_current.tile);
853     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
854       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);
855   }
856   if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
857   {
858     le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
859     le_current.obj->draw_on_screen(cursor_x,cursor_y);
860   }
861
862   if(mouse_select_object && selected_game_object != NULL)
863   {
864     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);
865     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);
866     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);
867     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);
868   }
869
870   if(le_world != NULL)
871   {
872     le_save_level_bt->draw();
873     le_exit_bt->draw();
874     le_test_level_bt->draw();
875     le_next_level_bt->draw();
876     le_previous_level_bt->draw();
877     le_rubber_bt->draw();
878     if(le_selection_mode == SQUARE)
879       le_select_mode_one_bt->draw();
880     else if(le_selection_mode == CURSOR)
881       le_select_mode_two_bt->draw();
882     le_settings_bt->draw();
883     le_move_right_bt->draw();
884     le_move_left_bt->draw();
885     le_move_up_bt->draw();
886     le_move_down_bt->draw();
887     le_tilegroup_bt->draw();
888     le_objects_bt->draw();
889     if(!cur_tilegroup.empty())
890       tilegroups_map[cur_tilegroup]->draw();
891     else if(!cur_objects.empty())
892     {
893       objects_map[cur_objects]->draw();
894     }
895
896     le_tilemap_panel->draw();
897
898     if(!cur_objects.empty())
899     {
900       le_object_select_bt->draw();
901       le_object_properties_bt->draw();
902     }
903
904     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
905     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
906
907     if(!le_help_shown)
908       white_small_text->draw("F1 for Help", 10, 430, 1);
909
910     if(display_level_info.check())
911       white_text->drawf(le_world->get_level()->name.c_str(), 0, 0, A_HMIDDLE, A_TOP, 0);
912   }
913   else
914   {
915     if(!Menu::current())
916       white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
917     else
918       white_small_text->draw("No Level Subset loaded", 10, 430, 1);
919   }
920
921 }
922
923 void le_drawlevel()
924 {
925   unsigned int y,x,s;
926   Uint8 a;
927
928   /* Draw the real background */
929   if(le_world->get_level()->bkgd_image[0] != '\0')
930   {
931     s = (int)((float)pos_x * ((float)le_world->get_level()->bkgd_speed/100.0f)) % screen->w;
932     le_world->get_level()->img_bkgd->draw_part(s,0,0,0,
933         le_world->get_level()->img_bkgd->w - s - 32, le_world->get_level()->img_bkgd->h);
934     le_world->get_level()->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
935         le_world->get_level()->img_bkgd->h);
936   }
937   else
938   {
939     drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
940   }
941
942   if(le_current.IsTile())
943   {
944     Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
945     if(!TileManager::instance()->get(le_current.tile)->images.empty())
946       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);
947   }
948   if(le_current.IsObject())
949   {
950     le_current.obj->move_to(cursor_x, cursor_y);
951   }
952
953   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
954
955   for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_world->get_level()->height; ++y)
956     for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
957     {
958
959       if(active_tm == TM_BG)
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()->bg_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
965
966       if(active_tm == TM_IA)
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()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a);
972
973       if(active_tm == TM_FG)
974         a = 255;
975       else
976         a = 128;
977
978       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);
979
980       /* draw whats inside stuff when cursor is selecting those */
981       /* (draw them all the time - is this the right behaviour?) */
982       Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)]);
983       if(edit_image && !edit_image->editor_images.empty())
984         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
985
986     }
987
988   /* Draw the Bad guys: */
989   for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
990   {
991     /* to support frames: img_bsod_left[(frame / 5) % 4] */
992
993     scroll_x = pos_x;
994     scroll_y = pos_y;
995     (*it)->draw();
996   }
997
998
999   /* Draw the player: */
1000   /* for now, the position is fixed at (100, 240) */
1001   largetux.walk_right->draw( 100 - pos_x, 240 - pos_y);
1002 }
1003
1004 void le_change_object_properties(GameObject *pobj)
1005 {
1006   Surface* cap_screen = Surface::CaptureScreen();
1007   Menu* object_properties_menu = new Menu();
1008   bool loop = true;
1009
1010   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
1011   object_properties_menu->additem(MN_HL,"",0,0);
1012
1013   if(pobj->type() == "BadGuy")
1014   {
1015     BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1016     object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
1017     for(int i = 0; i < NUM_BadGuyKinds; ++i)
1018     {
1019       string_list_add_item(object_properties_menu->get_item_by_id(1).list,badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
1020       if(pbad->kind == i)
1021         object_properties_menu->get_item_by_id(1).list->active_item = i;
1022     }
1023     object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
1024   }
1025
1026   object_properties_menu->additem(MN_HL,"",0,0);
1027   object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
1028
1029   Menu::set_current(object_properties_menu);
1030
1031   while(loop)
1032   {
1033     SDL_Event event;
1034
1035     while (SDL_PollEvent(&event))
1036     {
1037       object_properties_menu->event(event);
1038     }
1039
1040     cap_screen->draw(0,0);
1041
1042     object_properties_menu->draw();
1043     object_properties_menu->action();
1044
1045     switch (object_properties_menu->check())
1046     {
1047     case 3:
1048       if(pobj->type() == "BadGuy")
1049       {
1050         BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1051         pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
1052         pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
1053         int i = 0;
1054         std::list<BadGuy*>::iterator it;
1055         for(it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1056           if((*it) == pbad)
1057             break;
1058         le_world->get_level()->badguy_data[i].kind = pbad->kind;
1059         le_world->get_level()->badguy_data[i].stay_on_platform = pbad->stay_on_platform;
1060         delete (*it);
1061         (*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);
1062       }
1063       loop = false;
1064       break;
1065     default:
1066       break;
1067     }
1068
1069     if(Menu::current() == NULL)
1070       loop = false;
1071
1072     mouse_cursor->draw();
1073     flipscreen();
1074     SDL_Delay(25);
1075   }
1076
1077   delete cap_screen;
1078   Menu::set_current(0);
1079   delete object_properties_menu;
1080 }
1081
1082
1083 void le_checkevents()
1084 {
1085   SDLKey key;
1086   SDLMod keymod;
1087   Button* pbutton;
1088   int x,y;
1089
1090   keymod = SDL_GetModState();
1091
1092   while(SDL_PollEvent(&event))
1093   {
1094     if (Menu::current())
1095     {
1096       Menu::current()->event(event);
1097       if(!le_world && !Menu::current())
1098         Menu::set_current(leveleditor_menu);
1099     }
1100     else
1101     {
1102       mouse_cursor->set_state(MC_NORMAL);
1103
1104       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1105       if(event.type == SDL_KEYDOWN
1106           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1107               && (event.motion.x > 0
1108                   && event.motion.x < screen->w - 64 &&
1109                   event.motion.y > 0 && event.motion.y < screen->h)))
1110       {
1111         switch(event.type)
1112         {
1113         case SDL_KEYDOWN:       // key pressed
1114           key = event.key.keysym.sym;
1115           switch(key)
1116           {
1117           case SDLK_ESCAPE:
1118             Menu::set_current(leveleditor_menu);
1119             break;
1120           case SDLK_F1:
1121             if(le_world != NULL)
1122               le_showhelp();
1123             break;
1124           case SDLK_HOME:
1125             cursor_x = 0;
1126             pos_x = cursor_x;
1127             break;
1128           case SDLK_END:
1129             cursor_x = (le_world->get_level()->width * 32) - 32;
1130             pos_x = cursor_x;
1131             break;
1132           case SDLK_F9:
1133             le_show_grid = !le_show_grid;
1134             break;
1135           default:
1136             break;
1137           }
1138           break;
1139         case SDL_MOUSEBUTTONDOWN:
1140           if(event.button.button == SDL_BUTTON_LEFT)
1141           {
1142             le_mouse_pressed[LEFT] = true;
1143
1144             selection.x1 = event.motion.x + pos_x;
1145             selection.y1 = event.motion.y + pos_y;
1146             selection.x2 = event.motion.x + pos_x;
1147             selection.y2 = event.motion.y + pos_y;
1148           }
1149           else if(event.button.button == SDL_BUTTON_RIGHT)
1150           {
1151             le_mouse_pressed[RIGHT] = true;
1152           }
1153           break;
1154         case SDL_MOUSEBUTTONUP:
1155           if(event.button.button == SDL_BUTTON_LEFT)
1156           {
1157             le_mouse_pressed[LEFT] = false;
1158             le_mouse_clicked[LEFT] = true;
1159           }
1160           else if(event.button.button == SDL_BUTTON_RIGHT)
1161           {
1162             le_mouse_pressed[RIGHT] = false;
1163             le_mouse_clicked[RIGHT] = true;
1164           }
1165           break;
1166         case SDL_MOUSEMOTION:
1167
1168           if(!Menu::current())
1169           {
1170             x = event.motion.x;
1171             y = event.motion.y;
1172
1173             if(le_current.IsTile())
1174             {
1175               cursor_x = ((int)(pos_x + x) / 32) * 32;
1176               cursor_y = ((int)(pos_y + y) / 32) * 32;
1177             }
1178             else
1179             {
1180               cursor_x = x;
1181               cursor_y = y;
1182             }
1183
1184             if(le_mouse_pressed[LEFT])
1185             {
1186               selection.x2 = x + pos_x;
1187               selection.y2 = y + pos_y;
1188             }
1189
1190             if(le_mouse_pressed[RIGHT])
1191             {
1192               pos_x += -1 * event.motion.xrel;
1193               pos_y += -1 * event.motion.yrel;
1194             }
1195           }
1196           break;
1197         default:
1198           break;
1199         }
1200       }
1201       else if(event.type == SDL_QUIT) /* window closing */
1202       {
1203       done = 1;
1204       }
1205     }
1206
1207     if(le_world != NULL)
1208     {
1209       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 &&
1210           event.motion.y > 0 && event.motion.y < screen->h)))
1211       {
1212         le_mouse_pressed[LEFT] = false;
1213         le_mouse_pressed[RIGHT] = false;
1214
1215         if(!Menu::current())
1216         {
1217           /* Check for button events */
1218           le_test_level_bt->event(event);
1219           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1220             le_testlevel();
1221           le_save_level_bt->event(event);
1222           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1223             le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
1224           le_exit_bt->event(event);
1225           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1226           {
1227             Menu::set_current(leveleditor_menu);
1228           }
1229           le_next_level_bt->event(event);
1230           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1231           {
1232             if(le_level < le_level_subset->levels)
1233             {
1234               le_goto_level(le_level+1);
1235             }
1236             else
1237             {
1238               Level new_lev;
1239               char str[1024];
1240               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1241               if(confirm_dialog(str))
1242               {
1243                 new_lev.init_defaults();
1244                 new_lev.save(le_level_subset->name.c_str(),le_level+1);
1245                 le_level_subset->levels = le_level;
1246                 le_goto_level(le_level);
1247               }
1248             }
1249           }
1250           le_previous_level_bt->event(event);
1251           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1252           {
1253             if(le_level > 1)
1254               le_goto_level(le_level -1);
1255           }
1256           le_rubber_bt->event(event);
1257           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1258             le_current.Tile(0);
1259
1260           if(!cur_objects.empty())
1261           {
1262             le_object_select_bt->event(event);
1263             if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1264             {
1265               MouseCursor::set_current(mouse_select_object);
1266             }
1267
1268             le_object_properties_bt->event(event);
1269             if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1270             {
1271               le_change_object_properties(selected_game_object);
1272             }
1273           }
1274
1275
1276           if(le_selection_mode == SQUARE)
1277           {
1278             le_select_mode_one_bt->event(event);
1279             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1280               le_selection_mode = CURSOR;
1281           }
1282           else
1283           {
1284             le_select_mode_two_bt->event(event);
1285             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1286               le_selection_mode = SQUARE;
1287           }
1288           ButtonPanelMap::iterator it;
1289           le_tilegroup_bt->event(event);
1290           switch (le_tilegroup_bt->get_state())
1291           {
1292           case BUTTON_CLICKED:
1293             Menu::set_current(select_tilegroup_menu);
1294             select_tilegroup_menu_effect.start(200);
1295             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1296             break;
1297           case BUTTON_WHEELUP:
1298             if(cur_tilegroup.empty())
1299             {
1300               cur_tilegroup = tilegroups_map.begin()->first;
1301             }
1302             else
1303             {
1304               it = tilegroups_map.find(cur_tilegroup);
1305               if((++it) == tilegroups_map.end())
1306               {
1307                 cur_tilegroup = tilegroups_map.begin()->first;
1308               }
1309               else
1310               {
1311                 cur_tilegroup = (*it).first;
1312               }
1313             }
1314
1315             cur_objects = "";
1316             break;
1317           case BUTTON_WHEELDOWN:
1318             it = tilegroups_map.find(cur_tilegroup);
1319             if(it == tilegroups_map.begin())
1320             {
1321               cur_tilegroup = tilegroups_map.rbegin()->first;
1322               cur_objects = "";
1323               break;
1324             }
1325             if(--it != --tilegroups_map.begin())
1326               cur_tilegroup = (*it).first;
1327             else
1328               cur_tilegroup = tilegroups_map.rbegin()->first;
1329
1330             cur_objects = "";
1331             break;
1332           default:
1333             break;
1334           }
1335
1336           le_objects_bt->event(event);
1337           switch (le_objects_bt->get_state())
1338           {
1339           case BUTTON_CLICKED:
1340             Menu::set_current(select_objects_menu);
1341             select_objects_menu_effect.start(200);
1342             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1343             break;
1344           case BUTTON_WHEELUP:
1345             it = objects_map.find(cur_objects);
1346             if(it == objects_map.end())
1347             {
1348               cur_objects = objects_map.begin()->first;
1349               cur_tilegroup = "";
1350               break;
1351             }
1352             if(++it != objects_map.end())
1353               cur_objects = (*it).first;
1354             else
1355               cur_objects = objects_map.begin()->first;
1356
1357             cur_tilegroup = "";
1358             break;
1359           case BUTTON_WHEELDOWN:
1360             it = objects_map.find(cur_objects);
1361             if(it == objects_map.begin())
1362             {
1363               cur_objects = objects_map.rbegin()->first;
1364               cur_tilegroup = "";
1365               break;
1366             }
1367             if(--it != --objects_map.begin())
1368               cur_objects = (*it).first;
1369             else
1370               cur_objects = objects_map.rbegin()->first;
1371
1372             cur_tilegroup = "";
1373             break;
1374             break;
1375           default:
1376             break;
1377           }
1378
1379           le_settings_bt->event(event);
1380           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1381           {
1382             update_level_settings_menu();
1383             Menu::set_current(level_settings_menu);
1384           }
1385           if(!cur_tilegroup.empty())
1386           {
1387             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1388             {
1389               if(pbutton->get_state() == BUTTON_CLICKED)
1390               {
1391                 le_current.Tile(pbutton->get_tag());
1392               }
1393             }
1394           }
1395           else if(!cur_objects.empty())
1396           {
1397             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1398             {
1399               if(pbutton->get_state() == BUTTON_CLICKED)
1400               {
1401                 le_current.Object(pbutton->get_game_object());
1402               }
1403             }
1404           }
1405
1406           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1407           {
1408             if(pbutton->get_state() == BUTTON_CLICKED)
1409             {
1410               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1411             }
1412           }
1413         }
1414         else
1415         {
1416           le_settings_bt->event(event);
1417           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1418           {
1419             Menu::set_current(0);
1420           }
1421           le_tilegroup_bt->event(event);
1422           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1423           {
1424             Menu::set_current(0);
1425           }
1426           le_objects_bt->event(event);
1427           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1428           {
1429             Menu::set_current(0);
1430           }
1431         }
1432       }
1433
1434       if(!Menu::current() && !show_minimap)
1435       {
1436         if(le_mouse_pressed[LEFT])
1437         {
1438           if(MouseCursor::current() != mouse_select_object)
1439           {
1440             if(le_current.IsTile())
1441               le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1442           }
1443         }
1444         else if(le_mouse_clicked[LEFT])
1445         {
1446           if(MouseCursor::current() == mouse_select_object)
1447           {
1448             int i = 0;
1449             bool object_got_hit = false;
1450             base_type cursor_base;
1451             if(le_current.IsTile())
1452             {
1453             cursor_base.x = cursor_x;
1454             cursor_base.y = cursor_y;
1455             }
1456             else if(le_current.IsObject())
1457             {
1458             cursor_base.x = cursor_x + pos_x;
1459             cursor_base.y = cursor_y + pos_y;       
1460             }
1461             cursor_base.width = 32;
1462             cursor_base.height = 32;
1463
1464             for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1465               if(rectcollision(cursor_base,(*it)->base))
1466               {
1467                 selected_game_object = (*it);
1468                 object_got_hit = true;
1469                 break;
1470               }
1471
1472             if(!object_got_hit)
1473             {
1474               selected_game_object = NULL;
1475               le_object_properties_bt->set_active(false);
1476             }
1477             else
1478               le_object_properties_bt->set_active(true);
1479
1480             MouseCursor::set_current(mouse_cursor);
1481
1482           }
1483           else
1484           {
1485             if(le_current.IsObject())
1486             {
1487               le_level_changed  = true;
1488               std::string type = le_current.obj->type();
1489               if(type == "BadGuy")
1490               {
1491                 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1492
1493                 le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1494                 le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1495               }
1496             }
1497           }
1498           
1499           le_mouse_clicked[LEFT] = false;
1500
1501         }
1502       }
1503     }
1504   }
1505   if(!Menu::current())
1506   {
1507     show_minimap = false;
1508
1509     le_move_left_bt->event(event);
1510     le_move_right_bt->event(event);
1511     le_move_up_bt->event(event);
1512     le_move_down_bt->event(event);
1513     switch(le_move_left_bt->get_state())
1514     {
1515     case BUTTON_PRESSED:
1516       pos_x -= KEYBOARD_SPEED;
1517       show_minimap = true;
1518       break;
1519     case BUTTON_HOVER:
1520       pos_x -= MOUSE_SPEED;
1521       show_minimap = true;
1522       break;
1523     case BUTTON_CLICKED:
1524       show_minimap = true;
1525       break;
1526     default:
1527       break;
1528     }
1529
1530     switch(le_move_right_bt->get_state())
1531     {
1532     case BUTTON_PRESSED:
1533       pos_x += KEYBOARD_SPEED;
1534       show_minimap = true;
1535       break;
1536     case BUTTON_HOVER:
1537       pos_x += MOUSE_SPEED;
1538       show_minimap = true;
1539       break;
1540     case BUTTON_CLICKED:
1541       show_minimap = true;
1542       break;
1543     default:
1544       break;
1545     }
1546
1547     switch(le_move_up_bt->get_state())
1548     {
1549     case BUTTON_PRESSED:
1550       pos_y -= KEYBOARD_SPEED;
1551       show_minimap = true;
1552       break;
1553     case BUTTON_HOVER:
1554       pos_y -= MOUSE_SPEED;
1555       show_minimap = true;
1556       break;
1557     case BUTTON_CLICKED:
1558       show_minimap = true;
1559       break;
1560     default:
1561       break;
1562     }
1563
1564     switch(le_move_down_bt->get_state())
1565     {
1566     case BUTTON_PRESSED:
1567       pos_y += KEYBOARD_SPEED;
1568       show_minimap = true;
1569       break;
1570     case BUTTON_HOVER:
1571       pos_y += MOUSE_SPEED;
1572       show_minimap = true;
1573       break;
1574     case BUTTON_CLICKED:
1575       show_minimap = true;
1576       break;
1577     default:
1578       break;
1579     }
1580
1581       /* checking if pos_x and pos_y is within the limits... */
1582       if(pos_x > (le_world->get_level()->width * 32 + 32*2) - screen->w)
1583         pos_x = (le_world->get_level()->width * 32 + 32*2) - screen->w;
1584       if(pos_x < 0)
1585         pos_x = 0;
1586
1587       if(pos_y > (le_world->get_level()->height * 32) - screen->h)
1588         pos_y = (le_world->get_level()->height * 32) - screen->h;
1589       if(pos_y < 0)
1590         pos_y = 0;
1591
1592   }
1593
1594 }
1595
1596 void le_highlight_selection()
1597 {
1598   int x1, x2, y1, y2;
1599
1600   if(selection.x1 < selection.x2)
1601   {
1602     x1 = selection.x1;
1603     x2 = selection.x2;
1604   }
1605   else
1606   {
1607     x1 = selection.x2;
1608     x2 = selection.x1;
1609   }
1610   if(selection.y1 < selection.y2)
1611   {
1612     y1 = selection.y1;
1613     y2 = selection.y2;
1614   }
1615   else
1616   {
1617     y1 = selection.y2;
1618     y2 = selection.y1;
1619   }
1620
1621   x1 /= 32;
1622   x2 /= 32;
1623   y1 /= 32;
1624   y2 /= 32;
1625
1626   fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1627 }
1628
1629 void le_change(float x, float y, int tm, unsigned int c)
1630 {
1631   if(le_world != NULL)
1632   {
1633     int xx,yy;
1634     int x1, x2, y1, y2;
1635     unsigned int i = 0;
1636
1637     le_level_changed = true;
1638
1639     switch(le_selection_mode)
1640     {
1641     case CURSOR:
1642       le_world->get_level()->change(x,y,tm,c);
1643
1644       base_type cursor_base;
1645       cursor_base.x = x;
1646       cursor_base.y = y;
1647       cursor_base.width = 32;
1648       cursor_base.height = 32;
1649
1650       /* if there is a bad guy over there, remove it */
1651       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1652         if(rectcollision(cursor_base,(*it)->base))
1653         {
1654           delete (*it);
1655           le_world->bad_guys.erase(it);
1656           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1657           break;
1658         }
1659
1660       break;
1661     case SQUARE:
1662       if(selection.x1 < selection.x2)
1663       {
1664         x1 = selection.x1;
1665         x2 = selection.x2;
1666       }
1667       else
1668       {
1669         x1 = selection.x2;
1670         x2 = selection.x1;
1671       }
1672       if(selection.y1 < selection.y2)
1673       {
1674         y1 = selection.y1;
1675         y2 = selection.y2;
1676       }
1677       else
1678       {
1679         y1 = selection.y2;
1680         y2 = selection.y1;
1681       }
1682
1683       x1 /= 32;
1684       x2 /= 32;
1685       y1 /= 32;
1686       y2 /= 32;
1687
1688       /* if there is a bad guy over there, remove it */
1689       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
1690           it != le_world->bad_guys.end(); /* will be at end of loop */)
1691       {
1692         if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
1693             && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
1694         {
1695           delete (*it);
1696           it = le_world->bad_guys.erase(it);
1697           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1698           continue;
1699         }
1700         else
1701         {
1702           ++i;
1703           ++it;
1704         }
1705       }
1706
1707       for(xx = x1; xx <= x2; xx++)
1708         for(yy = y1; yy <= y2; yy++)
1709         {
1710           le_world->get_level()->change(xx*32, yy*32, tm, c);
1711
1712         }
1713       break;
1714     default:
1715       break;
1716     }
1717   }
1718 }
1719
1720 void le_testlevel()
1721 {
1722   //Make sure a time value is set when testing the level
1723   if(le_world->get_level()->time_left == 0)
1724     le_world->get_level()->time_left = 250;
1725
1726   le_world->get_level()->save("test", le_level);
1727
1728   GameSession session("test",le_level, ST_GL_TEST);
1729   session.run();
1730   player_status.reset();
1731
1732   music_manager->halt_music();
1733
1734   Menu::set_current(NULL);
1735   World::set_current(le_world);
1736 }
1737
1738 void le_showhelp()
1739 {
1740   bool tmp_show_grid = le_show_grid;
1741   SelectionMode temp_le_selection_mode = le_selection_mode;
1742   le_selection_mode = NONE;
1743   show_selections = true;
1744   le_show_grid = false;
1745   le_help_shown = true;
1746
1747   drawgradient(Color(0,0,0), Color(255,255,255));
1748   le_drawinterface();
1749
1750   SDL_Event event;
1751   unsigned int i, done_;
1752   char *text[] = {
1753
1754                    " - Supertux level editor tutorial - ",
1755                    "",
1756                    "To make your map, click the       ",
1757                    "tilegroup button and choose a     ",
1758                    "tilegroup.",
1759                    "Pick a tile and simply hold down  ",
1760                    "the left mouse button over the map",
1761                    "to \"paint\" your selection over",
1762                    "the screen.",
1763                    "",
1764                    "There are three layers for painting",
1765                    "tiles upon, Background layer,",
1766                    "the Interactive layer, and the",
1767                    "Foreground layer, which can be",
1768                    "toggled by the BkGrd, IntAct and",
1769                    "FrGrd buttons. The Foreground and",
1770                    "Background layers do not effect",
1771                    "Tux in the gameplay, but lie in",
1772                    "front of him or lie behind him in",
1773                    "his adventures.",
1774                  };
1775
1776   char *text2[] = {
1777
1778                     " - Supertux level editor tutorial - ",
1779                     "",
1780                     "The tiles placed on",
1781                     "the Interactive layer are those",
1782                     "which actually effect Tux in the",
1783                     "game.",
1784                     "",
1785                     "Click the objects menu to put ",
1786                     "bad guys and other objects in the",
1787                     "game. Unlike placing tiles, you",
1788                     "cannot \"paint\" enemies. Click",
1789                     "them onto the screen one at a time.",
1790                     "",
1791                     "To change the settings of your",
1792                     "level, click the button with the",
1793                     "screwdriver and wrench. From here",
1794                     "you can change the background,",
1795                     "music, length of the level,",
1796                     "and more."
1797                   };
1798
1799   char *text3[] = {
1800
1801                     " - Supertux level editor tutorial - ",
1802                     "",
1803                     "You may have more than one level.",
1804                     "Pressing the up and down buttons",
1805                     "above the button bar lets you",
1806                     "choose which one you are working on.",
1807                     "",
1808                     "If you would like to speed up your",
1809                     "level editing, a useful trick is",
1810                     "to learn the keyboard shortcuts.",
1811                     "They are easy to learn, just right-",
1812                     "click on the buttons.",
1813                     "",
1814                     "Have fun making levels! If you make",
1815                     "some good ones, send them to us on",
1816                     "the SuperTux mailing list!",
1817                     "- SuperTux team"
1818                   };
1819
1820
1821
1822   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1823
1824   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1825     white_text->draw(text[i], 5, 80+(i*white_text->h), 1);
1826
1827   gold_text->drawf("Press Anything to Continue - Page 1/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1828
1829   flipscreen();
1830
1831   done_ = 0;
1832
1833   while(done_ == 0)
1834   {
1835     done_ = wait_for_event(event);
1836     SDL_Delay(50);
1837   }
1838
1839   drawgradient(Color(0,0,0), Color(255,255,255));
1840   le_drawinterface();
1841
1842
1843   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1844
1845   for(i = 0; i < sizeof(text2)/sizeof(char *); i++)
1846     white_text->draw(text2[i], 5, 80+(i*white_text->h), 1);
1847
1848   gold_text->drawf("Press Anything to Continue - Page 2/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1849
1850   flipscreen();
1851
1852   done_ = 0;
1853
1854   while(done_ == 0)
1855   {
1856     done_ = wait_for_event(event);
1857     SDL_Delay(50);
1858   }
1859
1860   drawgradient(Color(0,0,0), Color(255,255,255));
1861   le_drawinterface();
1862
1863
1864   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1865
1866   for(i = 0; i < sizeof(text3)/sizeof(char *); i++)
1867     white_text->draw(text3[i], 5, 80+(i*white_text->h), 1);
1868
1869   gold_text->drawf("Press Anything to Continue - Page 3/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1870
1871   flipscreen();
1872
1873   done_ = 0;
1874
1875   while(done_ == 0)
1876   {
1877     done_ = wait_for_event(event);
1878     SDL_Delay(50);
1879   }
1880
1881   show_selections = true;
1882   le_show_grid = tmp_show_grid;
1883   le_selection_mode = temp_le_selection_mode;
1884   le_help_shown = false;
1885 }