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 bool 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 bool 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* leveleditor_menu;
112 static Menu* subset_load_menu;
113 static Menu* subset_new_menu;
114 static Menu* subset_settings_menu;
115 static Menu* 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 (leveleditor_menu->check())
198 update_subset_settings_menu();
201 done = DONE_LEVELEDITOR;
205 else if(current_menu == level_settings_menu)
207 switch (level_settings_menu->check())
210 apply_level_settings_menu();
211 Menu::set_current(leveleditor_menu);
218 else if(current_menu == subset_load_menu)
220 switch (i = subset_load_menu->check())
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 = subset_new_menu->check())
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 = new 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 = subset_settings_menu->check())
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 = true;
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 = false;
380 le_current_level = NULL;
382 le_current_tile = '.';
383 le_mouse_pressed[LEFT] = false;
384 le_mouse_pressed[RIGHT] = false;
386 texture_load(&le_selection, datadir + "/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 = true;
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 = true;
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 leveleditor_menu = new Menu();
492 subset_load_menu = new Menu();
493 subset_new_menu = new Menu();
494 subset_settings_menu = new Menu();
495 level_settings_menu = new Menu();
497 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
498 leveleditor_menu->additem(MN_HL,"",0,0);
499 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
500 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
501 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
502 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
503 leveleditor_menu->additem(MN_HL,"",0,0);
504 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
507 Menu::set_current(leveleditor_menu);
510 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
511 subset_load_menu->additem(MN_HL, "", 0, 0);
513 for(i = 0; i < level_subsets.num_items; ++i)
515 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
517 subset_load_menu->additem(MN_HL,"",0,0);
518 subset_load_menu->additem(MN_BACK,"Back",0,0);
520 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
521 subset_new_menu->additem(MN_HL,"",0,0);
522 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
523 subset_new_menu->additem(MN_ACTION,"Create",0,0);
524 subset_new_menu->additem(MN_HL,"",0,0);
525 subset_new_menu->additem(MN_BACK,"Back",0,0);
527 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
528 subset_settings_menu->additem(MN_HL,"",0,0);
529 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
530 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
531 subset_settings_menu->additem(MN_HL,"",0,0);
532 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
533 subset_settings_menu->additem(MN_HL,"",0,0);
534 subset_settings_menu->additem(MN_BACK,"Back",0,0);
536 level_settings_menu->arrange_left = true;
537 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
538 level_settings_menu->additem(MN_HL,"",0,0);
539 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
540 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
541 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
542 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
543 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
544 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
545 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
546 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
547 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
548 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
549 level_settings_menu->additem(MN_HL,"",0,0);
550 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
552 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
557 void update_level_settings_menu()
562 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
563 sprintf(str,"%d",le_current_level->width);
565 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
566 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
567 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
568 string_list_add_item(level_settings_menu->item[5].list,"");
569 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
570 level_settings_menu->item[3].list->active_item = i;
571 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
572 level_settings_menu->item[4].list->active_item = i;
573 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
574 level_settings_menu->item[5].list->active_item = i;
576 menu_item_change_input(&level_settings_menu->item[6], str);
577 sprintf(str,"%d",le_current_level->time_left);
578 menu_item_change_input(&level_settings_menu->item[7], str);
579 sprintf(str,"%2.0f",le_current_level->gravity);
580 menu_item_change_input(&level_settings_menu->item[8], str);
581 sprintf(str,"%d",le_current_level->bkgd_red);
582 menu_item_change_input(&level_settings_menu->item[9], str);
583 sprintf(str,"%d",le_current_level->bkgd_green);
584 menu_item_change_input(&level_settings_menu->item[10], str);
585 sprintf(str,"%d",le_current_level->bkgd_blue);
586 menu_item_change_input(&level_settings_menu->item[11], str);
589 void update_subset_settings_menu()
591 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
592 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
595 void apply_level_settings_menu()
600 le_current_level->name = level_settings_menu->item[2].input;
602 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
604 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
608 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
610 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
611 le_update_buttons(le_current_level->theme.c_str());
618 level_load_gfx(le_current_level);
621 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
623 i = le_current_level->width;
624 le_current_level->width = atoi(level_settings_menu->item[6].input);
625 if(le_current_level->width < i)
627 if(le_current_level->width < 21)
628 le_current_level->width = 21;
629 for(y = 0; y < 15; ++y)
631 le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
632 le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
635 else if(le_current_level->width > i)
637 for(y = 0; y < 15; ++y)
639 le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int));
640 for(j = 0; j < le_current_level->width - i; ++j)
641 le_current_level->tiles[y][i+j] = (unsigned int) '.';
642 le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0';
645 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
646 le_current_level->gravity = atof(level_settings_menu->item[8].input);
647 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
648 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
649 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
652 void save_subset_settings_menu()
654 le_level_subset.title = subset_settings_menu->item[2].input;
655 le_level_subset.description = subset_settings_menu->item[3].input;
656 le_level_subset.save();
659 void le_goto_level(int levelnb)
664 level_free(le_current_level);
665 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
667 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
676 le_update_buttons(le_current_level->theme.c_str());
679 level_load_gfx(le_current_level);
681 le_activate_bad_guys();
686 /*if(level_changed == true)
687 if(askforsaving() == CANCEL)
690 SDL_EnableKeyRepeat(0, 0); // disables key repeating
692 texture_free(&le_selection);
693 delete leveleditor_menu;
694 delete subset_load_menu;
695 delete subset_new_menu;
696 delete subset_settings_menu;
697 delete level_settings_menu;
698 button_panel_free(&le_bkgd_panel);
699 button_panel_free(&le_fgd_panel);
700 button_panel_free(&le_bad_panel);
701 button_free(&le_save_level_bt);
702 button_free(&le_test_level_bt);
703 button_free(&le_next_level_bt);
704 button_free(&le_previous_level_bt);
705 button_free(&le_move_right_bt);
706 button_free(&le_move_left_bt);
707 button_free(&le_rubber_bt);
708 button_free(&le_select_mode_one_bt);
709 button_free(&le_select_mode_two_bt);
710 button_free(&le_settings_bt);
711 button_free(&le_bad_bt);
712 button_free(&le_bkgd_bt);
713 button_free(&le_fgd_bt);
715 if(le_current_level != NULL)
718 level_free(le_current_level);
724 void le_drawinterface()
729 if(le_current_level != NULL)
731 /* draw a grid (if selected) */
734 for(x = 0; x < 19; x++)
735 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
736 for(y = 0; y < 15; y++)
737 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
741 if(le_selection_mode == CURSOR)
742 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
743 else if(le_selection_mode == SQUARE)
746 le_highlight_selection();
747 /* draw current selection */
748 w = selection.x2 - selection.x1;
749 h = selection.y2 - selection.y1;
750 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
751 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
752 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
753 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
757 /* draw button bar */
758 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
759 drawshape(19 * 32, 14 * 32, le_current_tile);
760 switch(le_current_tile)
763 texture_draw(&img_mints, 19 * 32, 14 * 32);
766 texture_draw(&img_golden_herring,19 * 32, 14 * 32);
771 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
774 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
777 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
780 texture_draw(&img_money_left[0],19 * 32, 14 * 32);
786 if(le_current_level != NULL)
788 button_draw(&le_save_level_bt);
789 button_draw(&le_test_level_bt);
790 button_draw(&le_next_level_bt);
791 button_draw(&le_previous_level_bt);
792 button_draw(&le_rubber_bt);
793 button_draw(&le_select_mode_one_bt);
794 button_draw(&le_select_mode_two_bt);
795 button_draw(&le_settings_bt);
796 button_draw(&le_move_right_bt);
797 button_draw(&le_move_left_bt);
798 button_draw(&le_bad_bt);
799 button_draw(&le_bkgd_bt);
800 button_draw(&le_fgd_bt);
801 button_panel_draw(&le_bkgd_panel);
802 button_panel_draw(&le_fgd_panel);
803 button_panel_draw(&le_bad_panel);
805 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
806 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
808 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
812 if(show_menu == false)
813 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
815 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
822 unsigned int y,x,i,s;
824 /* Draw the real background */
825 if(le_current_level->bkgd_image[0] != '\0')
828 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
829 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
833 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
836 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
838 for (y = 0; y < 15; ++y)
839 for (x = 0; x < 20; ++x)
841 drawshape(x * 32 - ((int)pos_x % 32), y * 32,
842 le_current_level->tiles[y][x + (int)(pos_x / 32)]);
844 /* draw whats inside stuff when cursor is selecting those */
845 /* (draw them all the time - is this the right behaviour?) */
846 switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
849 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
852 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
857 texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
864 /* Draw the Bad guys: */
865 for (i = 0; i < bad_guys.size(); ++i)
867 /* to support frames: img_bsod_left[(frame / 5) % 4] */
868 if(bad_guys[i].kind == BAD_BSOD)
869 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
870 else if(bad_guys[i].kind == BAD_LAPTOP)
871 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
872 else if (bad_guys[i].kind == BAD_MONEY)
873 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
877 /* Draw the player: */
878 /* for now, the position is fixed at (0, 240) */
879 texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240);
882 void le_checkevents()
886 button_type* pbutton;
889 keymod = SDL_GetModState();
891 while(SDL_PollEvent(&event))
893 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
894 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
895 event.motion.y > 0 && event.motion.y < screen->h)))
900 case SDL_KEYDOWN: // key pressed
901 key = event.key.keysym.sym;
904 menu_event(&event.key.keysym);
905 if(key == SDLK_ESCAPE)
908 Menu::set_current(leveleditor_menu);
922 cursor_x -= KEY_CURSOR_SPEED;
924 cursor_x -= KEY_CURSOR_FASTSPEED;
926 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
927 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
932 cursor_x += KEY_CURSOR_SPEED;
934 cursor_x += KEY_CURSOR_FASTSPEED;
936 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
937 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
942 cursor_y -= KEY_CURSOR_SPEED;
944 cursor_y -= KEY_CURSOR_FASTSPEED;
951 cursor_y += KEY_CURSOR_SPEED;
953 cursor_y += KEY_CURSOR_FASTSPEED;
955 if(cursor_y > screen->h-32)
956 cursor_y = screen->h-32;
969 cursor_x = (le_current_level->width * 32) - 32;
973 le_show_grid = !le_show_grid;
979 case SDL_KEYUP: /* key released */
980 switch(event.key.keysym.sym)
989 case SDL_MOUSEBUTTONDOWN:
990 if(event.button.button == SDL_BUTTON_LEFT)
992 le_mouse_pressed[LEFT] = true;
994 selection.x1 = event.motion.x + pos_x;
995 selection.y1 = event.motion.y;
996 selection.x2 = event.motion.x + pos_x;
997 selection.y2 = event.motion.y;
999 else if(event.button.button == SDL_BUTTON_RIGHT)
1000 le_mouse_pressed[RIGHT] = true;
1002 case SDL_MOUSEBUTTONUP:
1003 if(event.button.button == SDL_BUTTON_LEFT)
1004 le_mouse_pressed[LEFT] = false;
1005 else if(event.button.button == SDL_BUTTON_RIGHT)
1006 le_mouse_pressed[RIGHT] = false;
1008 case SDL_MOUSEMOTION:
1014 cursor_x = ((int)(pos_x + x) / 32) * 32;
1015 cursor_y = ((int) y / 32) * 32;
1017 if(le_mouse_pressed[LEFT] == true)
1019 selection.x2 = x + pos_x;
1023 if(le_mouse_pressed[RIGHT] == true)
1025 pos_x += -1 * event.motion.xrel;
1029 case SDL_QUIT: // window closed
1037 if(le_current_level != NULL)
1039 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 &&
1040 event.motion.y > 0 && event.motion.y < screen->h)))
1042 le_mouse_pressed[LEFT] = false;
1043 le_mouse_pressed[RIGHT] = false;
1045 if(show_menu == false)
1047 /* Check for button events */
1048 button_event(&le_test_level_bt,&event);
1049 if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
1051 button_event(&le_save_level_bt,&event);
1052 if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
1053 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
1054 button_event(&le_next_level_bt,&event);
1055 if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
1057 if(le_level < le_level_subset.levels)
1059 le_goto_level(++le_level);
1066 sprintf(str,"Level %d doesn't exist.",le_level+1);
1067 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
1068 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
1069 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
1073 while(SDL_PollEvent(&event))
1076 case SDL_KEYDOWN: // key pressed
1077 switch(event.key.keysym.sym)
1080 level_default(&new_lev);
1081 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
1082 le_level_subset.levels = le_level;
1083 le_goto_level(le_level);
1100 button_event(&le_previous_level_bt,&event);
1101 if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1104 le_goto_level(--le_level);
1106 button_event(&le_rubber_bt,&event);
1107 if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1108 le_current_tile = '.';
1109 button_event(&le_select_mode_one_bt,&event);
1110 if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1111 le_selection_mode = CURSOR;
1112 button_event(&le_select_mode_two_bt,&event);
1113 if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1114 le_selection_mode = SQUARE;
1116 button_event(&le_bad_bt,&event);
1117 if(button_get_state(&le_bad_bt) == BUTTON_CLICKED)
1119 le_bad_panel.hidden = false;
1120 le_fgd_panel.hidden = true;
1121 le_bkgd_panel.hidden = true;
1124 button_event(&le_fgd_bt,&event);
1125 if(button_get_state(&le_fgd_bt) == BUTTON_CLICKED)
1127 le_bad_panel.hidden = true;
1128 le_fgd_panel.hidden = false;
1129 le_bkgd_panel.hidden = true;
1131 button_event(&le_bkgd_bt,&event);
1132 if(button_get_state(&le_bkgd_bt) == BUTTON_CLICKED)
1134 le_bad_panel.hidden = true;
1135 le_fgd_panel.hidden = true;
1136 le_bkgd_panel.hidden = false;
1138 button_event(&le_settings_bt,&event);
1139 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1141 if(show_menu == false)
1143 update_level_settings_menu();
1144 Menu::set_current(level_settings_menu);
1149 Menu::set_current(leveleditor_menu);
1153 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1155 if(button_get_state(pbutton) == BUTTON_CLICKED)
1158 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1159 c = 'G' + pbutton->tag;
1160 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1161 c = 'g' + pbutton->tag - 4;
1162 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1163 c = 'C' + pbutton->tag - 8;
1164 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1165 c = 'c' + pbutton->tag - 12;
1167 le_current_tile = c;
1170 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1172 if(button_get_state(pbutton) == BUTTON_CLICKED)
1175 if(pbutton->tag == 0)
1177 else if(pbutton->tag == 1)
1179 else if(pbutton->tag == 2)
1181 else if(pbutton->tag == 3)
1183 else if(pbutton->tag == 4)
1185 else if(pbutton->tag == 5)
1187 else if(pbutton->tag == 6)
1189 else if(pbutton->tag == 7)
1191 else if(pbutton->tag == 8)
1193 else if(pbutton->tag == 9)
1195 else if(pbutton->tag == 10)
1197 else if(pbutton->tag == 11)
1199 else if(pbutton->tag == 12)
1201 else if(pbutton->tag == 13)
1203 else if(pbutton->tag == 14)
1205 else if(pbutton->tag == 15)
1207 else if(pbutton->tag == 16)
1209 else if(pbutton->tag == 17)
1212 le_current_tile = c;
1215 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1217 if(button_get_state(pbutton) == BUTTON_CLICKED)
1220 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1221 c = '0' + pbutton->tag;
1223 le_current_tile = c;
1229 button_event(&le_settings_bt,&event);
1230 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1232 if(show_menu == false)
1234 update_level_settings_menu();
1235 Menu::set_current(level_settings_menu);
1240 Menu::set_current(leveleditor_menu);
1246 if(show_menu == false)
1248 button_event(&le_move_left_bt,&event);
1249 button_event(&le_move_right_bt,&event);
1251 if(le_mouse_pressed[LEFT])
1253 le_change(cursor_x, cursor_y, le_current_tile);
1258 if(show_menu == false)
1260 if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1264 else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1269 if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1273 else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1281 void le_highlight_selection()
1285 if(selection.x1 < selection.x2)
1295 if(selection.y1 < selection.y2)
1311 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1314 void le_change(float x, float y, unsigned char c)
1316 if(le_current_level != NULL)
1322 /* level_changed = true; */
1324 switch(le_selection_mode)
1327 level_change(le_current_level,x,y,c);
1332 /* if there is a bad guy over there, remove it */
1333 for(i = 0; i < bad_guys.size(); ++i)
1334 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1335 bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(&bad_guys[i]));
1337 if(c == '0') /* if it's a bad guy */
1338 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1340 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1342 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1346 if(selection.x1 < selection.x2)
1356 if(selection.y1 < selection.y2)
1372 /* if there is a bad guy over there, remove it */
1373 for(i = 0; i < bad_guys.size(); ++i)
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.erase(static_cast<std::vector<bad_guy_type>::iterator>(&bad_guys[i]));
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);
1446 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1447 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1449 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1457 while(SDL_PollEvent(&event))
1460 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1461 case SDL_KEYDOWN: // key pressed