6ebe73521591e0acb62a87d9e5304d4c7642f0fd
[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   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;
114     if(tile->editor_images.size())
115       surface = tile->editor_images[0];
116     else if(tile->images.size())
117       surface = tile->images[0];
118     else
119       continue;
120
121     Button button = Button(surface, "", SDLKey(0));
122     tiles_board->add_button(button, id);
123     }
124
125   #if 0
126   for(int i = 0; i < NUM_BadGuyKinds; i++)
127     {
128     // filter bomb, since it is only for internal use, not for levels
129     if(i == BAD_BOMB)
130       continue;
131
132     BadGuyKind kind = BadGuyKind(i);
133     BadGuy badguy(kind, 0,0);
134     badguy.activate(LEFT);
135
136     Surface *img = badguy.get_image();
137     tiles_board->add_button(Button(img, "", SDLKey(SDLK_1+i)), -(i+1));
138     }
139   #endif
140
141   #if 0
142   tiles_board->add_button(Button(img_trampoline[0].get_frame(0), _("Trampoline"), SDLKey(0)), OBJ_TRAMPOLINE);
143   tiles_board->add_button(Button(img_flying_platform->get_frame(0), _("Flying Platform"), SDLKey(0)), OBJ_FLYING_PLATFORM);
144   #endif
145
146   tiles_layer = new ButtonGroup(Vector(12, screen->h-64), Vector(80,20), Vector(1,3));
147   tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
148                          SDLK_F10), LAYER_FOREGROUNDTILES);
149   tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
150                          SDLK_F11), LAYER_TILES, true);
151   tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
152                          SDLK_F12), LAYER_BACKGROUNDTILES);
153
154   level_options = new ButtonGroup(Vector(screen->w-164, screen->h-36), Vector(32,32), Vector(5,1));
155   level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
156                  Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
157   level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
158                  Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
159   level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
160   level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
161   level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
162 }
163
164 LevelEditor::~LevelEditor()
165 {
166 free_buttons_gfx();
167
168 delete tiles_board;
169 delete tiles_layer;
170 delete level_options;
171
172 delete subset_menu;
173 delete create_subset_menu;
174 delete main_menu;
175 delete settings_menu;
176
177 delete level;
178 delete level_subset;
179 }
180
181 void LevelEditor::load_buttons_gfx()
182 {
183 img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
184 img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
185 img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
186
187 img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
188 img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
189 img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
190
191 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
192
193 img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
194 img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
195 img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
196 img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
197 }
198
199 void LevelEditor::free_buttons_gfx()
200 {
201 delete img_foreground_bt;
202 delete img_interactive_bt;
203 delete img_background_bt;
204
205 delete img_save_level_bt;
206 delete img_test_level_bt;
207 delete img_setup_level_bt;
208
209 delete img_rubber_bt;
210
211 delete img_previous_level_bt;
212 delete img_next_level_bt;
213 delete img_previous_sector_bt;
214 delete img_next_sector_bt;
215 }
216
217 void LevelEditor::run(const std::string filename)
218 {
219 SoundManager::get()->halt_music();
220 Menu::set_current(0);
221
222 DrawingContext context;
223
224 if(!filename.empty())
225   {
226   level_nb = -1;
227   load_level(filename);
228   }
229 else
230   Menu::set_current(main_menu);
231
232 mouse_cursor->set_state(MC_NORMAL);
233
234 done = false;
235 while(!done)
236   {
237   events();
238   action();
239   draw(context);
240   }
241
242 if(level_changed)
243   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
244     save_level();
245 }
246
247 void LevelEditor::events()
248 {
249 mouse_moved = false;
250
251 while(SDL_PollEvent(&event))
252   {
253   Menu* menu = Menu::current();
254   if(menu)
255     {
256     menu->event(event);
257     menu->action();
258     if(menu == main_menu)
259       {
260       switch (main_menu->check())
261         {
262         case MN_ID_RETURN:
263           Menu::set_current(0);
264           break;
265         case MN_ID_QUIT:
266           done = true;
267           break;
268         }
269       }
270     else if(menu == create_subset_menu)
271       {
272       // activate or deactivate Create button if any filename as been specified
273       if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
274         create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
275       else
276         create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_ACTION;
277
278       if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
279         {   // applying settings:
280         std::string subset_name = create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input;
281         LevelSubset::create(subset_name);
282
283         delete level_subset;
284         level_subset = new LevelSubset();
285         level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
286
287         level_subset->title = create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).input;
288         level_subset->description = create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).input;
289         //FIXME: generate better level filenames
290         level_subset->add_level(subset_name+'/'+"new_level.stl");
291         Level::create(level_subset->get_level_filename(0));
292         level_subset->save();
293         
294         load_level(0);
295
296         create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
297         create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
298         create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
299         }
300       }
301     else if(menu == subset_menu)
302       {
303       int i = subset_menu->check();
304       if(i >= 0)
305         {
306         std::set<std::string>::iterator it = level_subsets.begin();
307         for(int t = 0; t < i; t++)
308           it++;
309         load_level_subset(*it);
310         Menu::set_current(0);
311         }
312       }
313     else if(menu == settings_menu)
314       {
315       if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
316         {   // applying settings:
317         level_changed = true;
318
319         level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
320         level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
321
322         solids->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         foregrounds->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         backgrounds->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
329         Menu::set_current(0);
330         }
331       }
332     }
333   // check for events in buttons
334   else if(tiles_board->event(event))
335     {
336     std::vector <int> vector;
337     vector.push_back(tiles_board->selected_id());
338
339     selection.clear();
340     selection.push_back(vector);
341     continue;
342     }
343   else if(tiles_layer->event(event))
344     {
345     cur_layer = tiles_layer->selected_id();
346     continue;
347     }
348   else if(level_options->event(event))
349     {
350     switch(level_options->selected_id())
351       {
352       case BT_LEVEL_SAVE:
353         save_level();
354         break;
355       case BT_LEVEL_TEST:
356         test_level();
357         break;
358       case BT_LEVEL_SETUP:
359         Menu::set_current(settings_menu);
360         break;
361       case BT_NEXT_LEVEL:
362         if(level_nb + 1 < level_subset->get_num_levels())
363           load_level(level_nb + 1);
364         else
365           {
366           char str[1024];
367           sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 2);
368           if(confirm_dialog(NULL, str))
369             {
370             level_subset->add_level("new_level.stl");
371             Level::create(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))->id);
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_ = Sector::create("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 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 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 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 }