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