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 imagefile += TileManager::instance()->get(*sit)->filenames[0];
502 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
504 tilegroups_map[it->name]->additem(button, *sit);
507 select_tilegroup_menu->additem(MN_HL,"",0,0);
509 select_objects_menu->arrange_left = true;
510 select_objects_menu->additem(MN_LABEL,"Select Objects",0,0);
511 select_objects_menu->additem(MN_HL,"",0,0);
512 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
513 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
515 for(int i = 0; i < NUM_BadGuyKinds; ++i)
517 BadGuy bad_tmp(0,0,BadGuyKind(i),false);
518 objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
519 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));
522 select_objects_menu->additem(MN_HL,"",0,0);
528 level_subsets = dsubdirs("/levels", "info");
530 le_level_subset = new LevelSubset;
536 /* level_changed = NO;*/
539 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
540 le_level_changed = false;
541 le_current_level = NULL;
543 le_mouse_pressed[LEFT] = false;
544 le_mouse_pressed[RIGHT] = false;
546 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
548 select_tilegroup_menu_effect.init(false);
549 select_objects_menu_effect.init(false);
552 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
553 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
554 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
555 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
556 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
557 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
558 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
559 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
560 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
561 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
562 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
563 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
564 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
566 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
567 le_tilemap_panel->set_button_size(32,10);
568 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
569 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
570 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
574 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
579 void update_level_settings_menu()
584 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_current_level->name.c_str());
585 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_current_level->author.c_str());
587 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
588 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
589 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
591 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_current_level->song_title.c_str())) != -1)
592 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
593 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_current_level->bkgd_image.c_str())) != -1)
594 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
596 sprintf(str,"%d",le_current_level->width);
597 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
598 sprintf(str,"%d",le_current_level->time_left);
599 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
600 sprintf(str,"%2.0f",le_current_level->gravity);
601 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
602 sprintf(str,"%d",le_current_level->bkgd_top.red);
603 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
604 sprintf(str,"%d",le_current_level->bkgd_top.green);
605 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
606 sprintf(str,"%d",le_current_level->bkgd_top.blue);
607 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
608 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
609 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
610 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
611 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
612 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
613 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
616 void update_subset_settings_menu()
618 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
619 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
622 void apply_level_settings_menu()
627 le_current_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
628 le_current_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
630 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
632 le_current_level->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
638 le_current_level->load_gfx();
641 le_current_level->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
643 le_current_level->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
644 le_current_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
645 le_current_level->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
646 le_current_level->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
647 le_current_level->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
648 le_current_level->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
649 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
650 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
651 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
654 void save_subset_settings_menu()
656 le_level_subset->title = subset_settings_menu->item[2].input;
657 le_level_subset->description = subset_settings_menu->item[3].input;
658 le_level_subset->save();
661 void le_goto_level(int levelnb)
663 le_world.arrays_free();
665 le_current_level->cleanup();
666 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
668 le_current_level->load(le_level_subset->name.c_str(), le_level);
677 le_current_level->load_gfx();
679 le_world.activate_bad_guys();
684 /*if(level_changed == true)
685 if(askforsaving() == CANCEL)
688 SDL_EnableKeyRepeat(0, 0); // disables key repeating
691 delete leveleditor_menu;
692 delete subset_load_menu;
693 delete subset_new_menu;
694 delete subset_settings_menu;
695 delete level_settings_menu;
696 delete select_tilegroup_menu;
697 delete select_objects_menu;
698 delete le_save_level_bt;
700 delete le_test_level_bt;
701 delete le_next_level_bt;
702 delete le_previous_level_bt;
703 delete le_move_right_bt;
704 delete le_move_left_bt;
706 delete le_select_mode_one_bt;
707 delete le_select_mode_two_bt;
708 delete le_settings_bt;
709 delete le_tilegroup_bt;
710 delete le_objects_bt;
711 delete le_tilemap_panel;
713 delete le_current_level;
714 le_current_level = 0;
715 delete le_level_subset;
718 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
719 i != tilegroups_map.end(); ++i)
723 for(ButtonPanelMap::iterator i = objects_map.begin();
724 i != objects_map.end(); ++i)
730 void le_drawinterface()
735 if(le_current_level != NULL)
737 /* draw a grid (if selected) */
740 for(x = 0; x < 19; x++)
741 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
742 for(y = 0; y < 15; y++)
743 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
747 if(le_selection_mode == CURSOR)
748 le_selection->draw( cursor_x - pos_x, cursor_y);
749 else if(le_selection_mode == SQUARE)
752 le_highlight_selection();
753 /* draw current selection */
754 w = selection.x2 - selection.x1;
755 h = selection.y2 - selection.y1;
756 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
757 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
758 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
759 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
763 /* draw button bar */
764 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
766 if(le_current.IsTile())
768 Tile::draw(19 * 32, 14 * 32, le_current.tile);
769 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
770 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
773 //if(le_current.IsObject())
776 if(le_current_level != NULL)
778 le_save_level_bt->draw();
780 le_test_level_bt->draw();
781 le_next_level_bt->draw();
782 le_previous_level_bt->draw();
783 le_rubber_bt->draw();
784 if(le_selection_mode == SQUARE)
785 le_select_mode_one_bt->draw();
786 else if(le_selection_mode == CURSOR)
787 le_select_mode_two_bt->draw();
788 le_settings_bt->draw();
789 le_move_right_bt->draw();
790 le_move_left_bt->draw();
791 le_tilegroup_bt->draw();
792 le_objects_bt->draw();
793 if(!cur_tilegroup.empty())
794 tilegroups_map[cur_tilegroup]->draw();
795 else if(!cur_objects.empty())
797 objects_map[cur_objects]->draw();
800 le_tilemap_panel->draw();
802 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
803 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
805 white_small_text->draw("F1 for Help", 10, 430, 1);
810 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
812 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
819 unsigned int y,x,i,s;
822 /* Draw the real background */
823 if(le_current_level->bkgd_image[0] != '\0')
826 le_current_level->img_bkgd->draw_part(s,0,0,0,
827 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
828 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
829 le_current_level->img_bkgd->h);
833 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
836 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
838 for (y = 0; y < 15; ++y)
839 for (x = 0; x < 20; ++x)
842 if(active_tm == TM_BG)
847 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
849 if(active_tm == TM_IA)
854 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
856 if(active_tm == TM_FG)
861 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
863 /* draw whats inside stuff when cursor is selecting those */
864 /* (draw them all the time - is this the right behaviour?) */
865 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
866 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);
870 /* Draw the Bad guys: */
871 for (i = 0; i < le_world.bad_guys.size(); ++i)
873 /* to support frames: img_bsod_left[(frame / 5) % 4] */
876 le_world.bad_guys[i].draw();
880 /* Draw the player: */
881 /* for now, the position is fixed at (100, 240) */
882 largetux.walk_right->draw( 100 - pos_x, 240);
885 void le_checkevents()
892 keymod = SDL_GetModState();
894 while(SDL_PollEvent(&event))
898 Menu::current()->event(event);
902 mouse_cursor->set_state(MC_NORMAL);
904 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
905 if(event.type == SDL_KEYDOWN
906 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
907 && (event.motion.x > 0
908 && event.motion.x < screen->w - 64 &&
909 event.motion.y > 0 && event.motion.y < screen->h)))
913 case SDL_KEYDOWN: // key pressed
914 key = event.key.keysym.sym;
918 Menu::set_current(leveleditor_menu);
921 cursor_x -= KEY_CURSOR_SPEED;
923 cursor_x -= KEY_CURSOR_FASTSPEED;
925 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
926 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
931 cursor_x += KEY_CURSOR_SPEED;
933 cursor_x += KEY_CURSOR_FASTSPEED;
935 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
936 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
941 cursor_y -= KEY_CURSOR_SPEED;
943 cursor_y -= KEY_CURSOR_FASTSPEED;
950 cursor_y += KEY_CURSOR_SPEED;
952 cursor_y += KEY_CURSOR_FASTSPEED;
954 if(cursor_y > screen->h-32)
955 cursor_y = screen->h-32;
968 cursor_x = (le_current_level->width * 32) - 32;
972 le_show_grid = !le_show_grid;
978 case SDL_KEYUP: /* key released */
979 switch(event.key.keysym.sym)
988 case SDL_MOUSEBUTTONDOWN:
989 if(event.button.button == SDL_BUTTON_LEFT)
991 le_mouse_pressed[LEFT] = true;
993 selection.x1 = event.motion.x + pos_x;
994 selection.y1 = event.motion.y;
995 selection.x2 = event.motion.x + pos_x;
996 selection.y2 = event.motion.y;
998 else if(event.button.button == SDL_BUTTON_RIGHT)
1000 le_mouse_pressed[RIGHT] = true;
1003 case SDL_MOUSEBUTTONUP:
1004 if(event.button.button == SDL_BUTTON_LEFT)
1005 le_mouse_pressed[LEFT] = false;
1006 else if(event.button.button == SDL_BUTTON_RIGHT)
1007 le_mouse_pressed[RIGHT] = false;
1009 case SDL_MOUSEMOTION:
1011 if(!Menu::current())
1016 if(le_current.IsTile())
1018 cursor_x = ((int)(pos_x + x) / 32) * 32;
1019 cursor_y = ((int) y / 32) * 32;
1027 if(le_mouse_pressed[LEFT])
1029 selection.x2 = x + pos_x;
1033 if(le_mouse_pressed[RIGHT])
1035 pos_x += -1 * event.motion.xrel;
1039 case SDL_QUIT: // window closed
1048 if(le_current_level != NULL)
1050 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 &&
1051 event.motion.y > 0 && event.motion.y < screen->h)))
1053 le_mouse_pressed[LEFT] = false;
1054 le_mouse_pressed[RIGHT] = false;
1056 if(!Menu::current())
1058 /* Check for button events */
1059 le_test_level_bt->event(event);
1060 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1062 le_save_level_bt->event(event);
1063 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1064 le_current_level->save(le_level_subset->name.c_str(),le_level);
1065 le_exit_bt->event(event);
1066 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1068 Menu::set_current(leveleditor_menu);
1070 le_next_level_bt->event(event);
1071 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1073 if(le_level < le_level_subset->levels)
1075 le_goto_level(++le_level);
1081 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1082 if(confirm_dialog(str))
1084 new_lev.init_defaults();
1085 new_lev.save(le_level_subset->name.c_str(),++le_level);
1086 le_level_subset->levels = le_level;
1087 le_goto_level(le_level);
1091 le_previous_level_bt->event(event);
1092 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1095 le_goto_level(--le_level);
1097 le_rubber_bt->event(event);
1098 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1101 if(le_selection_mode == SQUARE)
1103 le_select_mode_one_bt->event(event);
1104 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1105 le_selection_mode = CURSOR;
1109 le_select_mode_two_bt->event(event);
1110 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1111 le_selection_mode = SQUARE;
1114 le_tilegroup_bt->event(event);
1115 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1117 Menu::set_current(select_tilegroup_menu);
1118 select_tilegroup_menu_effect.start(200);
1119 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1122 le_objects_bt->event(event);
1123 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1125 Menu::set_current(select_objects_menu);
1126 select_objects_menu_effect.start(200);
1127 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1130 le_settings_bt->event(event);
1131 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1133 update_level_settings_menu();
1134 Menu::set_current(level_settings_menu);
1136 if(!cur_tilegroup.empty())
1138 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1140 if(pbutton->get_state() == BUTTON_CLICKED)
1142 le_current.Tile(pbutton->get_tag());
1146 else if(!cur_objects.empty())
1148 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1150 if(pbutton->get_state() == BUTTON_CLICKED)
1152 le_current.Object(pbutton->get_game_object());
1157 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1159 if(pbutton->get_state() == BUTTON_CLICKED)
1161 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1167 le_settings_bt->event(event);
1168 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1170 Menu::set_current(0);
1172 le_tilegroup_bt->event(event);
1173 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1175 Menu::set_current(0);
1180 if(!Menu::current())
1182 le_move_left_bt->event(event);
1183 le_move_right_bt->event(event);
1185 if(le_mouse_pressed[LEFT])
1187 if(le_current.IsTile())
1188 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1189 else if(le_current.IsObject())
1191 std::string type = le_current.obj->type();
1192 if(type == "BadGuy")
1194 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1196 le_world.bad_guys.push_back(BadGuy(cursor_x, cursor_y,pbadguy->kind,false));
1197 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1204 if(!Menu::current())
1206 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1210 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1215 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1219 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1227 void le_highlight_selection()
1231 if(selection.x1 < selection.x2)
1241 if(selection.y1 < selection.y2)
1257 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1260 void le_change(float x, float y, int tm, unsigned int c)
1262 if(le_current_level != NULL)
1268 /* level_changed = true; */
1270 switch(le_selection_mode)
1273 le_current_level->change(x,y,tm,c);
1275 base_type cursor_base;
1278 cursor_base.width = 32;
1279 cursor_base.height = 32;
1281 /* if there is a bad guy over there, remove it */
1282 for(i = 0; i < le_world.bad_guys.size(); ++i)
1283 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1285 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1286 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1291 if(selection.x1 < selection.x2)
1301 if(selection.y1 < selection.y2)
1317 /* if there is a bad guy over there, remove it */
1318 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1319 i != le_world.bad_guys.end(); /* will be at end of loop */)
1321 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1322 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1324 i = le_world.bad_guys.erase(i);
1333 for(xx = x1; xx <= x2; xx++)
1334 for(yy = y1; yy <= y2; yy++)
1336 le_current_level->change(xx*32, yy*32, tm, c);
1348 le_current_level->save("test", le_level);
1350 GameSession session("test",le_level, ST_GL_TEST);
1352 player_status.reset();
1354 music_manager->halt_music();
1356 Menu::set_current(leveleditor_menu);
1357 le_world.arrays_free();
1358 le_current_level->load_gfx();
1359 le_world.activate_bad_guys();
1365 unsigned int i, done_;
1367 " - This is SuperTux's built-in level editor -",
1368 "It has been designed to be light and easy to use from the start.",
1370 "When you first load the level editor you are given a menu where you",
1371 "can load level subsets, create a new level subset, edit the current",
1372 "subset's settings, or simply quit the editor. You can access this menu",
1373 "from the level editor at any time by pressing the escape key.",
1375 "To your right is your button bar. The center of this contains many",
1376 "tiles you can use to make your level. To select a tile, click on it",
1377 "with your left mouse button; your selection will be shown in the",
1378 "bottom right corner of the button box. Click anywhere on your level",
1379 "with the left mouse button to place that tile down. If you right click",
1380 "a tile in the button bar, you can find out what its keyboard shortcut",
1381 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1382 "background, and enemy tiles. The eraser lets you remove tiles.",
1383 "The left and right arrow keys scroll back and forth through your level.",
1384 "The button with the wrench and screwdriver, lets you change the",
1385 "settings of your level, including how long it is or what music it will",
1386 "play. When you are ready to give your level a test, click on the little",
1387 "running Tux. If you like the changes you have made to your level,",
1388 "press the red save key to keep them.",
1389 "To change which level in your subset you are editing, press the white",
1390 "up and down arrow keys at the top of the button box.",
1392 "Have fun making levels! If you make some good ones, send them to us on",
1393 "the SuperTux mailing list!",
1398 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1400 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1401 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1403 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1411 done_ = wait_for_event(event);