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