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 static std::map<std::string, ButtonPanel* > tilegroups_map;
144 static std::string cur_tilegroup;
146 static square selection;
147 static int le_selection_mode;
148 static SDL_Event event;
149 TileMapType active_tm;
151 // menu items for subset creation menu
156 void le_set_defaults()
158 if(le_current_level != NULL)
162 if(le_current_level->time_left == 0)
163 le_current_level->time_left = 255;
167 int leveleditor(int levelnb)
169 int last_time, now_time, i;
177 clearscreen(0, 0, 0);
180 music_manager->halt_music();
182 while (SDL_PollEvent(&event))
187 last_time = SDL_GetTicks();
192 if(Menu::current() == select_tilegroup_menu)
194 if(select_tilegroup_menu_effect.check())
196 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
200 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
203 if(le_current_level != NULL)
205 /* making events results to be in order */
208 if(pos_x > (le_current_level->width * 32) - screen->w)
209 pos_x = (le_current_level->width * 32) - screen->w;
215 clearscreen(0, 0, 0);
217 /* draw editor interface */
220 Menu* menu = Menu::current();
226 if(menu == leveleditor_menu)
228 switch (leveleditor_menu->check())
230 case MNID_RETURNLEVELEDITOR:
231 Menu::set_current(0);
233 case MNID_SUBSETSETTINGS:
234 update_subset_settings_menu();
236 case MNID_QUITLEVELEDITOR:
241 else if(menu == level_settings_menu)
243 switch (level_settings_menu->check())
245 case MNID_SUBSETSETTINGS:
246 apply_level_settings_menu();
247 Menu::set_current(leveleditor_menu);
255 else if(menu == select_tilegroup_menu)
258 switch (it = select_tilegroup_menu->check())
263 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
264 cur_tilegroup = select_tilegroup_menu->item[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 le_current_level = new Level;
285 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
291 le_current_level->load_gfx();
292 le_world.activate_bad_guys();
295 Menu::set_current(leveleditor_menu);
300 else if(menu == subset_new_menu)
302 if(subset_new_menu->item[2].input[0] == '\0')
303 subset_new_menu->item[3].kind = MN_DEACTIVE;
306 subset_new_menu->item[3].kind = MN_ACTION;
308 switch (i = subset_new_menu->check())
310 case MNID_CREATESUBSET:
311 LevelSubset::create(subset_new_menu->item[2].input);
312 le_level_subset.load(subset_new_menu->item[2].input);
313 leveleditor_menu->item[3].kind = MN_GOTO;
315 le_world.arrays_free();
316 le_current_level = new Level;
317 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
323 le_current_level->load_gfx();
324 le_world.activate_bad_guys();
325 subset_new_menu->item[2].change_input("");
326 // FIXME:? show_menu = true;
327 Menu::set_current(leveleditor_menu);
332 else if(menu == subset_settings_menu)
334 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 )
335 subset_settings_menu->item[5].kind = MN_DEACTIVE;
337 subset_settings_menu->item[5].kind = MN_ACTION;
339 switch (i = subset_settings_menu->check())
342 save_subset_settings_menu();
343 //FIXME:show_menu = true;
344 Menu::set_current(leveleditor_menu);
350 mouse_cursor->draw();
358 ++global_frame_counter;
361 now_time = SDL_GetTicks();
362 if (now_time < last_time + FPS)
363 SDL_Delay(last_time + FPS - now_time); /* delay some time */
374 level_subsets = dsubdirs("/levels", "info");
380 /* level_changed = NO;*/
383 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
384 le_level_changed = false;
385 le_current_level = NULL;
388 le_mouse_pressed[LEFT] = false;
389 le_mouse_pressed[RIGHT] = false;
391 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
393 select_tilegroup_menu_effect.init(false);
396 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
397 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
398 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
399 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
400 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
401 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
402 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
403 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
404 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
405 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
406 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
407 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
409 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
410 le_tilemap_panel->set_button_size(32,10);
411 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
412 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
413 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
415 leveleditor_menu = new Menu();
416 subset_load_menu = new Menu();
417 subset_new_menu = new Menu();
418 subset_settings_menu = new Menu();
419 level_settings_menu = new Menu();
420 select_tilegroup_menu = new Menu();
422 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
423 leveleditor_menu->additem(MN_HL,"",0,0);
424 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
425 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
426 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
427 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
428 leveleditor_menu->additem(MN_HL,"",0,0);
429 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
431 Menu::set_current(leveleditor_menu);
433 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
434 subset_load_menu->additem(MN_HL, "", 0, 0);
436 for(i = 0; i < level_subsets.num_items; ++i)
438 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
440 subset_load_menu->additem(MN_HL,"",0,0);
441 subset_load_menu->additem(MN_BACK,"Back",0,0);
443 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
444 subset_new_menu->additem(MN_HL,"",0,0);
445 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
446 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
447 subset_new_menu->additem(MN_HL,"",0,0);
448 subset_new_menu->additem(MN_BACK,"Back",0,0);
450 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
451 subset_settings_menu->additem(MN_HL,"",0,0);
452 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
453 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
454 subset_settings_menu->additem(MN_HL,"",0,0);
455 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
456 subset_settings_menu->additem(MN_HL,"",0,0);
457 subset_settings_menu->additem(MN_BACK,"Back",0,0);
459 level_settings_menu->arrange_left = true;
460 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
461 level_settings_menu->additem(MN_HL,"",0,0);
462 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
463 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
464 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
465 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
466 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
467 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
468 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
469 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
470 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
471 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
472 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
473 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
474 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
475 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
476 level_settings_menu->additem(MN_HL,"",0,0);
477 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
479 select_tilegroup_menu->arrange_left = true;
480 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
481 select_tilegroup_menu->additem(MN_HL,"",0,0);
482 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
483 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
486 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
487 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
489 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
490 tilegroups_map[(*it).name]->additem(new Button(const_cast<char*>(("images/tilesets/" + TileManager::instance()->get(*sit)->filenames[0]).c_str()), const_cast<char*>((*it).name.c_str()),(SDLKey)(i+'a'),0,0,32,32),(*sit));
492 select_tilegroup_menu->additem(MN_HL,"",0,0);
494 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
499 void update_level_settings_menu()
504 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
505 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
506 sprintf(str,"%d",le_current_level->width);
508 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
509 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
510 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
511 string_list_add_item(level_settings_menu->item[6].list,"");
512 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
513 level_settings_menu->item[3].list->active_item = i;
514 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
515 level_settings_menu->item[4].list->active_item = i;
516 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
517 level_settings_menu->item[5].list->active_item = i;
519 level_settings_menu->item[7].change_input(str);
520 sprintf(str,"%d",le_current_level->time_left);
521 level_settings_menu->item[8].change_input(str);
522 sprintf(str,"%2.0f",le_current_level->gravity);
523 level_settings_menu->item[9].change_input(str);
524 sprintf(str,"%d",le_current_level->bkgd_top.red);
525 level_settings_menu->item[10].change_input(str);
526 sprintf(str,"%d",le_current_level->bkgd_top.green);
527 level_settings_menu->item[11].change_input(str);
528 sprintf(str,"%d",le_current_level->bkgd_top.blue);
529 level_settings_menu->item[12].change_input(str);
530 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
531 level_settings_menu->item[13].change_input(str);
532 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
533 level_settings_menu->item[14].change_input(str);
534 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
535 level_settings_menu->item[15].change_input(str);
538 void update_subset_settings_menu()
540 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
541 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
544 void apply_level_settings_menu()
549 le_current_level->name = level_settings_menu->item[2].input;
550 le_current_level->author = level_settings_menu->item[3].input;
552 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
554 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
558 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
560 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
566 le_current_level->free_gfx();
567 le_current_level->load_gfx();
570 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
572 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
573 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
574 le_current_level->gravity = atof(level_settings_menu->item[9].input);
575 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
576 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
577 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
578 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
579 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
580 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
583 void save_subset_settings_menu()
585 le_level_subset.title = subset_settings_menu->item[2].input;
586 le_level_subset.description = subset_settings_menu->item[3].input;
587 le_level_subset.save();
590 void le_goto_level(int levelnb)
592 le_world.arrays_free();
594 le_current_level->cleanup();
595 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
597 le_current_level->load(le_level_subset.name.c_str(), le_level);
606 le_current_level->free_gfx();
607 le_current_level->load_gfx();
609 le_world.activate_bad_guys();
614 /*if(level_changed == true)
615 if(askforsaving() == CANCEL)
618 SDL_EnableKeyRepeat(0, 0); // disables key repeating
621 delete leveleditor_menu;
622 delete subset_load_menu;
623 delete subset_new_menu;
624 delete subset_settings_menu;
625 delete level_settings_menu;
626 delete select_tilegroup_menu;
627 delete le_save_level_bt;
629 delete le_test_level_bt;
630 delete le_next_level_bt;
631 delete le_previous_level_bt;
632 delete le_move_right_bt;
633 delete le_move_left_bt;
635 delete le_select_mode_one_bt;
636 delete le_select_mode_two_bt;
637 delete le_settings_bt;
638 delete le_tilegroup_bt;
639 delete le_tilemap_panel;
641 if(le_current_level != NULL)
643 le_current_level->free_gfx();
644 le_current_level->cleanup();
645 le_world.arrays_free();
649 void le_drawinterface()
654 if(le_current_level != NULL)
656 /* draw a grid (if selected) */
659 for(x = 0; x < 19; x++)
660 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
661 for(y = 0; y < 15; y++)
662 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
666 if(le_selection_mode == CURSOR)
667 le_selection->draw( cursor_x - pos_x, cursor_y);
668 else if(le_selection_mode == SQUARE)
671 le_highlight_selection();
672 /* draw current selection */
673 w = selection.x2 - selection.x1;
674 h = selection.y2 - selection.y1;
675 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
676 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
677 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
678 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
682 /* draw button bar */
683 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
684 Tile::draw(19 * 32, 14 * 32, le_current_tile);
686 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
687 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
689 if(le_current_level != NULL)
691 le_save_level_bt->draw();
693 le_test_level_bt->draw();
694 le_next_level_bt->draw();
695 le_previous_level_bt->draw();
696 le_rubber_bt->draw();
697 le_select_mode_one_bt->draw();
698 le_select_mode_two_bt->draw();
699 le_settings_bt->draw();
700 le_move_right_bt->draw();
701 le_move_left_bt->draw();
702 le_tilegroup_bt->draw();
703 if(!cur_tilegroup.empty())
704 tilegroups_map[cur_tilegroup]->draw();
705 le_tilemap_panel->draw();
707 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
708 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
710 white_small_text->draw("F1 for Help", 10, 430, 1);
715 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
717 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
724 unsigned int y,x,i,s;
727 /* Draw the real background */
728 if(le_current_level->bkgd_image[0] != '\0')
731 le_current_level->img_bkgd->draw_part(s,0,0,0,
732 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
733 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
734 le_current_level->img_bkgd->h);
738 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
741 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
743 for (y = 0; y < 15; ++y)
744 for (x = 0; x < 20; ++x)
747 if(active_tm == TM_BG)
752 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
754 if(active_tm == TM_IA)
759 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
761 if(active_tm == TM_FG)
766 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
768 /* draw whats inside stuff when cursor is selecting those */
769 /* (draw them all the time - is this the right behaviour?) */
770 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
771 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);
775 /* Draw the Bad guys: */
776 for (i = 0; i < le_world.bad_guys.size(); ++i)
778 /* to support frames: img_bsod_left[(frame / 5) % 4] */
781 le_world.bad_guys[i].draw();
785 /* Draw the player: */
786 /* for now, the position is fixed at (100, 240) */
787 largetux.walk_right->draw( 100 - pos_x, 240);
790 void le_checkevents()
797 keymod = SDL_GetModState();
799 while(SDL_PollEvent(&event))
803 Menu::current()->event(event);
807 mouse_cursor->set_state(MC_NORMAL);
809 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
810 if(event.type == SDL_KEYDOWN
811 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
812 && (event.motion.x > 0
813 && event.motion.x < screen->w - 64 &&
814 event.motion.y > 0 && event.motion.y < screen->h)))
818 case SDL_KEYDOWN: // key pressed
819 key = event.key.keysym.sym;
823 Menu::set_current(leveleditor_menu);
826 cursor_x -= KEY_CURSOR_SPEED;
828 cursor_x -= KEY_CURSOR_FASTSPEED;
830 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
831 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
836 cursor_x += KEY_CURSOR_SPEED;
838 cursor_x += KEY_CURSOR_FASTSPEED;
840 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
841 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
846 cursor_y -= KEY_CURSOR_SPEED;
848 cursor_y -= KEY_CURSOR_FASTSPEED;
855 cursor_y += KEY_CURSOR_SPEED;
857 cursor_y += KEY_CURSOR_FASTSPEED;
859 if(cursor_y > screen->h-32)
860 cursor_y = screen->h-32;
873 cursor_x = (le_current_level->width * 32) - 32;
877 le_show_grid = !le_show_grid;
883 case SDL_KEYUP: /* key released */
884 switch(event.key.keysym.sym)
893 case SDL_MOUSEBUTTONDOWN:
894 if(event.button.button == SDL_BUTTON_LEFT)
896 le_mouse_pressed[LEFT] = true;
898 selection.x1 = event.motion.x + pos_x;
899 selection.y1 = event.motion.y;
900 selection.x2 = event.motion.x + pos_x;
901 selection.y2 = event.motion.y;
903 else if(event.button.button == SDL_BUTTON_RIGHT)
905 le_mouse_pressed[RIGHT] = true;
908 case SDL_MOUSEBUTTONUP:
909 if(event.button.button == SDL_BUTTON_LEFT)
910 le_mouse_pressed[LEFT] = false;
911 else if(event.button.button == SDL_BUTTON_RIGHT)
912 le_mouse_pressed[RIGHT] = false;
914 case SDL_MOUSEMOTION:
921 cursor_x = ((int)(pos_x + x) / 32) * 32;
922 cursor_y = ((int) y / 32) * 32;
924 if(le_mouse_pressed[LEFT])
926 selection.x2 = x + pos_x;
930 if(le_mouse_pressed[RIGHT])
932 pos_x += -1 * event.motion.xrel;
936 case SDL_QUIT: // window closed
945 if(le_current_level != NULL)
947 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 &&
948 event.motion.y > 0 && event.motion.y < screen->h)))
950 le_mouse_pressed[LEFT] = false;
951 le_mouse_pressed[RIGHT] = false;
955 /* Check for button events */
956 le_test_level_bt->event(event);
957 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
959 le_save_level_bt->event(event);
960 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
961 le_current_level->save(le_level_subset.name.c_str(),le_level);
962 le_exit_bt->event(event);
963 if(le_exit_bt->get_state() == BUTTON_CLICKED)
965 Menu::set_current(leveleditor_menu);
967 le_next_level_bt->event(event);
968 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
970 if(le_level < le_level_subset.levels)
972 le_goto_level(++le_level);
978 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
979 if(confirm_dialog(str))
981 new_lev.init_defaults();
982 new_lev.save(le_level_subset.name.c_str(),++le_level);
983 le_level_subset.levels = le_level;
984 le_goto_level(le_level);
988 le_previous_level_bt->event(event);
989 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
992 le_goto_level(--le_level);
994 le_rubber_bt->event(event);
995 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
997 le_select_mode_one_bt->event(event);
998 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
999 le_selection_mode = CURSOR;
1000 le_select_mode_two_bt->event(event);
1001 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1002 le_selection_mode = SQUARE;
1004 le_tilegroup_bt->event(event);
1005 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1007 Menu::set_current(select_tilegroup_menu);
1008 select_tilegroup_menu_effect.start(200);
1009 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1012 le_settings_bt->event(event);
1013 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1015 update_level_settings_menu();
1016 Menu::set_current(level_settings_menu);
1018 if(!cur_tilegroup.empty())
1019 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1021 if(pbutton->get_state() == BUTTON_CLICKED)
1023 le_current_tile = pbutton->get_tag();
1026 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1028 if(pbutton->get_state() == BUTTON_CLICKED)
1030 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1036 le_settings_bt->event(event);
1037 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1039 Menu::set_current(0);
1041 le_tilegroup_bt->event(event);
1042 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1044 Menu::set_current(0);
1049 if(!Menu::current())
1051 le_move_left_bt->event(event);
1052 le_move_right_bt->event(event);
1054 if(le_mouse_pressed[LEFT])
1056 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1061 if(!Menu::current())
1063 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1067 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1072 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1076 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1084 void le_highlight_selection()
1088 if(selection.x1 < selection.x2)
1098 if(selection.y1 < selection.y2)
1114 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1117 void le_change(float x, float y, int tm, unsigned int c)
1119 if(le_current_level != NULL)
1125 /* level_changed = true; */
1127 switch(le_selection_mode)
1130 le_current_level->change(x,y,tm,c);
1135 /* if there is a bad guy over there, remove it */
1136 for(i = 0; i < le_world.bad_guys.size(); ++i)
1137 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1138 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1140 if(c == '0') /* if it's a bad guy */
1141 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1143 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1145 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1149 if(selection.x1 < selection.x2)
1159 if(selection.y1 < selection.y2)
1175 /* if there is a bad guy over there, remove it */
1176 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1177 i != le_world.bad_guys.end(); /* will be at end of loop */) {
1178 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1179 && i->base.y/32 >= y1 && i->base.y/32 <= y2) {
1180 i = le_world.bad_guys.erase(i);
1187 for(xx = x1; xx <= x2; xx++)
1188 for(yy = y1; yy <= y2; yy++)
1190 le_current_level->change(xx*32, yy*32, tm, c);
1192 if(c == '0') // if it's a bad guy
1193 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1195 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1197 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1208 le_current_level->save("test", le_level);
1210 GameSession session("test",le_level, ST_GL_TEST);
1213 music_manager->halt_music();
1215 Menu::set_current(leveleditor_menu);
1216 le_world.arrays_free();
1217 le_current_level->load_gfx();
1218 le_world.activate_bad_guys();
1224 unsigned int i, done_;
1226 " - This is SuperTux's built-in level editor -",
1227 "It has been designed to be light and easy to use from the start.",
1229 "When you first load the level editor you are given a menu where you",
1230 "can load level subsets, create a new level subset, edit the current",
1231 "subset's settings, or simply quit the editor. You can access this menu",
1232 "from the level editor at any time by pressing the escape key.",
1234 "To your right is your button bar. The center of this contains many",
1235 "tiles you can use to make your level. To select a tile, click on it",
1236 "with your left mouse button; your selection will be shown in the",
1237 "bottom right corner of the button box. Click anywhere on your level",
1238 "with the left mouse button to place that tile down. If you right click",
1239 "a tile in the button bar, you can find out what its keyboard shortcut",
1240 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1241 "background, and enemy tiles. The eraser lets you remove tiles.",
1242 "The left and right arrow keys scroll back and forth through your level.",
1243 "The button with the wrench and screwdriver, lets you change the",
1244 "settings of your level, including how long it is or what music it will",
1245 "play. When you are ready to give your level a test, click on the little",
1246 "running Tux. If you like the changes you have made to your level,",
1247 "press the red save key to keep them.",
1248 "To change which level in your subset you are editing, press the white",
1249 "up and down arrow keys at the top of the button box.",
1251 "Have fun making levels! If you make some good ones, send them to us on",
1252 "the SuperTux mailing list!",
1257 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1259 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1260 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1262 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1270 done_ = wait_for_event(event);