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 // 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));
141 tiles_board->add_button(Button(img_trampoline[0].get_frame(0), _("Trampoline"), SDLKey(0)), OBJ_TRAMPOLINE);
142 tiles_board->add_button(Button(img_flying_platform->get_frame(0), _("Flying Platform"), SDLKey(0)), OBJ_FLYING_PLATFORM);
143 tiles_board->add_button(Button(door->get_frame(0), _("Door"), SDLKey(0)), OBJ_DOOR);
145 tiles_layer = new ButtonGroup(Vector(12, screen->h-64), Vector(80,20), Vector(1,3));
146 tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
147 SDLK_F10), LAYER_FOREGROUNDTILES);
148 tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
149 SDLK_F11), LAYER_TILES, true);
150 tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
151 SDLK_F12), LAYER_BACKGROUNDTILES);
153 level_options = new ButtonGroup(Vector(screen->w-164, screen->h-36), Vector(32,32), Vector(5,1));
154 level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
155 Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
156 level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
157 Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
158 level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
159 level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
160 level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
163 LevelEditor::~LevelEditor()
169 delete level_options;
172 delete create_subset_menu;
174 delete settings_menu;
180 void LevelEditor::load_buttons_gfx()
182 img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
183 img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
184 img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
186 img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
187 img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
188 img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
190 img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
192 img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
193 img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
194 img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
195 img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
198 void LevelEditor::free_buttons_gfx()
200 delete img_foreground_bt;
201 delete img_interactive_bt;
202 delete img_background_bt;
204 delete img_save_level_bt;
205 delete img_test_level_bt;
206 delete img_setup_level_bt;
208 delete img_rubber_bt;
210 delete img_previous_level_bt;
211 delete img_next_level_bt;
212 delete img_previous_sector_bt;
213 delete img_next_sector_bt;
216 void LevelEditor::run(const std::string filename)
218 SoundManager::get()->halt_music();
219 Menu::set_current(0);
221 DrawingContext context;
223 if(!filename.empty())
226 load_level(filename);
229 Menu::set_current(main_menu);
231 mouse_cursor->set_state(MC_NORMAL);
242 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
246 void LevelEditor::events()
250 while(SDL_PollEvent(&event))
252 Menu* menu = Menu::current();
257 if(menu == main_menu)
259 switch (main_menu->check())
262 Menu::set_current(0);
269 else if(menu == create_subset_menu)
271 // activate or deactivate Create button if any filename as been specified
272 if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
273 create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
275 create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_ACTION;
277 if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
278 { // applying settings:
279 LevelSubset::create(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
282 level_subset = new LevelSubset();
283 level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
285 level_subset->title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
286 level_subset->description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
290 create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
291 create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
292 create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
295 else if(menu == subset_menu)
297 int i = subset_menu->check();
300 std::set<std::string>::iterator it = level_subsets.begin();
301 for(int t = 0; t < i; t++)
303 load_level_subset(*it);
304 Menu::set_current(0);
307 else if(menu == settings_menu)
309 if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
310 { // applying settings:
311 level_changed = true;
313 level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
314 level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
316 solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
317 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
318 foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
319 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
320 backgrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
321 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
323 Menu::set_current(0);
327 // check for events in buttons
328 else if(tiles_board->event(event))
330 std::vector <int> vector;
331 vector.push_back(tiles_board->selected_id());
334 selection.push_back(vector);
337 else if(tiles_layer->event(event))
339 cur_layer = tiles_layer->selected_id();
342 else if(level_options->event(event))
344 switch(level_options->selected_id())
353 Menu::set_current(settings_menu);
356 if(level_nb+1 < level_subset->get_num_levels())
357 load_level(level_nb + 1);
361 sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 1);
362 if(confirm_dialog(NULL, str))
365 level_subset->add_level("new_level.stl");
366 new_lev.save(level_subset->get_level_filename(level_nb + 1));
367 load_level(level_nb);
371 case BT_PREVIOUS_LEVEL:
373 load_level(level_nb - 1);
376 std::cerr << "next sector.\n";
377 std::cerr << "total sectors: " << level->get_total_sectors() << std::endl;
378 load_sector(level->get_next_sector(sector));
380 case BT_PREVIOUS_SECTOR:
381 std::cerr << "previous sector.\n";
382 load_sector(level->get_previous_sector(sector));
385 level_options->set_unselected();
392 case SDL_MOUSEMOTION:
394 if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
395 { // movement like in strategy games
396 scroll.x += -1 * event.motion.xrel;
397 scroll.y += -1 * event.motion.yrel;
401 case SDL_MOUSEBUTTONDOWN:
403 if(event.button.button == SDL_BUTTON_LEFT)
405 else if(event.button.button == SDL_BUTTON_MIDDLE)
407 middle_button = true;
408 selection_ini = Vector(event.button.x, event.button.y);
412 case SDL_MOUSEBUTTONUP:
414 if(event.button.button == SDL_BUTTON_LEFT)
416 else if(event.button.button == SDL_BUTTON_MIDDLE)
418 middle_button = false;
419 selection_end = Vector(event.button.x, event.button.y);
421 if(selection_end.x < selection_ini.x)
423 float t = selection_ini.x;
424 selection_ini.x = selection_end.x;
427 if(selection_end.y < selection_ini.y)
429 float t = selection_ini.y;
430 selection_ini.y = selection_end.y;
435 std::vector <int> vector;
437 TileMap* tilemap = 0;
438 if(cur_layer == LAYER_FOREGROUNDTILES)
439 tilemap = foregrounds;
440 else if(cur_layer == LAYER_TILES)
442 else if(cur_layer == LAYER_BACKGROUNDTILES)
443 tilemap = backgrounds;
445 for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
448 for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
450 vector.push_back(tilemap->get_tile(x +
451 (int)(((selection_ini.x+scroll.x)*zoom)/32),
452 y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->id);
454 selection.push_back(vector);
459 case SDL_KEYDOWN: // key pressed
460 switch(event.key.keysym.sym)
463 Menu::set_current(main_menu);
465 /* scrolling related events: */
470 scroll.x = sector->solids->get_height()*32 - screen->w;
503 show_grid = !show_grid;
510 case SDL_QUIT: // window closed
521 void LevelEditor::action()
523 mouse_cursor->set_state(MC_NORMAL);
524 if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
525 mouse_cursor->set_state(MC_LINK);
529 if(!frame_timer.check())
531 frame_timer.start(25);
532 ++global_frame_counter;
535 // don't scroll before the start or after the level's end
536 float width = sector->solids->get_width() * 32;
537 float height = sector->solids->get_height() * 32;
539 if(scroll.x < -screen->w/2)
540 scroll.x = -screen->w/2;
541 if(scroll.x > width - screen->w/2)
542 scroll.x = width - screen->w/2;
543 if(scroll.y < -screen->h/2)
544 scroll.y = -screen->h/2;
545 if(scroll.y > height - screen->h/2)
546 scroll.y = height - screen->h/2;
548 // set camera translation, since BadGuys like it
549 sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
551 if(left_button && mouse_moved)
552 for(unsigned int x = 0; x < selection.size(); x++)
553 for(unsigned int y = 0; y < selection[x].size(); y++)
554 change((int)(scroll.x + event.button.x) + (x*32),
555 (int)(scroll.y + event.button.y) + (y*32), selection[x][y],
560 #define FADING_TIME 600
562 void LevelEditor::draw(DrawingContext& context)
564 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
565 mouse_cursor->draw(context);
567 // draw a filled background
568 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
570 if(level_name_timer.check())
572 context.push_transform();
573 if(level_name_timer.get_left() < FADING_TIME)
574 context.set_alpha(level_name_timer.get_left() * 255 / FADING_TIME);
576 context.draw_text(gold_text, level->name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
580 sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
581 context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
584 context.pop_transform();
587 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
589 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
591 Menu* menu = Menu::current();
596 tiles_board->draw(context);
597 tiles_layer->draw(context);
598 level_options->draw(context);
606 context.set_drawing_effect(SEMI_TRANSPARENT);
610 if(selection[0][0] == 0 && selection.size() == 1)
611 context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
612 event.button.y - 8), LAYER_GUI-2);
613 else if(selection[0][0] < 0)
615 int id = selection[0][0];
617 if(id == OBJ_TRAMPOLINE)
618 context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
619 event.button.y - 8), LAYER_GUI-2);
620 else if(id == OBJ_FLYING_PLATFORM)
621 context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
622 event.button.y - 8), LAYER_GUI-2);
623 else if(id == OBJ_DOOR)
624 context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
625 event.button.y - 8), LAYER_GUI-2);
628 BadGuyKind kind = BadGuyKind((-id)-1);
629 BadGuy badguy(kind, 0,0);
630 badguy.activate(LEFT);
631 Surface *img = badguy.get_image();
633 context.draw_surface(img, Vector(event.button.x - 8,
634 event.button.y - 8), LAYER_GUI-2);
639 TileManager* tilemanager = TileManager::instance();
640 for(unsigned int x = 0; x < selection.size(); x++)
641 for(unsigned int y = 0; y < selection[x].size(); y++)
642 tilemanager->draw_tile(context, selection[x][y],
643 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
647 context.set_drawing_effect(NONE_EFFECT);
650 context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
651 std::min((int)selection_ini.y, (int)event.button.y))*zoom,
652 Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
653 abs(event.button.y - (int)selection_ini.y)*zoom),
654 Color(170,255,170,128), LAYER_GUI-2);
658 for(int x = 0; x < screen->w / (32*zoom); x++)
660 int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
661 context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
662 Color(225, 225, 225), LAYER_GUI-50);
664 for(int y = 0; y < screen->h / (32*zoom); y++)
666 int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
667 context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
668 Color(225, 225, 225), LAYER_GUI-50);
672 context.push_transform();
673 context.set_translation(scroll);
674 context.set_zooming(zoom);
676 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
678 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
680 { // draw the non-selected tiles semi-transparently
681 context.push_transform();
683 if(tilemap->get_layer() != cur_layer)
684 context.set_drawing_effect(SEMI_TRANSPARENT);
687 context.pop_transform();
690 Background* background = dynamic_cast<Background*> (*i);
692 { // don't resize background
693 context.push_transform();
694 context.set_zooming(1.0);
696 context.pop_transform();
702 context.pop_transform();
705 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
707 context.do_drawing();
710 void LevelEditor::load_level_subset(std::string filename)
713 level_subset = new LevelSubset();
714 level_subset->load(filename.c_str());
718 void LevelEditor::load_level(std::string filename)
722 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
728 level_filename = filename;
732 level->load(filename);
735 level_name_timer.start(3000);
736 scroll.x = scroll.y = 0;
737 level_changed = false;
739 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
740 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
743 void LevelEditor::load_level(int nb)
747 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
754 level_filename = level_subset->get_level_filename(level_nb);
756 load_level(level_filename);
759 void LevelEditor::load_sector(std::string name)
762 sector = level->get_sector(sector_name);
764 Termination::abort("Level has no " + sector_name + " sector.", "");
769 void LevelEditor::load_sector(Sector* sector_)
773 if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
775 Sector* nsector = new Sector();
776 level->add_sector(nsector);
784 /* Load sector stuff */
786 sector->update_game_objects();
788 foregrounds = solids = backgrounds = 0;
789 /* Point foregrounds, backgrounds, solids to its layer */
790 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
792 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
794 badguy->activate(LEFT);
796 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
799 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
800 foregrounds = tilemap;
801 else if(tilemap->get_layer() == LAYER_TILES)
803 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
804 backgrounds = tilemap;
810 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
811 sector->add_object(tilemap);
812 sector->update_game_objects();
816 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
817 sector->add_object(tilemap);
818 sector->update_game_objects();
822 sprintf(str, "%i", solids->get_width());
823 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
824 sprintf(str, "%i", solids->get_height());
825 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
828 void LevelEditor::save_level()
830 level->save(level_filename);
831 level_changed = false;
834 void LevelEditor::test_level()
838 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
844 GameSession session(level_filename, ST_GL_TEST);
846 // player_status.reset();
848 sound_manager->halt_music();
851 void LevelEditor::change(int x, int y, int newtile, int layer)
852 { // find the tilemap of the current layer, and then change the tile
853 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
854 y < 0 || (unsigned int)y > sector->solids->get_height()*32)
857 level_changed = true;
860 { // no need to do this for normal view (no zoom)
861 x = (int)(x * (zoom*32) / 32);
862 y = (int)(y * (zoom*32) / 32);
865 if(newtile < 0) // add object
867 // remove an active tile or object that might be there
868 change(x, y, 0, LAYER_TILES);
870 if(newtile == OBJ_TRAMPOLINE)
871 sector->add_object(new Trampoline(x, y));
872 else if(newtile == OBJ_FLYING_PLATFORM)
873 sector->add_object(new FlyingPlatform(x, y));
874 else if(newtile == OBJ_DOOR)
875 sector->add_object(new Door(x, y));
877 sector->add_bad_guy(x, y, BadGuyKind((-newtile)-1), true);
879 sector->update_game_objects();
881 else if(cur_layer == LAYER_FOREGROUNDTILES)
882 foregrounds->change(x/32, y/32, newtile);
883 else if(cur_layer == LAYER_TILES)
885 // remove a bad guy if it's there
886 // we /32 in order to round numbers
887 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
889 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
891 if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
892 sector->gameobjects.erase(i);
893 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
896 if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
897 sector->gameobjects.erase(i);
899 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
901 if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
902 sector->gameobjects.erase(i);
903 Door* door = dynamic_cast<Door*> (*i);
905 if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
906 sector->gameobjects.erase(i);
908 sector->update_game_objects();
909 solids->change(x/32, y/32, newtile);
911 else if(cur_layer == LAYER_BACKGROUNDTILES)
912 backgrounds->change(x/32, y/32, newtile);
915 void LevelEditor::show_help()
917 DrawingContext context;
919 bool show_grid_t = show_grid;
921 mouse_cursor->set_state(MC_HIDE);
926 _("This is the built-in level editor. It's aim is to be intuitive\n"
927 "and simple to use, so it should be pretty straight forward.\n"
929 "To open a level, first you'll have to select a level subset from\n"
930 "the menu (or create your own).\n"
931 "A level subset is basically a collection of levels.\n"
932 "They can then be played from the Contrib menu.\n"
934 "To access the menu from the level editor, just press Esc.\n"
936 "You are currently looking to the level, to scroll it, just\n"
937 "press the right mouse button and drag the mouse. It will move like\n"
939 "You can also use the arrow keys and Page Up/Down.\n"
941 "'+' and '-' keys can be used to zoom in/out the level.\n"
943 "You probably already noticed those floating group of buttons.\n"
944 "Each one serves a different purpose. To select a certain button\n"
945 "just press the Left mouse button on it. A few buttons have key\n"
946 "shortcuts, you can know it by pressing the Right mouse button on\n"
947 "it. That will also show what that button does.\n"
948 "Group of buttons can also be move around by just dragging them,\n"
949 "while pressing the Left mouse button.\n"
951 "Let's learn a bit of what each group of buttons do, shall we?\n"
953 "To starting putting tiles and objects around use the bigger gropup\n"
954 "of buttons. Each button is a different tile. To put it on the level,\n"
955 "just press it and then left click in the level.\n"
956 "You can also copy tiles from the level by using the middle mouse button.\n"
957 "Use the mouse wheel to scroll that group of buttons. You will find\n"
958 "enemies and game objects in the bottom.\n")
962 _("The Foreground/Interactive/Background buttons may be used to\n"
963 "see and edit the respective layer. Level's have three tiles layers:\n"
964 "Foreground - tiles are drawn in top of everything and have no contact\n"
966 "Interactive - these are the tiles that have contact with the player.\n"
967 "Background - tiles are drawn in bottom of everything and have no contact\n"
969 "The unselected layers will be drawn semi-transparently.\n"
971 "At last, but not least, the group of buttons that's left serves\n"
972 "to do related actions with the level.\n"
973 "From left to right:\n"
974 "Mini arrows - can be used to choose other sectors.\n"
975 "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
976 "Big arrows - choose other level in the same level subset.\n"
977 "Diskette - save the level\n"
978 "Tux - test the level\n"
979 "Tools - set a few settings for the level, incluiding resizing it.\n"
981 "We have reached the end of this Howto.\n"
983 "Don't forget to send us a few cool levels. :)\n"
986 " SuperTux development team\n"
988 "ps: If you are looking for something more powerfull, you can give it a\n"
989 "try to FlexLay. FlexLay is a level editor that supports several games,\n"
990 "including SuperTux. It is an independent project.\n"
991 "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
994 char **text[] = { text1, text2 };
998 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
1002 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
1004 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
1006 sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
1007 context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
1009 context.do_drawing();
1015 done = wait_for_event(event);
1020 show_grid = show_grid_t;
1021 mouse_cursor->set_state(MC_NORMAL);