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 if((i = string_list_find(level_settings_menu.item[3].list,le_current_level->theme)) != -1)
610 level_settings_menu.item[3].list->active_item = i;
611 if((i = string_list_find(level_settings_menu.item[4].list,le_current_level->song_title)) != -1)
612 level_settings_menu.item[4].list->active_item = i;
613 if((i = string_list_find(level_settings_menu.item[5].list,le_current_level->bkgd_image)) != -1)
614 level_settings_menu.item[5].list->active_item = i;
616 menu_item_change_input(&level_settings_menu.item[6], str);
617 sprintf(str,"%d",le_current_level->time_left);
618 menu_item_change_input(&level_settings_menu.item[7], str);
619 sprintf(str,"%2.0f",le_current_level->gravity);
620 menu_item_change_input(&level_settings_menu.item[8], str);
621 sprintf(str,"%d",le_current_level->bkgd_red);
622 menu_item_change_input(&level_settings_menu.item[9], str);
623 sprintf(str,"%d",le_current_level->bkgd_green);
624 menu_item_change_input(&level_settings_menu.item[10], str);
625 sprintf(str,"%d",le_current_level->bkgd_blue);
626 menu_item_change_input(&level_settings_menu.item[11], str);
629 void update_subset_settings_menu()
631 menu_item_change_input(&subset_settings_menu.item[2], le_level_subset.title);
632 menu_item_change_input(&subset_settings_menu.item[3], le_level_subset.description);
635 void apply_level_settings_menu()
640 strcpy(le_current_level->name,level_settings_menu.item[2].input);
642 if(strcmp(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list)) != 0)
644 strcpy(le_current_level->bkgd_image,string_list_active(level_settings_menu.item[5].list));
648 if(strcmp(le_current_level->theme,string_list_active(level_settings_menu.item[3].list)) != 0)
650 strcpy(le_current_level->theme,string_list_active(level_settings_menu.item[3].list));
651 le_update_buttons(le_current_level->theme);
658 level_load_gfx(le_current_level);
661 strcpy(le_current_level->song_title,string_list_active(level_settings_menu.item[4].list));
663 i = le_current_level->width;
664 le_current_level->width = atoi(level_settings_menu.item[6].input);
665 if(le_current_level->width < i)
667 if(le_current_level->width < 21)
668 le_current_level->width = 21;
669 for(y = 0; y < 15; ++y)
671 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
672 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
675 else if(le_current_level->width > i)
677 for(y = 0; y < 15; ++y)
679 le_current_level->tiles[y] = (unsigned char*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned char));
680 for(j = 0; j < le_current_level->width - i; ++j)
681 le_current_level->tiles[y][i+j] = (unsigned char) '.';
682 le_current_level->tiles[y][le_current_level->width] = (unsigned char) '\0';
685 le_current_level->time_left = atoi(level_settings_menu.item[7].input);
686 le_current_level->gravity = atof(level_settings_menu.item[8].input);
687 le_current_level->bkgd_red = atoi(level_settings_menu.item[9].input);
688 le_current_level->bkgd_green = atoi(level_settings_menu.item[10].input);
689 le_current_level->bkgd_blue = atoi(level_settings_menu.item[11].input);
692 void save_subset_settings_menu()
694 free(le_level_subset.title);
695 le_level_subset.title = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[2].input)+1));
696 strcpy(le_level_subset.title,subset_settings_menu.item[2].input);
697 free(le_level_subset.description);
698 le_level_subset.description = (char*) malloc(sizeof(char)*(strlen(subset_settings_menu.item[3].input)+1));
699 strcpy(le_level_subset.description,subset_settings_menu.item[3].input);
700 subset_save(&le_level_subset);
703 void le_goto_level(int levelnb)
708 level_free(le_current_level);
709 if(level_load(le_current_level, le_level_subset.name, levelnb) != 0)
711 level_load(le_current_level, le_level_subset.name, le_level);
720 le_update_buttons(le_current_level->theme);
723 level_load_gfx(le_current_level);
725 le_activate_bad_guys();
730 /*if(level_changed == YES)
731 if(askforsaving() == CANCEL)
734 SDL_EnableKeyRepeat(0, 0); // disables key repeating
736 texture_free(&le_selection);
737 menu_free(&leveleditor_menu);
738 menu_free(&subset_load_menu);
739 menu_free(&subset_new_menu);
740 menu_free(&subset_settings_menu);
741 menu_free(&level_settings_menu);
742 button_panel_free(&le_bkgd_panel);
743 button_panel_free(&le_fgd_panel);
744 button_panel_free(&le_bad_panel);
745 button_free(&le_save_level_bt);
746 button_free(&le_test_level_bt);
747 button_free(&le_next_level_bt);
748 button_free(&le_previous_level_bt);
749 button_free(&le_move_right_bt);
750 button_free(&le_move_left_bt);
751 button_free(&le_rubber_bt);
752 button_free(&le_select_mode_one_bt);
753 button_free(&le_select_mode_two_bt);
754 button_free(&le_settings_bt);
755 button_free(&le_bad_bt);
756 button_free(&le_bkgd_bt);
757 button_free(&le_fgd_bt);
759 if(le_current_level != NULL)
762 level_free(le_current_level);
768 void le_drawinterface()
773 if(le_current_level != NULL)
775 /* draw a grid (if selected) */
778 for(x = 0; x < 19; x++)
779 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
780 for(y = 0; y < 15; y++)
781 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
785 if(le_selection_mode == CURSOR)
786 texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
787 else if(le_selection_mode == SQUARE)
790 le_highlight_selection();
791 /* draw current selection */
792 w = selection.x2 - selection.x1;
793 h = selection.y2 - selection.y1;
794 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
795 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
796 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
797 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
801 /* draw button bar */
802 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
803 drawshape(19 * 32, 14 * 32, le_current_tile);
804 switch(le_current_tile)
807 texture_draw(&img_mints, 19 * 32, 14 * 32, NO_UPDATE);
810 texture_draw(&img_golden_herring,19 * 32, 14 * 32, NO_UPDATE);
815 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32, NO_UPDATE);
818 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32, NO_UPDATE);
821 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32, NO_UPDATE);
824 texture_draw(&img_money_left[0],19 * 32, 14 * 32, NO_UPDATE);
830 if(le_current_level != NULL)
832 button_draw(&le_save_level_bt);
833 button_draw(&le_test_level_bt);
834 button_draw(&le_next_level_bt);
835 button_draw(&le_previous_level_bt);
836 button_draw(&le_rubber_bt);
837 button_draw(&le_select_mode_one_bt);
838 button_draw(&le_select_mode_two_bt);
839 button_draw(&le_settings_bt);
840 button_draw(&le_move_right_bt);
841 button_draw(&le_move_left_bt);
842 button_draw(&le_bad_bt);
843 button_draw(&le_bkgd_bt);
844 button_draw(&le_fgd_bt);
845 button_panel_draw(&le_bkgd_panel);
846 button_panel_draw(&le_fgd_panel);
847 button_panel_draw(&le_bad_panel);
849 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
850 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_NONE, 1, NO_UPDATE);
852 text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
857 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
859 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
867 static char str[LEVEL_NAME_MAX];
869 /* Draw the real background */
870 if(le_current_level->bkgd_image[0] != '\0')
873 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h, NO_UPDATE);
874 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h, NO_UPDATE);
878 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
881 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
883 for (y = 0; y < 15; ++y)
884 for (x = 0; x < 20; ++x)
886 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
888 /* draw whats inside stuff when cursor is selecting those */
889 /* (draw them all the time - is this the right behaviour?) */
890 switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
893 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
896 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
901 texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
908 /* Draw the Bad guys: */
909 for (i = 0; i < num_bad_guys; ++i)
911 if(bad_guys[i].base.alive == NO)
913 /* to support frames: img_bsod_left[(frame / 5) % 4] */
914 if(bad_guys[i].kind == BAD_BSOD)
915 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
916 else if(bad_guys[i].kind == BAD_LAPTOP)
917 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
918 else if (bad_guys[i].kind == BAD_MONEY)
919 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
923 /* Draw the player: */
924 /* for now, the position is fixed at (0, 240) */
925 texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240, NO_UPDATE);
928 void le_checkevents()
932 button_type* pbutton;
935 keymod = SDL_GetModState();
937 while(SDL_PollEvent(&event))
939 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
940 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
941 event.motion.y > 0 && event.motion.y < screen->h)))
946 case SDL_KEYDOWN: // key pressed
947 key = event.key.keysym.sym;
950 menu_event(&event.key.keysym);
951 if(key == SDLK_ESCAPE)
954 menu_set_current(&leveleditor_menu);
968 cursor_x -= KEY_CURSOR_SPEED;
970 cursor_x -= KEY_CURSOR_FASTSPEED;
972 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
973 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
978 cursor_x += KEY_CURSOR_SPEED;
980 cursor_x += KEY_CURSOR_FASTSPEED;
982 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
983 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
988 cursor_y -= KEY_CURSOR_SPEED;
990 cursor_y -= KEY_CURSOR_FASTSPEED;
997 cursor_y += KEY_CURSOR_SPEED;
999 cursor_y += KEY_CURSOR_FASTSPEED;
1001 if(cursor_y > screen->h-32)
1002 cursor_y = screen->h-32;
1015 cursor_x = (le_current_level->width * 32) - 32;
1019 le_show_grid = !le_show_grid;
1025 case SDL_KEYUP: /* key released */
1026 switch(event.key.keysym.sym)
1035 case SDL_MOUSEBUTTONDOWN:
1036 if(event.button.button == SDL_BUTTON_LEFT)
1038 le_mouse_pressed[LEFT] = YES;
1040 selection.x1 = event.motion.x + pos_x;
1041 selection.y1 = event.motion.y;
1042 selection.x2 = event.motion.x + pos_x;
1043 selection.y2 = event.motion.y;
1045 else if(event.button.button == SDL_BUTTON_RIGHT)
1046 le_mouse_pressed[RIGHT] = YES;
1048 case SDL_MOUSEBUTTONUP:
1049 if(event.button.button == SDL_BUTTON_LEFT)
1050 le_mouse_pressed[LEFT] = NO;
1051 else if(event.button.button == SDL_BUTTON_RIGHT)
1052 le_mouse_pressed[RIGHT] = NO;
1054 case SDL_MOUSEMOTION:
1060 cursor_x = ((int)(pos_x + x) / 32) * 32;
1061 cursor_y = ((int) y / 32) * 32;
1063 if(le_mouse_pressed[LEFT] == YES)
1065 selection.x2 = x + pos_x;
1069 if(le_mouse_pressed[RIGHT] == YES)
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