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);
110 /* leveleditor internals */
111 static string_list_type level_subsets;
112 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
113 static int pos_x, cursor_x, cursor_y, fire;
115 static LevelEditorWorld le_world;
116 static LevelSubset* le_level_subset;
117 static int le_show_grid;
119 static Surface* le_selection;
121 static unsigned int le_current_tile;
122 static bool le_mouse_pressed[2];
123 static Button* le_save_level_bt;
124 static Button* le_exit_bt;
125 static Button* le_test_level_bt;
126 static Button* le_next_level_bt;
127 static Button* le_previous_level_bt;
128 static Button* le_move_right_bt;
129 static Button* le_move_left_bt;
130 static Button* le_rubber_bt;
131 static Button* le_select_mode_one_bt;
132 static Button* le_select_mode_two_bt;
133 static Button* le_settings_bt;
134 static Button* le_tilegroup_bt;
135 static ButtonPanel* le_tilemap_panel;
136 static Menu* leveleditor_menu;
137 static Menu* subset_load_menu;
138 static Menu* subset_new_menu;
139 static Menu* subset_settings_menu;
140 static Menu* level_settings_menu;
141 static Menu* select_tilegroup_menu;
142 static Timer select_tilegroup_menu_effect;
143 typedef std::map<std::string, ButtonPanel*> TileGroupsMap;
144 static TileGroupsMap tilegroups_map;
145 static std::string cur_tilegroup;
147 static square selection;
148 static int le_selection_mode;
149 static SDL_Event event;
150 TileMapType active_tm;
152 // menu items for subset creation menu
157 void le_set_defaults()
159 if(le_current_level != NULL)
163 if(le_current_level->time_left == 0)
164 le_current_level->time_left = 255;
168 int leveleditor(int levelnb)
170 int last_time, now_time, i;
178 clearscreen(0, 0, 0);
181 music_manager->halt_music();
183 while (SDL_PollEvent(&event))
188 last_time = SDL_GetTicks();
193 if(Menu::current() == select_tilegroup_menu)
195 if(select_tilegroup_menu_effect.check())
197 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
201 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
204 if(le_current_level != NULL)
206 /* making events results to be in order */
209 if(pos_x > (le_current_level->width * 32) - screen->w)
210 pos_x = (le_current_level->width * 32) - screen->w;
216 clearscreen(0, 0, 0);
218 /* draw editor interface */
221 Menu* menu = Menu::current();
227 if(menu == leveleditor_menu)
229 switch (leveleditor_menu->check())
231 case MNID_RETURNLEVELEDITOR:
232 Menu::set_current(0);
234 case MNID_SUBSETSETTINGS:
235 update_subset_settings_menu();
237 case MNID_QUITLEVELEDITOR:
242 else if(menu == level_settings_menu)
244 switch (level_settings_menu->check())
246 case MNID_SUBSETSETTINGS:
247 apply_level_settings_menu();
248 Menu::set_current(leveleditor_menu);
256 else if(menu == select_tilegroup_menu)
259 switch (it = select_tilegroup_menu->check())
265 = select_tilegroup_menu->get_item_by_id(it).text;
266 Menu::set_current(0);
271 else if(menu == subset_load_menu)
273 switch (i = subset_load_menu->check())
280 le_level_subset->load(level_subsets.item[i-1]);
281 leveleditor_menu->item[3].kind = MN_GOTO;
283 le_world.arrays_free();
284 delete le_current_level;
285 le_current_level = new Level;
286 if(le_current_level->load(le_level_subset->name, le_level) != 0)
292 le_current_level->load_gfx();
293 le_world.activate_bad_guys();
296 Menu::set_current(leveleditor_menu);
301 else if(menu == subset_new_menu)
303 if(subset_new_menu->item[2].input[0] == '\0')
304 subset_new_menu->item[3].kind = MN_DEACTIVE;
307 subset_new_menu->item[3].kind = MN_ACTION;
309 switch (i = subset_new_menu->check())
311 case MNID_CREATESUBSET:
312 LevelSubset::create(subset_new_menu->item[2].input);
313 le_level_subset->load(subset_new_menu->item[2].input);
314 leveleditor_menu->item[3].kind = MN_GOTO;
316 le_world.arrays_free();
317 delete le_current_level;
318 le_current_level = new Level;
319 if(le_current_level->load(le_level_subset->name, le_level) != 0)
325 le_current_level->load_gfx();
326 le_world.activate_bad_guys();
327 subset_new_menu->item[2].change_input("");
328 // FIXME:? show_menu = true;
329 Menu::set_current(leveleditor_menu);
334 else if(menu == subset_settings_menu)
336 if(le_level_subset->title.compare(subset_settings_menu->item[2].input) == 0 && le_level_subset->description.compare(subset_settings_menu->item[3].input) == 0 )
337 subset_settings_menu->item[5].kind = MN_DEACTIVE;
339 subset_settings_menu->item[5].kind = MN_ACTION;
341 switch (i = subset_settings_menu->check())
344 save_subset_settings_menu();
345 //FIXME:show_menu = true;
346 Menu::set_current(leveleditor_menu);
352 mouse_cursor->draw();
360 ++global_frame_counter;
363 now_time = SDL_GetTicks();
364 if (now_time < last_time + FPS)
365 SDL_Delay(last_time + FPS - now_time); /* delay some time */
377 level_subsets = dsubdirs("/levels", "info");
379 le_level_subset = new LevelSubset;
385 /* level_changed = NO;*/
388 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
389 le_level_changed = false;
390 le_current_level = NULL;
393 le_mouse_pressed[LEFT] = false;
394 le_mouse_pressed[RIGHT] = false;
396 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
398 select_tilegroup_menu_effect.init(false);
401 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
402 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
403 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
404 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
405 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
406 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
407 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
408 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
409 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
410 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
411 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
412 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
414 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
415 le_tilemap_panel->set_button_size(32,10);
416 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
417 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
418 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
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();
427 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
428 leveleditor_menu->additem(MN_HL,"",0,0);
429 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
430 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
431 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
432 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
433 leveleditor_menu->additem(MN_HL,"",0,0);
434 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
436 Menu::set_current(leveleditor_menu);
438 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
439 subset_load_menu->additem(MN_HL, "", 0, 0);
441 for(i = 0; i < level_subsets.num_items; ++i)
443 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
445 subset_load_menu->additem(MN_HL,"",0,0);
446 subset_load_menu->additem(MN_BACK,"Back",0,0);
448 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
449 subset_new_menu->additem(MN_HL,"",0,0);
450 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
451 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
452 subset_new_menu->additem(MN_HL,"",0,0);
453 subset_new_menu->additem(MN_BACK,"Back",0,0);
455 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
456 subset_settings_menu->additem(MN_HL,"",0,0);
457 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
458 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
459 subset_settings_menu->additem(MN_HL,"",0,0);
460 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
461 subset_settings_menu->additem(MN_HL,"",0,0);
462 subset_settings_menu->additem(MN_BACK,"Back",0,0);
464 level_settings_menu->arrange_left = true;
465 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
466 level_settings_menu->additem(MN_HL,"",0,0);
467 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
468 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
469 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
470 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
471 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
472 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
473 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
474 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
475 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
476 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
477 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
478 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
479 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
480 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
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 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
514 void update_level_settings_menu()
519 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
520 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
521 sprintf(str,"%d",le_current_level->width);
523 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
524 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
525 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
526 string_list_add_item(level_settings_menu->item[6].list,"");
527 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
528 level_settings_menu->item[3].list->active_item = i;
529 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
530 level_settings_menu->item[4].list->active_item = i;
531 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
532 level_settings_menu->item[5].list->active_item = i;
534 level_settings_menu->item[7].change_input(str);
535 sprintf(str,"%d",le_current_level->time_left);
536 level_settings_menu->item[8].change_input(str);
537 sprintf(str,"%2.0f",le_current_level->gravity);
538 level_settings_menu->item[9].change_input(str);
539 sprintf(str,"%d",le_current_level->bkgd_top.red);
540 level_settings_menu->item[10].change_input(str);
541 sprintf(str,"%d",le_current_level->bkgd_top.green);
542 level_settings_menu->item[11].change_input(str);
543 sprintf(str,"%d",le_current_level->bkgd_top.blue);
544 level_settings_menu->item[12].change_input(str);
545 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
546 level_settings_menu->item[13].change_input(str);
547 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
548 level_settings_menu->item[14].change_input(str);
549 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
550 level_settings_menu->item[15].change_input(str);
553 void update_subset_settings_menu()
555 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
556 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
559 void apply_level_settings_menu()
564 le_current_level->name = level_settings_menu->item[2].input;
565 le_current_level->author = level_settings_menu->item[3].input;
567 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
569 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
573 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
575 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
581 le_current_level->free_gfx();
582 le_current_level->load_gfx();
585 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
587 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
588 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
589 le_current_level->gravity = atof(level_settings_menu->item[9].input);
590 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
591 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
592 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
593 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
594 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
595 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
598 void save_subset_settings_menu()
600 le_level_subset->title = subset_settings_menu->item[2].input;
601 le_level_subset->description = subset_settings_menu->item[3].input;
602 le_level_subset->save();
605 void le_goto_level(int levelnb)
607 le_world.arrays_free();
609 le_current_level->cleanup();
610 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
612 le_current_level->load(le_level_subset->name.c_str(), le_level);
621 le_current_level->free_gfx();
622 le_current_level->load_gfx();
624 le_world.activate_bad_guys();
629 /*if(level_changed == true)
630 if(askforsaving() == CANCEL)
633 SDL_EnableKeyRepeat(0, 0); // disables key repeating
636 delete leveleditor_menu;
637 delete subset_load_menu;
638 delete subset_new_menu;
639 delete subset_settings_menu;
640 delete level_settings_menu;
641 delete select_tilegroup_menu;
642 delete le_save_level_bt;
644 delete le_test_level_bt;
645 delete le_next_level_bt;
646 delete le_previous_level_bt;
647 delete le_move_right_bt;
648 delete le_move_left_bt;
650 delete le_select_mode_one_bt;
651 delete le_select_mode_two_bt;
652 delete le_settings_bt;
653 delete le_tilegroup_bt;
654 delete le_tilemap_panel;
656 delete le_current_level;
657 le_current_level = 0;
659 for(TileGroupsMap::iterator i = tilegroups_map.begin();
660 i != tilegroups_map.end(); ++i)
666 void le_drawinterface()
671 if(le_current_level != NULL)
673 /* draw a grid (if selected) */
676 for(x = 0; x < 19; x++)
677 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
678 for(y = 0; y < 15; y++)
679 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
683 if(le_selection_mode == CURSOR)
684 le_selection->draw( cursor_x - pos_x, cursor_y);
685 else if(le_selection_mode == SQUARE)
688 le_highlight_selection();
689 /* draw current selection */
690 w = selection.x2 - selection.x1;
691 h = selection.y2 - selection.y1;
692 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
693 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
694 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
695 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
699 /* draw button bar */
700 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
701 Tile::draw(19 * 32, 14 * 32, le_current_tile);
703 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
704 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
706 if(le_current_level != NULL)
708 le_save_level_bt->draw();
710 le_test_level_bt->draw();
711 le_next_level_bt->draw();
712 le_previous_level_bt->draw();
713 le_rubber_bt->draw();
714 le_select_mode_one_bt->draw();
715 le_select_mode_two_bt->draw();
716 le_settings_bt->draw();
717 le_move_right_bt->draw();
718 le_move_left_bt->draw();
719 le_tilegroup_bt->draw();
720 if(!cur_tilegroup.empty())
721 tilegroups_map[cur_tilegroup]->draw();
722 le_tilemap_panel->draw();
724 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
725 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
727 white_small_text->draw("F1 for Help", 10, 430, 1);
732 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
734 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
741 unsigned int y,x,i,s;
744 /* Draw the real background */
745 if(le_current_level->bkgd_image[0] != '\0')
748 le_current_level->img_bkgd->draw_part(s,0,0,0,
749 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
750 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
751 le_current_level->img_bkgd->h);
755 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
758 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
760 for (y = 0; y < 15; ++y)
761 for (x = 0; x < 20; ++x)
764 if(active_tm == TM_BG)
769 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
771 if(active_tm == TM_IA)
776 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
778 if(active_tm == TM_FG)
783 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
785 /* draw whats inside stuff when cursor is selecting those */
786 /* (draw them all the time - is this the right behaviour?) */
787 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
788 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);
792 /* Draw the Bad guys: */
793 for (i = 0; i < le_world.bad_guys.size(); ++i)
795 /* to support frames: img_bsod_left[(frame / 5) % 4] */
798 le_world.bad_guys[i].draw();
802 /* Draw the player: */
803 /* for now, the position is fixed at (100, 240) */
804 largetux.walk_right->draw( 100 - pos_x, 240);
807 void le_checkevents()
814 keymod = SDL_GetModState();
816 while(SDL_PollEvent(&event))
820 Menu::current()->event(event);
824 mouse_cursor->set_state(MC_NORMAL);
826 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
827 if(event.type == SDL_KEYDOWN
828 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
829 && (event.motion.x > 0
830 && event.motion.x < screen->w - 64 &&
831 event.motion.y > 0 && event.motion.y < screen->h)))
835 case SDL_KEYDOWN: // key pressed
836 key = event.key.keysym.sym;
840 Menu::set_current(leveleditor_menu);
843 cursor_x -= KEY_CURSOR_SPEED;
845 cursor_x -= KEY_CURSOR_FASTSPEED;
847 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
848 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
853 cursor_x += KEY_CURSOR_SPEED;
855 cursor_x += KEY_CURSOR_FASTSPEED;
857 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
858 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
863 cursor_y -= KEY_CURSOR_SPEED;
865 cursor_y -= KEY_CURSOR_FASTSPEED;
872 cursor_y += KEY_CURSOR_SPEED;
874 cursor_y += KEY_CURSOR_FASTSPEED;
876 if(cursor_y > screen->h-32)
877 cursor_y = screen->h-32;
890 cursor_x = (le_current_level->width * 32) - 32;
894 le_show_grid = !le_show_grid;
900 case SDL_KEYUP: /* key released */
901 switch(event.key.keysym.sym)
910 case SDL_MOUSEBUTTONDOWN:
911 if(event.button.button == SDL_BUTTON_LEFT)
913 le_mouse_pressed[LEFT] = true;
915 selection.x1 = event.motion.x + pos_x;
916 selection.y1 = event.motion.y;
917 selection.x2 = event.motion.x + pos_x;
918 selection.y2 = event.motion.y;
920 else if(event.button.button == SDL_BUTTON_RIGHT)
922 le_mouse_pressed[RIGHT] = true;
925 case SDL_MOUSEBUTTONUP:
926 if(event.button.button == SDL_BUTTON_LEFT)
927 le_mouse_pressed[LEFT] = false;
928 else if(event.button.button == SDL_BUTTON_RIGHT)
929 le_mouse_pressed[RIGHT] = false;
931 case SDL_MOUSEMOTION:
938 cursor_x = ((int)(pos_x + x) / 32) * 32;
939 cursor_y = ((int) y / 32) * 32;
941 if(le_mouse_pressed[LEFT])
943 selection.x2 = x + pos_x;
947 if(le_mouse_pressed[RIGHT])
949 pos_x += -1 * event.motion.xrel;
953 case SDL_QUIT: // window closed
962 if(le_current_level != NULL)
964 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 &&
965 event.motion.y > 0 && event.motion.y < screen->h)))
967 le_mouse_pressed[LEFT] = false;
968 le_mouse_pressed[RIGHT] = false;
972 /* Check for button events */
973 le_test_level_bt->event(event);
974 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
976 le_save_level_bt->event(event);
977 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
978 le_current_level->save(le_level_subset->name.c_str(),le_level);
979 le_exit_bt->event(event);
980 if(le_exit_bt->get_state() == BUTTON_CLICKED)
982 Menu::set_current(leveleditor_menu);
984 le_next_level_bt->event(event);
985 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
987 if(le_level < le_level_subset->levels)
989 le_goto_level(++le_level);
995 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
996 if(confirm_dialog(str))
998 new_lev.init_defaults();
999 new_lev.save(le_level_subset->name.c_str(),++le_level);
1000 le_level_subset->levels = le_level;
1001 le_goto_level(le_level);
1005 le_previous_level_bt->event(event);
1006 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1009 le_goto_level(--le_level);
1011 le_rubber_bt->event(event);
1012 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1013 le_current_tile = 0;
1014 le_select_mode_one_bt->event(event);
1015 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1016 le_selection_mode = CURSOR;
1017 le_select_mode_two_bt->event(event);
1018 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1019 le_selection_mode = SQUARE;
1021 le_tilegroup_bt->event(event);
1022 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1024 Menu::set_current(select_tilegroup_menu);
1025 select_tilegroup_menu_effect.start(200);
1026 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1029 le_settings_bt->event(event);
1030 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1032 update_level_settings_menu();
1033 Menu::set_current(level_settings_menu);
1035 if(!cur_tilegroup.empty())
1036 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1038 if(pbutton->get_state() == BUTTON_CLICKED)
1040 le_current_tile = pbutton->get_tag();
1043 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1045 if(pbutton->get_state() == BUTTON_CLICKED)
1047 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1053 le_settings_bt->event(event);
1054 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1056 Menu::set_current(0);
1058 le_tilegroup_bt->event(event);
1059 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1061 Menu::set_current(0);
1066 if(!Menu::current())
1068 le_move_left_bt->event(event);
1069 le_move_right_bt->event(event);
1071 if(le_mouse_pressed[LEFT])
1073 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1078 if(!Menu::current())
1080 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1084 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1089 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1093 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1101 void le_highlight_selection()
1105 if(selection.x1 < selection.x2)
1115 if(selection.y1 < selection.y2)
1131 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1134 void le_change(float x, float y, int tm, unsigned int c)
1136 if(le_current_level != NULL)
1142 /* level_changed = true; */
1144 switch(le_selection_mode)
1147 le_current_level->change(x,y,tm,c);
1152 /* if there is a bad guy over there, remove it */
1153 for(i = 0; i < le_world.bad_guys.size(); ++i)
1154 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1155 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1157 if(c == '0') /* if it's a bad guy */
1158 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1160 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1162 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1166 if(selection.x1 < selection.x2)
1176 if(selection.y1 < selection.y2)
1192 /* if there is a bad guy over there, remove it */
1193 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1194 i != le_world.bad_guys.end(); /* will be at end of loop */) {
1195 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1196 && i->base.y/32 >= y1 && i->base.y/32 <= y2) {
1197 i = le_world.bad_guys.erase(i);
1204 for(xx = x1; xx <= x2; xx++)
1205 for(yy = y1; yy <= y2; yy++)
1207 le_current_level->change(xx*32, yy*32, tm, c);
1209 if(c == '0') // if it's a bad guy
1210 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1212 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1214 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1225 le_current_level->save("test", le_level);
1227 GameSession session("test",le_level, ST_GL_TEST);
1230 music_manager->halt_music();
1232 Menu::set_current(leveleditor_menu);
1233 le_world.arrays_free();
1234 le_current_level->load_gfx();
1235 le_world.activate_bad_guys();
1241 unsigned int i, done_;
1243 " - This is SuperTux's built-in level editor -",
1244 "It has been designed to be light and easy to use from the start.",
1246 "When you first load the level editor you are given a menu where you",
1247 "can load level subsets, create a new level subset, edit the current",
1248 "subset's settings, or simply quit the editor. You can access this menu",
1249 "from the level editor at any time by pressing the escape key.",
1251 "To your right is your button bar. The center of this contains many",
1252 "tiles you can use to make your level. To select a tile, click on it",
1253 "with your left mouse button; your selection will be shown in the",
1254 "bottom right corner of the button box. Click anywhere on your level",
1255 "with the left mouse button to place that tile down. If you right click",
1256 "a tile in the button bar, you can find out what its keyboard shortcut",
1257 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1258 "background, and enemy tiles. The eraser lets you remove tiles.",
1259 "The left and right arrow keys scroll back and forth through your level.",
1260 "The button with the wrench and screwdriver, lets you change the",
1261 "settings of your level, including how long it is or what music it will",
1262 "play. When you are ready to give your level a test, click on the little",
1263 "running Tux. If you like the changes you have made to your level,",
1264 "press the red save key to keep them.",
1265 "To change which level in your subset you are editing, press the white",
1266 "up and down arrow keys at the top of the button box.",
1268 "Have fun making levels! If you make some good ones, send them to us on",
1269 "the SuperTux mailing list!",
1274 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1276 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1277 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1279 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1287 done_ = wait_for_event(event);