changing directions while flapping now works
[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 < 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)
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 void LevelEditor::draw(DrawingContext& context)
549 {
550 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
551 mouse_cursor->draw(context);
552
553 // draw a filled background
554 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
555
556 if(level_name_timer.check())
557   {
558   context.draw_text(gold_text, level.name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
559   if(level_nb != -1)
560     {
561     char str[128];
562     sprintf(str, "%i/%i", level_nb+1, level_subset.get_num_levels());
563     context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
564     }
565   }
566 if(sector)
567   context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
568 else
569   context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
570
571 Menu* menu = Menu::current();
572 if(menu)
573   menu->draw(context);
574 else
575   {
576   tiles_board->draw(context);
577   tiles_layer->draw(context);
578   level_options->draw(context);
579   }
580
581 // draw selection
582 if(sector)
583   {
584   if(!middle_button)
585     {
586     context.set_drawing_effect(SEMI_TRANSPARENT);
587
588     if(selection.size())
589       {
590       if(selection[0][0] == 0 && selection.size() == 1)
591           context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
592           event.button.y - 8), LAYER_GUI-2);
593       else if(selection[0][0] < 0)
594         {
595         int id = selection[0][0];
596
597         if(id == OBJ_TRAMPOLINE)
598           context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
599           event.button.y - 8), LAYER_GUI-2);
600         else if(id == OBJ_FLYING_PLATFORM)
601           context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
602           event.button.y - 8), LAYER_GUI-2);
603         else if(id == OBJ_DOOR)
604           context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
605           event.button.y - 8), LAYER_GUI-2);
606         else
607           {
608           BadGuyKind kind = BadGuyKind((-id)-1);
609           BadGuy badguy(kind, 0,0);
610           badguy.activate(LEFT);
611           Surface *img = badguy.get_image();
612
613           context.draw_surface(img, Vector(event.button.x - 8,
614           event.button.y - 8), LAYER_GUI-2);
615           }
616         }
617       else
618         {
619         TileManager* tilemanager = TileManager::instance();
620         for(unsigned int x = 0; x < selection.size(); x++)
621           for(unsigned int y = 0; y < selection[x].size(); y++)
622             tilemanager->draw_tile(context, selection[x][y],
623                 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
624                 LAYER_GUI-2);
625         }
626       }
627     context.set_drawing_effect(NONE_EFFECT);
628     }
629   else
630     context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
631                    std::min((int)selection_ini.y, (int)event.button.y))*zoom,
632                    Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
633                    abs(event.button.y - (int)selection_ini.y)*zoom),
634                    Color(170,255,170,128), LAYER_GUI-2);
635
636   if(show_grid)
637     {
638     for(int x = 0; x < screen->w / (32*zoom); x++)
639       {
640       int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
641       context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
642                 Color(225, 225, 225), LAYER_GUI-50);
643       }
644     for(int y = 0; y < screen->h / (32*zoom); y++)
645       {
646       int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
647       context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
648                 Color(225, 225, 225), LAYER_GUI-50);
649       }
650     }
651
652   context.push_transform();
653   context.set_translation(scroll);
654   context.set_zooming(zoom);
655
656   for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
657     {
658     TileMap* tilemap = dynamic_cast<TileMap*> (*i);
659     if(tilemap)
660       {  // draw the non-selected tiles semi-transparently
661       context.push_transform();
662
663       if(tilemap->get_layer() != cur_layer)
664         context.set_drawing_effect(SEMI_TRANSPARENT);
665       (*i)->draw(context);
666
667       context.pop_transform();
668       }
669     Background* background = dynamic_cast<Background*> (*i);
670     if(background)
671       {  // don't resize background
672       context.push_transform();
673       context.set_translation(scroll);
674       context.set_zooming(1.0);
675       (*i)->draw(context);
676       context.pop_transform();
677       }
678     else
679       (*i)->draw(context);
680     }
681
682   context.pop_transform();
683   }
684 else
685   context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
686
687 context.do_drawing();
688 }
689
690 void LevelEditor::load_level_subset(std::string filename)
691 {
692 std::cerr << "loading subset...\n";
693 std::cerr << "filename: " << filename << std::endl;
694 level_subset.load(filename.c_str());
695 load_level(1);
696 }
697
698 void LevelEditor::load_level(std::string filename)
699 {
700 if(!level_changed)
701   save_level();
702
703 level_filename = filename;
704 level.load(filename);
705
706 load_sector("main");
707 level_name_timer.start(3000);
708 scroll.x = scroll.y = 0;
709 level_changed = false;
710
711 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level.name.c_str());
712 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level.author.c_str());
713 }
714
715 void LevelEditor::load_level(int nb)
716 {
717 if(!level_changed)
718   save_level();
719
720 level_nb = nb;
721 std::cerr << "level_nb: " << level_nb << std::endl;
722 std::cerr << "level_subset.get_level_filename(level_nb): " << level_subset.get_level_filename(level_nb) << std::endl;
723 level_filename = level_subset.get_level_filename(level_nb);
724
725 load_level(level_filename);
726 }
727
728 void LevelEditor::load_sector(std::string name)
729 {
730 sector_name = name;
731 sector = level.get_sector(sector_name);
732 if(!sector)
733   Termination::abort("Level has no " + sector_name + " sector.", "");
734
735 load_sector(sector);
736 }
737
738 void LevelEditor::load_sector(Sector* sector_)
739 {
740 if(sector == NULL)
741   {
742   if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
743     {
744     Sector* nsector = new Sector();
745     level.add_sector(nsector);
746     sector = nsector;
747     }
748   return;
749   }
750
751 sector = sector_;
752
753 /* Load sector stuff */
754
755 sector->update_game_objects();
756
757 foregrounds = solids = backgrounds = 0;
758 /* Point foregrounds, backgrounds, solids to its layer */
759 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
760   {
761   BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
762   if(badguy)
763     badguy->activate(LEFT);
764
765   TileMap* tilemap = dynamic_cast<TileMap*> (*i);
766   if(tilemap)
767     {
768     if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
769       foregrounds = tilemap;
770     else if(tilemap->get_layer() == LAYER_TILES)
771       solids = tilemap;
772     else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
773       backgrounds = tilemap;
774     }
775   }
776
777 if(!foregrounds)
778   {
779   TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
780   sector->add_object(tilemap);
781   sector->update_game_objects();
782   }
783 if(!backgrounds)
784   {
785   TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
786   sector->add_object(tilemap);
787   sector->update_game_objects();
788   }
789
790 char str[64];
791 sprintf(str, "%i", solids->get_width());
792 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
793 sprintf(str, "%i", solids->get_height());
794 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
795 }
796
797 void LevelEditor::save_level()
798 {
799 level.save(level_filename);
800 level_changed = false;
801 }
802
803 void LevelEditor::test_level()
804 {
805 if(level_changed)
806   {
807   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
808     save_level();
809   else
810     return;
811   }
812
813 GameSession session(level_filename, ST_GL_TEST);
814 session.run();
815 //  player_status.reset();
816 sound_manager->halt_music();
817 }
818
819 void LevelEditor::change(int x, int y, int newtile, int layer)
820 {  // find the tilemap of the current layer, and then change the tile
821 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
822    y < 0 || (unsigned int)y > sector->solids->get_height()*32)
823   return;
824
825 level_changed = true;
826
827 if(zoom != 1)
828   {  // no need to do this for normal view (no zoom)
829   x = (int)(x * (zoom*32) / 32);
830   y = (int)(y * (zoom*32) / 32);
831   }
832
833 if(newtile < 0)  // add object
834   {
835   // remove an active tile or object that might be there
836   change(x, y, 0, LAYER_TILES);
837
838   if(newtile == OBJ_TRAMPOLINE)
839     sector->add_object(new Trampoline(x, y));
840   else if(newtile == OBJ_FLYING_PLATFORM)
841     sector->add_object(new FlyingPlatform(x, y));
842   else if(newtile == OBJ_DOOR)
843     sector->add_object(new Door(x, y));
844   else
845     sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
846
847   sector->update_game_objects();
848   }
849 else if(cur_layer == LAYER_FOREGROUNDTILES)
850   foregrounds->change(x/32, y/32, newtile);
851 else if(cur_layer == LAYER_TILES)
852   {
853   // remove a bad guy if it's there
854   // we /32 in order to round numbers
855   for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
856     {
857     BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
858     if(badguy)
859       if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
860         sector->gameobjects.erase(i);
861     Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
862     if(trampoline)
863     {
864       if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
865         sector->gameobjects.erase(i);
866         }
867     FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
868     if(flying_platform)
869       if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
870         sector->gameobjects.erase(i);
871     Door* door = dynamic_cast<Door*> (*i);
872     if(door)
873       if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
874         sector->gameobjects.erase(i);
875     }
876   sector->update_game_objects();
877   solids->change(x/32, y/32, newtile);
878   }
879 else if(cur_layer == LAYER_BACKGROUNDTILES)
880   backgrounds->change(x/32, y/32, newtile);
881 }
882
883 void LevelEditor::show_help()
884 {
885 DrawingContext context;
886
887 bool show_grid_t = show_grid;
888 show_grid = false;
889 mouse_cursor->set_state(MC_HIDE);
890
891
892 char str[1024];
893 char *text1[] = {
894          _("This is the built-in level editor. It's aim is to be intuitive\n"
895          "and simple to use, so it should be pretty straight forward.\n"
896          "\n"
897          "To open a level, first you'll have to select a level subset from\n"
898          "the menu (or create your own).\n"
899          "A level subset is basically a collection of levels.\n"
900          "They can then be played from the Contrib menu.\n"
901          "\n"
902          "To access the menu from the level editor, just press Esc.\n"
903          "\n"
904          "You are currently looking to the level, to scroll it, just\n"
905          "press the right mouse button and drag the mouse. It will move like\n"
906          "a strategy game.\n"
907          "You can also use the arrow keys and Page Up/Down.\n"
908          "\n"
909          "'+' and '-' keys can be used to zoom in/out the level.\n"
910          "\n"
911          "You probably already noticed those floating group of buttons.\n"
912          "Each one serves a different purpose. To select a certain button\n"
913          "just press the Left mouse button on it. A few buttons have key\n"
914          "shortcuts, you can know it by pressing the Right mouse button on\n"
915          "it. That will also show what that button does.\n"
916          "Group of buttons can also be move around by just dragging them,\n"
917          "while pressing the Left mouse button.\n"
918          "\n"
919          "Let's learn a bit of what each group of buttons do, shall we?\n"
920          "\n"
921          "To starting putting tiles and objects around use the bigger gropup\n"
922          "of buttons. Each button is a different tile. To put it on the level,\n"
923          "just press it and then left click in the level.\n"
924          "You can also copy tiles from the level by using the middle mouse button.\n"
925          "Use the mouse wheel to scroll that group of buttons. You will find\n"
926          "enemies and game objects in the bottom.\n")
927                 };
928
929 char *text2[] = {
930          _("The Foreground/Interactive/Background buttons may be used to\n"
931          "see and edit the respective layer. Level's have three tiles layers:\n"
932          "Foreground - tiles are drawn in top of everything and have no contact\n"
933          "with the player.\n"
934          "Interactive - these are the tiles that have contact with the player.\n"
935          "Background - tiles are drawn in bottom of everything and have no contact\n"
936          "with the player.\n"
937          "The unselected layers will be drawn semi-transparently.\n"
938          "\n"
939          "At last, but not least, the group of buttons that's left serves\n"
940          "to do related actions with the level.\n"
941          "From left to right:\n"
942          "Mini arrows - can be used to choose other sectors.\n"
943          "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
944          "Big arrows - choose other level in the same level subset.\n"
945          "Diskette - save the level\n"
946          "Tux - test the level\n"
947          "Tools - set a few settings for the level, incluiding resizing it.\n"
948          "\n"
949          "We have reached the end of this Howto.\n"
950          "\n"
951          "Don't forget to send us a few cool levels. :)\n"
952          "\n"
953          "Enjoy,\n"
954          "  SuperTux development team\n"
955          "\n"
956          "ps: If you are looking for something more powerfull, you can give it a\n"
957          "try to FlexLay. FlexLay is a level editor that supports several games,\n"
958          "including SuperTux. It is an independent project.\n"
959          "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
960                 };
961
962 char **text[] = { text1, text2 };
963
964
965 bool done;
966 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
967   {
968   draw(context);
969
970   context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
971
972   context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
973
974   sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
975   context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
976
977   context.do_drawing();
978
979   done = false;
980
981   while(!done)
982     {
983     done = wait_for_event(event);
984     SDL_Delay(50);
985     }
986   }
987
988 show_grid = show_grid_t;
989 mouse_cursor->set_state(MC_NORMAL);
990 }