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 ***************************************************************************/
23 #include "gui/mousecursor.h"
25 #include "gui/button.h"
26 #include "audio/sound_manager.h"
27 #include "app/gettext.h"
28 #include "app/setup.h"
29 #include "app/globals.h"
30 #include "special/sprite.h"
31 #include "leveleditor.h"
32 #include "resources.h"
35 #include "tile_manager.h"
37 #include "background.h"
42 LevelEditor::LevelEditor()
47 global_frame_counter = 0;
48 selection_end = selection_ini = Vector(0,0);
49 left_button = middle_button = mouse_moved = 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)
66 subset_menu->additem(MN_ACTION, (*it),0,0,i);
67 subset_menu->additem(MN_HL,"",0,0);
68 subset_menu->additem(MN_BACK,_("Back"),0,0);
70 create_subset_menu = new Menu();
71 create_subset_menu->additem(MN_LABEL,_("New Level Subset"),0,0);
72 create_subset_menu->additem(MN_HL,"",0,0);
73 create_subset_menu->additem(MN_TEXTFIELD,_("Filename "),0,0,MN_ID_FILENAME_SUBSET);
74 create_subset_menu->additem(MN_TEXTFIELD,_("Title "),0,0,MN_ID_TITLE_SUBSET);
75 create_subset_menu->additem(MN_TEXTFIELD,_("Description"),0,0,MN_ID_DESCRIPTION_SUBSET);
76 create_subset_menu->additem(MN_ACTION,_("Create"),0,0, MN_ID_CREATE_SUBSET);
77 create_subset_menu->additem(MN_HL,"",0,0);
78 create_subset_menu->additem(MN_BACK,_("Back"),0,0);
80 main_menu = new Menu();
81 main_menu->additem(MN_LABEL,_("Level Editor Menu"),0,0);
82 main_menu->additem(MN_HL,"",0,0);
83 main_menu->additem(MN_ACTION,_("Return to Level Editor"),0,0,MN_ID_RETURN);
84 main_menu->additem(MN_GOTO,_("Create Level Subset"),0,create_subset_menu);
85 main_menu->additem(MN_GOTO,_("Load Level Subset"),0,subset_menu);
86 main_menu->additem(MN_HL,"",0,0);
87 main_menu->additem(MN_ACTION,_("Quit Level Editor"),0,0,MN_ID_QUIT);
89 settings_menu = new Menu();
90 settings_menu->additem(MN_LABEL,_("Level Settings"),0,0);
91 settings_menu->additem(MN_HL,"",0,0);
92 settings_menu->additem(MN_TEXTFIELD,_("Name "),0,0,MN_ID_NAME);
93 settings_menu->additem(MN_TEXTFIELD,_("Author "),0,0,MN_ID_AUTHOR);
94 settings_menu->additem(MN_NUMFIELD, _("Width "),0,0,MN_ID_WIDTH);
95 settings_menu->additem(MN_NUMFIELD, _("Height "),0,0,MN_ID_HEIGHT);
96 settings_menu->additem(MN_HL,"",0,0);
97 settings_menu->additem(MN_ACTION,_("Apply"),0,0,MN_ID_APPLY_SETTINGS);
99 /* Creating button groups */
102 tiles_board = new ButtonGroup(Vector(screen->w - 140, 100),
103 Vector(32,32), Vector(4,8));
105 TileManager* tilemanager = TileManager::instance();
107 tiles_board->add_button(Button(img_rubber_bt, _("Eraser"), SDLKey(SDLK_DELETE)), 0);
108 for(unsigned int id = 1; id < tilemanager->get_max_tileid(); id++)
110 const Tile* tile = tilemanager->get(id);
115 if(tile->editor_images.size())
116 surface = tile->editor_images[0];
117 else if(tile->images.size())
118 surface = tile->images[0];
122 Button button = Button(surface, "", SDLKey(0));
123 tiles_board->add_button(button, id);
127 for(int i = 0; i < NUM_BadGuyKinds; i++)
129 // filter bomb, since it is only for internal use, not for levels
133 BadGuyKind kind = BadGuyKind(i);
134 BadGuy badguy(kind, 0,0);
135 badguy.activate(LEFT);
137 Surface *img = badguy.get_image();
138 tiles_board->add_button(Button(img, "", SDLKey(SDLK_1+i)), -(i+1));
143 tiles_board->add_button(Button(img_trampoline[0].get_frame(0), _("Trampoline"), SDLKey(0)), OBJ_TRAMPOLINE);
144 tiles_board->add_button(Button(img_flying_platform->get_frame(0), _("Flying Platform"), SDLKey(0)), OBJ_FLYING_PLATFORM);
147 tiles_layer = new ButtonGroup(Vector(12, screen->h-64), Vector(80,20), Vector(1,3));
148 tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
149 SDLK_F10), LAYER_FOREGROUNDTILES);
150 tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
151 SDLK_F11), LAYER_TILES, true);
152 tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
153 SDLK_F12), LAYER_BACKGROUNDTILES);
155 level_options = new ButtonGroup(Vector(screen->w-164, screen->h-36), Vector(32,32), Vector(5,1));
156 level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
157 Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
158 level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
159 Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
160 level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
161 level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
162 level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
165 LevelEditor::~LevelEditor()
171 delete level_options;
174 delete create_subset_menu;
176 delete settings_menu;
182 void LevelEditor::load_buttons_gfx()
184 img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
185 img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
186 img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
188 img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
189 img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
190 img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
192 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
194 img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
195 img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
196 img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
197 img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
200 void LevelEditor::free_buttons_gfx()
202 delete img_foreground_bt;
203 delete img_interactive_bt;
204 delete img_background_bt;
206 delete img_save_level_bt;
207 delete img_test_level_bt;
208 delete img_setup_level_bt;
210 delete img_rubber_bt;
212 delete img_previous_level_bt;
213 delete img_next_level_bt;
214 delete img_previous_sector_bt;
215 delete img_next_sector_bt;
218 void LevelEditor::run(const std::string filename)
220 SoundManager::get()->halt_music();
221 Menu::set_current(0);
223 DrawingContext context;
225 if(!filename.empty())
228 load_level(filename);
231 Menu::set_current(main_menu);
233 mouse_cursor->set_state(MC_NORMAL);
235 frame_timer.start(.25, true);
245 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
249 void LevelEditor::events()
253 while(SDL_PollEvent(&event))
255 Menu* menu = Menu::current();
260 if(menu == main_menu)
262 switch (main_menu->check())
265 Menu::set_current(0);
272 else if(menu == create_subset_menu)
274 // activate or deactivate Create button if any filename as been specified
275 if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
276 create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
278 create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_ACTION;
280 if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
281 { // applying settings:
282 std::string subset_name = create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input;
283 LevelSubset::create(subset_name);
286 level_subset = new LevelSubset();
287 level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
289 level_subset->title = create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).input;
290 level_subset->description = create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).input;
291 //FIXME: generate better level filenames
292 level_subset->add_level(subset_name+'/'+"new_level.stl");
293 Level::create(level_subset->get_level_filename(0));
294 level_subset->save();
298 create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
299 create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
300 create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
303 else if(menu == subset_menu)
305 int i = subset_menu->check();
308 std::set<std::string>::iterator it = level_subsets.begin();
309 for(int t = 0; t < i; t++)
311 load_level_subset(*it);
312 Menu::set_current(0);
315 else if(menu == settings_menu)
317 if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
318 { // applying settings:
319 level_changed = true;
321 level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
322 level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
324 solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
325 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
326 foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
327 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
328 backgrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
329 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
331 Menu::set_current(0);
335 // check for events in buttons
336 else if(tiles_board->event(event))
338 std::vector <int> vector;
339 vector.push_back(tiles_board->selected_id());
342 selection.push_back(vector);
345 else if(tiles_layer->event(event))
347 cur_layer = tiles_layer->selected_id();
350 else if(level_options->event(event))
352 switch(level_options->selected_id())
361 Menu::set_current(settings_menu);
364 if(level_nb + 1 < level_subset->get_num_levels())
365 load_level(level_nb + 1);
369 sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 2);
370 if(confirm_dialog(NULL, str))
372 level_subset->add_level("new_level.stl");
373 Level::create(level_subset->get_level_filename(level_nb + 1));
374 level_subset->save();
375 load_level(level_nb + 1);
379 case BT_PREVIOUS_LEVEL:
380 if(level_nb - 1 >= 0)
381 load_level(level_nb - 1);
384 std::cerr << "next sector.\n";
385 std::cerr << "total sectors: " << level->get_total_sectors() << std::endl;
386 load_sector(level->get_next_sector(sector));
388 case BT_PREVIOUS_SECTOR:
389 std::cerr << "previous sector.\n";
390 load_sector(level->get_previous_sector(sector));
393 level_options->set_unselected();
400 case SDL_MOUSEMOTION:
402 if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
403 { // movement like in strategy games
404 scroll.x += -1 * event.motion.xrel;
405 scroll.y += -1 * event.motion.yrel;
409 case SDL_MOUSEBUTTONDOWN:
411 if(event.button.button == SDL_BUTTON_LEFT)
413 else if(event.button.button == SDL_BUTTON_MIDDLE)
415 middle_button = true;
416 selection_ini = Vector(event.button.x, event.button.y);
420 case SDL_MOUSEBUTTONUP:
422 if(event.button.button == SDL_BUTTON_LEFT)
424 else if(event.button.button == SDL_BUTTON_MIDDLE)
426 middle_button = false;
427 selection_end = Vector(event.button.x, event.button.y);
429 if(selection_end.x < selection_ini.x)
431 float t = selection_ini.x;
432 selection_ini.x = selection_end.x;
435 if(selection_end.y < selection_ini.y)
437 float t = selection_ini.y;
438 selection_ini.y = selection_end.y;
443 std::vector <int> vector;
445 TileMap* tilemap = 0;
446 if(cur_layer == LAYER_FOREGROUNDTILES)
447 tilemap = foregrounds;
448 else if(cur_layer == LAYER_TILES)
450 else if(cur_layer == LAYER_BACKGROUNDTILES)
451 tilemap = backgrounds;
453 for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
456 for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
458 vector.push_back(tilemap->get_tile(x +
459 (int)(((selection_ini.x+scroll.x)*zoom)/32),
460 y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->id);
462 selection.push_back(vector);
467 case SDL_KEYDOWN: // key pressed
468 switch(event.key.keysym.sym)
471 Menu::set_current(main_menu);
473 /* scrolling related events: */
478 scroll.x = sector->solids->get_height()*32 - screen->w;
511 show_grid = !show_grid;
518 case SDL_QUIT: // window closed
529 void LevelEditor::action()
531 mouse_cursor->set_state(MC_NORMAL);
532 if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
533 mouse_cursor->set_state(MC_LINK);
537 if(frame_timer.check()) {
538 ++global_frame_counter;
541 // don't scroll before the start or after the level's end
542 float width = sector->solids->get_width() * 32;
543 float height = sector->solids->get_height() * 32;
545 if(scroll.x < -screen->w/2)
546 scroll.x = -screen->w/2;
547 if(scroll.x > width - screen->w/2)
548 scroll.x = width - screen->w/2;
549 if(scroll.y < -screen->h/2)
550 scroll.y = -screen->h/2;
551 if(scroll.y > height - screen->h/2)
552 scroll.y = height - screen->h/2;
554 // set camera translation, since BadGuys like it
555 sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
557 if(left_button && mouse_moved)
558 for(unsigned int x = 0; x < selection.size(); x++)
559 for(unsigned int y = 0; y < selection[x].size(); y++)
560 change((int)(scroll.x + event.button.x) + (x*32),
561 (int)(scroll.y + event.button.y) + (y*32), selection[x][y],
566 #define FADING_TIME .6
568 void LevelEditor::draw(DrawingContext& context)
570 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
571 mouse_cursor->draw(context);
573 // draw a filled background
574 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
576 if(level_name_timer.check())
578 context.push_transform();
579 if(level_name_timer.get_timeleft() < FADING_TIME)
580 context.set_alpha(int(level_name_timer.get_timeleft() * 255 / FADING_TIME));
582 context.draw_text(gold_text, level->name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
586 sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
587 context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
590 context.pop_transform();
593 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
595 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
597 Menu* menu = Menu::current();
602 tiles_board->draw(context);
603 tiles_layer->draw(context);
604 level_options->draw(context);
612 context.set_drawing_effect(SEMI_TRANSPARENT);
616 if(selection[0][0] == 0 && selection.size() == 1)
617 context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
618 event.button.y - 8), LAYER_GUI-2);
619 else if(selection[0][0] < 0)
621 int id = selection[0][0];
624 if(id == OBJ_TRAMPOLINE)
625 context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
626 event.button.y - 8), LAYER_GUI-2);
627 else if(id == OBJ_FLYING_PLATFORM)
628 context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
629 event.button.y - 8), LAYER_GUI-2);
633 /*context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
634 event.button.y - 8), LAYER_GUI-2);*/
639 BadGuyKind kind = BadGuyKind((-id)-1);
640 BadGuy badguy(kind, 0,0);
641 badguy.activate(LEFT);
642 Surface *img = badguy.get_image();
644 context.draw_surface(img, Vector(event.button.x - 8,
645 event.button.y - 8), LAYER_GUI-2);
651 TileManager* tilemanager = TileManager::instance();
652 for(unsigned int x = 0; x < selection.size(); x++)
653 for(unsigned int y = 0; y < selection[x].size(); y++) {
654 const Tile* tile = tilemanager->get(selection[x][y]);
656 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
661 context.set_drawing_effect(NONE_EFFECT);
664 context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
665 std::min((int)selection_ini.y, (int)event.button.y))*zoom,
666 Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
667 abs(event.button.y - (int)selection_ini.y)*zoom),
668 Color(170,255,170,128), LAYER_GUI-2);
672 for(int x = 0; x < screen->w / (32*zoom); x++)
674 int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
675 context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
676 Color(225, 225, 225), LAYER_GUI-50);
678 for(int y = 0; y < screen->h / (32*zoom); y++)
680 int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
681 context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
682 Color(225, 225, 225), LAYER_GUI-50);
686 context.push_transform();
687 context.set_translation(scroll);
688 context.set_zooming(zoom);
690 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
692 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
694 { // draw the non-selected tiles semi-transparently
695 context.push_transform();
697 if(tilemap->get_layer() != cur_layer)
698 context.set_drawing_effect(SEMI_TRANSPARENT);
701 context.pop_transform();
704 Background* background = dynamic_cast<Background*> (*i);
706 { // don't resize background
707 context.push_transform();
708 context.set_zooming(1.0);
710 context.pop_transform();
716 context.pop_transform();
719 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
721 context.do_drawing();
724 void LevelEditor::load_level_subset(std::string filename)
727 level_subset = new LevelSubset();
728 level_subset->load(filename.c_str());
732 void LevelEditor::load_level(std::string filename)
736 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
742 level_filename = filename;
746 level->load(filename);
749 level_name_timer.start(3000);
750 scroll.x = scroll.y = 0;
751 level_changed = false;
753 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
754 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
757 void LevelEditor::load_level(int nb)
761 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
768 level_filename = level_subset->get_level_filename(level_nb);
770 load_level(level_filename);
773 void LevelEditor::load_sector(std::string name)
776 sector = level->get_sector(sector_name);
778 Termination::abort("Level has no " + sector_name + " sector.", "");
783 void LevelEditor::load_sector(Sector* sector_)
787 if(!confirm_dialog(NULL, _("No more sectors exist. Create another?")))
789 sector_ = Sector::create("new_sector",25,19);
790 level->add_sector(sector_);
795 /* Load sector stuff */
797 sector->update_game_objects();
799 foregrounds = solids = backgrounds = 0;
800 /* Point foregrounds, backgrounds, solids to its layer */
801 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
804 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
806 badguy->activate(LEFT);
809 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
812 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
813 foregrounds = tilemap;
814 else if(tilemap->get_layer() == LAYER_TILES)
816 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
817 backgrounds = tilemap;
823 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
824 sector->add_object(tilemap);
825 sector->update_game_objects();
829 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
830 sector->add_object(tilemap);
831 sector->update_game_objects();
835 sprintf(str, "%i", solids->get_width());
836 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
837 sprintf(str, "%i", solids->get_height());
838 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
841 void LevelEditor::save_level()
843 level->save(level_filename);
844 level_changed = false;
847 void LevelEditor::test_level()
850 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
856 GameSession session(level_filename, ST_GL_TEST);
858 // player_status.reset();
859 SoundManager::get()->halt_music();
862 void LevelEditor::change(int x, int y, int newtile, int layer)
864 // find the tilemap of the current layer, and then change the tile
865 if(x < 0 || (unsigned int)x >= sector->solids->get_width()*32 ||
866 y < 0 || (unsigned int)y >= sector->solids->get_height()*32)
869 level_changed = true;
872 { // no need to do this for normal view (no zoom)
873 x = (int)(x * (zoom*32) / 32);
874 y = (int)(y * (zoom*32) / 32);
877 if(newtile < 0) // add object
879 // remove an active tile or object that might be there
880 change(x, y, 0, LAYER_TILES);
883 if(newtile == OBJ_TRAMPOLINE)
884 sector->add_object(new Trampoline(x, y));
885 else if(newtile == OBJ_FLYING_PLATFORM)
886 sector->add_object(new FlyingPlatform(x, y));
888 if(newtile == OBJ_DOOR)
889 sector->add_object(new Door(x, y));
891 sector->add_bad_guy(x, y, BadGuyKind((-newtile)-1), true);
894 sector->update_game_objects();
895 } else if(cur_layer == LAYER_FOREGROUNDTILES) {
896 foregrounds->change(x/32, y/32, newtile);
897 } else if(cur_layer == LAYER_TILES) {
898 // remove a bad guy if it's there
899 // we /32 in order to round numbers
900 for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
901 i < sector->gameobjects.end(); i++) {
903 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
905 if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
906 sector->gameobjects.erase(i);
909 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
912 if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
913 sector->gameobjects.erase(i);
915 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
917 if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
918 sector->gameobjects.erase(i);
921 Door* door = dynamic_cast<Door*> (*i);
923 if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
924 sector->gameobjects.erase(i);
927 sector->update_game_objects();
928 solids->change(x/32, y/32, newtile);
929 } else if(cur_layer == LAYER_BACKGROUNDTILES)
930 backgrounds->change(x/32, y/32, newtile);
933 void LevelEditor::show_help()
935 DrawingContext context;
937 bool show_grid_t = show_grid;
939 mouse_cursor->set_state(MC_HIDE);
944 _("This is the built-in level editor. Its aim is to be intuitive\n"
945 "and simple to use, so it should be pretty straightforward.\n"
947 "To open a level, first you'll have to select a level subset from\n"
948 "the menu (or create your own).\n"
949 "A level subset is basically a collection of levels.\n"
950 "They can then be played from the Contrib menu.\n"
952 "To access the menu from the level editor, just press Esc.\n"
954 "You are currently looking at the level. To scroll it, just\n"
955 "press the right mouse button and drag the mouse. It will move like\n"
957 "You can also use the arrow keys and Page Up/Down.\n"
959 "'+' and '-' keys can be used to zoom the level in/out.\n"
961 "You probably already noticed those floating groups of buttons.\n"
962 "Each one serves a different purpose. To select a certain button\n"
963 "just press the Left mouse button on it. A few buttons have key\n"
964 "shortcuts. You can find them by pressing the Right mouse button on\n"
965 "a button. That will also show what that button does.\n"
966 "Groups of buttons can also be moved around by just dragging them,\n"
967 "while pressing the Left mouse button.\n"
969 "Let's learn a bit of what each group of buttons does, shall we?\n"
971 "To starting putting tiles and objects around use the bigger group\n"
972 "of buttons. Each button is a different tile. To put it on the level,\n"
973 "just press it and then left click in the level.\n"
974 "You can also copy tiles from the level by using the middle mouse button.\n"
975 "Use the mouse wheel to scroll that group of buttons. You will find\n"
976 "enemies and game objects in the bottom.\n")
980 _("The Foreground/Interactive/Background buttons may be used to\n"
981 "see and edit the respective layer. Levels have three tiles layers:\n"
982 "Foreground - tiles are drawn on top of everything and have no contact\n"
984 "Interactive - these are the tiles that have contact with the player.\n"
985 "Background - tiles are drawn underneath everything and have no contact\n"
987 "The unselected layers will be drawn semi-transparently.\n"
989 "Last, but not least, the group of buttons that's left serves\n"
990 "to do related actions with the level.\n"
991 "From left to right:\n"
992 "Mini arrows - can be used to choose other sectors.\n"
993 "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
994 "Big arrows - choose other level in the same level subset.\n"
995 "Diskette - save the level\n"
996 "Tux - test the level\n"
997 "Tools - set a few settings for the level, including resizing it.\n"
999 "We have reached the end of this Howto.\n"
1001 "Don't forget to send us a few cool levels. :)\n"
1004 " SuperTux development team\n"
1006 "PS: If you are looking for something more powerful, you might like to\n"
1007 "try FlexLay. FlexLay is a level editor that supports several games,\n"
1008 "including SuperTux. It is an independent project.\n"
1009 "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
1012 char **text[] = { text1, text2 };
1016 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
1020 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
1022 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
1024 sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
1025 context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
1027 context.do_drawing();
1033 done = wait_for_event(event);
1038 show_grid = show_grid_t;
1039 mouse_cursor->set_state(MC_NORMAL);