implemented a new object factory mechanism which is now really independent of the...
[supertux.git] / src / leveleditor.cpp
1 /***************************************************************************
2                   leveleditor.cpp  -  built'in leveleditor
3                      -------------------
4     begin                : June, 23 2004
5     copyright            : (C) 2004 by Ricardo Cruz
6     email                : rick2@aeiou.pt
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include <config.h>
19
20 #include <stdlib.h>
21 #include <algorithm>
22
23 #include "gui/mousecursor.h"
24 #include "gui/menu.h"
25 #include "gui/button.h"
26 #include "audio/sound_manager.h"
27 #include "app/gettext.h"
28 #include "app/setup.h"
29 #include "app/globals.h"
30 #include "special/sprite.h"
31 #include "leveleditor.h"
32 #include "resources.h"
33 #include "tile.h"
34 #include "tile_manager.h"
35 #include "sector.h"
36 #include "gameloop.h"
37 #include "object_factory.h"
38 #include "object/gameobjs.h"
39 #include "object/camera.h"
40 #include "object/tilemap.h"
41 #include "object/background.h"
42
43 LevelEditor::LevelEditor()
44 {
45   show_grid = true;
46
47   selection.clear();
48   selection_end = selection_ini = Vector(0,0);
49   left_button = middle_button = mouse_moved =  false;
50   level = 0;
51   level_subset = 0;
52
53   cur_layer = LAYER_TILES;
54   level_changed = false;
55
56   sector = 0;
57   zoom = 1.0;
58
59   /* Creating menus */
60   level_subsets = FileSystem::dsubdirs("/levels", "info");
61   subset_menu = new Menu();
62   subset_menu->additem(MN_LABEL,_("Load Subset"),0,0);
63   subset_menu->additem(MN_HL,"",0,0);
64   int i = 0;
65   for(std::set<std::string>::iterator it = level_subsets.begin(); it != level_subsets.end(); ++it, ++i)
66     subset_menu->additem(MN_ACTION, (*it),0,0,i);
67   subset_menu->additem(MN_HL,"",0,0);
68   subset_menu->additem(MN_BACK,_("Back"),0,0);
69
70   create_subset_menu = new Menu();
71   create_subset_menu->additem(MN_LABEL,_("New Level Subset"),0,0);
72   create_subset_menu->additem(MN_HL,"",0,0);
73   create_subset_menu->additem(MN_TEXTFIELD,_("Filename   "),0,0,MN_ID_FILENAME_SUBSET);
74   create_subset_menu->additem(MN_TEXTFIELD,_("Title      "),0,0,MN_ID_TITLE_SUBSET);
75   create_subset_menu->additem(MN_TEXTFIELD,_("Description"),0,0,MN_ID_DESCRIPTION_SUBSET);
76   create_subset_menu->additem(MN_ACTION,_("Create"),0,0, MN_ID_CREATE_SUBSET);
77   create_subset_menu->additem(MN_HL,"",0,0);
78   create_subset_menu->additem(MN_BACK,_("Back"),0,0);
79
80   main_menu = new Menu();
81   main_menu->additem(MN_LABEL,_("Level Editor Menu"),0,0);
82   main_menu->additem(MN_HL,"",0,0);
83   main_menu->additem(MN_ACTION,_("Return to Level Editor"),0,0,MN_ID_RETURN);
84   main_menu->additem(MN_GOTO,_("Create Level Subset"),0,create_subset_menu);
85   main_menu->additem(MN_GOTO,_("Load Level Subset"),0,subset_menu);
86   main_menu->additem(MN_HL,"",0,0);
87   main_menu->additem(MN_ACTION,_("Quit Level Editor"),0,0,MN_ID_QUIT);
88
89   settings_menu = new Menu();
90   settings_menu->additem(MN_LABEL,_("Level Settings"),0,0);
91   settings_menu->additem(MN_HL,"",0,0);
92   settings_menu->additem(MN_TEXTFIELD,_("Name    "),0,0,MN_ID_NAME);
93   settings_menu->additem(MN_TEXTFIELD,_("Author  "),0,0,MN_ID_AUTHOR);
94   settings_menu->additem(MN_NUMFIELD, _("Width   "),0,0,MN_ID_WIDTH);
95   settings_menu->additem(MN_NUMFIELD, _("Height  "),0,0,MN_ID_HEIGHT);
96   settings_menu->additem(MN_HL,"",0,0);
97   settings_menu->additem(MN_ACTION,_("Apply"),0,0,MN_ID_APPLY_SETTINGS);
98
99   /* Creating button groups */
100   load_buttons_gfx();
101
102   tiles_board = new ButtonGroup(Vector(screen->w - 140, 100),
103             Vector(32,32), Vector(4,8));
104
105   tiles_board->add_button(Button(img_rubber_bt, _("Eraser"), SDLKey(SDLK_DELETE)), 0);
106   unsigned int id;
107   for(id = 1; id < tile_manager->get_max_tileid(); id++)
108     {
109     const Tile* tile = tile_manager->get(id);
110     if(!tile)
111       continue;
112
113     Surface* surface = tile->get_editor_image();
114     if(!surface)
115       continue;
116
117     Button button = Button(surface, "", SDLKey(0));
118     tiles_board->add_button(button, id);
119     }
120   gameobjs_first_id = id;
121
122   for(Factories::iterator i = object_factories->begin();
123       i != object_factories->end(); ++i) {
124     
125 //    Surface *img = badguy.get_image();
126 // FIXME: get image from object. Using the rubber in the meanwhile.
127     tiles_board->add_button(Button(img_rubber_bt, i->first,
128                             SDLKey(SDLK_1+id)), id++);
129   }
130
131   tiles_layer = new ButtonGroup(Vector(12, screen->h-64), Vector(80,20), Vector(1,3));
132   tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
133                          SDLK_F10), LAYER_FOREGROUNDTILES);
134   tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
135                          SDLK_F11), LAYER_TILES, true);
136   tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
137                          SDLK_F12), LAYER_BACKGROUNDTILES);
138
139   level_options = new ButtonGroup(Vector(screen->w-164, screen->h-36), Vector(32,32), Vector(5,1));
140   level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
141                  Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
142   level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
143                  Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
144   level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
145   level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
146   level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
147 }
148
149 LevelEditor::~LevelEditor()
150 {
151 free_buttons_gfx();
152
153 delete tiles_board;
154 delete tiles_layer;
155 delete level_options;
156
157 delete subset_menu;
158 delete create_subset_menu;
159 delete main_menu;
160 delete settings_menu;
161
162 delete level;
163 delete level_subset;
164 }
165
166 void LevelEditor::load_buttons_gfx()
167 {
168 img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
169 img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
170 img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
171
172 img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
173 img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
174 img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
175
176 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
177
178 img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
179 img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
180 img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
181 img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
182 }
183
184 void LevelEditor::free_buttons_gfx()
185 {
186 delete img_foreground_bt;
187 delete img_interactive_bt;
188 delete img_background_bt;
189
190 delete img_save_level_bt;
191 delete img_test_level_bt;
192 delete img_setup_level_bt;
193
194 delete img_rubber_bt;
195
196 delete img_previous_level_bt;
197 delete img_next_level_bt;
198 delete img_previous_sector_bt;
199 delete img_next_sector_bt;
200 }
201
202 void LevelEditor::run(const std::string filename)
203 {
204 SoundManager::get()->halt_music();
205 Menu::set_current(0);
206
207 DrawingContext context;
208
209 if(!filename.empty())
210   {
211   level_nb = -1;
212   load_level(filename);
213   }
214 else
215   Menu::set_current(main_menu);
216
217 mouse_cursor->set_state(MC_NORMAL);
218
219 done = false;
220 while(!done)
221   {
222   events();
223   action();
224   draw(context);
225   }
226
227 if(level_changed)
228   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
229     save_level();
230 }
231
232 void LevelEditor::events()
233 {
234 mouse_moved = false;
235
236 while(SDL_PollEvent(&event))
237   {
238   Menu* menu = Menu::current();
239   if(menu)
240     {
241     menu->event(event);
242     menu->action();
243     if(menu == main_menu)
244       {
245       switch (main_menu->check())
246         {
247         case MN_ID_RETURN:
248           Menu::set_current(0);
249           break;
250         case MN_ID_QUIT:
251           done = true;
252           break;
253         }
254       }
255     else if(menu == create_subset_menu)
256       {
257       // activate or deactivate Create button if any filename as been specified
258       if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
259         create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
260       else
261         create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_ACTION;
262
263       if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
264         {   // applying settings:
265         std::string subset_name = create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input;
266         LevelSubset::create(subset_name);
267
268         delete level_subset;
269         level_subset = new LevelSubset();
270         level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
271
272         level_subset->title = create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).input;
273         level_subset->description = create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).input;
274         //FIXME: generate better level filenames
275         level_subset->add_level(subset_name+'/'+"new_level.stl");
276         Level* newlevel = new Level();
277         newlevel->add_sector(create_sector("main", 25, 19));
278         newlevel->save(level_subset->get_level_filename(0));
279         level_subset->save();
280         
281         load_level(0);
282
283         create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
284         create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
285         create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
286         }
287       }
288     else if(menu == subset_menu)
289       {
290       int i = subset_menu->check();
291       if(i >= 0)
292         {
293         std::set<std::string>::iterator it = level_subsets.begin();
294         for(int t = 0; t < i; t++)
295           it++;
296         load_level_subset(*it);
297         Menu::set_current(0);
298         }
299       }
300     else if(menu == settings_menu)
301       {
302       if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
303         {   // applying settings:
304         level_changed = true;
305
306         level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
307         level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
308
309         solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
310               atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
311         foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
312               atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
313         backgrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
314               atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
315
316         Menu::set_current(0);
317         }
318       }
319     }
320   // check for events in buttons
321   else if(tiles_board->event(event))
322     {
323     std::vector <int> vector;
324     vector.push_back(tiles_board->selected_id());
325
326     selection.clear();
327     selection.push_back(vector);
328     continue;
329     }
330   else if(tiles_layer->event(event))
331     {
332     cur_layer = tiles_layer->selected_id();
333     continue;
334     }
335   else if(level_options->event(event))
336     {
337     switch(level_options->selected_id())
338       {
339       case BT_LEVEL_SAVE:
340         save_level();
341         break;
342       case BT_LEVEL_TEST:
343         test_level();
344         break;
345       case BT_LEVEL_SETUP:
346         Menu::set_current(settings_menu);
347         break;
348       case BT_NEXT_LEVEL:
349         if(level_nb + 1 < level_subset->get_num_levels())
350           load_level(level_nb + 1);
351         else
352           {
353           char str[1024];
354           sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 2);
355           if(confirm_dialog(NULL, str))
356             {
357             level_subset->add_level("new_level.stl");
358             Level* newlevel = new Level();
359             newlevel->add_sector(create_sector("main", 25, 19));
360             newlevel->save(level_subset->get_level_filename(level_nb + 1));
361             level_subset->save();
362             load_level(level_nb + 1);
363             }
364           }
365         break;
366       case BT_PREVIOUS_LEVEL:
367         if(level_nb - 1 >= 0)
368           load_level(level_nb - 1);
369         break;
370       case BT_NEXT_SECTOR:
371 std::cerr << "next sector.\n";
372 std::cerr << "total sectors: " << level->get_total_sectors() << std::endl;
373         load_sector(level->get_next_sector(sector));
374         break;
375       case BT_PREVIOUS_SECTOR:
376 std::cerr << "previous sector.\n";
377         load_sector(level->get_previous_sector(sector));
378         break;
379       }
380     level_options->set_unselected();
381     continue;
382     }
383   else
384     {
385     switch(event.type)
386       {
387       case SDL_MOUSEMOTION:
388         mouse_moved = true;
389         if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
390           {  // movement like in strategy games
391           scroll.x += -1 * event.motion.xrel;
392           scroll.y += -1 * event.motion.yrel;
393           }
394         break;
395
396       case SDL_MOUSEBUTTONDOWN:
397         mouse_moved = true;
398         if(event.button.button == SDL_BUTTON_LEFT)
399           left_button = true;
400         else if(event.button.button == SDL_BUTTON_MIDDLE)
401           {
402           middle_button = true;
403           selection_ini = Vector(event.button.x, event.button.y);
404           }
405         break;
406
407       case SDL_MOUSEBUTTONUP:
408         mouse_moved = true;
409         if(event.button.button == SDL_BUTTON_LEFT)
410           left_button = false;
411         else if(event.button.button == SDL_BUTTON_MIDDLE)
412           {
413           middle_button = false;
414           selection_end = Vector(event.button.x, event.button.y);
415
416           if(selection_end.x < selection_ini.x)
417             {
418             float t = selection_ini.x;
419             selection_ini.x = selection_end.x;
420             selection_end.x = t;
421             }
422           if(selection_end.y < selection_ini.y)
423             {
424             float t = selection_ini.y;
425             selection_ini.y = selection_end.y;
426             selection_end.y = t;
427             }
428
429           selection.clear();
430           std::vector <int> vector;
431
432           TileMap* tilemap = 0;
433           if(cur_layer == LAYER_FOREGROUNDTILES)
434             tilemap = foregrounds;
435           else if(cur_layer == LAYER_TILES)
436             tilemap = solids;
437           else if(cur_layer == LAYER_BACKGROUNDTILES)
438             tilemap = backgrounds;
439
440           for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
441             {
442             vector.clear();
443             for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
444               {
445               vector.push_back(tilemap->get_tile(x +
446                (int)(((selection_ini.x+scroll.x)*zoom)/32),
447                y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->getID());
448               }
449             selection.push_back(vector);
450             }
451           }
452         break;
453
454       case SDL_KEYDOWN:   // key pressed
455         switch(event.key.keysym.sym)
456           {
457           case SDLK_ESCAPE:
458             Menu::set_current(main_menu);
459             break;
460           /* scrolling related events: */
461           case SDLK_HOME:
462             scroll.x = 0;
463             break;
464           case SDLK_END:
465             scroll.x = sector->solids->get_height()*32 - screen->w;
466             break;
467           case SDLK_LEFT:
468             scroll.x -= 80;
469             break;
470           case SDLK_RIGHT:
471             scroll.x += 80;
472             break;
473           case SDLK_UP:
474             scroll.y -= 80;
475             break;
476           case SDLK_DOWN:
477             scroll.y += 80;
478             break;
479           case SDLK_PAGEUP:
480             scroll.x -= 450;
481             break;
482           case SDLK_PAGEDOWN:
483             scroll.x += 450;
484             break;
485           case SDLK_PLUS:
486           case SDLK_KP_PLUS:
487             zoom += 0.10;
488             break;
489           case SDLK_MINUS:
490           case SDLK_KP_MINUS:
491             zoom -= 0.10;
492             break;
493
494           case SDLK_F1:
495             show_help();
496             break;
497           case SDLK_F2:
498             show_grid = !show_grid;
499             break;
500           default:
501             break;
502           }
503         break;
504
505       case SDL_QUIT:   // window closed
506         done = true;
507         break;
508
509         default:
510           break;
511       }
512     }
513   }
514 }
515
516 void LevelEditor::action()
517 {
518 mouse_cursor->set_state(MC_NORMAL);
519 if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
520   mouse_cursor->set_state(MC_LINK);
521
522 if(sector)
523   {
524   // don't scroll before the start or after the level's end
525   float width = sector->solids->get_width() * 32;
526   float height = sector->solids->get_height() * 32;
527
528   if(scroll.x < -screen->w/2)
529     scroll.x = -screen->w/2;
530   if(scroll.x > width - screen->w/2)
531     scroll.x = width - screen->w/2;
532   if(scroll.y < -screen->h/2)
533     scroll.y = -screen->h/2;
534   if(scroll.y > height - screen->h/2)
535     scroll.y = height - screen->h/2;
536
537   // set camera translation, since BadGuys like it
538   sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
539
540   if(left_button && mouse_moved)
541     for(unsigned int x = 0; x < selection.size(); x++)
542       for(unsigned int y = 0; y < selection[x].size(); y++)
543         change((int)(scroll.x + event.button.x) + (x*32),
544              (int)(scroll.y + event.button.y) + (y*32), selection[x][y], 
545              cur_layer);
546   }
547 }
548
549 #define FADING_TIME .6
550
551 void LevelEditor::draw(DrawingContext& context)
552 {
553 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
554 mouse_cursor->draw(context);
555
556 // draw a filled background
557 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
558
559 if(level_name_timer.check())
560   {
561   context.push_transform();
562   if(level_name_timer.get_timeleft() < FADING_TIME)
563     context.set_alpha(int(level_name_timer.get_timeleft() * 255 / FADING_TIME));
564
565   context.draw_text(gold_text, level->name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
566   if(level_nb != -1)
567     {
568     char str[128];
569     sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
570     context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
571     }
572
573   context.pop_transform();
574   }
575 if(sector)
576   context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
577 else
578   context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
579
580 Menu* menu = Menu::current();
581 if(menu)
582   menu->draw(context);
583 else
584   {
585   tiles_board->draw(context);
586   tiles_layer->draw(context);
587   level_options->draw(context);
588   }
589
590 // draw selection
591 if(sector)
592   {
593   if(!middle_button)
594     {
595     context.set_drawing_effect(SEMI_TRANSPARENT);
596
597     if(selection.size())
598       {
599       if(selection[0][0] == 0 && selection.size() == 1)
600           context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
601           event.button.y - 8), LAYER_GUI-2);
602       else if(selection[0][0] >= gameobjs_first_id || selection[0][0] < 0)
603         {
604 // FIXME: this should draw an object image near cursor
605 #if 0
606         int id = selection[0][0];
607
608         if(id == OBJ_TRAMPOLINE)
609           context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
610           event.button.y - 8), LAYER_GUI-2);
611         else if(id == OBJ_FLYING_PLATFORM)
612           context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
613           event.button.y - 8), LAYER_GUI-2);
614         else
615         if(id == OBJ_DOOR)
616           /*context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
617           event.button.y - 8), LAYER_GUI-2);*/
618           ;
619         else
620           {
621           BadGuyKind kind = BadGuyKind((-id)-1);
622           BadGuy badguy(kind, 0,0);
623           badguy.activate(LEFT);
624           Surface *img = badguy.get_image();
625
626           context.draw_surface(img, Vector(event.button.x - 8,
627           event.button.y - 8), LAYER_GUI-2);
628           }
629 #endif
630         }
631       else
632         {
633         for(unsigned int x = 0; x < selection.size(); x++)
634           for(unsigned int y = 0; y < selection[x].size(); y++) {
635             const Tile* tile = tile_manager->get(selection[x][y]);
636             tile->draw(context,
637                 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
638                 LAYER_GUI-2);
639           }
640         }
641       }
642     context.set_drawing_effect(NONE_EFFECT);
643     }
644   else
645     context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
646                    std::min((int)selection_ini.y, (int)event.button.y))*zoom,
647                    Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
648                    abs(event.button.y - (int)selection_ini.y)*zoom),
649                    Color(170,255,170,128), LAYER_GUI-2);
650
651   if(show_grid)
652     {
653     for(int x = 0; x < screen->w / (32*zoom); x++)
654       {
655       int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
656       context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
657                 Color(225, 225, 225), LAYER_GUI-50);
658       }
659     for(int y = 0; y < screen->h / (32*zoom); y++)
660       {
661       int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
662       context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
663                 Color(225, 225, 225), LAYER_GUI-50);
664       }
665     }
666
667   context.push_transform();
668   context.set_translation(scroll);
669   context.set_zooming(zoom);
670
671   for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
672     {
673     TileMap* tilemap = dynamic_cast<TileMap*> (*i);
674     if(tilemap)
675       {  // draw the non-selected tiles semi-transparently
676       context.push_transform();
677
678       if(tilemap->get_layer() != cur_layer)
679         context.set_drawing_effect(SEMI_TRANSPARENT);
680       (*i)->draw(context);
681
682       context.pop_transform();
683       continue;
684       }
685     Background* background = dynamic_cast<Background*> (*i);
686     if(background)
687       {  // don't resize background
688       context.push_transform();
689       context.set_zooming(1.0);
690       (*i)->draw(context);
691       context.pop_transform();
692       }
693     else
694       (*i)->draw(context);
695     }
696
697   context.pop_transform();
698   }
699 else
700   context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
701
702 context.do_drawing();
703 }
704
705 void LevelEditor::load_level_subset(std::string filename)
706 {
707 delete level_subset;
708 level_subset = new LevelSubset();
709 level_subset->load(filename.c_str());
710 load_level(0);
711 }
712
713 void LevelEditor::load_level(std::string filename)
714 {
715 if(level_changed)
716   {
717   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
718     save_level();
719   else
720     return;
721   }
722
723 level_filename = filename;
724
725 delete level;
726 level = new Level();
727 level->load(filename);
728
729 load_sector("main");
730 level_name_timer.start(3000);
731 scroll.x = scroll.y = 0;
732 level_changed = false;
733
734 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
735 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
736 }
737
738 void LevelEditor::load_level(int nb)
739 {
740 if(level_changed)
741   {
742   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
743     save_level();
744   else
745     return;
746   }
747
748 level_nb = nb;
749 level_filename = level_subset->get_level_filename(level_nb);
750
751 load_level(level_filename);
752 }
753
754 void LevelEditor::load_sector(std::string name)
755 {
756 sector_name = name;
757 sector = level->get_sector(sector_name);
758 if(!sector)
759   Termination::abort("Level has no " + sector_name + " sector.", "");
760
761 load_sector(sector);
762 }
763
764 void LevelEditor::load_sector(Sector* sector_)
765 {
766 if(sector_ == NULL)
767   {
768   if(!confirm_dialog(NULL, _("No more sectors exist. Create another?")))
769     return;
770   sector_ = create_sector("new_sector",25,19);
771   level->add_sector(sector_);
772   }
773
774 sector = sector_;
775
776 /* Load sector stuff */
777
778 sector->update_game_objects();
779
780 foregrounds = solids = backgrounds = 0;
781 /* Point foregrounds, backgrounds, solids to its layer */
782 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
783   {
784   TileMap* tilemap = dynamic_cast<TileMap*> (*i);
785   if(tilemap)
786     {
787     if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
788       foregrounds = tilemap;
789     else if(tilemap->get_layer() == LAYER_TILES)
790       solids = tilemap;
791     else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
792       backgrounds = tilemap;
793     }
794   }
795
796 if(!foregrounds)
797   {
798   TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
799   sector->add_object(tilemap);
800   sector->update_game_objects();
801   }
802 if(!backgrounds)
803   {
804   TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
805   sector->add_object(tilemap);
806   sector->update_game_objects();
807   }
808
809 char str[64];
810 sprintf(str, "%i", solids->get_width());
811 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
812 sprintf(str, "%i", solids->get_height());
813 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
814 }
815
816 void LevelEditor::save_level()
817 {
818 level->save(level_filename);
819 level_changed = false;
820 }
821
822 void LevelEditor::test_level()
823 {
824   if(level_changed) {
825     if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
826       save_level();
827     else
828       return;
829   }
830
831   GameSession session(level_filename, ST_GL_TEST);
832   session.run();
833   //  player_status.reset();
834   SoundManager::get()->halt_music();
835 }
836
837 void LevelEditor::change(int x, int y, int newtile, int layer)
838 {  
839   (void) layer;
840   // find the tilemap of the current layer, and then change the tile
841   if(x < 0 || (unsigned int)x >= sector->solids->get_width()*32 ||
842       y < 0 || (unsigned int)y >= sector->solids->get_height()*32)
843     return;
844
845   level_changed = true;
846   
847   if(zoom != 1)
848   { 
849     // no need to do this for normal view (no zoom)
850     x = (int)(x * (zoom*32) / 32);
851     y = (int)(y * (zoom*32) / 32);
852   }
853
854   if(newtile >= gameobjs_first_id)  // add object
855   {
856     // remove an active tile or object that might be there
857     change(x, y, 0, LAYER_TILES);
858
859     int id = 0;
860     GameObject* object = 0;
861     for(Factories::iterator i = object_factories->begin(); i !=
862         object_factories->end(); ++i) {
863       if(id == newtile - gameobjs_first_id) {
864         object = i->second->create_object(Vector(x, y));
865         break;
866       }
867       id++;
868     }
869     if(object) {
870       sector->add_object(object);
871       sector->update_game_objects();
872     }
873   } else if(cur_layer == LAYER_FOREGROUNDTILES) {
874     foregrounds->change(x/32, y/32, newtile);
875   } else if(cur_layer == LAYER_TILES) {
876     // remove a bad guy if it's there
877     // we /32 in order to round numbers
878     for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
879         i < sector->gameobjects.end(); i++) {
880 // FIXME: if there is a game objs in here, remove it!
881 #if 0
882       BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
883       if(badguy)
884         if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
885           sector->gameobjects.erase(i);
886       Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
887       if(trampoline)
888       {
889         if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
890           sector->gameobjects.erase(i);
891       }
892       FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
893       if(flying_platform)
894         if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
895           sector->gameobjects.erase(i);
896       Door* door = dynamic_cast<Door*> (*i);
897       if(door)
898         if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
899           sector->gameobjects.erase(i);
900 #endif
901     }
902     sector->update_game_objects();
903     solids->change(x/32, y/32, newtile);
904   } else if(cur_layer == LAYER_BACKGROUNDTILES)
905     backgrounds->change(x/32, y/32, newtile);
906 }
907
908 void LevelEditor::show_help()
909 {
910 DrawingContext context;
911
912 bool show_grid_t = show_grid;
913 show_grid = false;
914 mouse_cursor->set_state(MC_HIDE);
915
916
917 char str[1024];
918 const char *text1[] = {
919          _("This is the built-in level editor. Its aim is to be intuitive\n"
920          "and simple to use, so it should be pretty straightforward.\n"
921          "\n"
922          "To open a level, first you'll have to select a level subset from\n"
923          "the menu (or create your own).\n"
924          "A level subset is basically a collection of levels.\n"
925          "They can then be played from the Contrib menu.\n"
926          "\n"
927          "To access the menu from the level editor, just press Esc.\n"
928          "\n"
929          "You are currently looking at the level. To scroll it, just\n"
930          "press the right mouse button and drag the mouse. It will move like\n"
931          "a strategy game.\n"
932          "You can also use the arrow keys and Page Up/Down.\n"
933          "\n"
934          "'+' and '-' keys can be used to zoom the level in/out.\n"
935          "\n"
936          "You probably already noticed those floating groups of buttons.\n"
937          "Each one serves a different purpose. To select a certain button\n"
938          "just press the Left mouse button on it. A few buttons have key\n"
939          "shortcuts. You can find them by pressing the Right mouse button on\n"
940          "a button. That will also show what that button does.\n"
941          "Groups of buttons can also be moved around by just dragging them,\n"
942          "while pressing the Left mouse button.\n"
943          "\n"
944          "Let's learn a bit of what each group of buttons does, shall we?\n"
945          "\n"
946          "To starting putting tiles and objects around use the bigger group\n"
947          "of buttons. Each button is a different tile. To put it on the level,\n"
948          "just press it and then left click in the level.\n"
949          "You can also copy tiles from the level by using the middle mouse button.\n"
950          "Use the mouse wheel to scroll that group of buttons. You will find\n"
951          "enemies and game objects in the bottom.\n")
952                 };
953
954 const char *text2[] = {
955          _("The Foreground/Interactive/Background buttons may be used to\n"
956          "see and edit the respective layer. Levels have three tiles layers:\n"
957          "Foreground - tiles are drawn on top of everything and have no contact\n"
958          "with the player.\n"
959          "Interactive - these are the tiles that have contact with the player.\n"
960          "Background - tiles are drawn underneath everything and have no contact\n"
961          "with the player.\n"
962          "The unselected layers will be drawn semi-transparently.\n"
963          "\n"
964          "Last, but not least, the group of buttons that's left serves\n"
965          "to do related actions with the level.\n"
966          "From left to right:\n"
967          "Mini arrows - can be used to choose other sectors.\n"
968          "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
969          "Big arrows - choose other level in the same level subset.\n"
970          "Diskette - save the level\n"
971          "Tux - test the level\n"
972          "Tools - set a few settings for the level, including resizing it.\n"
973          "\n"
974          "We have reached the end of this Howto.\n"
975          "\n"
976          "Don't forget to send us a few cool levels. :)\n"
977          "\n"
978          "Enjoy,\n"
979          "  SuperTux development team\n"
980          "\n"
981          "PS: If you are looking for something more powerful, you might like to\n"
982          "try FlexLay. FlexLay is a level editor that supports several games,\n"
983          "including SuperTux. It is an independent project.\n"
984          "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
985                 };
986
987 const char **text[] = { text1, text2 };
988
989
990 bool done;
991 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
992   {
993   draw(context);
994
995   context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
996
997   context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
998
999   sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
1000   context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
1001
1002   context.do_drawing();
1003
1004   done = false;
1005
1006   while(!done)
1007     {
1008     done = wait_for_event(event);
1009     SDL_Delay(50);
1010     }
1011   }
1012
1013 show_grid = show_grid_t;
1014 mouse_cursor->set_state(MC_NORMAL);
1015 }
1016
1017 Sector*
1018 LevelEditor::create_sector(const std::string& name, size_t width, size_t height)
1019 {
1020   Sector* sector = new Sector;
1021   sector->set_name(name);
1022   
1023   sector->add_object(new TileMap(LAYER_BACKGROUNDTILES, false, width, height));
1024   sector->add_object(new TileMap(LAYER_TILES, true, width, height));
1025   sector->add_object(new TileMap(LAYER_FOREGROUNDTILES, false, width, height));
1026   sector->add_object(new Camera(sector));
1027   sector->update_game_objects();
1028   
1029   return sector;
1030 }
1031