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.
30 #include <SDL_image.h>
34 #include "leveleditor.h"
36 #include "screen/screen.h"
47 #include "resources.h"
48 #include "background.h"
51 /* definitions to aid development */
53 /* definitions that affect gameplay */
54 #define KEY_CURSOR_SPEED 32
55 #define KEY_CURSOR_FASTSPEED 64
57 /* when pagedown/up pressed speed:*/
58 #define PAGE_CURSOR_SPEED 13*32
60 #define MOUSE_LEFT_MARGIN 80
61 #define MOUSE_RIGHT_MARGIN (560-32)
64 #define KEYBOARD_SPEED 140
65 #define MOUSE_SPEED 40
68 #define SELECT_W 2 // size of the selections lines
69 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
71 enum { TM_IA, TM_BG, TM_FG };
73 LevelEditor::LevelEditor()
75 level_subsets = dsubdirs("/levels", "level1.stl");
76 le_level_subset = new LevelSubset;
80 selected_game_object = NULL;
84 show_selections = true;
89 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
90 le_level_changed = false;
91 le_help_shown = false;
93 le_mouse_pressed[LEFT] = false;
94 le_mouse_pressed[RIGHT] = false;
96 le_mouse_clicked[LEFT] = false;
97 le_mouse_clicked[RIGHT] = false;
99 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
101 select_tilegroup_menu_effect.init(false);
102 select_objects_menu_effect.init(false);
103 display_level_info.init(false);
106 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
107 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
108 le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
109 le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
110 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
111 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
112 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
113 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
114 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
115 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
116 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
117 le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
118 le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
119 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
120 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
121 le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
122 le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
123 le_object_properties_bt->set_active(false);
125 mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
126 mouse_select_object->set_mid(16,16);
128 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
129 le_tilemap_panel->set_button_size(32,10);
130 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
131 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0), TM_IA);
132 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
133 le_tilemap_panel->highlight_last(true);
134 le_tilemap_panel->set_last_clicked(TM_IA);
140 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
143 LevelEditor::~LevelEditor()
145 SDL_EnableKeyRepeat(0, 0); // disables key repeating
149 delete leveleditor_menu;
150 delete subset_load_menu;
151 delete subset_new_menu;
152 delete subset_settings_menu;
153 delete level_settings_menu;
154 delete select_tilegroup_menu;
155 delete select_objects_menu;
156 delete le_save_level_bt;
158 delete le_test_level_bt;
159 delete le_next_level_bt;
160 delete le_previous_level_bt;
161 delete le_move_right_bt;
162 delete le_move_left_bt;
163 delete le_move_up_bt;
164 delete le_move_down_bt;
166 delete le_select_mode_one_bt;
167 delete le_select_mode_two_bt;
168 delete le_settings_bt;
169 delete le_tilegroup_bt;
170 delete le_objects_bt;
171 delete le_tilemap_panel;
172 delete le_object_select_bt;
173 delete le_object_properties_bt;
174 delete mouse_select_object;
176 delete le_level_subset;
179 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
180 i != tilegroups_map.end(); ++i)
184 for(ButtonPanelMap::iterator i = objects_map.begin();
185 i != objects_map.end(); ++i)
191 int LevelEditor::run(char* filename)
193 int last_time, now_time, i;
194 DrawingContext context;
199 sound_manager->halt_music();
201 while (SDL_PollEvent(&event))
205 if(load_level_subset(filename))
210 last_time = SDL_GetTicks();
215 if(Menu::current() == select_tilegroup_menu)
217 if(select_tilegroup_menu_effect.check())
219 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
223 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
225 else if(Menu::current() == select_objects_menu)
227 if(select_objects_menu_effect.check())
229 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
232 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
237 /* making events results to be in order */
240 context.set_translation(Vector(pos_x, pos_y));
244 fillrect(0, 0, screen->w, screen->h, 0, 0, 0);
246 /* draw editor interface */
247 context.set_translation(Vector(0, 0));
248 drawinterface(context);
250 Menu* menu = Menu::current();
256 if(menu == leveleditor_menu)
258 switch (leveleditor_menu->check())
260 case MNID_RETURNLEVELEDITOR:
262 Menu::set_current(0);
264 Menu::set_current(leveleditor_menu);
266 case MNID_SUBSETSETTINGS:
267 update_subset_settings_menu();
269 case MNID_QUITLEVELEDITOR:
274 else if(menu == level_settings_menu)
276 switch (level_settings_menu->check())
279 apply_level_settings_menu();
280 Menu::set_current(NULL);
287 else if(menu == select_tilegroup_menu)
290 switch (it = select_tilegroup_menu->check())
295 cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
296 Menu::set_current(0);
303 else if(menu == select_objects_menu)
306 switch (it = select_objects_menu->check())
311 cur_objects = select_objects_menu->get_item_by_id(it).text;
314 Menu::set_current(0);
319 else if(menu == subset_load_menu)
321 switch (i = subset_load_menu->check())
328 if(load_level_subset(level_subsets.item[i-1]))
334 else if(menu == subset_new_menu)
336 if(subset_new_menu->item[2].input[0] == '\0')
337 subset_new_menu->item[3].kind = MN_DEACTIVE;
340 subset_new_menu->item[3].kind = MN_ACTION;
342 switch (i = subset_new_menu->check())
344 case MNID_CREATESUBSET:
345 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
346 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
347 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
349 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
351 Menu::set_current(subset_settings_menu);
356 else if(menu == subset_settings_menu)
358 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 )
359 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
361 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
363 switch (i = subset_settings_menu->check())
365 case MNID_SUBSETSAVECHANGES:
366 save_subset_settings_menu();
367 Menu::set_current(leveleditor_menu);
373 MouseCursor::current()->draw(context);
380 ++global_frame_counter;
383 now_time = SDL_GetTicks();
384 if (now_time < last_time + FPS)
385 SDL_Delay(last_time + FPS - now_time); /* delay some time */
387 context.do_drawing();
393 int LevelEditor::load_level_subset(char *filename)
395 le_level_subset->load(filename);
396 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
398 goto_level(le_levelnb);
400 //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
402 Menu::set_current(NULL);
407 void LevelEditor::init_menus()
411 leveleditor_menu = new Menu();
412 subset_load_menu = new Menu();
413 subset_new_menu = new Menu();
414 subset_settings_menu = new Menu();
415 level_settings_menu = new Menu();
416 select_tilegroup_menu = new Menu();
417 select_objects_menu = new Menu();
419 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
420 leveleditor_menu->additem(MN_HL,"",0,0);
421 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
422 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
423 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
424 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
425 leveleditor_menu->additem(MN_HL,"",0,0);
426 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
428 Menu::set_current(leveleditor_menu);
430 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
431 subset_load_menu->additem(MN_HL, "", 0, 0);
433 for(i = 0; i < level_subsets.num_items; ++i)
435 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
437 subset_load_menu->additem(MN_HL,"",0,0);
438 subset_load_menu->additem(MN_BACK,"Back",0,0);
440 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
441 subset_new_menu->additem(MN_HL,"",0,0);
442 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
443 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
444 subset_new_menu->additem(MN_HL,"",0,0);
445 subset_new_menu->additem(MN_BACK,"Back",0,0);
447 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
448 subset_settings_menu->additem(MN_HL,"",0,0);
449 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
450 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
451 subset_settings_menu->additem(MN_HL,"",0,0);
452 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
453 subset_settings_menu->additem(MN_HL,"",0,0);
454 subset_settings_menu->additem(MN_BACK,"Back",0,0);
456 level_settings_menu->arrange_left = true;
457 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
458 level_settings_menu->additem(MN_HL,"",0,0);
459 level_settings_menu->additem(MN_TEXTFIELD, "Name ",0,0,MNID_NAME);
460 level_settings_menu->additem(MN_TEXTFIELD, "Author ",0,0,MNID_AUTHOR);
461 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
462 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
463 level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
464 level_settings_menu->additem(MN_NUMFIELD, "Length ",0,0,MNID_LENGTH);
465 level_settings_menu->additem(MN_NUMFIELD, "Height ",0,0,MNID_HEIGHT);
466 level_settings_menu->additem(MN_NUMFIELD, "Time ",0,0,MNID_TIME);
467 level_settings_menu->additem(MN_NUMFIELD, "Gravity ",0,0,MNID_GRAVITY);
468 level_settings_menu->additem(MN_NUMFIELD, "Bg-Img-Speed",0,0,MNID_BGSPEED);
469 level_settings_menu->additem(MN_NUMFIELD, "Top Red ",0,0,MNID_TopRed);
470 level_settings_menu->additem(MN_NUMFIELD, "Top Green ",0,0,MNID_TopGreen);
471 level_settings_menu->additem(MN_NUMFIELD, "Top Blue ",0,0,MNID_TopBlue);
472 level_settings_menu->additem(MN_NUMFIELD, "Bottom Red ",0,0,MNID_BottomRed);
473 level_settings_menu->additem(MN_NUMFIELD, "Bottom Green",0,0,MNID_BottomGreen);
474 level_settings_menu->additem(MN_NUMFIELD, "Bottom Blue ",0,0,MNID_BottomBlue);
475 level_settings_menu->additem(MN_HL,"",0,0);
476 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
478 select_tilegroup_menu->arrange_left = true;
479 select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
480 select_tilegroup_menu->additem(MN_HL,"",0,0);
481 std::set<TileGroup>* tilegroups = TileManager::tilegroups();
483 for(std::set<TileGroup>::iterator it = tilegroups->begin();
484 it != tilegroups->end(); ++it )
486 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
488 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
491 for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
492 sit != (*it).tiles.end(); ++sit, ++i)
494 Tile& tile = *(TileManager::instance()->get(*sit));
496 if(tile.editor_images.size() > 0)
497 image = tile.editor_images[0];
498 else if(tile.images.size() > 0)
499 image = tile.images[0];
501 // TODO use some notile image...
504 Button* button = new Button(image, it->name, SDLKey(SDLK_a + i),
506 tilegroups_map[it->name]->additem(button, *sit);
509 select_tilegroup_menu->additem(MN_HL,"",0,0);
511 select_objects_menu->arrange_left = true;
512 select_objects_menu->additem(MN_LABEL,"Objects",0,0);
513 select_objects_menu->additem(MN_HL,"",0,0);
515 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
516 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
518 for(int i = 0; i < NUM_BadGuyKinds; ++i)
520 // BadGuy bad_tmp(BadGuyKind(i), 0, 0);
521 // objects_map["BadGuys"]->additem(new Button(0, "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
522 /* FIXME: maybe addbutton should already have a parameter for the surface
523 objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
524 BadGuy(BadGuyKind(i),
525 objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
526 objects_map["BadGuys"]->manipulate_button(i)->get_pos().y
530 select_objects_menu->additem(MN_HL,"",0,0);
534 void LevelEditor::update_level_settings_menu()
539 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_level->name.c_str());
540 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_level->author.c_str());
542 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
543 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
544 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
545 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
546 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
547 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
549 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)
550 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
551 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)
552 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
553 /* if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_level->get_sector("main")->particlesystem.c_str())) != -1)
554 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;*/
556 sprintf(str,"%d",le_level->get_sector("main")->solids->get_width());
557 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
558 sprintf(str,"%d",le_level->get_sector("main")->solids->get_height());
559 level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
560 sprintf(str,"%d",le_level->time_left);
561 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
562 sprintf(str,"%2.0f",le_level->get_sector("main")->gravity);
563 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
564 sprintf(str,"%2.2f", le_level->get_sector("main")->background->get_speed());
565 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
566 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().red);
567 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
568 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().green);
569 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
570 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().blue);
571 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
572 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().red);
573 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
574 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().green);
575 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
576 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().blue);
577 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
580 void LevelEditor::update_subset_settings_menu()
582 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
583 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
586 void LevelEditor::apply_level_settings_menu()
590 le_level_changed = true;
592 le_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
593 le_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
595 if(le_level->get_sector("main")->background->get_image().compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
597 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));
601 /* if(le_level->get_sector("main")->particlesystem.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
603 le_level->->get_sector("main")->particlesystem = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
608 le_level->load_gfx();
611 le_level->get_sector("main")->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
613 le_level->get_sector("main")->solids->resize(
614 atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input),
615 atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
616 le_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
617 le_level->get_sector("main")->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
618 le_level->get_sector("main")->background->set_gradient(Color(
619 atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input),
620 atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input),
621 atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input)), Color(
622 atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input),
623 atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input),
624 atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input)));
627 void LevelEditor::save_subset_settings_menu()
629 le_level_subset->title = subset_settings_menu->item[2].input;
630 le_level_subset->description = subset_settings_menu->item[3].input;
631 le_level_subset->save();
632 le_level_changed = false;
635 void LevelEditor::unload_level()
640 // TODO get level number
641 sprintf(str,"Save changes to level %d of %s?", 0/*le_level*/,le_level_subset->name.c_str());
642 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
643 if(confirm_dialog(surf, str))
645 le_level->save(le_level_subset->get_level_filename(le_levelnb));
652 le_level_changed = false;
655 void LevelEditor::goto_level(int levelnb)
658 le_level = new Level();
659 le_level->load(le_level_subset->get_level_filename(levelnb));
660 display_level_info.start(2500);
661 le_levelnb = levelnb;
664 void LevelEditor::drawminimap()
667 // if(le_level == NULL)
671 if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 4)
673 else if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 2)
677 int left_offset = (screen->w - 64 - le_level->get_sector("main")->solids->get_width()*mini_tile_width) / 2;
679 int mini_tile_height;
680 if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 4)
681 mini_tile_height = 4;
682 else if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 2)
683 mini_tile_height = 2;
685 mini_tile_height = 1;
687 for (unsigned int y = 0; y < le_level->get_sector("main")->solids->get_height(); ++y)
688 for (unsigned int x = 0; x < le_level->get_sector("main")->solids->get_width(); ++x)
691 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
692 mini_tile_width , mini_tile_height, le_level->bg_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
694 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
695 mini_tile_width , mini_tile_height, le_level->ia_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
697 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
698 mini_tile_width , mini_tile_height, le_level->fg_tiles[y + le_level->get_sector("main")->solids->get_width() + x]);
702 fillrect(left_offset, 0,
703 le_level->get_sector("main")->solids->get_width()*mini_tile_width, le_level->get_sector("main")->solids->get_height()*mini_tile_height,
706 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
707 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
709 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
710 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
712 fillrect(left_offset + (pos_x/32)*mini_tile_width + (VISIBLE_TILES_X-3)*mini_tile_width - 2, (pos_y/32)*mini_tile_height,
713 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
715 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height + (VISIBLE_TILES_Y-1)*mini_tile_height - 2,
716 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
721 void LevelEditor::drawinterface(DrawingContext &context)
728 /* draw a grid (if selected) */
731 for(x = 0; x < VISIBLE_TILES_X; x++)
732 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
733 for(y = 0; y < VISIBLE_TILES_Y; y++)
734 fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
738 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
741 if(show_selections && MouseCursor::current() != mouse_select_object)
743 if(le_selection_mode == CURSOR)
745 if(le_current.IsTile())
746 context.draw_surface(le_selection, Vector(cursor_x - pos_x, cursor_y - pos_y), LAYER_GUI);
748 else if(le_selection_mode == SQUARE)
751 highlight_selection();
752 /* draw current selection */
753 w = selection.x2 - selection.x1;
754 h = selection.y2 - selection.y1;
755 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
756 context.draw_filled_rect(Vector(selection.x1 - pos_x + w, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
757 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y + h), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
758 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
763 /* draw button bar */
764 context.draw_filled_rect(Vector(screen->w - 64, 0), Vector(64, screen->h), Color(50, 50, 50,255), LAYER_GUI);
766 if(le_current.IsTile())
768 // le_level->get_sector("main")->solids->draw(context);
770 /*screen->w - 32, screen->h - 32, le_current.tile);
771 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
772 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);*/
774 #if 0 // XXX FIXME TODO: Do we have a new solution for draw_on_screen()?
775 if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
777 le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
778 le_current.obj->draw_on_screen(cursor_x,cursor_y);
782 if(mouse_select_object && selected_game_object != NULL)
784 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);
785 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);
786 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);
787 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);
792 le_save_level_bt->draw(context);
793 le_exit_bt->draw(context);
794 le_test_level_bt->draw(context);
795 le_next_level_bt->draw(context);
796 le_previous_level_bt->draw(context);
797 le_rubber_bt->draw(context);
798 if(le_selection_mode == SQUARE)
799 le_select_mode_one_bt->draw(context);
800 else if(le_selection_mode == CURSOR)
801 le_select_mode_two_bt->draw(context);
802 le_settings_bt->draw(context);
803 le_move_right_bt->draw(context);
804 le_move_left_bt->draw(context);
805 le_move_up_bt->draw(context);
806 le_move_down_bt->draw(context);
807 le_tilegroup_bt->draw(context);
808 le_objects_bt->draw(context);
809 if(!cur_tilegroup.empty())
810 tilegroups_map[cur_tilegroup]->draw(context);
811 else if(!cur_objects.empty())
813 objects_map[cur_objects]->draw(context);
816 le_tilemap_panel->draw(context);
818 if(!cur_objects.empty())
820 le_object_select_bt->draw(context);
821 le_object_properties_bt->draw(context);
824 sprintf(str, "%d/%d", le_levelnb,le_level_subset->levels);
825 context.draw_text(white_text, str, Vector((le_level_subset->levels < 10) ? -10 : 0, 16), LAYER_GUI);
828 context.draw_text(white_small_text, "F1 for Help", Vector(10, 430), LAYER_GUI);
830 if(display_level_info.check())
831 context.draw_text_center(white_text, le_level->name.c_str(), Vector(0, 0), LAYER_GUI);
836 context.draw_text(white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", Vector(10, 430), LAYER_GUI);
838 context.draw_text(white_small_text, "No Level Subset loaded", Vector(10, 430), LAYER_GUI);
843 void LevelEditor::drawlevel(DrawingContext& context)
848 /* Draw the real background */
849 le_level->get_sector("main")->background->draw(context);
851 if(le_current.IsTile())
853 //le_level->get_sector("main")->solids->draw(context);
855 Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
856 if(!TileManager::instance()->get(le_current.tile)->images.empty())
857 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);*/
859 #if 0 // XXX FIXME TODO: Do we have a new solution for move_to()?
860 if(le_current.IsObject())
862 le_current.obj->move_to(cursor_x, cursor_y);
866 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
868 le_level->get_sector("main")->solids->draw(context);
870 // FIXME: make tiles to be drawn semi-transparent when not selected
872 for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_level->get_section("main")->height; ++y)
873 for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
876 if(active_tm == TM_BG)
881 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
882 le_level->bg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
883 (x + (int)(pos_x / 32))],a);
885 if(active_tm == TM_IA)
890 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
891 le_level->ia_tiles[ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width +
892 (x + (int)(pos_x / 32))],a);
895 if(active_tm == TM_FG)
900 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
901 le_level->fg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
902 (x + (int)(pos_x / 32))],a);
904 /* draw whats inside stuff when cursor is selecting those */
905 /* (draw them all the time - is this the right behaviour?) */
906 Tile* edit_image = TileManager::instance()->get(
908 [ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width + (x + (int)(pos_x / 32))]);
909 if(edit_image && !edit_image->editor_images.empty())
910 edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
914 /* Draw the Bad guys: */
915 for (std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
916 it != le_level->get_sector("main")->gameobjects.end(); ++it)
918 BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
922 /* to support frames: img_bsod_left[(frame / 5) % 4] */
923 badguy->draw(context);
926 /* Draw the player: */
927 /* for now, the position is fixed at (100, 240) */
928 largetux.walk_right->draw(context, Vector(100 - pos_x, 240 - pos_y), LAYER_OBJECTS-1);
931 void LevelEditor::change_object_properties(GameObject *pobj)
933 DrawingContext context;
935 Menu* object_properties_menu = new Menu();
938 std::string type = typeid(pobj).name();
939 object_properties_menu->additem(MN_LABEL, type + " Properties",0,0);
940 object_properties_menu->additem(MN_HL,"",0,0);
942 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
945 object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
946 for(int i = 0; i < NUM_BadGuyKinds; ++i)
948 string_list_add_item(object_properties_menu->get_item_by_id(1).list,
949 badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
951 object_properties_menu->get_item_by_id(1).list->active_item = i;
953 object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
956 object_properties_menu->additem(MN_HL,"",0,0);
957 object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
959 Menu::set_current(object_properties_menu);
965 while (SDL_PollEvent(&event))
967 object_properties_menu->event(event);
970 //cap_screen->draw(0,0);
972 object_properties_menu->draw(context);
973 object_properties_menu->action();
975 switch (object_properties_menu->check())
979 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
981 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
982 pbad->kind = badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
983 pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
992 if(Menu::current() == NULL)
995 mouse_cursor->draw(context);
996 // context.draw_filled_rect();
1000 //delete cap_screen;
1001 Menu::set_current(0);
1002 delete object_properties_menu;
1006 void LevelEditor::checkevents()
1013 keymod = SDL_GetModState();
1015 while(SDL_PollEvent(&event))
1017 if (Menu::current())
1019 Menu::current()->event(event);
1020 if(!le_level && !Menu::current())
1021 Menu::set_current(leveleditor_menu);
1025 mouse_cursor->set_state(MC_NORMAL);
1027 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1028 if(event.type == SDL_KEYDOWN
1029 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1030 && (event.motion.x > 0
1031 && event.motion.x < screen->w - 64 &&
1032 event.motion.y > 0 && event.motion.y < screen->h)))
1036 case SDL_KEYDOWN: // key pressed
1037 key = event.key.keysym.sym;
1041 Menu::set_current(leveleditor_menu);
1044 if(le_level != NULL)
1052 cursor_x = (le_level->get_sector("main")->solids->get_width() * 32) - 32;
1056 le_show_grid = !le_show_grid;
1062 case SDL_MOUSEBUTTONDOWN:
1063 if(event.button.button == SDL_BUTTON_LEFT)
1065 le_mouse_pressed[LEFT] = true;
1067 selection.x1 = event.motion.x + pos_x;
1068 selection.y1 = event.motion.y + pos_y;
1069 selection.x2 = event.motion.x + pos_x;
1070 selection.y2 = event.motion.y + pos_y;
1072 else if(event.button.button == SDL_BUTTON_RIGHT)
1074 le_mouse_pressed[RIGHT] = true;
1077 case SDL_MOUSEBUTTONUP:
1078 if(event.button.button == SDL_BUTTON_LEFT)
1080 le_mouse_pressed[LEFT] = false;
1081 le_mouse_clicked[LEFT] = true;
1083 else if(event.button.button == SDL_BUTTON_RIGHT)
1085 le_mouse_pressed[RIGHT] = false;
1086 le_mouse_clicked[RIGHT] = true;
1089 case SDL_MOUSEMOTION:
1091 if(!Menu::current())
1096 if(le_current.IsTile())
1098 cursor_x = ((int)(pos_x + x) / 32) * 32;
1099 cursor_y = ((int)(pos_y + y) / 32) * 32;
1107 if(le_mouse_pressed[LEFT])
1109 selection.x2 = x + pos_x;
1110 selection.y2 = y + pos_y;
1113 if(le_mouse_pressed[RIGHT])
1115 pos_x += -1 * event.motion.xrel;
1116 pos_y += -1 * event.motion.yrel;
1124 else if(event.type == SDL_QUIT) /* window closing */
1130 if(le_level != NULL)
1132 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 &&
1133 event.motion.y > 0 && event.motion.y < screen->h)))
1135 le_mouse_pressed[LEFT] = false;
1136 le_mouse_pressed[RIGHT] = false;
1138 if(!Menu::current())
1140 /* Check for button events */
1141 le_test_level_bt->event(event);
1142 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1144 le_save_level_bt->event(event);
1145 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1146 le_level->save(le_level_subset->name.c_str());
1147 le_exit_bt->event(event);
1148 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1150 Menu::set_current(leveleditor_menu);
1152 le_next_level_bt->event(event);
1153 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1155 if(le_levelnb < le_level_subset->levels)
1157 goto_level(le_levelnb+1);
1163 sprintf(str,"Level %d doesn't exist. Create it?",le_levelnb+1);
1164 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
1165 if(confirm_dialog(surf, str))
1167 new_lev.save(le_level_subset->name.c_str());
1168 le_level_subset->levels = le_levelnb;
1169 goto_level(le_levelnb);
1175 le_previous_level_bt->event(event);
1176 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1179 goto_level(le_levelnb -1);
1181 le_rubber_bt->event(event);
1182 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1185 if(!cur_objects.empty())
1187 le_object_select_bt->event(event);
1188 if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1190 MouseCursor::set_current(mouse_select_object);
1193 le_object_properties_bt->event(event);
1194 if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1196 change_object_properties(selected_game_object);
1201 if(le_selection_mode == SQUARE)
1203 le_select_mode_one_bt->event(event);
1204 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1205 le_selection_mode = CURSOR;
1209 le_select_mode_two_bt->event(event);
1210 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1211 le_selection_mode = SQUARE;
1213 ButtonPanelMap::iterator it;
1214 le_tilegroup_bt->event(event);
1215 switch (le_tilegroup_bt->get_state())
1217 case BUTTON_CLICKED:
1218 Menu::set_current(select_tilegroup_menu);
1219 select_tilegroup_menu_effect.start(200);
1220 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1222 case BUTTON_WHEELUP:
1223 if(cur_tilegroup.empty())
1225 cur_tilegroup = tilegroups_map.begin()->first;
1229 it = tilegroups_map.find(cur_tilegroup);
1230 if((++it) == tilegroups_map.end())
1232 cur_tilegroup = tilegroups_map.begin()->first;
1236 cur_tilegroup = (*it).first;
1242 case BUTTON_WHEELDOWN:
1243 it = tilegroups_map.find(cur_tilegroup);
1244 if(it == tilegroups_map.begin())
1246 cur_tilegroup = tilegroups_map.rbegin()->first;
1250 if(--it != --tilegroups_map.begin())
1251 cur_tilegroup = (*it).first;
1253 cur_tilegroup = tilegroups_map.rbegin()->first;
1261 le_objects_bt->event(event);
1262 switch (le_objects_bt->get_state())
1264 case BUTTON_CLICKED:
1265 Menu::set_current(select_objects_menu);
1266 select_objects_menu_effect.start(200);
1267 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1269 case BUTTON_WHEELUP:
1270 it = objects_map.find(cur_objects);
1271 if(it == objects_map.end())
1273 cur_objects = objects_map.begin()->first;
1277 if(++it != objects_map.end())
1278 cur_objects = (*it).first;
1280 cur_objects = objects_map.begin()->first;
1284 case BUTTON_WHEELDOWN:
1285 it = objects_map.find(cur_objects);
1286 if(it == objects_map.begin())
1288 cur_objects = objects_map.rbegin()->first;
1292 if(--it != --objects_map.begin())
1293 cur_objects = (*it).first;
1295 cur_objects = objects_map.rbegin()->first;
1304 le_settings_bt->event(event);
1305 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1307 update_level_settings_menu();
1308 Menu::set_current(level_settings_menu);
1310 if(!cur_tilegroup.empty())
1312 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1314 if(pbutton->get_state() == BUTTON_CLICKED)
1316 le_current.Tile(pbutton->get_tag());
1320 else if(!cur_objects.empty())
1322 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1324 if(pbutton->get_state() == BUTTON_CLICKED)
1326 #if 0 // TODO FIXME XXX: New solution for this?
1327 le_current.Object(pbutton->get_drawable());
1333 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1335 if(pbutton->get_state() == BUTTON_CLICKED)
1337 active_tm = pbutton->get_tag();
1343 le_settings_bt->event(event);
1344 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1346 Menu::set_current(0);
1348 le_tilegroup_bt->event(event);
1349 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1351 Menu::set_current(0);
1353 le_objects_bt->event(event);
1354 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1356 Menu::set_current(0);
1361 if(!Menu::current() && !show_minimap)
1363 if(le_mouse_pressed[LEFT])
1365 if(MouseCursor::current() != mouse_select_object)
1367 if(le_current.IsTile())
1368 change(cursor_x, cursor_y, active_tm, le_current.tile);
1371 else if(le_mouse_clicked[LEFT])
1373 if(MouseCursor::current() == mouse_select_object)
1375 bool object_got_hit = false;
1376 base_type cursor_base;
1377 if(le_current.IsTile())
1379 cursor_base.x = cursor_x;
1380 cursor_base.y = cursor_y;
1382 else if(le_current.IsObject())
1384 cursor_base.x = cursor_x + pos_x;
1385 cursor_base.y = cursor_y + pos_y;
1387 cursor_base.width = 32;
1388 cursor_base.height = 32;
1390 for(std::vector<GameObject*>::iterator it =
1391 le_level->get_sector("main")->gameobjects.begin();
1392 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1393 MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
1397 if(rectcollision(cursor_base, mobj->base))
1399 selected_game_object = mobj;
1400 object_got_hit = true;
1407 selected_game_object = NULL;
1408 le_object_properties_bt->set_active(false);
1411 le_object_properties_bt->set_active(true);
1413 MouseCursor::set_current(mouse_cursor);
1420 //FIXME: objects interactions with the level editor should have a major improvement
1421 if(le_current.IsObject())
1423 le_level_changed = true;
1424 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1428 Camera& camera = *le_level->get_sector("main")->camera;
1430 le_level->get_sector("main")->bad_guys.push_back(
1431 new BadGuy(pbadguy->kind,
1432 cursor_x + camera.get_translation().x,
1433 cursor_y + camera.get_translation().y));
1434 le_level->get_sector("main")->gameobjects.push_back(le_level->get_sector("main")->bad_guys.back());
1441 le_mouse_clicked[LEFT] = false;
1447 if(!Menu::current())
1449 show_minimap = false;
1451 if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB)
1452 show_minimap = true;
1454 le_move_left_bt->event(event);
1455 le_move_right_bt->event(event);
1456 le_move_up_bt->event(event);
1457 le_move_down_bt->event(event);
1458 switch(le_move_left_bt->get_state())
1460 case BUTTON_PRESSED:
1461 pos_x -= KEYBOARD_SPEED;
1462 show_minimap = true;
1465 pos_x -= MOUSE_SPEED;
1466 show_minimap = true;
1468 case BUTTON_CLICKED:
1469 show_minimap = true;
1475 switch(le_move_right_bt->get_state())
1477 case BUTTON_PRESSED:
1478 pos_x += KEYBOARD_SPEED;
1479 show_minimap = true;
1482 pos_x += MOUSE_SPEED;
1483 show_minimap = true;
1485 case BUTTON_CLICKED:
1486 show_minimap = true;
1492 switch(le_move_up_bt->get_state())
1494 case BUTTON_PRESSED:
1495 pos_y -= KEYBOARD_SPEED;
1496 show_minimap = true;
1499 pos_y -= MOUSE_SPEED;
1500 show_minimap = true;
1502 case BUTTON_CLICKED:
1503 show_minimap = true;
1509 switch(le_move_down_bt->get_state())
1511 case BUTTON_PRESSED:
1512 pos_y += KEYBOARD_SPEED;
1513 show_minimap = true;
1516 pos_y += MOUSE_SPEED;
1517 show_minimap = true;
1519 case BUTTON_CLICKED:
1520 show_minimap = true;
1526 /* checking if pos_x and pos_y is within the limits... */
1527 if((unsigned)pos_x > (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w)
1528 pos_x = (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w;
1532 if((unsigned)pos_y > (le_level->get_sector("main")->solids->get_height() * 32) - screen->h)
1533 pos_y = (le_level->get_sector("main")->solids->get_height() * 32) - screen->h;
1539 void LevelEditor::highlight_selection()
1543 if(selection.x1 < selection.x2)
1553 if(selection.y1 < selection.y2)
1569 fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1572 void LevelEditor::change(float x, float y, int tm, unsigned int c)
1574 if(le_level != NULL)
1579 le_level_changed = true;
1581 switch(le_selection_mode)
1586 base_type cursor_base;
1589 cursor_base.width = 32;
1590 cursor_base.height = 32;
1592 /* if there is a bad guy over there, remove it */
1594 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1595 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1596 BadGuy* badguy = dynamic_cast<BadGuy*>((*it));
1599 if(rectcollision(cursor_base, badguy->base))
1602 le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(),
1603 le_level->get_sector("main")->gameobjects.end(), *it),
1604 le_level->get_sector("main")->gameobjects.end());
1612 if(selection.x1 < selection.x2)
1622 if(selection.y1 < selection.y2)
1638 /* if there is a bad guy over there, remove it */
1640 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1641 it != le_level->get_sector("main")->gameobjects.end(); ++it /* will be at end of loop */)
1643 MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);
1646 if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
1647 && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
1650 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());
1660 for(xx = x1; xx <= x2; xx++)
1661 for(yy = y1; yy <= y2; yy++)
1663 change(xx*32, yy*32, tm, c);
1673 void LevelEditor::testlevel()
1675 //Make sure a time value is set when testing the level
1676 if(le_level->time_left == 0)
1677 le_level->time_left = 250;
1679 le_level->save("test.stl");
1681 GameSession session("test.stl", ST_GL_TEST);
1683 player_status.reset();
1685 sound_manager->halt_music();
1687 Menu::set_current(NULL);
1690 void LevelEditor::showhelp()
1692 DrawingContext context;
1694 bool tmp_show_grid = le_show_grid;
1695 SelectionMode temp_le_selection_mode = le_selection_mode;
1696 le_selection_mode = NONE;
1697 show_selections = true;
1698 le_show_grid = false;
1699 le_help_shown = true;
1706 " - Supertux level editor tutorial - ",
1708 "To make your map, click the ",
1709 "tilegroup button and choose a ",
1711 "Pick a tile and simply hold down ",
1712 "the left mouse button over the map",
1713 "to \"paint\" your selection over",
1716 "There are three layers for painting",
1717 "tiles upon, Background layer,",
1718 "the Interactive layer, and the",
1719 "Foreground layer, which can be",
1720 "toggled by the BkGrd, IntAct and",
1721 "FrGrd buttons. The Foreground and",
1722 "Background layers do not effect",
1723 "Tux in the gameplay, but lie in",
1724 "front of him or lie behind him in",
1730 " - Supertux level editor tutorial - ",
1732 "The tiles placed on",
1733 "the Interactive layer are those",
1734 "which actually effect Tux in the",
1737 "Click the objects menu to put ",
1738 "bad guys and other objects in the",
1739 "game. Unlike placing tiles, you",
1740 "cannot \"paint\" enemies. Click",
1741 "them onto the screen one at a time.",
1743 "To change the settings of your",
1744 "level, click the button with the",
1745 "screwdriver and wrench. From here",
1746 "you can change the background,",
1747 "music, length of the level,",
1753 " - Supertux level editor tutorial - ",
1755 "You may have more than one level.",
1756 "Pressing the up and down buttons",
1757 "above the button bar lets you",
1758 "choose which one you are working on.",
1760 "If you would like to speed up your",
1761 "level editing, a useful trick is",
1762 "to learn the keyboard shortcuts.",
1763 "They are easy to learn, just right-",
1764 "click on the buttons.",
1766 "Have fun making levels! If you make",
1767 "some good ones, send them to us on",
1768 "the SuperTux mailing list!",
1772 char **text[] = { text1, text2, text3 };
1775 for(int i = 0; i < 3; i++)
1777 context.draw_gradient(Color(0,0,0), Color(255,255,255), LAYER_BACKGROUND0);
1778 drawinterface(context);
1780 context.draw_text_center(blue_text, "- Help -", Vector(0, 30), LAYER_GUI);
1782 for(unsigned int t = 0; t < sizeof(text[i])/sizeof(char *); t++)
1783 context.draw_text(white_text, text[i][t], Vector(5, 80+(t*white_text->get_height())), LAYER_GUI);
1785 sprintf(str,"Press any key to continue - Page %d/%d?", i, sizeof(text));
1786 context.draw_text(gold_text, str, Vector(0, 0), LAYER_GUI);
1788 context.do_drawing();
1794 done_ = wait_for_event(event);
1799 show_selections = true;
1800 le_show_grid = tmp_show_grid;
1801 le_selection_mode = temp_le_selection_mode;
1802 le_help_shown = false;