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