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