Bugfix: change of level or level_subset is possible now.
[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 {
69 std::cerr << "adding entry level subset " << i << " entry: " << (*it) << std::endl;
70   subset_menu->additem(MN_ACTION, (*it),0,0,i);
71 }
72 subset_menu->additem(MN_HL,"",0,0);
73 subset_menu->additem(MN_BACK,_("Back"),0,0);
74
75 create_subset_menu = new Menu();
76 create_subset_menu->additem(MN_LABEL,_("New Level Subset"),0,0);
77 create_subset_menu->additem(MN_HL,"",0,0);
78 create_subset_menu->additem(MN_TEXTFIELD,_("Filename   "),0,0,MN_ID_FILENAME_SUBSET);
79 create_subset_menu->additem(MN_TEXTFIELD,_("Title      "),0,0,MN_ID_TITLE_SUBSET);
80 create_subset_menu->additem(MN_TEXTFIELD,_("Description"),0,0,MN_ID_DESCRIPTION_SUBSET);
81 create_subset_menu->additem(MN_ACTION,_("Create"),0,0, MN_ID_CREATE_SUBSET);
82 create_subset_menu->additem(MN_HL,"",0,0);
83 create_subset_menu->additem(MN_BACK,_("Back"),0,0);
84
85 main_menu = new Menu();
86 main_menu->additem(MN_LABEL,_("Level Editor Menu"),0,0);
87 main_menu->additem(MN_HL,"",0,0);
88 main_menu->additem(MN_ACTION,_("Return to Level Editor"),0,0,MN_ID_RETURN);
89 main_menu->additem(MN_GOTO,_("Create Level Subset"),0,create_subset_menu);
90 main_menu->additem(MN_GOTO,_("Load Level Subset"),0,subset_menu);
91 main_menu->additem(MN_HL,"",0,0);
92 main_menu->additem(MN_ACTION,_("Quit Level Editor"),0,0,MN_ID_QUIT);
93
94 settings_menu = new Menu();
95 settings_menu->additem(MN_LABEL,_("Level Settings"),0,0);
96 settings_menu->additem(MN_HL,"",0,0);
97 settings_menu->additem(MN_TEXTFIELD,_("Name    "),0,0,MN_ID_NAME);
98 settings_menu->additem(MN_TEXTFIELD,_("Author  "),0,0,MN_ID_AUTHOR);
99 settings_menu->additem(MN_NUMFIELD, _("Width   "),0,0,MN_ID_WIDTH);
100 settings_menu->additem(MN_NUMFIELD, _("Height  "),0,0,MN_ID_HEIGHT);
101 settings_menu->additem(MN_HL,"",0,0);
102 settings_menu->additem(MN_ACTION,_("Apply"),0,0,MN_ID_APPLY_SETTINGS);
103
104 /* Creating button groups */
105 load_buttons_gfx();
106
107 tiles_board = new ButtonGroup(Vector(screen->w - 140, 100),
108           Vector(32,32), Vector(4,8));
109
110 TileManager* tilemanager = TileManager::instance();
111
112 tiles_board->add_button(Button(img_rubber_bt, _("Eraser"), SDLKey(SDLK_DELETE)), 0);
113 for(unsigned int id = 1; id < tilemanager->total_ids(); id++)
114   {
115   Tile* tile = tilemanager->get(id);
116   if(!tile)
117     continue;
118
119   Surface* surface;
120   if(tile->editor_images.size())
121     surface = tile->editor_images[0];
122   else if(tile->images.size())
123     surface = tile->images[0];
124   else
125     continue;
126
127   Button button = Button(surface, "", SDLKey(0));
128   tiles_board->add_button(button, id);
129   }
130 for(int i = 0; i < NUM_BadGuyKinds; i++)
131   {
132   BadGuyKind kind = BadGuyKind(i);
133   BadGuy badguy(kind, 0,0);
134   badguy.activate(LEFT);
135
136   Surface *img = badguy.get_image();
137   tiles_board->add_button(Button(img, "", SDLKey(SDLK_1+i)), -(i+1));
138   }
139
140 tiles_board->add_button(Button(img_trampoline[0].get_frame(0), _("Trampoline"), SDLKey(0)), OBJ_TRAMPOLINE);
141 tiles_board->add_button(Button(img_flying_platform->get_frame(0), _("Flying Platform"), SDLKey(0)), OBJ_FLYING_PLATFORM);
142 tiles_board->add_button(Button(door->get_frame(0), _("Door"), SDLKey(0)), OBJ_DOOR);
143
144 tiles_layer = new ButtonGroup(Vector(12, screen->h-64), Vector(80,20), Vector(1,3));
145 tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
146                        SDLK_F10), LAYER_FOREGROUNDTILES);
147 tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
148                        SDLK_F11), LAYER_TILES, true);
149 tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
150                        SDLK_F12), LAYER_BACKGROUNDTILES);
151
152 level_options = new ButtonGroup(Vector(screen->w-164, screen->h-36), Vector(32,32), Vector(5,1));
153 level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
154                Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
155 level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
156                Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
157 level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
158 level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
159 level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
160 }
161
162 LevelEditor::~LevelEditor()
163 {
164 free_buttons_gfx();
165
166 delete tiles_board;
167 delete tiles_layer;
168 delete level_options;
169
170 delete subset_menu;
171 delete create_subset_menu;
172 delete main_menu;
173 delete settings_menu;
174
175 delete level;
176 delete level_subset;
177 }
178
179 void LevelEditor::load_buttons_gfx()
180 {
181 img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
182 img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
183 img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
184
185 img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
186 img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
187 img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
188
189 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
190
191 img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
192 img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
193 img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
194 img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
195 }
196
197 void LevelEditor::free_buttons_gfx()
198 {
199 delete img_foreground_bt;
200 delete img_interactive_bt;
201 delete img_background_bt;
202
203 delete img_save_level_bt;
204 delete img_test_level_bt;
205 delete img_setup_level_bt;
206
207 delete img_rubber_bt;
208
209 delete img_previous_level_bt;
210 delete img_next_level_bt;
211 delete img_previous_sector_bt;
212 delete img_next_sector_bt;
213 }
214
215 void LevelEditor::run(const std::string filename)
216 {
217 SoundManager::get()->halt_music();
218 Menu::set_current(0);
219
220 DrawingContext context;
221
222 if(!filename.empty())
223   {
224   level_nb = -1;
225   load_level(filename);
226   }
227 else
228   Menu::set_current(main_menu);
229
230 mouse_cursor->set_state(MC_NORMAL);
231
232 done = false;
233 while(!done)
234   {
235   events();
236   action();
237   draw(context);
238   }
239
240 if(level_changed)
241   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
242     save_level();
243 }
244
245 void LevelEditor::events()
246 {
247 mouse_moved = false;
248
249 while(SDL_PollEvent(&event))
250   {
251   Menu* menu = Menu::current();
252   if(menu)
253     {
254     menu->event(event);
255     menu->action();
256     if(menu == main_menu)
257       {
258       switch (main_menu->check())
259         {
260         case MN_ID_RETURN:
261           Menu::set_current(0);
262           break;
263         case MN_ID_QUIT:
264           done = true;
265           break;
266         }
267       }
268     else if(menu == create_subset_menu)
269       {
270       if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
271         create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
272       else if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
273         {   // applying settings:
274         LevelSubset::create(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
275
276         delete level_subset;
277         level_subset = new LevelSubset();
278         level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
279
280         level_subset->title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
281         level_subset->description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
282
283         load_level(1);
284
285         create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
286         create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
287         create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
288         }
289       }
290     else if(menu == subset_menu)
291       {
292       int i = subset_menu->check();
293       if(i >= 0)
294         {
295         std::set<std::string>::iterator it = level_subsets.begin();
296         for(int t = 0; t < i; t++)
297           it++;
298 std::cerr << "load subset level_subsets " << i << ": " << (*it) << std::endl;
299         load_level_subset(*it);
300         Menu::set_current(0);
301         }
302       }
303     else if(menu == settings_menu)
304       {
305       if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
306         {   // applying settings:
307         level_changed = true;
308
309         level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
310         level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
311
312         solids->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         foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
315               atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
316         backgrounds->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
319         Menu::set_current(0);
320         }
321       }
322     }
323   // check for events in buttons
324   else if(tiles_board->event(event))
325     {
326     std::vector <int> vector;
327     vector.push_back(tiles_board->selected_id());
328
329     selection.clear();
330     selection.push_back(vector);
331     continue;
332     }
333   else if(tiles_layer->event(event))
334     {
335     cur_layer = tiles_layer->selected_id();
336     continue;
337     }
338   else if(level_options->event(event))
339     {
340     switch(level_options->selected_id())
341       {
342       case BT_LEVEL_SAVE:
343         save_level();
344         break;
345       case BT_LEVEL_TEST:
346         test_level();
347         break;
348       case BT_LEVEL_SETUP:
349         Menu::set_current(settings_menu);
350         break;
351       case BT_NEXT_LEVEL:
352         if(level_nb+1 < level_subset->get_num_levels())
353           load_level(level_nb + 1);
354         else
355           {
356           char str[1024];
357           sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 1);
358           if(confirm_dialog(NULL, str))
359             {
360             Level new_lev;
361             level_subset->add_level("new_level.stl");
362             new_lev.save(level_subset->get_level_filename(level_nb + 1));
363             load_level(level_nb);
364             }
365           }
366         break;
367       case BT_PREVIOUS_LEVEL:
368         if(level_nb-1 > 0)
369           load_level(level_nb - 1);
370         break;
371       case BT_NEXT_SECTOR:
372 std::cerr << "next sector.\n";
373 std::cerr << "total sectors: " << level->get_total_sectors() << std::endl;
374         load_sector(level->get_next_sector(sector));
375         break;
376       case BT_PREVIOUS_SECTOR:
377 std::cerr << "previous sector.\n";
378         load_sector(level->get_previous_sector(sector));
379         break;
380       }
381     level_options->set_unselected();
382     continue;
383     }
384   else
385     {
386     switch(event.type)
387       {
388       case SDL_MOUSEMOTION:
389         mouse_moved = true;
390         if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
391           {  // movement like in strategy games
392           scroll.x += -1 * event.motion.xrel;
393           scroll.y += -1 * event.motion.yrel;
394           }
395         break;
396
397       case SDL_MOUSEBUTTONDOWN:
398         mouse_moved = true;
399         if(event.button.button == SDL_BUTTON_LEFT)
400           left_button = true;
401         else if(event.button.button == SDL_BUTTON_MIDDLE)
402           {
403           middle_button = true;
404           selection_ini = Vector(event.button.x, event.button.y);
405           }
406         break;
407
408       case SDL_MOUSEBUTTONUP:
409         mouse_moved = true;
410         if(event.button.button == SDL_BUTTON_LEFT)
411           left_button = false;
412         else if(event.button.button == SDL_BUTTON_MIDDLE)
413           {
414           middle_button = false;
415           selection_end = Vector(event.button.x, event.button.y);
416
417           if(selection_end.x < selection_ini.x)
418             {
419             float t = selection_ini.x;
420             selection_ini.x = selection_end.x;
421             selection_end.x = t;
422             }
423           if(selection_end.y < selection_ini.y)
424             {
425             float t = selection_ini.y;
426             selection_ini.y = selection_end.y;
427             selection_end.y = t;
428             }
429
430           selection.clear();
431           std::vector <int> vector;
432
433           TileMap* tilemap = 0;
434           if(cur_layer == LAYER_FOREGROUNDTILES)
435             tilemap = foregrounds;
436           else if(cur_layer == LAYER_TILES)
437             tilemap = solids;
438           else if(cur_layer == LAYER_BACKGROUNDTILES)
439             tilemap = backgrounds;
440
441           for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
442             {
443             vector.clear();
444             for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
445               {
446               vector.push_back(tilemap->get_tile(x +
447                (int)(((selection_ini.x+scroll.x)*zoom)/32),
448                y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->id);
449               }
450             selection.push_back(vector);
451             }
452           }
453         break;
454
455       case SDL_KEYDOWN:   // key pressed
456         switch(event.key.keysym.sym)
457           {
458           case SDLK_ESCAPE:
459             Menu::set_current(main_menu);
460             break;
461           /* scrolling related events: */
462           case SDLK_HOME:
463             scroll.x = 0;
464             break;
465           case SDLK_END:
466             scroll.x = sector->solids->get_height()*32 - screen->w;
467             break;
468           case SDLK_LEFT:
469             scroll.x -= 80;
470             break;
471           case SDLK_RIGHT:
472             scroll.x += 80;
473             break;
474           case SDLK_UP:
475             scroll.y -= 80;
476             break;
477           case SDLK_DOWN:
478             scroll.y += 80;
479             break;
480           case SDLK_PAGEUP:
481             scroll.x -= 450;
482             break;
483           case SDLK_PAGEDOWN:
484             scroll.x += 450;
485             break;
486           case SDLK_PLUS:
487           case SDLK_KP_PLUS:
488             zoom += 0.10;
489             break;
490           case SDLK_MINUS:
491           case SDLK_KP_MINUS:
492             zoom -= 0.10;
493             break;
494
495           case SDLK_F1:
496             show_help();
497             break;
498           case SDLK_F2:
499             show_grid = !show_grid;
500             break;
501           default:
502             break;
503           }
504         break;
505
506       case SDL_QUIT:   // window closed
507         done = true;
508         break;
509
510         default:
511           break;
512       }
513     }
514   }
515 }
516
517 void LevelEditor::action()
518 {
519 mouse_cursor->set_state(MC_NORMAL);
520 if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
521   mouse_cursor->set_state(MC_LINK);
522
523 if(sector)
524   {
525   if(!frame_timer.check())
526     {
527     frame_timer.start(25);
528     ++global_frame_counter;
529     }
530
531   // don't scroll before the start or after the level's end
532   float width = sector->solids->get_width() * 32;
533   float height = sector->solids->get_height() * 32;
534
535   if(scroll.x < -screen->w/2)
536     scroll.x = -screen->w/2;
537   if(scroll.x > width - screen->w/2)
538     scroll.x = width - screen->w/2;
539   if(scroll.y < -screen->h/2)
540     scroll.y = -screen->h/2;
541   if(scroll.y > height - screen->h/2)
542     scroll.y = height - screen->h/2;
543
544   // set camera translation, since BadGuys like it
545   sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
546
547   if(left_button && mouse_moved)
548     for(unsigned int x = 0; x < selection.size(); x++)
549       for(unsigned int y = 0; y < selection[x].size(); y++)
550         change((int)(scroll.x + event.button.x) + (x*32),
551              (int)(scroll.y + event.button.y) + (y*32), selection[x][y], 
552              cur_layer);
553   }
554 }
555
556 #define FADING_TIME 600
557
558 void LevelEditor::draw(DrawingContext& context)
559 {
560 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
561 mouse_cursor->draw(context);
562
563 // draw a filled background
564 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
565
566 if(level_name_timer.check())
567   {
568   context.push_transform();
569   if(level_name_timer.get_left() < FADING_TIME)
570     context.set_alpha(level_name_timer.get_left() * 255 / FADING_TIME);
571
572   context.draw_text(gold_text, level->name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
573   if(level_nb != -1)
574     {
575     char str[128];
576     sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
577     context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
578     }
579
580   context.pop_transform();
581   }
582 if(sector)
583   context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
584 else
585   context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
586
587 Menu* menu = Menu::current();
588 if(menu)
589   menu->draw(context);
590 else
591   {
592   tiles_board->draw(context);
593   tiles_layer->draw(context);
594   level_options->draw(context);
595   }
596
597 // draw selection
598 if(sector)
599   {
600   if(!middle_button)
601     {
602     context.set_drawing_effect(SEMI_TRANSPARENT);
603
604     if(selection.size())
605       {
606       if(selection[0][0] == 0 && selection.size() == 1)
607           context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
608           event.button.y - 8), LAYER_GUI-2);
609       else if(selection[0][0] < 0)
610         {
611         int id = selection[0][0];
612
613         if(id == OBJ_TRAMPOLINE)
614           context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
615           event.button.y - 8), LAYER_GUI-2);
616         else if(id == OBJ_FLYING_PLATFORM)
617           context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
618           event.button.y - 8), LAYER_GUI-2);
619         else if(id == OBJ_DOOR)
620           context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
621           event.button.y - 8), LAYER_GUI-2);
622         else
623           {
624           BadGuyKind kind = BadGuyKind((-id)-1);
625           BadGuy badguy(kind, 0,0);
626           badguy.activate(LEFT);
627           Surface *img = badguy.get_image();
628
629           context.draw_surface(img, Vector(event.button.x - 8,
630           event.button.y - 8), LAYER_GUI-2);
631           }
632         }
633       else
634         {
635         TileManager* tilemanager = TileManager::instance();
636         for(unsigned int x = 0; x < selection.size(); x++)
637           for(unsigned int y = 0; y < selection[x].size(); y++)
638             tilemanager->draw_tile(context, selection[x][y],
639                 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
640                 LAYER_GUI-2);
641         }
642       }
643     context.set_drawing_effect(NONE_EFFECT);
644     }
645   else
646     context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
647                    std::min((int)selection_ini.y, (int)event.button.y))*zoom,
648                    Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
649                    abs(event.button.y - (int)selection_ini.y)*zoom),
650                    Color(170,255,170,128), LAYER_GUI-2);
651
652   if(show_grid)
653     {
654     for(int x = 0; x < screen->w / (32*zoom); x++)
655       {
656       int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
657       context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
658                 Color(225, 225, 225), LAYER_GUI-50);
659       }
660     for(int y = 0; y < screen->h / (32*zoom); y++)
661       {
662       int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
663       context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
664                 Color(225, 225, 225), LAYER_GUI-50);
665       }
666     }
667
668   context.push_transform();
669   context.set_translation(scroll);
670   context.set_zooming(zoom);
671
672   for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
673     {
674     TileMap* tilemap = dynamic_cast<TileMap*> (*i);
675     if(tilemap)
676       {  // draw the non-selected tiles semi-transparently
677       context.push_transform();
678
679       if(tilemap->get_layer() != cur_layer)
680         context.set_drawing_effect(SEMI_TRANSPARENT);
681       (*i)->draw(context);
682
683       context.pop_transform();
684       }
685     Background* background = dynamic_cast<Background*> (*i);
686     if(background)
687       {  // don't resize background
688       context.push_transform();
689       context.set_translation(scroll);
690       context.set_zooming(1.0);
691       (*i)->draw(context);
692       context.pop_transform();
693       }
694     else
695       (*i)->draw(context);
696     }
697
698   context.pop_transform();
699   }
700 else
701   context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
702
703 context.do_drawing();
704 }
705
706 void LevelEditor::load_level_subset(std::string filename)
707 {
708 std::cerr << "loading subset...\n";
709 std::cerr << "filename: " << filename << std::endl;
710 delete level_subset;
711 level_subset = new LevelSubset();
712 level_subset->load(filename.c_str());
713 load_level(1);
714 }
715
716 void LevelEditor::load_level(std::string filename)
717 {
718 if(level_changed)
719   {
720   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
721     save_level();
722   else
723     return;
724   }
725
726 level_filename = filename;
727
728 delete level;
729 level = new Level();
730 level->load(filename);
731
732 load_sector("main");
733 level_name_timer.start(3000);
734 scroll.x = scroll.y = 0;
735 level_changed = false;
736
737 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
738 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
739 }
740
741 void LevelEditor::load_level(int nb)
742 {
743 if(level_changed)
744   {
745   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
746     save_level();
747   else
748     return;
749   }
750
751 level_nb = nb;
752 std::cerr << "level_nb: " << level_nb << std::endl;
753 std::cerr << "level_subset->get_level_filename(level_nb): " << level_subset->get_level_filename(level_nb) << std::endl;
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 std::cerr << "saving level...\n";
831 level->save(level_filename);
832 level_changed = false;
833 }
834
835 void LevelEditor::test_level()
836 {
837 if(level_changed)
838   {
839   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
840     save_level();
841   else
842     return;
843   }
844
845 GameSession session(level_filename, ST_GL_TEST);
846 session.run();
847 //  player_status.reset();
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_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
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 }