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();
80 void le_update_buttons(char*);
82 /* leveleditor internals */
83 static string_list_type level_subsets;
84 static int le_level_changed; /* if changes, ask for saving, when quiting*/
85 static int pos_x, cursor_x, cursor_y, cursor_tile, 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 int 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 subset_load(&le_level_subset,level_subsets.item[i-2]);
228 leveleditor_menu.item[3].kind = MN_GOTO;
232 le_current_level = (st_level*) malloc(sizeof(st_level));
233 if(level_load(le_current_level, le_level_subset.name, le_level) != 0)
238 le_update_buttons(le_current_level->theme);
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 le_new_subset(subset_new_menu.item[2].input);
259 subset_load(&le_level_subset,subset_new_menu.item[2].input);
260 leveleditor_menu.item[3].kind = MN_GOTO;
264 le_current_level = (st_level*) malloc(sizeof(st_level));
265 if(level_load(le_current_level, le_level_subset.name, le_level) != 0)
270 le_update_buttons(le_current_level->theme);
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(strcmp(le_level_subset.title,subset_settings_menu.item[2].input) == 0 && strcmp(le_level_subset.description,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 */
320 void le_default_level(st_level* plevel)
323 strcpy(plevel->name,"UnNamed");
324 strcpy(plevel->theme,"antarctica");
325 strcpy(plevel->song_title,"Mortimers_chipdisko.mod");
326 strcpy(plevel->bkgd_image,"arctis.png");
328 plevel->time_left = 100;
329 plevel->gravity = 10.;
330 plevel->bkgd_red = 0;
331 plevel->bkgd_green = 0;
332 plevel->bkgd_blue = 0;
334 for(i = 0; i < 15; ++i)
336 plevel->tiles[i] = (unsigned char*) malloc((plevel->width+1)*sizeof(unsigned char));
337 plevel->tiles[i][plevel->width] = (unsigned char) '\0';
338 for(y = 0; y < plevel->width; ++y)
339 plevel->tiles[i][y] = (unsigned char) '.';
340 plevel->tiles[i][plevel->width] = (unsigned char) '\0';
344 void le_new_subset(char *subset_name)
347 st_subset new_subset;
348 new_subset.name = (char*) malloc((strlen(subset_name)+1)*sizeof(char));
349 strcpy(new_subset.name,subset_name);
350 new_subset.title = (char*) malloc((strlen("Unknown Title")+1)*sizeof(char));
351 strcpy(new_subset.title,"Unknown Title");
352 new_subset.description = (char*) malloc((strlen("No description so far.")+1)*sizeof(char));
353 strcpy(new_subset.description,"No description so far.");
354 subset_save(&new_subset);
355 le_default_level(&new_lev);
356 level_save(&new_lev,subset_name,1);
359 void le_update_buttons(char *theme)
365 string_list_type bkgd_files;
366 string_list_type fgd_files;
368 sprintf(pathname,"images/themes/%s",theme);
369 bkgd_files = dfiles(pathname,"bkgd-", NULL);
370 string_list_sort(&bkgd_files);
372 le_bkgd_panel.hidden = YES;
374 for(i = 0; i < bkgd_files.num_items; ++i)
376 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
377 button_change_icon(&le_bkgd_panel.item[i],filename);
380 sprintf(pathname,"images/themes/%s",theme);
381 fgd_files = dfiles(pathname,"solid", NULL);
382 string_list_sort(&fgd_files);
384 for(i = 0; i < fgd_files.num_items; ++i)
386 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
387 button_change_icon(&le_fgd_panel.item[i],filename);
390 string_list_free(&fgd_files);
391 fgd_files = dfiles(pathname,"brick", NULL);
392 string_list_sort(&fgd_files);
394 for(i = 0; i < fgd_files.num_items; ++i)
396 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
397 button_change_icon(&le_fgd_panel.item[i+14],filename);
407 string_list_type fgd_files;
408 string_list_type bkgd_files;
409 string_list_type bad_files;
410 level_subsets = dsubdirs("/levels", "info");
414 /* level_changed = NO;*/
417 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
418 le_level_changed = NO;
420 subset_init(&le_level_subset);
422 le_current_level = NULL;
424 le_current_tile = '.';
425 le_mouse_pressed[LEFT] = NO;
426 le_mouse_pressed[RIGHT] = NO;
428 texture_load(&le_selection,DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA);
431 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
432 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
433 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
434 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
435 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
436 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
437 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
438 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
439 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
440 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
441 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
442 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
443 button_load(&le_bad_bt,"/images/icons/bad.png","Bad guys", SDLK_F9,screen->w-22,82);
445 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
446 string_list_sort(&bkgd_files);
448 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
449 le_bkgd_panel.hidden = YES;
451 for(i = 0; i < bkgd_files.num_items; ++i)
453 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
454 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
457 string_list_free(&bkgd_files);
458 bkgd_files = dfiles("images/shared","cloud-", NULL);
459 string_list_sort(&bkgd_files);
461 for(i = 0; i < bkgd_files.num_items; ++i)
463 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
464 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
467 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
468 string_list_sort(&fgd_files);
470 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
471 for(i = 0; i < fgd_files.num_items; ++i)
473 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
474 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
477 string_list_free(&fgd_files);
478 string_list_add_item(&fgd_files,"waves-0.png");
479 string_list_add_item(&fgd_files,"water.png");
480 string_list_add_item(&fgd_files,"pole.png");
481 string_list_add_item(&fgd_files,"poletop.png");
482 string_list_add_item(&fgd_files,"flag-0.png");
483 string_list_add_item(&fgd_files,"box-empty.png");
484 string_list_add_item(&fgd_files,"mints.png");
485 string_list_add_item(&fgd_files,"distro-0.png");
486 string_list_add_item(&fgd_files,"golden-herring.png");
487 string_list_add_item(&fgd_files,"distro-0.png");
489 for(i = 0; i < fgd_files.num_items; ++i)
491 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
492 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
495 string_list_free(&fgd_files);
496 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
497 string_list_sort(&fgd_files);
499 for(i = 0; i < fgd_files.num_items; ++i)
501 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
502 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
505 string_list_free(&fgd_files);
506 string_list_add_item(&fgd_files,"distro-0.png");
507 string_list_add_item(&fgd_files,"distro-0.png");
508 for(i = 0; i < fgd_files.num_items; ++i)
510 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
511 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
514 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
515 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
516 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
517 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
518 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
521 string_list_init(&bad_files);
522 string_list_add_item(&bad_files,"bsod-left-0.png");
523 string_list_add_item(&bad_files,"laptop-left-0.png");
524 string_list_add_item(&bad_files,"bag-left-0.png");
525 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
526 le_bad_panel.hidden = YES;
528 for(i = 0; i < bad_files.num_items; ++i)
530 sprintf(filename,"images/shared/%s",bad_files.item[i]);
531 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
534 menu_init(&leveleditor_menu);
535 menu_additem(&leveleditor_menu,menu_item_create(MN_LABEL,"Level Editor Menu",0,0));
536 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
537 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Return To Level Editor",0,0));
538 menu_additem(&leveleditor_menu,menu_item_create(MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu));
539 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"Load Level Subset",0,&subset_load_menu));
540 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"New Level Subset",0,&subset_new_menu));
541 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
542 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Quit Level Editor",0,0));
545 menu_set_current(&leveleditor_menu);
548 menu_init(&subset_load_menu);
549 menu_additem(&subset_load_menu,menu_item_create(MN_LABEL,"Load Level Subset",0,0));
550 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
551 for(i = 0; i < level_subsets.num_items; ++i)
553 menu_additem(&subset_load_menu,menu_item_create(MN_ACTION,level_subsets.item[i],0,0));
555 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
556 menu_additem(&subset_load_menu,menu_item_create(MN_BACK,"Back",0,0));
558 menu_init(&subset_new_menu);
559 menu_additem(&subset_new_menu,menu_item_create(MN_LABEL,"New Level Subset",0,0));
560 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
561 menu_additem(&subset_new_menu,menu_item_create(MN_TEXTFIELD,"Enter Name",0,0));
562 menu_additem(&subset_new_menu,menu_item_create(MN_ACTION,"Create",0,0));
563 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
564 menu_additem(&subset_new_menu,menu_item_create(MN_BACK,"Back",0,0));
566 menu_init(&subset_settings_menu);
567 menu_additem(&subset_settings_menu,menu_item_create(MN_LABEL,"Level Subset Settings",0,0));
568 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
569 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Title",0,0));
570 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Description",0,0));
571 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
572 menu_additem(&subset_settings_menu,menu_item_create(MN_ACTION,"Save Changes",0,0));
573 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
574 menu_additem(&subset_settings_menu,menu_item_create(MN_BACK,"Back",0,0));
576 menu_init(&level_settings_menu);
577 level_settings_menu.arrange_left = YES;
578 menu_additem(&level_settings_menu,menu_item_create(MN_LABEL,"Level Settings",0,0));
579 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
580 menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Name ",0,0));
581 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Theme ",0,0));
582 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Song ",0,0));
583 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Bg-Image",0,0));
584 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Length ",0,0));
585 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Time ",0,0));
586 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Gravity",0,0));
587 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Red ",0,0));
588 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Green ",0,0));
589 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Blue ",0,0));
590 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
591 menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Apply Changes",0,0));
593 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
598 void update_level_settings_menu()
603 menu_item_change_input(&level_settings_menu.item[2], le_current_level->name);
604 sprintf(str,"%d",le_current_level->width);
606 string_list_copy(level_settings_menu.item[3].list, dsubdirs("images/themes", "solid0.png"));
607 string_list_copy(level_settings_menu.item[4].list, dfiles("music/",NULL, "-fast"));
608 string_list_copy(level_settings_menu.item[5].list, dfiles("images/background",NULL, NULL));
609 string_list_add_item(level_settings_menu.item[5].list,"");
610 if((i = string_list_find(level_settings_menu.item[3].list,le_current_level->theme)) != -1)
611 level_settings_menu.item[3].list->active_item = i;
612 if((i = string_list_find(level_settings_menu.item[4].list,le_current_level->song_title)) != -1)
613 level_settings_menu.item[4].list->active_item = i;
614 if((i = string_list_find(level_settings_menu.item[5].list,le_current_level->bkgd_image)) != -1)
615 level_settings_menu.item[5].list->active_item = i;
617 menu_item_change_input(&level_settings_menu.item[6], str);
618 sprintf(str,"%d",le_current_level->time_left);
619 menu_item_change_input(&level_settings_menu.item[7], str);
620 sprintf(str,"%2.0f",le_current_level->gravity);
621 menu_item_change_input(&level_settings_menu.item[8], str);
622 sprintf(str,"%d",le_current_level->bkgd_red);
623 menu_item_change_input(&level_settings_menu.item[9], str);
624 sprintf(str,"%d",le_current_level->bkgd_green);
625 menu_item_change_input(&level_settings_menu.item[10], str);
626 sprintf(str,"%d",le_current_level->bkgd_blue);
627 menu_item_change_input(&level_settings_menu.item[11], str);
630 void update_subset_settings_menu()
632 menu_item_change_input(&subset_settings_menu.item[2], le_level_subset.title);
633 menu_item_change_input(&subset_settings_menu.item[3], le_level_subset.description);
636 void apply_level_settings_menu()
641 strcpy(le_current_level->name,level_settings_menu.item[2].input);
643 if(strcmp(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list)) != 0)
645 strcpy(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list));
649 if(strcmp(le_current_level->theme,string_list_active(level_settings_menu.item[3].list)) != 0)
651 strcpy(le_current_level->theme,string_list_active(level_settings_menu.item[3].list));
652 le_update_buttons(le_current_level->theme);
659 level_load_gfx(le_current_level);
662 strcpy(le_current_level->song_title,string_list_active(level_settings_menu.item[4].list));
664 i = le_current_level->width;
665 le_current_level->width = atoi(level_settings_menu.item[6].input);
666 if(le_current_level->width < i)
668 if(le_current_level->width < 21)
669 le_current_level->width = 21;
670 for(y = 0; y < 15; ++y)
672 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
673 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
676 else if(le_current_level->width > i)
678 for(y = 0; y < 15; ++y)
680 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
681 for(j = 0; j < le_current_level->width - i; ++j)
682 le_current_level->tiles[y][i+j] = (unsigned char) '.';
683 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
686 le_current_level->time_left = atoi(level_settings_menu.item[7].input);
687 le_current_level->gravity = atof(level_settings_menu.item[8].input);
688 le_current_level->bkgd_red = atoi(level_settings_menu.item[9].input);
689 le_current_level->bkgd_green = atoi(level_settings_menu.item[10].input);
690 le_current_level->bkgd_blue = atoi(level_settings_menu.item[11].input);
693 void save_subset_settings_menu()
695 free(le_level_subset.title);
696 le_level_subset.title = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[2].input)+1));
697 strcpy(le_level_subset.title,subset_settings_menu.item[2].input);
698 free(le_level_subset.description);
699 le_level_subset.description = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[3].input)+1));
700 strcpy(le_level_subset.description,subset_settings_menu.item[3].input);
701 subset_save(&le_level_subset);
704 void le_goto_level(int levelnb)
709 level_free(le_current_level);
710 if(level_load(le_current_level, le_level_subset.name, levelnb) != 0)
712 level_load(le_current_level, le_level_subset.name, le_level);
721 le_update_buttons(le_current_level->theme);
724 level_load_gfx(le_current_level);
726 le_activate_bad_guys();
731 /*if(level_changed == YES)
732 if(askforsaving() == CANCEL)
735 SDL_EnableKeyRepeat(0, 0); // disables key repeating
737 texture_free(&le_selection);
738 menu_free(&leveleditor_menu);
739 menu_free(&subset_load_menu);
740 menu_free(&subset_new_menu);
741 menu_free(&subset_settings_menu);
742 menu_free(&level_settings_menu);
743 button_panel_free(&le_bkgd_panel);
744 button_panel_free(&le_fgd_panel);
745 button_panel_free(&le_bad_panel);
746 button_free(&le_save_level_bt);
747 button_free(&le_test_level_bt);
748 button_free(&le_next_level_bt);
749 button_free(&le_previous_level_bt);
750 button_free(&le_move_right_bt);
751 button_free(&le_move_left_bt);
752 button_free(&le_rubber_bt);
753 button_free(&le_select_mode_one_bt);
754 button_free(&le_select_mode_two_bt);
755 button_free(&le_settings_bt);
756 button_free(&le_bad_bt);
757 button_free(&le_bkgd_bt);
758 button_free(&le_fgd_bt);
760 if(le_current_level != NULL)
763 level_free(le_current_level);
769 void le_drawinterface()
774 if(le_current_level != NULL)
776 /* draw a grid (if selected) */
779 for(x = 0; x < 19; x++)
780 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
781 for(y = 0; y < 15; y++)
782 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
786 if(le_selection_mode == CURSOR)
787 texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
788 else if(le_selection_mode == SQUARE)
791 le_highlight_selection();
792 /* draw current selection */
793 w = selection.x2 - selection.x1;
794 h = selection.y2 - selection.y1;
795 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
796 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
797 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
798 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
802 /* draw button bar */
803 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
804 drawshape(19 * 32, 14 * 32, le_current_tile);
805 switch(le_current_tile)
808 texture_draw(&img_mints, 19 * 32, 14 * 32, NO_UPDATE);
811 texture_draw(&img_golden_herring,19 * 32, 14 * 32, NO_UPDATE);
816 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32, NO_UPDATE);
819 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32, NO_UPDATE);
822 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32, NO_UPDATE);
825 texture_draw(&img_money_left[0],19 * 32, 14 * 32, NO_UPDATE);
831 if(le_current_level != NULL)
833 button_draw(&le_save_level_bt);
834 button_draw(&le_test_level_bt);
835 button_draw(&le_next_level_bt);
836 button_draw(&le_previous_level_bt);
837 button_draw(&le_rubber_bt);
838 button_draw(&le_select_mode_one_bt);
839 button_draw(&le_select_mode_two_bt);
840 button_draw(&le_settings_bt);
841 button_draw(&le_move_right_bt);
842 button_draw(&le_move_left_bt);
843 button_draw(&le_bad_bt);
844 button_draw(&le_bkgd_bt);
845 button_draw(&le_fgd_bt);
846 button_panel_draw(&le_bkgd_panel);
847 button_panel_draw(&le_fgd_panel);
848 button_panel_draw(&le_bad_panel);
850 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
851 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_NONE, 1, NO_UPDATE);
853 text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
858 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
860 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
868 static char str[LEVEL_NAME_MAX];
870 /* Draw the real background */
871 if(le_current_level->bkgd_image[0] != '\0')
874 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h, NO_UPDATE);
875 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h, NO_UPDATE);
879 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
882 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
884 for (y = 0; y < 15; ++y)
885 for (x = 0; x < 20; ++x)
887 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
889 /* draw whats inside stuff when cursor is selecting those */
890 /* (draw them all the time - is this the right behaviour?) */
891 switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
894 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
897 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
902 texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
909 /* Draw the Bad guys: */
910 for (i = 0; i < num_bad_guys; ++i)
912 if(bad_guys[i].base.alive == NO)
914 /* to support frames: img_bsod_left[(frame / 5) % 4] */
915 if(bad_guys[i].kind == BAD_BSOD)
916 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
917 else if(bad_guys[i].kind == BAD_LAPTOP)
918 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
919 else if (bad_guys[i].kind == BAD_MONEY)
920 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
924 /* Draw the player: */
925 /* for now, the position is fixed at (0, 240) */
926 texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240, NO_UPDATE);
929 void le_checkevents()
933 button_type* pbutton;
936 keymod = SDL_GetModState();
938 while(SDL_PollEvent(&event))
940 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
941 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
942 event.motion.y > 0 && event.motion.y < screen->h)))
947 case SDL_KEYDOWN: // key pressed
948 key = event.key.keysym.sym;
951 menu_event(&event.key.keysym);
952 if(key == SDLK_ESCAPE)
955 menu_set_current(&leveleditor_menu);
969 cursor_x -= KEY_CURSOR_SPEED;
971 cursor_x -= KEY_CURSOR_FASTSPEED;
973 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
974 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
979 cursor_x += KEY_CURSOR_SPEED;
981 cursor_x += KEY_CURSOR_FASTSPEED;
983 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
984 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
989 cursor_y -= KEY_CURSOR_SPEED;
991 cursor_y -= KEY_CURSOR_FASTSPEED;
998 cursor_y += KEY_CURSOR_SPEED;
1000 cursor_y += KEY_CURSOR_FASTSPEED;
1002 if(cursor_y > screen->h-32)
1003 cursor_y = screen->h-32;
1016 cursor_x = (le_current_level->width * 32) - 32;
1020 le_show_grid = !le_show_grid;
1026 case SDL_KEYUP: /* key released */
1027 switch(event.key.keysym.sym)
1036 case SDL_MOUSEBUTTONDOWN:
1037 if(event.button.button == SDL_BUTTON_LEFT)
1039 le_mouse_pressed[LEFT] = YES;
1041 selection.x1 = event.motion.x + pos_x;
1042 selection.y1 = event.motion.y;
1043 selection.x2 = event.motion.x + pos_x;
1044 selection.y2 = event.motion.y;
1046 else if(event.button.button == SDL_BUTTON_RIGHT)
1047 le_mouse_pressed[RIGHT] = YES;
1049 case SDL_MOUSEBUTTONUP:
1050 if(event.button.button == SDL_BUTTON_LEFT)
1051 le_mouse_pressed[LEFT] = NO;
1052 else if(event.button.button == SDL_BUTTON_RIGHT)
1053 le_mouse_pressed[RIGHT] = NO;
1055 case SDL_MOUSEMOTION:
1061 cursor_x = ((int)(pos_x + x) / 32) * 32;
1062 cursor_y = ((int) y / 32) * 32;
1064 if(le_mouse_pressed[LEFT] == YES)
1066 selection.x2 = x + pos_x;
1070 if(le_mouse_pressed[RIGHT] == YES)
1072 pos_x += -1 * event.motion.xrel;
1076 case SDL_QUIT: // window closed
1084 if(le_current_level != NULL)
1086 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 &&
1087 event.motion.y > 0 && event.motion.y < screen->h)))
1089 le_mouse_pressed[LEFT] = NO;
1090 le_mouse_pressed[RIGHT] = NO;
1094 /* Check for button events */
1095 button_event(&le_test_level_bt,&event);
1096 if(button_get_state(&le_test_level_bt) == BN_CLICKED)
1098 button_event(&le_save_level_bt,&event);
1099 if(button_get_state(&le_save_level_bt) == BN_CLICKED)
1100 level_save(le_current_level,le_level_subset.name,le_level);
1101 button_event(&le_next_level_bt,&event);
1102 if(button_get_state(&le_next_level_bt) == BN_CLICKED)
1104 if(le_level < le_level_subset.levels)
1106 le_goto_level(++le_level);
1113 sprintf(str,"Level %d doesn't exist.",le_level+1);
1114 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1115 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1116 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1120 while(SDL_PollEvent(&event))
1123 case SDL_KEYDOWN: // key pressed
1124 switch(event.key.keysym.sym)
1127 le_default_level(&new_lev);
1128 level_save(&new_lev,le_level_subset.name,++le_level);
1129 le_level_subset.levels = le_level;
1130 le_goto_level(le_level);
1145 button_event(&le_previous_level_bt,&event);
1146 if(button_get_state(&le_previous_level_bt) == BN_CLICKED)
1149 le_goto_level(--le_level);
1151 button_event(&le_rubber_bt,&event);
1152 if(button_get_state(&le_rubber_bt) == BN_CLICKED)
1153 le_current_tile = '.';
1154 button_event(&le_select_mode_one_bt,&event);
1155 if(button_get_state(&le_select_mode_one_bt) == BN_CLICKED)
1156 le_selection_mode = CURSOR;
1157 button_event(&le_select_mode_two_bt,&event);
1158 if(button_get_state(&le_select_mode_two_bt) == BN_CLICKED)
1159 le_selection_mode = SQUARE;
1161 button_event(&le_bad_bt,&event);
1162 if(button_get_state(&le_bad_bt) == BN_CLICKED)
1164 le_bad_panel.hidden = NO;
1165 le_fgd_panel.hidden = YES;
1166 le_bkgd_panel.hidden = YES;
1169 button_event(&le_fgd_bt,&event);
1170 if(button_get_state(&le_fgd_bt) == BN_CLICKED)
1172 le_bad_panel.hidden = YES;
1173 le_fgd_panel.hidden = NO;
1174 le_bkgd_panel.hidden = YES;
1176 button_event(&le_bkgd_bt,&event);
1177 if(button_get_state(&le_bkgd_bt) == BN_CLICKED)
1179 le_bad_panel.hidden = YES;
1180 le_fgd_panel.hidden = YES;
1181 le_bkgd_panel.hidden = NO;
1183 button_event(&le_settings_bt,&event);
1184 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1188 update_level_settings_menu();
1189 menu_set_current(&level_settings_menu);
1194 menu_set_current(&leveleditor_menu);
1198 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1200 if(button_get_state(pbutton) == BN_CLICKED)
1203 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1204 c = 'G' + pbutton->tag;
1205 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1206 c = 'g' + pbutton->tag - 4;
1207 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1208 c = 'C' + pbutton->tag - 8;
1209 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1210 c = 'c' + pbutton->tag - 12;
1212 le_current_tile = c;
1215 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1217 if(button_get_state(pbutton) == BN_CLICKED)
1220 if(pbutton->tag == 0)
1222 else if(pbutton->tag == 1)
1224 else if(pbutton->tag == 2)
1226 else if(pbutton->tag == 3)
1228 else if(pbutton->tag == 4)
1230 else if(pbutton->tag == 5)
1232 else if(pbutton->tag == 6)
1234 else if(pbutton->tag == 7)
1236 else if(pbutton->tag == 8)
1238 else if(pbutton->tag == 9)
1240 else if(pbutton->tag == 10)
1242 else if(pbutton->tag == 11)
1244 else if(pbutton->tag == 12)
1246 else if(pbutton->tag == 13)
1248 else if(pbutton->tag == 14)
1250 else if(pbutton->tag == 15)
1252 else if(pbutton->tag == 16)
1254 else if(pbutton->tag == 17)
1257 le_current_tile = c;
1260 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1262 if(button_get_state(pbutton) == BN_CLICKED)
1265 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1266 c = '0' + pbutton->tag;
1268 le_current_tile = c;
1274 button_event(&le_settings_bt,&event);
1275 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1279 update_level_settings_menu();
1280 menu_set_current(&level_settings_menu);
1285 menu_set_current(&leveleditor_menu);
1293 button_event(&le_move_left_bt,&event);
1294 button_event(&le_move_right_bt,&event);
1296 if(le_mouse_pressed[LEFT])
1298 le_change(cursor_x, cursor_y, le_current_tile);
1305 if(button_get_state(&le_move_left_bt) == BN_PRESSED)
1309 else if(button_get_state(&le_move_left_bt) == BN_HOVER)
1314 if(button_get_state(&le_move_right_bt) == BN_PRESSED)
1318 else if(button_get_state(&le_move_right_bt) == BN_HOVER)
1326 void le_highlight_selection()
1331 if(selection.x1 < selection.x2)
1341 if(selection.y1 < selection.y2)
1357 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1360 void le_change(float x, float y, unsigned char c)
1362 if(le_current_level != NULL)
1367 /* level_changed = YES; */
1369 switch(le_selection_mode)
1372 level_change(le_current_level,x,y,c);
1377 /* if there is a bad guy over there, remove it */
1378 for(i = 0; i < num_bad_guys; ++i)
1379 if (bad_guys[i].base.alive)
1380 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1381 bad_guys[i].base.alive = NO;
1383 if(c == '0') /* if it's a bad guy */
1384 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1386 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1388 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1392 if(selection.x1 < selection.x2)
1402 if(selection.y1 < selection.y2)
1418 /* if there is a bad guy over there, remove it */
1419 for(i = 0; i < num_bad_guys; ++i)
1420 if(bad_guys[i].base.alive)
1421 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1422 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1423 bad_guys[i].base.alive = NO;
1425 for(xx = x1; xx <= x2; xx++)
1426 for(yy = y1; yy <= y2; yy++)
1428 level_change(le_current_level, xx*32, yy*32, c);
1430 if(c == '0') // if it's a bad guy
1431 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1433 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1435 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1446 level_save(le_current_level,"test",le_level);
1447 gameloop("test",le_level, ST_GL_TEST);
1448 menu_set_current(&leveleditor_menu);
1450 level_load_gfx(le_current_level);
1452 le_activate_bad_guys();
1460 " - This is SuperTux's built-in level editor -",
1461 "The level editor was made to be light, as well as, easy from",
1462 "the start, so probabily i am just wasting my English ,-)",
1464 "At your right, you have the button bar, that allows you",
1465 "to select tiles, both background and foregrounds, as",
1466 "well as enemies. A-Z keys can be used as shortcuts.",
1467 "The button bar can be used also to do level actions,",
1468 "just as changing, save, setup and test the level. It",
1469 "also allows you to choose between two selection cursors.",
1470 "Scrolling the level is possible by pointing at the arrows",
1471 "buttons or by using the right-mouse button.",
1472 "Use the Esc key to go to the menu, in order to",
1473 "manage subsets or just quit the level editor.",
1475 "Have fun with it and don't forget to send your levels",
1476 "to us (using the mailing list) %-)",
1481 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2, NO_UPDATE);
1483 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1484 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1, NO_UPDATE);
1486 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1494 while(SDL_PollEvent(&event))
1497 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1498 case SDL_KEYDOWN: // key pressed