4 // Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
5 // Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <SDL_image.h>
30 #include "leveleditor.h"
43 #include "resources.h"
44 #include "music_manager.h"
46 /* definitions to aid development */
48 /* definitions that affect gameplay */
49 #define KEY_CURSOR_SPEED 32
50 #define KEY_CURSOR_FASTSPEED 64
52 /* when pagedown/up pressed speed:*/
53 #define PAGE_CURSOR_SPEED 13*32
55 #define MOUSE_LEFT_MARGIN 80
56 #define MOUSE_RIGHT_MARGIN (560-32)
57 /* right_margin should noticed that the cursor is 32 pixels,
58 so it should subtract that value */
59 #define MOUSE_POS_SPEED 20
62 #define SELECT_W 2 // size of the selections lines
63 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
65 /* own declerations */
66 /* crutial ones (main loop) */
70 void le_drawinterface();
71 void le_checkevents();
72 void le_change(float x, float y, int tm, unsigned int c);
75 void le_set_defaults(void);
76 void le_activate_bad_guys(void);
78 void le_highlight_selection();
80 void apply_level_settings_menu();
81 void update_subset_settings_menu();
82 void save_subset_settings_menu();
84 static Level* le_current_level;
86 struct LevelEditorWorld
88 std::vector<BadGuy> bad_guys;
89 void arrays_free(void)
94 void add_bad_guy(float x, float y, BadGuyKind kind)
96 bad_guys.push_back(BadGuy(x,y,kind, false /* stay_on_platform */));
99 void activate_bad_guys()
101 for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
102 i != le_current_level->badguy_data.end();
105 add_bad_guy(i->x, i->y, i->kind);
112 TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
114 void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
115 void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
116 //Returns true for a tile
117 bool IsTile() { return is_tile; };
118 //Returns true for a GameObject
119 bool IsObject() { return !is_tile; };
121 bool is_tile; //true for tile (false for object)
126 /* leveleditor internals */
127 static string_list_type level_subsets;
128 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
129 static int pos_x, cursor_x, cursor_y, fire;
131 static LevelEditorWorld le_world;
132 static LevelSubset* le_level_subset;
133 static int le_show_grid;
135 static Surface* le_selection;
137 static TileOrObject le_current;
138 static bool le_mouse_pressed[2];
139 static Button* le_save_level_bt;
140 static Button* le_exit_bt;
141 static Button* le_test_level_bt;
142 static Button* le_next_level_bt;
143 static Button* le_previous_level_bt;
144 static Button* le_move_right_bt;
145 static Button* le_move_left_bt;
146 static Button* le_rubber_bt;
147 static Button* le_select_mode_one_bt;
148 static Button* le_select_mode_two_bt;
149 static Button* le_settings_bt;
150 static Button* le_tilegroup_bt;
151 static Button* le_objects_bt;
152 static ButtonPanel* le_tilemap_panel;
153 static Menu* leveleditor_menu;
154 static Menu* subset_load_menu;
155 static Menu* subset_new_menu;
156 static Menu* subset_settings_menu;
157 static Menu* level_settings_menu;
158 static Menu* select_tilegroup_menu;
159 static Menu* select_objects_menu;
160 static Timer select_tilegroup_menu_effect;
161 static Timer select_objects_menu_effect;
162 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
163 static ButtonPanelMap tilegroups_map;
164 static ButtonPanelMap objects_map;
165 static std::string cur_tilegroup;
166 static std::string cur_objects;
168 static square selection;
169 static int le_selection_mode;
170 static SDL_Event event;
171 TileMapType active_tm;
173 void le_set_defaults()
175 if(le_current_level != NULL)
179 if(le_current_level->time_left == 0)
180 le_current_level->time_left = 255;
184 int leveleditor(int levelnb)
186 int last_time, now_time, i;
194 clearscreen(0, 0, 0);
197 music_manager->halt_music();
199 while (SDL_PollEvent(&event))
204 last_time = SDL_GetTicks();
209 if(Menu::current() == select_tilegroup_menu)
211 if(select_tilegroup_menu_effect.check())
213 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
217 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
219 else if(Menu::current() == select_objects_menu)
221 if(select_objects_menu_effect.check())
223 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
226 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
229 if(le_current_level != NULL)
231 /* making events results to be in order */
234 if(pos_x > (le_current_level->width * 32) - screen->w)
235 pos_x = (le_current_level->width * 32) - screen->w;
241 clearscreen(0, 0, 0);
243 /* draw editor interface */
246 Menu* menu = Menu::current();
252 if(menu == leveleditor_menu)
254 switch (leveleditor_menu->check())
256 case MNID_RETURNLEVELEDITOR:
257 Menu::set_current(0);
259 case MNID_SUBSETSETTINGS:
260 update_subset_settings_menu();
262 case MNID_QUITLEVELEDITOR:
267 else if(menu == level_settings_menu)
269 switch (level_settings_menu->check())
272 apply_level_settings_menu();
273 Menu::set_current(NULL);
281 else if(menu == select_tilegroup_menu)
284 switch (it = select_tilegroup_menu->check())
290 = select_tilegroup_menu->get_item_by_id(it).text;
291 Menu::set_current(0);
298 else if(menu == select_objects_menu)
301 switch (it = select_objects_menu->check())
306 cur_objects = select_objects_menu->get_item_by_id(it).text;
307 cur_tilegroup.clear();
309 Menu::set_current(0);
314 else if(menu == subset_load_menu)
316 switch (i = subset_load_menu->check())
323 le_level_subset->load(level_subsets.item[i-1]);
324 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
326 le_world.arrays_free();
327 delete le_current_level;
328 le_current_level = new Level;
329 if(le_current_level->load(le_level_subset->name, le_level) != 0)
335 le_current_level->load_gfx();
336 le_world.activate_bad_guys();
338 Menu::set_current(NULL);
343 else if(menu == subset_new_menu)
345 if(subset_new_menu->item[2].input[0] == '\0')
346 subset_new_menu->item[3].kind = MN_DEACTIVE;
349 subset_new_menu->item[3].kind = MN_ACTION;
351 switch (i = subset_new_menu->check())
353 case MNID_CREATESUBSET:
354 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
355 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
356 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
358 le_world.arrays_free();
359 delete le_current_level;
360 le_current_level = new Level;
361 if(le_current_level->load(le_level_subset->name, le_level) != 0)
367 le_current_level->load_gfx();
368 le_world.activate_bad_guys();
369 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
371 Menu::set_current(subset_settings_menu);
376 else if(menu == subset_settings_menu)
378 if(le_level_subset->title.compare(subset_settings_menu->get_item_by_id(MNID_TITLE).input) == 0 && le_level_subset->description.compare(subset_settings_menu->get_item_by_id(MNID_DESCRIPTION).input) == 0 )
379 subset_settings_menu->get_item_by_id(MNID_SAVE_CHANGES).kind = MN_DEACTIVE;
381 subset_settings_menu->get_item_by_id(MNID_SAVE_CHANGES).kind = MN_ACTION;
383 switch (i = subset_settings_menu->check())
385 case MNID_SAVE_CHANGES:
386 save_subset_settings_menu();
387 //FIXME:show_menu = true;
388 Menu::set_current(leveleditor_menu);
394 mouse_cursor->draw();
402 ++global_frame_counter;
405 now_time = SDL_GetTicks();
406 if (now_time < last_time + FPS)
407 SDL_Delay(last_time + FPS - now_time); /* delay some time */
420 leveleditor_menu = new Menu();
421 subset_load_menu = new Menu();
422 subset_new_menu = new Menu();
423 subset_settings_menu = new Menu();
424 level_settings_menu = new Menu();
425 select_tilegroup_menu = new Menu();
426 select_objects_menu = new Menu();
428 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
429 leveleditor_menu->additem(MN_HL,"",0,0);
430 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
431 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
432 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
433 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
434 leveleditor_menu->additem(MN_HL,"",0,0);
435 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
437 Menu::set_current(leveleditor_menu);
439 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
440 subset_load_menu->additem(MN_HL, "", 0, 0);
442 for(i = 0; i < level_subsets.num_items; ++i)
444 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
446 subset_load_menu->additem(MN_HL,"",0,0);
447 subset_load_menu->additem(MN_BACK,"Back",0,0);
449 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
450 subset_new_menu->additem(MN_HL,"",0,0);
451 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
452 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
453 subset_new_menu->additem(MN_HL,"",0,0);
454 subset_new_menu->additem(MN_BACK,"Back",0,0);
456 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
457 subset_settings_menu->additem(MN_HL,"",0,0);
458 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
459 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
460 subset_settings_menu->additem(MN_HL,"",0,0);
461 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
462 subset_settings_menu->additem(MN_HL,"",0,0);
463 subset_settings_menu->additem(MN_BACK,"Back",0,0);
465 level_settings_menu->arrange_left = true;
466 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
467 level_settings_menu->additem(MN_HL,"",0,0);
468 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0,MNID_NAME);
469 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0,MNID_AUTHOR);
470 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
471 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
472 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0,MNID_LENGTH);
473 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0,MNID_TIME);
474 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0,MNID_GRAVITY);
475 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0,MNID_TopRed);
476 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0,MNID_TopGreen);
477 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0,MNID_TopBlue);
478 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0,MNID_BottomRed);
479 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0,MNID_BottomGreen);
480 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0,MNID_BottomBlue);
481 level_settings_menu->additem(MN_HL,"",0,0);
482 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
484 select_tilegroup_menu->arrange_left = true;
485 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
486 select_tilegroup_menu->additem(MN_HL,"",0,0);
487 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
489 for(std::vector<TileGroup>::iterator it = tilegroups->begin();
490 it != tilegroups->end(); ++it )
492 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
494 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
497 for(std::vector<int>::iterator sit = (*it).tiles.begin();
498 sit != (*it).tiles.end(); ++sit, ++i)
500 std::string imagefile = "/images/tilesets/" ;
501 if(!TileManager::instance()->get(*sit)->filenames.empty())
503 imagefile += TileManager::instance()->get(*sit)->filenames[0];
505 else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
507 imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
511 imagefile += "notile.png";
513 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
515 tilegroups_map[it->name]->additem(button, *sit);
518 select_tilegroup_menu->additem(MN_HL,"",0,0);
520 select_objects_menu->arrange_left = true;
521 select_objects_menu->additem(MN_LABEL,"Select Objects",0,0);
522 select_objects_menu->additem(MN_HL,"",0,0);
523 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
524 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
526 for(int i = 0; i < NUM_BadGuyKinds; ++i)
528 BadGuy bad_tmp(0,0,BadGuyKind(i),false);
529 objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
530 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));
533 select_objects_menu->additem(MN_HL,"",0,0);
539 level_subsets = dsubdirs("/levels", "info");
541 le_level_subset = new LevelSubset;
547 /* level_changed = NO;*/
550 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
551 le_level_changed = false;
552 le_current_level = NULL;
554 le_mouse_pressed[LEFT] = false;
555 le_mouse_pressed[RIGHT] = false;
557 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
559 select_tilegroup_menu_effect.init(false);
560 select_objects_menu_effect.init(false);
563 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
564 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
565 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
566 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
567 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
568 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
569 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
570 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
571 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
572 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
573 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
574 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
575 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
577 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
578 le_tilemap_panel->set_button_size(32,10);
579 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
580 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
581 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
585 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
590 void update_level_settings_menu()
595 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_current_level->name.c_str());
596 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_current_level->author.c_str());
598 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
599 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
600 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
602 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_current_level->song_title.c_str())) != -1)
603 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
604 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_current_level->bkgd_image.c_str())) != -1)
605 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
607 sprintf(str,"%d",le_current_level->width);
608 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
609 sprintf(str,"%d",le_current_level->time_left);
610 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
611 sprintf(str,"%2.0f",le_current_level->gravity);
612 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
613 sprintf(str,"%d",le_current_level->bkgd_top.red);
614 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
615 sprintf(str,"%d",le_current_level->bkgd_top.green);
616 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
617 sprintf(str,"%d",le_current_level->bkgd_top.blue);
618 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
619 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
620 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
621 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
622 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
623 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
624 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
627 void update_subset_settings_menu()
629 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
630 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
633 void apply_level_settings_menu()
638 le_current_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
639 le_current_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
641 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
643 le_current_level->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
649 le_current_level->load_gfx();
652 le_current_level->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
654 le_current_level->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
655 le_current_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
656 le_current_level->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
657 le_current_level->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
658 le_current_level->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
659 le_current_level->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
660 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
661 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
662 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
665 void save_subset_settings_menu()
667 le_level_subset->title = subset_settings_menu->item[2].input;
668 le_level_subset->description = subset_settings_menu->item[3].input;
669 le_level_subset->save();
672 void le_goto_level(int levelnb)
674 le_world.arrays_free();
676 le_current_level->cleanup();
677 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
679 le_current_level->load(le_level_subset->name.c_str(), le_level);
688 le_current_level->load_gfx();
690 le_world.activate_bad_guys();
695 /*if(level_changed == true)
696 if(askforsaving() == CANCEL)
699 SDL_EnableKeyRepeat(0, 0); // disables key repeating
702 delete leveleditor_menu;
703 delete subset_load_menu;
704 delete subset_new_menu;
705 delete subset_settings_menu;
706 delete level_settings_menu;
707 delete select_tilegroup_menu;
708 delete select_objects_menu;
709 delete le_save_level_bt;
711 delete le_test_level_bt;
712 delete le_next_level_bt;
713 delete le_previous_level_bt;
714 delete le_move_right_bt;
715 delete le_move_left_bt;
717 delete le_select_mode_one_bt;
718 delete le_select_mode_two_bt;
719 delete le_settings_bt;
720 delete le_tilegroup_bt;
721 delete le_objects_bt;
722 delete le_tilemap_panel;
724 delete le_current_level;
725 le_current_level = 0;
726 delete le_level_subset;
729 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
730 i != tilegroups_map.end(); ++i)
734 for(ButtonPanelMap::iterator i = objects_map.begin();
735 i != objects_map.end(); ++i)
741 void le_drawinterface()
746 if(le_current_level != NULL)
748 /* draw a grid (if selected) */
751 for(x = 0; x < 19; x++)
752 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
753 for(y = 0; y < 15; y++)
754 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
758 if(le_selection_mode == CURSOR)
759 le_selection->draw( cursor_x - pos_x, cursor_y);
760 else if(le_selection_mode == SQUARE)
763 le_highlight_selection();
764 /* draw current selection */
765 w = selection.x2 - selection.x1;
766 h = selection.y2 - selection.y1;
767 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
768 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
769 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
770 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
774 /* draw button bar */
775 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
777 if(le_current.IsTile())
779 Tile::draw(19 * 32, 14 * 32, le_current.tile);
780 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
781 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
784 //if(le_current.IsObject())
787 if(le_current_level != NULL)
789 le_save_level_bt->draw();
791 le_test_level_bt->draw();
792 le_next_level_bt->draw();
793 le_previous_level_bt->draw();
794 le_rubber_bt->draw();
795 if(le_selection_mode == SQUARE)
796 le_select_mode_one_bt->draw();
797 else if(le_selection_mode == CURSOR)
798 le_select_mode_two_bt->draw();
799 le_settings_bt->draw();
800 le_move_right_bt->draw();
801 le_move_left_bt->draw();
802 le_tilegroup_bt->draw();
803 le_objects_bt->draw();
804 if(!cur_tilegroup.empty())
805 tilegroups_map[cur_tilegroup]->draw();
806 else if(!cur_objects.empty())
808 objects_map[cur_objects]->draw();
811 le_tilemap_panel->draw();
813 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
814 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
816 white_small_text->draw("F1 for Help", 10, 430, 1);
821 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
823 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
830 unsigned int y,x,i,s;
833 /* Draw the real background */
834 if(le_current_level->bkgd_image[0] != '\0')
837 le_current_level->img_bkgd->draw_part(s,0,0,0,
838 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
839 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
840 le_current_level->img_bkgd->h);
844 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
847 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
849 for (y = 0; y < 15; ++y)
850 for (x = 0; x < 20; ++x)
853 if(active_tm == TM_BG)
858 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
860 if(active_tm == TM_IA)
865 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
867 if(active_tm == TM_FG)
872 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
874 /* draw whats inside stuff when cursor is selecting those */
875 /* (draw them all the time - is this the right behaviour?) */
876 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
877 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);
881 /* Draw the Bad guys: */
882 for (i = 0; i < le_world.bad_guys.size(); ++i)
884 /* to support frames: img_bsod_left[(frame / 5) % 4] */
887 le_world.bad_guys[i].draw();
891 /* Draw the player: */
892 /* for now, the position is fixed at (100, 240) */
893 largetux.walk_right->draw( 100 - pos_x, 240);
896 void le_checkevents()
903 keymod = SDL_GetModState();
905 while(SDL_PollEvent(&event))
909 Menu::current()->event(event);
913 mouse_cursor->set_state(MC_NORMAL);
915 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
916 if(event.type == SDL_KEYDOWN
917 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
918 && (event.motion.x > 0
919 && event.motion.x < screen->w - 64 &&
920 event.motion.y > 0 && event.motion.y < screen->h)))
924 case SDL_KEYDOWN: // key pressed
925 key = event.key.keysym.sym;
929 Menu::set_current(leveleditor_menu);
932 cursor_x -= KEY_CURSOR_SPEED;
934 cursor_x -= KEY_CURSOR_FASTSPEED;
936 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
937 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
942 cursor_x += KEY_CURSOR_SPEED;
944 cursor_x += KEY_CURSOR_FASTSPEED;
946 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
947 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
952 cursor_y -= KEY_CURSOR_SPEED;
954 cursor_y -= KEY_CURSOR_FASTSPEED;
961 cursor_y += KEY_CURSOR_SPEED;
963 cursor_y += KEY_CURSOR_FASTSPEED;
965 if(cursor_y > screen->h-32)
966 cursor_y = screen->h-32;
979 cursor_x = (le_current_level->width * 32) - 32;
983 le_show_grid = !le_show_grid;
989 case SDL_KEYUP: /* key released */
990 switch(event.key.keysym.sym)
999 case SDL_MOUSEBUTTONDOWN:
1000 if(event.button.button == SDL_BUTTON_LEFT)
1002 le_mouse_pressed[LEFT] = true;
1004 selection.x1 = event.motion.x + pos_x;
1005 selection.y1 = event.motion.y;
1006 selection.x2 = event.motion.x + pos_x;
1007 selection.y2 = event.motion.y;
1009 else if(event.button.button == SDL_BUTTON_RIGHT)
1011 le_mouse_pressed[RIGHT] = true;
1014 case SDL_MOUSEBUTTONUP:
1015 if(event.button.button == SDL_BUTTON_LEFT)
1016 le_mouse_pressed[LEFT] = false;
1017 else if(event.button.button == SDL_BUTTON_RIGHT)
1018 le_mouse_pressed[RIGHT] = false;
1020 case SDL_MOUSEMOTION:
1022 if(!Menu::current())
1027 if(le_current.IsTile())
1029 cursor_x = ((int)(pos_x + x) / 32) * 32;
1030 cursor_y = ((int) y / 32) * 32;
1038 if(le_mouse_pressed[LEFT])
1040 selection.x2 = x + pos_x;
1044 if(le_mouse_pressed[RIGHT])
1046 pos_x += -1 * event.motion.xrel;
1050 case SDL_QUIT: // window closed
1059 if(le_current_level != NULL)
1061 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 &&
1062 event.motion.y > 0 && event.motion.y < screen->h)))
1064 le_mouse_pressed[LEFT] = false;
1065 le_mouse_pressed[RIGHT] = false;
1067 if(!Menu::current())
1069 /* Check for button events */
1070 le_test_level_bt->event(event);
1071 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1073 le_save_level_bt->event(event);
1074 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1075 le_current_level->save(le_level_subset->name.c_str(),le_level);
1076 le_exit_bt->event(event);
1077 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1079 Menu::set_current(leveleditor_menu);
1081 le_next_level_bt->event(event);
1082 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1084 if(le_level < le_level_subset->levels)
1086 le_goto_level(++le_level);
1092 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1093 if(confirm_dialog(str))
1095 new_lev.init_defaults();
1096 new_lev.save(le_level_subset->name.c_str(),++le_level);
1097 le_level_subset->levels = le_level;
1098 le_goto_level(le_level);
1102 le_previous_level_bt->event(event);
1103 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1106 le_goto_level(--le_level);
1108 le_rubber_bt->event(event);
1109 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1112 if(le_selection_mode == SQUARE)
1114 le_select_mode_one_bt->event(event);
1115 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1116 le_selection_mode = CURSOR;
1120 le_select_mode_two_bt->event(event);
1121 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1122 le_selection_mode = SQUARE;
1125 le_tilegroup_bt->event(event);
1126 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1128 Menu::set_current(select_tilegroup_menu);
1129 select_tilegroup_menu_effect.start(200);
1130 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1133 le_objects_bt->event(event);
1134 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1136 Menu::set_current(select_objects_menu);
1137 select_objects_menu_effect.start(200);
1138 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1141 le_settings_bt->event(event);
1142 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1144 update_level_settings_menu();
1145 Menu::set_current(level_settings_menu);
1147 if(!cur_tilegroup.empty())
1149 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1151 if(pbutton->get_state() == BUTTON_CLICKED)
1153 le_current.Tile(pbutton->get_tag());
1157 else if(!cur_objects.empty())
1159 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1161 if(pbutton->get_state() == BUTTON_CLICKED)
1163 le_current.Object(pbutton->get_game_object());
1168 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1170 if(pbutton->get_state() == BUTTON_CLICKED)
1172 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1178 le_settings_bt->event(event);
1179 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1181 Menu::set_current(0);
1183 le_tilegroup_bt->event(event);
1184 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1186 Menu::set_current(0);
1191 if(!Menu::current())
1193 le_move_left_bt->event(event);
1194 le_move_right_bt->event(event);
1196 if(le_mouse_pressed[LEFT])
1198 if(le_current.IsTile())
1199 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1200 else if(le_current.IsObject())
1202 std::string type = le_current.obj->type();
1203 if(type == "BadGuy")
1205 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1207 le_world.bad_guys.push_back(BadGuy(cursor_x, cursor_y,pbadguy->kind,false));
1208 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1215 if(!Menu::current())
1217 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1221 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1226 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1230 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1238 void le_highlight_selection()
1242 if(selection.x1 < selection.x2)
1252 if(selection.y1 < selection.y2)
1268 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1271 void le_change(float x, float y, int tm, unsigned int c)
1273 if(le_current_level != NULL)
1279 /* level_changed = true; */
1281 switch(le_selection_mode)
1284 le_current_level->change(x,y,tm,c);
1286 base_type cursor_base;
1289 cursor_base.width = 32;
1290 cursor_base.height = 32;
1292 /* if there is a bad guy over there, remove it */
1293 for(i = 0; i < le_world.bad_guys.size(); ++i)
1294 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1296 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1297 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1302 if(selection.x1 < selection.x2)
1312 if(selection.y1 < selection.y2)
1328 /* if there is a bad guy over there, remove it */
1329 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1330 i != le_world.bad_guys.end(); /* will be at end of loop */)
1332 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1333 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1335 i = le_world.bad_guys.erase(i);
1344 for(xx = x1; xx <= x2; xx++)
1345 for(yy = y1; yy <= y2; yy++)
1347 le_current_level->change(xx*32, yy*32, tm, c);
1359 le_current_level->save("test", le_level);
1361 GameSession session("test",le_level, ST_GL_TEST);
1363 player_status.reset();
1365 music_manager->halt_music();
1367 Menu::set_current(leveleditor_menu);
1368 le_world.arrays_free();
1369 le_current_level->load_gfx();
1370 le_world.activate_bad_guys();
1376 unsigned int i, done_;
1378 " - This is SuperTux's built-in level editor -",
1379 "It has been designed to be light and easy to use from the start.",
1381 "When you first load the level editor you are given a menu where you",
1382 "can load level subsets, create a new level subset, edit the current",
1383 "subset's settings, or simply quit the editor. You can access this menu",
1384 "from the level editor at any time by pressing the escape key.",
1386 "To your right is your button bar. The center of this contains many",
1387 "tiles you can use to make your level. To select a tile, click on it",
1388 "with your left mouse button; your selection will be shown in the",
1389 "bottom right corner of the button box. Click anywhere on your level",
1390 "with the left mouse button to place that tile down. If you right click",
1391 "a tile in the button bar, you can find out what its keyboard shortcut",
1392 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1393 "background, and enemy tiles. The eraser lets you remove tiles.",
1394 "The left and right arrow keys scroll back and forth through your level.",
1395 "The button with the wrench and screwdriver, lets you change the",
1396 "settings of your level, including how long it is or what music it will",
1397 "play. When you are ready to give your level a test, click on the little",
1398 "running Tux. If you like the changes you have made to your level,",
1399 "press the red save key to keep them.",
1400 "To change which level in your subset you are editing, press the white",
1401 "up and down arrow keys at the top of the button box.",
1403 "Have fun making levels! If you make some good ones, send them to us on",
1404 "the SuperTux mailing list!",
1409 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1411 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1412 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1414 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1422 done_ = wait_for_event(event);