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();
83 void le_update_buttons(const char*);
85 /* leveleditor internals */
86 static string_list_type level_subsets;
87 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
88 static int pos_x, cursor_x, cursor_y, fire;
90 static st_level* le_current_level;
91 static st_subset le_level_subset;
92 static int le_show_grid;
94 static texture_type le_selection;
96 static unsigned int le_current_tile;
97 static bool le_mouse_pressed[2];
98 static button_type le_save_level_bt;
99 static button_type le_test_level_bt;
100 static button_type le_next_level_bt;
101 static button_type le_previous_level_bt;
102 static button_type le_move_right_bt;
103 static button_type le_move_left_bt;
104 static button_type le_rubber_bt;
105 static button_type le_select_mode_one_bt;
106 static button_type le_select_mode_two_bt;
107 static button_type le_settings_bt;
108 static button_type le_tilegroup_bt;
109 static Menu* leveleditor_menu;
110 static Menu* subset_load_menu;
111 static Menu* subset_new_menu;
112 static Menu* subset_settings_menu;
113 static Menu* level_settings_menu;
114 static Menu* select_tilegroup_menu;
115 static timer_type select_tilegroup_menu_effect;
116 static std::map<std::string, button_panel_type > tilegroups_map;
117 static std::string cur_tilegroup;
119 static square selection;
120 static int le_selection_mode;
121 static SDL_Event event;
123 void le_set_defaults()
125 if(le_current_level != NULL)
129 if(le_current_level->time_left == 0)
130 le_current_level->time_left = 255;
134 int leveleditor(int levelnb)
136 int last_time, now_time, i;
144 clearscreen(0, 0, 0);
147 while (SDL_PollEvent(&event))
152 last_time = SDL_GetTicks();
157 if(current_menu == select_tilegroup_menu)
159 if(timer_check(&select_tilegroup_menu_effect))
161 select_tilegroup_menu->set_pos(screen->w - 64 + timer_get_left(&select_tilegroup_menu_effect),82,-0.5,0.5);
164 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
167 if(le_current_level != NULL)
169 /* making events results to be in order */
172 if(pos_x > (le_current_level->width * 32) - screen->w)
173 pos_x = (le_current_level->width * 32) - screen->w;
179 clearscreen(0, 0, 0);
181 /* draw editor interface */
186 menu_process_current();
187 if(current_menu == leveleditor_menu)
189 switch (leveleditor_menu->check())
195 update_subset_settings_menu();
198 done = DONE_LEVELEDITOR;
202 else if(current_menu == level_settings_menu)
204 switch (level_settings_menu->check())
207 apply_level_settings_menu();
208 Menu::set_current(leveleditor_menu);
215 else if(current_menu == select_tilegroup_menu)
218 switch (it = select_tilegroup_menu->check())
223 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
224 cur_tilegroup = select_tilegroup_menu->item[it].text;
231 else if(current_menu == subset_load_menu)
233 switch (i = subset_load_menu->check())
240 le_level_subset.load(level_subsets.item[i-2]);
241 leveleditor_menu->item[3].kind = MN_GOTO;
245 le_current_level = new st_level;
246 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
251 le_update_buttons(le_current_level->theme.c_str());
253 level_load_gfx(le_current_level);
259 else if(current_menu == subset_new_menu)
261 if(subset_new_menu->item[2].input[0] == '\0')
262 subset_new_menu->item[3].kind = MN_DEACTIVE;
265 subset_new_menu->item[3].kind = MN_ACTION;
267 switch (i = subset_new_menu->check())
270 st_subset::create(subset_new_menu->item[2].input);
271 le_level_subset.load(subset_new_menu->item[2].input);
272 leveleditor_menu->item[3].kind = MN_GOTO;
276 le_current_level = new st_level;
277 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
282 le_update_buttons(le_current_level->theme.c_str());
284 level_load_gfx(le_current_level);
285 menu_item_change_input(&subset_new_menu->item[2],"");
291 else if(current_menu == subset_settings_menu)
293 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 )
294 subset_settings_menu->item[5].kind = MN_DEACTIVE;
296 subset_settings_menu->item[5].kind = MN_ACTION;
298 switch (i = subset_settings_menu->check())
301 save_subset_settings_menu();
308 mouse_cursor->draw();
316 if(done == DONE_QUIT)
323 now_time = SDL_GetTicks();
324 if (now_time < last_time + FPS)
325 SDL_Delay(last_time + FPS - now_time); /* delay some time */
334 void le_update_buttons(const char *theme)
340 string_list_type bkgd_files;
341 string_list_type fgd_files;
343 sprintf(pathname,"images/themes/%s",theme);
344 bkgd_files = dfiles(pathname,"bkgd-", NULL);
345 string_list_sort(&bkgd_files);
347 le_bkgd_panel.hidden = true;
349 for(i = 0; i < bkgd_files.num_items; ++i)
351 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
352 button_change_icon(&le_bkgd_panel.item[i],filename);
355 sprintf(pathname,"images/themes/%s",theme);
356 fgd_files = dfiles(pathname,"solid", NULL);
357 string_list_sort(&fgd_files);
359 for(i = 0; i < fgd_files.num_items; ++i)
361 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
362 button_change_icon(&le_fgd_panel.item[i],filename);
365 string_list_free(&fgd_files);
366 fgd_files = dfiles(pathname,"brick", NULL);
367 string_list_sort(&fgd_files);
369 for(i = 0; i < fgd_files.num_items; ++i)
371 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
372 button_change_icon(&le_fgd_panel.item[i+14],filename);
381 string_list_type fgd_files;
382 string_list_type bkgd_files;
383 string_list_type bad_files;
384 level_subsets = dsubdirs("/levels", "info");
388 /* level_changed = NO;*/
391 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
392 le_level_changed = false;
393 le_current_level = NULL;
396 le_mouse_pressed[LEFT] = false;
397 le_mouse_pressed[RIGHT] = false;
399 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
401 timer_init(&select_tilegroup_menu_effect,false);
404 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
405 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
406 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
407 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
408 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
409 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
410 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
411 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
412 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
413 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
414 button_load(&le_tilegroup_bt,"/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,82);
416 leveleditor_menu = new Menu();
417 subset_load_menu = new Menu();
418 subset_new_menu = new Menu();
419 subset_settings_menu = new Menu();
420 level_settings_menu = new Menu();
421 select_tilegroup_menu = new Menu();
423 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
424 leveleditor_menu->additem(MN_HL,"",0,0);
425 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
426 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
427 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
428 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
429 leveleditor_menu->additem(MN_HL,"",0,0);
430 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
433 Menu::set_current(leveleditor_menu);
436 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
437 subset_load_menu->additem(MN_HL, "", 0, 0);
439 for(i = 0; i < level_subsets.num_items; ++i)
441 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
443 subset_load_menu->additem(MN_HL,"",0,0);
444 subset_load_menu->additem(MN_BACK,"Back",0,0);
446 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
447 subset_new_menu->additem(MN_HL,"",0,0);
448 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
449 subset_new_menu->additem(MN_ACTION,"Create",0,0);
450 subset_new_menu->additem(MN_HL,"",0,0);
451 subset_new_menu->additem(MN_BACK,"Back",0,0);
453 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
454 subset_settings_menu->additem(MN_HL,"",0,0);
455 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
456 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
457 subset_settings_menu->additem(MN_HL,"",0,0);
458 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
459 subset_settings_menu->additem(MN_HL,"",0,0);
460 subset_settings_menu->additem(MN_BACK,"Back",0,0);
462 level_settings_menu->arrange_left = true;
463 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
464 level_settings_menu->additem(MN_HL,"",0,0);
465 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
466 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
467 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
468 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
469 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
470 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
471 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
472 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
473 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
474 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
475 level_settings_menu->additem(MN_HL,"",0,0);
476 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
478 select_tilegroup_menu->arrange_left = true;
479 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
480 select_tilegroup_menu->additem(MN_HL,"",0,0);
481 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
482 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
485 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
486 button_panel_init(&tilegroups_map[(*it).name], screen->w - 64,98, 64, 318);
487 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit)
488 button_panel_additem(&tilegroups_map[(*it).name],button_create(const_cast<char*>(("images/tilesets/" + TileManager::instance()->get(*sit)->filenames[0]).c_str()), const_cast<char*>((*it).name.c_str()),(SDLKey)((int)key),0,0),(*sit));
490 select_tilegroup_menu->additem(MN_HL,"",0,0);
492 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
497 void update_level_settings_menu()
502 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
503 sprintf(str,"%d",le_current_level->width);
505 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
506 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
507 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
508 string_list_add_item(level_settings_menu->item[5].list,"");
509 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
510 level_settings_menu->item[3].list->active_item = i;
511 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
512 level_settings_menu->item[4].list->active_item = i;
513 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
514 level_settings_menu->item[5].list->active_item = i;
516 menu_item_change_input(&level_settings_menu->item[6], str);
517 sprintf(str,"%d",le_current_level->time_left);
518 menu_item_change_input(&level_settings_menu->item[7], str);
519 sprintf(str,"%2.0f",le_current_level->gravity);
520 menu_item_change_input(&level_settings_menu->item[8], str);
521 sprintf(str,"%d",le_current_level->bkgd_red);
522 menu_item_change_input(&level_settings_menu->item[9], str);
523 sprintf(str,"%d",le_current_level->bkgd_green);
524 menu_item_change_input(&level_settings_menu->item[10], str);
525 sprintf(str,"%d",le_current_level->bkgd_blue);
526 menu_item_change_input(&level_settings_menu->item[11], str);
529 void update_subset_settings_menu()
531 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
532 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
535 void apply_level_settings_menu()
540 le_current_level->name = level_settings_menu->item[2].input;
542 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
544 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
548 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
550 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
551 le_update_buttons(le_current_level->theme.c_str());
558 level_load_gfx(le_current_level);
561 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
563 level_change_size(le_current_level, atoi(level_settings_menu->item[6].input));
564 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
565 le_current_level->gravity = atof(level_settings_menu->item[8].input);
566 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
567 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
568 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
571 void save_subset_settings_menu()
573 le_level_subset.title = subset_settings_menu->item[2].input;
574 le_level_subset.description = subset_settings_menu->item[3].input;
575 le_level_subset.save();
578 void le_goto_level(int levelnb)
583 level_free(le_current_level);
584 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
586 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
595 le_update_buttons(le_current_level->theme.c_str());
598 level_load_gfx(le_current_level);
603 /*if(level_changed == true)
604 if(askforsaving() == CANCEL)
607 SDL_EnableKeyRepeat(0, 0); // disables key repeating
609 texture_free(&le_selection);
610 delete leveleditor_menu;
611 delete subset_load_menu;
612 delete subset_new_menu;
613 delete subset_settings_menu;
614 delete level_settings_menu;
615 delete select_tilegroup_menu;
616 button_free(&le_save_level_bt);
617 button_free(&le_test_level_bt);
618 button_free(&le_next_level_bt);
619 button_free(&le_previous_level_bt);
620 button_free(&le_move_right_bt);
621 button_free(&le_move_left_bt);
622 button_free(&le_rubber_bt);
623 button_free(&le_select_mode_one_bt);
624 button_free(&le_select_mode_two_bt);
625 button_free(&le_settings_bt);
626 button_free(&le_tilegroup_bt);
628 if(le_current_level != NULL)
631 level_free(le_current_level);
637 void le_drawinterface()
642 if(le_current_level != NULL)
644 /* draw a grid (if selected) */
647 for(x = 0; x < 19; x++)
648 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
649 for(y = 0; y < 15; y++)
650 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
654 if(le_selection_mode == CURSOR)
655 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
656 else if(le_selection_mode == SQUARE)
659 le_highlight_selection();
660 /* draw current selection */
661 w = selection.x2 - selection.x1;
662 h = selection.y2 - selection.y1;
663 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
664 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
665 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
666 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
670 /* draw button bar */
671 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
672 drawshape(19 * 32, 14 * 32, le_current_tile);
673 switch(le_current_tile)
676 texture_draw(&img_mints, 19 * 32, 14 * 32);
679 texture_draw(&img_golden_herring,19 * 32, 14 * 32);
684 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
687 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
690 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
693 texture_draw(&img_money_left[0],19 * 32, 14 * 32);
699 if(le_current_level != NULL)
701 button_draw(&le_save_level_bt);
702 button_draw(&le_test_level_bt);
703 button_draw(&le_next_level_bt);
704 button_draw(&le_previous_level_bt);
705 button_draw(&le_rubber_bt);
706 button_draw(&le_select_mode_one_bt);
707 button_draw(&le_select_mode_two_bt);
708 button_draw(&le_settings_bt);
709 button_draw(&le_move_right_bt);
710 button_draw(&le_move_left_bt);
711 button_draw(&le_tilegroup_bt);
712 button_panel_draw(&tilegroups_map[cur_tilegroup]);
714 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
715 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
717 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
721 if(show_menu == false)
722 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
724 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
731 unsigned int y,x,i,s;
733 /* Draw the real background */
734 if(le_current_level->bkgd_image[0] != '\0')
737 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
738 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
742 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
745 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
747 for (y = 0; y < 15; ++y)
748 for (x = 0; x < 20; ++x)
750 drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]);
752 /* draw whats inside stuff when cursor is selecting those */
753 /* (draw them all the time - is this the right behaviour?) */
754 switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)])
757 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
760 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
765 texture_draw(&img_distro[(global_frame_counter / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
772 /* Draw the Bad guys: */
773 for (i = 0; i < bad_guys.size(); ++i)
775 /* to support frames: img_bsod_left[(frame / 5) % 4] */
776 if(bad_guys[i].kind == BAD_BSOD)
777 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
778 else if(bad_guys[i].kind == BAD_LAPTOP)
779 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
780 else if (bad_guys[i].kind == BAD_MONEY)
781 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
785 /* Draw the player: */
786 /* for now, the position is fixed at (0, 240) */
787 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 0 - pos_x, 240);
790 void le_checkevents()
794 button_type* pbutton;
797 keymod = SDL_GetModState();
799 while(SDL_PollEvent(&event))
804 mouse_cursor->set_state(MC_NORMAL);
806 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
807 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
808 event.motion.y > 0 && event.motion.y < screen->h)))
812 case SDL_KEYDOWN: // key pressed
813 key = event.key.keysym.sym;
816 if(key == SDLK_ESCAPE)
819 Menu::set_current(leveleditor_menu);
833 cursor_x -= KEY_CURSOR_SPEED;
835 cursor_x -= KEY_CURSOR_FASTSPEED;
837 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
838 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
843 cursor_x += KEY_CURSOR_SPEED;
845 cursor_x += KEY_CURSOR_FASTSPEED;
847 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
848 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
853 cursor_y -= KEY_CURSOR_SPEED;
855 cursor_y -= KEY_CURSOR_FASTSPEED;
862 cursor_y += KEY_CURSOR_SPEED;
864 cursor_y += KEY_CURSOR_FASTSPEED;
866 if(cursor_y > screen->h-32)
867 cursor_y = screen->h-32;
880 cursor_x = (le_current_level->width * 32) - 32;
884 le_show_grid = !le_show_grid;
890 case SDL_KEYUP: /* key released */
891 switch(event.key.keysym.sym)
900 case SDL_MOUSEBUTTONDOWN:
901 if(event.button.button == SDL_BUTTON_LEFT)
903 le_mouse_pressed[LEFT] = true;
905 selection.x1 = event.motion.x + pos_x;
906 selection.y1 = event.motion.y;
907 selection.x2 = event.motion.x + pos_x;
908 selection.y2 = event.motion.y;
910 else if(event.button.button == SDL_BUTTON_RIGHT)
911 le_mouse_pressed[RIGHT] = true;
913 case SDL_MOUSEBUTTONUP:
914 if(event.button.button == SDL_BUTTON_LEFT)
915 le_mouse_pressed[LEFT] = false;
916 else if(event.button.button == SDL_BUTTON_RIGHT)
917 le_mouse_pressed[RIGHT] = false;
919 case SDL_MOUSEMOTION:
925 cursor_x = ((int)(pos_x + x) / 32) * 32;
926 cursor_y = ((int) y / 32) * 32;
928 if(le_mouse_pressed[LEFT])
930 selection.x2 = x + pos_x;
934 if(le_mouse_pressed[RIGHT])
936 pos_x += -1 * event.motion.xrel;
940 case SDL_QUIT: // window closed
948 if(le_current_level != NULL)
950 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 &&
951 event.motion.y > 0 && event.motion.y < screen->h)))
953 le_mouse_pressed[LEFT] = false;
954 le_mouse_pressed[RIGHT] = false;
956 if(show_menu == false)
958 /* Check for button events */
959 button_event(&le_test_level_bt,&event);
960 if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
962 button_event(&le_save_level_bt,&event);
963 if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
964 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
965 button_event(&le_next_level_bt,&event);
966 if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
968 if(le_level < le_level_subset.levels)
970 le_goto_level(++le_level);
977 sprintf(str,"Level %d doesn't exist.",le_level+1);
978 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
979 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
980 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
984 while(SDL_PollEvent(&event))
987 case SDL_KEYDOWN: // key pressed
988 switch(event.key.keysym.sym)
991 level_default(&new_lev);
992 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
993 le_level_subset.levels = le_level;
994 le_goto_level(le_level);
1011 button_event(&le_previous_level_bt,&event);
1012 if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1015 le_goto_level(--le_level);
1017 button_event(&le_rubber_bt,&event);
1018 if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1019 le_current_tile = 0;
1020 button_event(&le_select_mode_one_bt,&event);
1021 if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1022 le_selection_mode = CURSOR;
1023 button_event(&le_select_mode_two_bt,&event);
1024 if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1025 le_selection_mode = SQUARE;
1027 button_event(&le_tilegroup_bt,&event);
1028 if(button_get_state(&le_tilegroup_bt) == BUTTON_CLICKED)
1030 Menu::set_current(select_tilegroup_menu);
1031 timer_start(&select_tilegroup_menu_effect,200);
1032 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1036 button_event(&le_settings_bt,&event);
1037 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1039 update_level_settings_menu();
1040 Menu::set_current(level_settings_menu);
1043 if((pbutton = button_panel_event(&tilegroups_map[cur_tilegroup],&event)) != NULL)
1045 if(button_get_state(pbutton) == BUTTON_CLICKED)
1047 le_current_tile = pbutton->tag;
1050 /*if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1052 if(button_get_state(pbutton) == BUTTON_CLICKED)
1055 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1056 c = 'G' + pbutton->tag;
1057 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1058 c = 'g' + pbutton->tag - 4;
1059 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1060 c = 'C' + pbutton->tag - 8;
1061 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1062 c = 'c' + pbutton->tag - 12;
1064 le_current_tile = c;
1070 button_event(&le_settings_bt,&event);
1071 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1073 Menu::set_current(leveleditor_menu);
1076 button_event(&le_tilegroup_bt,&event);
1077 if(button_get_state(&le_tilegroup_bt) == BUTTON_CLICKED)
1079 Menu::set_current(leveleditor_menu);
1084 if(show_menu == false)
1086 button_event(&le_move_left_bt,&event);
1087 button_event(&le_move_right_bt,&event);
1089 if(le_mouse_pressed[LEFT])
1091 le_change(cursor_x, cursor_y, TM_IA, le_current_tile);
1096 if(show_menu == false)
1098 if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1102 else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1107 if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1111 else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1119 void le_highlight_selection()
1123 if(selection.x1 < selection.x2)
1133 if(selection.y1 < selection.y2)
1149 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1152 void le_change(float x, float y, int tm, unsigned int c)
1154 if(le_current_level != NULL)
1160 /* level_changed = true; */
1162 switch(le_selection_mode)
1165 level_change(le_current_level,x,y,tm,c);
1170 /* if there is a bad guy over there, remove it */
1171 for(i = 0; i < bad_guys.size(); ++i)
1172 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1173 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1175 if(c == '0') /* if it's a bad guy */
1176 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1178 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1180 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1184 if(selection.x1 < selection.x2)
1194 if(selection.y1 < selection.y2)
1210 /* if there is a bad guy over there, remove it */
1211 for(i = 0; i < bad_guys.size(); ++i)
1212 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1213 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1214 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1216 for(xx = x1; xx <= x2; xx++)
1217 for(yy = y1; yy <= y2; yy++)
1219 level_change(le_current_level, xx*32, yy*32, tm, c);
1221 if(c == '0') // if it's a bad guy
1222 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1224 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1226 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1237 level_save(le_current_level,"test",le_level);
1238 gameloop("test",le_level, ST_GL_TEST);
1239 Menu::set_current(leveleditor_menu);
1241 level_load_gfx(le_current_level);
1248 unsigned int i, done;
1250 " - This is SuperTux's built-in level editor -",
1251 "It has been designed to be light and easy to use from the start.",
1253 "When you first load the level editor you are given a menu where you",
1254 "can load level subsets, create a new level subset, edit the current",
1255 "subset's settings, or simply quit the editor. You can access this menu",
1256 "from the level editor at any time by pressing the escape key.",
1258 "To your right is your button bar. The center of this contains many",
1259 "tiles you can use to make your level. To select a tile, click on it",
1260 "with your left mouse button; your selection will be shown in the",
1261 "bottom right corner of the button box. Click anywhere on your level",
1262 "with the left mouse button to place that tile down. If you right click",
1263 "a tile in the button bar, you can find out what its keyboard shortcut",
1264 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1265 "background, and enemy tiles. The eraser lets you remove tiles.",
1266 "The left and right arrow keys scroll back and forth through your level.",
1267 "The button with the wrench and screwdriver, lets you change the",
1268 "settings of your level, including how long it is or what music it will",
1269 "play. When you are ready to give your level a test, click on the little",
1270 "running Tux. If you like the changes you have made to your level,",
1271 "press the red save key to keep them.",
1272 "To change which level in your subset you are editing, press the white",
1273 "up and down arrow keys at the top of the button box.",
1275 "Have fun making levels! If you make some good ones, send them to us on",
1276 "the SuperTux mailing list!",
1281 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1283 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1284 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1286 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1294 while(SDL_PollEvent(&event))
1297 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1298 case SDL_KEYDOWN: // key pressed