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