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"
42 LevelEditor::LevelEditor()
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;
55 cur_layer = LAYER_TILES;
56 level_changed = false;
62 level_subsets = FileSystem::dsubdirs("/levels", "info");
63 subset_menu = new Menu();
64 subset_menu->additem(MN_LABEL,_("Load Subset"),0,0);
65 subset_menu->additem(MN_HL,"",0,0);
67 for(std::set<std::string>::iterator it = level_subsets.begin(); it != level_subsets.end(); ++it, ++i)
68 subset_menu->additem(MN_ACTION, (*it),0,0,i);
69 subset_menu->additem(MN_HL,"",0,0);
70 subset_menu->additem(MN_BACK,_("Back"),0,0);
72 create_subset_menu = new Menu();
73 create_subset_menu->additem(MN_LABEL,_("New Level Subset"),0,0);
74 create_subset_menu->additem(MN_HL,"",0,0);
75 create_subset_menu->additem(MN_TEXTFIELD,_("Filename "),0,0,MN_ID_FILENAME_SUBSET);
76 create_subset_menu->additem(MN_TEXTFIELD,_("Title "),0,0,MN_ID_TITLE_SUBSET);
77 create_subset_menu->additem(MN_TEXTFIELD,_("Description"),0,0,MN_ID_DESCRIPTION_SUBSET);
78 create_subset_menu->additem(MN_ACTION,_("Create"),0,0, MN_ID_CREATE_SUBSET);
79 create_subset_menu->additem(MN_HL,"",0,0);
80 create_subset_menu->additem(MN_BACK,_("Back"),0,0);
82 main_menu = new Menu();
83 main_menu->additem(MN_LABEL,_("Level Editor Menu"),0,0);
84 main_menu->additem(MN_HL,"",0,0);
85 main_menu->additem(MN_ACTION,_("Return to Level Editor"),0,0,MN_ID_RETURN);
86 main_menu->additem(MN_GOTO,_("Create Level Subset"),0,create_subset_menu);
87 main_menu->additem(MN_GOTO,_("Load Level Subset"),0,subset_menu);
88 main_menu->additem(MN_HL,"",0,0);
89 main_menu->additem(MN_ACTION,_("Quit Level Editor"),0,0,MN_ID_QUIT);
91 settings_menu = new Menu();
92 settings_menu->additem(MN_LABEL,_("Level Settings"),0,0);
93 settings_menu->additem(MN_HL,"",0,0);
94 settings_menu->additem(MN_TEXTFIELD,_("Name "),0,0,MN_ID_NAME);
95 settings_menu->additem(MN_TEXTFIELD,_("Author "),0,0,MN_ID_AUTHOR);
96 settings_menu->additem(MN_NUMFIELD, _("Width "),0,0,MN_ID_WIDTH);
97 settings_menu->additem(MN_NUMFIELD, _("Height "),0,0,MN_ID_HEIGHT);
98 settings_menu->additem(MN_HL,"",0,0);
99 settings_menu->additem(MN_ACTION,_("Apply"),0,0,MN_ID_APPLY_SETTINGS);
101 /* Creating button groups */
104 tiles_board = new ButtonGroup(Vector(screen->w - 140, 100),
105 Vector(32,32), Vector(4,8));
107 TileManager* tilemanager = TileManager::instance();
109 tiles_board->add_button(Button(img_rubber_bt, _("Eraser"), SDLKey(SDLK_DELETE)), 0);
110 for(unsigned int id = 1; id < tilemanager->total_ids(); id++)
112 Tile* tile = tilemanager->get(id);
117 if(tile->editor_images.size())
118 surface = tile->editor_images[0];
119 else if(tile->images.size())
120 surface = tile->images[0];
124 Button button = Button(surface, "", SDLKey(0));
125 tiles_board->add_button(button, id);
127 for(int i = 0; i < NUM_BadGuyKinds; i++)
129 BadGuyKind kind = BadGuyKind(i);
130 BadGuy badguy(kind, 0,0);
131 badguy.activate(LEFT);
133 Surface *img = badguy.get_image();
134 tiles_board->add_button(Button(img, "", SDLKey(SDLK_1+i)), -(i+1));
137 tiles_board->add_button(Button(img_trampoline[0].get_frame(0), _("Trampoline"), SDLKey(0)), OBJ_TRAMPOLINE);
138 tiles_board->add_button(Button(img_flying_platform->get_frame(0), _("Flying Platform"), SDLKey(0)), OBJ_FLYING_PLATFORM);
139 tiles_board->add_button(Button(door->get_frame(0), _("Door"), SDLKey(0)), OBJ_DOOR);
141 tiles_layer = new ButtonGroup(Vector(12, screen->h-64), Vector(80,20), Vector(1,3));
142 tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
143 SDLK_F10), LAYER_FOREGROUNDTILES);
144 tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
145 SDLK_F11), LAYER_TILES, true);
146 tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
147 SDLK_F12), LAYER_BACKGROUNDTILES);
149 level_options = new ButtonGroup(Vector(screen->w-164, screen->h-36), Vector(32,32), Vector(5,1));
150 level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
151 Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
152 level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
153 Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
154 level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
155 level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
156 level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
159 LevelEditor::~LevelEditor()
165 delete level_options;
168 delete create_subset_menu;
170 delete settings_menu;
176 void LevelEditor::load_buttons_gfx()
178 img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
179 img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
180 img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
182 img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
183 img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
184 img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
186 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
188 img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
189 img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
190 img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
191 img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
194 void LevelEditor::free_buttons_gfx()
196 delete img_foreground_bt;
197 delete img_interactive_bt;
198 delete img_background_bt;
200 delete img_save_level_bt;
201 delete img_test_level_bt;
202 delete img_setup_level_bt;
204 delete img_rubber_bt;
206 delete img_previous_level_bt;
207 delete img_next_level_bt;
208 delete img_previous_sector_bt;
209 delete img_next_sector_bt;
212 void LevelEditor::run(const std::string filename)
214 SoundManager::get()->halt_music();
215 Menu::set_current(0);
217 DrawingContext context;
219 if(!filename.empty())
222 load_level(filename);
225 Menu::set_current(main_menu);
227 mouse_cursor->set_state(MC_NORMAL);
238 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
242 void LevelEditor::events()
246 while(SDL_PollEvent(&event))
248 Menu* menu = Menu::current();
253 if(menu == main_menu)
255 switch (main_menu->check())
258 Menu::set_current(0);
265 else if(menu == create_subset_menu)
267 if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
268 create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
269 else if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
270 { // applying settings:
271 LevelSubset::create(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
274 level_subset = new LevelSubset();
275 level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
277 level_subset->title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
278 level_subset->description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
282 create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
283 create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
284 create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
287 else if(menu == subset_menu)
289 int i = subset_menu->check();
292 std::set<std::string>::iterator it = level_subsets.begin();
293 for(int t = 0; t < i; t++)
295 load_level_subset(*it);
296 Menu::set_current(0);
299 else if(menu == settings_menu)
301 if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
302 { // applying settings:
303 level_changed = true;
305 level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
306 level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
308 solids->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 foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
311 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
312 backgrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
313 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
315 Menu::set_current(0);
319 // check for events in buttons
320 else if(tiles_board->event(event))
322 std::vector <int> vector;
323 vector.push_back(tiles_board->selected_id());
326 selection.push_back(vector);
329 else if(tiles_layer->event(event))
331 cur_layer = tiles_layer->selected_id();
334 else if(level_options->event(event))
336 switch(level_options->selected_id())
345 Menu::set_current(settings_menu);
348 if(level_nb+1 < level_subset->get_num_levels())
349 load_level(level_nb + 1);
353 sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 1);
354 if(confirm_dialog(NULL, str))
357 level_subset->add_level("new_level.stl");
358 new_lev.save(level_subset->get_level_filename(level_nb + 1));
359 load_level(level_nb);
363 case BT_PREVIOUS_LEVEL:
365 load_level(level_nb - 1);
368 std::cerr << "next sector.\n";
369 std::cerr << "total sectors: " << level->get_total_sectors() << std::endl;
370 load_sector(level->get_next_sector(sector));
372 case BT_PREVIOUS_SECTOR:
373 std::cerr << "previous sector.\n";
374 load_sector(level->get_previous_sector(sector));
377 level_options->set_unselected();
384 case SDL_MOUSEMOTION:
386 if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
387 { // movement like in strategy games
388 scroll.x += -1 * event.motion.xrel;
389 scroll.y += -1 * event.motion.yrel;
393 case SDL_MOUSEBUTTONDOWN:
395 if(event.button.button == SDL_BUTTON_LEFT)
397 else if(event.button.button == SDL_BUTTON_MIDDLE)
399 middle_button = true;
400 selection_ini = Vector(event.button.x, event.button.y);
404 case SDL_MOUSEBUTTONUP:
406 if(event.button.button == SDL_BUTTON_LEFT)
408 else if(event.button.button == SDL_BUTTON_MIDDLE)
410 middle_button = false;
411 selection_end = Vector(event.button.x, event.button.y);
413 if(selection_end.x < selection_ini.x)
415 float t = selection_ini.x;
416 selection_ini.x = selection_end.x;
419 if(selection_end.y < selection_ini.y)
421 float t = selection_ini.y;
422 selection_ini.y = selection_end.y;
427 std::vector <int> vector;
429 TileMap* tilemap = 0;
430 if(cur_layer == LAYER_FOREGROUNDTILES)
431 tilemap = foregrounds;
432 else if(cur_layer == LAYER_TILES)
434 else if(cur_layer == LAYER_BACKGROUNDTILES)
435 tilemap = backgrounds;
437 for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
440 for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
442 vector.push_back(tilemap->get_tile(x +
443 (int)(((selection_ini.x+scroll.x)*zoom)/32),
444 y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->id);
446 selection.push_back(vector);
451 case SDL_KEYDOWN: // key pressed
452 switch(event.key.keysym.sym)
455 Menu::set_current(main_menu);
457 /* scrolling related events: */
462 scroll.x = sector->solids->get_height()*32 - screen->w;
495 show_grid = !show_grid;
502 case SDL_QUIT: // window closed
513 void LevelEditor::action()
515 mouse_cursor->set_state(MC_NORMAL);
516 if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
517 mouse_cursor->set_state(MC_LINK);
521 if(!frame_timer.check())
523 frame_timer.start(25);
524 ++global_frame_counter;
527 // don't scroll before the start or after the level's end
528 float width = sector->solids->get_width() * 32;
529 float height = sector->solids->get_height() * 32;
531 if(scroll.x < -screen->w/2)
532 scroll.x = -screen->w/2;
533 if(scroll.x > width - screen->w/2)
534 scroll.x = width - screen->w/2;
535 if(scroll.y < -screen->h/2)
536 scroll.y = -screen->h/2;
537 if(scroll.y > height - screen->h/2)
538 scroll.y = height - screen->h/2;
540 // set camera translation, since BadGuys like it
541 sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
543 if(left_button && mouse_moved)
544 for(unsigned int x = 0; x < selection.size(); x++)
545 for(unsigned int y = 0; y < selection[x].size(); y++)
546 change((int)(scroll.x + event.button.x) + (x*32),
547 (int)(scroll.y + event.button.y) + (y*32), selection[x][y],
552 #define FADING_TIME 600
554 void LevelEditor::draw(DrawingContext& context)
556 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
557 mouse_cursor->draw(context);
559 // draw a filled background
560 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
562 if(level_name_timer.check())
564 context.push_transform();
565 if(level_name_timer.get_left() < FADING_TIME)
566 context.set_alpha(level_name_timer.get_left() * 255 / FADING_TIME);
568 context.draw_text(gold_text, level->name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
572 sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
573 context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
576 context.pop_transform();
579 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
581 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
583 Menu* menu = Menu::current();
588 tiles_board->draw(context);
589 tiles_layer->draw(context);
590 level_options->draw(context);
598 context.set_drawing_effect(SEMI_TRANSPARENT);
602 if(selection[0][0] == 0 && selection.size() == 1)
603 context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
604 event.button.y - 8), LAYER_GUI-2);
605 else if(selection[0][0] < 0)
607 int id = selection[0][0];
609 if(id == OBJ_TRAMPOLINE)
610 context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
611 event.button.y - 8), LAYER_GUI-2);
612 else if(id == OBJ_FLYING_PLATFORM)
613 context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
614 event.button.y - 8), LAYER_GUI-2);
615 else if(id == OBJ_DOOR)
616 context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
617 event.button.y - 8), LAYER_GUI-2);
620 BadGuyKind kind = BadGuyKind((-id)-1);
621 BadGuy badguy(kind, 0,0);
622 badguy.activate(LEFT);
623 Surface *img = badguy.get_image();
625 context.draw_surface(img, Vector(event.button.x - 8,
626 event.button.y - 8), LAYER_GUI-2);
631 TileManager* tilemanager = TileManager::instance();
632 for(unsigned int x = 0; x < selection.size(); x++)
633 for(unsigned int y = 0; y < selection[x].size(); y++)
634 tilemanager->draw_tile(context, selection[x][y],
635 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
639 context.set_drawing_effect(NONE_EFFECT);
642 context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
643 std::min((int)selection_ini.y, (int)event.button.y))*zoom,
644 Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
645 abs(event.button.y - (int)selection_ini.y)*zoom),
646 Color(170,255,170,128), LAYER_GUI-2);
650 for(int x = 0; x < screen->w / (32*zoom); x++)
652 int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
653 context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
654 Color(225, 225, 225), LAYER_GUI-50);
656 for(int y = 0; y < screen->h / (32*zoom); y++)
658 int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
659 context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
660 Color(225, 225, 225), LAYER_GUI-50);
664 context.push_transform();
665 context.set_translation(scroll);
666 context.set_zooming(zoom);
668 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
670 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
672 { // draw the non-selected tiles semi-transparently
673 context.push_transform();
675 if(tilemap->get_layer() != cur_layer)
676 context.set_drawing_effect(SEMI_TRANSPARENT);
679 context.pop_transform();
681 Background* background = dynamic_cast<Background*> (*i);
683 { // don't resize background
684 context.push_transform();
685 context.set_translation(scroll);
686 context.set_zooming(1.0);
688 context.pop_transform();
694 context.pop_transform();
697 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
699 context.do_drawing();
702 void LevelEditor::load_level_subset(std::string filename)
705 level_subset = new LevelSubset();
706 level_subset->load(filename.c_str());
710 void LevelEditor::load_level(std::string filename)
714 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
720 level_filename = filename;
724 level->load(filename);
727 level_name_timer.start(3000);
728 scroll.x = scroll.y = 0;
729 level_changed = false;
731 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
732 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
735 void LevelEditor::load_level(int nb)
739 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
746 level_filename = level_subset->get_level_filename(level_nb);
748 load_level(level_filename);
751 void LevelEditor::load_sector(std::string name)
754 sector = level->get_sector(sector_name);
756 Termination::abort("Level has no " + sector_name + " sector.", "");
761 void LevelEditor::load_sector(Sector* sector_)
765 if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
767 Sector* nsector = new Sector();
768 level->add_sector(nsector);
776 /* Load sector stuff */
778 sector->update_game_objects();
780 foregrounds = solids = backgrounds = 0;
781 /* Point foregrounds, backgrounds, solids to its layer */
782 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
784 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
786 badguy->activate(LEFT);
788 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
791 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
792 foregrounds = tilemap;
793 else if(tilemap->get_layer() == LAYER_TILES)
795 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
796 backgrounds = tilemap;
802 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
803 sector->add_object(tilemap);
804 sector->update_game_objects();
808 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
809 sector->add_object(tilemap);
810 sector->update_game_objects();
814 sprintf(str, "%i", solids->get_width());
815 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
816 sprintf(str, "%i", solids->get_height());
817 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
820 void LevelEditor::save_level()
822 level->save(level_filename);
823 level_changed = false;
826 void LevelEditor::test_level()
830 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
836 GameSession session(level_filename, ST_GL_TEST);
838 // player_status.reset();
839 sound_manager->halt_music();
842 void LevelEditor::change(int x, int y, int newtile, int layer)
843 { // find the tilemap of the current layer, and then change the tile
844 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
845 y < 0 || (unsigned int)y > sector->solids->get_height()*32)
848 level_changed = true;
851 { // no need to do this for normal view (no zoom)
852 x = (int)(x * (zoom*32) / 32);
853 y = (int)(y * (zoom*32) / 32);
856 if(newtile < 0) // add object
858 // remove an active tile or object that might be there
859 change(x, y, 0, LAYER_TILES);
861 if(newtile == OBJ_TRAMPOLINE)
862 sector->add_object(new Trampoline(x, y));
863 else if(newtile == OBJ_FLYING_PLATFORM)
864 sector->add_object(new FlyingPlatform(x, y));
865 else if(newtile == OBJ_DOOR)
866 sector->add_object(new Door(x, y));
868 sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
870 sector->update_game_objects();
872 else if(cur_layer == LAYER_FOREGROUNDTILES)
873 foregrounds->change(x/32, y/32, newtile);
874 else if(cur_layer == LAYER_TILES)
876 // remove a bad guy if it's there
877 // we /32 in order to round numbers
878 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
880 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
882 if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
883 sector->gameobjects.erase(i);
884 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
887 if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
888 sector->gameobjects.erase(i);
890 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
892 if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
893 sector->gameobjects.erase(i);
894 Door* door = dynamic_cast<Door*> (*i);
896 if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
897 sector->gameobjects.erase(i);
899 sector->update_game_objects();
900 solids->change(x/32, y/32, newtile);
902 else if(cur_layer == LAYER_BACKGROUNDTILES)
903 backgrounds->change(x/32, y/32, newtile);
906 void LevelEditor::show_help()
908 DrawingContext context;
910 bool show_grid_t = show_grid;
912 mouse_cursor->set_state(MC_HIDE);
917 _("This is the built-in level editor. It's aim is to be intuitive\n"
918 "and simple to use, so it should be pretty straight forward.\n"
920 "To open a level, first you'll have to select a level subset from\n"
921 "the menu (or create your own).\n"
922 "A level subset is basically a collection of levels.\n"
923 "They can then be played from the Contrib menu.\n"
925 "To access the menu from the level editor, just press Esc.\n"
927 "You are currently looking to the level, to scroll it, just\n"
928 "press the right mouse button and drag the mouse. It will move like\n"
930 "You can also use the arrow keys and Page Up/Down.\n"
932 "'+' and '-' keys can be used to zoom in/out the level.\n"
934 "You probably already noticed those floating group of buttons.\n"
935 "Each one serves a different purpose. To select a certain button\n"
936 "just press the Left mouse button on it. A few buttons have key\n"
937 "shortcuts, you can know it by pressing the Right mouse button on\n"
938 "it. That will also show what that button does.\n"
939 "Group of buttons can also be move around by just dragging them,\n"
940 "while pressing the Left mouse button.\n"
942 "Let's learn a bit of what each group of buttons do, shall we?\n"
944 "To starting putting tiles and objects around use the bigger gropup\n"
945 "of buttons. Each button is a different tile. To put it on the level,\n"
946 "just press it and then left click in the level.\n"
947 "You can also copy tiles from the level by using the middle mouse button.\n"
948 "Use the mouse wheel to scroll that group of buttons. You will find\n"
949 "enemies and game objects in the bottom.\n")
953 _("The Foreground/Interactive/Background buttons may be used to\n"
954 "see and edit the respective layer. Level's have three tiles layers:\n"
955 "Foreground - tiles are drawn in top of everything and have no contact\n"
957 "Interactive - these are the tiles that have contact with the player.\n"
958 "Background - tiles are drawn in bottom of everything and have no contact\n"
960 "The unselected layers will be drawn semi-transparently.\n"
962 "At last, but not least, the group of buttons that's left serves\n"
963 "to do related actions with the level.\n"
964 "From left to right:\n"
965 "Mini arrows - can be used to choose other sectors.\n"
966 "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
967 "Big arrows - choose other level in the same level subset.\n"
968 "Diskette - save the level\n"
969 "Tux - test the level\n"
970 "Tools - set a few settings for the level, incluiding resizing it.\n"
972 "We have reached the end of this Howto.\n"
974 "Don't forget to send us a few cool levels. :)\n"
977 " SuperTux development team\n"
979 "ps: If you are looking for something more powerfull, you can give it a\n"
980 "try to FlexLay. FlexLay is a level editor that supports several games,\n"
981 "including SuperTux. It is an independent project.\n"
982 "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
985 char **text[] = { text1, text2 };
989 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
993 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
995 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
997 sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
998 context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
1000 context.do_drawing();
1006 done = wait_for_event(event);
1011 show_grid = show_grid_t;
1012 mouse_cursor->set_state(MC_NORMAL);