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