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