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) */
69 int le_load_level(char *filename);
71 void le_drawinterface();
72 void le_checkevents();
73 void le_change(float x, float y, int tm, unsigned int c);
76 void le_set_defaults(void);
77 void le_activate_bad_guys(void);
79 void le_highlight_selection();
81 void apply_level_settings_menu();
82 void update_subset_settings_menu();
83 void save_subset_settings_menu();
85 static Level* le_current_level;
87 struct LevelEditorWorld
89 std::vector<BadGuy> bad_guys;
90 void arrays_free(void)
95 void add_bad_guy(float x, float y, BadGuyKind kind)
97 bad_guys.push_back(BadGuy(x,y,kind, false /* stay_on_platform */));
100 void activate_bad_guys()
102 for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
103 i != le_current_level->badguy_data.end();
106 add_bad_guy(i->x, i->y, i->kind);
113 TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
115 void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
116 void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
117 //Returns true for a tile
118 bool IsTile() { return is_tile; };
119 //Returns true for a GameObject
120 bool IsObject() { return !is_tile; };
121 void Init() { tile = 0; obj = NULL; is_tile = true; };
123 bool is_tile; //true for tile (false for object)
128 /* leveleditor internals */
129 static string_list_type level_subsets;
130 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
131 static int pos_x, cursor_x, cursor_y, fire;
133 static LevelEditorWorld le_world;
134 static LevelSubset* le_level_subset;
135 static int le_show_grid;
137 static Surface* le_selection;
139 static TileOrObject le_current;
140 static bool le_mouse_pressed[2];
141 static bool le_mouse_clicked[2];
142 static Button* le_save_level_bt;
143 static Button* le_exit_bt;
144 static Button* le_test_level_bt;
145 static Button* le_next_level_bt;
146 static Button* le_previous_level_bt;
147 static Button* le_move_right_bt;
148 static Button* le_move_left_bt;
149 static Button* le_rubber_bt;
150 static Button* le_select_mode_one_bt;
151 static Button* le_select_mode_two_bt;
152 static Button* le_settings_bt;
153 static Button* le_tilegroup_bt;
154 static Button* le_objects_bt;
155 static ButtonPanel* le_tilemap_panel;
156 static Menu* leveleditor_menu;
157 static Menu* subset_load_menu;
158 static Menu* subset_new_menu;
159 static Menu* subset_settings_menu;
160 static Menu* level_settings_menu;
161 static Menu* select_tilegroup_menu;
162 static Menu* select_objects_menu;
163 static Timer select_tilegroup_menu_effect;
164 static Timer select_objects_menu_effect;
165 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
166 static ButtonPanelMap tilegroups_map;
167 static ButtonPanelMap objects_map;
168 static std::string cur_tilegroup;
169 static std::string cur_objects;
171 static square selection;
172 static int le_selection_mode;
173 static SDL_Event event;
174 TileMapType active_tm;
176 void le_set_defaults()
178 if(le_current_level != NULL)
182 if(le_current_level->time_left == 0)
183 le_current_level->time_left = 255;
187 int leveleditor(char* filename)
189 int last_time, now_time, i;
198 clearscreen(0, 0, 0);
201 music_manager->halt_music();
203 while (SDL_PollEvent(&event))
207 if(le_load_level(filename))
212 last_time = SDL_GetTicks();
217 if(Menu::current() == select_tilegroup_menu)
219 if(select_tilegroup_menu_effect.check())
221 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
225 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
227 else if(Menu::current() == select_objects_menu)
229 if(select_objects_menu_effect.check())
231 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
234 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
237 if(le_current_level != NULL)
239 /* making events results to be in order */
242 if(pos_x > (le_current_level->width * 32) - screen->w)
243 pos_x = (le_current_level->width * 32) - screen->w;
249 clearscreen(0, 0, 0);
251 /* draw editor interface */
254 Menu* menu = Menu::current();
260 if(menu == leveleditor_menu)
262 switch (leveleditor_menu->check())
264 case MNID_RETURNLEVELEDITOR:
265 Menu::set_current(0);
267 case MNID_SUBSETSETTINGS:
268 update_subset_settings_menu();
270 case MNID_QUITLEVELEDITOR:
275 else if(menu == level_settings_menu)
277 switch (level_settings_menu->check())
280 apply_level_settings_menu();
281 Menu::set_current(NULL);
289 else if(menu == select_tilegroup_menu)
292 switch (it = select_tilegroup_menu->check())
298 = select_tilegroup_menu->get_item_by_id(it).text;
299 Menu::set_current(0);
306 else if(menu == select_objects_menu)
309 switch (it = select_objects_menu->check())
314 cur_objects = select_objects_menu->get_item_by_id(it).text;
315 cur_tilegroup.clear();
317 Menu::set_current(0);
322 else if(menu == subset_load_menu)
324 switch (i = subset_load_menu->check())
331 if(le_load_level(level_subsets.item[i-1]))
337 else if(menu == subset_new_menu)
339 if(subset_new_menu->item[2].input[0] == '\0')
340 subset_new_menu->item[3].kind = MN_DEACTIVE;
343 subset_new_menu->item[3].kind = MN_ACTION;
345 switch (i = subset_new_menu->check())
347 case MNID_CREATESUBSET:
348 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
349 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
350 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
352 le_world.arrays_free();
353 delete le_current_level;
354 le_current_level = new Level;
355 if(le_current_level->load(le_level_subset->name, le_level) != 0)
361 le_current_level->load_gfx();
362 le_world.activate_bad_guys();
363 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
365 Menu::set_current(subset_settings_menu);
370 else if(menu == subset_settings_menu)
372 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 )
373 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
375 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
377 switch (i = subset_settings_menu->check())
379 case MNID_SUBSETSAVECHANGES:
380 save_subset_settings_menu();
381 Menu::set_current(leveleditor_menu);
387 mouse_cursor->draw();
395 ++global_frame_counter;
398 now_time = SDL_GetTicks();
399 if (now_time < last_time + FPS)
400 SDL_Delay(last_time + FPS - now_time); /* delay some time */
408 int le_load_level(char *filename)
410 le_level_subset->load(filename);
411 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
413 le_world.arrays_free();
414 delete le_current_level;
415 le_current_level = new Level;
416 if(le_current_level->load(le_level_subset->name, le_level) != 0)
422 le_current_level->load_gfx();
423 le_world.activate_bad_guys();
425 Menu::set_current(NULL);
434 leveleditor_menu = new Menu();
435 subset_load_menu = new Menu();
436 subset_new_menu = new Menu();
437 subset_settings_menu = new Menu();
438 level_settings_menu = new Menu();
439 select_tilegroup_menu = new Menu();
440 select_objects_menu = new Menu();
442 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
443 leveleditor_menu->additem(MN_HL,"",0,0);
444 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
445 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
446 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
447 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
448 leveleditor_menu->additem(MN_HL,"",0,0);
449 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
451 Menu::set_current(leveleditor_menu);
453 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
454 subset_load_menu->additem(MN_HL, "", 0, 0);
456 for(i = 0; i < level_subsets.num_items; ++i)
458 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
460 subset_load_menu->additem(MN_HL,"",0,0);
461 subset_load_menu->additem(MN_BACK,"Back",0,0);
463 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
464 subset_new_menu->additem(MN_HL,"",0,0);
465 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
466 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
467 subset_new_menu->additem(MN_HL,"",0,0);
468 subset_new_menu->additem(MN_BACK,"Back",0,0);
470 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
471 subset_settings_menu->additem(MN_HL,"",0,0);
472 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
473 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
474 subset_settings_menu->additem(MN_HL,"",0,0);
475 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
476 subset_settings_menu->additem(MN_HL,"",0,0);
477 subset_settings_menu->additem(MN_BACK,"Back",0,0);
479 level_settings_menu->arrange_left = true;
480 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
481 level_settings_menu->additem(MN_HL,"",0,0);
482 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0,MNID_NAME);
483 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0,MNID_AUTHOR);
484 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
485 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
486 level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
487 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0,MNID_LENGTH);
488 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0,MNID_TIME);
489 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0,MNID_GRAVITY);
490 level_settings_menu->additem(MN_NUMFIELD,"Bg-Img-Speed",0,0,MNID_BGSPEED);
491 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0,MNID_TopRed);
492 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0,MNID_TopGreen);
493 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0,MNID_TopBlue);
494 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0,MNID_BottomRed);
495 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0,MNID_BottomGreen);
496 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0,MNID_BottomBlue);
497 level_settings_menu->additem(MN_HL,"",0,0);
498 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
500 select_tilegroup_menu->arrange_left = true;
501 select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
502 select_tilegroup_menu->additem(MN_HL,"",0,0);
503 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
505 for(std::vector<TileGroup>::iterator it = tilegroups->begin();
506 it != tilegroups->end(); ++it )
508 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
510 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
513 for(std::vector<int>::iterator sit = (*it).tiles.begin();
514 sit != (*it).tiles.end(); ++sit, ++i)
516 std::string imagefile = "/images/tilesets/" ;
517 bool only_editor_image = false;
518 if(!TileManager::instance()->get(*sit)->filenames.empty())
520 imagefile += TileManager::instance()->get(*sit)->filenames[0];
522 else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
524 imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
525 only_editor_image = true;
529 imagefile += "notile.png";
531 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
533 if(!only_editor_image)
534 if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
536 imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
537 button->add_icon(imagefile,32,32);
539 tilegroups_map[it->name]->additem(button, *sit);
542 select_tilegroup_menu->additem(MN_HL,"",0,0);
544 select_objects_menu->arrange_left = true;
545 select_objects_menu->additem(MN_LABEL,"Objects",0,0);
546 select_objects_menu->additem(MN_HL,"",0,0);
547 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
548 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
550 for(int i = 0; i < NUM_BadGuyKinds; ++i)
552 BadGuy bad_tmp(0,0,BadGuyKind(i),false);
553 objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
554 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));
557 select_objects_menu->additem(MN_HL,"",0,0);
563 level_subsets = dsubdirs("/levels", "info");
564 le_level_subset = new LevelSubset;
572 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
573 le_level_changed = false;
574 le_current_level = NULL;
576 le_mouse_pressed[LEFT] = false;
577 le_mouse_pressed[RIGHT] = false;
579 le_mouse_clicked[LEFT] = false;
580 le_mouse_clicked[RIGHT] = false;
582 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
584 select_tilegroup_menu_effect.init(false);
585 select_objects_menu_effect.init(false);
588 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
589 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
590 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
591 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
592 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
593 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
594 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
595 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
596 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
597 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
598 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
599 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
600 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
602 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
603 le_tilemap_panel->set_button_size(32,10);
604 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
605 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0),TM_IA);
606 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
607 le_tilemap_panel->highlight_last(true);
613 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
619 void update_level_settings_menu()
624 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_current_level->name.c_str());
625 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_current_level->author.c_str());
627 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
628 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
629 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
630 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
631 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
632 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
634 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_current_level->song_title.c_str())) != -1)
635 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
636 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_current_level->bkgd_image.c_str())) != -1)
637 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
638 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_current_level->particle_system.c_str())) != -1)
639 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
641 sprintf(str,"%d",le_current_level->width);
642 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
643 sprintf(str,"%d",le_current_level->time_left);
644 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
645 sprintf(str,"%2.0f",le_current_level->gravity);
646 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
647 sprintf(str,"%d",le_current_level->bkgd_speed);
648 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
649 sprintf(str,"%d",le_current_level->bkgd_top.red);
650 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
651 sprintf(str,"%d",le_current_level->bkgd_top.green);
652 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
653 sprintf(str,"%d",le_current_level->bkgd_top.blue);
654 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
655 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
656 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
657 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
658 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
659 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
660 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
663 void update_subset_settings_menu()
665 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
666 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
669 void apply_level_settings_menu()
674 le_current_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
675 le_current_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
677 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
679 le_current_level->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
683 if(le_current_level->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
685 le_current_level->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
690 le_current_level->load_gfx();
693 le_current_level->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
695 le_current_level->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
696 le_current_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
697 le_current_level->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
698 le_current_level->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
699 le_current_level->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
700 le_current_level->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
701 le_current_level->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
702 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
703 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
704 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
707 void save_subset_settings_menu()
709 le_level_subset->title = subset_settings_menu->item[2].input;
710 le_level_subset->description = subset_settings_menu->item[3].input;
711 le_level_subset->save();
714 void le_goto_level(int levelnb)
716 le_world.arrays_free();
718 le_current_level->cleanup();
719 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
721 le_current_level->load(le_level_subset->name.c_str(), le_level);
730 le_current_level->load_gfx();
732 le_world.activate_bad_guys();
737 /*if(level_changed == true)
738 if(askforsaving() == CANCEL)
741 SDL_EnableKeyRepeat(0, 0); // disables key repeating
744 delete leveleditor_menu;
745 delete subset_load_menu;
746 delete subset_new_menu;
747 delete subset_settings_menu;
748 delete level_settings_menu;
749 delete select_tilegroup_menu;
750 delete select_objects_menu;
751 delete le_save_level_bt;
753 delete le_test_level_bt;
754 delete le_next_level_bt;
755 delete le_previous_level_bt;
756 delete le_move_right_bt;
757 delete le_move_left_bt;
759 delete le_select_mode_one_bt;
760 delete le_select_mode_two_bt;
761 delete le_settings_bt;
762 delete le_tilegroup_bt;
763 delete le_objects_bt;
764 delete le_tilemap_panel;
766 delete le_current_level;
767 le_current_level = 0;
768 delete le_level_subset;
771 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
772 i != tilegroups_map.end(); ++i)
776 for(ButtonPanelMap::iterator i = objects_map.begin();
777 i != objects_map.end(); ++i)
783 void le_drawinterface()
788 if(le_current_level != NULL)
790 /* draw a grid (if selected) */
793 for(x = 0; x < 19; x++)
794 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
795 for(y = 0; y < 15; y++)
796 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
800 if(le_selection_mode == CURSOR)
801 le_selection->draw( cursor_x - scroll_x, cursor_y);
802 else if(le_selection_mode == SQUARE)
805 le_highlight_selection();
806 /* draw current selection */
807 w = selection.x2 - selection.x1;
808 h = selection.y2 - selection.y1;
809 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
810 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
811 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
812 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
816 /* draw button bar */
817 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
819 if(le_current.IsTile())
821 Tile::draw(19 * 32, 14 * 32, le_current.tile);
822 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
823 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
825 if(le_current.IsObject())
827 le_current.obj->draw_on_screen(19 * 32, 14 * 32);
830 //if(le_current.IsObject())
833 if(le_current_level != NULL)
835 le_save_level_bt->draw();
837 le_test_level_bt->draw();
838 le_next_level_bt->draw();
839 le_previous_level_bt->draw();
840 le_rubber_bt->draw();
841 if(le_selection_mode == SQUARE)
842 le_select_mode_one_bt->draw();
843 else if(le_selection_mode == CURSOR)
844 le_select_mode_two_bt->draw();
845 le_settings_bt->draw();
846 le_move_right_bt->draw();
847 le_move_left_bt->draw();
848 le_tilegroup_bt->draw();
849 le_objects_bt->draw();
850 if(!cur_tilegroup.empty())
851 tilegroups_map[cur_tilegroup]->draw();
852 else if(!cur_objects.empty())
854 objects_map[cur_objects]->draw();
857 le_tilemap_panel->draw();
859 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
860 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
862 white_small_text->draw("F1 for Help", 10, 430, 1);
867 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
869 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
876 unsigned int y,x,i,s;
879 /* Draw the real background */
880 if(le_current_level->bkgd_image[0] != '\0')
882 s = (int)((float)pos_x * ((float)le_current_level->bkgd_speed/60.)) % screen->w;
883 le_current_level->img_bkgd->draw_part(s,0,0,0,
884 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
885 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
886 le_current_level->img_bkgd->h);
890 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
893 if(le_current.IsTile())
895 Tile::draw(cursor_x, cursor_y,le_current.tile,128);
896 if(!TileManager::instance()->get(le_current.tile)->images.empty())
897 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);
899 if(le_current.IsObject())
901 le_current.obj->move_to(cursor_x, cursor_y);
904 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
906 for (y = 0; y < 15; ++y)
907 for (x = 0; x < 20; ++x)
910 if(active_tm == TM_BG)
915 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
917 if(active_tm == TM_IA)
922 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
924 if(active_tm == TM_FG)
929 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
931 /* draw whats inside stuff when cursor is selecting those */
932 /* (draw them all the time - is this the right behaviour?) */
933 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
934 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);
938 /* Draw the Bad guys: */
939 for (i = 0; i < le_world.bad_guys.size(); ++i)
941 /* to support frames: img_bsod_left[(frame / 5) % 4] */
944 le_world.bad_guys[i].draw();
948 /* Draw the player: */
949 /* for now, the position is fixed at (100, 240) */
950 largetux.walk_right->draw( 100 - pos_x, 240);
953 void le_checkevents()
960 keymod = SDL_GetModState();
962 while(SDL_PollEvent(&event))
966 Menu::current()->event(event);
970 mouse_cursor->set_state(MC_NORMAL);
972 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
973 if(event.type == SDL_KEYDOWN
974 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
975 && (event.motion.x > 0
976 && event.motion.x < screen->w - 64 &&
977 event.motion.y > 0 && event.motion.y < screen->h)))
981 case SDL_KEYDOWN: // key pressed
982 key = event.key.keysym.sym;
986 Menu::set_current(leveleditor_menu);
989 cursor_x -= KEY_CURSOR_SPEED;
991 cursor_x -= KEY_CURSOR_FASTSPEED;
993 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
994 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
999 cursor_x += KEY_CURSOR_SPEED;
1001 cursor_x += KEY_CURSOR_FASTSPEED;
1003 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
1004 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
1009 cursor_y -= KEY_CURSOR_SPEED;
1011 cursor_y -= KEY_CURSOR_FASTSPEED;
1018 cursor_y += KEY_CURSOR_SPEED;
1020 cursor_y += KEY_CURSOR_FASTSPEED;
1022 if(cursor_y > screen->h-32)
1023 cursor_y = screen->h-32;
1036 cursor_x = (le_current_level->width * 32) - 32;
1040 le_show_grid = !le_show_grid;
1046 case SDL_KEYUP: /* key released */
1047 switch(event.key.keysym.sym)
1056 case SDL_MOUSEBUTTONDOWN:
1057 if(event.button.button == SDL_BUTTON_LEFT)
1059 le_mouse_pressed[LEFT] = true;
1061 selection.x1 = event.motion.x + pos_x;
1062 selection.y1 = event.motion.y;
1063 selection.x2 = event.motion.x + pos_x;
1064 selection.y2 = event.motion.y;
1066 else if(event.button.button == SDL_BUTTON_RIGHT)
1068 le_mouse_pressed[RIGHT] = true;
1071 case SDL_MOUSEBUTTONUP:
1072 if(event.button.button == SDL_BUTTON_LEFT)
1074 le_mouse_pressed[LEFT] = false;
1075 le_mouse_clicked[LEFT] = true;
1077 else if(event.button.button == SDL_BUTTON_RIGHT)
1079 le_mouse_pressed[RIGHT] = false;
1080 le_mouse_clicked[RIGHT] = true;
1083 case SDL_MOUSEMOTION:
1085 if(!Menu::current())
1090 if(le_current.IsTile())
1092 cursor_x = ((int)(pos_x + x) / 32) * 32;
1093 cursor_y = ((int) y / 32) * 32;
1101 if(le_mouse_pressed[LEFT])
1103 selection.x2 = x + pos_x;
1107 if(le_mouse_pressed[RIGHT])
1109 pos_x += -1 * event.motion.xrel;
1113 case SDL_QUIT: // window closed
1122 if(le_current_level != NULL)
1124 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 &&
1125 event.motion.y > 0 && event.motion.y < screen->h)))
1127 le_mouse_pressed[LEFT] = false;
1128 le_mouse_pressed[RIGHT] = false;
1130 if(!Menu::current())
1132 /* Check for button events */
1133 le_test_level_bt->event(event);
1134 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1136 le_save_level_bt->event(event);
1137 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1138 le_current_level->save(le_level_subset->name.c_str(),le_level);
1139 le_exit_bt->event(event);
1140 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1142 Menu::set_current(leveleditor_menu);
1144 le_next_level_bt->event(event);
1145 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1147 if(le_level < le_level_subset->levels)
1149 le_goto_level(++le_level);
1155 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1156 if(confirm_dialog(str))
1158 new_lev.init_defaults();
1159 new_lev.save(le_level_subset->name.c_str(),++le_level);
1160 le_level_subset->levels = le_level;
1161 le_goto_level(le_level);
1165 le_previous_level_bt->event(event);
1166 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1169 le_goto_level(--le_level);
1171 le_rubber_bt->event(event);
1172 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1175 if(le_selection_mode == SQUARE)
1177 le_select_mode_one_bt->event(event);
1178 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1179 le_selection_mode = CURSOR;
1183 le_select_mode_two_bt->event(event);
1184 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1185 le_selection_mode = SQUARE;
1188 le_tilegroup_bt->event(event);
1189 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1191 Menu::set_current(select_tilegroup_menu);
1192 select_tilegroup_menu_effect.start(200);
1193 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1196 le_objects_bt->event(event);
1197 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1199 Menu::set_current(select_objects_menu);
1200 select_objects_menu_effect.start(200);
1201 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1204 le_settings_bt->event(event);
1205 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1207 update_level_settings_menu();
1208 Menu::set_current(level_settings_menu);
1210 if(!cur_tilegroup.empty())
1212 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1214 if(pbutton->get_state() == BUTTON_CLICKED)
1216 if(le_current.IsObject())
1217 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1218 le_current.Tile(pbutton->get_tag());
1222 else if(!cur_objects.empty())
1224 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1226 if(pbutton->get_state() == BUTTON_CLICKED)
1228 if(le_current.IsObject())
1229 le_current.obj->move_to(pbutton->get_pos().x,pbutton->get_pos().y);
1230 le_current.Object(pbutton->get_game_object());
1235 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1237 if(pbutton->get_state() == BUTTON_CLICKED)
1239 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1245 le_settings_bt->event(event);
1246 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1248 Menu::set_current(0);
1250 le_tilegroup_bt->event(event);
1251 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1253 Menu::set_current(0);
1258 if(!Menu::current())
1260 le_move_left_bt->event(event);
1261 le_move_right_bt->event(event);
1263 if(le_mouse_pressed[LEFT])
1265 if(le_current.IsTile())
1266 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1268 else if(le_mouse_clicked[LEFT])
1270 if(le_current.IsObject())
1272 std::string type = le_current.obj->type();
1273 if(type == "BadGuy")
1275 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1277 le_world.bad_guys.push_back(BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1278 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1281 le_mouse_clicked[LEFT] = false;
1286 if(!Menu::current())
1288 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1292 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1297 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1301 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1309 void le_highlight_selection()
1313 if(selection.x1 < selection.x2)
1323 if(selection.y1 < selection.y2)
1339 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1342 void le_change(float x, float y, int tm, unsigned int c)
1344 if(le_current_level != NULL)
1350 /* level_changed = true; */
1352 switch(le_selection_mode)
1355 le_current_level->change(x,y,tm,c);
1357 base_type cursor_base;
1360 cursor_base.width = 32;
1361 cursor_base.height = 32;
1363 /* if there is a bad guy over there, remove it */
1364 for(i = 0; i < le_world.bad_guys.size(); ++i)
1365 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1367 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1368 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1373 if(selection.x1 < selection.x2)
1383 if(selection.y1 < selection.y2)
1399 /* if there is a bad guy over there, remove it */
1400 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1401 i != le_world.bad_guys.end(); /* will be at end of loop */)
1403 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1404 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1406 i = le_world.bad_guys.erase(i);
1415 for(xx = x1; xx <= x2; xx++)
1416 for(yy = y1; yy <= y2; yy++)
1418 le_current_level->change(xx*32, yy*32, tm, c);
1430 le_current_level->save("test", le_level);
1432 GameSession session("test",le_level, ST_GL_TEST);
1434 player_status.reset();
1436 music_manager->halt_music();
1438 Menu::set_current(NULL);
1439 le_world.arrays_free();
1440 le_current_level->load_gfx();
1441 le_world.activate_bad_guys();
1447 unsigned int i, done_;
1449 " - This is SuperTux's built-in level editor -",
1450 "It has been designed to be light and easy to use from the start.",
1452 "When you first load the level editor you are given a menu where you",
1453 "can load level subsets, create a new level subset, edit the current",
1454 "subset's settings, or simply quit the editor. You can access this menu",
1455 "from the level editor at any time by pressing the escape key.",
1457 "To your right is your button bar. The center of this contains many",
1458 "tiles you can use to make your level. To select a tile, click on it",
1459 "with your left mouse button; your selection will be shown in the",
1460 "bottom right corner of the button box. Click anywhere on your level",
1461 "with the left mouse button to place that tile down. If you right click",
1462 "a tile in the button bar, you can find out what its keyboard shortcut",
1463 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1464 "background, and enemy tiles. The eraser lets you remove tiles.",
1465 "The left and right arrow keys scroll back and forth through your level.",
1466 "The button with the wrench and screwdriver, lets you change the",
1467 "settings of your level, including how long it is or what music it will",
1468 "play. When you are ready to give your level a test, click on the little",
1469 "running Tux. If you like the changes you have made to your level,",
1470 "press the red save key to keep them.",
1471 "To change which level in your subset you are editing, press the white",
1472 "up and down arrow keys at the top of the button box.",
1474 "Have fun making levels! If you make some good ones, send them to us on",
1475 "the SuperTux mailing list!",
1480 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1482 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1483 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1485 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1493 done_ = wait_for_event(event);