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