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