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.
29 #include <SDL_image.h>
30 #include "leveleditor.h"
43 #include "resources.h"
44 #include "music_manager.h"
46 /* definitions to aid development */
48 /* definitions that affect gameplay */
49 #define KEY_CURSOR_SPEED 32
50 #define KEY_CURSOR_FASTSPEED 64
52 /* when pagedown/up pressed speed:*/
53 #define PAGE_CURSOR_SPEED 13*32
55 #define MOUSE_LEFT_MARGIN 80
56 #define MOUSE_RIGHT_MARGIN (560-32)
57 /* right_margin should noticed that the cursor is 32 pixels,
58 so it should subtract that value */
59 #define MOUSE_POS_SPEED 20
62 #define SELECT_W 2 // size of the selections lines
63 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
65 /* own declerations */
66 /* crutial ones (main loop) */
70 void le_drawinterface();
71 void le_checkevents();
72 void le_change(float x, float y, int tm, unsigned int c);
75 void le_set_defaults(void);
76 void le_activate_bad_guys(void);
78 void le_highlight_selection();
80 void apply_level_settings_menu();
81 void update_subset_settings_menu();
82 void save_subset_settings_menu();
84 static Level* le_current_level;
86 struct LevelEditorWorld
88 std::vector<BadGuy> bad_guys;
89 void arrays_free(void)
94 void add_bad_guy(float x, float y, BadGuyKind kind)
96 bad_guys.push_back(BadGuy(x,y,kind, false /* stay_on_platform */));
99 void activate_bad_guys()
101 for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
102 i != le_current_level->badguy_data.end();
105 add_bad_guy(i->x, i->y, i->kind);
112 TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
114 void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
115 void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
116 //Returns true for a tile
117 bool IsTile() { return is_tile; };
118 //Returns true for a GameObject
119 bool IsObject() { return !is_tile; };
121 bool is_tile; //true for tile (false for object)
126 /* leveleditor internals */
127 static string_list_type level_subsets;
128 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
129 static int pos_x, cursor_x, cursor_y, fire;
131 static LevelEditorWorld le_world;
132 static LevelSubset* le_level_subset;
133 static int le_show_grid;
135 static Surface* le_selection;
137 static TileOrObject le_current;
138 static bool le_mouse_pressed[2];
139 static Button* le_save_level_bt;
140 static Button* le_exit_bt;
141 static Button* le_test_level_bt;
142 static Button* le_next_level_bt;
143 static Button* le_previous_level_bt;
144 static Button* le_move_right_bt;
145 static Button* le_move_left_bt;
146 static Button* le_rubber_bt;
147 static Button* le_select_mode_one_bt;
148 static Button* le_select_mode_two_bt;
149 static Button* le_settings_bt;
150 static Button* le_tilegroup_bt;
151 static Button* le_objects_bt;
152 static ButtonPanel* le_tilemap_panel;
153 static Menu* leveleditor_menu;
154 static Menu* subset_load_menu;
155 static Menu* subset_new_menu;
156 static Menu* subset_settings_menu;
157 static Menu* level_settings_menu;
158 static Menu* select_tilegroup_menu;
159 static Menu* select_objects_menu;
160 static Timer select_tilegroup_menu_effect;
161 static Timer select_objects_menu_effect;
162 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
163 static ButtonPanelMap tilegroups_map;
164 static ButtonPanelMap objects_map;
165 static std::string cur_tilegroup;
166 static std::string cur_objects;
168 static square selection;
169 static int le_selection_mode;
170 static SDL_Event event;
171 TileMapType active_tm;
173 void le_set_defaults()
175 if(le_current_level != NULL)
179 if(le_current_level->time_left == 0)
180 le_current_level->time_left = 255;
184 int leveleditor(int levelnb)
186 int last_time, now_time, i;
194 clearscreen(0, 0, 0);
197 music_manager->halt_music();
199 while (SDL_PollEvent(&event))
204 last_time = SDL_GetTicks();
209 if(Menu::current() == select_tilegroup_menu)
211 if(select_tilegroup_menu_effect.check())
213 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
217 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
219 else if(Menu::current() == select_objects_menu)
221 if(select_objects_menu_effect.check())
223 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
226 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
229 if(le_current_level != NULL)
231 /* making events results to be in order */
234 if(pos_x > (le_current_level->width * 32) - screen->w)
235 pos_x = (le_current_level->width * 32) - screen->w;
241 clearscreen(0, 0, 0);
243 /* draw editor interface */
246 Menu* menu = Menu::current();
252 if(menu == leveleditor_menu)
254 switch (leveleditor_menu->check())
256 case MNID_RETURNLEVELEDITOR:
257 Menu::set_current(0);
259 case MNID_SUBSETSETTINGS:
260 update_subset_settings_menu();
262 case MNID_QUITLEVELEDITOR:
267 else if(menu == level_settings_menu)
269 switch (level_settings_menu->check())
272 apply_level_settings_menu();
273 Menu::set_current(NULL);
281 else if(menu == select_tilegroup_menu)
284 switch (it = select_tilegroup_menu->check())
290 = select_tilegroup_menu->get_item_by_id(it).text;
291 Menu::set_current(0);
298 else if(menu == select_objects_menu)
301 switch (it = select_objects_menu->check())
306 cur_objects = select_objects_menu->get_item_by_id(it).text;
307 cur_tilegroup.clear();
309 Menu::set_current(0);
314 else if(menu == subset_load_menu)
316 switch (i = subset_load_menu->check())
323 le_level_subset->load(level_subsets.item[i-1]);
324 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
326 le_world.arrays_free();
327 delete le_current_level;
328 le_current_level = new Level;
329 if(le_current_level->load(le_level_subset->name, le_level) != 0)
335 le_current_level->load_gfx();
336 le_world.activate_bad_guys();
338 Menu::set_current(NULL);
343 else if(menu == subset_new_menu)
345 if(subset_new_menu->item[2].input[0] == '\0')
346 subset_new_menu->item[3].kind = MN_DEACTIVE;
349 subset_new_menu->item[3].kind = MN_ACTION;
351 switch (i = subset_new_menu->check())
353 case MNID_CREATESUBSET:
354 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
355 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
356 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
358 le_world.arrays_free();
359 delete le_current_level;
360 le_current_level = new Level;
361 if(le_current_level->load(le_level_subset->name, le_level) != 0)
367 le_current_level->load_gfx();
368 le_world.activate_bad_guys();
369 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
371 Menu::set_current(subset_settings_menu);
376 else if(menu == subset_settings_menu)
378 if(le_level_subset->title.compare(subset_settings_menu->get_item_by_id(MNID_TITLE).input) == 0 && le_level_subset->description.compare(subset_settings_menu->get_item_by_id(MNID_DESCRIPTION).input) == 0 )
379 subset_settings_menu->get_item_by_id(MNID_SAVE_CHANGES).kind = MN_DEACTIVE;
381 subset_settings_menu->get_item_by_id(MNID_SAVE_CHANGES).kind = MN_ACTION;
383 switch (i = subset_settings_menu->check())
385 case MNID_SAVE_CHANGES:
386 save_subset_settings_menu();
387 //FIXME:show_menu = true;
388 Menu::set_current(leveleditor_menu);
394 mouse_cursor->draw();
402 ++global_frame_counter;
405 now_time = SDL_GetTicks();
406 if (now_time < last_time + FPS)
407 SDL_Delay(last_time + FPS - now_time); /* delay some time */
420 leveleditor_menu = new Menu();
421 subset_load_menu = new Menu();
422 subset_new_menu = new Menu();
423 subset_settings_menu = new Menu();
424 level_settings_menu = new Menu();
425 select_tilegroup_menu = new Menu();
426 select_objects_menu = new Menu();
428 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
429 leveleditor_menu->additem(MN_HL,"",0,0);
430 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
431 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
432 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
433 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
434 leveleditor_menu->additem(MN_HL,"",0,0);
435 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
437 Menu::set_current(leveleditor_menu);
439 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
440 subset_load_menu->additem(MN_HL, "", 0, 0);
442 for(i = 0; i < level_subsets.num_items; ++i)
444 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
446 subset_load_menu->additem(MN_HL,"",0,0);
447 subset_load_menu->additem(MN_BACK,"Back",0,0);
449 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
450 subset_new_menu->additem(MN_HL,"",0,0);
451 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
452 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
453 subset_new_menu->additem(MN_HL,"",0,0);
454 subset_new_menu->additem(MN_BACK,"Back",0,0);
456 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
457 subset_settings_menu->additem(MN_HL,"",0,0);
458 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
459 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
460 subset_settings_menu->additem(MN_HL,"",0,0);
461 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
462 subset_settings_menu->additem(MN_HL,"",0,0);
463 subset_settings_menu->additem(MN_BACK,"Back",0,0);
465 level_settings_menu->arrange_left = true;
466 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
467 level_settings_menu->additem(MN_HL,"",0,0);
468 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0,MNID_NAME);
469 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0,MNID_AUTHOR);
470 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
471 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
472 level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
473 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0,MNID_LENGTH);
474 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0,MNID_TIME);
475 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0,MNID_GRAVITY);
476 level_settings_menu->additem(MN_NUMFIELD,"Bg-Img-Speed",0,0,MNID_BGSPEED);
477 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0,MNID_TopRed);
478 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0,MNID_TopGreen);
479 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0,MNID_TopBlue);
480 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0,MNID_BottomRed);
481 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0,MNID_BottomGreen);
482 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0,MNID_BottomBlue);
483 level_settings_menu->additem(MN_HL,"",0,0);
484 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
486 select_tilegroup_menu->arrange_left = true;
487 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
488 select_tilegroup_menu->additem(MN_HL,"",0,0);
489 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
491 for(std::vector<TileGroup>::iterator it = tilegroups->begin();
492 it != tilegroups->end(); ++it )
494 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
496 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
499 for(std::vector<int>::iterator sit = (*it).tiles.begin();
500 sit != (*it).tiles.end(); ++sit, ++i)
502 std::string imagefile = "/images/tilesets/" ;
503 if(!TileManager::instance()->get(*sit)->filenames.empty())
505 imagefile += TileManager::instance()->get(*sit)->filenames[0];
507 else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
509 imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
513 imagefile += "notile.png";
515 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
517 tilegroups_map[it->name]->additem(button, *sit);
520 select_tilegroup_menu->additem(MN_HL,"",0,0);
522 select_objects_menu->arrange_left = true;
523 select_objects_menu->additem(MN_LABEL,"Select Objects",0,0);
524 select_objects_menu->additem(MN_HL,"",0,0);
525 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
526 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
528 for(int i = 0; i < NUM_BadGuyKinds; ++i)
530 BadGuy bad_tmp(0,0,BadGuyKind(i),false);
531 objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
532 objects_map["BadGuys"]->manipulate_button(i)->set_game_object(new BadGuy(objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,objects_map["BadGuys"]->manipulate_button(i)->get_pos().y,BadGuyKind(i),false));
535 select_objects_menu->additem(MN_HL,"",0,0);
541 level_subsets = dsubdirs("/levels", "info");
543 le_level_subset = new LevelSubset;
549 /* level_changed = NO;*/
552 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
553 le_level_changed = false;
554 le_current_level = NULL;
556 le_mouse_pressed[LEFT] = false;
557 le_mouse_pressed[RIGHT] = false;
559 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
561 select_tilegroup_menu_effect.init(false);
562 select_objects_menu_effect.init(false);
565 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
566 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
567 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
568 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
569 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
570 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
571 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
572 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
573 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
574 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
575 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
576 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
577 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
579 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
580 le_tilemap_panel->set_button_size(32,10);
581 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
582 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
583 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
587 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
592 void update_level_settings_menu()
597 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_current_level->name.c_str());
598 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_current_level->author.c_str());
600 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
601 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
602 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
603 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
604 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
605 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
607 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_current_level->song_title.c_str())) != -1)
608 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
609 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_current_level->bkgd_image.c_str())) != -1)
610 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
611 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_current_level->particle_system.c_str())) != -1)
612 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
614 sprintf(str,"%d",le_current_level->width);
615 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
616 sprintf(str,"%d",le_current_level->time_left);
617 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
618 sprintf(str,"%2.0f",le_current_level->gravity);
619 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
620 sprintf(str,"%d",le_current_level->bkgd_speed);
621 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
622 sprintf(str,"%d",le_current_level->bkgd_top.red);
623 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
624 sprintf(str,"%d",le_current_level->bkgd_top.green);
625 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
626 sprintf(str,"%d",le_current_level->bkgd_top.blue);
627 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
628 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
629 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
630 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
631 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
632 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
633 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
636 void update_subset_settings_menu()
638 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
639 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
642 void apply_level_settings_menu()
647 le_current_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
648 le_current_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
650 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
652 le_current_level->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
656 if(le_current_level->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
658 le_current_level->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
663 le_current_level->load_gfx();
666 le_current_level->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
668 le_current_level->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
669 le_current_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
670 le_current_level->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
671 le_current_level->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
672 le_current_level->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
673 le_current_level->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
674 le_current_level->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
675 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
676 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
677 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
680 void save_subset_settings_menu()
682 le_level_subset->title = subset_settings_menu->item[2].input;
683 le_level_subset->description = subset_settings_menu->item[3].input;
684 le_level_subset->save();
687 void le_goto_level(int levelnb)
689 le_world.arrays_free();
691 le_current_level->cleanup();
692 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
694 le_current_level->load(le_level_subset->name.c_str(), le_level);
703 le_current_level->load_gfx();
705 le_world.activate_bad_guys();
710 /*if(level_changed == true)
711 if(askforsaving() == CANCEL)
714 SDL_EnableKeyRepeat(0, 0); // disables key repeating
717 delete leveleditor_menu;
718 delete subset_load_menu;
719 delete subset_new_menu;
720 delete subset_settings_menu;
721 delete level_settings_menu;
722 delete select_tilegroup_menu;
723 delete select_objects_menu;
724 delete le_save_level_bt;
726 delete le_test_level_bt;
727 delete le_next_level_bt;
728 delete le_previous_level_bt;
729 delete le_move_right_bt;
730 delete le_move_left_bt;
732 delete le_select_mode_one_bt;
733 delete le_select_mode_two_bt;
734 delete le_settings_bt;
735 delete le_tilegroup_bt;
736 delete le_objects_bt;
737 delete le_tilemap_panel;
739 delete le_current_level;
740 le_current_level = 0;
741 delete le_level_subset;
744 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
745 i != tilegroups_map.end(); ++i)
749 for(ButtonPanelMap::iterator i = objects_map.begin();
750 i != objects_map.end(); ++i)
756 void le_drawinterface()
761 if(le_current_level != NULL)
763 /* draw a grid (if selected) */
766 for(x = 0; x < 19; x++)
767 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
768 for(y = 0; y < 15; y++)
769 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
773 if(le_selection_mode == CURSOR)
774 le_selection->draw( cursor_x - scroll_x, cursor_y);
775 else if(le_selection_mode == SQUARE)
778 le_highlight_selection();
779 /* draw current selection */
780 w = selection.x2 - selection.x1;
781 h = selection.y2 - selection.y1;
782 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
783 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
784 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
785 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
789 /* draw button bar */
790 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
792 if(le_current.IsTile())
794 Tile::draw(19 * 32, 14 * 32, le_current.tile);
795 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
796 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
798 if(le_current.IsObject())
800 le_current.obj->draw_on_screen(19 * 32, 14 * 32);
803 //if(le_current.IsObject())
806 if(le_current_level != NULL)
808 le_save_level_bt->draw();
810 le_test_level_bt->draw();
811 le_next_level_bt->draw();
812 le_previous_level_bt->draw();
813 le_rubber_bt->draw();
814 if(le_selection_mode == SQUARE)
815 le_select_mode_one_bt->draw();
816 else if(le_selection_mode == CURSOR)
817 le_select_mode_two_bt->draw();
818 le_settings_bt->draw();
819 le_move_right_bt->draw();
820 le_move_left_bt->draw();
821 le_tilegroup_bt->draw();
822 le_objects_bt->draw();
823 if(!cur_tilegroup.empty())
824 tilegroups_map[cur_tilegroup]->draw();
825 else if(!cur_objects.empty())
827 objects_map[cur_objects]->draw();
830 le_tilemap_panel->draw();
832 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
833 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
835 white_small_text->draw("F1 for Help", 10, 430, 1);
840 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
842 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
849 unsigned int y,x,i,s;
852 /* Draw the real background */
853 if(le_current_level->bkgd_image[0] != '\0')
855 s = (int)((float)pos_x * ((float)le_current_level->bkgd_speed/60.)) % screen->w;
856 le_current_level->img_bkgd->draw_part(s,0,0,0,
857 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
858 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
859 le_current_level->img_bkgd->h);
863 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
866 if(le_current.IsTile())
868 Tile::draw(cursor_x, cursor_y,le_current.tile,128);
869 if(!TileManager::instance()->get(le_current.tile)->images.empty())
870 fillrect(cursor_x,cursor_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);
872 if(le_current.IsObject())
874 le_current.obj->move_to(cursor_x, cursor_y);
877 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
879 for (y = 0; y < 15; ++y)
880 for (x = 0; x < 20; ++x)
883 if(active_tm == TM_BG)
888 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
890 if(active_tm == TM_IA)
895 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
897 if(active_tm == TM_FG)
902 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][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 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
907 TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
911 /* Draw the Bad guys: */
912 for (i = 0; i < le_world.bad_guys.size(); ++i)
914 /* to support frames: img_bsod_left[(frame / 5) % 4] */
917 le_world.bad_guys[i].draw();
921 /* Draw the player: */
922 /* for now, the position is fixed at (100, 240) */
923 largetux.walk_right->draw( 100 - pos_x, 240);
926 void le_checkevents()
933 keymod = SDL_GetModState();
935 while(SDL_PollEvent(&event))
939 Menu::current()->event(event);
943 mouse_cursor->set_state(MC_NORMAL);
945 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
946 if(event.type == SDL_KEYDOWN
947 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
948 && (event.motion.x > 0
949 && event.motion.x < screen->w - 64 &&
950 event.motion.y > 0 && event.motion.y < screen->h)))
954 case SDL_KEYDOWN: // key pressed
955 key = event.key.keysym.sym;
959 Menu::set_current(leveleditor_menu);
962 cursor_x -= KEY_CURSOR_SPEED;
964 cursor_x -= KEY_CURSOR_FASTSPEED;
966 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
967 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
972 cursor_x += KEY_CURSOR_SPEED;
974 cursor_x += KEY_CURSOR_FASTSPEED;
976 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
977 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
982 cursor_y -= KEY_CURSOR_SPEED;
984 cursor_y -= KEY_CURSOR_FASTSPEED;
991 cursor_y += KEY_CURSOR_SPEED;
993 cursor_y += KEY_CURSOR_FASTSPEED;
995 if(cursor_y > screen->h-32)
996 cursor_y = screen->h-32;
1009 cursor_x = (le_current_level->width * 32) - 32;
1013 le_show_grid = !le_show_grid;
1019 case SDL_KEYUP: /* key released */
1020 switch(event.key.keysym.sym)
1029 case SDL_MOUSEBUTTONDOWN:
1030 if(event.button.button == SDL_BUTTON_LEFT)
1032 le_mouse_pressed[LEFT] = true;
1034 selection.x1 = event.motion.x + pos_x;
1035 selection.y1 = event.motion.y;
1036 selection.x2 = event.motion.x + pos_x;
1037 selection.y2 = event.motion.y;
1039 else if(event.button.button == SDL_BUTTON_RIGHT)
1041 le_mouse_pressed[RIGHT] = true;
1044 case SDL_MOUSEBUTTONUP:
1045 if(event.button.button == SDL_BUTTON_LEFT)
1046 le_mouse_pressed[LEFT] = false;
1047 else if(event.button.button == SDL_BUTTON_RIGHT)
1048 le_mouse_pressed[RIGHT] = false;
1050 case SDL_MOUSEMOTION:
1052 if(!Menu::current())
1057 if(le_current.IsTile())
1059 cursor_x = ((int)(pos_x + x) / 32) * 32;
1060 cursor_y = ((int) y / 32) * 32;
1068 if(le_mouse_pressed[LEFT])
1070 selection.x2 = x + pos_x;
1074 if(le_mouse_pressed[RIGHT])
1076 pos_x += -1 * event.motion.xrel;
1080 case SDL_QUIT: // window closed
1089 if(le_current_level != NULL)
1091 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 &&
1092 event.motion.y > 0 && event.motion.y < screen->h)))
1094 le_mouse_pressed[LEFT] = false;
1095 le_mouse_pressed[RIGHT] = false;
1097 if(!Menu::current())
1099 /* Check for button events */
1100 le_test_level_bt->event(event);
1101 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1103 le_save_level_bt->event(event);
1104 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1105 le_current_level->save(le_level_subset->name.c_str(),le_level);
1106 le_exit_bt->event(event);
1107 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1109 Menu::set_current(leveleditor_menu);
1111 le_next_level_bt->event(event);
1112 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1114 if(le_level < le_level_subset->levels)
1116 le_goto_level(++le_level);
1122 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1123 if(confirm_dialog(str))
1125 new_lev.init_defaults();
1126 new_lev.save(le_level_subset->name.c_str(),++le_level);
1127 le_level_subset->levels = le_level;
1128 le_goto_level(le_level);
1132 le_previous_level_bt->event(event);
1133 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1136 le_goto_level(--le_level);
1138 le_rubber_bt->event(event);
1139 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1142 if(le_selection_mode == SQUARE)
1144 le_select_mode_one_bt->event(event);
1145 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1146 le_selection_mode = CURSOR;
1150 le_select_mode_two_bt->event(event);
1151 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1152 le_selection_mode = SQUARE;
1155 le_tilegroup_bt->event(event);
1156 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1158 Menu::set_current(select_tilegroup_menu);
1159 select_tilegroup_menu_effect.start(200);
1160 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1163 le_objects_bt->event(event);
1164 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1166 Menu::set_current(select_objects_menu);
1167 select_objects_menu_effect.start(200);
1168 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1171 le_settings_bt->event(event);
1172 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1174 update_level_settings_menu();
1175 Menu::set_current(level_settings_menu);
1177 if(!cur_tilegroup.empty())
1179 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1181 if(pbutton->get_state() == BUTTON_CLICKED)
1183 if(le_current.IsObject())
1184 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1185 le_current.Tile(pbutton->get_tag());
1189 else if(!cur_objects.empty())
1191 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1193 if(pbutton->get_state() == BUTTON_CLICKED)
1195 if(le_current.IsObject())
1196 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1197 le_current.Object(pbutton->get_game_object());
1202 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1204 if(pbutton->get_state() == BUTTON_CLICKED)
1206 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1212 le_settings_bt->event(event);
1213 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1215 Menu::set_current(0);
1217 le_tilegroup_bt->event(event);
1218 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1220 Menu::set_current(0);
1225 if(!Menu::current())
1227 le_move_left_bt->event(event);
1228 le_move_right_bt->event(event);
1230 if(le_mouse_pressed[LEFT])
1232 if(le_current.IsTile())
1233 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1234 else if(le_current.IsObject())
1236 std::string type = le_current.obj->type();
1237 if(type == "BadGuy")
1239 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1241 le_world.bad_guys.push_back(BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1242 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1249 if(!Menu::current())
1251 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1255 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1260 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1264 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1272 void le_highlight_selection()
1276 if(selection.x1 < selection.x2)
1286 if(selection.y1 < selection.y2)
1302 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1305 void le_change(float x, float y, int tm, unsigned int c)
1307 if(le_current_level != NULL)
1313 /* level_changed = true; */
1315 switch(le_selection_mode)
1318 le_current_level->change(x,y,tm,c);
1320 base_type cursor_base;
1323 cursor_base.width = 32;
1324 cursor_base.height = 32;
1326 /* if there is a bad guy over there, remove it */
1327 for(i = 0; i < le_world.bad_guys.size(); ++i)
1328 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1330 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1331 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1336 if(selection.x1 < selection.x2)
1346 if(selection.y1 < selection.y2)
1362 /* if there is a bad guy over there, remove it */
1363 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1364 i != le_world.bad_guys.end(); /* will be at end of loop */)
1366 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1367 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1369 i = le_world.bad_guys.erase(i);
1378 for(xx = x1; xx <= x2; xx++)
1379 for(yy = y1; yy <= y2; yy++)
1381 le_current_level->change(xx*32, yy*32, tm, c);
1393 le_current_level->save("test", le_level);
1395 GameSession session("test",le_level, ST_GL_TEST);
1397 player_status.reset();
1399 music_manager->halt_music();
1401 Menu::set_current(leveleditor_menu);
1402 le_world.arrays_free();
1403 le_current_level->load_gfx();
1404 le_world.activate_bad_guys();
1410 unsigned int i, done_;
1412 " - This is SuperTux's built-in level editor -",
1413 "It has been designed to be light and easy to use from the start.",
1415 "When you first load the level editor you are given a menu where you",
1416 "can load level subsets, create a new level subset, edit the current",
1417 "subset's settings, or simply quit the editor. You can access this menu",
1418 "from the level editor at any time by pressing the escape key.",
1420 "To your right is your button bar. The center of this contains many",
1421 "tiles you can use to make your level. To select a tile, click on it",
1422 "with your left mouse button; your selection will be shown in the",
1423 "bottom right corner of the button box. Click anywhere on your level",
1424 "with the left mouse button to place that tile down. If you right click",
1425 "a tile in the button bar, you can find out what its keyboard shortcut",
1426 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1427 "background, and enemy tiles. The eraser lets you remove tiles.",
1428 "The left and right arrow keys scroll back and forth through your level.",
1429 "The button with the wrench and screwdriver, lets you change the",
1430 "settings of your level, including how long it is or what music it will",
1431 "play. When you are ready to give your level a test, click on the little",
1432 "running Tux. If you like the changes you have made to your level,",
1433 "press the red save key to keep them.",
1434 "To change which level in your subset you are editing, press the white",
1435 "up and down arrow keys at the top of the button box.",
1437 "Have fun making levels! If you make some good ones, send them to us on",
1438 "the SuperTux mailing list!",
1443 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1445 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1446 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1448 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1456 done_ = wait_for_event(event);