1 /***************************************************************************
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
8 ***************************************************************************/
10 /* December 28, 2003 - March 15, 2004 */
12 /* leveleditor.c - A built-in level editor for SuperTux
13 Ricardo Cruz <rick2@aeiou.pt>
14 Tobias Glaesser <tobi.web@gmx.de> */
24 #include <SDL_image.h>
25 #include "leveleditor.h"
38 /* definitions to aid development */
39 #define DONE_LEVELEDITOR 1
41 #define DONE_CHANGELEVEL 3
43 /* definitions that affect gameplay */
44 #define KEY_CURSOR_SPEED 32
45 #define KEY_CURSOR_FASTSPEED 64
47 /* when pagedown/up pressed speed:*/
48 #define PAGE_CURSOR_SPEED 13*32
50 #define MOUSE_LEFT_MARGIN 80
51 #define MOUSE_RIGHT_MARGIN (560-32)
52 /* right_margin should noticed that the cursor is 32 pixels,
53 so it should subtract that value */
54 #define MOUSE_POS_SPEED 20
57 #define SELECT_W 2 // size of the selections lines
58 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
60 /* gameloop funcs declerations */
62 void loadshared(void);
63 void unloadshared(void);
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 /* leveleditor internals */
85 static string_list_type level_subsets;
86 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
87 static int pos_x, cursor_x, cursor_y, fire;
89 static st_level* le_current_level;
90 static st_subset le_level_subset;
91 static int le_show_grid;
93 static texture_type le_selection;
95 static unsigned int le_current_tile;
96 static bool le_mouse_pressed[2];
97 static Button* le_save_level_bt;
98 static Button* le_exit_bt;
99 static Button* le_test_level_bt;
100 static Button* le_next_level_bt;
101 static Button* le_previous_level_bt;
102 static Button* le_move_right_bt;
103 static Button* le_move_left_bt;
104 static Button* le_rubber_bt;
105 static Button* le_select_mode_one_bt;
106 static Button* le_select_mode_two_bt;
107 static Button* le_settings_bt;
108 static Button* le_tilegroup_bt;
109 static ButtonPanel* le_tilemap_panel;
110 static Menu* leveleditor_menu;
111 static Menu* subset_load_menu;
112 static Menu* subset_new_menu;
113 static Menu* subset_settings_menu;
114 static Menu* level_settings_menu;
115 static Menu* select_tilegroup_menu;
116 static timer_type select_tilegroup_menu_effect;
117 static std::map<std::string, ButtonPanel* > tilegroups_map;
118 static std::string cur_tilegroup;
120 static square selection;
121 static int le_selection_mode;
122 static SDL_Event event;
123 TileMapType active_tm;
125 void le_set_defaults()
127 if(le_current_level != NULL)
131 if(le_current_level->time_left == 0)
132 le_current_level->time_left = 255;
136 int leveleditor(int levelnb)
138 int last_time, now_time, i;
146 clearscreen(0, 0, 0);
149 while (SDL_PollEvent(&event))
154 last_time = SDL_GetTicks();
159 if(current_menu == select_tilegroup_menu)
161 if(timer_check(&select_tilegroup_menu_effect))
163 select_tilegroup_menu->set_pos(screen->w - 64 + timer_get_left(&select_tilegroup_menu_effect),82,-0.5,0.5);
166 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
169 if(le_current_level != NULL)
171 /* making events results to be in order */
174 if(pos_x > (le_current_level->width * 32) - screen->w)
175 pos_x = (le_current_level->width * 32) - screen->w;
181 clearscreen(0, 0, 0);
183 /* draw editor interface */
188 menu_process_current();
189 if(current_menu == leveleditor_menu)
191 switch (leveleditor_menu->check())
197 update_subset_settings_menu();
200 done = DONE_LEVELEDITOR;
204 else if(current_menu == level_settings_menu)
206 switch (level_settings_menu->check())
209 apply_level_settings_menu();
210 Menu::set_current(leveleditor_menu);
217 else if(current_menu == select_tilegroup_menu)
220 switch (it = select_tilegroup_menu->check())
225 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
226 cur_tilegroup = select_tilegroup_menu->item[it].text;
233 else if(current_menu == subset_load_menu)
235 switch (i = subset_load_menu->check())
242 le_level_subset.load(level_subsets.item[i-2]);
243 leveleditor_menu->item[3].kind = MN_GOTO;
247 le_current_level = new st_level;
248 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
254 level_load_gfx(le_current_level);
255 activate_bad_guys(le_current_level);
261 else if(current_menu == subset_new_menu)
263 if(subset_new_menu->item[2].input[0] == '\0')
264 subset_new_menu->item[3].kind = MN_DEACTIVE;
267 subset_new_menu->item[3].kind = MN_ACTION;
269 switch (i = subset_new_menu->check())
272 st_subset::create(subset_new_menu->item[2].input);
273 le_level_subset.load(subset_new_menu->item[2].input);
274 leveleditor_menu->item[3].kind = MN_GOTO;
278 le_current_level = new st_level;
279 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
285 level_load_gfx(le_current_level);
286 activate_bad_guys(le_current_level);
287 menu_item_change_input(&subset_new_menu->item[2],"");
293 else if(current_menu == subset_settings_menu)
295 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 )
296 subset_settings_menu->item[5].kind = MN_DEACTIVE;
298 subset_settings_menu->item[5].kind = MN_ACTION;
300 switch (i = subset_settings_menu->check())
303 save_subset_settings_menu();
310 mouse_cursor->draw();
318 if(done == DONE_QUIT)
324 ++global_frame_counter;
327 now_time = SDL_GetTicks();
328 if (now_time < last_time + FPS)
329 SDL_Delay(last_time + FPS - now_time); /* delay some time */
340 level_subsets = dsubdirs("/levels", "info");
346 /* level_changed = NO;*/
349 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
350 le_level_changed = false;
351 le_current_level = NULL;
354 le_mouse_pressed[LEFT] = false;
355 le_mouse_pressed[RIGHT] = false;
357 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
359 timer_init(&select_tilegroup_menu_effect,false);
362 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
363 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
364 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
365 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
366 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
367 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
368 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
369 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
370 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
371 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
372 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
373 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
375 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
376 le_tilemap_panel->set_button_size(32,10);
377 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
378 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
379 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
381 leveleditor_menu = new Menu();
382 subset_load_menu = new Menu();
383 subset_new_menu = new Menu();
384 subset_settings_menu = new Menu();
385 level_settings_menu = new Menu();
386 select_tilegroup_menu = new Menu();
388 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
389 leveleditor_menu->additem(MN_HL,"",0,0);
390 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
391 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
392 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
393 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
394 leveleditor_menu->additem(MN_HL,"",0,0);
395 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
398 Menu::set_current(leveleditor_menu);
401 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
402 subset_load_menu->additem(MN_HL, "", 0, 0);
404 for(i = 0; i < level_subsets.num_items; ++i)
406 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
408 subset_load_menu->additem(MN_HL,"",0,0);
409 subset_load_menu->additem(MN_BACK,"Back",0,0);
411 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
412 subset_new_menu->additem(MN_HL,"",0,0);
413 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
414 subset_new_menu->additem(MN_ACTION,"Create",0,0);
415 subset_new_menu->additem(MN_HL,"",0,0);
416 subset_new_menu->additem(MN_BACK,"Back",0,0);
418 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
419 subset_settings_menu->additem(MN_HL,"",0,0);
420 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
421 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
422 subset_settings_menu->additem(MN_HL,"",0,0);
423 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
424 subset_settings_menu->additem(MN_HL,"",0,0);
425 subset_settings_menu->additem(MN_BACK,"Back",0,0);
427 level_settings_menu->arrange_left = true;
428 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
429 level_settings_menu->additem(MN_HL,"",0,0);
430 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
431 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
432 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
433 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
434 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
435 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
436 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
437 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
438 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
439 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
440 level_settings_menu->additem(MN_HL,"",0,0);
441 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
443 select_tilegroup_menu->arrange_left = true;
444 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
445 select_tilegroup_menu->additem(MN_HL,"",0,0);
446 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
447 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
450 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
451 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
453 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
454 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));
456 select_tilegroup_menu->additem(MN_HL,"",0,0);
458 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
463 void update_level_settings_menu()
468 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
469 sprintf(str,"%d",le_current_level->width);
471 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
472 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
473 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
474 string_list_add_item(level_settings_menu->item[5].list,"");
475 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
476 level_settings_menu->item[3].list->active_item = i;
477 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
478 level_settings_menu->item[4].list->active_item = i;
479 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
480 level_settings_menu->item[5].list->active_item = i;
482 menu_item_change_input(&level_settings_menu->item[6], str);
483 sprintf(str,"%d",le_current_level->time_left);
484 menu_item_change_input(&level_settings_menu->item[7], str);
485 sprintf(str,"%2.0f",le_current_level->gravity);
486 menu_item_change_input(&level_settings_menu->item[8], str);
487 sprintf(str,"%d",le_current_level->bkgd_red);
488 menu_item_change_input(&level_settings_menu->item[9], str);
489 sprintf(str,"%d",le_current_level->bkgd_green);
490 menu_item_change_input(&level_settings_menu->item[10], str);
491 sprintf(str,"%d",le_current_level->bkgd_blue);
492 menu_item_change_input(&level_settings_menu->item[11], str);
495 void update_subset_settings_menu()
497 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
498 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
501 void apply_level_settings_menu()
506 le_current_level->name = level_settings_menu->item[2].input;
508 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
510 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
514 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
516 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
523 level_load_gfx(le_current_level);
526 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
528 level_change_size(le_current_level, atoi(level_settings_menu->item[6].input));
529 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
530 le_current_level->gravity = atof(level_settings_menu->item[8].input);
531 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
532 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
533 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
536 void save_subset_settings_menu()
538 le_level_subset.title = subset_settings_menu->item[2].input;
539 le_level_subset.description = subset_settings_menu->item[3].input;
540 le_level_subset.save();
543 void le_goto_level(int levelnb)
547 level_free(le_current_level);
548 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
550 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
561 level_load_gfx(le_current_level);
562 activate_bad_guys(le_current_level);
567 /*if(level_changed == true)
568 if(askforsaving() == CANCEL)
571 SDL_EnableKeyRepeat(0, 0); // disables key repeating
573 texture_free(&le_selection);
574 delete leveleditor_menu;
575 delete subset_load_menu;
576 delete subset_new_menu;
577 delete subset_settings_menu;
578 delete level_settings_menu;
579 delete select_tilegroup_menu;
580 delete le_save_level_bt;
582 delete le_test_level_bt;
583 delete le_next_level_bt;
584 delete le_previous_level_bt;
585 delete le_move_right_bt;
586 delete le_move_left_bt;
588 delete le_select_mode_one_bt;
589 delete le_select_mode_two_bt;
590 delete le_settings_bt;
591 delete le_tilegroup_bt;
592 delete le_tilemap_panel;
594 if(le_current_level != NULL)
597 level_free(le_current_level);
603 void le_drawinterface()
608 if(le_current_level != NULL)
610 /* draw a grid (if selected) */
613 for(x = 0; x < 19; x++)
614 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
615 for(y = 0; y < 15; y++)
616 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
620 if(le_selection_mode == CURSOR)
621 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
622 else if(le_selection_mode == SQUARE)
625 le_highlight_selection();
626 /* draw current selection */
627 w = selection.x2 - selection.x1;
628 h = selection.y2 - selection.y1;
629 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
630 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
631 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
632 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
636 /* draw button bar */
637 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
638 drawshape(19 * 32, 14 * 32, le_current_tile);
640 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
641 texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
643 if(le_current_level != NULL)
645 le_save_level_bt->draw();
647 le_test_level_bt->draw();
648 le_next_level_bt->draw();
649 le_previous_level_bt->draw();
650 le_rubber_bt->draw();
651 le_select_mode_one_bt->draw();
652 le_select_mode_two_bt->draw();
653 le_settings_bt->draw();
654 le_move_right_bt->draw();
655 le_move_left_bt->draw();
656 le_tilegroup_bt->draw();
657 if(!cur_tilegroup.empty())
658 tilegroups_map[cur_tilegroup]->draw();
659 le_tilemap_panel->draw();
661 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
662 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
664 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
668 if(show_menu == false)
669 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
671 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
678 unsigned int y,x,i,s;
681 /* Draw the real background */
682 if(le_current_level->bkgd_image[0] != '\0')
685 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
686 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
690 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
693 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
695 for (y = 0; y < 15; ++y)
696 for (x = 0; x < 20; ++x)
699 if(active_tm == TM_BG)
704 drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
706 if(active_tm == TM_IA)
711 drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
713 if(active_tm == TM_FG)
718 drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
720 /* draw whats inside stuff when cursor is selecting those */
721 /* (draw them all the time - is this the right behaviour?) */
722 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
723 texture_draw(&TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images[0], x * 32 - ((int)pos_x % 32), y*32);
727 /* Draw the Bad guys: */
728 for (i = 0; i < bad_guys.size(); ++i)
730 /* to support frames: img_bsod_left[(frame / 5) % 4] */
737 /* Draw the player: */
738 /* for now, the position is fixed at (100, 240) */
739 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
742 void le_checkevents()
749 keymod = SDL_GetModState();
751 while(SDL_PollEvent(&event))
756 mouse_cursor->set_state(MC_NORMAL);
758 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
759 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
760 event.motion.y > 0 && event.motion.y < screen->h)))
764 case SDL_KEYDOWN: // key pressed
765 key = event.key.keysym.sym;
768 if(key == SDLK_ESCAPE)
771 Menu::set_current(leveleditor_menu);
785 cursor_x -= KEY_CURSOR_SPEED;
787 cursor_x -= KEY_CURSOR_FASTSPEED;
789 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
790 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
795 cursor_x += KEY_CURSOR_SPEED;
797 cursor_x += KEY_CURSOR_FASTSPEED;
799 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
800 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
805 cursor_y -= KEY_CURSOR_SPEED;
807 cursor_y -= KEY_CURSOR_FASTSPEED;
814 cursor_y += KEY_CURSOR_SPEED;
816 cursor_y += KEY_CURSOR_FASTSPEED;
818 if(cursor_y > screen->h-32)
819 cursor_y = screen->h-32;
832 cursor_x = (le_current_level->width * 32) - 32;
836 le_show_grid = !le_show_grid;
842 case SDL_KEYUP: /* key released */
843 switch(event.key.keysym.sym)
852 case SDL_MOUSEBUTTONDOWN:
853 if(event.button.button == SDL_BUTTON_LEFT)
855 le_mouse_pressed[LEFT] = true;
857 selection.x1 = event.motion.x + pos_x;
858 selection.y1 = event.motion.y;
859 selection.x2 = event.motion.x + pos_x;
860 selection.y2 = event.motion.y;
862 else if(event.button.button == SDL_BUTTON_RIGHT)
878 le_mouse_pressed[RIGHT] = true;
881 case SDL_MOUSEBUTTONUP:
882 if(event.button.button == SDL_BUTTON_LEFT)
883 le_mouse_pressed[LEFT] = false;
884 else if(event.button.button == SDL_BUTTON_RIGHT)
885 le_mouse_pressed[RIGHT] = false;
887 case SDL_MOUSEMOTION:
893 cursor_x = ((int)(pos_x + x) / 32) * 32;
894 cursor_y = ((int) y / 32) * 32;
896 if(le_mouse_pressed[LEFT])
898 selection.x2 = x + pos_x;
902 if(le_mouse_pressed[RIGHT])
904 pos_x += -1 * event.motion.xrel;
908 case SDL_QUIT: // window closed
916 if(le_current_level != NULL)
918 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 &&
919 event.motion.y > 0 && event.motion.y < screen->h)))
921 le_mouse_pressed[LEFT] = false;
922 le_mouse_pressed[RIGHT] = false;
924 if(show_menu == false)
926 /* Check for button events */
927 le_test_level_bt->event(event);
928 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
930 le_save_level_bt->event(event);
931 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
932 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
933 le_exit_bt->event(event);
934 if(le_exit_bt->get_state() == BUTTON_CLICKED)
936 Menu::set_current(leveleditor_menu);
939 le_next_level_bt->event(event);
940 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
942 if(le_level < le_level_subset.levels)
944 le_goto_level(++le_level);
951 sprintf(str,"Level %d doesn't exist.",le_level+1);
952 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
953 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
954 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
958 while(SDL_PollEvent(&event))
961 case SDL_KEYDOWN: // key pressed
962 switch(event.key.keysym.sym)
965 level_default(&new_lev);
966 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
967 le_level_subset.levels = le_level;
968 le_goto_level(le_level);
985 le_previous_level_bt->event(event);
986 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
989 le_goto_level(--le_level);
991 le_rubber_bt->event(event);
992 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
994 le_select_mode_one_bt->event(event);
995 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
996 le_selection_mode = CURSOR;
997 le_select_mode_two_bt->event(event);
998 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
999 le_selection_mode = SQUARE;
1001 le_tilegroup_bt->event(event);
1002 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1004 Menu::set_current(select_tilegroup_menu);
1005 timer_start(&select_tilegroup_menu_effect,200);
1006 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1010 le_settings_bt->event(event);
1011 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1013 update_level_settings_menu();
1014 Menu::set_current(level_settings_menu);
1017 if(!cur_tilegroup.empty())
1018 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1020 if(pbutton->get_state() == BUTTON_CLICKED)
1022 le_current_tile = pbutton->get_tag();
1025 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1027 if(pbutton->get_state() == BUTTON_CLICKED)
1029 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1035 le_settings_bt->event(event);
1036 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1038 Menu::set_current(leveleditor_menu);
1041 le_tilegroup_bt->event(event);
1042 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1044 Menu::set_current(leveleditor_menu);
1049 if(show_menu == false)
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(show_menu == false)
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 level_change(le_current_level,x,y,tm,c);
1135 /* if there is a bad guy over there, remove it */
1136 for(i = 0; i < bad_guys.size(); ++i)
1137 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1138 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1140 if(c == '0') /* if it's a bad guy */
1141 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1143 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1145 add_bad_guy(xx*32, yy*32, BAD_MONEY);
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(i = 0; i < bad_guys.size(); ++i)
1177 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1178 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1179 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1181 for(xx = x1; xx <= x2; xx++)
1182 for(yy = y1; yy <= y2; yy++)
1184 level_change(le_current_level, xx*32, yy*32, tm, c);
1186 if(c == '0') // if it's a bad guy
1187 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1189 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1191 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1202 level_save(le_current_level,"test",le_level);
1203 gameloop("test",le_level, ST_GL_TEST);
1204 Menu::set_current(leveleditor_menu);
1206 level_load_gfx(le_current_level);
1208 activate_bad_guys(le_current_level);
1214 unsigned int i, done;
1216 " - This is SuperTux's built-in level editor -",
1217 "It has been designed to be light and easy to use from the start.",
1219 "When you first load the level editor you are given a menu where you",
1220 "can load level subsets, create a new level subset, edit the current",
1221 "subset's settings, or simply quit the editor. You can access this menu",
1222 "from the level editor at any time by pressing the escape key.",
1224 "To your right is your button bar. The center of this contains many",
1225 "tiles you can use to make your level. To select a tile, click on it",
1226 "with your left mouse button; your selection will be shown in the",
1227 "bottom right corner of the button box. Click anywhere on your level",
1228 "with the left mouse button to place that tile down. If you right click",
1229 "a tile in the button bar, you can find out what its keyboard shortcut",
1230 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1231 "background, and enemy tiles. The eraser lets you remove tiles.",
1232 "The left and right arrow keys scroll back and forth through your level.",
1233 "The button with the wrench and screwdriver, lets you change the",
1234 "settings of your level, including how long it is or what music it will",
1235 "play. When you are ready to give your level a test, click on the little",
1236 "running Tux. If you like the changes you have made to your level,",
1237 "press the red save key to keep them.",
1238 "To change which level in your subset you are editing, press the white",
1239 "up and down arrow keys at the top of the button box.",
1241 "Have fun making levels! If you make some good ones, send them to us on",
1242 "the SuperTux mailing list!",
1247 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1249 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1250 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1252 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1260 while(SDL_PollEvent(&event))
1263 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1264 case SDL_KEYDOWN: // key pressed