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 "video/screen.h"
38 #include "app/globals.h"
39 #include "app/setup.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 /* Frames per second: */
74 #define FPS (1000 / 25)
76 enum { TM_IA, TM_BG, TM_FG };
78 LevelEditor::LevelEditor()
80 level_subsets = FileSystem::dsubdirs("/levels", "level1.stl");
81 le_level_subset = new LevelSubset;
85 selected_game_object = NULL;
89 show_selections = true;
94 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
95 le_level_changed = false;
96 le_help_shown = false;
98 le_mouse_pressed[LEFT] = false;
99 le_mouse_pressed[RIGHT] = false;
101 le_mouse_clicked[LEFT] = false;
102 le_mouse_clicked[RIGHT] = false;
104 le_selection = new Surface(datadir + "/images/leveleditor/select.png", true);
106 select_tilegroup_menu_effect.init(false);
107 select_objects_menu_effect.init(false);
108 display_level_info.init(false);
111 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
112 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
113 le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
114 le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
115 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
116 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
117 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
118 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
119 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
120 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
121 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
122 le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
123 le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
124 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
125 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
126 le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
127 le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
128 le_object_properties_bt->set_active(false);
130 mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
131 mouse_select_object->set_mid(16,16);
133 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
134 le_tilemap_panel->set_button_size(32,10);
135 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
136 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0), TM_IA);
137 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
138 le_tilemap_panel->highlight_last(true);
139 le_tilemap_panel->set_last_clicked(TM_IA);
145 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
148 LevelEditor::~LevelEditor()
150 SDL_EnableKeyRepeat(0, 0); // disables key repeating
154 delete leveleditor_menu;
155 delete subset_load_menu;
156 delete subset_new_menu;
157 delete subset_settings_menu;
158 delete level_settings_menu;
159 delete select_tilegroup_menu;
160 delete select_objects_menu;
161 delete le_save_level_bt;
163 delete le_test_level_bt;
164 delete le_next_level_bt;
165 delete le_previous_level_bt;
166 delete le_move_right_bt;
167 delete le_move_left_bt;
168 delete le_move_up_bt;
169 delete le_move_down_bt;
171 delete le_select_mode_one_bt;
172 delete le_select_mode_two_bt;
173 delete le_settings_bt;
174 delete le_tilegroup_bt;
175 delete le_objects_bt;
176 delete le_tilemap_panel;
177 delete le_object_select_bt;
178 delete le_object_properties_bt;
179 delete mouse_select_object;
181 delete le_level_subset;
184 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
185 i != tilegroups_map.end(); ++i)
189 for(ButtonPanelMap::iterator i = objects_map.begin();
190 i != objects_map.end(); ++i)
196 int LevelEditor::run(char* filename)
198 int last_time, now_time, i;
199 DrawingContext context;
204 SoundManager::get()->halt_music();
206 while (SDL_PollEvent(&event))
210 if(load_level_subset(filename))
215 last_time = SDL_GetTicks();
220 if(Menu::current() == select_tilegroup_menu)
222 if(select_tilegroup_menu_effect.check())
224 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
228 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
230 else if(Menu::current() == select_objects_menu)
232 if(select_objects_menu_effect.check())
234 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
237 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
242 /* making events results to be in order */
245 context.set_translation(Vector(pos_x, pos_y));
249 fillrect(0, 0, screen->w, screen->h, 0, 0, 0);
251 /* draw editor interface */
252 context.set_translation(Vector(0, 0));
253 drawinterface(context);
255 Menu* menu = Menu::current();
261 if(menu == leveleditor_menu)
263 switch (leveleditor_menu->check())
265 case MNID_RETURNLEVELEDITOR:
267 Menu::set_current(0);
269 Menu::set_current(leveleditor_menu);
271 case MNID_SUBSETSETTINGS:
272 update_subset_settings_menu();
274 case MNID_QUITLEVELEDITOR:
279 else if(menu == level_settings_menu)
281 switch (level_settings_menu->check())
284 apply_level_settings_menu();
285 Menu::set_current(NULL);
292 else if(menu == select_tilegroup_menu)
295 switch (it = select_tilegroup_menu->check())
300 cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
301 Menu::set_current(0);
308 else if(menu == select_objects_menu)
311 switch (it = select_objects_menu->check())
316 cur_objects = select_objects_menu->get_item_by_id(it).text;
319 Menu::set_current(0);
324 else if(menu == subset_load_menu)
326 switch (i = subset_load_menu->check())
333 if(load_level_subset(subset_load_menu->item[i+1].text.c_str()))
339 else if(menu == subset_new_menu)
341 if(subset_new_menu->item[2].input[0] == '\0')
342 subset_new_menu->item[3].kind = MN_DEACTIVE;
345 subset_new_menu->item[3].kind = MN_ACTION;
347 switch (i = subset_new_menu->check())
349 case MNID_CREATESUBSET:
350 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
351 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input.c_str());
352 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
354 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
356 Menu::set_current(subset_settings_menu);
361 else if(menu == subset_settings_menu)
363 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 )
364 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
366 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
368 switch (i = subset_settings_menu->check())
370 case MNID_SUBSETSAVECHANGES:
371 save_subset_settings_menu();
372 Menu::set_current(leveleditor_menu);
378 MouseCursor::current()->draw(context);
385 ++global_frame_counter;
388 now_time = SDL_GetTicks();
389 if (now_time < last_time + FPS)
390 SDL_Delay(last_time + FPS - now_time); /* delay some time */
392 context.do_drawing();
398 int LevelEditor::load_level_subset(const char *filename)
400 le_level_subset->load(filename);
401 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
403 goto_level(le_levelnb);
405 //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
407 Menu::set_current(NULL);
412 void LevelEditor::init_menus()
416 leveleditor_menu = new Menu();
417 subset_load_menu = new Menu();
418 subset_new_menu = new Menu();
419 subset_settings_menu = new Menu();
420 level_settings_menu = new Menu();
421 select_tilegroup_menu = new Menu();
422 select_objects_menu = new Menu();
424 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
425 leveleditor_menu->additem(MN_HL,"",0,0);
426 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
427 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
428 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
429 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
430 leveleditor_menu->additem(MN_HL,"",0,0);
431 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
433 Menu::set_current(leveleditor_menu);
435 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
436 subset_load_menu->additem(MN_HL, "", 0, 0);
438 for(std::set<std::string>::iterator it = level_subsets.begin(); it != level_subsets.end(); ++it)
440 subset_load_menu->additem(MN_ACTION,(*it),0,0, i+1);
442 subset_load_menu->additem(MN_HL,"",0,0);
443 subset_load_menu->additem(MN_BACK,"Back",0,0);
445 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
446 subset_new_menu->additem(MN_HL,"",0,0);
447 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
448 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
449 subset_new_menu->additem(MN_HL,"",0,0);
450 subset_new_menu->additem(MN_BACK,"Back",0,0);
452 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
453 subset_settings_menu->additem(MN_HL,"",0,0);
454 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
455 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
456 subset_settings_menu->additem(MN_HL,"",0,0);
457 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
458 subset_settings_menu->additem(MN_HL,"",0,0);
459 subset_settings_menu->additem(MN_BACK,"Back",0,0);
461 level_settings_menu->arrange_left = true;
462 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
463 level_settings_menu->additem(MN_HL,"",0,0);
464 level_settings_menu->additem(MN_TEXTFIELD, "Name ",0,0,MNID_NAME);
465 level_settings_menu->additem(MN_TEXTFIELD, "Author ",0,0,MNID_AUTHOR);
466 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
467 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
468 level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
469 level_settings_menu->additem(MN_NUMFIELD, "Length ",0,0,MNID_LENGTH);
470 level_settings_menu->additem(MN_NUMFIELD, "Height ",0,0,MNID_HEIGHT);
471 level_settings_menu->additem(MN_NUMFIELD, "Time ",0,0,MNID_TIME);
472 level_settings_menu->additem(MN_NUMFIELD, "Gravity ",0,0,MNID_GRAVITY);
473 level_settings_menu->additem(MN_NUMFIELD, "Bg-Img-Speed",0,0,MNID_BGSPEED);
474 level_settings_menu->additem(MN_NUMFIELD, "Top Red ",0,0,MNID_TopRed);
475 level_settings_menu->additem(MN_NUMFIELD, "Top Green ",0,0,MNID_TopGreen);
476 level_settings_menu->additem(MN_NUMFIELD, "Top Blue ",0,0,MNID_TopBlue);
477 level_settings_menu->additem(MN_NUMFIELD, "Bottom Red ",0,0,MNID_BottomRed);
478 level_settings_menu->additem(MN_NUMFIELD, "Bottom Green",0,0,MNID_BottomGreen);
479 level_settings_menu->additem(MN_NUMFIELD, "Bottom Blue ",0,0,MNID_BottomBlue);
480 level_settings_menu->additem(MN_HL,"",0,0);
481 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
483 select_tilegroup_menu->arrange_left = true;
484 select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
485 select_tilegroup_menu->additem(MN_HL,"",0,0);
486 std::set<TileGroup>* tilegroups = TileManager::tilegroups();
488 for(std::set<TileGroup>::iterator it = tilegroups->begin();
489 it != tilegroups->end(); ++it )
491 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
493 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
496 for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
497 sit != (*it).tiles.end(); ++sit, ++i)
499 /* Tile& tile = TileManager::instance()->get(*sit);
501 if(tile.editor_images.size() > 0)
502 image = tile.editor_images[0];
503 else if(tile.images.size() > 0)
504 image = tile.images[0];
506 // TODO use some notile image...
509 Button* button = new Button(image, it->name, SDLKey(SDLK_a + i),
511 tilegroups_map[it->name]->additem(button, *sit);*/
514 select_tilegroup_menu->additem(MN_HL,"",0,0);
516 select_objects_menu->arrange_left = true;
517 select_objects_menu->additem(MN_LABEL,"Objects",0,0);
518 select_objects_menu->additem(MN_HL,"",0,0);
520 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
521 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
523 for(int i = 0; i < NUM_BadGuyKinds; ++i)
525 // BadGuy bad_tmp(BadGuyKind(i), 0, 0);
526 // objects_map["BadGuys"]->additem(new Button(0, "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
527 /* FIXME: maybe addbutton should already have a parameter for the surface
528 objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
529 BadGuy(BadGuyKind(i),
530 objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
531 objects_map["BadGuys"]->manipulate_button(i)->get_pos().y
535 select_objects_menu->additem(MN_HL,"",0,0);
539 void LevelEditor::update_level_settings_menu()
542 std::set<std::string>::iterator it;
544 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_level->name.c_str());
545 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_level->author.c_str());
547 level_settings_menu->get_item_by_id(MNID_SONG).list.first = FileSystem::dfiles("music/","", "-fast");
548 level_settings_menu->get_item_by_id(MNID_BGIMG).list.first = FileSystem::dfiles("images/background","", "");
549 level_settings_menu->get_item_by_id(MNID_BGIMG).list.first.insert("");
550 level_settings_menu->get_item_by_id(MNID_PARTICLE).list.first.insert("");
551 level_settings_menu->get_item_by_id(MNID_PARTICLE).list.first.insert("snow");
552 level_settings_menu->get_item_by_id(MNID_PARTICLE).list.first.insert("clouds");
554 if((it = level_settings_menu->get_item_by_id(MNID_SONG).list.first.find(le_level->get_sector("main")->song_title)) != level_settings_menu->get_item_by_id(MNID_SONG).list.first.end())
555 level_settings_menu->get_item_by_id(MNID_SONG).list.second = it;
556 if((it = level_settings_menu->get_item_by_id(MNID_BGIMG).list.first.find(le_level->get_sector("main")->background->get_image())) != level_settings_menu->get_item_by_id(MNID_BGIMG).list.first.end())
557 level_settings_menu->get_item_by_id(MNID_BGIMG).list.second = it;
558 /* if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_level->get_sector("main")->particlesystem.c_str())) != -1)
559 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;*/
561 sprintf(str,"%d",static_cast<int>(le_level->get_sector("main")->solids->get_width()));
562 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
563 sprintf(str,"%d", static_cast<int>(le_level->get_sector("main")->solids->get_height()));
564 level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
565 sprintf(str,"%d",le_level->time_left);
566 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
567 sprintf(str,"%2.0f",le_level->get_sector("main")->gravity);
568 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
569 sprintf(str,"%2.2f", le_level->get_sector("main")->background->get_speed());
570 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
571 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().red);
572 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
573 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().green);
574 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
575 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().blue);
576 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
577 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().red);
578 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
579 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().green);
580 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
581 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().blue);
582 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
585 void LevelEditor::update_subset_settings_menu()
587 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
588 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
591 void LevelEditor::apply_level_settings_menu()
595 le_level_changed = true;
597 le_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
598 le_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
600 if(le_level->get_sector("main")->background->get_image().compare((*level_settings_menu->get_item_by_id(MNID_BGIMG).list.second)) != 0)
602 le_level->get_sector("main")->background->set_image((*level_settings_menu->get_item_by_id(MNID_BGIMG).list.second), atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input.c_str()));
606 /* if(le_level->get_sector("main")->particlesystem.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
608 le_level->->get_sector("main")->particlesystem = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
613 le_level->load_gfx();
616 le_level->get_sector("main")->song_title = (*level_settings_menu->get_item_by_id(MNID_SONG).list.second);
618 le_level->get_sector("main")->solids->resize(
619 atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input.c_str()),
620 atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input.c_str()));
621 le_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input.c_str());
622 le_level->get_sector("main")->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input.c_str());
623 le_level->get_sector("main")->background->set_gradient(Color(
624 atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input.c_str()),
625 atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input.c_str()),
626 atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input.c_str())), Color(
627 atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input.c_str()),
628 atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input.c_str()),
629 atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input.c_str())));
632 void LevelEditor::save_subset_settings_menu()
634 le_level_subset->title = subset_settings_menu->item[2].input;
635 le_level_subset->description = subset_settings_menu->item[3].input;
636 le_level_subset->save();
637 le_level_changed = false;
640 void LevelEditor::unload_level()
645 // TODO get level number
646 sprintf(str,"Save changes to level %d of %s?", 0/*le_level*/,le_level_subset->name.c_str());
647 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
648 if(confirm_dialog(surf, str))
650 le_level->save(le_level_subset->get_level_filename(le_levelnb));
657 le_level_changed = false;
660 void LevelEditor::goto_level(int levelnb)
663 le_level = new Level();
664 le_level->load(le_level_subset->get_level_filename(levelnb));
665 display_level_info.start(2500);
666 le_levelnb = levelnb;
669 void LevelEditor::drawminimap()
672 // if(le_level == NULL)
676 if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 4)
678 else if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 2)
682 int left_offset = (screen->w - 64 - le_level->get_sector("main")->solids->get_width()*mini_tile_width) / 2;
684 int mini_tile_height;
685 if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 4)
686 mini_tile_height = 4;
687 else if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 2)
688 mini_tile_height = 2;
690 mini_tile_height = 1;
692 for (unsigned int y = 0; y < le_level->get_sector("main")->solids->get_height(); ++y)
693 for (unsigned int x = 0; x < le_level->get_sector("main")->solids->get_width(); ++x)
696 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
697 mini_tile_width , mini_tile_height, le_level->bg_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
699 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
700 mini_tile_width , mini_tile_height, le_level->ia_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
702 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
703 mini_tile_width , mini_tile_height, le_level->fg_tiles[y + le_level->get_sector("main")->solids->get_width() + x]);
707 fillrect(left_offset, 0,
708 le_level->get_sector("main")->solids->get_width()*mini_tile_width, le_level->get_sector("main")->solids->get_height()*mini_tile_height,
711 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
712 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
714 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
715 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
717 fillrect(left_offset + (pos_x/32)*mini_tile_width + (VISIBLE_TILES_X-3)*mini_tile_width - 2, (pos_y/32)*mini_tile_height,
718 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
720 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height + (VISIBLE_TILES_Y-1)*mini_tile_height - 2,
721 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
726 void LevelEditor::drawinterface(DrawingContext &context)
733 /* draw a grid (if selected) */
736 for(x = 0; x < VISIBLE_TILES_X; x++)
737 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
738 for(y = 0; y < VISIBLE_TILES_Y; y++)
739 fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
743 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
746 if(show_selections && MouseCursor::current() != mouse_select_object)
748 if(le_selection_mode == CURSOR)
750 if(le_current.IsTile())
751 context.draw_surface(le_selection, Vector(cursor_x - pos_x, cursor_y - pos_y), LAYER_GUI);
753 else if(le_selection_mode == SQUARE)
756 highlight_selection();
757 /* draw current selection */
758 w = selection.x2 - selection.x1;
759 h = selection.y2 - selection.y1;
760 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
761 context.draw_filled_rect(Vector(selection.x1 - pos_x + w, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
762 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y + h), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
763 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
768 /* draw button bar */
769 context.draw_filled_rect(Vector(screen->w - 64, 0), Vector(64, screen->h), Color(50, 50, 50,255), LAYER_GUI);
771 if(le_current.IsTile())
773 // le_level->get_sector("main")->solids->draw(context);
775 /*screen->w - 32, screen->h - 32, le_current.tile);
776 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
777 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);*/
779 #if 0 // XXX FIXME TODO: Do we have a new solution for draw_on_screen()?
780 if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
782 le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
783 le_current.obj->draw_on_screen(cursor_x,cursor_y);
787 if(mouse_select_object && selected_game_object != NULL)
789 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);
790 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);
791 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);
792 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);
797 le_save_level_bt->draw(context);
798 le_exit_bt->draw(context);
799 le_test_level_bt->draw(context);
800 le_next_level_bt->draw(context);
801 le_previous_level_bt->draw(context);
802 le_rubber_bt->draw(context);
803 if(le_selection_mode == SQUARE)
804 le_select_mode_one_bt->draw(context);
805 else if(le_selection_mode == CURSOR)
806 le_select_mode_two_bt->draw(context);
807 le_settings_bt->draw(context);
808 le_move_right_bt->draw(context);
809 le_move_left_bt->draw(context);
810 le_move_up_bt->draw(context);
811 le_move_down_bt->draw(context);
812 le_tilegroup_bt->draw(context);
813 le_objects_bt->draw(context);
814 if(!cur_tilegroup.empty())
815 tilegroups_map[cur_tilegroup]->draw(context);
816 else if(!cur_objects.empty())
818 objects_map[cur_objects]->draw(context);
821 le_tilemap_panel->draw(context);
823 if(!cur_objects.empty())
825 le_object_select_bt->draw(context);
826 le_object_properties_bt->draw(context);
829 sprintf(str, "%d/%d", le_levelnb, le_level_subset->get_num_levels());
830 context.draw_text(white_text, str, Vector((le_level_subset->get_num_levels() < 10) ? -10 : 0, 16), LEFT_ALLIGN, LAYER_GUI);
833 context.draw_text(white_small_text, "F1 for Help", Vector(10, 430), LEFT_ALLIGN, LAYER_GUI);
835 if(display_level_info.check())
836 context.draw_text(white_text, le_level->name.c_str(), Vector(screen->w/2, 0), CENTER_ALLIGN, LAYER_GUI);
841 context.draw_text(white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", Vector(10, 430), LEFT_ALLIGN, LAYER_GUI);
843 context.draw_text(white_small_text, "No Level Subset loaded", Vector(10, 430), LEFT_ALLIGN, LAYER_GUI);
848 void LevelEditor::drawlevel(DrawingContext& context)
853 /* Draw the real background */
854 le_level->get_sector("main")->background->draw(context);
856 if(le_current.IsTile())
858 //le_level->get_sector("main")->solids->draw(context);
860 Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
861 if(!TileManager::instance()->get(le_current.tile)->images.empty())
862 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);*/
864 #if 0 // XXX FIXME TODO: Do we have a new solution for move_to()?
865 if(le_current.IsObject())
867 le_current.obj->move_to(cursor_x, cursor_y);
871 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
873 le_level->get_sector("main")->solids->draw(context);
875 // FIXME: make tiles to be drawn semi-transparent when not selected
877 for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_level->get_section("main")->height; ++y)
878 for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
881 if(active_tm == TM_BG)
886 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
887 le_level->bg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
888 (x + (int)(pos_x / 32))],a);
890 if(active_tm == TM_IA)
895 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
896 le_level->ia_tiles[ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width +
897 (x + (int)(pos_x / 32))],a);
900 if(active_tm == TM_FG)
905 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
906 le_level->fg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
907 (x + (int)(pos_x / 32))],a);
909 /* draw whats inside stuff when cursor is selecting those */
910 /* (draw them all the time - is this the right behaviour?) */
911 Tile* edit_image = TileManager::instance()->get(
913 [ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width + (x + (int)(pos_x / 32))]);
914 if(edit_image && !edit_image->editor_images.empty())
915 edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
919 /* Draw the Bad guys: */
920 for (std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
921 it != le_level->get_sector("main")->gameobjects.end(); ++it)
923 BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
927 /* to support frames: img_bsod_left[(frame / 5) % 4] */
928 badguy->draw(context);
931 /* Draw the player: */
932 /* for now, the position is fixed at (100, 240) */
933 // largetux.walk_right->draw(context, Vector(100 - pos_x, 240 - pos_y), LAYER_OBJECTS-1);
936 void LevelEditor::change_object_properties(GameObject *pobj)
938 DrawingContext context;
940 Menu* object_properties_menu = new Menu();
943 std::string type = typeid(pobj).name();
944 object_properties_menu->additem(MN_LABEL, type + " Properties",0,0);
945 object_properties_menu->additem(MN_HL,"",0,0);
947 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
950 object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
951 for(int i = 0; i < NUM_BadGuyKinds; ++i)
953 object_properties_menu->get_item_by_id(1).list.first.insert(
954 badguykind_to_string(static_cast<BadGuyKind>(i)));
956 object_properties_menu->get_item_by_id(1).list.second = object_properties_menu->get_item_by_id(1).list.first.find(badguykind_to_string(static_cast<BadGuyKind>(i)));
958 object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
961 object_properties_menu->additem(MN_HL,"",0,0);
962 object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
964 Menu::set_current(object_properties_menu);
970 while (SDL_PollEvent(&event))
972 object_properties_menu->event(event);
975 //cap_screen->draw(0,0);
977 object_properties_menu->draw(context);
978 object_properties_menu->action();
980 switch (object_properties_menu->check())
984 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
986 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
987 pbad->kind = badguykind_from_string((*object_properties_menu->get_item_by_id(1).list.second));
988 pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
997 if(Menu::current() == NULL)
1000 mouse_cursor->draw(context);
1001 // context.draw_filled_rect();
1005 //delete cap_screen;
1006 Menu::set_current(0);
1007 delete object_properties_menu;
1011 void LevelEditor::checkevents()
1018 keymod = SDL_GetModState();
1020 while(SDL_PollEvent(&event))
1022 if (Menu::current())
1024 Menu::current()->event(event);
1025 if(!le_level && !Menu::current())
1026 Menu::set_current(leveleditor_menu);
1030 mouse_cursor->set_state(MC_NORMAL);
1032 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1033 if(event.type == SDL_KEYDOWN
1034 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1035 && (event.motion.x > 0
1036 && event.motion.x < screen->w - 64 &&
1037 event.motion.y > 0 && event.motion.y < screen->h)))
1041 case SDL_KEYDOWN: // key pressed
1042 key = event.key.keysym.sym;
1046 Menu::set_current(leveleditor_menu);
1049 if(le_level != NULL)
1057 cursor_x = (le_level->get_sector("main")->solids->get_width() * 32) - 32;
1061 le_show_grid = !le_show_grid;
1067 case SDL_MOUSEBUTTONDOWN:
1068 if(event.button.button == SDL_BUTTON_LEFT)
1070 le_mouse_pressed[LEFT] = true;
1072 selection.x1 = event.motion.x + pos_x;
1073 selection.y1 = event.motion.y + pos_y;
1074 selection.x2 = event.motion.x + pos_x;
1075 selection.y2 = event.motion.y + pos_y;
1077 else if(event.button.button == SDL_BUTTON_RIGHT)
1079 le_mouse_pressed[RIGHT] = true;
1082 case SDL_MOUSEBUTTONUP:
1083 if(event.button.button == SDL_BUTTON_LEFT)
1085 le_mouse_pressed[LEFT] = false;
1086 le_mouse_clicked[LEFT] = true;
1088 else if(event.button.button == SDL_BUTTON_RIGHT)
1090 le_mouse_pressed[RIGHT] = false;
1091 le_mouse_clicked[RIGHT] = true;
1094 case SDL_MOUSEMOTION:
1096 if(!Menu::current())
1101 if(le_current.IsTile())
1103 cursor_x = ((int)(pos_x + x) / 32) * 32;
1104 cursor_y = ((int)(pos_y + y) / 32) * 32;
1112 if(le_mouse_pressed[LEFT])
1114 selection.x2 = x + pos_x;
1115 selection.y2 = y + pos_y;
1118 if(le_mouse_pressed[RIGHT])
1120 pos_x += -1 * event.motion.xrel;
1121 pos_y += -1 * event.motion.yrel;
1129 else if(event.type == SDL_QUIT) /* window closing */
1135 if(le_level != NULL)
1137 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 &&
1138 event.motion.y > 0 && event.motion.y < screen->h)))
1140 le_mouse_pressed[LEFT] = false;
1141 le_mouse_pressed[RIGHT] = false;
1143 if(!Menu::current())
1145 /* Check for button events */
1146 le_test_level_bt->event(event);
1147 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1149 le_save_level_bt->event(event);
1150 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1151 le_level->save(le_level_subset->name.c_str());
1152 le_exit_bt->event(event);
1153 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1155 Menu::set_current(leveleditor_menu);
1157 le_next_level_bt->event(event);
1158 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1160 if(le_levelnb < le_level_subset->get_num_levels())
1162 goto_level(le_levelnb+1);
1168 sprintf(str,"Level %d doesn't exist. Create it?",le_levelnb+1);
1169 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
1170 if(confirm_dialog(surf, str))
1172 le_level_subset->add_level("newlevel.stl");
1173 new_lev.save(le_level_subset->get_level_filename(le_levelnb+1));
1174 goto_level(le_levelnb);
1180 le_previous_level_bt->event(event);
1181 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1184 goto_level(le_levelnb -1);
1186 le_rubber_bt->event(event);
1187 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1190 if(!cur_objects.empty())
1192 le_object_select_bt->event(event);
1193 if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1195 MouseCursor::set_current(mouse_select_object);
1198 le_object_properties_bt->event(event);
1199 if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1201 change_object_properties(selected_game_object);
1206 if(le_selection_mode == SQUARE)
1208 le_select_mode_one_bt->event(event);
1209 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1210 le_selection_mode = CURSOR;
1214 le_select_mode_two_bt->event(event);
1215 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1216 le_selection_mode = SQUARE;
1218 ButtonPanelMap::iterator it;
1219 le_tilegroup_bt->event(event);
1220 switch (le_tilegroup_bt->get_state())
1222 case BUTTON_CLICKED:
1223 Menu::set_current(select_tilegroup_menu);
1224 select_tilegroup_menu_effect.start(200);
1225 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1227 case BUTTON_WHEELUP:
1228 if(cur_tilegroup.empty())
1230 cur_tilegroup = tilegroups_map.begin()->first;
1234 it = tilegroups_map.find(cur_tilegroup);
1235 if((++it) == tilegroups_map.end())
1237 cur_tilegroup = tilegroups_map.begin()->first;
1241 cur_tilegroup = (*it).first;
1247 case BUTTON_WHEELDOWN:
1248 it = tilegroups_map.find(cur_tilegroup);
1249 if(it == tilegroups_map.begin())
1251 cur_tilegroup = tilegroups_map.rbegin()->first;
1255 if(--it != --tilegroups_map.begin())
1256 cur_tilegroup = (*it).first;
1258 cur_tilegroup = tilegroups_map.rbegin()->first;
1266 le_objects_bt->event(event);
1267 switch (le_objects_bt->get_state())
1269 case BUTTON_CLICKED:
1270 Menu::set_current(select_objects_menu);
1271 select_objects_menu_effect.start(200);
1272 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1274 case BUTTON_WHEELUP:
1275 it = objects_map.find(cur_objects);
1276 if(it == objects_map.end())
1278 cur_objects = objects_map.begin()->first;
1282 if(++it != objects_map.end())
1283 cur_objects = (*it).first;
1285 cur_objects = objects_map.begin()->first;
1289 case BUTTON_WHEELDOWN:
1290 it = objects_map.find(cur_objects);
1291 if(it == objects_map.begin())
1293 cur_objects = objects_map.rbegin()->first;
1297 if(--it != --objects_map.begin())
1298 cur_objects = (*it).first;
1300 cur_objects = objects_map.rbegin()->first;
1309 le_settings_bt->event(event);
1310 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1312 update_level_settings_menu();
1313 Menu::set_current(level_settings_menu);
1315 if(!cur_tilegroup.empty())
1317 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1319 if(pbutton->get_state() == BUTTON_CLICKED)
1321 le_current.Tile(pbutton->get_tag());
1325 else if(!cur_objects.empty())
1327 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1329 if(pbutton->get_state() == BUTTON_CLICKED)
1331 #if 0 // TODO FIXME XXX: New solution for this?
1332 le_current.Object(pbutton->get_drawable());
1338 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1340 if(pbutton->get_state() == BUTTON_CLICKED)
1342 active_tm = pbutton->get_tag();
1348 le_settings_bt->event(event);
1349 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1351 Menu::set_current(0);
1353 le_tilegroup_bt->event(event);
1354 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1356 Menu::set_current(0);
1358 le_objects_bt->event(event);
1359 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1361 Menu::set_current(0);
1366 if(!Menu::current() && !show_minimap)
1368 if(le_mouse_pressed[LEFT])
1370 if(MouseCursor::current() != mouse_select_object)
1372 if(le_current.IsTile())
1373 change(cursor_x, cursor_y, active_tm, le_current.tile);
1376 else if(le_mouse_clicked[LEFT])
1378 if(MouseCursor::current() == mouse_select_object)
1380 bool object_got_hit = false;
1381 base_type cursor_base;
1382 if(le_current.IsTile())
1384 cursor_base.x = cursor_x;
1385 cursor_base.y = cursor_y;
1387 else if(le_current.IsObject())
1389 cursor_base.x = cursor_x + pos_x;
1390 cursor_base.y = cursor_y + pos_y;
1392 cursor_base.width = 32;
1393 cursor_base.height = 32;
1395 for(std::vector<GameObject*>::iterator it =
1396 le_level->get_sector("main")->gameobjects.begin();
1397 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1398 MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
1402 if(rectcollision(cursor_base, mobj->base))
1404 selected_game_object = mobj;
1405 object_got_hit = true;
1412 selected_game_object = NULL;
1413 le_object_properties_bt->set_active(false);
1416 le_object_properties_bt->set_active(true);
1418 MouseCursor::set_current(mouse_cursor);
1425 //FIXME: objects interactions with the level editor should have a major improvement
1426 if(le_current.IsObject())
1428 le_level_changed = true;
1429 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1433 Camera& camera = *le_level->get_sector("main")->camera;
1435 le_level->get_sector("main")->bad_guys.push_back(
1436 new BadGuy(pbadguy->kind,
1437 cursor_x + camera.get_translation().x,
1438 cursor_y + camera.get_translation().y));
1439 le_level->get_sector("main")->gameobjects.push_back(le_level->get_sector("main")->bad_guys.back());
1446 le_mouse_clicked[LEFT] = false;
1452 if(!Menu::current())
1454 show_minimap = false;
1456 if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB)
1457 show_minimap = true;
1459 le_move_left_bt->event(event);
1460 le_move_right_bt->event(event);
1461 le_move_up_bt->event(event);
1462 le_move_down_bt->event(event);
1463 switch(le_move_left_bt->get_state())
1465 case BUTTON_PRESSED:
1466 pos_x -= KEYBOARD_SPEED;
1467 show_minimap = true;
1470 pos_x -= MOUSE_SPEED;
1471 show_minimap = true;
1473 case BUTTON_CLICKED:
1474 show_minimap = true;
1480 switch(le_move_right_bt->get_state())
1482 case BUTTON_PRESSED:
1483 pos_x += KEYBOARD_SPEED;
1484 show_minimap = true;
1487 pos_x += MOUSE_SPEED;
1488 show_minimap = true;
1490 case BUTTON_CLICKED:
1491 show_minimap = true;
1497 switch(le_move_up_bt->get_state())
1499 case BUTTON_PRESSED:
1500 pos_y -= KEYBOARD_SPEED;
1501 show_minimap = true;
1504 pos_y -= MOUSE_SPEED;
1505 show_minimap = true;
1507 case BUTTON_CLICKED:
1508 show_minimap = true;
1514 switch(le_move_down_bt->get_state())
1516 case BUTTON_PRESSED:
1517 pos_y += KEYBOARD_SPEED;
1518 show_minimap = true;
1521 pos_y += MOUSE_SPEED;
1522 show_minimap = true;
1524 case BUTTON_CLICKED:
1525 show_minimap = true;
1531 /* checking if pos_x and pos_y is within the limits... */
1532 if((unsigned)pos_x > (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w)
1533 pos_x = (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w;
1537 if((unsigned)pos_y > (le_level->get_sector("main")->solids->get_height() * 32) - screen->h)
1538 pos_y = (le_level->get_sector("main")->solids->get_height() * 32) - screen->h;
1544 void LevelEditor::highlight_selection()
1548 if(selection.x1 < selection.x2)
1558 if(selection.y1 < selection.y2)
1574 fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1577 void LevelEditor::change(float x, float y, int tm, unsigned int c)
1579 if(le_level != NULL)
1584 le_level_changed = true;
1586 switch(le_selection_mode)
1591 base_type cursor_base;
1594 cursor_base.width = 32;
1595 cursor_base.height = 32;
1597 /* if there is a bad guy over there, remove it */
1599 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1600 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1601 BadGuy* badguy = dynamic_cast<BadGuy*>((*it));
1604 if(rectcollision(cursor_base, badguy->base))
1607 le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(),
1608 le_level->get_sector("main")->gameobjects.end(), *it),
1609 le_level->get_sector("main")->gameobjects.end());
1617 if(selection.x1 < selection.x2)
1627 if(selection.y1 < selection.y2)
1643 /* if there is a bad guy over there, remove it */
1645 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1646 it != le_level->get_sector("main")->gameobjects.end(); ++it /* will be at end of loop */)
1648 MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);
1651 if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
1652 && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
1655 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());
1665 for(xx = x1; xx <= x2; xx++)
1666 for(yy = y1; yy <= y2; yy++)
1668 change(xx*32, yy*32, tm, c);
1678 void LevelEditor::testlevel()
1680 //Make sure a time value is set when testing the level
1681 if(le_level->time_left == 0)
1682 le_level->time_left = 250;
1684 le_level->save("test.stl");
1686 GameSession session("test.stl", ST_GL_TEST);
1688 player_status.reset();
1690 SoundManager::get()->halt_music();
1692 Menu::set_current(NULL);
1695 void LevelEditor::showhelp()
1697 DrawingContext context;
1699 bool tmp_show_grid = le_show_grid;
1700 SelectionMode temp_le_selection_mode = le_selection_mode;
1701 le_selection_mode = NONE;
1702 show_selections = true;
1703 le_show_grid = false;
1704 le_help_shown = true;
1711 " - Supertux level editor tutorial - ",
1713 "To make your map, click the ",
1714 "tilegroup button and choose a ",
1716 "Pick a tile and simply hold down ",
1717 "the left mouse button over the map",
1718 "to \"paint\" your selection over",
1721 "There are three layers for painting",
1722 "tiles upon, Background layer,",
1723 "the Interactive layer, and the",
1724 "Foreground layer, which can be",
1725 "toggled by the BkGrd, IntAct and",
1726 "FrGrd buttons. The Foreground and",
1727 "Background layers do not effect",
1728 "Tux in the gameplay, but lie in",
1729 "front of him or lie behind him in",
1735 " - Supertux level editor tutorial - ",
1737 "The tiles placed on",
1738 "the Interactive layer are those",
1739 "which actually effect Tux in the",
1742 "Click the objects menu to put ",
1743 "bad guys and other objects in the",
1744 "game. Unlike placing tiles, you",
1745 "cannot \"paint\" enemies. Click",
1746 "them onto the screen one at a time.",
1748 "To change the settings of your",
1749 "level, click the button with the",
1750 "screwdriver and wrench. From here",
1751 "you can change the background,",
1752 "music, length of the level,",
1758 " - Supertux level editor tutorial - ",
1760 "You may have more than one level.",
1761 "Pressing the up and down buttons",
1762 "above the button bar lets you",
1763 "choose which one you are working on.",
1765 "If you would like to speed up your",
1766 "level editing, a useful trick is",
1767 "to learn the keyboard shortcuts.",
1768 "They are easy to learn, just right-",
1769 "click on the buttons.",
1771 "Have fun making levels! If you make",
1772 "some good ones, send them to us on",
1773 "the SuperTux mailing list!",
1777 char **text[] = { text1, text2, text3 };
1780 for(int i = 0; i < 3; i++)
1782 context.draw_gradient(Color(0,0,0), Color(255,255,255), LAYER_BACKGROUND0);
1783 drawinterface(context);
1785 context.draw_text(blue_text, "- Help -", Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
1787 for(unsigned int t = 0; t < sizeof(text[i])/sizeof(char *); t++)
1788 context.draw_text(white_text, text[i][t], Vector(5, 80+(t*white_text->get_height())), LEFT_ALLIGN, LAYER_GUI);
1790 sprintf(str,"Press any key to continue - Page %d/%d?", i, static_cast<int>(sizeof(text)));
1791 context.draw_text(gold_text, str, Vector(0, 0), LEFT_ALLIGN, LAYER_GUI);
1793 context.do_drawing();
1799 done_ = wait_for_event(event);
1804 show_selections = true;
1805 le_show_grid = tmp_show_grid;
1806 le_selection_mode = temp_le_selection_mode;
1807 le_help_shown = false;