- fixed some enums
[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 SelectionMode 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   le_level_changed = false;
686 }
687
688 void le_unload_level()
689 {
690   if(le_level_changed)
691   {
692     le_drawlevel();
693     le_drawinterface();
694     char str[1024];
695     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
696     if(confirm_dialog(str))
697     {
698       le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
699     }
700   }
701
702   delete le_world;
703   le_level_changed = false;
704 }
705
706 void le_goto_level(int levelnb)
707 {
708   le_unload_level();
709   le_world = new World(le_level_subset->name, levelnb);
710   display_level_info.start(2500);
711   le_level = levelnb;
712 }
713
714 void le_quit(void)
715 {
716   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
717
718   le_unload_level();
719   delete le_selection;
720   delete leveleditor_menu;
721   delete subset_load_menu;
722   delete subset_new_menu;
723   delete subset_settings_menu;
724   delete level_settings_menu;
725   delete select_tilegroup_menu;
726   delete select_objects_menu;
727   delete le_save_level_bt;
728   delete le_exit_bt;
729   delete le_test_level_bt;
730   delete le_next_level_bt;
731   delete le_previous_level_bt;
732   delete le_move_right_bt;
733   delete le_move_left_bt;
734   delete le_rubber_bt;
735   delete le_select_mode_one_bt;
736   delete le_select_mode_two_bt;
737   delete le_settings_bt;
738   delete le_tilegroup_bt;
739   delete le_objects_bt;
740   delete le_tilemap_panel;
741   delete le_object_select_bt;
742   delete le_object_properties_bt;
743   delete mouse_select_object;
744
745   delete le_level_subset;
746   le_level_subset = 0;
747
748   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
749       i != tilegroups_map.end(); ++i)
750   {
751     delete i->second;
752   }
753   for(ButtonPanelMap::iterator i = objects_map.begin();
754       i != objects_map.end(); ++i)
755   {
756     delete i->second;
757   }
758 }
759
760 void le_drawminimap()
761 {
762   if(le_world == NULL)
763     return;
764
765   int mini_tile_width;
766   if(screen->w - 64 > le_world->get_level()->width * 4)
767     mini_tile_width = 4;
768   else if(screen->w - 64 > le_world->get_level()->width * 2)
769     mini_tile_width = 2;
770   else
771     mini_tile_width = 1;
772   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
773
774   for (int y = 0; y < 15; ++y)
775     for (int x = 0; x < le_world->get_level()->width; ++x)
776     {
777
778       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
779
780       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
781
782       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
783
784     }
785
786   fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, 15*4, 200, 200, 200, 128);
787
788   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
789   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, 15*4, 200, 200, 200, 200);
790   fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, 15*4, 200, 200, 200, 200);
791   fillrect(left_offset + (pos_x/32)*mini_tile_width, 15*4-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
792
793 }
794
795 void le_drawinterface()
796 {
797   int x,y;
798   char str[80];
799
800   if(le_world != NULL)
801   {
802     /* draw a grid (if selected) */
803     if(le_show_grid)
804     {
805       for(x = 0; x < 19; x++)
806         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
807       for(y = 0; y < 15; y++)
808         fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
809     }
810   }
811
812   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
813     le_drawminimap();
814
815   if(show_selections && MouseCursor::current() != mouse_select_object)
816   {
817     if(le_selection_mode == CURSOR)
818     {
819       if(le_current.IsTile())
820         le_selection->draw( cursor_x - pos_x, cursor_y);
821     }
822     else if(le_selection_mode == SQUARE)
823     {
824       int w, h;
825       le_highlight_selection();
826       /* draw current selection */
827       w = selection.x2 - selection.x1;
828       h = selection.y2 - selection.y1;
829       fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
830       fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
831       fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
832       fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
833     }
834   }
835
836
837   /* draw button bar */
838   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
839
840   if(le_current.IsTile())
841   {
842     Tile::draw(19 * 32, 14 * 32, le_current.tile);
843     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
844       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
845   }
846   if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
847   {
848     le_current.obj->draw_on_screen(19 * 32, 14 * 32);
849     le_current.obj->draw_on_screen(cursor_x,cursor_y);
850   }
851
852   if(mouse_select_object && selected_game_object != NULL)
853   {
854     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y,selected_game_object->base.width,3,255,0,0,255);
855     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y,3,selected_game_object->base.height,255,0,0,255);
856     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);
857     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);
858   }
859
860   if(le_world != NULL)
861   {
862     le_save_level_bt->draw();
863     le_exit_bt->draw();
864     le_test_level_bt->draw();
865     le_next_level_bt->draw();
866     le_previous_level_bt->draw();
867     le_rubber_bt->draw();
868     if(le_selection_mode == SQUARE)
869       le_select_mode_one_bt->draw();
870     else if(le_selection_mode == CURSOR)
871       le_select_mode_two_bt->draw();
872     le_settings_bt->draw();
873     le_move_right_bt->draw();
874     le_move_left_bt->draw();
875     le_tilegroup_bt->draw();
876     le_objects_bt->draw();
877     if(!cur_tilegroup.empty())
878       tilegroups_map[cur_tilegroup]->draw();
879     else if(!cur_objects.empty())
880     {
881       objects_map[cur_objects]->draw();
882     }
883
884     le_tilemap_panel->draw();
885
886     if(!cur_objects.empty())
887     {
888       le_object_select_bt->draw();
889       le_object_properties_bt->draw();
890     }
891
892     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
893     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
894
895     if(!le_help_shown)
896       white_small_text->draw("F1 for Help", 10, 430, 1);
897
898     if(display_level_info.check())
899       white_text->drawf(le_world->get_level()->name.c_str(), 0, 0, A_HMIDDLE, A_TOP, 0);
900   }
901   else
902   {
903     if(!Menu::current())
904       white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
905     else
906       white_small_text->draw("No Level Subset loaded", 10, 430, 1);
907   }
908
909 }
910
911 void le_drawlevel()
912 {
913   unsigned int y,x,s;
914   Uint8 a;
915
916   /* Draw the real background */
917   if(le_world->get_level()->bkgd_image[0] != '\0')
918   {
919     s = (int)((float)pos_x * ((float)le_world->get_level()->bkgd_speed/100.0f)) % screen->w;
920     le_world->get_level()->img_bkgd->draw_part(s,0,0,0,
921         le_world->get_level()->img_bkgd->w - s - 32, le_world->get_level()->img_bkgd->h);
922     le_world->get_level()->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
923         le_world->get_level()->img_bkgd->h);
924   }
925   else
926   {
927     drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
928   }
929
930   if(le_current.IsTile())
931   {
932     Tile::draw(cursor_x-pos_x, cursor_y,le_current.tile,128);
933     if(!TileManager::instance()->get(le_current.tile)->images.empty())
934       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);
935   }
936   if(le_current.IsObject())
937   {
938     le_current.obj->move_to(cursor_x, cursor_y);
939   }
940
941   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
942
943   for (y = 0; y < 15; ++y)
944     for (x = 0; x < 20; ++x)
945     {
946
947       if(active_tm == TM_BG)
948         a = 255;
949       else
950         a = 128;
951
952       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->bg_tiles[y][x + (int)(pos_x / 32)],a);
953
954       if(active_tm == TM_IA)
955         a = 255;
956       else
957         a = 128;
958
959       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)],a);
960
961       if(active_tm == TM_FG)
962         a = 255;
963       else
964         a = 128;
965
966       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->fg_tiles[y][x + (int)(pos_x / 32)],a);
967
968       /* draw whats inside stuff when cursor is selecting those */
969       /* (draw them all the time - is this the right behaviour?) */
970       Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)]);
971       if(edit_image && !edit_image->editor_images.empty())
972         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
973
974     }
975
976   /* Draw the Bad guys: */
977   for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
978   {
979     /* to support frames: img_bsod_left[(frame / 5) % 4] */
980
981     scroll_x = pos_x;
982     (*it)->draw();
983   }
984
985
986   /* Draw the player: */
987   /* for now, the position is fixed at (100, 240) */
988   largetux.walk_right->draw( 100 - pos_x, 240);
989 }
990
991 void le_change_object_properties(GameObject *pobj)
992 {
993   Surface* cap_screen = Surface::CaptureScreen();
994   Menu* object_properties_menu = new Menu();
995   bool loop = true;
996
997   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
998   object_properties_menu->additem(MN_HL,"",0,0);
999
1000   if(pobj->type() == "BadGuy")
1001   {
1002     BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1003     object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
1004     for(int i = 0; i < NUM_BadGuyKinds; ++i)
1005     {
1006       string_list_add_item(object_properties_menu->get_item_by_id(1).list,badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
1007       if(pbad->kind == i)
1008         object_properties_menu->get_item_by_id(1).list->active_item = i;
1009     }
1010     object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
1011   }
1012
1013   object_properties_menu->additem(MN_HL,"",0,0);
1014   object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
1015
1016   Menu::set_current(object_properties_menu);
1017
1018   while(loop)
1019   {
1020     SDL_Event event;
1021
1022     while (SDL_PollEvent(&event))
1023     {
1024       object_properties_menu->event(event);
1025     }
1026
1027     cap_screen->draw(0,0);
1028
1029     object_properties_menu->draw();
1030     object_properties_menu->action();
1031
1032     switch (object_properties_menu->check())
1033     {
1034     case 3:
1035       if(pobj->type() == "BadGuy")
1036       {
1037         BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1038         pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
1039         pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
1040         int i = 0;
1041         std::list<BadGuy*>::iterator it;
1042         for(it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1043           if((*it) == pbad)
1044             break;
1045         le_world->get_level()->badguy_data[i].kind = pbad->kind;
1046         le_world->get_level()->badguy_data[i].stay_on_platform = pbad->stay_on_platform;
1047         delete (*it);
1048         (*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);
1049       }
1050       loop = false;
1051       break;
1052     default:
1053       break;
1054     }
1055
1056     if(Menu::current() == NULL)
1057       loop = false;
1058
1059     mouse_cursor->draw();
1060     flipscreen();
1061     SDL_Delay(25);
1062   }
1063
1064   delete cap_screen;
1065   Menu::set_current(0);
1066   delete object_properties_menu;
1067 }
1068
1069
1070 void le_checkevents()
1071 {
1072   SDLKey key;
1073   SDLMod keymod;
1074   Button* pbutton;
1075   int x,y;
1076
1077   keymod = SDL_GetModState();
1078
1079   while(SDL_PollEvent(&event))
1080   {
1081     if (Menu::current())
1082     {
1083       Menu::current()->event(event);
1084       if(!le_world && !Menu::current())
1085         Menu::set_current(leveleditor_menu);
1086     }
1087     else
1088     {
1089       mouse_cursor->set_state(MC_NORMAL);
1090
1091       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1092       if(event.type == SDL_KEYDOWN
1093           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1094               && (event.motion.x > 0
1095                   && event.motion.x < screen->w - 64 &&
1096                   event.motion.y > 0 && event.motion.y < screen->h)))
1097       {
1098         switch(event.type)
1099         {
1100         case SDL_KEYDOWN:       // key pressed
1101           key = event.key.keysym.sym;
1102           switch(key)
1103           {
1104           case SDLK_ESCAPE:
1105             Menu::set_current(leveleditor_menu);
1106             break;
1107           case SDLK_LEFT:
1108             if(fire == DOWN)
1109               cursor_x -= KEY_CURSOR_SPEED;
1110             else
1111               cursor_x -= KEY_CURSOR_FASTSPEED;
1112
1113             if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
1114               pos_x = cursor_x - MOUSE_LEFT_MARGIN;
1115
1116             break;
1117           case SDLK_RIGHT:
1118             if(fire == DOWN)
1119               cursor_x += KEY_CURSOR_SPEED;
1120             else
1121               cursor_x += KEY_CURSOR_FASTSPEED;
1122
1123             if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
1124               pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
1125
1126             break;
1127           case SDLK_UP:
1128             if(fire == DOWN)
1129               cursor_y -= KEY_CURSOR_SPEED;
1130             else
1131               cursor_y -= KEY_CURSOR_FASTSPEED;
1132
1133             if(cursor_y < 0)
1134               cursor_y = 0;
1135             break;
1136           case SDLK_DOWN:
1137             if(fire == DOWN)
1138               cursor_y += KEY_CURSOR_SPEED;
1139             else
1140               cursor_y += KEY_CURSOR_FASTSPEED;
1141
1142             if(cursor_y > screen->h-32)
1143               cursor_y = screen->h-32;
1144             break;
1145           case SDLK_LCTRL:
1146             fire =UP;
1147             break;
1148           case SDLK_F1:
1149             if(le_world != NULL)
1150               le_showhelp();
1151             break;
1152           case SDLK_HOME:
1153             cursor_x = 0;
1154             pos_x = cursor_x;
1155             break;
1156           case SDLK_END:
1157             cursor_x = (le_world->get_level()->width * 32) - 32;
1158             pos_x = cursor_x;
1159             break;
1160           case SDLK_F9:
1161             le_show_grid = !le_show_grid;
1162             break;
1163           default:
1164             break;
1165           }
1166           break;
1167         case SDL_KEYUP: /* key released */
1168           switch(event.key.keysym.sym)
1169           {
1170           case SDLK_LCTRL:
1171             fire = DOWN;
1172             break;
1173           default:
1174             break;
1175           }
1176           break;
1177         case SDL_MOUSEBUTTONDOWN:
1178           if(event.button.button == SDL_BUTTON_LEFT)
1179           {
1180             le_mouse_pressed[LEFT] = true;
1181
1182             selection.x1 = event.motion.x + pos_x;
1183             selection.y1 = event.motion.y;
1184             selection.x2 = event.motion.x + pos_x;
1185             selection.y2 = event.motion.y;
1186           }
1187           else if(event.button.button == SDL_BUTTON_RIGHT)
1188           {
1189             le_mouse_pressed[RIGHT] = true;
1190           }
1191           break;
1192         case SDL_MOUSEBUTTONUP:
1193           if(event.button.button == SDL_BUTTON_LEFT)
1194           {
1195             le_mouse_pressed[LEFT] = false;
1196             le_mouse_clicked[LEFT] = true;
1197           }
1198           else if(event.button.button == SDL_BUTTON_RIGHT)
1199           {
1200             le_mouse_pressed[RIGHT] = false;
1201             le_mouse_clicked[RIGHT] = true;
1202           }
1203           break;
1204         case SDL_MOUSEMOTION:
1205
1206           if(!Menu::current())
1207           {
1208             x = event.motion.x;
1209             y = event.motion.y;
1210
1211             if(le_current.IsTile())
1212             {
1213               cursor_x = ((int)(pos_x + x) / 32) * 32;
1214               cursor_y = ((int) y / 32) * 32;
1215             }
1216             else
1217             {
1218               cursor_x = x;
1219               cursor_y = y;
1220             }
1221
1222             if(le_mouse_pressed[LEFT])
1223             {
1224               selection.x2 = x + pos_x;
1225               selection.y2 = y;
1226             }
1227
1228             if(le_mouse_pressed[RIGHT])
1229             {
1230               pos_x += -1 * event.motion.xrel;
1231             }
1232           }
1233           break;
1234         default:
1235           break;
1236         }
1237       }
1238       else if(event.type == SDL_QUIT) /* window closing */
1239       {
1240       done = 1;
1241       }
1242     }
1243
1244     if(le_world != NULL)
1245     {
1246       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 &&
1247           event.motion.y > 0 && event.motion.y < screen->h)))
1248       {
1249         le_mouse_pressed[LEFT] = false;
1250         le_mouse_pressed[RIGHT] = false;
1251
1252         if(!Menu::current())
1253         {
1254           /* Check for button events */
1255           le_test_level_bt->event(event);
1256           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1257             le_testlevel();
1258           le_save_level_bt->event(event);
1259           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1260             le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
1261           le_exit_bt->event(event);
1262           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1263           {
1264             Menu::set_current(leveleditor_menu);
1265           }
1266           le_next_level_bt->event(event);
1267           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1268           {
1269             if(le_level < le_level_subset->levels)
1270             {
1271               le_goto_level(le_level+1);
1272             }
1273             else
1274             {
1275               Level new_lev;
1276               char str[1024];
1277               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1278               if(confirm_dialog(str))
1279               {
1280                 new_lev.init_defaults();
1281                 new_lev.save(le_level_subset->name.c_str(),le_level+1);
1282                 le_level_subset->levels = le_level;
1283                 le_goto_level(le_level);
1284               }
1285             }
1286           }
1287           le_previous_level_bt->event(event);
1288           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1289           {
1290             if(le_level > 1)
1291               le_goto_level(le_level -1);
1292           }
1293           le_rubber_bt->event(event);
1294           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1295             le_current.Tile(0);
1296
1297           if(!cur_objects.empty())
1298           {
1299             le_object_select_bt->event(event);
1300             if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1301             {
1302               MouseCursor::set_current(mouse_select_object);
1303             }
1304
1305             le_object_properties_bt->event(event);
1306             if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1307             {
1308               le_change_object_properties(selected_game_object);
1309             }
1310           }
1311
1312
1313           if(le_selection_mode == SQUARE)
1314           {
1315             le_select_mode_one_bt->event(event);
1316             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1317               le_selection_mode = CURSOR;
1318           }
1319           else
1320           {
1321             le_select_mode_two_bt->event(event);
1322             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1323               le_selection_mode = SQUARE;
1324           }
1325           ButtonPanelMap::iterator it;
1326           le_tilegroup_bt->event(event);
1327           switch (le_tilegroup_bt->get_state())
1328           {
1329           case BUTTON_CLICKED:
1330             Menu::set_current(select_tilegroup_menu);
1331             select_tilegroup_menu_effect.start(200);
1332             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1333             break;
1334           case BUTTON_WHEELUP:
1335             if(cur_tilegroup.empty())
1336             {
1337               cur_tilegroup = tilegroups_map.begin()->first;
1338             }
1339             else
1340             {
1341               it = tilegroups_map.find(cur_tilegroup);
1342               if((++it) == tilegroups_map.end())
1343               {
1344                 cur_tilegroup = tilegroups_map.begin()->first;
1345               }
1346               else
1347               {
1348                 cur_tilegroup = (*it).first;
1349               }
1350             }
1351
1352             cur_objects = "";
1353             break;
1354           case BUTTON_WHEELDOWN:
1355             it = tilegroups_map.find(cur_tilegroup);
1356             if(it == tilegroups_map.begin())
1357             {
1358               cur_tilegroup = tilegroups_map.rbegin()->first;
1359               cur_objects = "";
1360               break;
1361             }
1362             if(--it != --tilegroups_map.begin())
1363               cur_tilegroup = (*it).first;
1364             else
1365               cur_tilegroup = tilegroups_map.rbegin()->first;
1366
1367             cur_objects = "";
1368             break;
1369           default:
1370             break;
1371           }
1372
1373           le_objects_bt->event(event);
1374           switch (le_objects_bt->get_state())
1375           {
1376           case BUTTON_CLICKED:
1377             Menu::set_current(select_objects_menu);
1378             select_objects_menu_effect.start(200);
1379             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1380             break;
1381           case BUTTON_WHEELUP:
1382             it = objects_map.find(cur_objects);
1383             if(it == objects_map.end())
1384             {
1385               cur_objects = objects_map.begin()->first;
1386               cur_tilegroup = "";
1387               break;
1388             }
1389             if(++it != objects_map.end())
1390               cur_objects = (*it).first;
1391             else
1392               cur_objects = objects_map.begin()->first;
1393
1394             cur_tilegroup = "";
1395             break;
1396           case BUTTON_WHEELDOWN:
1397             it = objects_map.find(cur_objects);
1398             if(it == objects_map.begin())
1399             {
1400               cur_objects = objects_map.rbegin()->first;
1401               cur_tilegroup = "";
1402               break;
1403             }
1404             if(--it != --objects_map.begin())
1405               cur_objects = (*it).first;
1406             else
1407               cur_objects = objects_map.rbegin()->first;
1408
1409             cur_tilegroup = "";
1410             break;
1411             break;
1412           default:
1413             break;
1414           }
1415
1416           le_settings_bt->event(event);
1417           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1418           {
1419             update_level_settings_menu();
1420             Menu::set_current(level_settings_menu);
1421           }
1422           if(!cur_tilegroup.empty())
1423           {
1424             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1425             {
1426               if(pbutton->get_state() == BUTTON_CLICKED)
1427               {
1428                 le_current.Tile(pbutton->get_tag());
1429               }
1430             }
1431           }
1432           else if(!cur_objects.empty())
1433           {
1434             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1435             {
1436               if(pbutton->get_state() == BUTTON_CLICKED)
1437               {
1438                 le_current.Object(pbutton->get_game_object());
1439               }
1440             }
1441           }
1442
1443           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1444           {
1445             if(pbutton->get_state() == BUTTON_CLICKED)
1446             {
1447               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1448             }
1449           }
1450         }
1451         else
1452         {
1453           le_settings_bt->event(event);
1454           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1455           {
1456             Menu::set_current(0);
1457           }
1458           le_tilegroup_bt->event(event);
1459           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1460           {
1461             Menu::set_current(0);
1462           }
1463           le_objects_bt->event(event);
1464           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1465           {
1466             Menu::set_current(0);
1467           }
1468         }
1469       }
1470
1471       if(!Menu::current() && !show_minimap)
1472       {
1473         if(le_mouse_pressed[LEFT])
1474         {
1475           if(MouseCursor::current() != mouse_select_object)
1476           {
1477             if(le_current.IsTile())
1478               le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1479           }
1480         }
1481         else if(le_mouse_clicked[LEFT])
1482         {
1483           if(MouseCursor::current() == mouse_select_object)
1484           {
1485             int i = 0;
1486             bool object_got_hit = false;
1487             base_type cursor_base;
1488             if(le_current.IsTile())
1489             {
1490             cursor_base.x = cursor_x;
1491             cursor_base.y = cursor_y;
1492             }
1493             else if(le_current.IsObject())
1494             {
1495             cursor_base.x = cursor_x + pos_x;
1496             cursor_base.y = cursor_y + pos_x;       
1497             }
1498             cursor_base.width = 32;
1499             cursor_base.height = 32;
1500
1501             for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1502               if(rectcollision(cursor_base,(*it)->base))
1503               {
1504                 selected_game_object = (*it);
1505                 object_got_hit = true;
1506                 break;
1507               }
1508
1509             if(!object_got_hit)
1510             {
1511               selected_game_object = NULL;
1512               le_object_properties_bt->set_active(false);
1513             }
1514             else
1515               le_object_properties_bt->set_active(true);
1516
1517             MouseCursor::set_current(mouse_cursor);
1518
1519           }
1520           else
1521           {
1522             if(le_current.IsObject())
1523             {
1524               le_level_changed  = true;
1525               std::string type = le_current.obj->type();
1526               if(type == "BadGuy")
1527               {
1528                 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1529
1530                 le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1531                 le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1532               }
1533             }
1534           }
1535           
1536           le_mouse_clicked[LEFT] = false;
1537
1538         }
1539       }
1540     }
1541   }
1542   if(!Menu::current())
1543   {
1544     show_minimap = false;
1545
1546     le_move_left_bt->event(event);
1547     le_move_right_bt->event(event);
1548     switch(le_move_left_bt->get_state())
1549     {
1550     case BUTTON_PRESSED:
1551       pos_x -= 192;
1552       show_minimap = true;
1553       break;
1554     case BUTTON_HOVER:
1555       pos_x -= 32;
1556       show_minimap = true;
1557       break;
1558     case BUTTON_CLICKED:
1559       show_minimap = true;
1560       break;
1561     default:
1562       break;
1563     }
1564
1565     switch(le_move_right_bt->get_state())
1566     {
1567     case BUTTON_PRESSED:
1568       pos_x += 192;
1569       show_minimap = true;
1570       break;
1571     case BUTTON_HOVER:
1572       pos_x += 32;
1573       show_minimap = true;
1574       break;
1575     case BUTTON_CLICKED:
1576       show_minimap = true;
1577       break;
1578     default:
1579       break;
1580     }
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,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 }