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);
74 void le_new_subset(char *subset_name);
76 void le_highlight_selection();
78 void apply_level_settings_menu();
79 void update_subset_settings_menu();
80 void save_subset_settings_menu();
81 void le_update_buttons(char*);
83 /* leveleditor internals */
84 static string_list_type level_subsets;
85 static int le_level_changed; /* if changes, ask for saving, when quiting*/
86 static int pos_x, cursor_x, cursor_y, cursor_tile, fire;
88 static st_level* le_current_level;
89 static st_subset le_level_subset;
90 static int le_show_grid;
92 static texture_type le_selection;
94 static char le_current_tile;
95 static int le_mouse_pressed[2];
96 static button_type le_save_level_bt;
97 static button_type le_test_level_bt;
98 static button_type le_next_level_bt;
99 static button_type le_previous_level_bt;
100 static button_type le_move_right_bt;
101 static button_type le_move_left_bt;
102 static button_type le_rubber_bt;
103 static button_type le_select_mode_one_bt;
104 static button_type le_select_mode_two_bt;
105 static button_type le_settings_bt;
106 static button_type le_bad_bt;
107 static button_type le_bkgd_bt;
108 static button_type le_fgd_bt;
109 static button_panel_type le_bkgd_panel;
110 static button_panel_type le_fgd_panel;
111 static button_panel_type le_bad_panel;
112 static menu_type leveleditor_menu;
113 static menu_type subset_load_menu;
114 static menu_type subset_new_menu;
115 static menu_type subset_settings_menu;
116 static menu_type level_settings_menu;
118 static square selection;
119 static int le_selection_mode;
120 static SDL_Event event;
122 void le_activate_bad_guys(void)
126 /* Activate bad guys: */
128 /* as oposed to the gameloop.c func, this one doesn't remove
129 the badguys from tiles */
131 for (y = 0; y < 15; ++y)
132 for (x = 0; x < le_current_level->width; ++x)
133 if (le_current_level->tiles[y][x] >= '0' && le_current_level->tiles[y][x] <= '9')
134 add_bad_guy(x * 32, y * 32, le_current_level->tiles[y][x] - '0');
137 void le_set_defaults()
139 if(le_current_level != NULL)
143 if(le_current_level->time_left == 0)
144 le_current_level->time_left = 255;
148 int leveleditor(int levelnb)
150 int last_time, now_time, i;
158 clearscreen(0, 0, 0);
161 while (SDL_PollEvent(&event))
166 last_time = SDL_GetTicks();
171 if(le_current_level != NULL)
173 /* making events results to be in order */
176 if(pos_x > (le_current_level->width * 32) - screen->w)
177 pos_x = (le_current_level->width * 32) - screen->w;
183 clearscreen(0, 0, 0);
185 /* draw editor interface */
190 menu_process_current();
191 if(current_menu == &leveleditor_menu)
193 switch (menu_check(&leveleditor_menu))
199 update_subset_settings_menu();
202 done = DONE_LEVELEDITOR;
206 else if(current_menu == &level_settings_menu)
208 switch (menu_check(&level_settings_menu))
211 apply_level_settings_menu();
212 menu_set_current(&leveleditor_menu);
219 else if(current_menu == &subset_load_menu)
221 switch (i = menu_check(&subset_load_menu))
228 subset_load(&le_level_subset,level_subsets.item[i-2]);
229 leveleditor_menu.item[3].kind = MN_GOTO;
233 le_current_level = (st_level*) malloc(sizeof(st_level));
234 if(level_load(le_current_level, le_level_subset.name, le_level) != 0)
239 le_update_buttons(le_current_level->theme);
241 level_load_gfx(le_current_level);
242 le_activate_bad_guys();
248 else if(current_menu == &subset_new_menu)
250 if(subset_new_menu.item[2].input[0] == '\0')
251 subset_new_menu.item[3].kind = MN_DEACTIVE;
254 subset_new_menu.item[3].kind = MN_ACTION;
256 switch (i = menu_check(&subset_new_menu))
259 le_new_subset(subset_new_menu.item[2].input);
260 subset_load(&le_level_subset,subset_new_menu.item[2].input);
261 leveleditor_menu.item[3].kind = MN_GOTO;
265 le_current_level = (st_level*) malloc(sizeof(st_level));
266 if(level_load(le_current_level, le_level_subset.name, le_level) != 0)
271 le_update_buttons(le_current_level->theme);
273 level_load_gfx(le_current_level);
274 le_activate_bad_guys();
275 menu_item_change_input(&subset_new_menu.item[2],"");
281 else if(current_menu == &subset_settings_menu)
283 if(strcmp(le_level_subset.title,subset_settings_menu.item[2].input) == 0 && strcmp(le_level_subset.description,subset_settings_menu.item[3].input) == 0 )
284 subset_settings_menu.item[5].kind = MN_DEACTIVE;
286 subset_settings_menu.item[5].kind = MN_ACTION;
288 switch (i = menu_check(&subset_settings_menu))
291 save_subset_settings_menu();
304 if(done == DONE_QUIT)
311 now_time = SDL_GetTicks();
312 if (now_time < last_time + FPS)
313 SDL_Delay(last_time + FPS - now_time); /* delay some time */
321 void le_default_level(st_level* plevel)
324 strcpy(plevel->name,"UnNamed");
325 strcpy(plevel->theme,"antarctica");
326 strcpy(plevel->song_title,"Mortimers_chipdisko.mod");
327 strcpy(plevel->bkgd_image,"arctis.png");
329 plevel->time_left = 100;
330 plevel->gravity = 10.;
331 plevel->bkgd_red = 0;
332 plevel->bkgd_green = 0;
333 plevel->bkgd_blue = 0;
335 for(i = 0; i < 15; ++i)
337 plevel->tiles[i] = (unsigned char*) malloc((plevel->width+1)*sizeof(unsigned char));
338 plevel->tiles[i][plevel->width] = (unsigned char) '\0';
339 for(y = 0; y < plevel->width; ++y)
340 plevel->tiles[i][y] = (unsigned char) '.';
341 plevel->tiles[i][plevel->width] = (unsigned char) '\0';
345 void le_new_subset(char *subset_name)
348 st_subset new_subset;
349 new_subset.name = (char*) malloc((strlen(subset_name)+1)*sizeof(char));
350 strcpy(new_subset.name,subset_name);
351 new_subset.title = (char*) malloc((strlen("Unknown Title")+1)*sizeof(char));
352 strcpy(new_subset.title,"Unknown Title");
353 new_subset.description = (char*) malloc((strlen("No description so far.")+1)*sizeof(char));
354 strcpy(new_subset.description,"No description so far.");
355 subset_save(&new_subset);
356 le_default_level(&new_lev);
357 level_save(&new_lev,subset_name,1);
360 void le_update_buttons(char *theme)
366 string_list_type bkgd_files;
367 string_list_type fgd_files;
369 sprintf(pathname,"images/themes/%s",theme);
370 bkgd_files = dfiles(pathname,"bkgd-", NULL);
371 string_list_sort(&bkgd_files);
373 le_bkgd_panel.hidden = YES;
375 for(i = 0; i < bkgd_files.num_items; ++i)
377 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
378 button_change_icon(&le_bkgd_panel.item[i],filename);
381 sprintf(pathname,"images/themes/%s",theme);
382 fgd_files = dfiles(pathname,"solid", NULL);
383 string_list_sort(&fgd_files);
385 for(i = 0; i < fgd_files.num_items; ++i)
387 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
388 button_change_icon(&le_fgd_panel.item[i],filename);
391 string_list_free(&fgd_files);
392 fgd_files = dfiles(pathname,"brick", NULL);
393 string_list_sort(&fgd_files);
395 for(i = 0; i < fgd_files.num_items; ++i)
397 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
398 button_change_icon(&le_fgd_panel.item[i+14],filename);
408 string_list_type fgd_files;
409 string_list_type bkgd_files;
410 string_list_type bad_files;
411 level_subsets = dsubdirs("/levels", "info");
415 /* level_changed = NO;*/
418 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
419 le_level_changed = NO;
421 subset_init(&le_level_subset);
423 le_current_level = NULL;
425 le_current_tile = '.';
426 le_mouse_pressed[LEFT] = NO;
427 le_mouse_pressed[RIGHT] = NO;
429 texture_load(&le_selection,DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA);
432 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
433 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
434 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
435 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
436 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
437 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
438 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
439 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
440 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
441 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
442 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
443 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
444 button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
446 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
447 string_list_sort(&bkgd_files);
449 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
450 le_bkgd_panel.hidden = YES;
452 for(i = 0; i < bkgd_files.num_items; ++i)
454 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
455 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
458 string_list_free(&bkgd_files);
459 bkgd_files = dfiles("images/shared","cloud-", NULL);
460 string_list_sort(&bkgd_files);
462 for(i = 0; i < bkgd_files.num_items; ++i)
464 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
465 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
468 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
469 string_list_sort(&fgd_files);
471 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
472 for(i = 0; i < fgd_files.num_items; ++i)
474 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
475 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
478 string_list_free(&fgd_files);
479 string_list_add_item(&fgd_files,"waves-0.png");
480 string_list_add_item(&fgd_files,"water.png");
481 string_list_add_item(&fgd_files,"pole.png");
482 string_list_add_item(&fgd_files,"poletop.png");
483 string_list_add_item(&fgd_files,"flag-0.png");
484 string_list_add_item(&fgd_files,"box-empty.png");
485 string_list_add_item(&fgd_files,"mints.png");
486 string_list_add_item(&fgd_files,"distro-0.png");
487 string_list_add_item(&fgd_files,"golden-herring.png");
488 string_list_add_item(&fgd_files,"distro-0.png");
490 for(i = 0; i < fgd_files.num_items; ++i)
492 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
493 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
496 string_list_free(&fgd_files);
497 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
498 string_list_sort(&fgd_files);
500 for(i = 0; i < fgd_files.num_items; ++i)
502 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
503 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
506 string_list_free(&fgd_files);
507 string_list_add_item(&fgd_files,"distro-0.png");
508 string_list_add_item(&fgd_files,"distro-0.png");
509 for(i = 0; i < fgd_files.num_items; ++i)
511 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
512 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
515 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
516 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
517 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
518 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
519 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
522 string_list_init(&bad_files);
523 string_list_add_item(&bad_files,"bsod-left-0.png");
524 string_list_add_item(&bad_files,"laptop-left-0.png");
525 string_list_add_item(&bad_files,"bag-left-0.png");
526 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
527 le_bad_panel.hidden = YES;
529 for(i = 0; i < bad_files.num_items; ++i)
531 sprintf(filename,"images/shared/%s",bad_files.item[i]);
532 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
535 menu_init(&leveleditor_menu);
536 menu_additem(&leveleditor_menu,menu_item_create(MN_LABEL,"Level Editor Menu",0,0));
537 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
538 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Return To Level Editor",0,0));
539 menu_additem(&leveleditor_menu,menu_item_create(MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu));
540 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"Load Level Subset",0,&subset_load_menu));
541 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"New Level Subset",0,&subset_new_menu));
542 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
543 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Quit Level Editor",0,0));
546 menu_set_current(&leveleditor_menu);
549 menu_init(&subset_load_menu);
550 menu_additem(&subset_load_menu,menu_item_create(MN_LABEL,"Load Level Subset",0,0));
551 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
552 for(i = 0; i < level_subsets.num_items; ++i)
554 menu_additem(&subset_load_menu,menu_item_create(MN_ACTION,level_subsets.item[i],0,0));
556 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
557 menu_additem(&subset_load_menu,menu_item_create(MN_BACK,"Back",0,0));
559 menu_init(&subset_new_menu);
560 menu_additem(&subset_new_menu,menu_item_create(MN_LABEL,"New Level Subset",0,0));
561 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
562 menu_additem(&subset_new_menu,menu_item_create(MN_TEXTFIELD,"Enter Name",0,0));
563 menu_additem(&subset_new_menu,menu_item_create(MN_ACTION,"Create",0,0));
564 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
565 menu_additem(&subset_new_menu,menu_item_create(MN_BACK,"Back",0,0));
567 menu_init(&subset_settings_menu);
568 menu_additem(&subset_settings_menu,menu_item_create(MN_LABEL,"Level Subset Settings",0,0));
569 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
570 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Title",0,0));
571 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Description",0,0));
572 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
573 menu_additem(&subset_settings_menu,menu_item_create(MN_ACTION,"Save Changes",0,0));
574 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
575 menu_additem(&subset_settings_menu,menu_item_create(MN_BACK,"Back",0,0));
577 menu_init(&level_settings_menu);
578 level_settings_menu.arrange_left = YES;
579 menu_additem(&level_settings_menu,menu_item_create(MN_LABEL,"Level Settings",0,0));
580 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
581 menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Name ",0,0));
582 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Theme ",0,0));
583 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Song ",0,0));
584 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Bg-Image",0,0));
585 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Length ",0,0));
586 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Time ",0,0));
587 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Gravity",0,0));
588 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Red ",0,0));
589 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Green ",0,0));
590 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Blue ",0,0));
591 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
592 menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Apply Changes",0,0));
594 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
599 void update_level_settings_menu()
604 menu_item_change_input(&level_settings_menu.item[2], le_current_level->name);
605 sprintf(str,"%d",le_current_level->width);
607 string_list_copy(level_settings_menu.item[3].list, dsubdirs("images/themes", "solid0.png"));
608 string_list_copy(level_settings_menu.item[4].list, dfiles("music/",NULL, "-fast"));
609 string_list_copy(level_settings_menu.item[5].list, dfiles("images/background",NULL, NULL));
610 string_list_add_item(level_settings_menu.item[5].list,"");
611 if((i = string_list_find(level_settings_menu.item[3].list,le_current_level->theme)) != -1)
612 level_settings_menu.item[3].list->active_item = i;
613 if((i = string_list_find(level_settings_menu.item[4].list,le_current_level->song_title)) != -1)
614 level_settings_menu.item[4].list->active_item = i;
615 if((i = string_list_find(level_settings_menu.item[5].list,le_current_level->bkgd_image)) != -1)
616 level_settings_menu.item[5].list->active_item = i;
618 menu_item_change_input(&level_settings_menu.item[6], str);
619 sprintf(str,"%d",le_current_level->time_left);
620 menu_item_change_input(&level_settings_menu.item[7], str);
621 sprintf(str,"%2.0f",le_current_level->gravity);
622 menu_item_change_input(&level_settings_menu.item[8], str);
623 sprintf(str,"%d",le_current_level->bkgd_red);
624 menu_item_change_input(&level_settings_menu.item[9], str);
625 sprintf(str,"%d",le_current_level->bkgd_green);
626 menu_item_change_input(&level_settings_menu.item[10], str);
627 sprintf(str,"%d",le_current_level->bkgd_blue);
628 menu_item_change_input(&level_settings_menu.item[11], str);
631 void update_subset_settings_menu()
633 menu_item_change_input(&subset_settings_menu.item[2], le_level_subset.title);
634 menu_item_change_input(&subset_settings_menu.item[3], le_level_subset.description);
637 void apply_level_settings_menu()
642 strcpy(le_current_level->name,level_settings_menu.item[2].input);
644 if(strcmp(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list)) != 0)
646 strcpy(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list));
650 if(strcmp(le_current_level->theme,string_list_active(level_settings_menu.item[3].list)) != 0)
652 strcpy(le_current_level->theme,string_list_active(level_settings_menu.item[3].list));
653 le_update_buttons(le_current_level->theme);
660 level_load_gfx(le_current_level);
663 strcpy(le_current_level->song_title,string_list_active(level_settings_menu.item[4].list));
665 i = le_current_level->width;
666 le_current_level->width = atoi(level_settings_menu.item[6].input);
667 if(le_current_level->width < i)
669 if(le_current_level->width < 21)
670 le_current_level->width = 21;
671 for(y = 0; y < 15; ++y)
673 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
674 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
677 else if(le_current_level->width > i)
679 for(y = 0; y < 15; ++y)
681 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
682 for(j = 0; j < le_current_level->width - i; ++j)
683 le_current_level->tiles[y][i+j] = (unsigned char) '.';
684 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
687 le_current_level->time_left = atoi(level_settings_menu.item[7].input);
688 le_current_level->gravity = atof(level_settings_menu.item[8].input);
689 le_current_level->bkgd_red = atoi(level_settings_menu.item[9].input);
690 le_current_level->bkgd_green = atoi(level_settings_menu.item[10].input);
691 le_current_level->bkgd_blue = atoi(level_settings_menu.item[11].input);
694 void save_subset_settings_menu()
696 free(le_level_subset.title);
697 le_level_subset.title = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[2].input)+1));
698 strcpy(le_level_subset.title,subset_settings_menu.item[2].input);
699 free(le_level_subset.description);
700 le_level_subset.description = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[3].input)+1));
701 strcpy(le_level_subset.description,subset_settings_menu.item[3].input);
702 subset_save(&le_level_subset);
705 void le_goto_level(int levelnb)
710 level_free(le_current_level);
711 if(level_load(le_current_level, le_level_subset.name, levelnb) != 0)
713 level_load(le_current_level, le_level_subset.name, le_level);
722 le_update_buttons(le_current_level->theme);
725 level_load_gfx(le_current_level);
727 le_activate_bad_guys();
732 /*if(level_changed == YES)
733 if(askforsaving() == CANCEL)
736 SDL_EnableKeyRepeat(0, 0); // disables key repeating
738 texture_free(&le_selection);
739 menu_free(&leveleditor_menu);
740 menu_free(&subset_load_menu);
741 menu_free(&subset_new_menu);
742 menu_free(&subset_settings_menu);
743 menu_free(&level_settings_menu);
744 button_panel_free(&le_bkgd_panel);
745 button_panel_free(&le_fgd_panel);
746 button_panel_free(&le_bad_panel);
747 button_free(&le_save_level_bt);
748 button_free(&le_test_level_bt);
749 button_free(&le_next_level_bt);
750 button_free(&le_previous_level_bt);
751 button_free(&le_move_right_bt);
752 button_free(&le_move_left_bt);
753 button_free(&le_rubber_bt);
754 button_free(&le_select_mode_one_bt);
755 button_free(&le_select_mode_two_bt);
756 button_free(&le_settings_bt);
757 button_free(&le_bad_bt);
758 button_free(&le_bkgd_bt);
759 button_free(&le_fgd_bt);
761 if(le_current_level != NULL)
764 level_free(le_current_level);
770 void le_drawinterface()
775 if(le_current_level != NULL)
777 /* draw a grid (if selected) */
780 for(x = 0; x < 19; x++)
781 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
782 for(y = 0; y < 15; y++)
783 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
787 if(le_selection_mode == CURSOR)
788 texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
789 else if(le_selection_mode == SQUARE)
792 le_highlight_selection();
793 /* draw current selection */
794 w = selection.x2 - selection.x1;
795 h = selection.y2 - selection.y1;
796 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
797 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
798 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
799 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
803 /* draw button bar */
804 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
805 drawshape(19 * 32, 14 * 32, le_current_tile);
806 switch(le_current_tile)
809 texture_draw(&img_mints, 19 * 32, 14 * 32, NO_UPDATE);
812 texture_draw(&img_golden_herring,19 * 32, 14 * 32, NO_UPDATE);
817 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32, NO_UPDATE);
820 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32, NO_UPDATE);
823 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32, NO_UPDATE);
826 texture_draw(&img_money_left[0],19 * 32, 14 * 32, NO_UPDATE);
832 if(le_current_level != NULL)
834 button_draw(&le_save_level_bt);
835 button_draw(&le_test_level_bt);
836 button_draw(&le_next_level_bt);
837 button_draw(&le_previous_level_bt);
838 button_draw(&le_rubber_bt);
839 button_draw(&le_select_mode_one_bt);
840 button_draw(&le_select_mode_two_bt);
841 button_draw(&le_settings_bt);
842 button_draw(&le_move_right_bt);
843 button_draw(&le_move_left_bt);
844 button_draw(&le_bad_bt);
845 button_draw(&le_bkgd_bt);
846 button_draw(&le_fgd_bt);
847 button_panel_draw(&le_bkgd_panel);
848 button_panel_draw(&le_fgd_panel);
849 button_panel_draw(&le_bad_panel);
851 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
852 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_NONE, 1, NO_UPDATE);
854 text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
859 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
861 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
869 static char str[LEVEL_NAME_MAX];
871 /* Draw the real background */
872 if(le_current_level->bkgd_image[0] != '\0')
875 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h, NO_UPDATE);
876 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h, NO_UPDATE);
880 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
883 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
885 for (y = 0; y < 15; ++y)
886 for (x = 0; x < 20; ++x)
888 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
890 /* draw whats inside stuff when cursor is selecting those */
891 /* (draw them all the time - is this the right behaviour?) */
892 switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
895 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
898 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
903 texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
910 /* Draw the Bad guys: */
911 for (i = 0; i < num_bad_guys; ++i)
913 if(bad_guys[i].base.alive == NO)
915 /* to support frames: img_bsod_left[(frame / 5) % 4] */
916 if(bad_guys[i].kind == BAD_BSOD)
917 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
918 else if(bad_guys[i].kind == BAD_LAPTOP)
919 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
920 else if (bad_guys[i].kind == BAD_MONEY)
921 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
925 /* Draw the player: */
926 /* for now, the position is fixed at (0, 240) */
927 texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240, NO_UPDATE);
930 void le_checkevents()
934 button_type* pbutton;
937 keymod = SDL_GetModState();
939 while(SDL_PollEvent(&event))
941 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
942 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
943 event.motion.y > 0 && event.motion.y < screen->h)))
948 case SDL_KEYDOWN: // key pressed
949 key = event.key.keysym.sym;
952 menu_event(&event.key.keysym);
953 if(key == SDLK_ESCAPE)
956 menu_set_current(&leveleditor_menu);
970 cursor_x -= KEY_CURSOR_SPEED;
972 cursor_x -= KEY_CURSOR_FASTSPEED;
974 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
975 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
980 cursor_x += KEY_CURSOR_SPEED;
982 cursor_x += KEY_CURSOR_FASTSPEED;
984 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
985 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
990 cursor_y -= KEY_CURSOR_SPEED;
992 cursor_y -= KEY_CURSOR_FASTSPEED;
999 cursor_y += KEY_CURSOR_SPEED;
1001 cursor_y += KEY_CURSOR_FASTSPEED;
1003 if(cursor_y > screen->h-32)
1004 cursor_y = screen->h-32;
1017 cursor_x = (le_current_level->width * 32) - 32;
1021 le_show_grid = !le_show_grid;
1027 case SDL_KEYUP: /* key released */
1028 switch(event.key.keysym.sym)
1037 case SDL_MOUSEBUTTONDOWN:
1038 if(event.button.button == SDL_BUTTON_LEFT)
1040 le_mouse_pressed[LEFT] = YES;
1042 selection.x1 = event.motion.x + pos_x;
1043 selection.y1 = event.motion.y;
1044 selection.x2 = event.motion.x + pos_x;
1045 selection.y2 = event.motion.y;
1047 else if(event.button.button == SDL_BUTTON_RIGHT)
1048 le_mouse_pressed[RIGHT] = YES;
1050 case SDL_MOUSEBUTTONUP:
1051 if(event.button.button == SDL_BUTTON_LEFT)
1052 le_mouse_pressed[LEFT] = NO;
1053 else if(event.button.button == SDL_BUTTON_RIGHT)
1054 le_mouse_pressed[RIGHT] = NO;
1056 case SDL_MOUSEMOTION:
1062 cursor_x = ((int)(pos_x + x) / 32) * 32;
1063 cursor_y = ((int) y / 32) * 32;
1065 if(le_mouse_pressed[LEFT] == YES)
1067 selection.x2 = x + pos_x;
1071 if(le_mouse_pressed[RIGHT] == YES)
1073 pos_x += -1 * event.motion.xrel;
1077 case SDL_QUIT: // window closed
1085 if(le_current_level != NULL)
1087 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 &&
1088 event.motion.y > 0 && event.motion.y < screen->h)))
1090 le_mouse_pressed[LEFT] = NO;
1091 le_mouse_pressed[RIGHT] = NO;
1095 /* Check for button events */
1096 button_event(&le_test_level_bt,&event);
1097 if(button_get_state(&le_test_level_bt) == BN_CLICKED)
1099 button_event(&le_save_level_bt,&event);
1100 if(button_get_state(&le_save_level_bt) == BN_CLICKED)
1101 level_save(le_current_level,le_level_subset.name,le_level);
1102 button_event(&le_next_level_bt,&event);
1103 if(button_get_state(&le_next_level_bt) == BN_CLICKED)
1105 if(le_level < le_level_subset.levels)
1107 le_goto_level(++le_level);
1114 sprintf(str,"Level %d doesn't exist.",le_level+1);
1115 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1116 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1117 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1121 while(SDL_PollEvent(&event))
1124 case SDL_KEYDOWN: // key pressed
1125 switch(event.key.keysym.sym)
1128 le_default_level(&new_lev);
1129 level_save(&new_lev,le_level_subset.name,++le_level);
1130 le_level_subset.levels = le_level;
1131 le_goto_level(le_level);
1146 button_event(&le_previous_level_bt,&event);
1147 if(button_get_state(&le_previous_level_bt) == BN_CLICKED)
1150 le_goto_level(--le_level);
1152 button_event(&le_rubber_bt,&event);
1153 if(button_get_state(&le_rubber_bt) == BN_CLICKED)
1154 le_current_tile = '.';
1155 button_event(&le_select_mode_one_bt,&event);
1156 if(button_get_state(&le_select_mode_one_bt) == BN_CLICKED)
1157 le_selection_mode = CURSOR;
1158 button_event(&le_select_mode_two_bt,&event);
1159 if(button_get_state(&le_select_mode_two_bt) == BN_CLICKED)
1160 le_selection_mode = SQUARE;
1162 button_event(&le_bad_bt,&event);
1163 if(button_get_state(&le_bad_bt) == BN_CLICKED)
1165 le_bad_panel.hidden = NO;
1166 le_fgd_panel.hidden = YES;
1167 le_bkgd_panel.hidden = YES;
1170 button_event(&le_fgd_bt,&event);
1171 if(button_get_state(&le_fgd_bt) == BN_CLICKED)
1173 le_bad_panel.hidden = YES;
1174 le_fgd_panel.hidden = NO;
1175 le_bkgd_panel.hidden = YES;
1177 button_event(&le_bkgd_bt,&event);
1178 if(button_get_state(&le_bkgd_bt) == BN_CLICKED)
1180 le_bad_panel.hidden = YES;
1181 le_fgd_panel.hidden = YES;
1182 le_bkgd_panel.hidden = NO;
1184 button_event(&le_settings_bt,&event);
1185 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1189 update_level_settings_menu();
1190 menu_set_current(&level_settings_menu);
1195 menu_set_current(&leveleditor_menu);
1199 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1201 if(button_get_state(pbutton) == BN_CLICKED)
1204 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1205 c = 'G' + pbutton->tag;
1206 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1207 c = 'g' + pbutton->tag - 4;
1208 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1209 c = 'C' + pbutton->tag - 8;
1210 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1211 c = 'c' + pbutton->tag - 12;
1213 le_current_tile = c;
1216 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1218 if(button_get_state(pbutton) == BN_CLICKED)
1221 if(pbutton->tag == 0)
1223 else if(pbutton->tag == 1)
1225 else if(pbutton->tag == 2)
1227 else if(pbutton->tag == 3)
1229 else if(pbutton->tag == 4)
1231 else if(pbutton->tag == 5)
1233 else if(pbutton->tag == 6)
1235 else if(pbutton->tag == 7)
1237 else if(pbutton->tag == 8)
1239 else if(pbutton->tag == 9)
1241 else if(pbutton->tag == 10)
1243 else if(pbutton->tag == 11)
1245 else if(pbutton->tag == 12)
1247 else if(pbutton->tag == 13)
1249 else if(pbutton->tag == 14)
1251 else if(pbutton->tag == 15)
1253 else if(pbutton->tag == 16)
1255 else if(pbutton->tag == 17)
1258 le_current_tile = c;
1261 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1263 if(button_get_state(pbutton) == BN_CLICKED)
1266 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1267 c = '0' + pbutton->tag;
1269 le_current_tile = c;
1275 button_event(&le_settings_bt,&event);
1276 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1280 update_level_settings_menu();
1281 menu_set_current(&level_settings_menu);
1286 menu_set_current(&leveleditor_menu);
1294 button_event(&le_move_left_bt,&event);
1295 button_event(&le_move_right_bt,&event);
1297 if(le_mouse_pressed[LEFT])
1299 le_change(cursor_x, cursor_y, le_current_tile);
1306 if(button_get_state(&le_move_left_bt) == BN_PRESSED)
1310 else if(button_get_state(&le_move_left_bt) == BN_HOVER)
1315 if(button_get_state(&le_move_right_bt) == BN_PRESSED)
1319 else if(button_get_state(&le_move_right_bt) == BN_HOVER)
1327 void le_highlight_selection()
1332 if(selection.x1 < selection.x2)
1342 if(selection.y1 < selection.y2)
1358 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1361 void le_change(float x, float y, unsigned char c)
1363 if(le_current_level != NULL)
1368 /* level_changed = YES; */
1370 switch(le_selection_mode)
1373 level_change(le_current_level,x,y,c);
1378 /* if there is a bad guy over there, remove it */
1379 for(i = 0; i < num_bad_guys; ++i)
1380 if (bad_guys[i].base.alive)
1381 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1382 bad_guys[i].base.alive = NO;
1384 if(c == '0') /* if it's a bad guy */
1385 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1387 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1389 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1393 if(selection.x1 < selection.x2)
1403 if(selection.y1 < selection.y2)
1419 /* if there is a bad guy over there, remove it */
1420 for(i = 0; i < num_bad_guys; ++i)
1421 if(bad_guys[i].base.alive)
1422 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1423 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1424 bad_guys[i].base.alive = NO;
1426 for(xx = x1; xx <= x2; xx++)
1427 for(yy = y1; yy <= y2; yy++)
1429 level_change(le_current_level, xx*32, yy*32, c);
1431 if(c == '0') // if it's a bad guy
1432 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1434 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1436 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1447 level_save(le_current_level,"test",le_level);
1448 gameloop("test",le_level, ST_GL_TEST);
1449 menu_set_current(&leveleditor_menu);
1451 level_load_gfx(le_current_level);
1453 le_activate_bad_guys();
1461 " - This is SuperTux's built-in level editor -",
1462 "It has been designed to be light and easy to use from the start.",
1464 "When you first load the level editor you are given a menu where you",
1465 "can load level subsets, create a new level subset, edit the current",
1466 "subset's settings, or simply quit the editor. You can access this menu",
1467 "from the level editor at any time by pressing the escape key.",
1469 "To your right is your button bar. The center of this contains many",
1470 "tiles you can use to make your level. To select a tile, click on it",
1471 "with your left mouse button; your selection will be shown in the",
1472 "bottom right corner of the button box. Click anywhere on your level",
1473 "with the left mouse button to place that tile down. If you right click",
1474 "a tile in the button bar, you can find out what its keyboard shortcut",
1475 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1476 "background, and enemy tiles. The eraser lets you remove tiles.",
1477 "The left and right arrow keys scroll back and forth through your level.",
1478 "The button with the wrench and screwdriver, lets you change the",
1479 "settings of your level, including how long it is or what music it will",
1480 "play. When you are ready to give your level a test, click on the little",
1481 "running Tux. If you like the changes you have made to your level,",
1482 "press the red save key to keep them.",
1483 "To change which level in your subset you are editing, press the white",
1484 "up and down arrow keys at the top of the button box.",
1486 "Have fun making levels! If you make some good ones, send them to us on",
1487 "the SuperTux mailing list!",
1492 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2, NO_UPDATE);
1494 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1495 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1, NO_UPDATE);
1497 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1505 while(SDL_PollEvent(&event))
1508 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1509 case SDL_KEYDOWN: // key pressed