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())
218 load_level(filename);
220 Menu::set_current(main_menu);
222 mouse_cursor->set_state(MC_NORMAL);
233 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
237 void LevelEditor::events()
241 while(SDL_PollEvent(&event))
243 Menu* menu = Menu::current();
248 if(menu == main_menu)
250 switch (main_menu->check())
253 Menu::set_current(0);
260 else if(menu == create_subset_menu)
262 if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
263 create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
264 else if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
265 { // applying settings:
266 LevelSubset::create(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
267 level_subset.load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
269 level_subset.title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
270 level_subset.description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
274 create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
275 create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
276 create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
279 else if(menu == subset_menu)
281 int i = subset_menu->check();
284 std::set<std::string>::iterator it = level_subsets.begin();
285 for(int t = 0; t < i; t++)
287 std::cerr << "load subset level_subsets " << i << ": " << (*it) << std::endl;
288 load_level_subset(*it);
289 Menu::set_current(0);
292 else if(menu == settings_menu)
294 if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
295 { // applying settings:
296 level_changed = true;
298 level.name = settings_menu->get_item_by_id(MN_ID_NAME).input;
299 level.author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
301 solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
302 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
303 foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
304 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
305 backgrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
306 atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
308 Menu::set_current(0);
312 // check for events in buttons
313 else if(tiles_board->event(event))
315 std::vector <int> vector;
316 vector.push_back(tiles_board->selected_id());
319 selection.push_back(vector);
322 else if(tiles_layer->event(event))
324 cur_layer = tiles_layer->selected_id();
327 else if(level_options->event(event))
329 switch(level_options->selected_id())
338 Menu::set_current(settings_menu);
341 if(level_nb < level_subset.get_num_levels())
342 load_level(level_nb + 1);
347 sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 1);
348 if(confirm_dialog(NULL, str))
350 level_subset.add_level("new_level.stl");
351 new_lev.save(level_subset.get_level_filename(level_nb + 1));
352 load_level(level_nb);
356 case BT_PREVIOUS_LEVEL:
358 load_level(level_nb - 1);
361 std::cerr << "next sector.\n";
362 std::cerr << "total sectors: " << level.get_total_sectors() << std::endl;
363 load_sector(level.get_next_sector(sector));
365 case BT_PREVIOUS_SECTOR:
366 std::cerr << "previous sector.\n";
367 load_sector(level.get_previous_sector(sector));
370 level_options->set_unselected();
377 case SDL_MOUSEMOTION:
379 if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
380 { // movement like in strategy games
381 scroll.x += -1 * event.motion.xrel;
382 scroll.y += -1 * event.motion.yrel;
386 case SDL_MOUSEBUTTONDOWN:
388 if(event.button.button == SDL_BUTTON_LEFT)
390 else if(event.button.button == SDL_BUTTON_MIDDLE)
392 middle_button = true;
393 selection_ini = Vector(event.button.x, event.button.y);
397 case SDL_MOUSEBUTTONUP:
399 if(event.button.button == SDL_BUTTON_LEFT)
401 else if(event.button.button == SDL_BUTTON_MIDDLE)
403 middle_button = false;
404 selection_end = Vector(event.button.x, event.button.y);
406 if(selection_end.x < selection_ini.x)
408 float t = selection_ini.x;
409 selection_ini.x = selection_end.x;
412 if(selection_end.y < selection_ini.y)
414 float t = selection_ini.y;
415 selection_ini.y = selection_end.y;
420 std::vector <int> vector;
422 TileMap* tilemap = 0;
423 if(cur_layer == LAYER_FOREGROUNDTILES)
424 tilemap = foregrounds;
425 else if(cur_layer == LAYER_TILES)
427 else if(cur_layer == LAYER_BACKGROUNDTILES)
428 tilemap = backgrounds;
430 for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
433 for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
435 vector.push_back(tilemap->get_tile(x +
436 (int)(((selection_ini.x+scroll.x)*zoom)/32),
437 y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->id);
439 selection.push_back(vector);
444 case SDL_KEYDOWN: // key pressed
445 switch(event.key.keysym.sym)
448 Menu::set_current(main_menu);
450 /* scrolling related events: */
455 scroll.x = sector->solids->get_height()*32 - screen->w;
488 show_grid = !show_grid;
495 case SDL_QUIT: // window closed
506 void LevelEditor::action()
508 mouse_cursor->set_state(MC_NORMAL);
509 if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
510 mouse_cursor->set_state(MC_LINK);
514 if(!frame_timer.check())
516 frame_timer.start(25);
517 ++global_frame_counter;
520 // don't scroll before the start or after the level's end
521 float width = sector->solids->get_width() * 32;
522 float height = sector->solids->get_height() * 32;
524 if(scroll.x < -screen->w/2)
525 scroll.x = -screen->w/2;
526 if(scroll.x > width - screen->w/2)
527 scroll.x = width - screen->w/2;
528 if(scroll.y < -screen->h/2)
529 scroll.y = -screen->h/2;
530 if(scroll.y > height - screen->h/2)
531 scroll.y = height - screen->h/2;
533 // set camera translation, since BadGuys like it
534 sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
536 if(left_button && mouse_moved)
537 for(unsigned int x = 0; x < selection.size(); x++)
538 for(unsigned int y = 0; y < selection[x].size(); y++)
539 change((int)(scroll.x + event.button.x) + (x*32),
540 (int)(scroll.y + event.button.y) + (y*32), selection[x][y],
545 void LevelEditor::draw(DrawingContext& context)
547 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
548 mouse_cursor->draw(context);
550 // draw a filled background
551 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,60), LAYER_BACKGROUND0-1);
553 if(level_name_timer.check())
555 context.draw_text(gold_text, level.name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
557 sprintf(str, "%i/%i", level_nb+1, level_subset.get_num_levels());
558 context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
561 context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
563 context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
565 Menu* menu = Menu::current();
570 tiles_board->draw(context);
571 tiles_layer->draw(context);
572 level_options->draw(context);
580 context.set_drawing_effect(SEMI_TRANSPARENT);
584 if(selection[0][0] == 0 && selection.size() == 1)
585 context.draw_surface(img_rubber_bt, Vector(event.button.x - 8,
586 event.button.y - 8), LAYER_GUI-2);
587 else if(selection[0][0] < 0)
589 int id = selection[0][0];
591 if(id == OBJ_TRAMPOLINE)
592 context.draw_surface(img_trampoline[0].get_frame(0), Vector(event.button.x - 8,
593 event.button.y - 8), LAYER_GUI-2);
594 else if(id == OBJ_FLYING_PLATFORM)
595 context.draw_surface(img_flying_platform->get_frame(0), Vector(event.button.x - 8,
596 event.button.y - 8), LAYER_GUI-2);
597 else if(id == OBJ_DOOR)
598 context.draw_surface(door->get_frame(0), Vector(event.button.x - 8,
599 event.button.y - 8), LAYER_GUI-2);
602 BadGuyKind kind = BadGuyKind((-id)-1);
603 BadGuy badguy(kind, 0,0);
604 badguy.activate(LEFT);
605 Surface *img = badguy.get_image();
607 context.draw_surface(img, Vector(event.button.x - 8,
608 event.button.y - 8), LAYER_GUI-2);
613 TileManager* tilemanager = TileManager::instance();
614 for(unsigned int x = 0; x < selection.size(); x++)
615 for(unsigned int y = 0; y < selection[x].size(); y++)
616 tilemanager->draw_tile(context, selection[x][y],
617 Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8),
621 context.set_drawing_effect(NONE_EFFECT);
624 context.draw_filled_rect(Vector(std::min((int)selection_ini.x, (int)event.button.x)*zoom,
625 std::min((int)selection_ini.y, (int)event.button.y))*zoom,
626 Vector(abs(event.button.x - (int)selection_ini.x)*zoom,
627 abs(event.button.y - (int)selection_ini.y)*zoom),
628 Color(170,255,170,128), LAYER_GUI-2);
632 for(int x = 0; x < screen->w / (32*zoom); x++)
634 int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
635 context.draw_filled_rect(Vector (pos, 0), Vector(1, screen->h),
636 Color(225, 225, 225), LAYER_GUI-50);
638 for(int y = 0; y < screen->h / (32*zoom); y++)
640 int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
641 context.draw_filled_rect(Vector (0, pos), Vector(screen->w, 1),
642 Color(225, 225, 225), LAYER_GUI-50);
646 context.push_transform();
647 context.set_translation(scroll);
648 context.set_zooming(zoom);
650 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
652 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
654 { // draw the non-selected tiles semi-transparently
655 context.push_transform();
657 if(tilemap->get_layer() != cur_layer)
658 context.set_drawing_effect(SEMI_TRANSPARENT);
661 context.pop_transform();
663 Background* background = dynamic_cast<Background*> (*i);
665 { // don't resize background
666 context.push_transform();
667 context.set_translation(scroll);
668 context.set_zooming(1.0);
670 context.pop_transform();
676 context.pop_transform();
679 context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h),Color(0,0,0), LAYER_BACKGROUND0);
681 context.do_drawing();
684 void LevelEditor::load_level_subset(std::string filename)
686 std::cerr << "loading subset...\n";
687 std::cerr << "filename: " << filename << std::endl;
688 level_subset.load(filename.c_str());
692 void LevelEditor::load_level(std::string filename)
697 level_filename = filename;
698 level.load(filename);
701 level_name_timer.start(3000);
702 scroll.x = scroll.y = 0;
703 level_changed = false;
705 settings_menu->get_item_by_id(MN_ID_NAME).change_input(level.name.c_str());
706 settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level.author.c_str());
709 void LevelEditor::load_level(int nb)
715 std::cerr << "level_nb: " << level_nb << std::endl;
716 std::cerr << "level_subset.get_level_filename(level_nb): " << level_subset.get_level_filename(level_nb) << std::endl;
717 level_filename = level_subset.get_level_filename(level_nb);
719 load_level(level_filename);
722 void LevelEditor::load_sector(std::string name)
725 sector = level.get_sector(sector_name);
727 Termination::abort("Level has no " + sector_name + " sector.", "");
732 void LevelEditor::load_sector(Sector* sector_)
736 if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
738 Sector* nsector = new Sector();
739 level.add_sector(nsector);
747 /* Load sector stuff */
749 sector->update_game_objects();
751 foregrounds = solids = backgrounds = 0;
752 /* Point foregrounds, backgrounds, solids to its layer */
753 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
755 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
757 badguy->activate(LEFT);
759 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
762 if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
763 foregrounds = tilemap;
764 else if(tilemap->get_layer() == LAYER_TILES)
766 else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
767 backgrounds = tilemap;
773 TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
774 sector->add_object(tilemap);
775 sector->update_game_objects();
779 TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
780 sector->add_object(tilemap);
781 sector->update_game_objects();
785 sprintf(str, "%i", solids->get_width());
786 settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
787 sprintf(str, "%i", solids->get_height());
788 settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
791 void LevelEditor::save_level()
793 level.save(level_filename);
794 level_changed = false;
797 void LevelEditor::test_level()
801 if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
807 GameSession session(level_filename, ST_GL_TEST);
809 // player_status.reset();
810 sound_manager->halt_music();
813 void LevelEditor::change(int x, int y, int newtile, int layer)
814 { // find the tilemap of the current layer, and then change the tile
815 if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
816 y < 0 || (unsigned int)y > sector->solids->get_height()*32)
819 level_changed = true;
822 { // no need to do this for normal view (no zoom)
823 x = (int)(x * (zoom*32) / 32);
824 y = (int)(y * (zoom*32) / 32);
827 if(newtile < 0) // add object
829 // remove an active tile or object that might be there
830 change(x, y, 0, LAYER_TILES);
832 if(newtile == OBJ_TRAMPOLINE)
833 sector->add_object(new Trampoline(x, y));
834 else if(newtile == OBJ_FLYING_PLATFORM)
835 sector->add_object(new FlyingPlatform(x, y));
836 else if(newtile == OBJ_DOOR)
837 sector->add_object(new Door(x, y));
839 sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
841 sector->update_game_objects();
843 else if(cur_layer == LAYER_FOREGROUNDTILES)
844 foregrounds->change(x/32, y/32, newtile);
845 else if(cur_layer == LAYER_TILES)
847 // remove a bad guy if it's there
848 // we /32 in order to round numbers
849 for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
851 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
853 if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
854 sector->gameobjects.erase(i);
855 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
858 if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
859 sector->gameobjects.erase(i);
861 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
863 if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
864 sector->gameobjects.erase(i);
865 Door* door = dynamic_cast<Door*> (*i);
867 if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
868 sector->gameobjects.erase(i);
870 sector->update_game_objects();
871 solids->change(x/32, y/32, newtile);
873 else if(cur_layer == LAYER_BACKGROUNDTILES)
874 backgrounds->change(x/32, y/32, newtile);
877 void LevelEditor::show_help()
879 DrawingContext context;
881 bool show_grid_t = show_grid;
883 mouse_cursor->set_state(MC_HIDE);
888 _("This is the built-in level editor. It's aim is to be intuitive\n"
889 "and simple to use, so it should be pretty straight forward.\n"
891 "To open a level, first you'll have to select a level subset from\n"
892 "the menu (or create your own).\n"
893 "A level subset is basically a collection of levels.\n"
894 "They can then be played from the Contrib menu.\n"
896 "To access the menu from the level editor, just press Esc.\n"
898 "You are currently looking to the level, to scroll it, just\n"
899 "press the right mouse button and drag the mouse. It will move like\n"
901 "You can also use the arrow keys and Page Up/Down.\n"
903 "'+' and '-' keys can be used to zoom in/out the level.\n"
905 "You probably already noticed those floating group of buttons.\n"
906 "Each one serves a different purpose. To select a certain button\n"
907 "just press the Left mouse button on it. A few buttons have key\n"
908 "shortcuts, you can know it by pressing the Right mouse button on\n"
909 "it. That will also show what that button does.\n"
910 "Group of buttons can also be move around by just dragging them,\n"
911 "while pressing the Left mouse button.\n"
913 "Let's learn a bit of what each group of buttons do, shall we?\n"
915 "To starting putting tiles and objects around use the bigger gropup\n"
916 "of buttons. Each button is a different tile. To put it on the level,\n"
917 "just press it and then left click in the level.\n"
918 "You can also copy tiles from the level by using the middle mouse button.\n"
919 "Use the mouse wheel to scroll that group of buttons. You will find\n"
920 "enemies and game objects in the bottom.\n")
924 _("The Foreground/Interactive/Background buttons may be used to\n"
925 "see and edit the respective layer. Level's have three tiles layers:\n"
926 "Foreground - tiles are drawn in top of everything and have no contact\n"
928 "Interactive - these are the tiles that have contact with the player.\n"
929 "Background - tiles are drawn in bottom of everything and have no contact\n"
931 "The unselected layers will be drawn semi-transparently.\n"
933 "At last, but not least, the group of buttons that's left serves\n"
934 "to do related actions with the level.\n"
935 "From left to right:\n"
936 "Mini arrows - can be used to choose other sectors.\n"
937 "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
938 "Big arrows - choose other level in the same level subset.\n"
939 "Diskette - save the level\n"
940 "Tux - test the level\n"
941 "Tools - set a few settings for the level, incluiding resizing it.\n"
943 "We have reached the end of this Howto.\n"
945 "Don't forget to send us a few cool levels. :)\n"
948 " SuperTux development team\n"
950 "ps: If you are looking for something more powerfull, you can give it a\n"
951 "try to FlexLay. FlexLay is a level editor that supports several games,\n"
952 "including SuperTux. It is an independent project.\n"
953 "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
956 char **text[] = { text1, text2 };
960 for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
964 context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(screen->w/2, 60), CENTER_ALLIGN, LAYER_GUI);
966 context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
968 sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
969 context.draw_text(gold_text, str, Vector(screen->w/2, screen->h-60), CENTER_ALLIGN, LAYER_GUI);
971 context.do_drawing();
977 done = wait_for_event(event);
982 show_grid = show_grid_t;
983 mouse_cursor->set_state(MC_NORMAL);