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