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