Had a bit of time today and worked on supertux:
[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   SDL_Event event;
237   while(SDL_PollEvent(&event))
238     {
239     Menu* menu = Menu::current();
240     if(menu)
241       {
242       menu->event(event);
243       menu->action();
244       if(menu == main_menu)
245         {
246         switch (main_menu->check())
247           {
248           case MN_ID_RETURN:
249             Menu::set_current(0);
250             break;
251           case MN_ID_QUIT:
252             done = true;
253             break;
254           }
255         }
256       else if(menu == create_subset_menu)
257         {
258         // activate or deactivate Create button if any filename as been specified
259         if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
260           create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
261         else
262           create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_ACTION;
263
264         if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
265           {   // applying settings:
266           std::string subset_name = create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input;
267           LevelSubset::create(subset_name);
268
269           delete level_subset;
270           level_subset = new LevelSubset();
271           level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
272
273           level_subset->title = create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).input;
274           level_subset->description = create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).input;
275           //FIXME: generate better level filenames
276           level_subset->add_level(subset_name+'/'+"new_level.stl");
277           Level* newlevel = new Level();
278           newlevel->add_sector(create_sector("main", 25, 19));
279           newlevel->save(level_subset->get_level_filename(0));
280           level_subset->save();
281           
282           load_level(0);
283
284           create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
285           create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
286           create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
287           }
288         }
289       else if(menu == subset_menu)
290         {
291         int i = subset_menu->check();
292         if(i >= 0)
293           {
294           std::set<std::string>::iterator it = level_subsets.begin();
295           for(int t = 0; t < i; t++)
296             it++;
297           load_level_subset(*it);
298           Menu::set_current(0);
299           }
300         }
301       else if(menu == settings_menu)
302         {
303         if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
304           {   // applying settings:
305           level_changed = true;
306
307           level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
308           level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
309
310           solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
311                 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
312           foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
313                 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
314           backgrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
315                 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
316
317           Menu::set_current(0);
318           }
319         }
320       }
321     // check for events in buttons
322     else if(tiles_board->event(event))
323       {
324       std::vector <int> vector;
325       vector.push_back(tiles_board->selected_id());
326
327       selection.clear();
328       selection.push_back(vector);
329       continue;
330       }
331     else if(tiles_layer->event(event))
332       {
333       cur_layer = tiles_layer->selected_id();
334       continue;
335       }
336     else if(level_options->event(event))
337       {
338       switch(level_options->selected_id())
339         {
340         case BT_LEVEL_SAVE:
341           save_level();
342           break;
343         case BT_LEVEL_TEST:
344           test_level();
345           break;
346         case BT_LEVEL_SETUP:
347           Menu::set_current(settings_menu);
348           break;
349         case BT_NEXT_LEVEL:
350           if(level_nb + 1 < level_subset->get_num_levels())
351             load_level(level_nb + 1);
352           else
353             {
354             char str[1024];
355             sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 2);
356             if(confirm_dialog(NULL, str))
357               {
358               level_subset->add_level("new_level.stl");
359               Level* newlevel = new Level();
360               newlevel->add_sector(create_sector("main", 25, 19));
361               newlevel->save(level_subset->get_level_filename(level_nb + 1));
362               level_subset->save();
363               load_level(level_nb + 1);
364               }
365             }
366           break;
367         case BT_PREVIOUS_LEVEL:
368           if(level_nb - 1 >= 0)
369             load_level(level_nb - 1);
370           break;
371         case BT_NEXT_SECTOR:
372           std::cerr << "next sector.\n";
373           load_sector(sectornum+1);
374           break;
375         case BT_PREVIOUS_SECTOR:
376           std::cerr << "previous sector.\n";
377           if(sectornum > 0)
378             load_sector(sectornum-1);
379           break;
380         }
381       level_options->set_unselected();
382       continue;
383       }
384     else
385       {
386       switch(event.type)
387         {
388         case SDL_MOUSEMOTION:
389           mouse_moved = true;
390           mouse_x = event.motion.x;
391           mouse_y = event.motion.y;
392           if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
393             {  // movement like in strategy games
394             scroll.x += -1 * event.motion.xrel;
395             scroll.y += -1 * event.motion.yrel;
396             }
397           break;
398
399         case SDL_MOUSEBUTTONDOWN:
400           mouse_moved = true;
401           mouse_x = event.motion.x;
402           mouse_y = event.motion.y;          
403           if(event.button.button == SDL_BUTTON_LEFT)
404             left_button = true;
405           else if(event.button.button == SDL_BUTTON_MIDDLE)
406             {
407             middle_button = true;
408             selection_ini = Vector(event.button.x, event.button.y);
409             }
410           break;
411
412         case SDL_MOUSEBUTTONUP:
413           mouse_moved = true;
414           mouse_x = event.motion.x;
415           mouse_y = event.motion.y;                    
416           if(event.button.button == SDL_BUTTON_LEFT)
417             left_button = false;
418           else if(event.button.button == SDL_BUTTON_MIDDLE)
419             {
420             middle_button = false;
421             selection_end = Vector(event.button.x, event.button.y);
422
423             if(selection_end.x < selection_ini.x)
424               {
425               float t = selection_ini.x;
426               selection_ini.x = selection_end.x;
427               selection_end.x = t;
428               }
429             if(selection_end.y < selection_ini.y)
430               {
431               float t = selection_ini.y;
432               selection_ini.y = selection_end.y;
433               selection_end.y = t;
434               }
435
436             selection.clear();
437             std::vector <int> vector;
438
439             TileMap* tilemap = 0;
440             if(cur_layer == LAYER_FOREGROUNDTILES)
441               tilemap = foregrounds;
442             else if(cur_layer == LAYER_TILES)
443               tilemap = solids;
444             else if(cur_layer == LAYER_BACKGROUNDTILES)
445               tilemap = backgrounds;
446
447             for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
448               {
449               vector.clear();
450               for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
451                 {
452                 vector.push_back(tilemap->get_tile(x +
453                  (int)(((selection_ini.x+scroll.x)*zoom)/32),
454                  y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->getID());
455                 }
456               selection.push_back(vector);
457               }
458             }
459           break;
460
461         case SDL_KEYDOWN:   // key pressed
462           switch(event.key.keysym.sym)
463             {
464             case SDLK_ESCAPE:
465               Menu::set_current(main_menu);
466               break;
467             /* scrolling related events: */
468             case SDLK_HOME:
469               scroll.x = 0;
470               break;
471             case SDLK_END:
472               scroll.x = sector->solids->get_height()*32 - screen->w;
473               break;
474             case SDLK_LEFT:
475               scroll.x -= 80;
476               break;
477             case SDLK_RIGHT:
478               scroll.x += 80;
479               break;
480             case SDLK_UP:
481               scroll.y -= 80;
482               break;
483             case SDLK_DOWN:
484               scroll.y += 80;
485               break;
486             case SDLK_PAGEUP:
487               scroll.x -= 450;
488               break;
489             case SDLK_PAGEDOWN:
490               scroll.x += 450;
491               break;
492             case SDLK_PLUS:
493             case SDLK_KP_PLUS:
494               zoom += 0.10;
495               break;
496             case SDLK_MINUS:
497             case SDLK_KP_MINUS:
498               zoom -= 0.10;
499               break;
500
501             case SDLK_F1:
502               show_help();
503               break;
504             case SDLK_F2:
505               show_grid = !show_grid;
506               break;
507             default:
508               break;
509             }
510           break;
511
512         case SDL_QUIT:   // window closed
513           done = true;
514           break;
515
516           default:
517             break;
518         }
519       }
520     }
521 }
522
523 void LevelEditor::action()
524 {
525   mouse_cursor->set_state(MC_NORMAL);
526   if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
527     mouse_cursor->set_state(MC_LINK);
528
529   if(sector)
530     {
531     // don't scroll before the start or after the level's end
532     float width = sector->solids->get_width() * 32;
533     float height = sector->solids->get_height() * 32;
534
535     if(scroll.x < -screen->w/2)
536       scroll.x = -screen->w/2;
537     if(scroll.x > width - screen->w/2)
538       scroll.x = width - screen->w/2;
539     if(scroll.y < -screen->h/2)
540       scroll.y = -screen->h/2;
541     if(scroll.y > height - screen->h/2)
542       scroll.y = height - screen->h/2;
543
544     // set camera translation, since BadGuys like it
545     sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
546
547     if(left_button && mouse_moved)
548       for(unsigned int x = 0; x < selection.size(); x++)
549         for(unsigned int y = 0; y < selection[x].size(); y++)
550           change((int)(scroll.x + mouse_x) + (x*32),
551                (int)(scroll.y + mouse_y) + (y*32), selection[x][y], 
552                cur_layer);
553     }
554 }
555
556 #define FADING_TIME .6
557
558 void LevelEditor::draw(DrawingContext& context)
559 {
560   context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
561   mouse_cursor->draw(context);
562
563   // draw a filled background
564   context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
565
566   if(level_name_timer.check())
567     {
568     context.push_transform();
569     if(level_name_timer.get_timeleft() < FADING_TIME)
570       context.set_alpha(int(level_name_timer.get_timeleft() * 255 / FADING_TIME));
571
572     context.draw_text(gold_text, level->name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
573     if(level_nb != -1)
574       {
575       char str[128];
576       sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
577       context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
578       }
579
580     context.pop_transform();
581     }
582   if(sector)
583     context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
584   else
585     context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
586
587   Menu* menu = Menu::current();
588   if(menu)
589     menu->draw(context);
590   else
591     {
592     tiles_board->draw(context);
593     tiles_layer->draw(context);
594     level_options->draw(context);
595     }
596
597   // draw selection
598   if(sector)
599     {
600     if(!middle_button)
601       {
602       context.set_drawing_effect(SEMI_TRANSPARENT);
603
604       if(selection.size())
605         {
606         if(selection[0][0] == 0 && selection.size() == 1)
607             context.draw_surface(img_rubber_bt, Vector(mouse_x - 8,
608             mouse_y - 8), LAYER_GUI-2);
609         else if(selection[0][0] >= gameobjs_first_id || selection[0][0] < 0)
610           {
611   // FIXME: this should draw an object image near cursor
612   #if 0
613           int id = selection[0][0];
614
615           if(id == OBJ_TRAMPOLINE)
616             context.draw_surface(img_trampoline[0].get_frame(0), Vector(mouse_x - 8,
617             mouse_y - 8), LAYER_GUI-2);
618           else if(id == OBJ_FLYING_PLATFORM)
619             context.draw_surface(img_flying_platform->get_frame(0), Vector(mouse_x - 8,
620             mouse_y - 8), LAYER_GUI-2);
621           else
622           if(id == OBJ_DOOR)
623             /*context.draw_surface(door->get_frame(0), Vector(mouse_x - 8,
624             mouse_y - 8), LAYER_GUI-2);*/
625             ;
626           else
627             {
628             BadGuyKind kind = BadGuyKind((-id)-1);
629             BadGuy badguy(kind, 0,0);
630             badguy.activate(LEFT);
631             Surface *img = badguy.get_image();
632
633             context.draw_surface(img, Vector(mouse_x - 8,
634             mouse_y - 8), LAYER_GUI-2);
635             }
636   #endif
637           }
638         else
639           {
640           for(unsigned int x = 0; x < selection.size(); x++)
641             for(unsigned int y = 0; y < selection[x].size(); y++) {
642               const Tile* tile = tile_manager->get(selection[x][y]);
643               tile->draw(context,
644                   Vector(mouse_x + x*32 - 8, mouse_y + y*32 - 8),
645                   LAYER_GUI-2);
646             }
647           }
648         }
649       context.set_drawing_effect(NONE_EFFECT);
650       }
651     else
652       context.draw_filled_rect(Vector(std::min((int)selection_ini.x, mouse_x)*zoom,
653                      std::min((int)selection_ini.y, mouse_y))*zoom,
654                      Vector(abs(mouse_x - (int)selection_ini.x)*zoom,
655                      abs(mouse_y - (int)selection_ini.y)*zoom),
656                      Color(170,255,170,128), LAYER_GUI-2);
657
658     if(show_grid)
659       {
660       for(int x = 0; x < screen->w / (32*zoom); x++)
661         {
662         int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
663         context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
664                   Color(225, 225, 225), LAYER_GUI-50);
665         }
666       for(int y = 0; y < screen->h / (32*zoom); y++)
667         {
668         int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
669         context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
670                   Color(225, 225, 225), LAYER_GUI-50);
671         }
672       }
673
674     context.push_transform();
675     context.set_translation(scroll);
676     context.set_zooming(zoom);
677
678     for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
679       {
680       TileMap* tilemap = dynamic_cast<TileMap*> (*i);
681       if(tilemap)
682         {  // draw the non-selected tiles semi-transparently
683         context.push_transform();
684
685         if(tilemap->get_layer() != cur_layer)
686           context.set_drawing_effect(SEMI_TRANSPARENT);
687         (*i)->draw(context);
688
689         context.pop_transform();
690         continue;
691         }
692       Background* background = dynamic_cast<Background*> (*i);
693       if(background)
694         {  // don't resize background
695         context.push_transform();
696         context.set_zooming(1.0);
697         (*i)->draw(context);
698         context.pop_transform();
699         }
700       else
701         (*i)->draw(context);
702       }
703
704     context.pop_transform();
705     }
706   else
707     context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
708
709   context.do_drawing();
710 }
711
712 void LevelEditor::load_level_subset(std::string filename)
713 {
714   delete level_subset;
715   level_subset = new LevelSubset();
716   level_subset->load(filename.c_str());
717   load_level(0);
718 }
719
720 void LevelEditor::load_level(std::string filename)
721 {
722   if(level_changed)
723     {
724     if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
725       save_level();
726     else
727       return;
728     }
729
730   level_filename = filename;
731
732   delete level;
733   level = new Level();
734   level->load(filename);
735   
736   sectornum = 0;
737   load_sector(0);
738   level_name_timer.start(3000);
739   scroll.x = scroll.y = 0;
740   level_changed = false;
741
742   settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
743   settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
744 }
745
746 void LevelEditor::load_level(int nb)
747 {
748   if(level_changed)
749     {
750     if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
751       save_level();
752     else
753       return;
754     }
755
756   level_nb = nb;
757   level_filename = level_subset->get_level_filename(level_nb);
758
759   load_level(level_filename);
760 }
761
762 void LevelEditor::load_sector(size_t num)
763 {
764   assert(num <= level->get_sector_count());
765   
766   if(num >= level->get_sector_count())
767   {
768     if(!confirm_dialog(NULL, _("No more sectors exist. Create another?")))
769       return;
770     Sector* sector_ = create_sector("new_sector",25,19);
771     level->add_sector(sector_);
772     num = level->get_sector_count()-1;
773   }
774
775   sector = level->get_sector(num);
776
777   /* Load sector stuff */
778
779   sector->update_game_objects();
780
781   foregrounds = solids = backgrounds = 0;
782   /* Point foregrounds, backgrounds, solids to its layer */
783   for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
784     {
785     TileMap* tilemap = dynamic_cast<TileMap*> (*i);
786     if(tilemap)
787       {
788       if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
789         foregrounds = tilemap;
790       else if(tilemap->get_layer() == LAYER_TILES)
791         solids = tilemap;
792       else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
793         backgrounds = tilemap;
794       }
795     }
796
797   if(!foregrounds)
798     {
799     TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
800     sector->add_object(tilemap);
801     sector->update_game_objects();
802     }
803   if(!backgrounds)
804     {
805     TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
806     sector->add_object(tilemap);
807     sector->update_game_objects();
808     }
809
810   char str[64];
811   sprintf(str, "%i", solids->get_width());
812   settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
813   sprintf(str, "%i", solids->get_height());
814   settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
815
816   sectornum = num;
817 }
818
819 void LevelEditor::save_level()
820 {
821   level->save(level_filename);
822   level_changed = false;
823 }
824
825 void LevelEditor::test_level()
826 {
827   if(level_changed) {
828     if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
829       save_level();
830     else
831       return;
832   }
833
834   GameSession session(level_filename, ST_GL_TEST);
835   session.run();
836   //  player_status.reset();
837   SoundManager::get()->halt_music();
838 }
839
840 void LevelEditor::change(int x, int y, int newtile, int layer)
841 {  
842   (void) layer;
843   // find the tilemap of the current layer, and then change the tile
844   if(x < 0 || (unsigned int)x >= sector->solids->get_width()*32 ||
845       y < 0 || (unsigned int)y >= sector->solids->get_height()*32)
846     return;
847
848   level_changed = true;
849   
850   if(zoom != 1)
851   { 
852     // no need to do this for normal view (no zoom)
853     x = (int)(x * (zoom*32) / 32);
854     y = (int)(y * (zoom*32) / 32);
855   }
856
857   if(newtile >= gameobjs_first_id)  // add object
858   {
859     // remove an active tile or object that might be there
860     change(x, y, 0, LAYER_TILES);
861
862     int id = 0;
863     GameObject* object = 0;
864     for(Factories::iterator i = object_factories->begin(); i !=
865         object_factories->end(); ++i) {
866       if(id == newtile - gameobjs_first_id) {
867         object = create_object(i->first, Vector(x, y));
868         break;
869       }
870       id++;
871     }
872     if(object) {
873       sector->add_object(object);
874       sector->update_game_objects();
875     }
876   } else if(cur_layer == LAYER_FOREGROUNDTILES) {
877     foregrounds->change(x/32, y/32, newtile);
878   } else if(cur_layer == LAYER_TILES) {
879     // remove a bad guy if it's there
880     // we /32 in order to round numbers
881     for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
882         i < sector->gameobjects.end(); i++) {
883 // FIXME: if there is a game objs in here, remove it!
884 #if 0
885       BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
886       if(badguy)
887         if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
888           sector->gameobjects.erase(i);
889       Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
890       if(trampoline)
891       {
892         if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
893           sector->gameobjects.erase(i);
894       }
895       FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
896       if(flying_platform)
897         if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
898           sector->gameobjects.erase(i);
899       Door* door = dynamic_cast<Door*> (*i);
900       if(door)
901         if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
902           sector->gameobjects.erase(i);
903 #endif
904     }
905     sector->update_game_objects();
906     solids->change(x/32, y/32, newtile);
907   } else if(cur_layer == LAYER_BACKGROUNDTILES)
908     backgrounds->change(x/32, y/32, newtile);
909 }
910
911 void LevelEditor::show_help()
912 {
913   DrawingContext context;
914
915   bool show_grid_t = show_grid;
916   show_grid = false;
917   mouse_cursor->set_state(MC_HIDE);
918
919
920   char str[1024];
921   const char *text1[] = {
922            _("This is the built-in level editor. Its aim is to be intuitive\n"
923            "and simple to use, so it should be pretty straightforward.\n"
924            "\n"
925            "To open a level, first you'll have to select a level subset from\n"
926            "the menu (or create your own).\n"
927            "A level subset is basically a collection of levels.\n"
928            "They can then be played from the Contrib menu.\n"
929            "\n"
930            "To access the menu from the level editor, just press Esc.\n"
931            "\n"
932            "You are currently looking at the level. To scroll it, just\n"
933            "press the right mouse button and drag the mouse. It will move like\n"
934            "a strategy game.\n"
935            "You can also use the arrow keys and Page Up/Down.\n"
936            "\n"
937            "'+' and '-' keys can be used to zoom the level in/out.\n"
938            "\n"
939            "You probably already noticed those floating groups of buttons.\n"
940            "Each one serves a different purpose. To select a certain button\n"
941            "just press the Left mouse button on it. A few buttons have key\n"
942            "shortcuts. You can find them by pressing the Right mouse button on\n"
943            "a button. That will also show what that button does.\n"
944            "Groups of buttons can also be moved around by just dragging them,\n"
945            "while pressing the Left mouse button.\n"
946            "\n"
947            "Let's learn a bit of what each group of buttons does, shall we?\n"
948            "\n"
949            "To starting putting tiles and objects around use the bigger group\n"
950            "of buttons. Each button is a different tile. To put it on the level,\n"
951            "just press it and then left click in the level.\n"
952            "You can also copy tiles from the level by using the middle mouse button.\n"
953            "Use the mouse wheel to scroll that group of buttons. You will find\n"
954            "enemies and game objects in the bottom.\n")
955                   };
956
957   const char *text2[] = {
958            _("The Foreground/Interactive/Background buttons may be used to\n"
959            "see and edit the respective layer. Levels have three tiles layers:\n"
960            "Foreground - tiles are drawn on top of everything and have no contact\n"
961            "with the player.\n"
962            "Interactive - these are the tiles that have contact with the player.\n"
963            "Background - tiles are drawn underneath everything and have no contact\n"
964            "with the player.\n"
965            "The unselected layers will be drawn semi-transparently.\n"
966            "\n"
967            "Last, but not least, the group of buttons that's left serves\n"
968            "to do related actions with the level.\n"
969            "From left to right:\n"
970            "Mini arrows - can be used to choose other sectors.\n"
971            "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
972            "Big arrows - choose other level in the same level subset.\n"
973            "Diskette - save the level\n"
974            "Tux - test the level\n"
975            "Tools - set a few settings for the level, including resizing it.\n"
976            "\n"
977            "We have reached the end of this Howto.\n"
978            "\n"
979            "Don't forget to send us a few cool levels. :)\n"
980            "\n"
981            "Enjoy,\n"
982            "  SuperTux development team\n"
983            "\n"
984            "PS: If you are looking for something more powerful, you might like to\n"
985            "try FlexLay. FlexLay is a level editor that supports several games,\n"
986            "including SuperTux. It is an independent project.\n"
987            "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
988                   };
989
990   const char **text[] = { text1, text2 };
991
992
993   bool done;
994   for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
995     {
996     draw(context);
997
998     context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
999
1000     context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
1001
1002     sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
1003     context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
1004
1005     context.do_drawing();
1006
1007     done = false;
1008
1009     while(!done) {
1010       SDL_Event event;
1011       done = wait_for_event(event);
1012       SDL_Delay(50);
1013     }
1014   }
1015
1016   show_grid = show_grid_t;
1017   mouse_cursor->set_state(MC_NORMAL);
1018 }
1019
1020 Sector*
1021 LevelEditor::create_sector(const std::string& name, size_t width, size_t height)
1022 {
1023   Sector* sector = new Sector;
1024   sector->set_name(name);
1025   
1026   sector->add_object(new TileMap(LAYER_BACKGROUNDTILES, false, width, height));
1027   sector->add_object(new TileMap(LAYER_TILES, true, width, height));
1028   sector->add_object(new TileMap(LAYER_FOREGROUNDTILES, false, width, height));
1029   sector->add_object(new Camera(sector));
1030   sector->update_game_objects();
1031   
1032   return sector;
1033 }
1034