4 // Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
5 // Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include "SDL_image.h"
35 #include "leveleditor.h"
36 #include "screen/screen.h"
47 #include "tile_manager.h"
48 #include "resources.h"
49 #include "background.h"
52 /* definitions to aid development */
54 /* definitions that affect gameplay */
55 #define KEY_CURSOR_SPEED 32
56 #define KEY_CURSOR_FASTSPEED 64
58 /* when pagedown/up pressed speed:*/
59 #define PAGE_CURSOR_SPEED 13*32
61 #define MOUSE_LEFT_MARGIN 80
62 #define MOUSE_RIGHT_MARGIN (560-32)
65 #define KEYBOARD_SPEED 140
66 #define MOUSE_SPEED 40
69 #define SELECT_W 2 // size of the selections lines
70 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
72 enum { TM_IA, TM_BG, TM_FG };
74 LevelEditor::LevelEditor()
76 level_subsets = dsubdirs("/levels", "level1.stl");
77 le_level_subset = new LevelSubset;
81 selected_game_object = NULL;
85 show_selections = true;
90 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
91 le_level_changed = false;
92 le_help_shown = false;
94 le_mouse_pressed[LEFT] = false;
95 le_mouse_pressed[RIGHT] = false;
97 le_mouse_clicked[LEFT] = false;
98 le_mouse_clicked[RIGHT] = false;
100 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
102 select_tilegroup_menu_effect.init(false);
103 select_objects_menu_effect.init(false);
104 display_level_info.init(false);
107 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
108 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
109 le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
110 le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
111 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
112 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
113 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
114 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
115 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
116 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
117 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
118 le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
119 le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
120 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
121 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
122 le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
123 le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
124 le_object_properties_bt->set_active(false);
126 mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
127 mouse_select_object->set_mid(16,16);
129 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
130 le_tilemap_panel->set_button_size(32,10);
131 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
132 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0), TM_IA);
133 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
134 le_tilemap_panel->highlight_last(true);
135 le_tilemap_panel->set_last_clicked(TM_IA);
141 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
144 LevelEditor::~LevelEditor()
146 SDL_EnableKeyRepeat(0, 0); // disables key repeating
150 delete leveleditor_menu;
151 delete subset_load_menu;
152 delete subset_new_menu;
153 delete subset_settings_menu;
154 delete level_settings_menu;
155 delete select_tilegroup_menu;
156 delete select_objects_menu;
157 delete le_save_level_bt;
159 delete le_test_level_bt;
160 delete le_next_level_bt;
161 delete le_previous_level_bt;
162 delete le_move_right_bt;
163 delete le_move_left_bt;
164 delete le_move_up_bt;
165 delete le_move_down_bt;
167 delete le_select_mode_one_bt;
168 delete le_select_mode_two_bt;
169 delete le_settings_bt;
170 delete le_tilegroup_bt;
171 delete le_objects_bt;
172 delete le_tilemap_panel;
173 delete le_object_select_bt;
174 delete le_object_properties_bt;
175 delete mouse_select_object;
177 delete le_level_subset;
180 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
181 i != tilegroups_map.end(); ++i)
185 for(ButtonPanelMap::iterator i = objects_map.begin();
186 i != objects_map.end(); ++i)
192 int LevelEditor::run(char* filename)
194 int last_time, now_time, i;
195 DrawingContext context;
200 sound_manager->halt_music();
202 while (SDL_PollEvent(&event))
206 if(load_level_subset(filename))
211 last_time = SDL_GetTicks();
216 if(Menu::current() == select_tilegroup_menu)
218 if(select_tilegroup_menu_effect.check())
220 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
224 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
226 else if(Menu::current() == select_objects_menu)
228 if(select_objects_menu_effect.check())
230 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
233 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
238 /* making events results to be in order */
241 context.set_translation(Vector(pos_x, pos_y));
245 fillrect(0, 0, screen->w, screen->h, 0, 0, 0);
247 /* draw editor interface */
248 context.set_translation(Vector(0, 0));
249 drawinterface(context);
251 Menu* menu = Menu::current();
257 if(menu == leveleditor_menu)
259 switch (leveleditor_menu->check())
261 case MNID_RETURNLEVELEDITOR:
263 Menu::set_current(0);
265 Menu::set_current(leveleditor_menu);
267 case MNID_SUBSETSETTINGS:
268 update_subset_settings_menu();
270 case MNID_QUITLEVELEDITOR:
275 else if(menu == level_settings_menu)
277 switch (level_settings_menu->check())
280 apply_level_settings_menu();
281 Menu::set_current(NULL);
288 else if(menu == select_tilegroup_menu)
291 switch (it = select_tilegroup_menu->check())
296 cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
297 Menu::set_current(0);
304 else if(menu == select_objects_menu)
307 switch (it = select_objects_menu->check())
312 cur_objects = select_objects_menu->get_item_by_id(it).text;
315 Menu::set_current(0);
320 else if(menu == subset_load_menu)
322 switch (i = subset_load_menu->check())
329 if(load_level_subset(level_subsets.item[i-1]))
335 else if(menu == subset_new_menu)
337 if(subset_new_menu->item[2].input[0] == '\0')
338 subset_new_menu->item[3].kind = MN_DEACTIVE;
341 subset_new_menu->item[3].kind = MN_ACTION;
343 switch (i = subset_new_menu->check())
345 case MNID_CREATESUBSET:
346 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
347 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
348 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
350 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
352 Menu::set_current(subset_settings_menu);
357 else if(menu == subset_settings_menu)
359 if(le_level_subset->title.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETTITLE).input) == 0 && le_level_subset->description.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETDESCRIPTION).input) == 0 )
360 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
362 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
364 switch (i = subset_settings_menu->check())
366 case MNID_SUBSETSAVECHANGES:
367 save_subset_settings_menu();
368 Menu::set_current(leveleditor_menu);
374 MouseCursor::current()->draw(context);
381 ++global_frame_counter;
384 now_time = SDL_GetTicks();
385 if (now_time < last_time + FPS)
386 SDL_Delay(last_time + FPS - now_time); /* delay some time */
388 context.do_drawing();
394 int LevelEditor::load_level_subset(char *filename)
396 le_level_subset->load(filename);
397 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
399 goto_level(le_levelnb);
401 //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
403 Menu::set_current(NULL);
408 void LevelEditor::init_menus()
412 leveleditor_menu = new Menu();
413 subset_load_menu = new Menu();
414 subset_new_menu = new Menu();
415 subset_settings_menu = new Menu();
416 level_settings_menu = new Menu();
417 select_tilegroup_menu = new Menu();
418 select_objects_menu = new Menu();
420 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
421 leveleditor_menu->additem(MN_HL,"",0,0);
422 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
423 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
424 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
425 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
426 leveleditor_menu->additem(MN_HL,"",0,0);
427 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
429 Menu::set_current(leveleditor_menu);
431 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
432 subset_load_menu->additem(MN_HL, "", 0, 0);
434 for(i = 0; i < level_subsets.num_items; ++i)
436 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
438 subset_load_menu->additem(MN_HL,"",0,0);
439 subset_load_menu->additem(MN_BACK,"Back",0,0);
441 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
442 subset_new_menu->additem(MN_HL,"",0,0);
443 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
444 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
445 subset_new_menu->additem(MN_HL,"",0,0);
446 subset_new_menu->additem(MN_BACK,"Back",0,0);
448 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
449 subset_settings_menu->additem(MN_HL,"",0,0);
450 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
451 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
452 subset_settings_menu->additem(MN_HL,"",0,0);
453 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
454 subset_settings_menu->additem(MN_HL,"",0,0);
455 subset_settings_menu->additem(MN_BACK,"Back",0,0);
457 level_settings_menu->arrange_left = true;
458 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
459 level_settings_menu->additem(MN_HL,"",0,0);
460 level_settings_menu->additem(MN_TEXTFIELD, "Name ",0,0,MNID_NAME);
461 level_settings_menu->additem(MN_TEXTFIELD, "Author ",0,0,MNID_AUTHOR);
462 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
463 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
464 level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
465 level_settings_menu->additem(MN_NUMFIELD, "Length ",0,0,MNID_LENGTH);
466 level_settings_menu->additem(MN_NUMFIELD, "Height ",0,0,MNID_HEIGHT);
467 level_settings_menu->additem(MN_NUMFIELD, "Time ",0,0,MNID_TIME);
468 level_settings_menu->additem(MN_NUMFIELD, "Gravity ",0,0,MNID_GRAVITY);
469 level_settings_menu->additem(MN_NUMFIELD, "Bg-Img-Speed",0,0,MNID_BGSPEED);
470 level_settings_menu->additem(MN_NUMFIELD, "Top Red ",0,0,MNID_TopRed);
471 level_settings_menu->additem(MN_NUMFIELD, "Top Green ",0,0,MNID_TopGreen);
472 level_settings_menu->additem(MN_NUMFIELD, "Top Blue ",0,0,MNID_TopBlue);
473 level_settings_menu->additem(MN_NUMFIELD, "Bottom Red ",0,0,MNID_BottomRed);
474 level_settings_menu->additem(MN_NUMFIELD, "Bottom Green",0,0,MNID_BottomGreen);
475 level_settings_menu->additem(MN_NUMFIELD, "Bottom Blue ",0,0,MNID_BottomBlue);
476 level_settings_menu->additem(MN_HL,"",0,0);
477 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
479 select_tilegroup_menu->arrange_left = true;
480 select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
481 select_tilegroup_menu->additem(MN_HL,"",0,0);
482 std::set<TileGroup>* tilegroups = TileManager::tilegroups();
484 for(std::set<TileGroup>::iterator it = tilegroups->begin();
485 it != tilegroups->end(); ++it )
487 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
489 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
492 for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
493 sit != (*it).tiles.end(); ++sit, ++i)
495 Tile& tile = TileManager::instance()->get(*sit);
497 if(tile.editor_images.size() > 0)
498 image = tile.editor_images[0];
499 else if(tile.images.size() > 0)
500 image = tile.images[0];
502 // TODO use some notile image...
505 Button* button = new Button(image, it->name, SDLKey(SDLK_a + i),
507 tilegroups_map[it->name]->additem(button, *sit);
510 select_tilegroup_menu->additem(MN_HL,"",0,0);
512 select_objects_menu->arrange_left = true;
513 select_objects_menu->additem(MN_LABEL,"Objects",0,0);
514 select_objects_menu->additem(MN_HL,"",0,0);
516 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
517 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
519 for(int i = 0; i < NUM_BadGuyKinds; ++i)
521 // BadGuy bad_tmp(BadGuyKind(i), 0, 0);
522 // objects_map["BadGuys"]->additem(new Button(0, "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
523 /* FIXME: maybe addbutton should already have a parameter for the surface
524 objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
525 BadGuy(BadGuyKind(i),
526 objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
527 objects_map["BadGuys"]->manipulate_button(i)->get_pos().y
531 select_objects_menu->additem(MN_HL,"",0,0);
535 void LevelEditor::update_level_settings_menu()
540 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_level->name.c_str());
541 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_level->author.c_str());
543 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
544 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
545 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
546 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
547 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
548 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
550 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_level->get_sector("main")->song_title.c_str())) != -1)
551 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
552 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_level->get_sector("main")->background->get_image().c_str())) != -1)
553 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
554 /* if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_level->get_sector("main")->particlesystem.c_str())) != -1)
555 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;*/
557 sprintf(str,"%d",static_cast<int>(le_level->get_sector("main")->solids->get_width()));
558 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
559 sprintf(str,"%d", static_cast<int>(le_level->get_sector("main")->solids->get_height()));
560 level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
561 sprintf(str,"%d",le_level->time_left);
562 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
563 sprintf(str,"%2.0f",le_level->get_sector("main")->gravity);
564 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
565 sprintf(str,"%2.2f", le_level->get_sector("main")->background->get_speed());
566 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
567 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().red);
568 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
569 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().green);
570 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
571 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().blue);
572 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
573 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().red);
574 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
575 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().green);
576 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
577 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().blue);
578 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
581 void LevelEditor::update_subset_settings_menu()
583 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
584 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
587 void LevelEditor::apply_level_settings_menu()
591 le_level_changed = true;
593 le_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
594 le_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
596 if(le_level->get_sector("main")->background->get_image().compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
598 le_level->get_sector("main")->background->set_image(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list), atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input));
602 /* if(le_level->get_sector("main")->particlesystem.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
604 le_level->->get_sector("main")->particlesystem = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
609 le_level->load_gfx();
612 le_level->get_sector("main")->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
614 le_level->get_sector("main")->solids->resize(
615 atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input),
616 atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
617 le_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
618 le_level->get_sector("main")->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
619 le_level->get_sector("main")->background->set_gradient(Color(
620 atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input),
621 atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input),
622 atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input)), Color(
623 atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input),
624 atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input),
625 atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input)));
628 void LevelEditor::save_subset_settings_menu()
630 le_level_subset->title = subset_settings_menu->item[2].input;
631 le_level_subset->description = subset_settings_menu->item[3].input;
632 le_level_subset->save();
633 le_level_changed = false;
636 void LevelEditor::unload_level()
641 // TODO get level number
642 sprintf(str,"Save changes to level %d of %s?", 0/*le_level*/,le_level_subset->name.c_str());
643 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
644 if(confirm_dialog(surf, str))
646 le_level->save(le_level_subset->get_level_filename(le_levelnb));
653 le_level_changed = false;
656 void LevelEditor::goto_level(int levelnb)
659 le_level = new Level();
660 le_level->load(le_level_subset->get_level_filename(levelnb));
661 display_level_info.start(2500);
662 le_levelnb = levelnb;
665 void LevelEditor::drawminimap()
668 // if(le_level == NULL)
672 if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 4)
674 else if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 2)
678 int left_offset = (screen->w - 64 - le_level->get_sector("main")->solids->get_width()*mini_tile_width) / 2;
680 int mini_tile_height;
681 if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 4)
682 mini_tile_height = 4;
683 else if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 2)
684 mini_tile_height = 2;
686 mini_tile_height = 1;
688 for (unsigned int y = 0; y < le_level->get_sector("main")->solids->get_height(); ++y)
689 for (unsigned int x = 0; x < le_level->get_sector("main")->solids->get_width(); ++x)
692 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
693 mini_tile_width , mini_tile_height, le_level->bg_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
695 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
696 mini_tile_width , mini_tile_height, le_level->ia_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
698 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
699 mini_tile_width , mini_tile_height, le_level->fg_tiles[y + le_level->get_sector("main")->solids->get_width() + x]);
703 fillrect(left_offset, 0,
704 le_level->get_sector("main")->solids->get_width()*mini_tile_width, le_level->get_sector("main")->solids->get_height()*mini_tile_height,
707 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
708 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
710 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
711 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
713 fillrect(left_offset + (pos_x/32)*mini_tile_width + (VISIBLE_TILES_X-3)*mini_tile_width - 2, (pos_y/32)*mini_tile_height,
714 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
716 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height + (VISIBLE_TILES_Y-1)*mini_tile_height - 2,
717 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
722 void LevelEditor::drawinterface(DrawingContext &context)
729 /* draw a grid (if selected) */
732 for(x = 0; x < VISIBLE_TILES_X; x++)
733 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
734 for(y = 0; y < VISIBLE_TILES_Y; y++)
735 fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
739 if(show_minimap) // use_gl because the minimap isn't shown correctly in software mode. Any idea? FIXME Possible reasons: SDL_SoftStretch is a hack itsself || an alpha blitting issue SDL can't handle in software mode
742 if(show_selections && MouseCursor::current() != mouse_select_object)
744 if(le_selection_mode == CURSOR)
746 if(le_current.IsTile())
747 context.draw_surface(le_selection, Vector(cursor_x - pos_x, cursor_y - pos_y), LAYER_GUI);
749 else if(le_selection_mode == SQUARE)
752 highlight_selection();
753 /* draw current selection */
754 w = selection.x2 - selection.x1;
755 h = selection.y2 - selection.y1;
756 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
757 context.draw_filled_rect(Vector(selection.x1 - pos_x + w, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
758 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y + h), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
759 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
764 /* draw button bar */
765 context.draw_filled_rect(Vector(screen->w - 64, 0), Vector(64, screen->h), Color(50, 50, 50,255), LAYER_GUI);
767 if(le_current.IsTile())
769 // le_level->get_sector("main")->solids->draw(context);
771 /*screen->w - 32, screen->h - 32, le_current.tile);
772 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
773 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);*/
775 #if 0 // XXX FIXME TODO: Do we have a new solution for draw_on_screen()?
776 if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
778 le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
779 le_current.obj->draw_on_screen(cursor_x,cursor_y);
783 if(mouse_select_object && selected_game_object != NULL)
785 fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,selected_game_object->base.width,3,255,0,0,255);
786 fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
787 fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y+selected_game_object->base.height,selected_game_object->base.width,3,255,0,0,255);
788 fillrect(selected_game_object->base.x-pos_x+selected_game_object->base.width,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
793 le_save_level_bt->draw(context);
794 le_exit_bt->draw(context);
795 le_test_level_bt->draw(context);
796 le_next_level_bt->draw(context);
797 le_previous_level_bt->draw(context);
798 le_rubber_bt->draw(context);
799 if(le_selection_mode == SQUARE)
800 le_select_mode_one_bt->draw(context);
801 else if(le_selection_mode == CURSOR)
802 le_select_mode_two_bt->draw(context);
803 le_settings_bt->draw(context);
804 le_move_right_bt->draw(context);
805 le_move_left_bt->draw(context);
806 le_move_up_bt->draw(context);
807 le_move_down_bt->draw(context);
808 le_tilegroup_bt->draw(context);
809 le_objects_bt->draw(context);
810 if(!cur_tilegroup.empty())
811 tilegroups_map[cur_tilegroup]->draw(context);
812 else if(!cur_objects.empty())
814 objects_map[cur_objects]->draw(context);
817 le_tilemap_panel->draw(context);
819 if(!cur_objects.empty())
821 le_object_select_bt->draw(context);
822 le_object_properties_bt->draw(context);
825 sprintf(str, "%d/%d", le_levelnb,le_level_subset->levels);
826 context.draw_text(white_text, str, Vector((le_level_subset->levels < 10) ? -10 : 0, 16), LAYER_GUI);
829 context.draw_text(white_small_text, "F1 for Help", Vector(10, 430), LAYER_GUI);
831 if(display_level_info.check())
832 context.draw_text_center(white_text, le_level->name.c_str(), Vector(0, 0), LAYER_GUI);
837 context.draw_text(white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", Vector(10, 430), LAYER_GUI);
839 context.draw_text(white_small_text, "No Level Subset loaded", Vector(10, 430), LAYER_GUI);
844 void LevelEditor::drawlevel(DrawingContext& context)
849 /* Draw the real background */
850 le_level->get_sector("main")->background->draw(context);
852 if(le_current.IsTile())
854 //le_level->get_sector("main")->solids->draw(context);
856 Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
857 if(!TileManager::instance()->get(le_current.tile)->images.empty())
858 fillrect(cursor_x-pos_x,cursor_y-pos_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);*/
860 #if 0 // XXX FIXME TODO: Do we have a new solution for move_to()?
861 if(le_current.IsObject())
863 le_current.obj->move_to(cursor_x, cursor_y);
867 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
869 le_level->get_sector("main")->solids->draw(context);
871 // FIXME: make tiles to be drawn semi-transparent when not selected
873 for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_level->get_section("main")->height; ++y)
874 for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
877 if(active_tm == TM_BG)
882 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
883 le_level->bg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
884 (x + (int)(pos_x / 32))],a);
886 if(active_tm == TM_IA)
891 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
892 le_level->ia_tiles[ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width +
893 (x + (int)(pos_x / 32))],a);
896 if(active_tm == TM_FG)
901 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
902 le_level->fg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
903 (x + (int)(pos_x / 32))],a);
905 /* draw whats inside stuff when cursor is selecting those */
906 /* (draw them all the time - is this the right behaviour?) */
907 Tile* edit_image = TileManager::instance()->get(
909 [ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width + (x + (int)(pos_x / 32))]);
910 if(edit_image && !edit_image->editor_images.empty())
911 edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
915 /* Draw the Bad guys: */
916 for (std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
917 it != le_level->get_sector("main")->gameobjects.end(); ++it)
919 BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
923 /* to support frames: img_bsod_left[(frame / 5) % 4] */
924 badguy->draw(context);
927 /* Draw the player: */
928 /* for now, the position is fixed at (100, 240) */
929 largetux.walk_right->draw(context, Vector(100 - pos_x, 240 - pos_y), LAYER_OBJECTS-1);
932 void LevelEditor::change_object_properties(GameObject *pobj)
934 DrawingContext context;
936 Menu* object_properties_menu = new Menu();
939 std::string type = typeid(pobj).name();
940 object_properties_menu->additem(MN_LABEL, type + " Properties",0,0);
941 object_properties_menu->additem(MN_HL,"",0,0);
943 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
946 object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
947 for(int i = 0; i < NUM_BadGuyKinds; ++i)
949 string_list_add_item(object_properties_menu->get_item_by_id(1).list,
950 badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
952 object_properties_menu->get_item_by_id(1).list->active_item = i;
954 object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
957 object_properties_menu->additem(MN_HL,"",0,0);
958 object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
960 Menu::set_current(object_properties_menu);
966 while (SDL_PollEvent(&event))
968 object_properties_menu->event(event);
971 //cap_screen->draw(0,0);
973 object_properties_menu->draw(context);
974 object_properties_menu->action();
976 switch (object_properties_menu->check())
980 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
982 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
983 pbad->kind = badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
984 pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
993 if(Menu::current() == NULL)
996 mouse_cursor->draw(context);
997 // context.draw_filled_rect();
1001 //delete cap_screen;
1002 Menu::set_current(0);
1003 delete object_properties_menu;
1007 void LevelEditor::checkevents()
1014 keymod = SDL_GetModState();
1016 while(SDL_PollEvent(&event))
1018 if (Menu::current())
1020 Menu::current()->event(event);
1021 if(!le_level && !Menu::current())
1022 Menu::set_current(leveleditor_menu);
1026 mouse_cursor->set_state(MC_NORMAL);
1028 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1029 if(event.type == SDL_KEYDOWN
1030 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1031 && (event.motion.x > 0
1032 && event.motion.x < screen->w - 64 &&
1033 event.motion.y > 0 && event.motion.y < screen->h)))
1037 case SDL_KEYDOWN: // key pressed
1038 key = event.key.keysym.sym;
1042 Menu::set_current(leveleditor_menu);
1045 if(le_level != NULL)
1053 cursor_x = (le_level->get_sector("main")->solids->get_width() * 32) - 32;
1057 le_show_grid = !le_show_grid;
1063 case SDL_MOUSEBUTTONDOWN:
1064 if(event.button.button == SDL_BUTTON_LEFT)
1066 le_mouse_pressed[LEFT] = true;
1068 selection.x1 = event.motion.x + pos_x;
1069 selection.y1 = event.motion.y + pos_y;
1070 selection.x2 = event.motion.x + pos_x;
1071 selection.y2 = event.motion.y + pos_y;
1073 else if(event.button.button == SDL_BUTTON_RIGHT)
1075 le_mouse_pressed[RIGHT] = true;
1078 case SDL_MOUSEBUTTONUP:
1079 if(event.button.button == SDL_BUTTON_LEFT)
1081 le_mouse_pressed[LEFT] = false;
1082 le_mouse_clicked[LEFT] = true;
1084 else if(event.button.button == SDL_BUTTON_RIGHT)
1086 le_mouse_pressed[RIGHT] = false;
1087 le_mouse_clicked[RIGHT] = true;
1090 case SDL_MOUSEMOTION:
1092 if(!Menu::current())
1097 if(le_current.IsTile())
1099 cursor_x = ((int)(pos_x + x) / 32) * 32;
1100 cursor_y = ((int)(pos_y + y) / 32) * 32;
1108 if(le_mouse_pressed[LEFT])
1110 selection.x2 = x + pos_x;
1111 selection.y2 = y + pos_y;
1114 if(le_mouse_pressed[RIGHT])
1116 pos_x += -1 * event.motion.xrel;
1117 pos_y += -1 * event.motion.yrel;
1125 else if(event.type == SDL_QUIT) /* window closing */
1131 if(le_level != NULL)
1133 if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > screen->w-64 && event.motion.x < screen->w &&
1134 event.motion.y > 0 && event.motion.y < screen->h)))
1136 le_mouse_pressed[LEFT] = false;
1137 le_mouse_pressed[RIGHT] = false;
1139 if(!Menu::current())
1141 /* Check for button events */
1142 le_test_level_bt->event(event);
1143 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1145 le_save_level_bt->event(event);
1146 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1147 le_level->save(le_level_subset->name.c_str());
1148 le_exit_bt->event(event);
1149 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1151 Menu::set_current(leveleditor_menu);
1153 le_next_level_bt->event(event);
1154 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1156 if(le_levelnb < le_level_subset->levels)
1158 goto_level(le_levelnb+1);
1164 sprintf(str,"Level %d doesn't exist. Create it?",le_levelnb+1);
1165 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
1166 if(confirm_dialog(surf, str))
1168 new_lev.save(le_level_subset->name.c_str());
1169 le_level_subset->levels = le_levelnb;
1170 goto_level(le_levelnb);
1176 le_previous_level_bt->event(event);
1177 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1180 goto_level(le_levelnb -1);
1182 le_rubber_bt->event(event);
1183 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1186 if(!cur_objects.empty())
1188 le_object_select_bt->event(event);
1189 if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1191 MouseCursor::set_current(mouse_select_object);
1194 le_object_properties_bt->event(event);
1195 if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1197 change_object_properties(selected_game_object);
1202 if(le_selection_mode == SQUARE)
1204 le_select_mode_one_bt->event(event);
1205 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1206 le_selection_mode = CURSOR;
1210 le_select_mode_two_bt->event(event);
1211 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1212 le_selection_mode = SQUARE;
1214 ButtonPanelMap::iterator it;
1215 le_tilegroup_bt->event(event);
1216 switch (le_tilegroup_bt->get_state())
1218 case BUTTON_CLICKED:
1219 Menu::set_current(select_tilegroup_menu);
1220 select_tilegroup_menu_effect.start(200);
1221 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1223 case BUTTON_WHEELUP:
1224 if(cur_tilegroup.empty())
1226 cur_tilegroup = tilegroups_map.begin()->first;
1230 it = tilegroups_map.find(cur_tilegroup);
1231 if((++it) == tilegroups_map.end())
1233 cur_tilegroup = tilegroups_map.begin()->first;
1237 cur_tilegroup = (*it).first;
1243 case BUTTON_WHEELDOWN:
1244 it = tilegroups_map.find(cur_tilegroup);
1245 if(it == tilegroups_map.begin())
1247 cur_tilegroup = tilegroups_map.rbegin()->first;
1251 if(--it != --tilegroups_map.begin())
1252 cur_tilegroup = (*it).first;
1254 cur_tilegroup = tilegroups_map.rbegin()->first;
1262 le_objects_bt->event(event);
1263 switch (le_objects_bt->get_state())
1265 case BUTTON_CLICKED:
1266 Menu::set_current(select_objects_menu);
1267 select_objects_menu_effect.start(200);
1268 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1270 case BUTTON_WHEELUP:
1271 it = objects_map.find(cur_objects);
1272 if(it == objects_map.end())
1274 cur_objects = objects_map.begin()->first;
1278 if(++it != objects_map.end())
1279 cur_objects = (*it).first;
1281 cur_objects = objects_map.begin()->first;
1285 case BUTTON_WHEELDOWN:
1286 it = objects_map.find(cur_objects);
1287 if(it == objects_map.begin())
1289 cur_objects = objects_map.rbegin()->first;
1293 if(--it != --objects_map.begin())
1294 cur_objects = (*it).first;
1296 cur_objects = objects_map.rbegin()->first;
1305 le_settings_bt->event(event);
1306 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1308 update_level_settings_menu();
1309 Menu::set_current(level_settings_menu);
1311 if(!cur_tilegroup.empty())
1313 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1315 if(pbutton->get_state() == BUTTON_CLICKED)
1317 le_current.Tile(pbutton->get_tag());
1321 else if(!cur_objects.empty())
1323 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1325 if(pbutton->get_state() == BUTTON_CLICKED)
1327 #if 0 // TODO FIXME XXX: New solution for this?
1328 le_current.Object(pbutton->get_drawable());
1334 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1336 if(pbutton->get_state() == BUTTON_CLICKED)
1338 active_tm = pbutton->get_tag();
1344 le_settings_bt->event(event);
1345 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1347 Menu::set_current(0);
1349 le_tilegroup_bt->event(event);
1350 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1352 Menu::set_current(0);
1354 le_objects_bt->event(event);
1355 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1357 Menu::set_current(0);
1362 if(!Menu::current() && !show_minimap)
1364 if(le_mouse_pressed[LEFT])
1366 if(MouseCursor::current() != mouse_select_object)
1368 if(le_current.IsTile())
1369 change(cursor_x, cursor_y, active_tm, le_current.tile);
1372 else if(le_mouse_clicked[LEFT])
1374 if(MouseCursor::current() == mouse_select_object)
1376 bool object_got_hit = false;
1377 base_type cursor_base;
1378 if(le_current.IsTile())
1380 cursor_base.x = cursor_x;
1381 cursor_base.y = cursor_y;
1383 else if(le_current.IsObject())
1385 cursor_base.x = cursor_x + pos_x;
1386 cursor_base.y = cursor_y + pos_y;
1388 cursor_base.width = 32;
1389 cursor_base.height = 32;
1391 for(std::vector<GameObject*>::iterator it =
1392 le_level->get_sector("main")->gameobjects.begin();
1393 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1394 MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
1398 if(rectcollision(cursor_base, mobj->base))
1400 selected_game_object = mobj;
1401 object_got_hit = true;
1408 selected_game_object = NULL;
1409 le_object_properties_bt->set_active(false);
1412 le_object_properties_bt->set_active(true);
1414 MouseCursor::set_current(mouse_cursor);
1421 //FIXME: objects interactions with the level editor should have a major improvement
1422 if(le_current.IsObject())
1424 le_level_changed = true;
1425 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1429 Camera& camera = *le_level->get_sector("main")->camera;
1431 le_level->get_sector("main")->bad_guys.push_back(
1432 new BadGuy(pbadguy->kind,
1433 cursor_x + camera.get_translation().x,
1434 cursor_y + camera.get_translation().y));
1435 le_level->get_sector("main")->gameobjects.push_back(le_level->get_sector("main")->bad_guys.back());
1442 le_mouse_clicked[LEFT] = false;
1448 if(!Menu::current())
1450 show_minimap = false;
1452 if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB)
1453 show_minimap = true;
1455 le_move_left_bt->event(event);
1456 le_move_right_bt->event(event);
1457 le_move_up_bt->event(event);
1458 le_move_down_bt->event(event);
1459 switch(le_move_left_bt->get_state())
1461 case BUTTON_PRESSED:
1462 pos_x -= KEYBOARD_SPEED;
1463 show_minimap = true;
1466 pos_x -= MOUSE_SPEED;
1467 show_minimap = true;
1469 case BUTTON_CLICKED:
1470 show_minimap = true;
1476 switch(le_move_right_bt->get_state())
1478 case BUTTON_PRESSED:
1479 pos_x += KEYBOARD_SPEED;
1480 show_minimap = true;
1483 pos_x += MOUSE_SPEED;
1484 show_minimap = true;
1486 case BUTTON_CLICKED:
1487 show_minimap = true;
1493 switch(le_move_up_bt->get_state())
1495 case BUTTON_PRESSED:
1496 pos_y -= KEYBOARD_SPEED;
1497 show_minimap = true;
1500 pos_y -= MOUSE_SPEED;
1501 show_minimap = true;
1503 case BUTTON_CLICKED:
1504 show_minimap = true;
1510 switch(le_move_down_bt->get_state())
1512 case BUTTON_PRESSED:
1513 pos_y += KEYBOARD_SPEED;
1514 show_minimap = true;
1517 pos_y += MOUSE_SPEED;
1518 show_minimap = true;
1520 case BUTTON_CLICKED:
1521 show_minimap = true;
1527 /* checking if pos_x and pos_y is within the limits... */
1528 if((unsigned)pos_x > (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w)
1529 pos_x = (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w;
1533 if((unsigned)pos_y > (le_level->get_sector("main")->solids->get_height() * 32) - screen->h)
1534 pos_y = (le_level->get_sector("main")->solids->get_height() * 32) - screen->h;
1540 void LevelEditor::highlight_selection()
1544 if(selection.x1 < selection.x2)
1554 if(selection.y1 < selection.y2)
1570 fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1573 void LevelEditor::change(float x, float y, int tm, unsigned int c)
1575 if(le_level != NULL)
1580 le_level_changed = true;
1582 switch(le_selection_mode)
1587 base_type cursor_base;
1590 cursor_base.width = 32;
1591 cursor_base.height = 32;
1593 /* if there is a bad guy over there, remove it */
1595 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1596 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1597 BadGuy* badguy = dynamic_cast<BadGuy*>((*it));
1600 if(rectcollision(cursor_base, badguy->base))
1603 le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(),
1604 le_level->get_sector("main")->gameobjects.end(), *it),
1605 le_level->get_sector("main")->gameobjects.end());
1613 if(selection.x1 < selection.x2)
1623 if(selection.y1 < selection.y2)
1639 /* if there is a bad guy over there, remove it */
1641 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1642 it != le_level->get_sector("main")->gameobjects.end(); ++it /* will be at end of loop */)
1644 MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);
1647 if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
1648 && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
1651 le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(), le_level->get_sector("main")->gameobjects.end(), *it), le_level->get_sector("main")->gameobjects.end());
1661 for(xx = x1; xx <= x2; xx++)
1662 for(yy = y1; yy <= y2; yy++)
1664 change(xx*32, yy*32, tm, c);
1674 void LevelEditor::testlevel()
1676 //Make sure a time value is set when testing the level
1677 if(le_level->time_left == 0)
1678 le_level->time_left = 250;
1680 le_level->save("test.stl");
1682 GameSession session("test.stl", ST_GL_TEST);
1684 player_status.reset();
1686 sound_manager->halt_music();
1688 Menu::set_current(NULL);
1691 void LevelEditor::showhelp()
1693 DrawingContext context;
1695 bool tmp_show_grid = le_show_grid;
1696 SelectionMode temp_le_selection_mode = le_selection_mode;
1697 le_selection_mode = NONE;
1698 show_selections = true;
1699 le_show_grid = false;
1700 le_help_shown = true;
1707 " - Supertux level editor tutorial - ",
1709 "To make your map, click the ",
1710 "tilegroup button and choose a ",
1712 "Pick a tile and simply hold down ",
1713 "the left mouse button over the map",
1714 "to \"paint\" your selection over",
1717 "There are three layers for painting",
1718 "tiles upon, Background layer,",
1719 "the Interactive layer, and the",
1720 "Foreground layer, which can be",
1721 "toggled by the BkGrd, IntAct and",
1722 "FrGrd buttons. The Foreground and",
1723 "Background layers do not effect",
1724 "Tux in the gameplay, but lie in",
1725 "front of him or lie behind him in",
1731 " - Supertux level editor tutorial - ",
1733 "The tiles placed on",
1734 "the Interactive layer are those",
1735 "which actually effect Tux in the",
1738 "Click the objects menu to put ",
1739 "bad guys and other objects in the",
1740 "game. Unlike placing tiles, you",
1741 "cannot \"paint\" enemies. Click",
1742 "them onto the screen one at a time.",
1744 "To change the settings of your",
1745 "level, click the button with the",
1746 "screwdriver and wrench. From here",
1747 "you can change the background,",
1748 "music, length of the level,",
1754 " - Supertux level editor tutorial - ",
1756 "You may have more than one level.",
1757 "Pressing the up and down buttons",
1758 "above the button bar lets you",
1759 "choose which one you are working on.",
1761 "If you would like to speed up your",
1762 "level editing, a useful trick is",
1763 "to learn the keyboard shortcuts.",
1764 "They are easy to learn, just right-",
1765 "click on the buttons.",
1767 "Have fun making levels! If you make",
1768 "some good ones, send them to us on",
1769 "the SuperTux mailing list!",
1773 char **text[] = { text1, text2, text3 };
1776 for(int i = 0; i < 3; i++)
1778 context.draw_gradient(Color(0,0,0), Color(255,255,255), LAYER_BACKGROUND0);
1779 drawinterface(context);
1781 context.draw_text_center(blue_text, "- Help -", Vector(0, 30), LAYER_GUI);
1783 for(unsigned int t = 0; t < sizeof(text[i])/sizeof(char *); t++)
1784 context.draw_text(white_text, text[i][t], Vector(5, 80+(t*white_text->get_height())), LAYER_GUI);
1786 sprintf(str,"Press any key to continue - Page %d/%d?", i, static_cast<int>(sizeof(text)));
1787 context.draw_text(gold_text, str, Vector(0, 0), LAYER_GUI);
1789 context.do_drawing();
1795 done_ = wait_for_event(event);
1800 show_selections = true;
1801 le_show_grid = tmp_show_grid;
1802 le_selection_mode = temp_le_selection_mode;
1803 le_help_shown = false;