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