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 #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 if(level_name_timer.get_left() < FADING_TIME)
562 context.push_transform();
563 context.set_alpha(level_name_timer.get_left() * 255 / FADING_TIME);
566 context.draw_text(gold_text, level.name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
570 sprintf(str, "%i/%i", level_nb+1, level_subset.get_num_levels());
571 context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
574 if(level_name_timer.get_left() < FADING_TIME)
575 context.pop_transform();
578 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
580 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
582 Menu* menu = Menu::current();
587 tiles_board->draw(context);
588 tiles_layer->draw(context);
589 level_options->draw(context);
597 context.set_drawing_effect(SEMI_TRANSPARENT);
601 if(selection[0][0] == 0 && selection.size() == 1)
602 context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
603 event.button.y - 8), LAYER_GUI-2);
604 else if(selection[0][0] < 0)
606 int id = selection[0][0];
608 if(id == OBJ_TRAMPOLINE)
609 context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
610 event.button.y - 8), LAYER_GUI-2);
611 else if(id == OBJ_FLYING_PLATFORM)
612 context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
613 event.button.y - 8), LAYER_GUI-2);
614 else if(id == OBJ_DOOR)
615 context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
616 event.button.y - 8), LAYER_GUI-2);
619 BadGuyKind kind = BadGuyKind((-id)-1);
620 BadGuy badguy(kind, 0,0);
621 badguy.activate(LEFT);
622 Surface *img = badguy.get_image();
624 context.draw_surface(img, Vector(event.button.x - 8,
625 event.button.y - 8), LAYER_GUI-2);
630 TileManager* tilemanager = TileManager::instance();
631 for(unsigned int x = 0; x < selection.size(); x++)
632 for(unsigned int y = 0; y < selection[x].size(); y++)
633 tilemanager->draw_tile(context, selection[x][y],
634 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
638 context.set_drawing_effect(NONE_EFFECT);
641 context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
642 std::min((int)selection_ini.y, (int)event.button.y))*zoom,
643 Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
644 abs(event.button.y - (int)selection_ini.y)*zoom),
645 Color(170,255,170,128), LAYER_GUI-2);
649 for(int x = 0; x < screen->w / (32*zoom); x++)
651 int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
652 context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
653 Color(225, 225, 225), LAYER_GUI-50);
655 for(int y = 0; y < screen->h / (32*zoom); y++)
657 int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
658 context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
659 Color(225, 225, 225), LAYER_GUI-50);
663 context.push_transform();
664 context.set_translation(scroll);
665 context.set_zooming(zoom);
667 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
669 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
671 { // draw the non-selected tiles semi-transparently
672 context.push_transform();
674 if(tilemap->get_layer() != cur_layer)
675 context.set_drawing_effect(SEMI_TRANSPARENT);
678 context.pop_transform();
680 Background* background = dynamic_cast<Background*> (*i);
682 { // don't resize background
683 context.push_transform();
684 context.set_translation(scroll);
685 context.set_zooming(1.0);
687 context.pop_transform();
693 context.pop_transform();
696 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
698 context.do_drawing();
701 void LevelEditor::load_level_subset(std::string filename)
703 std::cerr << "loading subset...\n";
704 std::cerr << "filename: " << filename << std::endl;
705 level_subset.load(filename.c_str());
709 void LevelEditor::load_level(std::string filename)
714 level_filename = filename;
715 level.load(filename);
718 level_name_timer.start(3000);
719 scroll.x = scroll.y = 0;
720 level_changed = false;
722 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level.name.c_str());
723 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level.author.c_str());
726 void LevelEditor::load_level(int nb)
732 std::cerr << "level_nb: " << level_nb << std::endl;
733 std::cerr << "level_subset.get_level_filename(level_nb): " << level_subset.get_level_filename(level_nb) << std::endl;
734 level_filename = level_subset.get_level_filename(level_nb);
736 load_level(level_filename);
739 void LevelEditor::load_sector(std::string name)
742 sector = level.get_sector(sector_name);
744 Termination::abort("Level has no " + sector_name + " sector.", "");
749 void LevelEditor::load_sector(Sector* sector_)
753 if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
755 Sector* nsector = new Sector();
756 level.add_sector(nsector);
764 /* Load sector stuff */
766 sector->update_game_objects();
768 foregrounds = solids = backgrounds = 0;
769 /* Point foregrounds, backgrounds, solids to its layer */
770 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
772 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
774 badguy->activate(LEFT);
776 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
779 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
780 foregrounds = tilemap;
781 else if(tilemap->get_layer() == LAYER_TILES)
783 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
784 backgrounds = tilemap;
790 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
791 sector->add_object(tilemap);
792 sector->update_game_objects();
796 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
797 sector->add_object(tilemap);
798 sector->update_game_objects();
802 sprintf(str, "%i", solids->get_width());
803 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
804 sprintf(str, "%i", solids->get_height());
805 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
808 void LevelEditor::save_level()
810 level.save(level_filename);
811 level_changed = false;
814 void LevelEditor::test_level()
818 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
824 GameSession session(level_filename, ST_GL_TEST);
826 // player_status.reset();
827 sound_manager->halt_music();
830 void LevelEditor::change(int x, int y, int newtile, int layer)
831 { // find the tilemap of the current layer, and then change the tile
832 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
833 y < 0 || (unsigned int)y > sector->solids->get_height()*32)
836 level_changed = true;
839 { // no need to do this for normal view (no zoom)
840 x = (int)(x * (zoom*32) / 32);
841 y = (int)(y * (zoom*32) / 32);
844 if(newtile < 0) // add object
846 // remove an active tile or object that might be there
847 change(x, y, 0, LAYER_TILES);
849 if(newtile == OBJ_TRAMPOLINE)
850 sector->add_object(new Trampoline(x, y));
851 else if(newtile == OBJ_FLYING_PLATFORM)
852 sector->add_object(new FlyingPlatform(x, y));
853 else if(newtile == OBJ_DOOR)
854 sector->add_object(new Door(x, y));
856 sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
858 sector->update_game_objects();
860 else if(cur_layer == LAYER_FOREGROUNDTILES)
861 foregrounds->change(x/32, y/32, newtile);
862 else if(cur_layer == LAYER_TILES)
864 // remove a bad guy if it's there
865 // we /32 in order to round numbers
866 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
868 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
870 if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
871 sector->gameobjects.erase(i);
872 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
875 if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
876 sector->gameobjects.erase(i);
878 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
880 if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
881 sector->gameobjects.erase(i);
882 Door* door = dynamic_cast<Door*> (*i);
884 if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
885 sector->gameobjects.erase(i);
887 sector->update_game_objects();
888 solids->change(x/32, y/32, newtile);
890 else if(cur_layer == LAYER_BACKGROUNDTILES)
891 backgrounds->change(x/32, y/32, newtile);
894 void LevelEditor::show_help()
896 DrawingContext context;
898 bool show_grid_t = show_grid;
900 mouse_cursor->set_state(MC_HIDE);
905 _("This is the built-in level editor. It's aim is to be intuitive\n"
906 "and simple to use, so it should be pretty straight forward.\n"
908 "To open a level, first you'll have to select a level subset from\n"
909 "the menu (or create your own).\n"
910 "A level subset is basically a collection of levels.\n"
911 "They can then be played from the Contrib menu.\n"
913 "To access the menu from the level editor, just press Esc.\n"
915 "You are currently looking to the level, to scroll it, just\n"
916 "press the right mouse button and drag the mouse. It will move like\n"
918 "You can also use the arrow keys and Page Up/Down.\n"
920 "'+' and '-' keys can be used to zoom in/out the level.\n"
922 "You probably already noticed those floating group of buttons.\n"
923 "Each one serves a different purpose. To select a certain button\n"
924 "just press the Left mouse button on it. A few buttons have key\n"
925 "shortcuts, you can know it by pressing the Right mouse button on\n"
926 "it. That will also show what that button does.\n"
927 "Group of buttons can also be move around by just dragging them,\n"
928 "while pressing the Left mouse button.\n"
930 "Let's learn a bit of what each group of buttons do, shall we?\n"
932 "To starting putting tiles and objects around use the bigger gropup\n"
933 "of buttons. Each button is a different tile. To put it on the level,\n"
934 "just press it and then left click in the level.\n"
935 "You can also copy tiles from the level by using the middle mouse button.\n"
936 "Use the mouse wheel to scroll that group of buttons. You will find\n"
937 "enemies and game objects in the bottom.\n")
941 _("The Foreground/Interactive/Background buttons may be used to\n"
942 "see and edit the respective layer. Level's have three tiles layers:\n"
943 "Foreground - tiles are drawn in top of everything and have no contact\n"
945 "Interactive - these are the tiles that have contact with the player.\n"
946 "Background - tiles are drawn in bottom of everything and have no contact\n"
948 "The unselected layers will be drawn semi-transparently.\n"
950 "At last, but not least, the group of buttons that's left serves\n"
951 "to do related actions with the level.\n"
952 "From left to right:\n"
953 "Mini arrows - can be used to choose other sectors.\n"
954 "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
955 "Big arrows - choose other level in the same level subset.\n"
956 "Diskette - save the level\n"
957 "Tux - test the level\n"
958 "Tools - set a few settings for the level, incluiding resizing it.\n"
960 "We have reached the end of this Howto.\n"
962 "Don't forget to send us a few cool levels. :)\n"
965 " SuperTux development team\n"
967 "ps: If you are looking for something more powerfull, you can give it a\n"
968 "try to FlexLay. FlexLay is a level editor that supports several games,\n"
969 "including SuperTux. It is an independent project.\n"
970 "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
973 char **text[] = { text1, text2 };
977 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
981 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
983 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
985 sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
986 context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
988 context.do_drawing();
994 done = wait_for_event(event);
999 show_grid = show_grid_t;
1000 mouse_cursor->set_state(MC_NORMAL);