1 /***************************************************************************
2 leveleditor.cpp - built'in leveleditor
5 copyright : (C) 2004 by Ricardo Cruz
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
21 #include "gui/mousecursor.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"
33 #include "tile_manager.h"
35 #include "background.h"
41 LevelEditor::LevelEditor()
46 global_frame_counter = 0;
47 frame_timer.init(true);
48 level_name_timer.init(true);
49 selection_end = selection_ini = Vector(0,0);
51 middle_button = false;
53 cur_layer = LAYER_TILES;
54 level_changed = false;
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);
65 for(std::set<std::string>::iterator it = level_subsets.begin(); it != level_subsets.end(); ++it, ++i)
67 std::cerr << "adding entry level subset " << i << " entry: " << (*it) << std::endl;
68 subset_menu->additem(MN_ACTION, (*it),0,0,i);
70 subset_menu->additem(MN_HL,"",0,0);
71 subset_menu->additem(MN_BACK,_("Back"),0,0);
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);
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);
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);
102 /* Creating button groups */
105 tiles_board = new ButtonGroup(Vector(screen->w - 140, 100),
106 Vector(32,32), Vector(4,8));
108 TileManager* tilemanager = TileManager::instance();
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++)
113 Tile* tile = tilemanager->get(id);
118 if(tile->editor_images.size())
119 surface = tile->editor_images[0];
120 else if(tile->images.size())
121 surface = tile->images[0];
125 Button button = Button(surface, "", SDLKey(0));
126 tiles_board->add_button(button, id);
128 for(int i = 0; i < NUM_BadGuyKinds; i++)
130 BadGuyKind kind = BadGuyKind(i);
131 BadGuy badguy(kind, 0,0);
132 badguy.activate(LEFT);
134 Surface *img = badguy.get_image();
135 tiles_board->add_button(Button(img, "", SDLKey(SDLK_1+i)), -(i+1));
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);
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);
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);
160 LevelEditor::~LevelEditor()
166 delete level_options;
169 delete create_subset_menu;
171 delete settings_menu;
174 void LevelEditor::load_buttons_gfx()
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);
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);
184 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
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);
192 void LevelEditor::free_buttons_gfx()
194 delete img_foreground_bt;
195 delete img_interactive_bt;
196 delete img_background_bt;
198 delete img_save_level_bt;
199 delete img_test_level_bt;
200 delete img_setup_level_bt;
202 delete img_rubber_bt;
204 delete img_previous_level_bt;
205 delete img_next_level_bt;
206 delete img_previous_sector_bt;
207 delete img_next_sector_bt;
210 void LevelEditor::run(const std::string filename)
212 SoundManager::get()->halt_music();
213 Menu::set_current(0);
215 DrawingContext context;
217 if(!filename.empty())
218 load_level(filename);
220 Menu::set_current(main_menu);
222 mouse_cursor->set_state(MC_NORMAL);
233 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
237 void LevelEditor::events()
239 while(SDL_PollEvent(&event))
241 Menu* menu = Menu::current();
246 if(menu == main_menu)
248 switch (main_menu->check())
251 Menu::set_current(0);
258 else if(menu == create_subset_menu)
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);
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;
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("");
277 else if(menu == subset_menu)
279 int i = subset_menu->check();
282 std::set<std::string>::iterator it = level_subsets.begin();
283 for(int t = 0; t < i; t++)
285 std::cerr << "load subset level_subsets " << i << ": " << (*it) << std::endl;
286 load_level_subset(*it);
287 Menu::set_current(0);
290 else if(menu == settings_menu)
292 if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
293 { // applying settings:
294 level_changed = true;
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;
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()));
306 Menu::set_current(0);
310 // check for events in buttons
311 else if(tiles_board->event(event))
313 std::vector <int> vector;
314 vector.push_back(tiles_board->selected_id());
317 selection.push_back(vector);
320 else if(tiles_layer->event(event))
322 cur_layer = tiles_layer->selected_id();
325 else if(level_options->event(event))
327 switch(level_options->selected_id())
336 Menu::set_current(settings_menu);
339 if(level_nb < level_subset.get_num_levels())
340 load_level(level_nb + 1);
345 sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 1);
346 if(confirm_dialog(NULL, str))
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);
354 case BT_PREVIOUS_LEVEL:
356 load_level(level_nb - 1);
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));
363 case BT_PREVIOUS_SECTOR:
364 std::cerr << "previous sector.\n";
365 load_sector(level.get_previous_sector(sector));
368 level_options->set_unselected();
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;
383 case SDL_MOUSEBUTTONDOWN:
384 if(event.button.button == SDL_BUTTON_LEFT)
386 else if(event.button.button == SDL_BUTTON_MIDDLE)
388 middle_button = true;
389 selection_ini = Vector(event.button.x, event.button.y);
393 case SDL_MOUSEBUTTONUP:
394 if(event.button.button == SDL_BUTTON_LEFT)
396 else if(event.button.button == SDL_BUTTON_MIDDLE)
398 middle_button = false;
399 selection_end = Vector(event.button.x, event.button.y);
401 if(selection_end.x < selection_ini.x)
403 float t = selection_ini.x;
404 selection_ini.x = selection_end.x;
407 if(selection_end.y < selection_ini.y)
409 float t = selection_ini.y;
410 selection_ini.y = selection_end.y;
415 std::vector <int> vector;
417 TileMap* tilemap = 0;
418 if(cur_layer == LAYER_FOREGROUNDTILES)
419 tilemap = foregrounds;
420 else if(cur_layer == LAYER_TILES)
422 else if(cur_layer == LAYER_BACKGROUNDTILES)
423 tilemap = backgrounds;
425 for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
428 for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
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);
434 selection.push_back(vector);
439 case SDL_KEYDOWN: // key pressed
440 switch(event.key.keysym.sym)
443 Menu::set_current(main_menu);
445 /* scrolling related events: */
450 scroll.x = sector->solids->get_height()*32 - screen->w;
483 show_grid = !show_grid;
490 case SDL_QUIT: // window closed
501 void LevelEditor::action()
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);
509 if(!frame_timer.check())
511 frame_timer.start(25);
512 ++global_frame_counter;
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;
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;
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],
537 void LevelEditor::draw(DrawingContext& context)
539 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
540 mouse_cursor->draw(context);
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);
545 if(level_name_timer.check())
547 context.draw_text(gold_text, level.name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
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);
553 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
555 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
557 Menu* menu = Menu::current();
562 tiles_board->draw(context);
563 tiles_layer->draw(context);
564 level_options->draw(context);
572 context.set_drawing_effect(SEMI_TRANSPARENT);
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)
581 int id = selection[0][0];
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);
594 BadGuyKind kind = BadGuyKind((-id)-1);
595 BadGuy badguy(kind, 0,0);
596 badguy.activate(LEFT);
597 Surface *img = badguy.get_image();
599 context.draw_surface(img, Vector(event.button.x - 8,
600 event.button.y - 8), LAYER_GUI-2);
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),
613 context.set_drawing_effect(NONE_EFFECT);
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);
624 for(int x = 0; x < screen->w / (32*zoom); x++)
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);
630 for(int y = 0; y < screen->h / (32*zoom); y++)
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);
638 context.push_transform();
639 context.set_translation(scroll);
640 context.set_zooming(zoom);
642 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
644 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
646 { // draw the non-selected tiles semi-transparently
647 context.push_transform();
649 if(tilemap->get_layer() != cur_layer)
650 context.set_drawing_effect(SEMI_TRANSPARENT);
653 context.pop_transform();
655 Background* background = dynamic_cast<Background*> (*i);
657 { // don't resize background
658 context.push_transform();
659 context.set_translation(scroll);
660 context.set_zooming(1.0);
662 context.pop_transform();
668 context.pop_transform();
671 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
673 context.do_drawing();
676 void LevelEditor::load_level_subset(std::string filename)
678 std::cerr << "loading subset...\n";
679 std::cerr << "filename: " << filename << std::endl;
680 level_subset.load(filename.c_str());
684 void LevelEditor::load_level(std::string filename)
689 level_filename = filename;
690 level.load(filename);
693 level_name_timer.start(3000);
694 scroll.x = scroll.y = 0;
695 level_changed = false;
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());
701 void LevelEditor::load_level(int 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);
711 load_level(level_filename);
714 void LevelEditor::load_sector(std::string name)
717 sector = level.get_sector(sector_name);
719 Termination::abort("Level has no " + sector_name + " sector.", "");
724 void LevelEditor::load_sector(Sector* sector_)
728 if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
730 Sector* nsector = new Sector();
731 level.add_sector(nsector);
739 /* Load sector stuff */
741 sector->update_game_objects();
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++)
747 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
749 badguy->activate(LEFT);
751 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
754 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
755 foregrounds = tilemap;
756 else if(tilemap->get_layer() == LAYER_TILES)
758 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
759 backgrounds = tilemap;
765 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
766 sector->add_object(tilemap);
767 sector->update_game_objects();
771 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
772 sector->add_object(tilemap);
773 sector->update_game_objects();
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);
783 void LevelEditor::save_level()
785 level.save(level_filename);
786 level_changed = false;
789 void LevelEditor::test_level()
793 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
799 GameSession session(level_filename, ST_GL_TEST);
801 // player_status.reset();
802 sound_manager->halt_music();
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())
811 level_changed = true;
813 if(newtile < 0) // add object
815 // remove an active tile or object that might be there
816 change(x, y, 0, LAYER_TILES);
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));
825 sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x*32, y*32));
827 sector->update_game_objects();
829 else if(cur_layer == LAYER_FOREGROUNDTILES)
830 foregrounds->change(x, y, newtile);
831 else if(cur_layer == LAYER_TILES)
833 // remove a bad guy if it's there
834 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
836 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
838 if(badguy->base.x == x*32 && badguy->base.y == y*32)
839 sector->gameobjects.erase(i);
840 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
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);
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);
850 if(door->get_area().x == x*32 && door->get_area().y == y*32)
851 sector->gameobjects.erase(i);
853 sector->update_game_objects();
854 solids->change(x, y, newtile);
856 else if(cur_layer == LAYER_BACKGROUNDTILES)
857 backgrounds->change(x, y, newtile);
860 void LevelEditor::show_help()
862 DrawingContext context;
864 bool show_grid_t = show_grid;
866 mouse_cursor->set_state(MC_HIDE);
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"
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"
879 "To access the menu from the level editor, just press Esc.\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"
884 "You can also use the arrow keys and Page Up/Down.\n"
886 "'+' and '-' keys can be used to zoom in/out the level.\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"
896 "Let's learn a bit of what each group of buttons do, shall we?\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")
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"
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"
914 "The unselected layers will be drawn semi-transparently.\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"
926 "We have reached the end of this Howto.\n"
928 "Don't forget to send us a few cool levels. :)\n"
931 " SuperTux development team\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/")
939 char **text[] = { text1, text2 };
943 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
947 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
949 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
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);
954 context.do_drawing();
960 done = wait_for_event(event);
965 show_grid = show_grid_t;
966 mouse_cursor->set_state(MC_NORMAL);