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);
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,"Select 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,"Select 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_F4,0,0),TM_BG);
589 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
590 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
596 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
601 void update_level_settings_menu()
606 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_current_level->name.c_str());
607 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_current_level->author.c_str());
609 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
610 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
611 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
612 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
613 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
614 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
616 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_current_level->song_title.c_str())) != -1)
617 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
618 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_current_level->bkgd_image.c_str())) != -1)
619 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
620 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_current_level->particle_system.c_str())) != -1)
621 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
623 sprintf(str,"%d",le_current_level->width);
624 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
625 sprintf(str,"%d",le_current_level->time_left);
626 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
627 sprintf(str,"%2.0f",le_current_level->gravity);
628 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
629 sprintf(str,"%d",le_current_level->bkgd_speed);
630 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
631 sprintf(str,"%d",le_current_level->bkgd_top.red);
632 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
633 sprintf(str,"%d",le_current_level->bkgd_top.green);
634 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
635 sprintf(str,"%d",le_current_level->bkgd_top.blue);
636 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
637 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
638 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
639 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
640 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
641 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
642 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
645 void update_subset_settings_menu()
647 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
648 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
651 void apply_level_settings_menu()
656 le_current_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
657 le_current_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
659 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
661 le_current_level->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
665 if(le_current_level->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
667 le_current_level->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
672 le_current_level->load_gfx();
675 le_current_level->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
677 le_current_level->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
678 le_current_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
679 le_current_level->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
680 le_current_level->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
681 le_current_level->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
682 le_current_level->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
683 le_current_level->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
684 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
685 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
686 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
689 void save_subset_settings_menu()
691 le_level_subset->title = subset_settings_menu->item[2].input;
692 le_level_subset->description = subset_settings_menu->item[3].input;
693 le_level_subset->save();
696 void le_goto_level(int levelnb)
698 le_world.arrays_free();
700 le_current_level->cleanup();
701 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
703 le_current_level->load(le_level_subset->name.c_str(), le_level);
712 le_current_level->load_gfx();
714 le_world.activate_bad_guys();
719 /*if(level_changed == true)
720 if(askforsaving() == CANCEL)
723 SDL_EnableKeyRepeat(0, 0); // disables key repeating
726 delete leveleditor_menu;
727 delete subset_load_menu;
728 delete subset_new_menu;
729 delete subset_settings_menu;
730 delete level_settings_menu;
731 delete select_tilegroup_menu;
732 delete select_objects_menu;
733 delete le_save_level_bt;
735 delete le_test_level_bt;
736 delete le_next_level_bt;
737 delete le_previous_level_bt;
738 delete le_move_right_bt;
739 delete le_move_left_bt;
741 delete le_select_mode_one_bt;
742 delete le_select_mode_two_bt;
743 delete le_settings_bt;
744 delete le_tilegroup_bt;
745 delete le_objects_bt;
746 delete le_tilemap_panel;
748 delete le_current_level;
749 le_current_level = 0;
750 delete le_level_subset;
753 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
754 i != tilegroups_map.end(); ++i)
758 for(ButtonPanelMap::iterator i = objects_map.begin();
759 i != objects_map.end(); ++i)
765 void le_drawinterface()
770 if(le_current_level != NULL)
772 /* draw a grid (if selected) */
775 for(x = 0; x < 19; x++)
776 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
777 for(y = 0; y < 15; y++)
778 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
782 if(le_selection_mode == CURSOR)
783 le_selection->draw( cursor_x - scroll_x, cursor_y);
784 else if(le_selection_mode == SQUARE)
787 le_highlight_selection();
788 /* draw current selection */
789 w = selection.x2 - selection.x1;
790 h = selection.y2 - selection.y1;
791 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
792 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
793 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
794 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
798 /* draw button bar */
799 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
801 if(le_current.IsTile())
803 Tile::draw(19 * 32, 14 * 32, le_current.tile);
804 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
805 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
807 if(le_current.IsObject())
809 le_current.obj->draw_on_screen(19 * 32, 14 * 32);
812 //if(le_current.IsObject())
815 if(le_current_level != NULL)
817 le_save_level_bt->draw();
819 le_test_level_bt->draw();
820 le_next_level_bt->draw();
821 le_previous_level_bt->draw();
822 le_rubber_bt->draw();
823 if(le_selection_mode == SQUARE)
824 le_select_mode_one_bt->draw();
825 else if(le_selection_mode == CURSOR)
826 le_select_mode_two_bt->draw();
827 le_settings_bt->draw();
828 le_move_right_bt->draw();
829 le_move_left_bt->draw();
830 le_tilegroup_bt->draw();
831 le_objects_bt->draw();
832 if(!cur_tilegroup.empty())
833 tilegroups_map[cur_tilegroup]->draw();
834 else if(!cur_objects.empty())
836 objects_map[cur_objects]->draw();
839 le_tilemap_panel->draw();
841 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
842 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
844 white_small_text->draw("F1 for Help", 10, 430, 1);
849 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
851 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
858 unsigned int y,x,i,s;
861 /* Draw the real background */
862 if(le_current_level->bkgd_image[0] != '\0')
864 s = (int)((float)pos_x * ((float)le_current_level->bkgd_speed/60.)) % screen->w;
865 le_current_level->img_bkgd->draw_part(s,0,0,0,
866 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
867 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
868 le_current_level->img_bkgd->h);
872 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
875 if(le_current.IsTile())
877 Tile::draw(cursor_x, cursor_y,le_current.tile,128);
878 if(!TileManager::instance()->get(le_current.tile)->images.empty())
879 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);
881 if(le_current.IsObject())
883 le_current.obj->move_to(cursor_x, cursor_y);
886 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
888 for (y = 0; y < 15; ++y)
889 for (x = 0; x < 20; ++x)
892 if(active_tm == TM_BG)
897 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
899 if(active_tm == TM_IA)
904 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
906 if(active_tm == TM_FG)
911 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
913 /* draw whats inside stuff when cursor is selecting those */
914 /* (draw them all the time - is this the right behaviour?) */
915 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
916 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);
920 /* Draw the Bad guys: */
921 for (i = 0; i < le_world.bad_guys.size(); ++i)
923 /* to support frames: img_bsod_left[(frame / 5) % 4] */
926 le_world.bad_guys[i].draw();
930 /* Draw the player: */
931 /* for now, the position is fixed at (100, 240) */
932 largetux.walk_right->draw( 100 - pos_x, 240);
935 void le_checkevents()
942 keymod = SDL_GetModState();
944 while(SDL_PollEvent(&event))
948 Menu::current()->event(event);
952 mouse_cursor->set_state(MC_NORMAL);
954 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
955 if(event.type == SDL_KEYDOWN
956 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
957 && (event.motion.x > 0
958 && event.motion.x < screen->w - 64 &&
959 event.motion.y > 0 && event.motion.y < screen->h)))
963 case SDL_KEYDOWN: // key pressed
964 key = event.key.keysym.sym;
968 Menu::set_current(leveleditor_menu);
971 cursor_x -= KEY_CURSOR_SPEED;
973 cursor_x -= KEY_CURSOR_FASTSPEED;
975 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
976 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
981 cursor_x += KEY_CURSOR_SPEED;
983 cursor_x += KEY_CURSOR_FASTSPEED;
985 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
986 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
991 cursor_y -= KEY_CURSOR_SPEED;
993 cursor_y -= KEY_CURSOR_FASTSPEED;
1000 cursor_y += KEY_CURSOR_SPEED;
1002 cursor_y += KEY_CURSOR_FASTSPEED;
1004 if(cursor_y > screen->h-32)
1005 cursor_y = screen->h-32;
1018 cursor_x = (le_current_level->width * 32) - 32;
1022 le_show_grid = !le_show_grid;
1028 case SDL_KEYUP: /* key released */
1029 switch(event.key.keysym.sym)
1038 case SDL_MOUSEBUTTONDOWN:
1039 if(event.button.button == SDL_BUTTON_LEFT)
1041 le_mouse_pressed[LEFT] = true;
1043 selection.x1 = event.motion.x + pos_x;
1044 selection.y1 = event.motion.y;
1045 selection.x2 = event.motion.x + pos_x;
1046 selection.y2 = event.motion.y;
1048 else if(event.button.button == SDL_BUTTON_RIGHT)
1050 le_mouse_pressed[RIGHT] = true;
1053 case SDL_MOUSEBUTTONUP:
1054 if(event.button.button == SDL_BUTTON_LEFT)
1055 le_mouse_pressed[LEFT] = false;
1056 else if(event.button.button == SDL_BUTTON_RIGHT)
1057 le_mouse_pressed[RIGHT] = false;
1059 case SDL_MOUSEMOTION:
1061 if(!Menu::current())
1066 if(le_current.IsTile())
1068 cursor_x = ((int)(pos_x + x) / 32) * 32;
1069 cursor_y = ((int) y / 32) * 32;
1077 if(le_mouse_pressed[LEFT])
1079 selection.x2 = x + pos_x;
1083 if(le_mouse_pressed[RIGHT])
1085 pos_x += -1 * event.motion.xrel;
1089 case SDL_QUIT: // window closed
1098 if(le_current_level != NULL)
1100 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 &&
1101 event.motion.y > 0 && event.motion.y < screen->h)))
1103 le_mouse_pressed[LEFT] = false;
1104 le_mouse_pressed[RIGHT] = false;
1106 if(!Menu::current())
1108 /* Check for button events */
1109 le_test_level_bt->event(event);
1110 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1112 le_save_level_bt->event(event);
1113 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1114 le_current_level->save(le_level_subset->name.c_str(),le_level);
1115 le_exit_bt->event(event);
1116 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1118 Menu::set_current(leveleditor_menu);
1120 le_next_level_bt->event(event);
1121 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1123 if(le_level < le_level_subset->levels)
1125 le_goto_level(++le_level);
1131 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1132 if(confirm_dialog(str))
1134 new_lev.init_defaults();
1135 new_lev.save(le_level_subset->name.c_str(),++le_level);
1136 le_level_subset->levels = le_level;
1137 le_goto_level(le_level);
1141 le_previous_level_bt->event(event);
1142 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1145 le_goto_level(--le_level);
1147 le_rubber_bt->event(event);
1148 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1151 if(le_selection_mode == SQUARE)
1153 le_select_mode_one_bt->event(event);
1154 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1155 le_selection_mode = CURSOR;
1159 le_select_mode_two_bt->event(event);
1160 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1161 le_selection_mode = SQUARE;
1164 le_tilegroup_bt->event(event);
1165 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1167 Menu::set_current(select_tilegroup_menu);
1168 select_tilegroup_menu_effect.start(200);
1169 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1172 le_objects_bt->event(event);
1173 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1175 Menu::set_current(select_objects_menu);
1176 select_objects_menu_effect.start(200);
1177 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1180 le_settings_bt->event(event);
1181 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1183 update_level_settings_menu();
1184 Menu::set_current(level_settings_menu);
1186 if(!cur_tilegroup.empty())
1188 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1190 if(pbutton->get_state() == BUTTON_CLICKED)
1192 if(le_current.IsObject())
1193 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1194 le_current.Tile(pbutton->get_tag());
1198 else if(!cur_objects.empty())
1200 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1202 if(pbutton->get_state() == BUTTON_CLICKED)
1204 if(le_current.IsObject())
1205 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1206 le_current.Object(pbutton->get_game_object());
1211 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1213 if(pbutton->get_state() == BUTTON_CLICKED)
1215 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1221 le_settings_bt->event(event);
1222 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1224 Menu::set_current(0);
1226 le_tilegroup_bt->event(event);
1227 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1229 Menu::set_current(0);
1234 if(!Menu::current())
1236 le_move_left_bt->event(event);
1237 le_move_right_bt->event(event);
1239 if(le_mouse_pressed[LEFT])
1241 if(le_current.IsTile())
1242 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1243 else if(le_current.IsObject())
1245 std::string type = le_current.obj->type();
1246 if(type == "BadGuy")
1248 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1250 le_world.bad_guys.push_back(BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1251 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1258 if(!Menu::current())
1260 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1264 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1269 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1273 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1281 void le_highlight_selection()
1285 if(selection.x1 < selection.x2)
1295 if(selection.y1 < selection.y2)
1311 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1314 void le_change(float x, float y, int tm, unsigned int c)
1316 if(le_current_level != NULL)
1322 /* level_changed = true; */
1324 switch(le_selection_mode)
1327 le_current_level->change(x,y,tm,c);
1329 base_type cursor_base;
1332 cursor_base.width = 32;
1333 cursor_base.height = 32;
1335 /* if there is a bad guy over there, remove it */
1336 for(i = 0; i < le_world.bad_guys.size(); ++i)
1337 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1339 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1340 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1345 if(selection.x1 < selection.x2)
1355 if(selection.y1 < selection.y2)
1371 /* if there is a bad guy over there, remove it */
1372 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1373 i != le_world.bad_guys.end(); /* will be at end of loop */)
1375 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1376 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1378 i = le_world.bad_guys.erase(i);
1387 for(xx = x1; xx <= x2; xx++)
1388 for(yy = y1; yy <= y2; yy++)
1390 le_current_level->change(xx*32, yy*32, tm, c);
1402 le_current_level->save("test", le_level);
1404 GameSession session("test",le_level, ST_GL_TEST);
1406 player_status.reset();
1408 music_manager->halt_music();
1410 Menu::set_current(NULL);
1411 le_world.arrays_free();
1412 le_current_level->load_gfx();
1413 le_world.activate_bad_guys();
1419 unsigned int i, done_;
1421 " - This is SuperTux's built-in level editor -",
1422 "It has been designed to be light and easy to use from the start.",
1424 "When you first load the level editor you are given a menu where you",
1425 "can load level subsets, create a new level subset, edit the current",
1426 "subset's settings, or simply quit the editor. You can access this menu",
1427 "from the level editor at any time by pressing the escape key.",
1429 "To your right is your button bar. The center of this contains many",
1430 "tiles you can use to make your level. To select a tile, click on it",
1431 "with your left mouse button; your selection will be shown in the",
1432 "bottom right corner of the button box. Click anywhere on your level",
1433 "with the left mouse button to place that tile down. If you right click",
1434 "a tile in the button bar, you can find out what its keyboard shortcut",
1435 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1436 "background, and enemy tiles. The eraser lets you remove tiles.",
1437 "The left and right arrow keys scroll back and forth through your level.",
1438 "The button with the wrench and screwdriver, lets you change the",
1439 "settings of your level, including how long it is or what music it will",
1440 "play. When you are ready to give your level a test, click on the little",
1441 "running Tux. If you like the changes you have made to your level,",
1442 "press the red save key to keep them.",
1443 "To change which level in your subset you are editing, press the white",
1444 "up and down arrow keys at the top of the button box.",
1446 "Have fun making levels! If you make some good ones, send them to us on",
1447 "the SuperTux mailing list!",
1452 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1454 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1455 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1457 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1465 done_ = wait_for_event(event);