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 - February 1st, 2004 */
12 /* leveleditor.c - A built-in level editor for SuperTux
13 by Ricardo Cruz <rick2@aeiou.pt> */
21 #include <SDL_image.h>
22 #include "leveleditor.h"
34 /* definitions to aid development */
35 #define DONE_LEVELEDITOR 1
37 #define DONE_CHANGELEVEL 3
39 /* definitions that affect gameplay */
40 #define KEY_CURSOR_SPEED 32
41 #define KEY_CURSOR_FASTSPEED 64
43 /* when pagedown/up pressed speed:*/
44 #define PAGE_CURSOR_SPEED 13*32
46 #define MOUSE_LEFT_MARGIN 80
47 #define MOUSE_RIGHT_MARGIN (560-32)
48 /* right_margin should noticed that the cursor is 32 pixels,
49 so it should subtract that value */
50 #define MOUSE_POS_SPEED 20
53 #define SELECT_W 2 // size of the selections lines
54 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
56 /* gameloop funcs declerations */
58 void loadshared(void);
59 void unloadshared(void);
61 /* own declerations */
62 /* crutial ones (main loop) */
66 void le_drawinterface();
67 void le_checkevents();
68 void le_change(float x, float y, unsigned char c);
71 void le_set_defaults(void);
72 void le_activate_bad_guys(void);
73 void le_new_subset(char *subset_name);
75 void le_highlight_selection();
77 void apply_level_settings_menu();
78 void update_subset_settings_menu();
79 void save_subset_settings_menu();
81 /* leveleditor internals */
82 static string_list_type level_subsets;
83 static int le_level_changed; /* if changes, ask for saving, when quiting*/
84 static int pos_x, cursor_x, cursor_y, cursor_tile, fire;
86 static st_level* le_current_level;
87 static st_subset le_level_subset;
88 static int le_show_grid;
90 static texture_type le_selection;
92 static char le_current_tile;
93 static int le_mouse_pressed[2];
94 static button_type le_save_level_bt;
95 static button_type le_test_level_bt;
96 static button_type le_next_level_bt;
97 static button_type le_previous_level_bt;
98 static button_type le_move_right_bt;
99 static button_type le_move_left_bt;
100 static button_type le_rubber_bt;
101 static button_type le_select_mode_one_bt;
102 static button_type le_select_mode_two_bt;
103 static button_type le_settings_bt;
104 static button_type le_bad_bt;
105 static button_type le_bkgd_bt;
106 static button_type le_fgd_bt;
107 static button_panel_type le_bkgd_panel;
108 static button_panel_type le_fgd_panel;
109 static button_panel_type le_bad_panel;
110 static menu_type leveleditor_menu;
111 static menu_type subset_load_menu;
112 static menu_type subset_new_menu;
113 static menu_type subset_settings_menu;
114 static menu_type level_settings_menu;
116 static square selection;
117 static int le_selection_mode;
118 static SDL_Event event;
120 void le_activate_bad_guys(void)
124 /* Activate bad guys: */
126 /* as oposed to the gameloop.c func, this one doesn't remove
127 the badguys from tiles */
129 for (y = 0; y < 15; ++y)
130 for (x = 0; x < le_current_level->width; ++x)
131 if (le_current_level->tiles[y][x] >= '0' && le_current_level->tiles[y][x] <= '9')
132 add_bad_guy(x * 32, y * 32, le_current_level->tiles[y][x] - '0');
135 void le_set_defaults()
137 if(le_current_level != NULL)
141 if(le_current_level->time_left == 0)
142 le_current_level->time_left = 255;
146 int leveleditor(int levelnb)
148 int last_time, now_time, i;
156 clearscreen(0, 0, 0);
159 while (SDL_PollEvent(&event))
164 last_time = SDL_GetTicks();
169 if(le_current_level != NULL)
171 /* making events results to be in order */
174 if(pos_x > (le_current_level->width * 32) - screen->w)
175 pos_x = (le_current_level->width * 32) - screen->w;
181 clearscreen(0, 0, 0);
183 /* draw editor interface */
188 menu_process_current();
189 if(current_menu == &leveleditor_menu)
191 switch (menu_check(&leveleditor_menu))
197 update_subset_settings_menu();
200 done = DONE_LEVELEDITOR;
204 else if(current_menu == &level_settings_menu)
206 switch (menu_check(&level_settings_menu))
209 apply_level_settings_menu();
210 menu_set_current(&leveleditor_menu);
217 else if(current_menu == &subset_load_menu)
219 switch (i = menu_check(&subset_load_menu))
226 subset_load(&le_level_subset,level_subsets.item[i-2]);
227 leveleditor_menu.item[3].kind = MN_GOTO;
231 le_current_level = (st_level*) malloc(sizeof(st_level));
232 if(level_load(le_current_level, le_level_subset.name, le_level) != 0)
237 le_update_buttons(le_current_level->theme);
239 level_load_gfx(le_current_level);
240 le_activate_bad_guys();
246 else if(current_menu == &subset_new_menu)
248 if(subset_new_menu.item[2].input[0] == '\0')
249 subset_new_menu.item[3].kind = MN_DEACTIVE;
252 subset_new_menu.item[3].kind = MN_ACTION;
254 switch (i = menu_check(&subset_new_menu))
257 le_new_subset(subset_new_menu.item[2].input);
258 subset_load(&le_level_subset,subset_new_menu.item[2].input);
259 leveleditor_menu.item[3].kind = MN_GOTO;
263 le_current_level = (st_level*) malloc(sizeof(st_level));
264 if(level_load(le_current_level, le_level_subset.name, le_level) != 0)
269 le_update_buttons(le_current_level->theme);
271 level_load_gfx(le_current_level);
272 le_activate_bad_guys();
273 menu_item_change_input(&subset_new_menu.item[2],"");
279 else if(current_menu == &subset_settings_menu)
281 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 )
282 subset_settings_menu.item[5].kind = MN_DEACTIVE;
284 subset_settings_menu.item[5].kind = MN_ACTION;
286 switch (i = menu_check(&subset_settings_menu))
289 save_subset_settings_menu();
302 if(done == DONE_QUIT)
309 now_time = SDL_GetTicks();
310 if (now_time < last_time + FPS)
311 SDL_Delay(last_time + FPS - now_time); /* delay some time */
319 void le_default_level(st_level* plevel)
322 strcpy(plevel->name,"UnNamed");
323 strcpy(plevel->theme,"antarctica");
324 strcpy(plevel->song_title,"Mortimers_chipdisko.mod");
325 strcpy(plevel->bkgd_image,"arctis.png");
327 plevel->time_left = 100;
328 plevel->gravity = 10.;
329 plevel->bkgd_red = 0;
330 plevel->bkgd_green = 0;
331 plevel->bkgd_blue = 0;
333 for(i = 0; i < 15; ++i)
335 plevel->tiles[i] = (unsigned char*) malloc((plevel->width+1)*sizeof(unsigned char));
336 plevel->tiles[i][plevel->width] = (unsigned char) '\0';
337 for(y = 0; y < plevel->width; ++y)
338 plevel->tiles[i][y] = (unsigned char) '.';
339 plevel->tiles[i][plevel->width] = (unsigned char) '\0';
343 void le_new_subset(char *subset_name)
346 st_subset new_subset;
347 new_subset.name = (char*) malloc((strlen(subset_name)+1)*sizeof(char));
348 strcpy(new_subset.name,subset_name);
349 new_subset.title = (char*) malloc((strlen("Unknown Title")+1)*sizeof(char));
350 strcpy(new_subset.title,"Unknown Title");
351 new_subset.description = (char*) malloc((strlen("No description so far.")+1)*sizeof(char));
352 strcpy(new_subset.description,"No description so far.");
353 subset_save(&new_subset);
354 le_default_level(&new_lev);
355 level_save(&new_lev,subset_name,1);
358 le_update_buttons(char *theme)
364 string_list_type bkgd_files;
365 string_list_type fgd_files;
367 sprintf(pathname,"images/themes/%s",theme);
368 bkgd_files = dfiles(pathname,"bkgd-", NULL);
369 string_list_sort(&bkgd_files);
371 le_bkgd_panel.hidden = YES;
373 for(i = 0; i < bkgd_files.num_items; ++i)
375 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
376 button_change_icon(&le_bkgd_panel.item[i],filename);
379 sprintf(pathname,"images/themes/%s",theme);
380 fgd_files = dfiles(pathname,"solid", NULL);
381 string_list_sort(&fgd_files);
383 for(i = 0; i < fgd_files.num_items; ++i)
385 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
386 button_change_icon(&le_fgd_panel.item[i],filename);
389 string_list_free(&fgd_files);
390 fgd_files = dfiles(pathname,"brick", NULL);
391 string_list_sort(&fgd_files);
393 for(i = 0; i < fgd_files.num_items; ++i)
395 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
396 button_change_icon(&le_fgd_panel.item[i+14],filename);
406 string_list_type fgd_files;
407 string_list_type bkgd_files;
408 string_list_type bad_files;
409 level_subsets = dsubdirs("/levels", "info");
413 /* level_changed = NO;*/
416 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
417 le_level_changed = NO;
419 subset_init(&le_level_subset);
421 le_current_level = NULL;
423 le_current_tile = '.';
424 le_mouse_pressed[LEFT] = NO;
425 le_mouse_pressed[RIGHT] = NO;
427 texture_load(&le_selection,DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA);
430 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
431 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
432 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
433 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
434 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
435 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
436 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
437 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
438 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
439 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
440 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
441 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
442 button_load(&le_bad_bt,"/images/icons/bad.png","Bad guys", SDLK_F9,screen->w-22,82);
444 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
445 string_list_sort(&bkgd_files);
447 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
448 le_bkgd_panel.hidden = YES;
450 for(i = 0; i < bkgd_files.num_items; ++i)
452 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
453 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
456 string_list_free(&bkgd_files);
457 bkgd_files = dfiles("images/shared","cloud-", NULL);
458 string_list_sort(&bkgd_files);
460 for(i = 0; i < bkgd_files.num_items; ++i)
462 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
463 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
466 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
467 string_list_sort(&fgd_files);
469 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
470 for(i = 0; i < fgd_files.num_items; ++i)
472 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
473 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
476 string_list_free(&fgd_files);
477 string_list_add_item(&fgd_files,"waves-0.png");
478 string_list_add_item(&fgd_files,"water.png");
479 string_list_add_item(&fgd_files,"pole.png");
480 string_list_add_item(&fgd_files,"poletop.png");
481 string_list_add_item(&fgd_files,"flag-0.png");
482 string_list_add_item(&fgd_files,"box-empty.png");
483 string_list_add_item(&fgd_files,"mints.png");
484 string_list_add_item(&fgd_files,"distro-0.png");
485 string_list_add_item(&fgd_files,"golden-herring.png");
486 string_list_add_item(&fgd_files,"distro-0.png");
488 for(i = 0; i < fgd_files.num_items; ++i)
490 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
491 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
494 string_list_free(&fgd_files);
495 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
496 string_list_sort(&fgd_files);
498 for(i = 0; i < fgd_files.num_items; ++i)
500 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
501 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
504 string_list_free(&fgd_files);
505 string_list_add_item(&fgd_files,"distro-0.png");
506 string_list_add_item(&fgd_files,"distro-0.png");
507 for(i = 0; i < fgd_files.num_items; ++i)
509 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
510 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
513 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
514 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
515 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
516 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
517 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
520 string_list_init(&bad_files);
521 string_list_add_item(&bad_files,"bsod-left-0.png");
522 string_list_add_item(&bad_files,"laptop-left-0.png");
523 string_list_add_item(&bad_files,"bag-left-0.png");
524 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
525 le_bad_panel.hidden = YES;
527 for(i = 0; i < bad_files.num_items; ++i)
529 sprintf(filename,"images/shared/%s",bad_files.item[i]);
530 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
533 menu_init(&leveleditor_menu);
534 menu_additem(&leveleditor_menu,menu_item_create(MN_LABEL,"Level Editor Menu",0,0));
535 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
536 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Return To Level Editor",0,0));
537 menu_additem(&leveleditor_menu,menu_item_create(MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu));
538 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"Load Level Subset",0,&subset_load_menu));
539 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"New Level Subset",0,&subset_new_menu));
540 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
541 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Quit Level Editor",0,0));
544 menu_set_current(&leveleditor_menu);
547 menu_init(&subset_load_menu);
548 menu_additem(&subset_load_menu,menu_item_create(MN_LABEL,"Load Level Subset",0,0));
549 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
550 for(i = 0; i < level_subsets.num_items; ++i)
552 menu_additem(&subset_load_menu,menu_item_create(MN_ACTION,level_subsets.item[i],0,0));
554 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
555 menu_additem(&subset_load_menu,menu_item_create(MN_BACK,"Back",0,0));
557 menu_init(&subset_new_menu);
558 menu_additem(&subset_new_menu,menu_item_create(MN_LABEL,"New Level Subset",0,0));
559 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
560 menu_additem(&subset_new_menu,menu_item_create(MN_TEXTFIELD,"Enter Name",0,0));
561 menu_additem(&subset_new_menu,menu_item_create(MN_ACTION,"Create",0,0));
562 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
563 menu_additem(&subset_new_menu,menu_item_create(MN_BACK,"Back",0,0));
565 menu_init(&subset_settings_menu);
566 menu_additem(&subset_settings_menu,menu_item_create(MN_LABEL,"Level Subset Settings",0,0));
567 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
568 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Title",0,0));
569 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Description",0,0));
570 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
571 menu_additem(&subset_settings_menu,menu_item_create(MN_ACTION,"Save Changes",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_BACK,"Back",0,0));
575 menu_init(&level_settings_menu);
576 level_settings_menu.arrange_left = YES;
577 menu_additem(&level_settings_menu,menu_item_create(MN_LABEL,"Level Settings",0,0));
578 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
579 menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Name ",0,0));
580 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Theme ",0,0));
581 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Song ",0,0));
582 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Bg-Image",0,0));
583 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Length ",0,0));
584 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Time ",0,0));
585 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Gravity",0,0));
586 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Red ",0,0));
587 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Green ",0,0));
588 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Blue ",0,0));
589 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
590 menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Apply Changes",0,0));
592 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
597 void update_level_settings_menu()
602 menu_item_change_input(&level_settings_menu.item[2], le_current_level->name);
603 sprintf(str,"%d",le_current_level->width);
605 string_list_copy(level_settings_menu.item[3].list, dsubdirs("images/themes", "solid0.png"));
606 string_list_copy(level_settings_menu.item[4].list, dfiles("music/",NULL, "-fast"));
607 string_list_copy(level_settings_menu.item[5].list, dfiles("images/background",NULL, NULL));
608 if((i = string_list_find(level_settings_menu.item[3].list,le_current_level->theme)) != -1)
609 level_settings_menu.item[3].list->active_item = i;
610 if((i = string_list_find(level_settings_menu.item[4].list,le_current_level->song_title)) != -1)
611 level_settings_menu.item[4].list->active_item = i;
612 if((i = string_list_find(level_settings_menu.item[5].list,le_current_level->bkgd_image)) != -1)
613 level_settings_menu.item[5].list->active_item = i;
615 menu_item_change_input(&level_settings_menu.item[6], str);
616 sprintf(str,"%d",le_current_level->time_left);
617 menu_item_change_input(&level_settings_menu.item[7], str);
618 sprintf(str,"%2.0f",le_current_level->gravity);
619 menu_item_change_input(&level_settings_menu.item[8], str);
620 sprintf(str,"%d",le_current_level->bkgd_red);
621 menu_item_change_input(&level_settings_menu.item[9], str);
622 sprintf(str,"%d",le_current_level->bkgd_green);
623 menu_item_change_input(&level_settings_menu.item[10], str);
624 sprintf(str,"%d",le_current_level->bkgd_blue);
625 menu_item_change_input(&level_settings_menu.item[11], str);
628 void update_subset_settings_menu()
630 menu_item_change_input(&subset_settings_menu.item[2], le_level_subset.title);
631 menu_item_change_input(&subset_settings_menu.item[3], le_level_subset.description);
634 void apply_level_settings_menu()
639 strcpy(le_current_level->name,level_settings_menu.item[2].input);
641 if(strcmp(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list)) != 0)
643 strcpy(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list));
647 if(strcmp(le_current_level->theme,string_list_active(level_settings_menu.item[3].list)) != 0)
649 strcpy(le_current_level->theme,string_list_active(level_settings_menu.item[3].list));
650 le_update_buttons(le_current_level->theme);
657 level_load_gfx(le_current_level);
660 strcpy(le_current_level->song_title,string_list_active(level_settings_menu.item[4].list));
662 i = le_current_level->width;
663 le_current_level->width = atoi(level_settings_menu.item[6].input);
664 if(le_current_level->width < i)
666 if(le_current_level->width < 21)
667 le_current_level->width = 21;
668 for(y = 0; y < 15; ++y)
670 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
671 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
674 else if(le_current_level->width > i)
676 for(y = 0; y < 15; ++y)
678 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
679 for(j = 0; j < le_current_level->width - i; ++j)
680 le_current_level->tiles[y][i+j] = (unsigned char) '.';
681 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
684 le_current_level->time_left = atoi(level_settings_menu.item[7].input);
685 le_current_level->gravity = atof(level_settings_menu.item[8].input);
686 le_current_level->bkgd_red = atoi(level_settings_menu.item[9].input);
687 le_current_level->bkgd_green = atoi(level_settings_menu.item[10].input);
688 le_current_level->bkgd_blue = atoi(level_settings_menu.item[11].input);
691 void save_subset_settings_menu()
693 free(le_level_subset.title);
694 le_level_subset.title = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[2].input)+1));
695 strcpy(le_level_subset.title,subset_settings_menu.item[2].input);
696 free(le_level_subset.description);
697 le_level_subset.description = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[3].input)+1));
698 strcpy(le_level_subset.description,subset_settings_menu.item[3].input);
699 subset_save(&le_level_subset);
702 void le_goto_level(int levelnb)
707 level_free(le_current_level);
708 if(level_load(le_current_level, le_level_subset.name, levelnb) != 0)
710 level_load(le_current_level, le_level_subset.name, le_level);
719 le_update_buttons(le_current_level->theme);
722 level_load_gfx(le_current_level);
724 le_activate_bad_guys();
729 /*if(level_changed == YES)
730 if(askforsaving() == CANCEL)
733 SDL_EnableKeyRepeat(0, 0); // disables key repeating
735 texture_free(&le_selection);
736 menu_free(&leveleditor_menu);
737 menu_free(&subset_load_menu);
738 menu_free(&subset_new_menu);
739 menu_free(&subset_settings_menu);
740 menu_free(&level_settings_menu);
741 button_panel_free(&le_bkgd_panel);
742 button_panel_free(&le_fgd_panel);
743 button_panel_free(&le_bad_panel);
744 button_free(&le_save_level_bt);
745 button_free(&le_test_level_bt);
746 button_free(&le_next_level_bt);
747 button_free(&le_previous_level_bt);
748 button_free(&le_move_right_bt);
749 button_free(&le_move_left_bt);
750 button_free(&le_rubber_bt);
751 button_free(&le_select_mode_one_bt);
752 button_free(&le_select_mode_two_bt);
753 button_free(&le_settings_bt);
754 button_free(&le_bad_bt);
755 button_free(&le_bkgd_bt);
756 button_free(&le_fgd_bt);
758 if(le_current_level != NULL)
761 level_free(le_current_level);
767 void le_drawinterface()
772 if(le_current_level != NULL)
774 /* draw a grid (if selected) */
777 for(x = 0; x < 19; x++)
778 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
779 for(y = 0; y < 15; y++)
780 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
784 if(le_selection_mode == CURSOR)
785 texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
786 else if(le_selection_mode == SQUARE)
789 le_highlight_selection();
790 /* draw current selection */
791 w = selection.x2 - selection.x1;
792 h = selection.y2 - selection.y1;
793 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
794 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
795 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
796 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
800 /* draw button bar */
801 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
802 drawshape(19 * 32, 14 * 32, le_current_tile);
803 switch(le_current_tile)
806 texture_draw(&img_mints, 19 * 32, 14 * 32, NO_UPDATE);
809 texture_draw(&img_golden_herring,19 * 32, 14 * 32, NO_UPDATE);
814 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32, NO_UPDATE);
817 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32, NO_UPDATE);
820 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32, NO_UPDATE);
823 texture_draw(&img_money_left[0],19 * 32, 14 * 32, NO_UPDATE);
829 if(le_current_level != NULL)
831 button_draw(&le_save_level_bt);
832 button_draw(&le_test_level_bt);
833 button_draw(&le_next_level_bt);
834 button_draw(&le_previous_level_bt);
835 button_draw(&le_rubber_bt);
836 button_draw(&le_select_mode_one_bt);
837 button_draw(&le_select_mode_two_bt);
838 button_draw(&le_settings_bt);
839 button_draw(&le_move_right_bt);
840 button_draw(&le_move_left_bt);
841 button_draw(&le_bad_bt);
842 button_draw(&le_bkgd_bt);
843 button_draw(&le_fgd_bt);
844 button_panel_draw(&le_bkgd_panel);
845 button_panel_draw(&le_fgd_panel);
846 button_panel_draw(&le_bad_panel);
848 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
849 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_NONE, 1, NO_UPDATE);
851 text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
856 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
858 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
866 static char str[LEVEL_NAME_MAX];
868 /* Draw the real background */
869 if(le_current_level->bkgd_image[0] != '\0')
872 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h, NO_UPDATE);
873 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h, NO_UPDATE);
877 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
880 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
882 for (y = 0; y < 15; ++y)
883 for (x = 0; x < 20; ++x)
885 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
887 /* draw whats inside stuff when cursor is selecting those */
888 /* (draw them all the time - is this the right behaviour?) */
889 switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
892 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
895 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
900 texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
907 /* Draw the Bad guys: */
908 for (i = 0; i < num_bad_guys; ++i)
910 if(bad_guys[i].base.alive == NO)
912 /* to support frames: img_bsod_left[(frame / 5) % 4] */
913 if(bad_guys[i].kind == BAD_BSOD)
914 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
915 else if(bad_guys[i].kind == BAD_LAPTOP)
916 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
917 else if (bad_guys[i].kind == BAD_MONEY)
918 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
922 /* Draw the player: */
923 /* for now, the position is fixed at (0, 240) */
924 texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240, NO_UPDATE);
927 void le_checkevents()
931 button_type* pbutton;
934 keymod = SDL_GetModState();
936 while(SDL_PollEvent(&event))
938 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
939 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
940 event.motion.y > 0 && event.motion.y < screen->h)))
945 case SDL_KEYDOWN: // key pressed
946 key = event.key.keysym.sym;
949 menu_event(&event.key.keysym);
950 if(key == SDLK_ESCAPE)
953 menu_set_current(&leveleditor_menu);
967 cursor_x -= KEY_CURSOR_SPEED;
969 cursor_x -= KEY_CURSOR_FASTSPEED;
971 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
972 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
977 cursor_x += KEY_CURSOR_SPEED;
979 cursor_x += KEY_CURSOR_FASTSPEED;
981 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
982 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
987 cursor_y -= KEY_CURSOR_SPEED;
989 cursor_y -= KEY_CURSOR_FASTSPEED;
996 cursor_y += KEY_CURSOR_SPEED;
998 cursor_y += KEY_CURSOR_FASTSPEED;
1000 if(cursor_y > screen->h-32)
1001 cursor_y = screen->h-32;
1014 cursor_x = (le_current_level->width * 32) - 32;
1018 le_show_grid = !le_show_grid;
1024 case SDL_KEYUP: /* key released */
1025 switch(event.key.keysym.sym)
1034 case SDL_MOUSEBUTTONDOWN:
1035 if(event.button.button == SDL_BUTTON_LEFT)
1037 le_mouse_pressed[LEFT] = YES;
1039 selection.x1 = event.motion.x + pos_x;
1040 selection.y1 = event.motion.y;
1041 selection.x2 = event.motion.x + pos_x;
1042 selection.y2 = event.motion.y;
1044 else if(event.button.button == SDL_BUTTON_RIGHT)
1045 le_mouse_pressed[RIGHT] = YES;
1047 case SDL_MOUSEBUTTONUP:
1048 if(event.button.button == SDL_BUTTON_LEFT)
1049 le_mouse_pressed[LEFT] = NO;
1050 else if(event.button.button == SDL_BUTTON_RIGHT)
1051 le_mouse_pressed[RIGHT] = NO;
1053 case SDL_MOUSEMOTION:
1059 cursor_x = ((int)(pos_x + x) / 32) * 32;
1060 cursor_y = ((int) y / 32) * 32;
1062 if(le_mouse_pressed[LEFT] == YES)
1064 selection.x2 = x + pos_x;
1068 if(le_mouse_pressed[RIGHT] == YES)
1070 fprintf(stderr, "mouse scrolling\n");
1071 pos_x += -1 * event.motion.xrel;
1075 case SDL_QUIT: // window closed
1083 if(le_current_level != NULL)
1085 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 &&
1086 event.motion.y > 0 && event.motion.y < screen->h)))
1088 le_mouse_pressed[LEFT] = NO;
1089 le_mouse_pressed[RIGHT] = NO;
1093 /* Check for button events */
1094 button_event(&le_test_level_bt,&event);
1095 if(button_get_state(&le_test_level_bt) == BN_CLICKED)
1097 button_event(&le_save_level_bt,&event);
1098 if(button_get_state(&le_save_level_bt) == BN_CLICKED)
1099 level_save(le_current_level,le_level_subset.name,le_level);
1100 button_event(&le_next_level_bt,&event);
1101 if(button_get_state(&le_next_level_bt) == BN_CLICKED)
1103 if(le_level < le_level_subset.levels)
1105 le_goto_level(++le_level);
1112 sprintf(str,"Level %d doesn't exist.",le_level+1);
1113 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1114 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1115 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1119 while(SDL_PollEvent(&event))
1122 case SDL_KEYDOWN: // key pressed
1123 switch(event.key.keysym.sym)
1126 le_default_level(&new_lev);
1127 level_save(&new_lev,le_level_subset.name,++le_level);
1128 le_level_subset.levels = le_level;
1129 le_goto_level(le_level);
1144 button_event(&le_previous_level_bt,&event);
1145 if(button_get_state(&le_previous_level_bt) == BN_CLICKED)
1148 le_goto_level(--le_level);
1150 button_event(&le_rubber_bt,&event);
1151 if(button_get_state(&le_rubber_bt) == BN_CLICKED)
1152 le_current_tile = '.';
1153 button_event(&le_select_mode_one_bt,&event);
1154 if(button_get_state(&le_select_mode_one_bt) == BN_CLICKED)
1155 le_selection_mode = CURSOR;
1156 button_event(&le_select_mode_two_bt,&event);
1157 if(button_get_state(&le_select_mode_two_bt) == BN_CLICKED)
1158 le_selection_mode = SQUARE;
1160 button_event(&le_bad_bt,&event);
1161 if(button_get_state(&le_bad_bt) == BN_CLICKED)
1163 le_bad_panel.hidden = NO;
1164 le_fgd_panel.hidden = YES;
1165 le_bkgd_panel.hidden = YES;
1168 button_event(&le_fgd_bt,&event);
1169 if(button_get_state(&le_fgd_bt) == BN_CLICKED)
1171 le_bad_panel.hidden = YES;
1172 le_fgd_panel.hidden = NO;
1173 le_bkgd_panel.hidden = YES;
1175 button_event(&le_bkgd_bt,&event);
1176 if(button_get_state(&le_bkgd_bt) == BN_CLICKED)
1178 le_bad_panel.hidden = YES;
1179 le_fgd_panel.hidden = YES;
1180 le_bkgd_panel.hidden = NO;
1182 button_event(&le_settings_bt,&event);
1183 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1187 update_level_settings_menu();
1188 menu_set_current(&level_settings_menu);
1193 menu_set_current(&leveleditor_menu);
1197 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1199 if(button_get_state(pbutton) == BN_CLICKED)
1202 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1203 c = 'G' + pbutton->tag;
1204 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1205 c = 'g' + pbutton->tag - 4;
1206 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1207 c = 'C' + pbutton->tag - 8;
1208 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1209 c = 'c' + pbutton->tag - 12;
1211 le_current_tile = c;
1214 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1216 if(button_get_state(pbutton) == BN_CLICKED)
1219 if(pbutton->tag == 0)
1221 else if(pbutton->tag == 1)
1223 else if(pbutton->tag == 2)
1225 else if(pbutton->tag == 3)
1227 else if(pbutton->tag == 4)
1229 else if(pbutton->tag == 5)
1231 else if(pbutton->tag == 6)
1233 else if(pbutton->tag == 7)
1235 else if(pbutton->tag == 8)
1237 else if(pbutton->tag == 9)
1239 else if(pbutton->tag == 10)
1241 else if(pbutton->tag == 11)
1243 else if(pbutton->tag == 12)
1245 else if(pbutton->tag == 13)
1247 else if(pbutton->tag == 14)
1249 else if(pbutton->tag == 15)
1251 else if(pbutton->tag == 16)
1253 else if(pbutton->tag == 17)
1256 le_current_tile = c;
1259 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1261 if(button_get_state(pbutton) == BN_CLICKED)
1264 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1265 c = '0' + pbutton->tag;
1267 le_current_tile = c;
1273 button_event(&le_settings_bt,&event);
1274 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1278 update_level_settings_menu();
1279 menu_set_current(&level_settings_menu);
1284 menu_set_current(&leveleditor_menu);
1292 button_event(&le_move_left_bt,&event);
1293 button_event(&le_move_right_bt,&event);
1295 if(le_mouse_pressed[LEFT])
1297 le_change(cursor_x, cursor_y, le_current_tile);
1304 if(button_get_state(&le_move_left_bt) == BN_PRESSED)
1308 else if(button_get_state(&le_move_left_bt) == BN_HOVER)
1313 if(button_get_state(&le_move_right_bt) == BN_PRESSED)
1317 else if(button_get_state(&le_move_right_bt) == BN_HOVER)
1325 void le_highlight_selection()
1330 if(selection.x1 < selection.x2)
1340 if(selection.y1 < selection.y2)
1356 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1359 void le_change(float x, float y, unsigned char c)
1361 if(le_current_level != NULL)
1366 /* level_changed = YES; */
1368 switch(le_selection_mode)
1371 level_change(le_current_level,x,y,c);
1376 /* if there is a bad guy over there, remove it */
1377 for(i = 0; i < num_bad_guys; ++i)
1378 if (bad_guys[i].base.alive)
1379 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1380 bad_guys[i].base.alive = NO;
1382 if(c == '0') /* if it's a bad guy */
1383 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1385 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1387 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1391 if(selection.x1 < selection.x2)
1401 if(selection.y1 < selection.y2)
1417 /* if there is a bad guy over there, remove it */
1418 for(i = 0; i < num_bad_guys; ++i)
1419 if(bad_guys[i].base.alive)
1420 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1421 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1422 bad_guys[i].base.alive = NO;
1424 for(xx = x1; xx <= x2; xx++)
1425 for(yy = y1; yy <= y2; yy++)
1427 level_change(le_current_level, xx*32, yy*32, c);
1429 if(c == '0') // if it's a bad guy
1430 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1432 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1434 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1445 level_save(le_current_level,"test",le_level);
1446 gameloop("test",le_level, ST_GL_TEST);
1447 menu_set_current(&leveleditor_menu);
1449 level_load_gfx(le_current_level);
1451 le_activate_bad_guys();
1459 " - This is SuperTux's built-in level editor -",
1460 "The level editor was made to be light, as well as, easy from",
1461 "the start, so probabily i am just wasting my English ,-)",
1463 "At your right, you have the button bar, that allows you",
1464 "to select tiles, both background and foregrounds, as",
1465 "well as enemies. A-Z keys can be used as shortcuts.",
1466 "The button bar can be used also to do level actions,",
1467 "just as changing, save, setup and test the level. It",
1468 "also allows you to choose between two selection cursors.",
1469 "Scrolling the level is possible by pointing at the arrows",
1470 "buttons or by using the right-mouse button.",
1471 "Use the Esc key to go to the menu, in order to",
1472 "manage subsets or just quit the level editor.",
1474 "Have fun with it and don't forget to send your levels",
1475 "to us (using the mailing list) %-)",
1480 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2, NO_UPDATE);
1482 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1483 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1, NO_UPDATE);
1485 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1493 while(SDL_PollEvent(&event))
1496 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1497 case SDL_KEYDOWN: // key pressed