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