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;
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())
220 load_level(filename);
223 Menu::set_current(main_menu);
225 mouse_cursor->set_state(MC_NORMAL);
236 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
240 void LevelEditor::events()
244 while(SDL_PollEvent(&event))
246 Menu* menu = Menu::current();
251 if(menu == main_menu)
253 switch (main_menu->check())
256 Menu::set_current(0);
263 else if(menu == create_subset_menu)
265 if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
266 create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
267 else if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
268 { // applying settings:
269 LevelSubset::create(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
270 level_subset.load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
272 level_subset.title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
273 level_subset.description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
277 create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
278 create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
279 create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
282 else if(menu == subset_menu)
284 int i = subset_menu->check();
287 std::set<std::string>::iterator it = level_subsets.begin();
288 for(int t = 0; t < i; t++)
290 std::cerr << "load subset level_subsets " << i << ": " << (*it) << std::endl;
291 load_level_subset(*it);
292 Menu::set_current(0);
295 else if(menu == settings_menu)
297 if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
298 { // applying settings:
299 level_changed = true;
301 level.name = settings_menu->get_item_by_id(MN_ID_NAME).input;
302 level.author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
304 solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
305 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
306 foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
307 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
308 backgrounds->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()));
311 Menu::set_current(0);
315 // check for events in buttons
316 else if(tiles_board->event(event))
318 std::vector <int> vector;
319 vector.push_back(tiles_board->selected_id());
322 selection.push_back(vector);
325 else if(tiles_layer->event(event))
327 cur_layer = tiles_layer->selected_id();
330 else if(level_options->event(event))
332 switch(level_options->selected_id())
341 Menu::set_current(settings_menu);
344 if(level_nb+1 < level_subset.get_num_levels())
345 load_level(level_nb + 1);
350 sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 1);
351 if(confirm_dialog(NULL, str))
353 level_subset.add_level("new_level.stl");
354 new_lev.save(level_subset.get_level_filename(level_nb + 1));
355 load_level(level_nb);
359 case BT_PREVIOUS_LEVEL:
361 load_level(level_nb - 1);
364 std::cerr << "next sector.\n";
365 std::cerr << "total sectors: " << level.get_total_sectors() << std::endl;
366 load_sector(level.get_next_sector(sector));
368 case BT_PREVIOUS_SECTOR:
369 std::cerr << "previous sector.\n";
370 load_sector(level.get_previous_sector(sector));
373 level_options->set_unselected();
380 case SDL_MOUSEMOTION:
382 if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
383 { // movement like in strategy games
384 scroll.x += -1 * event.motion.xrel;
385 scroll.y += -1 * event.motion.yrel;
389 case SDL_MOUSEBUTTONDOWN:
391 if(event.button.button == SDL_BUTTON_LEFT)
393 else if(event.button.button == SDL_BUTTON_MIDDLE)
395 middle_button = true;
396 selection_ini = Vector(event.button.x, event.button.y);
400 case SDL_MOUSEBUTTONUP:
402 if(event.button.button == SDL_BUTTON_LEFT)
404 else if(event.button.button == SDL_BUTTON_MIDDLE)
406 middle_button = false;
407 selection_end = Vector(event.button.x, event.button.y);
409 if(selection_end.x < selection_ini.x)
411 float t = selection_ini.x;
412 selection_ini.x = selection_end.x;
415 if(selection_end.y < selection_ini.y)
417 float t = selection_ini.y;
418 selection_ini.y = selection_end.y;
423 std::vector <int> vector;
425 TileMap* tilemap = 0;
426 if(cur_layer == LAYER_FOREGROUNDTILES)
427 tilemap = foregrounds;
428 else if(cur_layer == LAYER_TILES)
430 else if(cur_layer == LAYER_BACKGROUNDTILES)
431 tilemap = backgrounds;
433 for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
436 for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
438 vector.push_back(tilemap->get_tile(x +
439 (int)(((selection_ini.x+scroll.x)*zoom)/32),
440 y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->id);
442 selection.push_back(vector);
447 case SDL_KEYDOWN: // key pressed
448 switch(event.key.keysym.sym)
451 Menu::set_current(main_menu);
453 /* scrolling related events: */
458 scroll.x = sector->solids->get_height()*32 - screen->w;
491 show_grid = !show_grid;
498 case SDL_QUIT: // window closed
509 void LevelEditor::action()
511 mouse_cursor->set_state(MC_NORMAL);
512 if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
513 mouse_cursor->set_state(MC_LINK);
517 if(!frame_timer.check())
519 frame_timer.start(25);
520 ++global_frame_counter;
523 // don't scroll before the start or after the level's end
524 float width = sector->solids->get_width() * 32;
525 float height = sector->solids->get_height() * 32;
527 if(scroll.x < -screen->w/2)
528 scroll.x = -screen->w/2;
529 if(scroll.x > width - screen->w/2)
530 scroll.x = width - screen->w/2;
531 if(scroll.y < -screen->h/2)
532 scroll.y = -screen->h/2;
533 if(scroll.y > height - screen->h/2)
534 scroll.y = height - screen->h/2;
536 // set camera translation, since BadGuys like it
537 sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
539 if(left_button && mouse_moved)
540 for(unsigned int x = 0; x < selection.size(); x++)
541 for(unsigned int y = 0; y < selection[x].size(); y++)
542 change((int)(scroll.x + event.button.x) + (x*32),
543 (int)(scroll.y + event.button.y) + (y*32), selection[x][y],
548 #define FADING_TIME 600
550 void LevelEditor::draw(DrawingContext& context)
552 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
553 mouse_cursor->draw(context);
555 // draw a filled background
556 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
558 if(level_name_timer.check())
560 context.push_transform();
561 if(level_name_timer.get_left() < FADING_TIME)
562 context.set_alpha(level_name_timer.get_left() * 255 / FADING_TIME);
564 context.draw_text(gold_text, level.name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
568 sprintf(str, "%i/%i", level_nb+1, level_subset.get_num_levels());
569 context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
572 context.pop_transform();
575 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
577 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
579 Menu* menu = Menu::current();
584 tiles_board->draw(context);
585 tiles_layer->draw(context);
586 level_options->draw(context);
594 context.set_drawing_effect(SEMI_TRANSPARENT);
598 if(selection[0][0] == 0 && selection.size() == 1)
599 context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
600 event.button.y - 8), LAYER_GUI-2);
601 else if(selection[0][0] < 0)
603 int id = selection[0][0];
605 if(id == OBJ_TRAMPOLINE)
606 context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
607 event.button.y - 8), LAYER_GUI-2);
608 else if(id == OBJ_FLYING_PLATFORM)
609 context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
610 event.button.y - 8), LAYER_GUI-2);
611 else if(id == OBJ_DOOR)
612 context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
613 event.button.y - 8), LAYER_GUI-2);
616 BadGuyKind kind = BadGuyKind((-id)-1);
617 BadGuy badguy(kind, 0,0);
618 badguy.activate(LEFT);
619 Surface *img = badguy.get_image();
621 context.draw_surface(img, Vector(event.button.x - 8,
622 event.button.y - 8), LAYER_GUI-2);
627 TileManager* tilemanager = TileManager::instance();
628 for(unsigned int x = 0; x < selection.size(); x++)
629 for(unsigned int y = 0; y < selection[x].size(); y++)
630 tilemanager->draw_tile(context, selection[x][y],
631 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
635 context.set_drawing_effect(NONE_EFFECT);
638 context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
639 std::min((int)selection_ini.y, (int)event.button.y))*zoom,
640 Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
641 abs(event.button.y - (int)selection_ini.y)*zoom),
642 Color(170,255,170,128), LAYER_GUI-2);
646 for(int x = 0; x < screen->w / (32*zoom); x++)
648 int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
649 context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
650 Color(225, 225, 225), LAYER_GUI-50);
652 for(int y = 0; y < screen->h / (32*zoom); y++)
654 int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
655 context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
656 Color(225, 225, 225), LAYER_GUI-50);
660 context.push_transform();
661 context.set_translation(scroll);
662 context.set_zooming(zoom);
664 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
666 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
668 { // draw the non-selected tiles semi-transparently
669 context.push_transform();
671 if(tilemap->get_layer() != cur_layer)
672 context.set_drawing_effect(SEMI_TRANSPARENT);
675 context.pop_transform();
677 Background* background = dynamic_cast<Background*> (*i);
679 { // don't resize background
680 context.push_transform();
681 context.set_translation(scroll);
682 context.set_zooming(1.0);
684 context.pop_transform();
690 context.pop_transform();
693 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
695 context.do_drawing();
698 void LevelEditor::load_level_subset(std::string filename)
700 std::cerr << "loading subset...\n";
701 std::cerr << "filename: " << filename << std::endl;
702 level_subset.load(filename.c_str());
706 void LevelEditor::load_level(std::string filename)
710 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
716 level_filename = filename;
717 level.load(filename);
720 level_name_timer.start(3000);
721 scroll.x = scroll.y = 0;
722 level_changed = false;
724 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level.name.c_str());
725 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level.author.c_str());
728 void LevelEditor::load_level(int nb)
732 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
739 std::cerr << "level_nb: " << level_nb << std::endl;
740 std::cerr << "level_subset.get_level_filename(level_nb): " << level_subset.get_level_filename(level_nb) << std::endl;
741 level_filename = level_subset.get_level_filename(level_nb);
743 load_level(level_filename);
746 void LevelEditor::load_sector(std::string name)
749 sector = level.get_sector(sector_name);
751 Termination::abort("Level has no " + sector_name + " sector.", "");
756 void LevelEditor::load_sector(Sector* sector_)
760 if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
762 Sector* nsector = new Sector();
763 level.add_sector(nsector);
771 /* Load sector stuff */
773 sector->update_game_objects();
775 foregrounds = solids = backgrounds = 0;
776 /* Point foregrounds, backgrounds, solids to its layer */
777 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
779 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
781 badguy->activate(LEFT);
783 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
786 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
787 foregrounds = tilemap;
788 else if(tilemap->get_layer() == LAYER_TILES)
790 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
791 backgrounds = tilemap;
797 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
798 sector->add_object(tilemap);
799 sector->update_game_objects();
803 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
804 sector->add_object(tilemap);
805 sector->update_game_objects();
809 sprintf(str, "%i", solids->get_width());
810 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
811 sprintf(str, "%i", solids->get_height());
812 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
815 void LevelEditor::save_level()
817 std::cerr << "saving level...\n";
818 level.save(level_filename);
819 level_changed = false;
822 void LevelEditor::test_level()
826 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
832 GameSession session(level_filename, ST_GL_TEST);
834 // player_status.reset();
835 sound_manager->halt_music();
838 void LevelEditor::change(int x, int y, int newtile, int layer)
839 { // find the tilemap of the current layer, and then change the tile
840 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
841 y < 0 || (unsigned int)y > sector->solids->get_height()*32)
844 level_changed = true;
847 { // no need to do this for normal view (no zoom)
848 x = (int)(x * (zoom*32) / 32);
849 y = (int)(y * (zoom*32) / 32);
852 if(newtile < 0) // add object
854 // remove an active tile or object that might be there
855 change(x, y, 0, LAYER_TILES);
857 if(newtile == OBJ_TRAMPOLINE)
858 sector->add_object(new Trampoline(x, y));
859 else if(newtile == OBJ_FLYING_PLATFORM)
860 sector->add_object(new FlyingPlatform(x, y));
861 else if(newtile == OBJ_DOOR)
862 sector->add_object(new Door(x, y));
864 sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
866 sector->update_game_objects();
868 else if(cur_layer == LAYER_FOREGROUNDTILES)
869 foregrounds->change(x/32, y/32, newtile);
870 else if(cur_layer == LAYER_TILES)
872 // remove a bad guy if it's there
873 // we /32 in order to round numbers
874 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
876 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
878 if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
879 sector->gameobjects.erase(i);
880 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
883 if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
884 sector->gameobjects.erase(i);
886 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
888 if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
889 sector->gameobjects.erase(i);
890 Door* door = dynamic_cast<Door*> (*i);
892 if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
893 sector->gameobjects.erase(i);
895 sector->update_game_objects();
896 solids->change(x/32, y/32, newtile);
898 else if(cur_layer == LAYER_BACKGROUNDTILES)
899 backgrounds->change(x/32, y/32, newtile);
902 void LevelEditor::show_help()
904 DrawingContext context;
906 bool show_grid_t = show_grid;
908 mouse_cursor->set_state(MC_HIDE);
913 _("This is the built-in level editor. It's aim is to be intuitive\n"
914 "and simple to use, so it should be pretty straight forward.\n"
916 "To open a level, first you'll have to select a level subset from\n"
917 "the menu (or create your own).\n"
918 "A level subset is basically a collection of levels.\n"
919 "They can then be played from the Contrib menu.\n"
921 "To access the menu from the level editor, just press Esc.\n"
923 "You are currently looking to the level, to scroll it, just\n"
924 "press the right mouse button and drag the mouse. It will move like\n"
926 "You can also use the arrow keys and Page Up/Down.\n"
928 "'+' and '-' keys can be used to zoom in/out the level.\n"
930 "You probably already noticed those floating group of buttons.\n"
931 "Each one serves a different purpose. To select a certain button\n"
932 "just press the Left mouse button on it. A few buttons have key\n"
933 "shortcuts, you can know it by pressing the Right mouse button on\n"
934 "it. That will also show what that button does.\n"
935 "Group of buttons can also be move around by just dragging them,\n"
936 "while pressing the Left mouse button.\n"
938 "Let's learn a bit of what each group of buttons do, shall we?\n"
940 "To starting putting tiles and objects around use the bigger gropup\n"
941 "of buttons. Each button is a different tile. To put it on the level,\n"
942 "just press it and then left click in the level.\n"
943 "You can also copy tiles from the level by using the middle mouse button.\n"
944 "Use the mouse wheel to scroll that group of buttons. You will find\n"
945 "enemies and game objects in the bottom.\n")
949 _("The Foreground/Interactive/Background buttons may be used to\n"
950 "see and edit the respective layer. Level's have three tiles layers:\n"
951 "Foreground - tiles are drawn in top of everything and have no contact\n"
953 "Interactive - these are the tiles that have contact with the player.\n"
954 "Background - tiles are drawn in bottom of everything and have no contact\n"
956 "The unselected layers will be drawn semi-transparently.\n"
958 "At last, but not least, the group of buttons that's left serves\n"
959 "to do related actions with the level.\n"
960 "From left to right:\n"
961 "Mini arrows - can be used to choose other sectors.\n"
962 "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
963 "Big arrows - choose other level in the same level subset.\n"
964 "Diskette - save the level\n"
965 "Tux - test the level\n"
966 "Tools - set a few settings for the level, incluiding resizing it.\n"
968 "We have reached the end of this Howto.\n"
970 "Don't forget to send us a few cool levels. :)\n"
973 " SuperTux development team\n"
975 "ps: If you are looking for something more powerfull, you can give it a\n"
976 "try to FlexLay. FlexLay is a level editor that supports several games,\n"
977 "including SuperTux. It is an independent project.\n"
978 "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
981 char **text[] = { text1, text2 };
985 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
989 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
991 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
993 sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
994 context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
996 context.do_drawing();
1002 done = wait_for_event(event);
1007 show_grid = show_grid_t;
1008 mouse_cursor->set_state(MC_NORMAL);