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 */
376 level_subsets = dsubdirs("/levels", "info");
378 le_level_subset = new LevelSubset;
384 /* level_changed = NO;*/
387 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
388 le_level_changed = false;
389 le_current_level = NULL;
392 le_mouse_pressed[LEFT] = false;
393 le_mouse_pressed[RIGHT] = false;
395 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
397 select_tilegroup_menu_effect.init(false);
400 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
401 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
402 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
403 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
404 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
405 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
406 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
407 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
408 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
409 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
410 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
411 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
413 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
414 le_tilemap_panel->set_button_size(32,10);
415 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
416 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
417 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
419 leveleditor_menu = new Menu();
420 subset_load_menu = new Menu();
421 subset_new_menu = new Menu();
422 subset_settings_menu = new Menu();
423 level_settings_menu = new Menu();
424 select_tilegroup_menu = new Menu();
426 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
427 leveleditor_menu->additem(MN_HL,"",0,0);
428 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
429 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
430 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
431 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
432 leveleditor_menu->additem(MN_HL,"",0,0);
433 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
435 Menu::set_current(leveleditor_menu);
437 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
438 subset_load_menu->additem(MN_HL, "", 0, 0);
440 for(i = 0; i < level_subsets.num_items; ++i)
442 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
444 subset_load_menu->additem(MN_HL,"",0,0);
445 subset_load_menu->additem(MN_BACK,"Back",0,0);
447 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
448 subset_new_menu->additem(MN_HL,"",0,0);
449 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
450 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
451 subset_new_menu->additem(MN_HL,"",0,0);
452 subset_new_menu->additem(MN_BACK,"Back",0,0);
454 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
455 subset_settings_menu->additem(MN_HL,"",0,0);
456 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
457 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
458 subset_settings_menu->additem(MN_HL,"",0,0);
459 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
460 subset_settings_menu->additem(MN_HL,"",0,0);
461 subset_settings_menu->additem(MN_BACK,"Back",0,0);
463 level_settings_menu->arrange_left = true;
464 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
465 level_settings_menu->additem(MN_HL,"",0,0);
466 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
467 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
468 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
469 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
470 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
471 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
472 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
473 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
474 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
475 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
476 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
477 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
478 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
479 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
480 level_settings_menu->additem(MN_HL,"",0,0);
481 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
483 select_tilegroup_menu->arrange_left = true;
484 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
485 select_tilegroup_menu->additem(MN_HL,"",0,0);
486 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
488 for(std::vector<TileGroup>::iterator it = tilegroups->begin();
489 it != tilegroups->end(); ++it )
491 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
493 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
496 for(std::vector<int>::iterator sit = (*it).tiles.begin();
497 sit != (*it).tiles.end(); ++sit, ++i)
499 std::string imagefile = "/images/tilesets/" ;
500 imagefile += TileManager::instance()->get(*sit)->filenames[0];
501 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
503 tilegroups_map[it->name]->additem(button, *sit);
506 select_tilegroup_menu->additem(MN_HL,"",0,0);
508 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
513 void update_level_settings_menu()
518 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
519 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
520 sprintf(str,"%d",le_current_level->width);
522 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
523 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
524 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
525 string_list_add_item(level_settings_menu->item[6].list,"");
526 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
527 level_settings_menu->item[3].list->active_item = i;
528 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
529 level_settings_menu->item[4].list->active_item = i;
530 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
531 level_settings_menu->item[5].list->active_item = i;
533 level_settings_menu->item[7].change_input(str);
534 sprintf(str,"%d",le_current_level->time_left);
535 level_settings_menu->item[8].change_input(str);
536 sprintf(str,"%2.0f",le_current_level->gravity);
537 level_settings_menu->item[9].change_input(str);
538 sprintf(str,"%d",le_current_level->bkgd_top.red);
539 level_settings_menu->item[10].change_input(str);
540 sprintf(str,"%d",le_current_level->bkgd_top.green);
541 level_settings_menu->item[11].change_input(str);
542 sprintf(str,"%d",le_current_level->bkgd_top.blue);
543 level_settings_menu->item[12].change_input(str);
544 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
545 level_settings_menu->item[13].change_input(str);
546 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
547 level_settings_menu->item[14].change_input(str);
548 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
549 level_settings_menu->item[15].change_input(str);
552 void update_subset_settings_menu()
554 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
555 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
558 void apply_level_settings_menu()
563 le_current_level->name = level_settings_menu->item[2].input;
564 le_current_level->author = level_settings_menu->item[3].input;
566 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
568 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
572 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
574 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
580 le_current_level->load_gfx();
583 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
585 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
586 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
587 le_current_level->gravity = atof(level_settings_menu->item[9].input);
588 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
589 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
590 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
591 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
592 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
593 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
596 void save_subset_settings_menu()
598 le_level_subset->title = subset_settings_menu->item[2].input;
599 le_level_subset->description = subset_settings_menu->item[3].input;
600 le_level_subset->save();
603 void le_goto_level(int levelnb)
605 le_world.arrays_free();
607 le_current_level->cleanup();
608 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
610 le_current_level->load(le_level_subset->name.c_str(), le_level);
619 le_current_level->load_gfx();
621 le_world.activate_bad_guys();
626 /*if(level_changed == true)
627 if(askforsaving() == CANCEL)
630 SDL_EnableKeyRepeat(0, 0); // disables key repeating
633 delete leveleditor_menu;
634 delete subset_load_menu;
635 delete subset_new_menu;
636 delete subset_settings_menu;
637 delete level_settings_menu;
638 delete select_tilegroup_menu;
639 delete le_save_level_bt;
641 delete le_test_level_bt;
642 delete le_next_level_bt;
643 delete le_previous_level_bt;
644 delete le_move_right_bt;
645 delete le_move_left_bt;
647 delete le_select_mode_one_bt;
648 delete le_select_mode_two_bt;
649 delete le_settings_bt;
650 delete le_tilegroup_bt;
651 delete le_tilemap_panel;
653 delete le_current_level;
654 le_current_level = 0;
655 delete le_level_subset;
658 for(TileGroupsMap::iterator i = tilegroups_map.begin();
659 i != tilegroups_map.end(); ++i)
665 void le_drawinterface()
670 if(le_current_level != NULL)
672 /* draw a grid (if selected) */
675 for(x = 0; x < 19; x++)
676 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
677 for(y = 0; y < 15; y++)
678 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
682 if(le_selection_mode == CURSOR)
683 le_selection->draw( cursor_x - pos_x, cursor_y);
684 else if(le_selection_mode == SQUARE)
687 le_highlight_selection();
688 /* draw current selection */
689 w = selection.x2 - selection.x1;
690 h = selection.y2 - selection.y1;
691 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
692 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
693 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
694 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
698 /* draw button bar */
699 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
700 Tile::draw(19 * 32, 14 * 32, le_current_tile);
702 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
703 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
705 if(le_current_level != NULL)
707 le_save_level_bt->draw();
709 le_test_level_bt->draw();
710 le_next_level_bt->draw();
711 le_previous_level_bt->draw();
712 le_rubber_bt->draw();
713 le_select_mode_one_bt->draw();
714 le_select_mode_two_bt->draw();
715 le_settings_bt->draw();
716 le_move_right_bt->draw();
717 le_move_left_bt->draw();
718 le_tilegroup_bt->draw();
719 if(!cur_tilegroup.empty())
720 tilegroups_map[cur_tilegroup]->draw();
721 le_tilemap_panel->draw();
723 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
724 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
726 white_small_text->draw("F1 for Help", 10, 430, 1);
731 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
733 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
740 unsigned int y,x,i,s;
743 /* Draw the real background */
744 if(le_current_level->bkgd_image[0] != '\0')
747 le_current_level->img_bkgd->draw_part(s,0,0,0,
748 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
749 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
750 le_current_level->img_bkgd->h);
754 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
757 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
759 for (y = 0; y < 15; ++y)
760 for (x = 0; x < 20; ++x)
763 if(active_tm == TM_BG)
768 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
770 if(active_tm == TM_IA)
775 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
777 if(active_tm == TM_FG)
782 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
784 /* draw whats inside stuff when cursor is selecting those */
785 /* (draw them all the time - is this the right behaviour?) */
786 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
787 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);
791 /* Draw the Bad guys: */
792 for (i = 0; i < le_world.bad_guys.size(); ++i)
794 /* to support frames: img_bsod_left[(frame / 5) % 4] */
797 le_world.bad_guys[i].draw();
801 /* Draw the player: */
802 /* for now, the position is fixed at (100, 240) */
803 largetux.walk_right->draw( 100 - pos_x, 240);
806 void le_checkevents()
813 keymod = SDL_GetModState();
815 while(SDL_PollEvent(&event))
819 Menu::current()->event(event);
823 mouse_cursor->set_state(MC_NORMAL);
825 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
826 if(event.type == SDL_KEYDOWN
827 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
828 && (event.motion.x > 0
829 && event.motion.x < screen->w - 64 &&
830 event.motion.y > 0 && event.motion.y < screen->h)))
834 case SDL_KEYDOWN: // key pressed
835 key = event.key.keysym.sym;
839 Menu::set_current(leveleditor_menu);
842 cursor_x -= KEY_CURSOR_SPEED;
844 cursor_x -= KEY_CURSOR_FASTSPEED;
846 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
847 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
852 cursor_x += KEY_CURSOR_SPEED;
854 cursor_x += KEY_CURSOR_FASTSPEED;
856 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
857 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
862 cursor_y -= KEY_CURSOR_SPEED;
864 cursor_y -= KEY_CURSOR_FASTSPEED;
871 cursor_y += KEY_CURSOR_SPEED;
873 cursor_y += KEY_CURSOR_FASTSPEED;
875 if(cursor_y > screen->h-32)
876 cursor_y = screen->h-32;
889 cursor_x = (le_current_level->width * 32) - 32;
893 le_show_grid = !le_show_grid;
899 case SDL_KEYUP: /* key released */
900 switch(event.key.keysym.sym)
909 case SDL_MOUSEBUTTONDOWN:
910 if(event.button.button == SDL_BUTTON_LEFT)
912 le_mouse_pressed[LEFT] = true;
914 selection.x1 = event.motion.x + pos_x;
915 selection.y1 = event.motion.y;
916 selection.x2 = event.motion.x + pos_x;
917 selection.y2 = event.motion.y;
919 else if(event.button.button == SDL_BUTTON_RIGHT)
921 le_mouse_pressed[RIGHT] = true;
924 case SDL_MOUSEBUTTONUP:
925 if(event.button.button == SDL_BUTTON_LEFT)
926 le_mouse_pressed[LEFT] = false;
927 else if(event.button.button == SDL_BUTTON_RIGHT)
928 le_mouse_pressed[RIGHT] = false;
930 case SDL_MOUSEMOTION:
937 cursor_x = ((int)(pos_x + x) / 32) * 32;
938 cursor_y = ((int) y / 32) * 32;
940 if(le_mouse_pressed[LEFT])
942 selection.x2 = x + pos_x;
946 if(le_mouse_pressed[RIGHT])
948 pos_x += -1 * event.motion.xrel;
952 case SDL_QUIT: // window closed
961 if(le_current_level != NULL)
963 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 &&
964 event.motion.y > 0 && event.motion.y < screen->h)))
966 le_mouse_pressed[LEFT] = false;
967 le_mouse_pressed[RIGHT] = false;
971 /* Check for button events */
972 le_test_level_bt->event(event);
973 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
975 le_save_level_bt->event(event);
976 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
977 le_current_level->save(le_level_subset->name.c_str(),le_level);
978 le_exit_bt->event(event);
979 if(le_exit_bt->get_state() == BUTTON_CLICKED)
981 Menu::set_current(leveleditor_menu);
983 le_next_level_bt->event(event);
984 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
986 if(le_level < le_level_subset->levels)
988 le_goto_level(++le_level);
994 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
995 if(confirm_dialog(str))
997 new_lev.init_defaults();
998 new_lev.save(le_level_subset->name.c_str(),++le_level);
999 le_level_subset->levels = le_level;
1000 le_goto_level(le_level);
1004 le_previous_level_bt->event(event);
1005 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1008 le_goto_level(--le_level);
1010 le_rubber_bt->event(event);
1011 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1012 le_current_tile = 0;
1013 le_select_mode_one_bt->event(event);
1014 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1015 le_selection_mode = CURSOR;
1016 le_select_mode_two_bt->event(event);
1017 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1018 le_selection_mode = SQUARE;
1020 le_tilegroup_bt->event(event);
1021 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1023 Menu::set_current(select_tilegroup_menu);
1024 select_tilegroup_menu_effect.start(200);
1025 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1028 le_settings_bt->event(event);
1029 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1031 update_level_settings_menu();
1032 Menu::set_current(level_settings_menu);
1034 if(!cur_tilegroup.empty())
1035 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1037 if(pbutton->get_state() == BUTTON_CLICKED)
1039 le_current_tile = pbutton->get_tag();
1042 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1044 if(pbutton->get_state() == BUTTON_CLICKED)
1046 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1052 le_settings_bt->event(event);
1053 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1055 Menu::set_current(0);
1057 le_tilegroup_bt->event(event);
1058 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1060 Menu::set_current(0);
1065 if(!Menu::current())
1067 le_move_left_bt->event(event);
1068 le_move_right_bt->event(event);
1070 if(le_mouse_pressed[LEFT])
1072 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1077 if(!Menu::current())
1079 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1083 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1088 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1092 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1100 void le_highlight_selection()
1104 if(selection.x1 < selection.x2)
1114 if(selection.y1 < selection.y2)
1130 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1133 void le_change(float x, float y, int tm, unsigned int c)
1135 if(le_current_level != NULL)
1141 /* level_changed = true; */
1143 switch(le_selection_mode)
1146 le_current_level->change(x,y,tm,c);
1151 /* if there is a bad guy over there, remove it */
1152 for(i = 0; i < le_world.bad_guys.size(); ++i)
1153 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1154 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1156 if(c == '0') /* if it's a bad guy */
1157 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1159 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1161 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1165 if(selection.x1 < selection.x2)
1175 if(selection.y1 < selection.y2)
1191 /* if there is a bad guy over there, remove it */
1192 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1193 i != le_world.bad_guys.end(); /* will be at end of loop */) {
1194 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1195 && i->base.y/32 >= y1 && i->base.y/32 <= y2) {
1196 i = le_world.bad_guys.erase(i);
1203 for(xx = x1; xx <= x2; xx++)
1204 for(yy = y1; yy <= y2; yy++)
1206 le_current_level->change(xx*32, yy*32, tm, c);
1208 if(c == '0') // if it's a bad guy
1209 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1211 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1213 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1224 le_current_level->save("test", le_level);
1226 GameSession session("test",le_level, ST_GL_TEST);
1229 music_manager->halt_music();
1231 Menu::set_current(leveleditor_menu);
1232 le_world.arrays_free();
1233 le_current_level->load_gfx();
1234 le_world.activate_bad_guys();
1240 unsigned int i, done_;
1242 " - This is SuperTux's built-in level editor -",
1243 "It has been designed to be light and easy to use from the start.",
1245 "When you first load the level editor you are given a menu where you",
1246 "can load level subsets, create a new level subset, edit the current",
1247 "subset's settings, or simply quit the editor. You can access this menu",
1248 "from the level editor at any time by pressing the escape key.",
1250 "To your right is your button bar. The center of this contains many",
1251 "tiles you can use to make your level. To select a tile, click on it",
1252 "with your left mouse button; your selection will be shown in the",
1253 "bottom right corner of the button box. Click anywhere on your level",
1254 "with the left mouse button to place that tile down. If you right click",
1255 "a tile in the button bar, you can find out what its keyboard shortcut",
1256 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1257 "background, and enemy tiles. The eraser lets you remove tiles.",
1258 "The left and right arrow keys scroll back and forth through your level.",
1259 "The button with the wrench and screwdriver, lets you change the",
1260 "settings of your level, including how long it is or what music it will",
1261 "play. When you are ready to give your level a test, click on the little",
1262 "running Tux. If you like the changes you have made to your level,",
1263 "press the red save key to keep them.",
1264 "To change which level in your subset you are editing, press the white",
1265 "up and down arrow keys at the top of the button box.",
1267 "Have fun making levels! If you make some good ones, send them to us on",
1268 "the SuperTux mailing list!",
1273 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1275 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1276 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1278 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1286 done_ = wait_for_event(event);