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> */
22 #include <SDL_image.h>
23 #include "leveleditor.h"
35 /* definitions to aid development */
36 #define DONE_LEVELEDITOR 1
38 #define DONE_CHANGELEVEL 3
40 /* definitions that affect gameplay */
41 #define KEY_CURSOR_SPEED 32
42 #define KEY_CURSOR_FASTSPEED 64
44 /* when pagedown/up pressed speed:*/
45 #define PAGE_CURSOR_SPEED 13*32
47 #define MOUSE_LEFT_MARGIN 80
48 #define MOUSE_RIGHT_MARGIN (560-32)
49 /* right_margin should noticed that the cursor is 32 pixels,
50 so it should subtract that value */
51 #define MOUSE_POS_SPEED 20
54 #define SELECT_W 2 // size of the selections lines
55 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
57 /* gameloop funcs declerations */
59 void loadshared(void);
60 void unloadshared(void);
62 /* own declerations */
63 /* crutial ones (main loop) */
67 void le_drawinterface();
68 void le_checkevents();
69 void le_change(float x, float y, unsigned char c);
72 void le_set_defaults(void);
73 void le_activate_bad_guys(void);
75 void le_highlight_selection();
77 void apply_level_settings_menu();
78 void update_subset_settings_menu();
79 void save_subset_settings_menu();
80 void le_update_buttons(const char*);
82 /* leveleditor internals */
83 static string_list_type level_subsets;
84 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
85 static int pos_x, cursor_x, cursor_y, fire;
87 static st_level* le_current_level;
88 static st_subset le_level_subset;
89 static int le_show_grid;
91 static texture_type le_selection;
93 static char le_current_tile;
94 static bool le_mouse_pressed[2];
95 static button_type le_save_level_bt;
96 static button_type le_test_level_bt;
97 static button_type le_next_level_bt;
98 static button_type le_previous_level_bt;
99 static button_type le_move_right_bt;
100 static button_type le_move_left_bt;
101 static button_type le_rubber_bt;
102 static button_type le_select_mode_one_bt;
103 static button_type le_select_mode_two_bt;
104 static button_type le_settings_bt;
105 static button_type le_bad_bt;
106 static button_type le_bkgd_bt;
107 static button_type le_fgd_bt;
108 static button_panel_type le_bkgd_panel;
109 static button_panel_type le_fgd_panel;
110 static button_panel_type le_bad_panel;
111 static menu_type leveleditor_menu;
112 static menu_type subset_load_menu;
113 static menu_type subset_new_menu;
114 static menu_type subset_settings_menu;
115 static menu_type level_settings_menu;
117 static square selection;
118 static int le_selection_mode;
119 static SDL_Event event;
121 void le_activate_bad_guys(void)
125 /* Activate bad guys: */
127 /* as oposed to the gameloop.c func, this one doesn't remove
128 the badguys from tiles */
130 for (y = 0; y < 15; ++y)
131 for (x = 0; x < le_current_level->width; ++x)
132 if (le_current_level->tiles[y][x] >= '0' && le_current_level->tiles[y][x] <= '9')
133 add_bad_guy(x * 32, y * 32, le_current_level->tiles[y][x] - '0');
136 void le_set_defaults()
138 if(le_current_level != NULL)
142 if(le_current_level->time_left == 0)
143 le_current_level->time_left = 255;
147 int leveleditor(int levelnb)
149 int last_time, now_time, i;
157 clearscreen(0, 0, 0);
160 while (SDL_PollEvent(&event))
165 last_time = SDL_GetTicks();
170 if(le_current_level != NULL)
172 /* making events results to be in order */
175 if(pos_x > (le_current_level->width * 32) - screen->w)
176 pos_x = (le_current_level->width * 32) - screen->w;
182 clearscreen(0, 0, 0);
184 /* draw editor interface */
189 menu_process_current();
190 if(current_menu == &leveleditor_menu)
192 switch (menu_check(&leveleditor_menu))
198 update_subset_settings_menu();
201 done = DONE_LEVELEDITOR;
205 else if(current_menu == &level_settings_menu)
207 switch (menu_check(&level_settings_menu))
210 apply_level_settings_menu();
211 menu_set_current(&leveleditor_menu);
218 else if(current_menu == &subset_load_menu)
220 switch (i = menu_check(&subset_load_menu))
227 le_level_subset.load(level_subsets.item[i-2]);
228 leveleditor_menu.item[3].kind = MN_GOTO;
232 le_current_level = new st_level;
233 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
238 le_update_buttons(le_current_level->theme.c_str());
240 level_load_gfx(le_current_level);
241 le_activate_bad_guys();
247 else if(current_menu == &subset_new_menu)
249 if(subset_new_menu.item[2].input[0] == '\0')
250 subset_new_menu.item[3].kind = MN_DEACTIVE;
253 subset_new_menu.item[3].kind = MN_ACTION;
255 switch (i = menu_check(&subset_new_menu))
258 st_subset::create(subset_new_menu.item[2].input);
259 le_level_subset.load(subset_new_menu.item[2].input);
260 leveleditor_menu.item[3].kind = MN_GOTO;
264 le_current_level = new st_level;
265 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
270 le_update_buttons(le_current_level->theme.c_str());
272 level_load_gfx(le_current_level);
273 le_activate_bad_guys();
274 menu_item_change_input(&subset_new_menu.item[2],"");
280 else if(current_menu == &subset_settings_menu)
282 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 )
283 subset_settings_menu.item[5].kind = MN_DEACTIVE;
285 subset_settings_menu.item[5].kind = MN_ACTION;
287 switch (i = menu_check(&subset_settings_menu))
290 save_subset_settings_menu();
303 if(done == DONE_QUIT)
310 now_time = SDL_GetTicks();
311 if (now_time < last_time + FPS)
312 SDL_Delay(last_time + FPS - now_time); /* delay some time */
321 void le_update_buttons(const char *theme)
327 string_list_type bkgd_files;
328 string_list_type fgd_files;
330 sprintf(pathname,"images/themes/%s",theme);
331 bkgd_files = dfiles(pathname,"bkgd-", NULL);
332 string_list_sort(&bkgd_files);
334 le_bkgd_panel.hidden = true;
336 for(i = 0; i < bkgd_files.num_items; ++i)
338 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
339 button_change_icon(&le_bkgd_panel.item[i],filename);
342 sprintf(pathname,"images/themes/%s",theme);
343 fgd_files = dfiles(pathname,"solid", NULL);
344 string_list_sort(&fgd_files);
346 for(i = 0; i < fgd_files.num_items; ++i)
348 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
349 button_change_icon(&le_fgd_panel.item[i],filename);
352 string_list_free(&fgd_files);
353 fgd_files = dfiles(pathname,"brick", NULL);
354 string_list_sort(&fgd_files);
356 for(i = 0; i < fgd_files.num_items; ++i)
358 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
359 button_change_icon(&le_fgd_panel.item[i+14],filename);
368 string_list_type fgd_files;
369 string_list_type bkgd_files;
370 string_list_type bad_files;
371 level_subsets = dsubdirs("/levels", "info");
375 /* level_changed = NO;*/
378 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
379 le_level_changed = false;
380 le_current_level = NULL;
382 le_current_tile = '.';
383 le_mouse_pressed[LEFT] = false;
384 le_mouse_pressed[RIGHT] = false;
386 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
389 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
390 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
391 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
392 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
393 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
394 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
395 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
396 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
397 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
398 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
399 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
400 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
401 button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
403 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
404 string_list_sort(&bkgd_files);
406 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
407 le_bkgd_panel.hidden = true;
409 for(i = 0; i < bkgd_files.num_items; ++i)
411 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
412 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
415 string_list_free(&bkgd_files);
416 bkgd_files = dfiles("images/shared","cloud-", NULL);
417 string_list_sort(&bkgd_files);
419 for(i = 0; i < bkgd_files.num_items; ++i)
421 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
422 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
425 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
426 string_list_sort(&fgd_files);
428 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
429 for(i = 0; i < fgd_files.num_items; ++i)
431 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
432 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
435 string_list_free(&fgd_files);
436 string_list_add_item(&fgd_files,"waves-0.png");
437 string_list_add_item(&fgd_files,"water.png");
438 string_list_add_item(&fgd_files,"pole.png");
439 string_list_add_item(&fgd_files,"poletop.png");
440 string_list_add_item(&fgd_files,"flag-0.png");
441 string_list_add_item(&fgd_files,"box-empty.png");
442 string_list_add_item(&fgd_files,"mints.png");
443 string_list_add_item(&fgd_files,"distro-0.png");
444 string_list_add_item(&fgd_files,"golden-herring.png");
445 string_list_add_item(&fgd_files,"distro-0.png");
447 for(i = 0; i < fgd_files.num_items; ++i)
449 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
450 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
453 string_list_free(&fgd_files);
454 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
455 string_list_sort(&fgd_files);
457 for(i = 0; i < fgd_files.num_items; ++i)
459 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
460 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
463 string_list_free(&fgd_files);
464 string_list_add_item(&fgd_files,"distro-0.png");
465 string_list_add_item(&fgd_files,"distro-0.png");
466 for(i = 0; i < fgd_files.num_items; ++i)
468 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
469 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
472 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
473 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
474 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
475 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
476 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
478 string_list_init(&bad_files);
479 string_list_add_item(&bad_files,"bsod-left-0.png");
480 string_list_add_item(&bad_files,"laptop-left-0.png");
481 string_list_add_item(&bad_files,"bag-left-0.png");
482 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
483 le_bad_panel.hidden = true;
485 for(i = 0; i < bad_files.num_items; ++i)
487 sprintf(filename,"images/shared/%s",bad_files.item[i]);
488 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
491 menu_init(&leveleditor_menu);
492 menu_additem(&leveleditor_menu, MN_LABEL,"Level Editor Menu",0,0);
493 menu_additem(&leveleditor_menu, MN_HL,"",0,0);
494 menu_additem(&leveleditor_menu, MN_ACTION,"Return To Level Editor",0,0);
495 menu_additem(&leveleditor_menu, MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu);
496 menu_additem(&leveleditor_menu, MN_GOTO,"Load Level Subset",0,&subset_load_menu);
497 menu_additem(&leveleditor_menu, MN_GOTO,"New Level Subset",0,&subset_new_menu);
498 menu_additem(&leveleditor_menu, MN_HL,"",0,0);
499 menu_additem(&leveleditor_menu, MN_ACTION,"Quit Level Editor",0,0);
502 menu_set_current(&leveleditor_menu);
505 menu_init(&subset_load_menu);
506 menu_additem(&subset_load_menu,MN_LABEL,"Load Level Subset",0,0);
507 menu_additem(&subset_load_menu,MN_HL,"",0,0);
508 for(i = 0; i < level_subsets.num_items; ++i)
510 menu_additem(&subset_load_menu,MN_ACTION,level_subsets.item[i],0,0);
512 menu_additem(&subset_load_menu,MN_HL,"",0,0);
513 menu_additem(&subset_load_menu,MN_BACK,"Back",0,0);
515 menu_init(&subset_new_menu);
516 menu_additem(&subset_new_menu,MN_LABEL,"New Level Subset",0,0);
517 menu_additem(&subset_new_menu,MN_HL,"",0,0);
518 menu_additem(&subset_new_menu,MN_TEXTFIELD,"Enter Name",0,0);
519 menu_additem(&subset_new_menu,MN_ACTION,"Create",0,0);
520 menu_additem(&subset_new_menu,MN_HL,"",0,0);
521 menu_additem(&subset_new_menu,MN_BACK,"Back",0,0);
523 menu_init(&subset_settings_menu);
524 menu_additem(&subset_settings_menu,MN_LABEL,"Level Subset Settings",0,0);
525 menu_additem(&subset_settings_menu,MN_HL,"",0,0);
526 menu_additem(&subset_settings_menu,MN_TEXTFIELD,"Title",0,0);
527 menu_additem(&subset_settings_menu,MN_TEXTFIELD,"Description",0,0);
528 menu_additem(&subset_settings_menu,MN_HL,"",0,0);
529 menu_additem(&subset_settings_menu,MN_ACTION,"Save Changes",0,0);
530 menu_additem(&subset_settings_menu,MN_HL,"",0,0);
531 menu_additem(&subset_settings_menu,MN_BACK,"Back",0,0);
533 menu_init(&level_settings_menu);
534 level_settings_menu.arrange_left = true;
535 menu_additem(&level_settings_menu,MN_LABEL,"Level Settings",0,0);
536 menu_additem(&level_settings_menu,MN_HL,"",0,0);
537 menu_additem(&level_settings_menu,MN_TEXTFIELD,"Name ",0,0);
538 menu_additem(&level_settings_menu,MN_STRINGSELECT,"Theme ",0,0);
539 menu_additem(&level_settings_menu,MN_STRINGSELECT,"Song ",0,0);
540 menu_additem(&level_settings_menu,MN_STRINGSELECT,"Bg-Image",0,0);
541 menu_additem(&level_settings_menu,MN_NUMFIELD,"Length ",0,0);
542 menu_additem(&level_settings_menu,MN_NUMFIELD,"Time ",0,0);
543 menu_additem(&level_settings_menu,MN_NUMFIELD,"Gravity",0,0);
544 menu_additem(&level_settings_menu,MN_NUMFIELD,"Red ",0,0);
545 menu_additem(&level_settings_menu,MN_NUMFIELD,"Green ",0,0);
546 menu_additem(&level_settings_menu,MN_NUMFIELD,"Blue ",0,0);
547 menu_additem(&level_settings_menu,MN_HL,"",0,0);
548 menu_additem(&level_settings_menu,MN_ACTION,"Apply Changes",0,0);
550 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
555 void update_level_settings_menu()
560 menu_item_change_input(&level_settings_menu.item[2], le_current_level->name.c_str());
561 sprintf(str,"%d",le_current_level->width);
563 string_list_copy(level_settings_menu.item[3].list, dsubdirs("images/themes", "solid0.png"));
564 string_list_copy(level_settings_menu.item[4].list, dfiles("music/",NULL, "-fast"));
565 string_list_copy(level_settings_menu.item[5].list, dfiles("images/background",NULL, NULL));
566 string_list_add_item(level_settings_menu.item[5].list,"");
567 if((i = string_list_find(level_settings_menu.item[3].list,le_current_level->theme.c_str())) != -1)
568 level_settings_menu.item[3].list->active_item = i;
569 if((i = string_list_find(level_settings_menu.item[4].list,le_current_level->song_title.c_str())) != -1)
570 level_settings_menu.item[4].list->active_item = i;
571 if((i = string_list_find(level_settings_menu.item[5].list,le_current_level->bkgd_image.c_str())) != -1)
572 level_settings_menu.item[5].list->active_item = i;
574 menu_item_change_input(&level_settings_menu.item[6], str);
575 sprintf(str,"%d",le_current_level->time_left);
576 menu_item_change_input(&level_settings_menu.item[7], str);
577 sprintf(str,"%2.0f",le_current_level->gravity);
578 menu_item_change_input(&level_settings_menu.item[8], str);
579 sprintf(str,"%d",le_current_level->bkgd_red);
580 menu_item_change_input(&level_settings_menu.item[9], str);
581 sprintf(str,"%d",le_current_level->bkgd_green);
582 menu_item_change_input(&level_settings_menu.item[10], str);
583 sprintf(str,"%d",le_current_level->bkgd_blue);
584 menu_item_change_input(&level_settings_menu.item[11], str);
587 void update_subset_settings_menu()
589 menu_item_change_input(&subset_settings_menu.item[2], le_level_subset.title.c_str());
590 menu_item_change_input(&subset_settings_menu.item[3], le_level_subset.description.c_str());
593 void apply_level_settings_menu()
598 le_current_level->name = level_settings_menu.item[2].input;
600 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu.item[5].list)) != 0)
602 le_current_level->bkgd_image = string_list_active(level_settings_menu.item[5].list);
606 if(le_current_level->theme.compare(string_list_active(level_settings_menu.item[3].list)) != 0)
608 le_current_level->theme = string_list_active(level_settings_menu.item[3].list);
609 le_update_buttons(le_current_level->theme.c_str());
616 level_load_gfx(le_current_level);
619 le_current_level->song_title = string_list_active(level_settings_menu.item[4].list);
621 i = le_current_level->width;
622 le_current_level->width = atoi(level_settings_menu.item[6].input);
623 if(le_current_level->width < i)
625 if(le_current_level->width < 21)
626 le_current_level->width = 21;
627 for(y = 0; y < 15; ++y)
629 le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
630 le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
633 else if(le_current_level->width > i)
635 for(y = 0; y < 15; ++y)
637 le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
638 for(j = 0; j < le_current_level->width - i; ++j)
639 le_current_level->tiles[y][i+j] = (unsigned int) '.';
640 le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
643 le_current_level->time_left = atoi(level_settings_menu.item[7].input);
644 le_current_level->gravity = atof(level_settings_menu.item[8].input);
645 le_current_level->bkgd_red = atoi(level_settings_menu.item[9].input);
646 le_current_level->bkgd_green = atoi(level_settings_menu.item[10].input);
647 le_current_level->bkgd_blue = atoi(level_settings_menu.item[11].input);
650 void save_subset_settings_menu()
652 le_level_subset.title = subset_settings_menu.item[2].input;
653 le_level_subset.description = subset_settings_menu.item[3].input;
654 le_level_subset.save();
657 void le_goto_level(int levelnb)
662 level_free(le_current_level);
663 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
665 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
674 le_update_buttons(le_current_level->theme.c_str());
677 level_load_gfx(le_current_level);
679 le_activate_bad_guys();
684 /*if(level_changed == true)
685 if(askforsaving() == CANCEL)
688 SDL_EnableKeyRepeat(0, 0); // disables key repeating
690 texture_free(&le_selection);
691 menu_free(&leveleditor_menu);
692 menu_free(&subset_load_menu);
693 menu_free(&subset_new_menu);
694 menu_free(&subset_settings_menu);
695 menu_free(&level_settings_menu);
696 button_panel_free(&le_bkgd_panel);
697 button_panel_free(&le_fgd_panel);
698 button_panel_free(&le_bad_panel);
699 button_free(&le_save_level_bt);
700 button_free(&le_test_level_bt);
701 button_free(&le_next_level_bt);
702 button_free(&le_previous_level_bt);
703 button_free(&le_move_right_bt);
704 button_free(&le_move_left_bt);
705 button_free(&le_rubber_bt);
706 button_free(&le_select_mode_one_bt);
707 button_free(&le_select_mode_two_bt);
708 button_free(&le_settings_bt);
709 button_free(&le_bad_bt);
710 button_free(&le_bkgd_bt);
711 button_free(&le_fgd_bt);
713 if(le_current_level != NULL)
716 level_free(le_current_level);
722 void le_drawinterface()
727 if(le_current_level != NULL)
729 /* draw a grid (if selected) */
732 for(x = 0; x < 19; x++)
733 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
734 for(y = 0; y < 15; y++)
735 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
739 if(le_selection_mode == CURSOR)
740 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
741 else if(le_selection_mode == SQUARE)
744 le_highlight_selection();
745 /* draw current selection */
746 w = selection.x2 - selection.x1;
747 h = selection.y2 - selection.y1;
748 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
749 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
750 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
751 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
755 /* draw button bar */
756 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
757 drawshape(19 * 32, 14 * 32, le_current_tile);
758 switch(le_current_tile)
761 texture_draw(&img_mints, 19 * 32, 14 * 32);
764 texture_draw(&img_golden_herring,19 * 32, 14 * 32);
769 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
772 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
775 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
778 texture_draw(&img_money_left[0],19 * 32, 14 * 32);
784 if(le_current_level != NULL)
786 button_draw(&le_save_level_bt);
787 button_draw(&le_test_level_bt);
788 button_draw(&le_next_level_bt);
789 button_draw(&le_previous_level_bt);
790 button_draw(&le_rubber_bt);
791 button_draw(&le_select_mode_one_bt);
792 button_draw(&le_select_mode_two_bt);
793 button_draw(&le_settings_bt);
794 button_draw(&le_move_right_bt);
795 button_draw(&le_move_left_bt);
796 button_draw(&le_bad_bt);
797 button_draw(&le_bkgd_bt);
798 button_draw(&le_fgd_bt);
799 button_panel_draw(&le_bkgd_panel);
800 button_panel_draw(&le_fgd_panel);
801 button_panel_draw(&le_bad_panel);
803 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
804 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
806 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
810 if(show_menu == false)
811 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
813 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
820 unsigned int y,x,i,s;
822 /* Draw the real background */
823 if(le_current_level->bkgd_image[0] != '\0')
826 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
827 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
831 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
834 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
836 for (y = 0; y < 15; ++y)
837 for (x = 0; x < 20; ++x)
839 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
841 /* draw whats inside stuff when cursor is selecting those */
842 /* (draw them all the time - is this the right behaviour?) */
843 switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
846 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
849 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
854 texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
861 /* Draw the Bad guys: */
862 for (i = 0; i < bad_guys.size(); ++i)
864 /* to support frames: img_bsod_left[(frame / 5) % 4] */
865 if(bad_guys[i].kind == BAD_BSOD)
866 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
867 else if(bad_guys[i].kind == BAD_LAPTOP)
868 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
869 else if (bad_guys[i].kind == BAD_MONEY)
870 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
874 /* Draw the player: */
875 /* for now, the position is fixed at (0, 240) */
876 texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240);
879 void le_checkevents()
883 button_type* pbutton;
886 keymod = SDL_GetModState();
888 while(SDL_PollEvent(&event))
890 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
891 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
892 event.motion.y > 0 && event.motion.y < screen->h)))
897 case SDL_KEYDOWN: // key pressed
898 key = event.key.keysym.sym;
901 menu_event(&event.key.keysym);
902 if(key == SDLK_ESCAPE)
905 menu_set_current(&leveleditor_menu);
919 cursor_x -= KEY_CURSOR_SPEED;
921 cursor_x -= KEY_CURSOR_FASTSPEED;
923 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
924 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
929 cursor_x += KEY_CURSOR_SPEED;
931 cursor_x += KEY_CURSOR_FASTSPEED;
933 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
934 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
939 cursor_y -= KEY_CURSOR_SPEED;
941 cursor_y -= KEY_CURSOR_FASTSPEED;
948 cursor_y += KEY_CURSOR_SPEED;
950 cursor_y += KEY_CURSOR_FASTSPEED;
952 if(cursor_y > screen->h-32)
953 cursor_y = screen->h-32;
966 cursor_x = (le_current_level->width * 32) - 32;
970 le_show_grid = !le_show_grid;
976 case SDL_KEYUP: /* key released */
977 switch(event.key.keysym.sym)
986 case SDL_MOUSEBUTTONDOWN:
987 if(event.button.button == SDL_BUTTON_LEFT)
989 le_mouse_pressed[LEFT] = true;
991 selection.x1 = event.motion.x + pos_x;
992 selection.y1 = event.motion.y;
993 selection.x2 = event.motion.x + pos_x;
994 selection.y2 = event.motion.y;
996 else if(event.button.button == SDL_BUTTON_RIGHT)
997 le_mouse_pressed[RIGHT] = true;
999 case SDL_MOUSEBUTTONUP:
1000 if(event.button.button == SDL_BUTTON_LEFT)
1001 le_mouse_pressed[LEFT] = false;
1002 else if(event.button.button == SDL_BUTTON_RIGHT)
1003 le_mouse_pressed[RIGHT] = false;
1005 case SDL_MOUSEMOTION:
1011 cursor_x = ((int)(pos_x + x) / 32) * 32;
1012 cursor_y = ((int) y / 32) * 32;
1014 if(le_mouse_pressed[LEFT] == true)
1016 selection.x2 = x + pos_x;
1020 if(le_mouse_pressed[RIGHT] == true)
1022 pos_x += -1 * event.motion.xrel;
1026 case SDL_QUIT: // window closed
1034 if(le_current_level != NULL)
1036 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 &&
1037 event.motion.y > 0 && event.motion.y < screen->h)))
1039 le_mouse_pressed[LEFT] = false;
1040 le_mouse_pressed[RIGHT] = false;
1042 if(show_menu == false)
1044 /* Check for button events */
1045 button_event(&le_test_level_bt,&event);
1046 if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
1048 button_event(&le_save_level_bt,&event);
1049 if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
1050 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
1051 button_event(&le_next_level_bt,&event);
1052 if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
1054 if(le_level < le_level_subset.levels)
1056 le_goto_level(++le_level);
1063 sprintf(str,"Level %d doesn't exist.",le_level+1);
1064 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
1065 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
1066 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
1070 while(SDL_PollEvent(&event))
1073 case SDL_KEYDOWN: // key pressed
1074 switch(event.key.keysym.sym)
1077 level_default(&new_lev);
1078 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
1079 le_level_subset.levels = le_level;
1080 le_goto_level(le_level);
1097 button_event(&le_previous_level_bt,&event);
1098 if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1101 le_goto_level(--le_level);
1103 button_event(&le_rubber_bt,&event);
1104 if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1105 le_current_tile = '.';
1106 button_event(&le_select_mode_one_bt,&event);
1107 if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1108 le_selection_mode = CURSOR;
1109 button_event(&le_select_mode_two_bt,&event);
1110 if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1111 le_selection_mode = SQUARE;
1113 button_event(&le_bad_bt,&event);
1114 if(button_get_state(&le_bad_bt) == BUTTON_CLICKED)
1116 le_bad_panel.hidden = false;
1117 le_fgd_panel.hidden = true;
1118 le_bkgd_panel.hidden = true;
1121 button_event(&le_fgd_bt,&event);
1122 if(button_get_state(&le_fgd_bt) == BUTTON_CLICKED)
1124 le_bad_panel.hidden = true;
1125 le_fgd_panel.hidden = false;
1126 le_bkgd_panel.hidden = true;
1128 button_event(&le_bkgd_bt,&event);
1129 if(button_get_state(&le_bkgd_bt) == BUTTON_CLICKED)
1131 le_bad_panel.hidden = true;
1132 le_fgd_panel.hidden = true;
1133 le_bkgd_panel.hidden = false;
1135 button_event(&le_settings_bt,&event);
1136 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1138 if(show_menu == false)
1140 update_level_settings_menu();
1141 menu_set_current(&level_settings_menu);
1146 menu_set_current(&leveleditor_menu);
1150 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1152 if(button_get_state(pbutton) == BUTTON_CLICKED)
1155 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1156 c = 'G' + pbutton->tag;
1157 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1158 c = 'g' + pbutton->tag - 4;
1159 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1160 c = 'C' + pbutton->tag - 8;
1161 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1162 c = 'c' + pbutton->tag - 12;
1164 le_current_tile = c;
1167 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1169 if(button_get_state(pbutton) == BUTTON_CLICKED)
1172 if(pbutton->tag == 0)
1174 else if(pbutton->tag == 1)
1176 else if(pbutton->tag == 2)
1178 else if(pbutton->tag == 3)
1180 else if(pbutton->tag == 4)
1182 else if(pbutton->tag == 5)
1184 else if(pbutton->tag == 6)
1186 else if(pbutton->tag == 7)
1188 else if(pbutton->tag == 8)
1190 else if(pbutton->tag == 9)
1192 else if(pbutton->tag == 10)
1194 else if(pbutton->tag == 11)
1196 else if(pbutton->tag == 12)
1198 else if(pbutton->tag == 13)
1200 else if(pbutton->tag == 14)
1202 else if(pbutton->tag == 15)
1204 else if(pbutton->tag == 16)
1206 else if(pbutton->tag == 17)
1209 le_current_tile = c;
1212 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1214 if(button_get_state(pbutton) == BUTTON_CLICKED)
1217 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1218 c = '0' + pbutton->tag;
1220 le_current_tile = c;
1226 button_event(&le_settings_bt,&event);
1227 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1229 if(show_menu == false)
1231 update_level_settings_menu();
1232 menu_set_current(&level_settings_menu);
1237 menu_set_current(&leveleditor_menu);
1243 if(show_menu == false)
1245 button_event(&le_move_left_bt,&event);
1246 button_event(&le_move_right_bt,&event);
1248 if(le_mouse_pressed[LEFT])
1250 le_change(cursor_x, cursor_y, le_current_tile);
1255 if(show_menu == false)
1257 if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1261 else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1266 if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1270 else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1278 void le_highlight_selection()
1282 if(selection.x1 < selection.x2)
1292 if(selection.y1 < selection.y2)
1308 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1311 void le_change(float x, float y, unsigned char c)
1313 if(le_current_level != NULL)
1319 /* level_changed = true; */
1321 switch(le_selection_mode)
1324 level_change(le_current_level,x,y,c);
1329 /* if there is a bad guy over there, remove it */
1330 for(i = 0; i < bad_guys.size(); ++i)
1331 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1332 bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(&bad_guys[i]));
1334 if(c == '0') /* if it's a bad guy */
1335 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1337 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1339 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1343 if(selection.x1 < selection.x2)
1353 if(selection.y1 < selection.y2)
1369 /* if there is a bad guy over there, remove it */
1370 for(i = 0; i < bad_guys.size(); ++i)
1371 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1372 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1373 bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(&bad_guys[i]));
1375 for(xx = x1; xx <= x2; xx++)
1376 for(yy = y1; yy <= y2; yy++)
1378 level_change(le_current_level, xx*32, yy*32, c);
1380 if(c == '0') // if it's a bad guy
1381 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1383 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1385 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1396 level_save(le_current_level,"test",le_level);
1397 gameloop("test",le_level, ST_GL_TEST);
1398 menu_set_current(&leveleditor_menu);
1400 level_load_gfx(le_current_level);
1402 le_activate_bad_guys();
1408 unsigned int i, done;
1410 " - This is SuperTux's built-in level editor -",
1411 "It has been designed to be light and easy to use from the start.",
1413 "When you first load the level editor you are given a menu where you",
1414 "can load level subsets, create a new level subset, edit the current",
1415 "subset's settings, or simply quit the editor. You can access this menu",
1416 "from the level editor at any time by pressing the escape key.",
1418 "To your right is your button bar. The center of this contains many",
1419 "tiles you can use to make your level. To select a tile, click on it",
1420 "with your left mouse button; your selection will be shown in the",
1421 "bottom right corner of the button box. Click anywhere on your level",
1422 "with the left mouse button to place that tile down. If you right click",
1423 "a tile in the button bar, you can find out what its keyboard shortcut",
1424 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1425 "background, and enemy tiles. The eraser lets you remove tiles.",
1426 "The left and right arrow keys scroll back and forth through your level.",
1427 "The button with the wrench and screwdriver, lets you change the",
1428 "settings of your level, including how long it is or what music it will",
1429 "play. When you are ready to give your level a test, click on the little",
1430 "running Tux. If you like the changes you have made to your level,",
1431 "press the red save key to keep them.",
1432 "To change which level in your subset you are editing, press the white",
1433 "up and down arrow keys at the top of the button box.",
1435 "Have fun making levels! If you make some good ones, send them to us on",
1436 "the SuperTux mailing list!",
1441 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1443 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1444 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1446 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1454 while(SDL_PollEvent(&event))
1457 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1458 case SDL_KEYDOWN: // key pressed