Leveleditor closes on SDL_QUIT events now.
[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/100.0f)) % 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         default:
1230           break;
1231         }
1232       }
1233       else if(event.type == SDL_QUIT) /* window closing */
1234       {
1235       done = 1;
1236       }
1237     }
1238
1239     if(le_world != NULL)
1240     {
1241       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 &&
1242           event.motion.y > 0 && event.motion.y < screen->h)))
1243       {
1244         le_mouse_pressed[LEFT] = false;
1245         le_mouse_pressed[RIGHT] = false;
1246
1247         if(!Menu::current())
1248         {
1249           /* Check for button events */
1250           le_test_level_bt->event(event);
1251           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1252             le_testlevel();
1253           le_save_level_bt->event(event);
1254           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1255             le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
1256           le_exit_bt->event(event);
1257           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1258           {
1259             Menu::set_current(leveleditor_menu);
1260           }
1261           le_next_level_bt->event(event);
1262           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1263           {
1264             if(le_level < le_level_subset->levels)
1265             {
1266               le_goto_level(le_level+1);
1267             }
1268             else
1269             {
1270               Level new_lev;
1271               char str[1024];
1272               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1273               if(confirm_dialog(str))
1274               {
1275                 new_lev.init_defaults();
1276                 new_lev.save(le_level_subset->name.c_str(),le_level+1);
1277                 le_level_subset->levels = le_level;
1278                 le_goto_level(le_level);
1279               }
1280             }
1281           }
1282           le_previous_level_bt->event(event);
1283           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1284           {
1285             if(le_level > 1)
1286               le_goto_level(le_level -1);
1287           }
1288           le_rubber_bt->event(event);
1289           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1290             le_current.Tile(0);
1291
1292           if(!cur_objects.empty())
1293           {
1294             le_object_select_bt->event(event);
1295             if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1296             {
1297               MouseCursor::set_current(mouse_select_object);
1298             }
1299
1300             le_object_properties_bt->event(event);
1301             if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1302             {
1303               le_change_object_properties(selected_game_object);
1304             }
1305           }
1306
1307
1308           if(le_selection_mode == SQUARE)
1309           {
1310             le_select_mode_one_bt->event(event);
1311             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1312               le_selection_mode = CURSOR;
1313           }
1314           else
1315           {
1316             le_select_mode_two_bt->event(event);
1317             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1318               le_selection_mode = SQUARE;
1319           }
1320           ButtonPanelMap::iterator it;
1321           le_tilegroup_bt->event(event);
1322           switch (le_tilegroup_bt->get_state())
1323           {
1324           case BUTTON_CLICKED:
1325             Menu::set_current(select_tilegroup_menu);
1326             select_tilegroup_menu_effect.start(200);
1327             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1328             break;
1329           case BUTTON_WHEELUP:
1330             if(cur_tilegroup.empty())
1331             {
1332               cur_tilegroup = tilegroups_map.begin()->first;
1333             }
1334             else
1335             {
1336               it = tilegroups_map.find(cur_tilegroup);
1337               if((++it) == tilegroups_map.end())
1338               {
1339                 cur_tilegroup = tilegroups_map.begin()->first;
1340               }
1341               else
1342               {
1343                 cur_tilegroup = (*it).first;
1344               }
1345             }
1346
1347             cur_objects = "";
1348             break;
1349           case BUTTON_WHEELDOWN:
1350             it = tilegroups_map.find(cur_tilegroup);
1351             if(it == tilegroups_map.begin())
1352             {
1353               cur_tilegroup = tilegroups_map.rbegin()->first;
1354               cur_objects = "";
1355               break;
1356             }
1357             if(--it != --tilegroups_map.begin())
1358               cur_tilegroup = (*it).first;
1359             else
1360               cur_tilegroup = tilegroups_map.rbegin()->first;
1361
1362             cur_objects = "";
1363             break;
1364           default:
1365             break;
1366           }
1367
1368           le_objects_bt->event(event);
1369           switch (le_objects_bt->get_state())
1370           {
1371           case BUTTON_CLICKED:
1372             Menu::set_current(select_objects_menu);
1373             select_objects_menu_effect.start(200);
1374             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1375             break;
1376           case BUTTON_WHEELUP:
1377             it = objects_map.find(cur_objects);
1378             if(it == objects_map.end())
1379             {
1380               cur_objects = objects_map.begin()->first;
1381               cur_tilegroup = "";
1382               break;
1383             }
1384             if(++it != objects_map.end())
1385               cur_objects = (*it).first;
1386             else
1387               cur_objects = objects_map.begin()->first;
1388
1389             cur_tilegroup = "";
1390             break;
1391           case BUTTON_WHEELDOWN:
1392             it = objects_map.find(cur_objects);
1393             if(it == objects_map.begin())
1394             {
1395               cur_objects = objects_map.rbegin()->first;
1396               cur_tilegroup = "";
1397               break;
1398             }
1399             if(--it != --objects_map.begin())
1400               cur_objects = (*it).first;
1401             else
1402               cur_objects = objects_map.rbegin()->first;
1403
1404             cur_tilegroup = "";
1405             break;
1406             break;
1407           default:
1408             break;
1409           }
1410
1411           le_settings_bt->event(event);
1412           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1413           {
1414             update_level_settings_menu();
1415             Menu::set_current(level_settings_menu);
1416           }
1417           if(!cur_tilegroup.empty())
1418           {
1419             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1420             {
1421               if(pbutton->get_state() == BUTTON_CLICKED)
1422               {
1423                 le_current.Tile(pbutton->get_tag());
1424               }
1425             }
1426           }
1427           else if(!cur_objects.empty())
1428           {
1429             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1430             {
1431               if(pbutton->get_state() == BUTTON_CLICKED)
1432               {
1433                 le_current.Object(pbutton->get_game_object());
1434               }
1435             }
1436           }
1437
1438           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1439           {
1440             if(pbutton->get_state() == BUTTON_CLICKED)
1441             {
1442               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1443             }
1444           }
1445         }
1446         else
1447         {
1448           le_settings_bt->event(event);
1449           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1450           {
1451             Menu::set_current(0);
1452           }
1453           le_tilegroup_bt->event(event);
1454           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1455           {
1456             Menu::set_current(0);
1457           }
1458           le_objects_bt->event(event);
1459           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1460           {
1461             Menu::set_current(0);
1462           }
1463         }
1464       }
1465
1466       if(!Menu::current() && !show_minimap)
1467       {
1468         if(le_mouse_pressed[LEFT])
1469         {
1470           if(MouseCursor::current() != mouse_select_object)
1471           {
1472             if(le_current.IsTile())
1473               le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1474           }
1475         }
1476         else if(le_mouse_clicked[LEFT])
1477         {
1478           if(MouseCursor::current() == mouse_select_object)
1479           {
1480             int i = 0;
1481             bool object_got_hit = false;
1482             base_type cursor_base;
1483             if(le_current.IsTile())
1484             {
1485             cursor_base.x = cursor_x;
1486             cursor_base.y = cursor_y;
1487             }
1488             else if(le_current.IsObject())
1489             {
1490             cursor_base.x = cursor_x + pos_x;
1491             cursor_base.y = cursor_y + pos_x;       
1492             }
1493             cursor_base.width = 32;
1494             cursor_base.height = 32;
1495
1496             for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1497               if(rectcollision(cursor_base,(*it)->base))
1498               {
1499                 selected_game_object = (*it);
1500                 object_got_hit = true;
1501                 break;
1502               }
1503
1504             if(!object_got_hit)
1505             {
1506               selected_game_object = NULL;
1507               le_object_properties_bt->set_active(false);
1508             }
1509             else
1510               le_object_properties_bt->set_active(true);
1511
1512             MouseCursor::set_current(mouse_cursor);
1513
1514           }
1515           else
1516           {
1517             if(le_current.IsObject())
1518             {
1519               le_level_changed  = true;
1520               std::string type = le_current.obj->type();
1521               if(type == "BadGuy")
1522               {
1523                 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1524
1525                 le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1526                 le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1527               }
1528             }
1529           }
1530           
1531           le_mouse_clicked[LEFT] = false;
1532
1533         }
1534       }
1535     }
1536   }
1537   if(!Menu::current())
1538   {
1539     show_minimap = false;
1540
1541     le_move_left_bt->event(event);
1542     le_move_right_bt->event(event);
1543     switch(le_move_left_bt->get_state())
1544     {
1545     case BUTTON_PRESSED:
1546       pos_x -= 192;
1547       show_minimap = true;
1548       break;
1549     case BUTTON_HOVER:
1550       pos_x -= 32;
1551       show_minimap = true;
1552       break;
1553     case BUTTON_CLICKED:
1554       show_minimap = true;
1555       break;
1556     default:
1557       break;
1558     }
1559
1560     switch(le_move_right_bt->get_state())
1561     {
1562     case BUTTON_PRESSED:
1563       pos_x += 192;
1564       show_minimap = true;
1565       break;
1566     case BUTTON_HOVER:
1567       pos_x += 32;
1568       show_minimap = true;
1569       break;
1570     case BUTTON_CLICKED:
1571       show_minimap = true;
1572       break;
1573     default:
1574       break;
1575     }
1576
1577   }
1578
1579 }
1580
1581 void le_highlight_selection()
1582 {
1583   int x1, x2, y1, y2;
1584
1585   if(selection.x1 < selection.x2)
1586   {
1587     x1 = selection.x1;
1588     x2 = selection.x2;
1589   }
1590   else
1591   {
1592     x1 = selection.x2;
1593     x2 = selection.x1;
1594   }
1595   if(selection.y1 < selection.y2)
1596   {
1597     y1 = selection.y1;
1598     y2 = selection.y2;
1599   }
1600   else
1601   {
1602     y1 = selection.y2;
1603     y2 = selection.y1;
1604   }
1605
1606   x1 /= 32;
1607   x2 /= 32;
1608   y1 /= 32;
1609   y2 /= 32;
1610
1611   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1612 }
1613
1614 void le_change(float x, float y, int tm, unsigned int c)
1615 {
1616   if(le_world != NULL)
1617   {
1618     int xx,yy;
1619     int x1, x2, y1, y2;
1620     unsigned int i = 0;
1621
1622     le_level_changed = true;
1623
1624     switch(le_selection_mode)
1625     {
1626     case CURSOR:
1627       le_world->get_level()->change(x,y,tm,c);
1628
1629       base_type cursor_base;
1630       cursor_base.x = x;
1631       cursor_base.y = y;
1632       cursor_base.width = 32;
1633       cursor_base.height = 32;
1634
1635       /* if there is a bad guy over there, remove it */
1636       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1637         if(rectcollision(cursor_base,(*it)->base))
1638         {
1639           delete (*it);
1640           le_world->bad_guys.erase(it);
1641           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1642           break;
1643         }
1644
1645       break;
1646     case SQUARE:
1647       if(selection.x1 < selection.x2)
1648       {
1649         x1 = selection.x1;
1650         x2 = selection.x2;
1651       }
1652       else
1653       {
1654         x1 = selection.x2;
1655         x2 = selection.x1;
1656       }
1657       if(selection.y1 < selection.y2)
1658       {
1659         y1 = selection.y1;
1660         y2 = selection.y2;
1661       }
1662       else
1663       {
1664         y1 = selection.y2;
1665         y2 = selection.y1;
1666       }
1667
1668       x1 /= 32;
1669       x2 /= 32;
1670       y1 /= 32;
1671       y2 /= 32;
1672
1673       /* if there is a bad guy over there, remove it */
1674       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
1675           it != le_world->bad_guys.end(); /* will be at end of loop */)
1676       {
1677         if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
1678             && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
1679         {
1680           delete (*it);
1681           it = le_world->bad_guys.erase(it);
1682           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1683           continue;
1684         }
1685         else
1686         {
1687           ++i;
1688           ++it;
1689         }
1690       }
1691
1692       for(xx = x1; xx <= x2; xx++)
1693         for(yy = y1; yy <= y2; yy++)
1694         {
1695           le_world->get_level()->change(xx*32, yy*32, tm, c);
1696
1697         }
1698       break;
1699     default:
1700       break;
1701     }
1702   }
1703 }
1704
1705 void le_testlevel()
1706 {
1707   //Make sure a time value is set when testing the level
1708   if(le_world->get_level()->time_left == 0)
1709     le_world->get_level()->time_left = 250;
1710
1711   le_world->get_level()->save("test", le_level);
1712
1713   GameSession session("test",le_level, ST_GL_TEST);
1714   session.run();
1715   player_status.reset();
1716
1717   music_manager->halt_music();
1718
1719   Menu::set_current(NULL);
1720   World::set_current(le_world);
1721 }
1722
1723 void le_showhelp()
1724 {
1725   bool tmp_show_grid = le_show_grid;
1726   int temp_le_selection_mode = le_selection_mode;
1727   le_selection_mode = NONE;
1728   show_selections = true;
1729   le_show_grid = false;
1730   le_help_shown = true;
1731
1732   drawgradient(Color(0,0,0), Color(255,255,255));
1733   le_drawinterface();
1734
1735   SDL_Event event;
1736   unsigned int i, done_;
1737   char *text[] = {
1738
1739                    " - Supertux level editor tutorial - ",
1740                    "",
1741                    "To make your map, click the       ",
1742                    "tilegroup button and choose a     ",
1743                    "tilegroup.",
1744                    "Pick a tile and simply hold down  ",
1745                    "the left mouse button over the map",
1746                    "to \"paint\" your selection over",
1747                    "the screen.",
1748                    "",
1749                    "There are three layers for painting",
1750                    "tiles upon, Background layer,",
1751                    "the Interactive layer, and the",
1752                    "Foreground layer, which can be",
1753                    "toggled by the BkGrd, IntAct and",
1754                    "FrGrd buttons. The Foreground and",
1755                    "Background layers do not effect",
1756                    "Tux in the gameplay, but lie in",
1757                    "front of him or lie behind him in",
1758                    "his adventures.",
1759                  };
1760
1761   char *text2[] = {
1762
1763                     " - Supertux level editor tutorial - ",
1764                     "",
1765                     "The tiles placed on",
1766                     "the Interactive layer are those",
1767                     "which actually effect Tux in the",
1768                     "game.",
1769                     "",
1770                     "Click the objects menu to put ",
1771                     "bad guys and other objects in the",
1772                     "game. Unlike placing tiles, you",
1773                     "cannot \"paint\" enemies. Click",
1774                     "them onto the screen one at a time.",
1775                     "",
1776                     "To change the settings of your",
1777                     "level, click the button with the",
1778                     "screwdriver and wrench. From here",
1779                     "you can change the background,",
1780                     "music, length of the level,",
1781                     "and more."
1782                   };
1783
1784   char *text3[] = {
1785
1786                     " - Supertux level editor tutorial - ",
1787                     "",
1788                     "You may have more than one level.",
1789                     "Pressing the up and down buttons",
1790                     "above the button bar lets you",
1791                     "choose which one you are working on.",
1792                     "",
1793                     "If you would like to speed up your",
1794                     "level editing, a useful trick is",
1795                     "to learn the keyboard shortcuts.",
1796                     "They are easy to learn, just right-",
1797                     "click on the buttons.",
1798                     "",
1799                     "Have fun making levels! If you make",
1800                     "some good ones, send them to us on",
1801                     "the SuperTux mailing list!",
1802                     "- SuperTux team"
1803                   };
1804
1805
1806
1807   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1808
1809   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1810     white_text->draw(text[i], 5, 80+(i*white_text->h), 1);
1811
1812   gold_text->drawf("Press Anything to Continue - Page 1/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1813
1814   flipscreen();
1815
1816   done_ = 0;
1817
1818   while(done_ == 0)
1819   {
1820     done_ = wait_for_event(event);
1821     SDL_Delay(50);
1822   }
1823
1824   drawgradient(Color(0,0,0), Color(255,255,255));
1825   le_drawinterface();
1826
1827
1828   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1829
1830   for(i = 0; i < sizeof(text2)/sizeof(char *); i++)
1831     white_text->draw(text2[i], 5, 80+(i*white_text->h), 1);
1832
1833   gold_text->drawf("Press Anything to Continue - Page 2/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1834
1835   flipscreen();
1836
1837   done_ = 0;
1838
1839   while(done_ == 0)
1840   {
1841     done_ = wait_for_event(event);
1842     SDL_Delay(50);
1843   }
1844
1845   drawgradient(Color(0,0,0), Color(255,255,255));
1846   le_drawinterface();
1847
1848
1849   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1850
1851   for(i = 0; i < sizeof(text3)/sizeof(char *); i++)
1852     white_text->draw(text3[i], 5, 80+(i*white_text->h), 1);
1853
1854   gold_text->drawf("Press Anything to Continue - Page 3/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1855
1856   flipscreen();
1857
1858   done_ = 0;
1859
1860   while(done_ == 0)
1861   {
1862     done_ = wait_for_event(event);
1863     SDL_Delay(50);
1864   }
1865
1866   show_selections = true;
1867   le_show_grid = tmp_show_grid;
1868   le_selection_mode = temp_le_selection_mode;
1869   le_help_shown = false;
1870 }