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 < 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 void LevelEditor::draw(DrawingContext& context)
550 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
551 mouse_cursor->draw(context);
553 // draw a filled background
554 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
556 if(level_name_timer.check())
558 context.draw_text(gold_text, level.name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
562 sprintf(str, "%i/%i", level_nb+1, level_subset.get_num_levels());
563 context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
567 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
569 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
571 Menu* menu = Menu::current();
576 tiles_board->draw(context);
577 tiles_layer->draw(context);
578 level_options->draw(context);
586 context.set_drawing_effect(SEMI_TRANSPARENT);
590 if(selection[0][0] == 0 && selection.size() == 1)
591 context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
592 event.button.y - 8), LAYER_GUI-2);
593 else if(selection[0][0] < 0)
595 int id = selection[0][0];
597 if(id == OBJ_TRAMPOLINE)
598 context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
599 event.button.y - 8), LAYER_GUI-2);
600 else if(id == OBJ_FLYING_PLATFORM)
601 context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
602 event.button.y - 8), LAYER_GUI-2);
603 else if(id == OBJ_DOOR)
604 context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
605 event.button.y - 8), LAYER_GUI-2);
608 BadGuyKind kind = BadGuyKind((-id)-1);
609 BadGuy badguy(kind, 0,0);
610 badguy.activate(LEFT);
611 Surface *img = badguy.get_image();
613 context.draw_surface(img, Vector(event.button.x - 8,
614 event.button.y - 8), LAYER_GUI-2);
619 TileManager* tilemanager = TileManager::instance();
620 for(unsigned int x = 0; x < selection.size(); x++)
621 for(unsigned int y = 0; y < selection[x].size(); y++)
622 tilemanager->draw_tile(context, selection[x][y],
623 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
627 context.set_drawing_effect(NONE_EFFECT);
630 context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
631 std::min((int)selection_ini.y, (int)event.button.y))*zoom,
632 Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
633 abs(event.button.y - (int)selection_ini.y)*zoom),
634 Color(170,255,170,128), LAYER_GUI-2);
638 for(int x = 0; x < screen->w / (32*zoom); x++)
640 int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
641 context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
642 Color(225, 225, 225), LAYER_GUI-50);
644 for(int y = 0; y < screen->h / (32*zoom); y++)
646 int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
647 context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
648 Color(225, 225, 225), LAYER_GUI-50);
652 context.push_transform();
653 context.set_translation(scroll);
654 context.set_zooming(zoom);
656 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
658 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
660 { // draw the non-selected tiles semi-transparently
661 context.push_transform();
663 if(tilemap->get_layer() != cur_layer)
664 context.set_drawing_effect(SEMI_TRANSPARENT);
667 context.pop_transform();
669 Background* background = dynamic_cast<Background*> (*i);
671 { // don't resize background
672 context.push_transform();
673 context.set_translation(scroll);
674 context.set_zooming(1.0);
676 context.pop_transform();
682 context.pop_transform();
685 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
687 context.do_drawing();
690 void LevelEditor::load_level_subset(std::string filename)
692 std::cerr << "loading subset...\n";
693 std::cerr << "filename: " << filename << std::endl;
694 level_subset.load(filename.c_str());
698 void LevelEditor::load_level(std::string filename)
703 level_filename = filename;
704 level.load(filename);
707 level_name_timer.start(3000);
708 scroll.x = scroll.y = 0;
709 level_changed = false;
711 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level.name.c_str());
712 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level.author.c_str());
715 void LevelEditor::load_level(int nb)
721 std::cerr << "level_nb: " << level_nb << std::endl;
722 std::cerr << "level_subset.get_level_filename(level_nb): " << level_subset.get_level_filename(level_nb) << std::endl;
723 level_filename = level_subset.get_level_filename(level_nb);
725 load_level(level_filename);
728 void LevelEditor::load_sector(std::string name)
731 sector = level.get_sector(sector_name);
733 Termination::abort("Level has no " + sector_name + " sector.", "");
738 void LevelEditor::load_sector(Sector* sector_)
742 if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
744 Sector* nsector = new Sector();
745 level.add_sector(nsector);
753 /* Load sector stuff */
755 sector->update_game_objects();
757 foregrounds = solids = backgrounds = 0;
758 /* Point foregrounds, backgrounds, solids to its layer */
759 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
761 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
763 badguy->activate(LEFT);
765 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
768 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
769 foregrounds = tilemap;
770 else if(tilemap->get_layer() == LAYER_TILES)
772 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
773 backgrounds = tilemap;
779 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
780 sector->add_object(tilemap);
781 sector->update_game_objects();
785 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
786 sector->add_object(tilemap);
787 sector->update_game_objects();
791 sprintf(str, "%i", solids->get_width());
792 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
793 sprintf(str, "%i", solids->get_height());
794 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
797 void LevelEditor::save_level()
799 level.save(level_filename);
800 level_changed = false;
803 void LevelEditor::test_level()
807 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
813 GameSession session(level_filename, ST_GL_TEST);
815 // player_status.reset();
816 sound_manager->halt_music();
819 void LevelEditor::change(int x, int y, int newtile, int layer)
820 { // find the tilemap of the current layer, and then change the tile
821 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
822 y < 0 || (unsigned int)y > sector->solids->get_height()*32)
825 level_changed = true;
828 { // no need to do this for normal view (no zoom)
829 x = (int)(x * (zoom*32) / 32);
830 y = (int)(y * (zoom*32) / 32);
833 if(newtile < 0) // add object
835 // remove an active tile or object that might be there
836 change(x, y, 0, LAYER_TILES);
838 if(newtile == OBJ_TRAMPOLINE)
839 sector->add_object(new Trampoline(x, y));
840 else if(newtile == OBJ_FLYING_PLATFORM)
841 sector->add_object(new FlyingPlatform(x, y));
842 else if(newtile == OBJ_DOOR)
843 sector->add_object(new Door(x, y));
845 sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
847 sector->update_game_objects();
849 else if(cur_layer == LAYER_FOREGROUNDTILES)
850 foregrounds->change(x/32, y/32, newtile);
851 else if(cur_layer == LAYER_TILES)
853 // remove a bad guy if it's there
854 // we /32 in order to round numbers
855 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
857 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
859 if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
860 sector->gameobjects.erase(i);
861 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
864 if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
865 sector->gameobjects.erase(i);
867 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
869 if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
870 sector->gameobjects.erase(i);
871 Door* door = dynamic_cast<Door*> (*i);
873 if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
874 sector->gameobjects.erase(i);
876 sector->update_game_objects();
877 solids->change(x/32, y/32, newtile);
879 else if(cur_layer == LAYER_BACKGROUNDTILES)
880 backgrounds->change(x/32, y/32, newtile);
883 void LevelEditor::show_help()
885 DrawingContext context;
887 bool show_grid_t = show_grid;
889 mouse_cursor->set_state(MC_HIDE);
894 _("This is the built-in level editor. It's aim is to be intuitive\n"
895 "and simple to use, so it should be pretty straight forward.\n"
897 "To open a level, first you'll have to select a level subset from\n"
898 "the menu (or create your own).\n"
899 "A level subset is basically a collection of levels.\n"
900 "They can then be played from the Contrib menu.\n"
902 "To access the menu from the level editor, just press Esc.\n"
904 "You are currently looking to the level, to scroll it, just\n"
905 "press the right mouse button and drag the mouse. It will move like\n"
907 "You can also use the arrow keys and Page Up/Down.\n"
909 "'+' and '-' keys can be used to zoom in/out the level.\n"
911 "You probably already noticed those floating group of buttons.\n"
912 "Each one serves a different purpose. To select a certain button\n"
913 "just press the Left mouse button on it. A few buttons have key\n"
914 "shortcuts, you can know it by pressing the Right mouse button on\n"
915 "it. That will also show what that button does.\n"
916 "Group of buttons can also be move around by just dragging them,\n"
917 "while pressing the Left mouse button.\n"
919 "Let's learn a bit of what each group of buttons do, shall we?\n"
921 "To starting putting tiles and objects around use the bigger gropup\n"
922 "of buttons. Each button is a different tile. To put it on the level,\n"
923 "just press it and then left click in the level.\n"
924 "You can also copy tiles from the level by using the middle mouse button.\n"
925 "Use the mouse wheel to scroll that group of buttons. You will find\n"
926 "enemies and game objects in the bottom.\n")
930 _("The Foreground/Interactive/Background buttons may be used to\n"
931 "see and edit the respective layer. Level's have three tiles layers:\n"
932 "Foreground - tiles are drawn in top of everything and have no contact\n"
934 "Interactive - these are the tiles that have contact with the player.\n"
935 "Background - tiles are drawn in bottom of everything and have no contact\n"
937 "The unselected layers will be drawn semi-transparently.\n"
939 "At last, but not least, the group of buttons that's left serves\n"
940 "to do related actions with the level.\n"
941 "From left to right:\n"
942 "Mini arrows - can be used to choose other sectors.\n"
943 "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
944 "Big arrows - choose other level in the same level subset.\n"
945 "Diskette - save the level\n"
946 "Tux - test the level\n"
947 "Tools - set a few settings for the level, incluiding resizing it.\n"
949 "We have reached the end of this Howto.\n"
951 "Don't forget to send us a few cool levels. :)\n"
954 " SuperTux development team\n"
956 "ps: If you are looking for something more powerfull, you can give it a\n"
957 "try to FlexLay. FlexLay is a level editor that supports several games,\n"
958 "including SuperTux. It is an independent project.\n"
959 "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
962 char **text[] = { text1, text2 };
966 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
970 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
972 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
974 sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
975 context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
977 context.do_drawing();
983 done = wait_for_event(event);
988 show_grid = show_grid_t;
989 mouse_cursor->set_state(MC_NORMAL);