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