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; };
120 void Init() { tile = 0; obj = NULL; is_tile = true; };
122 bool is_tile; //true for tile (false for object)
127 /* leveleditor internals */
128 static string_list_type level_subsets;
129 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
130 static int pos_x, cursor_x, cursor_y, fire;
132 static LevelEditorWorld le_world;
133 static LevelSubset* le_level_subset;
134 static int le_show_grid;
136 static Surface* le_selection;
138 static TileOrObject le_current;
139 static bool le_mouse_pressed[2];
140 static Button* le_save_level_bt;
141 static Button* le_exit_bt;
142 static Button* le_test_level_bt;
143 static Button* le_next_level_bt;
144 static Button* le_previous_level_bt;
145 static Button* le_move_right_bt;
146 static Button* le_move_left_bt;
147 static Button* le_rubber_bt;
148 static Button* le_select_mode_one_bt;
149 static Button* le_select_mode_two_bt;
150 static Button* le_settings_bt;
151 static Button* le_tilegroup_bt;
152 static Button* le_objects_bt;
153 static ButtonPanel* le_tilemap_panel;
154 static Menu* leveleditor_menu;
155 static Menu* subset_load_menu;
156 static Menu* subset_new_menu;
157 static Menu* subset_settings_menu;
158 static Menu* level_settings_menu;
159 static Menu* select_tilegroup_menu;
160 static Menu* select_objects_menu;
161 static Timer select_tilegroup_menu_effect;
162 static Timer select_objects_menu_effect;
163 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
164 static ButtonPanelMap tilegroups_map;
165 static ButtonPanelMap objects_map;
166 static std::string cur_tilegroup;
167 static std::string cur_objects;
169 static square selection;
170 static int le_selection_mode;
171 static SDL_Event event;
172 TileMapType active_tm;
174 void le_set_defaults()
176 if(le_current_level != NULL)
180 if(le_current_level->time_left == 0)
181 le_current_level->time_left = 255;
185 int leveleditor(int levelnb)
187 int last_time, now_time, i;
195 clearscreen(0, 0, 0);
198 music_manager->halt_music();
200 while (SDL_PollEvent(&event))
205 last_time = SDL_GetTicks();
210 if(Menu::current() == select_tilegroup_menu)
212 if(select_tilegroup_menu_effect.check())
214 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
218 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
220 else if(Menu::current() == select_objects_menu)
222 if(select_objects_menu_effect.check())
224 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
227 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
230 if(le_current_level != NULL)
232 /* making events results to be in order */
235 if(pos_x > (le_current_level->width * 32) - screen->w)
236 pos_x = (le_current_level->width * 32) - screen->w;
242 clearscreen(0, 0, 0);
244 /* draw editor interface */
247 Menu* menu = Menu::current();
253 if(menu == leveleditor_menu)
255 switch (leveleditor_menu->check())
257 case MNID_RETURNLEVELEDITOR:
258 Menu::set_current(0);
260 case MNID_SUBSETSETTINGS:
261 update_subset_settings_menu();
263 case MNID_QUITLEVELEDITOR:
268 else if(menu == level_settings_menu)
270 switch (level_settings_menu->check())
273 apply_level_settings_menu();
274 Menu::set_current(NULL);
282 else if(menu == select_tilegroup_menu)
285 switch (it = select_tilegroup_menu->check())
291 = select_tilegroup_menu->get_item_by_id(it).text;
292 Menu::set_current(0);
299 else if(menu == select_objects_menu)
302 switch (it = select_objects_menu->check())
307 cur_objects = select_objects_menu->get_item_by_id(it).text;
308 cur_tilegroup.clear();
310 Menu::set_current(0);
315 else if(menu == subset_load_menu)
317 switch (i = subset_load_menu->check())
324 le_level_subset->load(level_subsets.item[i-1]);
325 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
327 le_world.arrays_free();
328 delete le_current_level;
329 le_current_level = new Level;
330 if(le_current_level->load(le_level_subset->name, le_level) != 0)
336 le_current_level->load_gfx();
337 le_world.activate_bad_guys();
339 Menu::set_current(NULL);
344 else if(menu == subset_new_menu)
346 if(subset_new_menu->item[2].input[0] == '\0')
347 subset_new_menu->item[3].kind = MN_DEACTIVE;
350 subset_new_menu->item[3].kind = MN_ACTION;
352 switch (i = subset_new_menu->check())
354 case MNID_CREATESUBSET:
355 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
356 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
357 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
359 le_world.arrays_free();
360 delete le_current_level;
361 le_current_level = new Level;
362 if(le_current_level->load(le_level_subset->name, le_level) != 0)
368 le_current_level->load_gfx();
369 le_world.activate_bad_guys();
370 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
372 Menu::set_current(subset_settings_menu);
377 else if(menu == subset_settings_menu)
379 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 )
380 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
382 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
384 switch (i = subset_settings_menu->check())
386 case MNID_SUBSETSAVECHANGES:
387 save_subset_settings_menu();
388 //FIXME:show_menu = true;
389 Menu::set_current(leveleditor_menu);
395 mouse_cursor->draw();
403 ++global_frame_counter;
406 now_time = SDL_GetTicks();
407 if (now_time < last_time + FPS)
408 SDL_Delay(last_time + FPS - now_time); /* delay some time */
421 leveleditor_menu = new Menu();
422 subset_load_menu = new Menu();
423 subset_new_menu = new Menu();
424 subset_settings_menu = new Menu();
425 level_settings_menu = new Menu();
426 select_tilegroup_menu = new Menu();
427 select_objects_menu = new Menu();
429 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
430 leveleditor_menu->additem(MN_HL,"",0,0);
431 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
432 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
433 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
434 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
435 leveleditor_menu->additem(MN_HL,"",0,0);
436 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
438 Menu::set_current(leveleditor_menu);
440 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
441 subset_load_menu->additem(MN_HL, "", 0, 0);
443 for(i = 0; i < level_subsets.num_items; ++i)
445 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
447 subset_load_menu->additem(MN_HL,"",0,0);
448 subset_load_menu->additem(MN_BACK,"Back",0,0);
450 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
451 subset_new_menu->additem(MN_HL,"",0,0);
452 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
453 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
454 subset_new_menu->additem(MN_HL,"",0,0);
455 subset_new_menu->additem(MN_BACK,"Back",0,0);
457 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
458 subset_settings_menu->additem(MN_HL,"",0,0);
459 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
460 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
461 subset_settings_menu->additem(MN_HL,"",0,0);
462 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
463 subset_settings_menu->additem(MN_HL,"",0,0);
464 subset_settings_menu->additem(MN_BACK,"Back",0,0);
466 level_settings_menu->arrange_left = true;
467 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
468 level_settings_menu->additem(MN_HL,"",0,0);
469 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0,MNID_NAME);
470 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0,MNID_AUTHOR);
471 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
472 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
473 level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
474 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0,MNID_LENGTH);
475 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0,MNID_TIME);
476 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0,MNID_GRAVITY);
477 level_settings_menu->additem(MN_NUMFIELD,"Bg-Img-Speed",0,0,MNID_BGSPEED);
478 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0,MNID_TopRed);
479 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0,MNID_TopGreen);
480 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0,MNID_TopBlue);
481 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0,MNID_BottomRed);
482 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0,MNID_BottomGreen);
483 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0,MNID_BottomBlue);
484 level_settings_menu->additem(MN_HL,"",0,0);
485 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
487 select_tilegroup_menu->arrange_left = true;
488 select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
489 select_tilegroup_menu->additem(MN_HL,"",0,0);
490 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
492 for(std::vector<TileGroup>::iterator it = tilegroups->begin();
493 it != tilegroups->end(); ++it )
495 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
497 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
500 for(std::vector<int>::iterator sit = (*it).tiles.begin();
501 sit != (*it).tiles.end(); ++sit, ++i)
503 std::string imagefile = "/images/tilesets/" ;
504 bool only_editor_image = false;
505 if(!TileManager::instance()->get(*sit)->filenames.empty())
507 imagefile += TileManager::instance()->get(*sit)->filenames[0];
509 else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
511 imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
512 only_editor_image = true;
516 imagefile += "notile.png";
518 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
520 if(!only_editor_image)
521 if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
523 imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
524 button->add_icon(imagefile,32,32);
526 tilegroups_map[it->name]->additem(button, *sit);
529 select_tilegroup_menu->additem(MN_HL,"",0,0);
531 select_objects_menu->arrange_left = true;
532 select_objects_menu->additem(MN_LABEL,"Objects",0,0);
533 select_objects_menu->additem(MN_HL,"",0,0);
534 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
535 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
537 for(int i = 0; i < NUM_BadGuyKinds; ++i)
539 BadGuy bad_tmp(0,0,BadGuyKind(i),false);
540 objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
541 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));
544 select_objects_menu->additem(MN_HL,"",0,0);
550 level_subsets = dsubdirs("/levels", "info");
551 le_level_subset = new LevelSubset;
559 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
560 le_level_changed = false;
561 le_current_level = NULL;
563 le_mouse_pressed[LEFT] = false;
564 le_mouse_pressed[RIGHT] = false;
566 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
568 select_tilegroup_menu_effect.init(false);
569 select_objects_menu_effect.init(false);
572 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
573 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
574 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
575 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
576 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
577 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
578 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
579 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
580 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
581 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
582 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
583 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
584 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
586 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
587 le_tilemap_panel->set_button_size(32,10);
588 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
589 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0),TM_IA);
590 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
591 le_tilemap_panel->highlight_last(true);
597 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
602 void update_level_settings_menu()
607 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_current_level->name.c_str());
608 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_current_level->author.c_str());
610 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
611 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
612 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
613 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
614 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
615 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
617 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_current_level->song_title.c_str())) != -1)
618 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
619 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_current_level->bkgd_image.c_str())) != -1)
620 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
621 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_current_level->particle_system.c_str())) != -1)
622 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
624 sprintf(str,"%d",le_current_level->width);
625 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
626 sprintf(str,"%d",le_current_level->time_left);
627 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
628 sprintf(str,"%2.0f",le_current_level->gravity);
629 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
630 sprintf(str,"%d",le_current_level->bkgd_speed);
631 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
632 sprintf(str,"%d",le_current_level->bkgd_top.red);
633 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
634 sprintf(str,"%d",le_current_level->bkgd_top.green);
635 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
636 sprintf(str,"%d",le_current_level->bkgd_top.blue);
637 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
638 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
639 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
640 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
641 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
642 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
643 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
646 void update_subset_settings_menu()
648 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
649 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
652 void apply_level_settings_menu()
657 le_current_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
658 le_current_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
660 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
662 le_current_level->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
666 if(le_current_level->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
668 le_current_level->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
673 le_current_level->load_gfx();
676 le_current_level->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
678 le_current_level->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
679 le_current_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
680 le_current_level->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
681 le_current_level->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
682 le_current_level->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
683 le_current_level->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
684 le_current_level->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
685 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
686 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
687 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
690 void save_subset_settings_menu()
692 le_level_subset->title = subset_settings_menu->item[2].input;
693 le_level_subset->description = subset_settings_menu->item[3].input;
694 le_level_subset->save();
697 void le_goto_level(int levelnb)
699 le_world.arrays_free();
701 le_current_level->cleanup();
702 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
704 le_current_level->load(le_level_subset->name.c_str(), le_level);
713 le_current_level->load_gfx();
715 le_world.activate_bad_guys();
720 /*if(level_changed == true)
721 if(askforsaving() == CANCEL)
724 SDL_EnableKeyRepeat(0, 0); // disables key repeating
727 delete leveleditor_menu;
728 delete subset_load_menu;
729 delete subset_new_menu;
730 delete subset_settings_menu;
731 delete level_settings_menu;
732 delete select_tilegroup_menu;
733 delete select_objects_menu;
734 delete le_save_level_bt;
736 delete le_test_level_bt;
737 delete le_next_level_bt;
738 delete le_previous_level_bt;
739 delete le_move_right_bt;
740 delete le_move_left_bt;
742 delete le_select_mode_one_bt;
743 delete le_select_mode_two_bt;
744 delete le_settings_bt;
745 delete le_tilegroup_bt;
746 delete le_objects_bt;
747 delete le_tilemap_panel;
749 delete le_current_level;
750 le_current_level = 0;
751 delete le_level_subset;
754 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
755 i != tilegroups_map.end(); ++i)
759 for(ButtonPanelMap::iterator i = objects_map.begin();
760 i != objects_map.end(); ++i)
766 void le_drawinterface()
771 if(le_current_level != NULL)
773 /* draw a grid (if selected) */
776 for(x = 0; x < 19; x++)
777 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
778 for(y = 0; y < 15; y++)
779 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
783 if(le_selection_mode == CURSOR)
784 le_selection->draw( cursor_x - scroll_x, cursor_y);
785 else if(le_selection_mode == SQUARE)
788 le_highlight_selection();
789 /* draw current selection */
790 w = selection.x2 - selection.x1;
791 h = selection.y2 - selection.y1;
792 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
793 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
794 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
795 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
799 /* draw button bar */
800 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
802 if(le_current.IsTile())
804 Tile::draw(19 * 32, 14 * 32, le_current.tile);
805 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
806 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
808 if(le_current.IsObject())
810 le_current.obj->draw_on_screen(19 * 32, 14 * 32);
813 //if(le_current.IsObject())
816 if(le_current_level != NULL)
818 le_save_level_bt->draw();
820 le_test_level_bt->draw();
821 le_next_level_bt->draw();
822 le_previous_level_bt->draw();
823 le_rubber_bt->draw();
824 if(le_selection_mode == SQUARE)
825 le_select_mode_one_bt->draw();
826 else if(le_selection_mode == CURSOR)
827 le_select_mode_two_bt->draw();
828 le_settings_bt->draw();
829 le_move_right_bt->draw();
830 le_move_left_bt->draw();
831 le_tilegroup_bt->draw();
832 le_objects_bt->draw();
833 if(!cur_tilegroup.empty())
834 tilegroups_map[cur_tilegroup]->draw();
835 else if(!cur_objects.empty())
837 objects_map[cur_objects]->draw();
840 le_tilemap_panel->draw();
842 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
843 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
845 white_small_text->draw("F1 for Help", 10, 430, 1);
850 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
852 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
859 unsigned int y,x,i,s;
862 /* Draw the real background */
863 if(le_current_level->bkgd_image[0] != '\0')
865 s = (int)((float)pos_x * ((float)le_current_level->bkgd_speed/60.)) % screen->w;
866 le_current_level->img_bkgd->draw_part(s,0,0,0,
867 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
868 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
869 le_current_level->img_bkgd->h);
873 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
876 if(le_current.IsTile())
878 Tile::draw(cursor_x, cursor_y,le_current.tile,128);
879 if(!TileManager::instance()->get(le_current.tile)->images.empty())
880 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);
882 if(le_current.IsObject())
884 le_current.obj->move_to(cursor_x, cursor_y);
887 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
889 for (y = 0; y < 15; ++y)
890 for (x = 0; x < 20; ++x)
893 if(active_tm == TM_BG)
898 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
900 if(active_tm == TM_IA)
905 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
907 if(active_tm == TM_FG)
912 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
914 /* draw whats inside stuff when cursor is selecting those */
915 /* (draw them all the time - is this the right behaviour?) */
916 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
917 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);
921 /* Draw the Bad guys: */
922 for (i = 0; i < le_world.bad_guys.size(); ++i)
924 /* to support frames: img_bsod_left[(frame / 5) % 4] */
927 le_world.bad_guys[i].draw();
931 /* Draw the player: */
932 /* for now, the position is fixed at (100, 240) */
933 largetux.walk_right->draw( 100 - pos_x, 240);
936 void le_checkevents()
943 keymod = SDL_GetModState();
945 while(SDL_PollEvent(&event))
949 Menu::current()->event(event);
953 mouse_cursor->set_state(MC_NORMAL);
955 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
956 if(event.type == SDL_KEYDOWN
957 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
958 && (event.motion.x > 0
959 && event.motion.x < screen->w - 64 &&
960 event.motion.y > 0 && event.motion.y < screen->h)))
964 case SDL_KEYDOWN: // key pressed
965 key = event.key.keysym.sym;
969 Menu::set_current(leveleditor_menu);
972 cursor_x -= KEY_CURSOR_SPEED;
974 cursor_x -= KEY_CURSOR_FASTSPEED;
976 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
977 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
982 cursor_x += KEY_CURSOR_SPEED;
984 cursor_x += KEY_CURSOR_FASTSPEED;
986 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
987 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
992 cursor_y -= KEY_CURSOR_SPEED;
994 cursor_y -= KEY_CURSOR_FASTSPEED;
1001 cursor_y += KEY_CURSOR_SPEED;
1003 cursor_y += KEY_CURSOR_FASTSPEED;
1005 if(cursor_y > screen->h-32)
1006 cursor_y = screen->h-32;
1019 cursor_x = (le_current_level->width * 32) - 32;
1023 le_show_grid = !le_show_grid;
1029 case SDL_KEYUP: /* key released */
1030 switch(event.key.keysym.sym)
1039 case SDL_MOUSEBUTTONDOWN:
1040 if(event.button.button == SDL_BUTTON_LEFT)
1042 le_mouse_pressed[LEFT] = true;
1044 selection.x1 = event.motion.x + pos_x;
1045 selection.y1 = event.motion.y;
1046 selection.x2 = event.motion.x + pos_x;
1047 selection.y2 = event.motion.y;
1049 else if(event.button.button == SDL_BUTTON_RIGHT)
1051 le_mouse_pressed[RIGHT] = true;
1054 case SDL_MOUSEBUTTONUP:
1055 if(event.button.button == SDL_BUTTON_LEFT)
1056 le_mouse_pressed[LEFT] = false;
1057 else if(event.button.button == SDL_BUTTON_RIGHT)
1058 le_mouse_pressed[RIGHT] = false;
1060 case SDL_MOUSEMOTION:
1062 if(!Menu::current())
1067 if(le_current.IsTile())
1069 cursor_x = ((int)(pos_x + x) / 32) * 32;
1070 cursor_y = ((int) y / 32) * 32;
1078 if(le_mouse_pressed[LEFT])
1080 selection.x2 = x + pos_x;
1084 if(le_mouse_pressed[RIGHT])
1086 pos_x += -1 * event.motion.xrel;
1090 case SDL_QUIT: // window closed
1099 if(le_current_level != NULL)
1101 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 &&
1102 event.motion.y > 0 && event.motion.y < screen->h)))
1104 le_mouse_pressed[LEFT] = false;
1105 le_mouse_pressed[RIGHT] = false;
1107 if(!Menu::current())
1109 /* Check for button events */
1110 le_test_level_bt->event(event);
1111 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1113 le_save_level_bt->event(event);
1114 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1115 le_current_level->save(le_level_subset->name.c_str(),le_level);
1116 le_exit_bt->event(event);
1117 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1119 Menu::set_current(leveleditor_menu);
1121 le_next_level_bt->event(event);
1122 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1124 if(le_level < le_level_subset->levels)
1126 le_goto_level(++le_level);
1132 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1133 if(confirm_dialog(str))
1135 new_lev.init_defaults();
1136 new_lev.save(le_level_subset->name.c_str(),++le_level);
1137 le_level_subset->levels = le_level;
1138 le_goto_level(le_level);
1142 le_previous_level_bt->event(event);
1143 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1146 le_goto_level(--le_level);
1148 le_rubber_bt->event(event);
1149 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1152 if(le_selection_mode == SQUARE)
1154 le_select_mode_one_bt->event(event);
1155 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1156 le_selection_mode = CURSOR;
1160 le_select_mode_two_bt->event(event);
1161 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1162 le_selection_mode = SQUARE;
1165 le_tilegroup_bt->event(event);
1166 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1168 Menu::set_current(select_tilegroup_menu);
1169 select_tilegroup_menu_effect.start(200);
1170 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1173 le_objects_bt->event(event);
1174 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1176 Menu::set_current(select_objects_menu);
1177 select_objects_menu_effect.start(200);
1178 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1181 le_settings_bt->event(event);
1182 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1184 update_level_settings_menu();
1185 Menu::set_current(level_settings_menu);
1187 if(!cur_tilegroup.empty())
1189 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1191 if(pbutton->get_state() == BUTTON_CLICKED)
1193 if(le_current.IsObject())
1194 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1195 le_current.Tile(pbutton->get_tag());
1199 else if(!cur_objects.empty())
1201 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1203 if(pbutton->get_state() == BUTTON_CLICKED)
1205 if(le_current.IsObject())
1206 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1207 le_current.Object(pbutton->get_game_object());
1212 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1214 if(pbutton->get_state() == BUTTON_CLICKED)
1216 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1222 le_settings_bt->event(event);
1223 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1225 Menu::set_current(0);
1227 le_tilegroup_bt->event(event);
1228 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1230 Menu::set_current(0);
1235 if(!Menu::current())
1237 le_move_left_bt->event(event);
1238 le_move_right_bt->event(event);
1240 if(le_mouse_pressed[LEFT])
1242 if(le_current.IsTile())
1243 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1244 else if(le_current.IsObject())
1246 std::string type = le_current.obj->type();
1247 if(type == "BadGuy")
1249 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1251 le_world.bad_guys.push_back(BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1252 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1259 if(!Menu::current())
1261 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1265 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1270 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1274 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1282 void le_highlight_selection()
1286 if(selection.x1 < selection.x2)
1296 if(selection.y1 < selection.y2)
1312 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1315 void le_change(float x, float y, int tm, unsigned int c)
1317 if(le_current_level != NULL)
1323 /* level_changed = true; */
1325 switch(le_selection_mode)
1328 le_current_level->change(x,y,tm,c);
1330 base_type cursor_base;
1333 cursor_base.width = 32;
1334 cursor_base.height = 32;
1336 /* if there is a bad guy over there, remove it */
1337 for(i = 0; i < le_world.bad_guys.size(); ++i)
1338 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1340 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1341 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1346 if(selection.x1 < selection.x2)
1356 if(selection.y1 < selection.y2)
1372 /* if there is a bad guy over there, remove it */
1373 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1374 i != le_world.bad_guys.end(); /* will be at end of loop */)
1376 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1377 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1379 i = le_world.bad_guys.erase(i);
1388 for(xx = x1; xx <= x2; xx++)
1389 for(yy = y1; yy <= y2; yy++)
1391 le_current_level->change(xx*32, yy*32, tm, c);
1403 le_current_level->save("test", le_level);
1405 GameSession session("test",le_level, ST_GL_TEST);
1407 player_status.reset();
1409 music_manager->halt_music();
1411 Menu::set_current(NULL);
1412 le_world.arrays_free();
1413 le_current_level->load_gfx();
1414 le_world.activate_bad_guys();
1420 unsigned int i, done_;
1422 " - This is SuperTux's built-in level editor -",
1423 "It has been designed to be light and easy to use from the start.",
1425 "When you first load the level editor you are given a menu where you",
1426 "can load level subsets, create a new level subset, edit the current",
1427 "subset's settings, or simply quit the editor. You can access this menu",
1428 "from the level editor at any time by pressing the escape key.",
1430 "To your right is your button bar. The center of this contains many",
1431 "tiles you can use to make your level. To select a tile, click on it",
1432 "with your left mouse button; your selection will be shown in the",
1433 "bottom right corner of the button box. Click anywhere on your level",
1434 "with the left mouse button to place that tile down. If you right click",
1435 "a tile in the button bar, you can find out what its keyboard shortcut",
1436 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1437 "background, and enemy tiles. The eraser lets you remove tiles.",
1438 "The left and right arrow keys scroll back and forth through your level.",
1439 "The button with the wrench and screwdriver, lets you change the",
1440 "settings of your level, including how long it is or what music it will",
1441 "play. When you are ready to give your level a test, click on the little",
1442 "running Tux. If you like the changes you have made to your level,",
1443 "press the red save key to keep them.",
1444 "To change which level in your subset you are editing, press the white",
1445 "up and down arrow keys at the top of the button box.",
1447 "Have fun making levels! If you make some good ones, send them to us on",
1448 "the SuperTux mailing list!",
1453 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1455 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1456 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1458 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1466 done_ = wait_for_event(event);