1 /***************************************************************************
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
8 ***************************************************************************/
10 /* December 28, 2003 - March 15, 2004 */
12 /* leveleditor.c - A built-in level editor for SuperTux
13 Ricardo Cruz <rick2@aeiou.pt>
14 Tobias Glaesser <tobi.web@gmx.de> */
22 #include <SDL_image.h>
23 #include "leveleditor.h"
35 /* definitions to aid development */
36 #define DONE_LEVELEDITOR 1
38 #define DONE_CHANGELEVEL 3
40 /* definitions that affect gameplay */
41 #define KEY_CURSOR_SPEED 32
42 #define KEY_CURSOR_FASTSPEED 64
44 /* when pagedown/up pressed speed:*/
45 #define PAGE_CURSOR_SPEED 13*32
47 #define MOUSE_LEFT_MARGIN 80
48 #define MOUSE_RIGHT_MARGIN (560-32)
49 /* right_margin should noticed that the cursor is 32 pixels,
50 so it should subtract that value */
51 #define MOUSE_POS_SPEED 20
54 #define SELECT_W 2 // size of the selections lines
55 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
57 /* gameloop funcs declerations */
59 void loadshared(void);
60 void unloadshared(void);
62 /* own declerations */
63 /* crutial ones (main loop) */
67 void le_drawinterface();
68 void le_checkevents();
69 void le_change(float x, float y, unsigned char c);
72 void le_set_defaults(void);
73 void le_activate_bad_guys(void);
75 void le_highlight_selection();
77 void apply_level_settings_menu();
78 void update_subset_settings_menu();
79 void save_subset_settings_menu();
80 void le_update_buttons(const char*);
82 /* leveleditor internals */
83 static string_list_type level_subsets;
84 static int le_level_changed; /* if changes, ask for saving, when quiting*/
85 static int pos_x, cursor_x, cursor_y, fire;
87 static st_level* le_current_level;
88 static st_subset le_level_subset;
89 static int le_show_grid;
91 static texture_type le_selection;
93 static char le_current_tile;
94 static 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 le_level_subset.load(level_subsets.item[i-2]);
228 leveleditor_menu.item[3].kind = MN_GOTO;
232 le_current_level = new st_level;
233 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
238 le_update_buttons(le_current_level->theme.c_str());
240 level_load_gfx(le_current_level);
241 le_activate_bad_guys();
247 else if(current_menu == &subset_new_menu)
249 if(subset_new_menu.item[2].input[0] == '\0')
250 subset_new_menu.item[3].kind = MN_DEACTIVE;
253 subset_new_menu.item[3].kind = MN_ACTION;
255 switch (i = menu_check(&subset_new_menu))
258 st_subset::create(subset_new_menu.item[2].input);
259 le_level_subset.load(subset_new_menu.item[2].input);
260 leveleditor_menu.item[3].kind = MN_GOTO;
264 le_current_level = (st_level*) malloc(sizeof(st_level));
265 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
270 le_update_buttons(le_current_level->theme.c_str());
272 level_load_gfx(le_current_level);
273 le_activate_bad_guys();
274 menu_item_change_input(&subset_new_menu.item[2],"");
280 else if(current_menu == &subset_settings_menu)
282 if(le_level_subset.title.compare(subset_settings_menu.item[2].input) == 0 && le_level_subset.description.compare(subset_settings_menu.item[3].input) == 0 )
283 subset_settings_menu.item[5].kind = MN_DEACTIVE;
285 subset_settings_menu.item[5].kind = MN_ACTION;
287 switch (i = menu_check(&subset_settings_menu))
290 save_subset_settings_menu();
303 if(done == DONE_QUIT)
310 now_time = SDL_GetTicks();
311 if (now_time < last_time + FPS)
312 SDL_Delay(last_time + FPS - now_time); /* delay some time */
321 void le_update_buttons(const char *theme)
327 string_list_type bkgd_files;
328 string_list_type fgd_files;
330 sprintf(pathname,"images/themes/%s",theme);
331 bkgd_files = dfiles(pathname,"bkgd-", NULL);
332 string_list_sort(&bkgd_files);
334 le_bkgd_panel.hidden = YES;
336 for(i = 0; i < bkgd_files.num_items; ++i)
338 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
339 button_change_icon(&le_bkgd_panel.item[i],filename);
342 sprintf(pathname,"images/themes/%s",theme);
343 fgd_files = dfiles(pathname,"solid", NULL);
344 string_list_sort(&fgd_files);
346 for(i = 0; i < fgd_files.num_items; ++i)
348 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
349 button_change_icon(&le_fgd_panel.item[i],filename);
352 string_list_free(&fgd_files);
353 fgd_files = dfiles(pathname,"brick", NULL);
354 string_list_sort(&fgd_files);
356 for(i = 0; i < fgd_files.num_items; ++i)
358 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
359 button_change_icon(&le_fgd_panel.item[i+14],filename);
368 string_list_type fgd_files;
369 string_list_type bkgd_files;
370 string_list_type bad_files;
371 level_subsets = dsubdirs("/levels", "info");
375 /* level_changed = NO;*/
378 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
379 le_level_changed = NO;
380 le_current_level = NULL;
382 le_current_tile = '.';
383 le_mouse_pressed[LEFT] = NO;
384 le_mouse_pressed[RIGHT] = NO;
386 texture_load(&le_selection,DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA);
389 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
390 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
391 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
392 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
393 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
394 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
395 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
396 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
397 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
398 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
399 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
400 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
401 button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
403 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
404 string_list_sort(&bkgd_files);
406 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
407 le_bkgd_panel.hidden = YES;
409 for(i = 0; i < bkgd_files.num_items; ++i)
411 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
412 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
415 string_list_free(&bkgd_files);
416 bkgd_files = dfiles("images/shared","cloud-", NULL);
417 string_list_sort(&bkgd_files);
419 for(i = 0; i < bkgd_files.num_items; ++i)
421 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
422 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
425 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
426 string_list_sort(&fgd_files);
428 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
429 for(i = 0; i < fgd_files.num_items; ++i)
431 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
432 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
435 string_list_free(&fgd_files);
436 string_list_add_item(&fgd_files,"waves-0.png");
437 string_list_add_item(&fgd_files,"water.png");
438 string_list_add_item(&fgd_files,"pole.png");
439 string_list_add_item(&fgd_files,"poletop.png");
440 string_list_add_item(&fgd_files,"flag-0.png");
441 string_list_add_item(&fgd_files,"box-empty.png");
442 string_list_add_item(&fgd_files,"mints.png");
443 string_list_add_item(&fgd_files,"distro-0.png");
444 string_list_add_item(&fgd_files,"golden-herring.png");
445 string_list_add_item(&fgd_files,"distro-0.png");
447 for(i = 0; i < fgd_files.num_items; ++i)
449 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
450 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
453 string_list_free(&fgd_files);
454 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
455 string_list_sort(&fgd_files);
457 for(i = 0; i < fgd_files.num_items; ++i)
459 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
460 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
463 string_list_free(&fgd_files);
464 string_list_add_item(&fgd_files,"distro-0.png");
465 string_list_add_item(&fgd_files,"distro-0.png");
466 for(i = 0; i < fgd_files.num_items; ++i)
468 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
469 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
472 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
473 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
474 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
475 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
476 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
478 string_list_init(&bad_files);
479 string_list_add_item(&bad_files,"bsod-left-0.png");
480 string_list_add_item(&bad_files,"laptop-left-0.png");
481 string_list_add_item(&bad_files,"bag-left-0.png");
482 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
483 le_bad_panel.hidden = YES;
485 for(i = 0; i < bad_files.num_items; ++i)
487 sprintf(filename,"images/shared/%s",bad_files.item[i]);
488 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
491 menu_init(&leveleditor_menu);
492 menu_additem(&leveleditor_menu,menu_item_create(MN_LABEL,"Level Editor Menu",0,0));
493 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
494 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Return To Level Editor",0,0));
495 menu_additem(&leveleditor_menu,menu_item_create(MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu));
496 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"Load Level Subset",0,&subset_load_menu));
497 menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"New Level Subset",0,&subset_new_menu));
498 menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
499 menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Quit Level Editor",0,0));
502 menu_set_current(&leveleditor_menu);
505 menu_init(&subset_load_menu);
506 menu_additem(&subset_load_menu,menu_item_create(MN_LABEL,"Load Level Subset",0,0));
507 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
508 for(i = 0; i < level_subsets.num_items; ++i)
510 menu_additem(&subset_load_menu,menu_item_create(MN_ACTION,level_subsets.item[i],0,0));
512 menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
513 menu_additem(&subset_load_menu,menu_item_create(MN_BACK,"Back",0,0));
515 menu_init(&subset_new_menu);
516 menu_additem(&subset_new_menu,menu_item_create(MN_LABEL,"New Level Subset",0,0));
517 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
518 menu_additem(&subset_new_menu,menu_item_create(MN_TEXTFIELD,"Enter Name",0,0));
519 menu_additem(&subset_new_menu,menu_item_create(MN_ACTION,"Create",0,0));
520 menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
521 menu_additem(&subset_new_menu,menu_item_create(MN_BACK,"Back",0,0));
523 menu_init(&subset_settings_menu);
524 menu_additem(&subset_settings_menu,menu_item_create(MN_LABEL,"Level Subset Settings",0,0));
525 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
526 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Title",0,0));
527 menu_additem(&subset_settings_menu,menu_item_create(MN_TEXTFIELD,"Description",0,0));
528 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
529 menu_additem(&subset_settings_menu,menu_item_create(MN_ACTION,"Save Changes",0,0));
530 menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
531 menu_additem(&subset_settings_menu,menu_item_create(MN_BACK,"Back",0,0));
533 menu_init(&level_settings_menu);
534 level_settings_menu.arrange_left = YES;
535 menu_additem(&level_settings_menu,menu_item_create(MN_LABEL,"Level Settings",0,0));
536 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
537 menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Name ",0,0));
538 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Theme ",0,0));
539 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Song ",0,0));
540 menu_additem(&level_settings_menu,menu_item_create(MN_STRINGSELECT,"Bg-Image",0,0));
541 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Length ",0,0));
542 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Time ",0,0));
543 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Gravity",0,0));
544 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Red ",0,0));
545 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Green ",0,0));
546 menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Blue ",0,0));
547 menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
548 menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Apply Changes",0,0));
550 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
555 void update_level_settings_menu()
560 menu_item_change_input(&level_settings_menu.item[2], le_current_level->name.c_str());
561 sprintf(str,"%d",le_current_level->width);
563 string_list_copy(level_settings_menu.item[3].list, dsubdirs("images/themes", "solid0.png"));
564 string_list_copy(level_settings_menu.item[4].list, dfiles("music/",NULL, "-fast"));
565 string_list_copy(level_settings_menu.item[5].list, dfiles("images/background",NULL, NULL));
566 string_list_add_item(level_settings_menu.item[5].list,"");
567 if((i = string_list_find(level_settings_menu.item[3].list,le_current_level->theme.c_str())) != -1)
568 level_settings_menu.item[3].list->active_item = i;
569 if((i = string_list_find(level_settings_menu.item[4].list,le_current_level->song_title.c_str())) != -1)
570 level_settings_menu.item[4].list->active_item = i;
571 if((i = string_list_find(level_settings_menu.item[5].list,le_current_level->bkgd_image.c_str())) != -1)
572 level_settings_menu.item[5].list->active_item = i;
574 menu_item_change_input(&level_settings_menu.item[6], str);
575 sprintf(str,"%d",le_current_level->time_left);
576 menu_item_change_input(&level_settings_menu.item[7], str);
577 sprintf(str,"%2.0f",le_current_level->gravity);
578 menu_item_change_input(&level_settings_menu.item[8], str);
579 sprintf(str,"%d",le_current_level->bkgd_red);
580 menu_item_change_input(&level_settings_menu.item[9], str);
581 sprintf(str,"%d",le_current_level->bkgd_green);
582 menu_item_change_input(&level_settings_menu.item[10], str);
583 sprintf(str,"%d",le_current_level->bkgd_blue);
584 menu_item_change_input(&level_settings_menu.item[11], str);
587 void update_subset_settings_menu()
589 menu_item_change_input(&subset_settings_menu.item[2], le_level_subset.title.c_str());
590 menu_item_change_input(&subset_settings_menu.item[3], le_level_subset.description.c_str());
593 void apply_level_settings_menu()
598 le_current_level->name = level_settings_menu.item[2].input;
600 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu.item[5].list)) != 0)
602 le_current_level->bkgd_image = string_list_active(level_settings_menu.item[5].list);
606 if(le_current_level->theme.compare(string_list_active(level_settings_menu.item[3].list)) != 0)
608 le_current_level->theme = string_list_active(level_settings_menu.item[3].list);
609 le_update_buttons(le_current_level->theme.c_str());
616 level_load_gfx(le_current_level);
619 le_current_level->song_title = string_list_active(level_settings_menu.item[4].list);
621 i = le_current_level->width;
622 le_current_level->width = atoi(level_settings_menu.item[6].input);
623 if(le_current_level->width < i)
625 if(le_current_level->width < 21)
626 le_current_level->width = 21;
627 for(y = 0; y < 15; ++y)
629 le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
630 le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
633 else if(le_current_level->width > i)
635 for(y = 0; y < 15; ++y)
637 le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
638 for(j = 0; j < le_current_level->width - i; ++j)
639 le_current_level->tiles[y][i+j] = (unsigned int) '.';
640 le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
643 le_current_level->time_left = atoi(level_settings_menu.item[7].input);
644 le_current_level->gravity = atof(level_settings_menu.item[8].input);
645 le_current_level->bkgd_red = atoi(level_settings_menu.item[9].input);
646 le_current_level->bkgd_green = atoi(level_settings_menu.item[10].input);
647 le_current_level->bkgd_blue = atoi(level_settings_menu.item[11].input);
650 void save_subset_settings_menu()
652 le_level_subset.title = subset_settings_menu.item[2].input;
653 le_level_subset.description = subset_settings_menu.item[3].input;
654 le_level_subset.save();
657 void le_goto_level(int levelnb)
662 level_free(le_current_level);
663 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
665 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
674 le_update_buttons(le_current_level->theme.c_str());
677 level_load_gfx(le_current_level);
679 le_activate_bad_guys();
684 /*if(level_changed == YES)
685 if(askforsaving() == CANCEL)
688 SDL_EnableKeyRepeat(0, 0); // disables key repeating
690 texture_free(&le_selection);
691 menu_free(&leveleditor_menu);
692 menu_free(&subset_load_menu);
693 menu_free(&subset_new_menu);
694 menu_free(&subset_settings_menu);
695 menu_free(&level_settings_menu);
696 button_panel_free(&le_bkgd_panel);
697 button_panel_free(&le_fgd_panel);
698 button_panel_free(&le_bad_panel);
699 button_free(&le_save_level_bt);
700 button_free(&le_test_level_bt);
701 button_free(&le_next_level_bt);
702 button_free(&le_previous_level_bt);
703 button_free(&le_move_right_bt);
704 button_free(&le_move_left_bt);
705 button_free(&le_rubber_bt);
706 button_free(&le_select_mode_one_bt);
707 button_free(&le_select_mode_two_bt);
708 button_free(&le_settings_bt);
709 button_free(&le_bad_bt);
710 button_free(&le_bkgd_bt);
711 button_free(&le_fgd_bt);
713 if(le_current_level != NULL)
716 level_free(le_current_level);
722 void le_drawinterface()
727 if(le_current_level != NULL)
729 /* draw a grid (if selected) */
732 for(x = 0; x < 19; x++)
733 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
734 for(y = 0; y < 15; y++)
735 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
739 if(le_selection_mode == CURSOR)
740 texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
741 else if(le_selection_mode == SQUARE)
744 le_highlight_selection();
745 /* draw current selection */
746 w = selection.x2 - selection.x1;
747 h = selection.y2 - selection.y1;
748 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
749 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
750 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
751 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
755 /* draw button bar */
756 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
757 drawshape(19 * 32, 14 * 32, le_current_tile);
758 switch(le_current_tile)
761 texture_draw(&img_mints, 19 * 32, 14 * 32, NO_UPDATE);
764 texture_draw(&img_golden_herring,19 * 32, 14 * 32, NO_UPDATE);
769 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32, NO_UPDATE);
772 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32, NO_UPDATE);
775 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32, NO_UPDATE);
778 texture_draw(&img_money_left[0],19 * 32, 14 * 32, NO_UPDATE);
784 if(le_current_level != NULL)
786 button_draw(&le_save_level_bt);
787 button_draw(&le_test_level_bt);
788 button_draw(&le_next_level_bt);
789 button_draw(&le_previous_level_bt);
790 button_draw(&le_rubber_bt);
791 button_draw(&le_select_mode_one_bt);
792 button_draw(&le_select_mode_two_bt);
793 button_draw(&le_settings_bt);
794 button_draw(&le_move_right_bt);
795 button_draw(&le_move_left_bt);
796 button_draw(&le_bad_bt);
797 button_draw(&le_bkgd_bt);
798 button_draw(&le_fgd_bt);
799 button_panel_draw(&le_bkgd_panel);
800 button_panel_draw(&le_fgd_panel);
801 button_panel_draw(&le_bad_panel);
803 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
804 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_NONE, 1, NO_UPDATE);
806 text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
811 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
813 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
822 /* Draw the real background */
823 if(le_current_level->bkgd_image[0] != '\0')
826 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h, NO_UPDATE);
827 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h, NO_UPDATE);
831 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
834 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
836 for (y = 0; y < 15; ++y)
837 for (x = 0; x < 20; ++x)
839 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
841 /* draw whats inside stuff when cursor is selecting those */
842 /* (draw them all the time - is this the right behaviour?) */
843 switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
846 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
849 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
854 texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
861 /* Draw the Bad guys: */
862 for (i = 0; i < num_bad_guys; ++i)
864 if(bad_guys[i].base.alive == NO)
866 /* to support frames: img_bsod_left[(frame / 5) % 4] */
867 if(bad_guys[i].kind == BAD_BSOD)
868 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
869 else if(bad_guys[i].kind == BAD_LAPTOP)
870 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
871 else if (bad_guys[i].kind == BAD_MONEY)
872 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
876 /* Draw the player: */
877 /* for now, the position is fixed at (0, 240) */
878 texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240, NO_UPDATE);
881 void le_checkevents()
885 button_type* pbutton;
888 keymod = SDL_GetModState();
890 while(SDL_PollEvent(&event))
892 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
893 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
894 event.motion.y > 0 && event.motion.y < screen->h)))
899 case SDL_KEYDOWN: // key pressed
900 key = event.key.keysym.sym;
903 menu_event(&event.key.keysym);
904 if(key == SDLK_ESCAPE)
907 menu_set_current(&leveleditor_menu);
921 cursor_x -= KEY_CURSOR_SPEED;
923 cursor_x -= KEY_CURSOR_FASTSPEED;
925 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
926 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
931 cursor_x += KEY_CURSOR_SPEED;
933 cursor_x += KEY_CURSOR_FASTSPEED;
935 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
936 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
941 cursor_y -= KEY_CURSOR_SPEED;
943 cursor_y -= KEY_CURSOR_FASTSPEED;
950 cursor_y += KEY_CURSOR_SPEED;
952 cursor_y += KEY_CURSOR_FASTSPEED;
954 if(cursor_y > screen->h-32)
955 cursor_y = screen->h-32;
968 cursor_x = (le_current_level->width * 32) - 32;
972 le_show_grid = !le_show_grid;
978 case SDL_KEYUP: /* key released */
979 switch(event.key.keysym.sym)
988 case SDL_MOUSEBUTTONDOWN:
989 if(event.button.button == SDL_BUTTON_LEFT)
991 le_mouse_pressed[LEFT] = YES;
993 selection.x1 = event.motion.x + pos_x;
994 selection.y1 = event.motion.y;
995 selection.x2 = event.motion.x + pos_x;
996 selection.y2 = event.motion.y;
998 else if(event.button.button == SDL_BUTTON_RIGHT)
999 le_mouse_pressed[RIGHT] = YES;
1001 case SDL_MOUSEBUTTONUP:
1002 if(event.button.button == SDL_BUTTON_LEFT)
1003 le_mouse_pressed[LEFT] = NO;
1004 else if(event.button.button == SDL_BUTTON_RIGHT)
1005 le_mouse_pressed[RIGHT] = NO;
1007 case SDL_MOUSEMOTION:
1013 cursor_x = ((int)(pos_x + x) / 32) * 32;
1014 cursor_y = ((int) y / 32) * 32;
1016 if(le_mouse_pressed[LEFT] == YES)
1018 selection.x2 = x + pos_x;
1022 if(le_mouse_pressed[RIGHT] == YES)
1024 pos_x += -1 * event.motion.xrel;
1028 case SDL_QUIT: // window closed
1036 if(le_current_level != NULL)
1038 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 &&
1039 event.motion.y > 0 && event.motion.y < screen->h)))
1041 le_mouse_pressed[LEFT] = NO;
1042 le_mouse_pressed[RIGHT] = NO;
1046 /* Check for button events */
1047 button_event(&le_test_level_bt,&event);
1048 if(button_get_state(&le_test_level_bt) == BN_CLICKED)
1050 button_event(&le_save_level_bt,&event);
1051 if(button_get_state(&le_save_level_bt) == BN_CLICKED)
1052 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
1053 button_event(&le_next_level_bt,&event);
1054 if(button_get_state(&le_next_level_bt) == BN_CLICKED)
1056 if(le_level < le_level_subset.levels)
1058 le_goto_level(++le_level);
1065 sprintf(str,"Level %d doesn't exist.",le_level+1);
1066 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1067 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1068 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2,NO_UPDATE);
1072 while(SDL_PollEvent(&event))
1075 case SDL_KEYDOWN: // key pressed
1076 switch(event.key.keysym.sym)
1079 level_default(&new_lev);
1080 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
1081 le_level_subset.levels = le_level;
1082 le_goto_level(le_level);
1099 button_event(&le_previous_level_bt,&event);
1100 if(button_get_state(&le_previous_level_bt) == BN_CLICKED)
1103 le_goto_level(--le_level);
1105 button_event(&le_rubber_bt,&event);
1106 if(button_get_state(&le_rubber_bt) == BN_CLICKED)
1107 le_current_tile = '.';
1108 button_event(&le_select_mode_one_bt,&event);
1109 if(button_get_state(&le_select_mode_one_bt) == BN_CLICKED)
1110 le_selection_mode = CURSOR;
1111 button_event(&le_select_mode_two_bt,&event);
1112 if(button_get_state(&le_select_mode_two_bt) == BN_CLICKED)
1113 le_selection_mode = SQUARE;
1115 button_event(&le_bad_bt,&event);
1116 if(button_get_state(&le_bad_bt) == BN_CLICKED)
1118 le_bad_panel.hidden = NO;
1119 le_fgd_panel.hidden = YES;
1120 le_bkgd_panel.hidden = YES;
1123 button_event(&le_fgd_bt,&event);
1124 if(button_get_state(&le_fgd_bt) == BN_CLICKED)
1126 le_bad_panel.hidden = YES;
1127 le_fgd_panel.hidden = NO;
1128 le_bkgd_panel.hidden = YES;
1130 button_event(&le_bkgd_bt,&event);
1131 if(button_get_state(&le_bkgd_bt) == BN_CLICKED)
1133 le_bad_panel.hidden = YES;
1134 le_fgd_panel.hidden = YES;
1135 le_bkgd_panel.hidden = NO;
1137 button_event(&le_settings_bt,&event);
1138 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1142 update_level_settings_menu();
1143 menu_set_current(&level_settings_menu);
1148 menu_set_current(&leveleditor_menu);
1152 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1154 if(button_get_state(pbutton) == BN_CLICKED)
1157 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1158 c = 'G' + pbutton->tag;
1159 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1160 c = 'g' + pbutton->tag - 4;
1161 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1162 c = 'C' + pbutton->tag - 8;
1163 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1164 c = 'c' + pbutton->tag - 12;
1166 le_current_tile = c;
1169 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1171 if(button_get_state(pbutton) == BN_CLICKED)
1174 if(pbutton->tag == 0)
1176 else if(pbutton->tag == 1)
1178 else if(pbutton->tag == 2)
1180 else if(pbutton->tag == 3)
1182 else if(pbutton->tag == 4)
1184 else if(pbutton->tag == 5)
1186 else if(pbutton->tag == 6)
1188 else if(pbutton->tag == 7)
1190 else if(pbutton->tag == 8)
1192 else if(pbutton->tag == 9)
1194 else if(pbutton->tag == 10)
1196 else if(pbutton->tag == 11)
1198 else if(pbutton->tag == 12)
1200 else if(pbutton->tag == 13)
1202 else if(pbutton->tag == 14)
1204 else if(pbutton->tag == 15)
1206 else if(pbutton->tag == 16)
1208 else if(pbutton->tag == 17)
1211 le_current_tile = c;
1214 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1216 if(button_get_state(pbutton) == BN_CLICKED)
1219 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1220 c = '0' + pbutton->tag;
1222 le_current_tile = c;
1228 button_event(&le_settings_bt,&event);
1229 if(button_get_state(&le_settings_bt) == BN_CLICKED)
1233 update_level_settings_menu();
1234 menu_set_current(&level_settings_menu);
1239 menu_set_current(&leveleditor_menu);
1247 button_event(&le_move_left_bt,&event);
1248 button_event(&le_move_right_bt,&event);
1250 if(le_mouse_pressed[LEFT])
1252 le_change(cursor_x, cursor_y, le_current_tile);
1259 if(button_get_state(&le_move_left_bt) == BN_PRESSED)
1263 else if(button_get_state(&le_move_left_bt) == BN_HOVER)
1268 if(button_get_state(&le_move_right_bt) == BN_PRESSED)
1272 else if(button_get_state(&le_move_right_bt) == BN_HOVER)
1280 void le_highlight_selection()
1284 if(selection.x1 < selection.x2)
1294 if(selection.y1 < selection.y2)
1310 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1313 void le_change(float x, float y, unsigned char c)
1315 if(le_current_level != NULL)
1320 /* level_changed = YES; */
1322 switch(le_selection_mode)
1325 level_change(le_current_level,x,y,c);
1330 /* if there is a bad guy over there, remove it */
1331 for(i = 0; i < num_bad_guys; ++i)
1332 if (bad_guys[i].base.alive)
1333 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1334 bad_guys[i].base.alive = NO;
1336 if(c == '0') /* if it's a bad guy */
1337 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1339 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1341 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1345 if(selection.x1 < selection.x2)
1355 if(selection.y1 < selection.y2)
1371 /* if there is a bad guy over there, remove it */
1372 for(i = 0; i < num_bad_guys; ++i)
1373 if(bad_guys[i].base.alive)
1374 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1375 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1376 bad_guys[i].base.alive = NO;
1378 for(xx = x1; xx <= x2; xx++)
1379 for(yy = y1; yy <= y2; yy++)
1381 level_change(le_current_level, xx*32, yy*32, c);
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);
1399 level_save(le_current_level,"test",le_level);
1400 gameloop("test",le_level, ST_GL_TEST);
1401 menu_set_current(&leveleditor_menu);
1403 level_load_gfx(le_current_level);
1405 le_activate_bad_guys();
1411 unsigned int i, done;
1413 " - This is SuperTux's built-in level editor -",
1414 "It has been designed to be light and easy to use from the start.",
1416 "When you first load the level editor you are given a menu where you",
1417 "can load level subsets, create a new level subset, edit the current",
1418 "subset's settings, or simply quit the editor. You can access this menu",
1419 "from the level editor at any time by pressing the escape key.",
1421 "To your right is your button bar. The center of this contains many",
1422 "tiles you can use to make your level. To select a tile, click on it",
1423 "with your left mouse button; your selection will be shown in the",
1424 "bottom right corner of the button box. Click anywhere on your level",
1425 "with the left mouse button to place that tile down. If you right click",
1426 "a tile in the button bar, you can find out what its keyboard shortcut",
1427 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1428 "background, and enemy tiles. The eraser lets you remove tiles.",
1429 "The left and right arrow keys scroll back and forth through your level.",
1430 "The button with the wrench and screwdriver, lets you change the",
1431 "settings of your level, including how long it is or what music it will",
1432 "play. When you are ready to give your level a test, click on the little",
1433 "running Tux. If you like the changes you have made to your level,",
1434 "press the red save key to keep them.",
1435 "To change which level in your subset you are editing, press the white",
1436 "up and down arrow keys at the top of the button box.",
1438 "Have fun making levels! If you make some good ones, send them to us on",
1439 "the SuperTux mailing list!",
1444 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2, NO_UPDATE);
1446 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1447 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1, NO_UPDATE);
1449 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1457 while(SDL_PollEvent(&event))
1460 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1461 case SDL_KEYDOWN: // key pressed