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