- committed patch from Richard Smith
[supertux.git] / src / leveleditor.cpp
1 /***************************************************************************
2                   leveleditor.cpp  -  built'in leveleditor
3                      -------------------
4     begin                : June, 23 2004
5     copyright            : (C) 2004 by Ricardo Cruz
6     email                : rick2@aeiou.pt
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include <stdlib.h>
19 #include <algorithm>
20
21 #include "gui/mousecursor.h"
22 #include "gui/menu.h"
23 #include "gui/button.h"
24 #include "audio/sound_manager.h"
25 #include "app/gettext.h"
26 #include "app/setup.h"
27 #include "app/globals.h"
28 #include "special/sprite.h"
29 #include "leveleditor.h"
30 #include "resources.h"
31 #include "tile.h"
32 #include "tilemap.h"
33 #include "tile_manager.h"
34 #include "sector.h"
35 #include "background.h"
36 #include "gameloop.h"
37 #include "badguy.h"
38 #include "gameobjs.h"
39 #include "door.h"
40 #include "camera.h"
41
42 LevelEditor::LevelEditor()
43 {
44 show_grid = true;
45
46 selection.clear();
47 global_frame_counter = 0;
48 frame_timer.init(true);
49 level_name_timer.init(true);
50 selection_end = selection_ini = Vector(0,0);
51 left_button = middle_button = mouse_moved =  false;
52 level = 0;
53 level_subset = 0;
54
55 cur_layer = LAYER_TILES;
56 level_changed = false;
57
58 sector = 0;
59 zoom = 1.0;
60
61 /* Creating menus */
62 level_subsets = FileSystem::dsubdirs("/levels", "info");
63 subset_menu = new Menu();
64 subset_menu->additem(MN_LABEL,_("Load Subset"),0,0);
65 subset_menu->additem(MN_HL,"",0,0);
66 int i = 0;
67 for(std::set<std::string>::iterator it = level_subsets.begin(); it != level_subsets.end(); ++it, ++i)
68   subset_menu->additem(MN_ACTION, (*it),0,0,i);
69 subset_menu->additem(MN_HL,"",0,0);
70 subset_menu->additem(MN_BACK,_("Back"),0,0);
71
72 create_subset_menu = new Menu();
73 create_subset_menu->additem(MN_LABEL,_("New Level Subset"),0,0);
74 create_subset_menu->additem(MN_HL,"",0,0);
75 create_subset_menu->additem(MN_TEXTFIELD,_("Filename   "),0,0,MN_ID_FILENAME_SUBSET);
76 create_subset_menu->additem(MN_TEXTFIELD,_("Title      "),0,0,MN_ID_TITLE_SUBSET);
77 create_subset_menu->additem(MN_TEXTFIELD,_("Description"),0,0,MN_ID_DESCRIPTION_SUBSET);
78 create_subset_menu->additem(MN_ACTION,_("Create"),0,0, MN_ID_CREATE_SUBSET);
79 create_subset_menu->additem(MN_HL,"",0,0);
80 create_subset_menu->additem(MN_BACK,_("Back"),0,0);
81
82 main_menu = new Menu();
83 main_menu->additem(MN_LABEL,_("Level Editor Menu"),0,0);
84 main_menu->additem(MN_HL,"",0,0);
85 main_menu->additem(MN_ACTION,_("Return to Level Editor"),0,0,MN_ID_RETURN);
86 main_menu->additem(MN_GOTO,_("Create Level Subset"),0,create_subset_menu);
87 main_menu->additem(MN_GOTO,_("Load Level Subset"),0,subset_menu);
88 main_menu->additem(MN_HL,"",0,0);
89 main_menu->additem(MN_ACTION,_("Quit Level Editor"),0,0,MN_ID_QUIT);
90
91 settings_menu = new Menu();
92 settings_menu->additem(MN_LABEL,_("Level Settings"),0,0);
93 settings_menu->additem(MN_HL,"",0,0);
94 settings_menu->additem(MN_TEXTFIELD,_("Name    "),0,0,MN_ID_NAME);
95 settings_menu->additem(MN_TEXTFIELD,_("Author  "),0,0,MN_ID_AUTHOR);
96 settings_menu->additem(MN_NUMFIELD, _("Width   "),0,0,MN_ID_WIDTH);
97 settings_menu->additem(MN_NUMFIELD, _("Height  "),0,0,MN_ID_HEIGHT);
98 settings_menu->additem(MN_HL,"",0,0);
99 settings_menu->additem(MN_ACTION,_("Apply"),0,0,MN_ID_APPLY_SETTINGS);
100
101 /* Creating button groups */
102 load_buttons_gfx();
103
104 tiles_board = new ButtonGroup(Vector(screen->w - 140, 100),
105           Vector(32,32), Vector(4,8));
106
107 TileManager* tilemanager = TileManager::instance();
108
109 tiles_board->add_button(Button(img_rubber_bt, _("Eraser"), SDLKey(SDLK_DELETE)), 0);
110 for(unsigned int id = 1; id < tilemanager->total_ids(); id++)
111   {
112   Tile* tile = tilemanager->get(id);
113   if(!tile)
114     continue;
115
116   Surface* surface;
117   if(tile->editor_images.size())
118     surface = tile->editor_images[0];
119   else if(tile->images.size())
120     surface = tile->images[0];
121   else
122     continue;
123
124   Button button = Button(surface, "", SDLKey(0));
125   tiles_board->add_button(button, id);
126   }
127 for(int i = 0; i < NUM_BadGuyKinds; i++)
128   {
129   // filter bomb, since it is only for internal use, not for levels
130   if(i == BAD_BOMB)
131     continue;
132
133   BadGuyKind kind = BadGuyKind(i);
134   BadGuy badguy(kind, 0,0);
135   badguy.activate(LEFT);
136
137   Surface *img = badguy.get_image();
138   tiles_board->add_button(Button(img, "", SDLKey(SDLK_1+i)), -(i+1));
139   }
140
141 tiles_board->add_button(Button(img_trampoline[0].get_frame(0), _("Trampoline"), SDLKey(0)), OBJ_TRAMPOLINE);
142 tiles_board->add_button(Button(img_flying_platform->get_frame(0), _("Flying Platform"), SDLKey(0)), OBJ_FLYING_PLATFORM);
143 tiles_board->add_button(Button(door->get_frame(0), _("Door"), SDLKey(0)), OBJ_DOOR);
144
145 tiles_layer = new ButtonGroup(Vector(12, screen->h-64), Vector(80,20), Vector(1,3));
146 tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
147                        SDLK_F10), LAYER_FOREGROUNDTILES);
148 tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
149                        SDLK_F11), LAYER_TILES, true);
150 tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
151                        SDLK_F12), LAYER_BACKGROUNDTILES);
152
153 level_options = new ButtonGroup(Vector(screen->w-164, screen->h-36), Vector(32,32), Vector(5,1));
154 level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
155                Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
156 level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
157                Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
158 level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
159 level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
160 level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
161 }
162
163 LevelEditor::~LevelEditor()
164 {
165 free_buttons_gfx();
166
167 delete tiles_board;
168 delete tiles_layer;
169 delete level_options;
170
171 delete subset_menu;
172 delete create_subset_menu;
173 delete main_menu;
174 delete settings_menu;
175
176 delete level;
177 delete level_subset;
178 }
179
180 void LevelEditor::load_buttons_gfx()
181 {
182 img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
183 img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
184 img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
185
186 img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
187 img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
188 img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
189
190 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
191
192 img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
193 img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
194 img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
195 img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
196 }
197
198 void LevelEditor::free_buttons_gfx()
199 {
200 delete img_foreground_bt;
201 delete img_interactive_bt;
202 delete img_background_bt;
203
204 delete img_save_level_bt;
205 delete img_test_level_bt;
206 delete img_setup_level_bt;
207
208 delete img_rubber_bt;
209
210 delete img_previous_level_bt;
211 delete img_next_level_bt;
212 delete img_previous_sector_bt;
213 delete img_next_sector_bt;
214 }
215
216 void LevelEditor::run(const std::string filename)
217 {
218 SoundManager::get()->halt_music();
219 Menu::set_current(0);
220
221 DrawingContext context;
222
223 if(!filename.empty())
224   {
225   level_nb = -1;
226   load_level(filename);
227   }
228 else
229   Menu::set_current(main_menu);
230
231 mouse_cursor->set_state(MC_NORMAL);
232
233 done = false;
234 while(!done)
235   {
236   events();
237   action();
238   draw(context);
239   }
240
241 if(level_changed)
242   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
243     save_level();
244 }
245
246 void LevelEditor::events()
247 {
248 mouse_moved = false;
249
250 while(SDL_PollEvent(&event))
251   {
252   Menu* menu = Menu::current();
253   if(menu)
254     {
255     menu->event(event);
256     menu->action();
257     if(menu == main_menu)
258       {
259       switch (main_menu->check())
260         {
261         case MN_ID_RETURN:
262           Menu::set_current(0);
263           break;
264         case MN_ID_QUIT:
265           done = true;
266           break;
267         }
268       }
269     else if(menu == create_subset_menu)
270       {
271       if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
272         create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
273       else if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
274         {   // applying settings:
275         LevelSubset::create(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
276
277         delete level_subset;
278         level_subset = new LevelSubset();
279         level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
280
281         level_subset->title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
282         level_subset->description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
283
284         load_level(1);
285
286         create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
287         create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
288         create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
289         }
290       }
291     else if(menu == subset_menu)
292       {
293       int i = subset_menu->check();
294       if(i >= 0)
295         {
296         std::set<std::string>::iterator it = level_subsets.begin();
297         for(int t = 0; t < i; t++)
298           it++;
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       continue;
685       }
686     Background* background = dynamic_cast<Background*> (*i);
687     if(background)
688       {  // don't resize background
689       context.push_transform();
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 delete level_subset;
709 level_subset = new LevelSubset();
710 level_subset->load(filename.c_str());
711 load_level(1);
712 }
713
714 void LevelEditor::load_level(std::string filename)
715 {
716 if(level_changed)
717   {
718   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
719     save_level();
720   else
721     return;
722   }
723
724 level_filename = filename;
725
726 delete level;
727 level = new Level();
728 level->load(filename);
729
730 load_sector("main");
731 level_name_timer.start(3000);
732 scroll.x = scroll.y = 0;
733 level_changed = false;
734
735 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
736 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
737 }
738
739 void LevelEditor::load_level(int nb)
740 {
741 if(level_changed)
742   {
743   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
744     save_level();
745   else
746     return;
747   }
748
749 level_nb = nb;
750 level_filename = level_subset->get_level_filename(level_nb);
751
752 load_level(level_filename);
753 }
754
755 void LevelEditor::load_sector(std::string name)
756 {
757 sector_name = name;
758 sector = level->get_sector(sector_name);
759 if(!sector)
760   Termination::abort("Level has no " + sector_name + " sector.", "");
761
762 load_sector(sector);
763 }
764
765 void LevelEditor::load_sector(Sector* sector_)
766 {
767 if(sector == NULL)
768   {
769   if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
770     {
771     Sector* nsector = new Sector();
772     level->add_sector(nsector);
773     sector = nsector;
774     }
775   return;
776   }
777
778 sector = sector_;
779
780 /* Load sector stuff */
781
782 sector->update_game_objects();
783
784 foregrounds = solids = backgrounds = 0;
785 /* Point foregrounds, backgrounds, solids to its layer */
786 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
787   {
788   BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
789   if(badguy)
790     badguy->activate(LEFT);
791
792   TileMap* tilemap = dynamic_cast<TileMap*> (*i);
793   if(tilemap)
794     {
795     if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
796       foregrounds = tilemap;
797     else if(tilemap->get_layer() == LAYER_TILES)
798       solids = tilemap;
799     else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
800       backgrounds = tilemap;
801     }
802   }
803
804 if(!foregrounds)
805   {
806   TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
807   sector->add_object(tilemap);
808   sector->update_game_objects();
809   }
810 if(!backgrounds)
811   {
812   TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
813   sector->add_object(tilemap);
814   sector->update_game_objects();
815   }
816
817 char str[64];
818 sprintf(str, "%i", solids->get_width());
819 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
820 sprintf(str, "%i", solids->get_height());
821 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
822 }
823
824 void LevelEditor::save_level()
825 {
826 level->save(level_filename);
827 level_changed = false;
828 }
829
830 void LevelEditor::test_level()
831 {
832 if(level_changed)
833   {
834   if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
835     save_level();
836   else
837     return;
838   }
839
840 GameSession session(level_filename, ST_GL_TEST);
841 session.run();
842 //  player_status.reset();
843 if(sound_manager)
844   sound_manager->halt_music();
845 }
846
847 void LevelEditor::change(int x, int y, int newtile, int layer)
848 {  // find the tilemap of the current layer, and then change the tile
849 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
850    y < 0 || (unsigned int)y > sector->solids->get_height()*32)
851   return;
852
853 level_changed = true;
854
855 if(zoom != 1)
856   {  // no need to do this for normal view (no zoom)
857   x = (int)(x * (zoom*32) / 32);
858   y = (int)(y * (zoom*32) / 32);
859   }
860
861 if(newtile < 0)  // add object
862   {
863   // remove an active tile or object that might be there
864   change(x, y, 0, LAYER_TILES);
865
866   if(newtile == OBJ_TRAMPOLINE)
867     sector->add_object(new Trampoline(x, y));
868   else if(newtile == OBJ_FLYING_PLATFORM)
869     sector->add_object(new FlyingPlatform(x, y));
870   else if(newtile == OBJ_DOOR)
871     sector->add_object(new Door(x, y));
872   else
873     sector->add_bad_guy(x, y, BadGuyKind((-newtile)-1), true);
874
875   sector->update_game_objects();
876   }
877 else if(cur_layer == LAYER_FOREGROUNDTILES)
878   foregrounds->change(x/32, y/32, newtile);
879 else if(cur_layer == LAYER_TILES)
880   {
881   // remove a bad guy if it's there
882   // we /32 in order to round numbers
883   for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
884     {
885     BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
886     if(badguy)
887       if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
888         sector->gameobjects.erase(i);
889     Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
890     if(trampoline)
891     {
892       if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
893         sector->gameobjects.erase(i);
894         }
895     FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
896     if(flying_platform)
897       if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
898         sector->gameobjects.erase(i);
899     Door* door = dynamic_cast<Door*> (*i);
900     if(door)
901       if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
902         sector->gameobjects.erase(i);
903     }
904   sector->update_game_objects();
905   solids->change(x/32, y/32, newtile);
906   }
907 else if(cur_layer == LAYER_BACKGROUNDTILES)
908   backgrounds->change(x/32, y/32, newtile);
909 }
910
911 void LevelEditor::show_help()
912 {
913 DrawingContext context;
914
915 bool show_grid_t = show_grid;
916 show_grid = false;
917 mouse_cursor->set_state(MC_HIDE);
918
919
920 char str[1024];
921 char *text1[] = {
922          _("This is the built-in level editor. It's aim is to be intuitive\n"
923          "and simple to use, so it should be pretty straight forward.\n"
924          "\n"
925          "To open a level, first you'll have to select a level subset from\n"
926          "the menu (or create your own).\n"
927          "A level subset is basically a collection of levels.\n"
928          "They can then be played from the Contrib menu.\n"
929          "\n"
930          "To access the menu from the level editor, just press Esc.\n"
931          "\n"
932          "You are currently looking to the level, to scroll it, just\n"
933          "press the right mouse button and drag the mouse. It will move like\n"
934          "a strategy game.\n"
935          "You can also use the arrow keys and Page Up/Down.\n"
936          "\n"
937          "'+' and '-' keys can be used to zoom in/out the level.\n"
938          "\n"
939          "You probably already noticed those floating group of buttons.\n"
940          "Each one serves a different purpose. To select a certain button\n"
941          "just press the Left mouse button on it. A few buttons have key\n"
942          "shortcuts, you can know it by pressing the Right mouse button on\n"
943          "it. That will also show what that button does.\n"
944          "Group of buttons can also be move around by just dragging them,\n"
945          "while pressing the Left mouse button.\n"
946          "\n"
947          "Let's learn a bit of what each group of buttons do, shall we?\n"
948          "\n"
949          "To starting putting tiles and objects around use the bigger gropup\n"
950          "of buttons. Each button is a different tile. To put it on the level,\n"
951          "just press it and then left click in the level.\n"
952          "You can also copy tiles from the level by using the middle mouse button.\n"
953          "Use the mouse wheel to scroll that group of buttons. You will find\n"
954          "enemies and game objects in the bottom.\n")
955                 };
956
957 char *text2[] = {
958          _("The Foreground/Interactive/Background buttons may be used to\n"
959          "see and edit the respective layer. Level's have three tiles layers:\n"
960          "Foreground - tiles are drawn in top of everything and have no contact\n"
961          "with the player.\n"
962          "Interactive - these are the tiles that have contact with the player.\n"
963          "Background - tiles are drawn in bottom of everything and have no contact\n"
964          "with the player.\n"
965          "The unselected layers will be drawn semi-transparently.\n"
966          "\n"
967          "At last, but not least, the group of buttons that's left serves\n"
968          "to do related actions with the level.\n"
969          "From left to right:\n"
970          "Mini arrows - can be used to choose other sectors.\n"
971          "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
972          "Big arrows - choose other level in the same level subset.\n"
973          "Diskette - save the level\n"
974          "Tux - test the level\n"
975          "Tools - set a few settings for the level, incluiding resizing it.\n"
976          "\n"
977          "We have reached the end of this Howto.\n"
978          "\n"
979          "Don't forget to send us a few cool levels. :)\n"
980          "\n"
981          "Enjoy,\n"
982          "  SuperTux development team\n"
983          "\n"
984          "ps: If you are looking for something more powerfull, you can give it a\n"
985          "try to FlexLay. FlexLay is a level editor that supports several games,\n"
986          "including SuperTux. It is an independent project.\n"
987          "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
988                 };
989
990 char **text[] = { text1, text2 };
991
992
993 bool done;
994 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
995   {
996   draw(context);
997
998   context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
999
1000   context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
1001
1002   sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
1003   context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
1004
1005   context.do_drawing();
1006
1007   done = false;
1008
1009   while(!done)
1010     {
1011     done = wait_for_event(event);
1012     SDL_Delay(50);
1013     }
1014   }
1015
1016 show_grid = show_grid_t;
1017 mouse_cursor->set_state(MC_NORMAL);
1018 }