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