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