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