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