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, int tm, unsigned int 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 unsigned int 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_set_defaults()
123 if(le_current_level != NULL)
127 if(le_current_level->time_left == 0)
128 le_current_level->time_left = 255;
132 int leveleditor(int levelnb)
134 int last_time, now_time, i;
142 clearscreen(0, 0, 0);
145 while (SDL_PollEvent(&event))
150 last_time = SDL_GetTicks();
155 if(le_current_level != NULL)
157 /* making events results to be in order */
160 if(pos_x > (le_current_level->width * 32) - screen->w)
161 pos_x = (le_current_level->width * 32) - screen->w;
167 clearscreen(0, 0, 0);
169 /* draw editor interface */
174 menu_process_current();
175 if(current_menu == leveleditor_menu)
177 switch (leveleditor_menu->check())
183 update_subset_settings_menu();
186 done = DONE_LEVELEDITOR;
190 else if(current_menu == level_settings_menu)
192 switch (level_settings_menu->check())
195 apply_level_settings_menu();
196 Menu::set_current(leveleditor_menu);
203 else if(current_menu == subset_load_menu)
205 switch (i = subset_load_menu->check())
212 le_level_subset.load(level_subsets.item[i-2]);
213 leveleditor_menu->item[3].kind = MN_GOTO;
217 le_current_level = new st_level;
218 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
223 le_update_buttons(le_current_level->theme.c_str());
225 level_load_gfx(le_current_level);
231 else if(current_menu == subset_new_menu)
233 if(subset_new_menu->item[2].input[0] == '\0')
234 subset_new_menu->item[3].kind = MN_DEACTIVE;
237 subset_new_menu->item[3].kind = MN_ACTION;
239 switch (i = subset_new_menu->check())
242 st_subset::create(subset_new_menu->item[2].input);
243 le_level_subset.load(subset_new_menu->item[2].input);
244 leveleditor_menu->item[3].kind = MN_GOTO;
248 le_current_level = new st_level;
249 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
254 le_update_buttons(le_current_level->theme.c_str());
256 level_load_gfx(le_current_level);
257 menu_item_change_input(&subset_new_menu->item[2],"");
263 else if(current_menu == subset_settings_menu)
265 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 )
266 subset_settings_menu->item[5].kind = MN_DEACTIVE;
268 subset_settings_menu->item[5].kind = MN_ACTION;
270 switch (i = subset_settings_menu->check())
273 save_subset_settings_menu();
280 mouse_cursor->draw();
288 if(done == DONE_QUIT)
295 now_time = SDL_GetTicks();
296 if (now_time < last_time + FPS)
297 SDL_Delay(last_time + FPS - now_time); /* delay some time */
306 void le_update_buttons(const char *theme)
312 string_list_type bkgd_files;
313 string_list_type fgd_files;
315 sprintf(pathname,"images/themes/%s",theme);
316 bkgd_files = dfiles(pathname,"bkgd-", NULL);
317 string_list_sort(&bkgd_files);
319 le_bkgd_panel.hidden = true;
321 for(i = 0; i < bkgd_files.num_items; ++i)
323 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
324 button_change_icon(&le_bkgd_panel.item[i],filename);
327 sprintf(pathname,"images/themes/%s",theme);
328 fgd_files = dfiles(pathname,"solid", NULL);
329 string_list_sort(&fgd_files);
331 for(i = 0; i < fgd_files.num_items; ++i)
333 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
334 button_change_icon(&le_fgd_panel.item[i],filename);
337 string_list_free(&fgd_files);
338 fgd_files = dfiles(pathname,"brick", NULL);
339 string_list_sort(&fgd_files);
341 for(i = 0; i < fgd_files.num_items; ++i)
343 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
344 button_change_icon(&le_fgd_panel.item[i+14],filename);
353 string_list_type fgd_files;
354 string_list_type bkgd_files;
355 string_list_type bad_files;
356 level_subsets = dsubdirs("/levels", "info");
360 /* level_changed = NO;*/
363 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
364 le_level_changed = false;
365 le_current_level = NULL;
368 le_mouse_pressed[LEFT] = false;
369 le_mouse_pressed[RIGHT] = false;
371 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
374 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
375 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
376 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
377 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
378 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
379 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
380 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
381 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
382 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
383 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
384 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
385 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
386 button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
388 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
389 string_list_sort(&bkgd_files);
391 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
392 le_bkgd_panel.hidden = true;
394 for(i = 0; i < bkgd_files.num_items; ++i)
396 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
397 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
400 string_list_free(&bkgd_files);
401 bkgd_files = dfiles("images/shared","cloud-", NULL);
402 string_list_sort(&bkgd_files);
404 for(i = 0; i < bkgd_files.num_items; ++i)
406 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
407 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
410 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
411 string_list_sort(&fgd_files);
413 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
414 for(i = 0; i < fgd_files.num_items; ++i)
416 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
417 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
420 string_list_free(&fgd_files);
421 string_list_add_item(&fgd_files,"waves-0.png");
422 string_list_add_item(&fgd_files,"water.png");
423 string_list_add_item(&fgd_files,"pole.png");
424 string_list_add_item(&fgd_files,"poletop.png");
425 string_list_add_item(&fgd_files,"flag-0.png");
426 string_list_add_item(&fgd_files,"box-empty.png");
427 string_list_add_item(&fgd_files,"mints.png");
428 string_list_add_item(&fgd_files,"distro-0.png");
429 string_list_add_item(&fgd_files,"golden-herring.png");
430 string_list_add_item(&fgd_files,"distro-0.png");
432 for(i = 0; i < fgd_files.num_items; ++i)
434 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
435 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
438 string_list_free(&fgd_files);
439 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
440 string_list_sort(&fgd_files);
442 for(i = 0; i < fgd_files.num_items; ++i)
444 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
445 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
448 string_list_free(&fgd_files);
449 string_list_add_item(&fgd_files,"distro-0.png");
450 string_list_add_item(&fgd_files,"distro-0.png");
451 for(i = 0; i < fgd_files.num_items; ++i)
453 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
454 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
457 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
458 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
459 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
460 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
461 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
463 string_list_init(&bad_files);
464 string_list_add_item(&bad_files,"bsod-left-0.png");
465 string_list_add_item(&bad_files,"laptop-left-0.png");
466 string_list_add_item(&bad_files,"bag-left-0.png");
467 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
468 le_bad_panel.hidden = true;
470 for(i = 0; i < bad_files.num_items; ++i)
472 sprintf(filename,"images/shared/%s",bad_files.item[i]);
473 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
476 leveleditor_menu = new Menu();
477 subset_load_menu = new Menu();
478 subset_new_menu = new Menu();
479 subset_settings_menu = new Menu();
480 level_settings_menu = new Menu();
482 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
483 leveleditor_menu->additem(MN_HL,"",0,0);
484 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
485 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
486 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
487 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
488 leveleditor_menu->additem(MN_HL,"",0,0);
489 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
492 Menu::set_current(leveleditor_menu);
495 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
496 subset_load_menu->additem(MN_HL, "", 0, 0);
498 for(i = 0; i < level_subsets.num_items; ++i)
500 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
502 subset_load_menu->additem(MN_HL,"",0,0);
503 subset_load_menu->additem(MN_BACK,"Back",0,0);
505 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
506 subset_new_menu->additem(MN_HL,"",0,0);
507 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
508 subset_new_menu->additem(MN_ACTION,"Create",0,0);
509 subset_new_menu->additem(MN_HL,"",0,0);
510 subset_new_menu->additem(MN_BACK,"Back",0,0);
512 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
513 subset_settings_menu->additem(MN_HL,"",0,0);
514 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
515 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
516 subset_settings_menu->additem(MN_HL,"",0,0);
517 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
518 subset_settings_menu->additem(MN_HL,"",0,0);
519 subset_settings_menu->additem(MN_BACK,"Back",0,0);
521 level_settings_menu->arrange_left = true;
522 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
523 level_settings_menu->additem(MN_HL,"",0,0);
524 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
525 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
526 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
527 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
528 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
529 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
530 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
531 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
532 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
533 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
534 level_settings_menu->additem(MN_HL,"",0,0);
535 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
537 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
542 void update_level_settings_menu()
547 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
548 sprintf(str,"%d",le_current_level->width);
550 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
551 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
552 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
553 string_list_add_item(level_settings_menu->item[5].list,"");
554 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
555 level_settings_menu->item[3].list->active_item = i;
556 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
557 level_settings_menu->item[4].list->active_item = i;
558 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
559 level_settings_menu->item[5].list->active_item = i;
561 menu_item_change_input(&level_settings_menu->item[6], str);
562 sprintf(str,"%d",le_current_level->time_left);
563 menu_item_change_input(&level_settings_menu->item[7], str);
564 sprintf(str,"%2.0f",le_current_level->gravity);
565 menu_item_change_input(&level_settings_menu->item[8], str);
566 sprintf(str,"%d",le_current_level->bkgd_red);
567 menu_item_change_input(&level_settings_menu->item[9], str);
568 sprintf(str,"%d",le_current_level->bkgd_green);
569 menu_item_change_input(&level_settings_menu->item[10], str);
570 sprintf(str,"%d",le_current_level->bkgd_blue);
571 menu_item_change_input(&level_settings_menu->item[11], str);
574 void update_subset_settings_menu()
576 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
577 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
580 void apply_level_settings_menu()
585 le_current_level->name = level_settings_menu->item[2].input;
587 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
589 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
593 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
595 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
596 le_update_buttons(le_current_level->theme.c_str());
603 level_load_gfx(le_current_level);
606 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
608 level_change_size(le_current_level, atoi(level_settings_menu->item[6].input));
609 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
610 le_current_level->gravity = atof(level_settings_menu->item[8].input);
611 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
612 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
613 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
616 void save_subset_settings_menu()
618 le_level_subset.title = subset_settings_menu->item[2].input;
619 le_level_subset.description = subset_settings_menu->item[3].input;
620 le_level_subset.save();
623 void le_goto_level(int levelnb)
628 level_free(le_current_level);
629 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
631 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
640 le_update_buttons(le_current_level->theme.c_str());
643 level_load_gfx(le_current_level);
648 /*if(level_changed == true)
649 if(askforsaving() == CANCEL)
652 SDL_EnableKeyRepeat(0, 0); // disables key repeating
654 texture_free(&le_selection);
655 delete leveleditor_menu;
656 delete subset_load_menu;
657 delete subset_new_menu;
658 delete subset_settings_menu;
659 delete level_settings_menu;
660 button_panel_free(&le_bkgd_panel);
661 button_panel_free(&le_fgd_panel);
662 button_panel_free(&le_bad_panel);
663 button_free(&le_save_level_bt);
664 button_free(&le_test_level_bt);
665 button_free(&le_next_level_bt);
666 button_free(&le_previous_level_bt);
667 button_free(&le_move_right_bt);
668 button_free(&le_move_left_bt);
669 button_free(&le_rubber_bt);
670 button_free(&le_select_mode_one_bt);
671 button_free(&le_select_mode_two_bt);
672 button_free(&le_settings_bt);
673 button_free(&le_bad_bt);
674 button_free(&le_bkgd_bt);
675 button_free(&le_fgd_bt);
677 if(le_current_level != NULL)
680 level_free(le_current_level);
686 void le_drawinterface()
691 if(le_current_level != NULL)
693 /* draw a grid (if selected) */
696 for(x = 0; x < 19; x++)
697 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
698 for(y = 0; y < 15; y++)
699 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
703 if(le_selection_mode == CURSOR)
704 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
705 else if(le_selection_mode == SQUARE)
708 le_highlight_selection();
709 /* draw current selection */
710 w = selection.x2 - selection.x1;
711 h = selection.y2 - selection.y1;
712 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
713 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
714 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
715 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
719 /* draw button bar */
720 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
721 drawshape(19 * 32, 14 * 32, le_current_tile);
722 switch(le_current_tile)
725 texture_draw(&img_mints, 19 * 32, 14 * 32);
728 texture_draw(&img_golden_herring,19 * 32, 14 * 32);
733 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
736 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
739 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
742 texture_draw(&img_money_left[0],19 * 32, 14 * 32);
748 if(le_current_level != NULL)
750 button_draw(&le_save_level_bt);
751 button_draw(&le_test_level_bt);
752 button_draw(&le_next_level_bt);
753 button_draw(&le_previous_level_bt);
754 button_draw(&le_rubber_bt);
755 button_draw(&le_select_mode_one_bt);
756 button_draw(&le_select_mode_two_bt);
757 button_draw(&le_settings_bt);
758 button_draw(&le_move_right_bt);
759 button_draw(&le_move_left_bt);
760 button_draw(&le_bad_bt);
761 button_draw(&le_bkgd_bt);
762 button_draw(&le_fgd_bt);
763 button_panel_draw(&le_bkgd_panel);
764 button_panel_draw(&le_fgd_panel);
765 button_panel_draw(&le_bad_panel);
767 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
768 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
770 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
774 if(show_menu == false)
775 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
777 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
784 unsigned int y,x,i,s;
786 /* Draw the real background */
787 if(le_current_level->bkgd_image[0] != '\0')
790 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
791 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
795 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
798 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
800 for (y = 0; y < 15; ++y)
801 for (x = 0; x < 20; ++x)
803 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]);
805 /* draw whats inside stuff when cursor is selecting those */
806 /* (draw them all the time - is this the right behaviour?) */
807 switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)])
810 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
813 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
818 texture_draw(&img_distro[(global_frame_counter / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
825 /* Draw the Bad guys: */
826 for (i = 0; i < bad_guys.size(); ++i)
828 /* to support frames: img_bsod_left[(frame / 5) % 4] */
829 if(bad_guys[i].kind == BAD_BSOD)
830 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
831 else if(bad_guys[i].kind == BAD_LAPTOP)
832 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
833 else if (bad_guys[i].kind == BAD_MONEY)
834 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
838 /* Draw the player: */
839 /* for now, the position is fixed at (0, 240) */
840 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 0 - pos_x, 240);
843 void le_checkevents()
847 button_type* pbutton;
850 keymod = SDL_GetModState();
852 while(SDL_PollEvent(&event))
857 mouse_cursor->set_state(MC_NORMAL);
859 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
860 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
861 event.motion.y > 0 && event.motion.y < screen->h)))
865 case SDL_KEYDOWN: // key pressed
866 key = event.key.keysym.sym;
869 if(key == SDLK_ESCAPE)
872 Menu::set_current(leveleditor_menu);
886 cursor_x -= KEY_CURSOR_SPEED;
888 cursor_x -= KEY_CURSOR_FASTSPEED;
890 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
891 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
896 cursor_x += KEY_CURSOR_SPEED;
898 cursor_x += KEY_CURSOR_FASTSPEED;
900 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
901 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
906 cursor_y -= KEY_CURSOR_SPEED;
908 cursor_y -= KEY_CURSOR_FASTSPEED;
915 cursor_y += KEY_CURSOR_SPEED;
917 cursor_y += KEY_CURSOR_FASTSPEED;
919 if(cursor_y > screen->h-32)
920 cursor_y = screen->h-32;
933 cursor_x = (le_current_level->width * 32) - 32;
937 le_show_grid = !le_show_grid;
943 case SDL_KEYUP: /* key released */
944 switch(event.key.keysym.sym)
953 case SDL_MOUSEBUTTONDOWN:
954 if(event.button.button == SDL_BUTTON_LEFT)
956 le_mouse_pressed[LEFT] = true;
958 selection.x1 = event.motion.x + pos_x;
959 selection.y1 = event.motion.y;
960 selection.x2 = event.motion.x + pos_x;
961 selection.y2 = event.motion.y;
963 else if(event.button.button == SDL_BUTTON_RIGHT)
964 le_mouse_pressed[RIGHT] = true;
966 case SDL_MOUSEBUTTONUP:
967 if(event.button.button == SDL_BUTTON_LEFT)
968 le_mouse_pressed[LEFT] = false;
969 else if(event.button.button == SDL_BUTTON_RIGHT)
970 le_mouse_pressed[RIGHT] = false;
972 case SDL_MOUSEMOTION:
978 cursor_x = ((int)(pos_x + x) / 32) * 32;
979 cursor_y = ((int) y / 32) * 32;
981 if(le_mouse_pressed[LEFT])
983 selection.x2 = x + pos_x;
987 if(le_mouse_pressed[RIGHT])
989 pos_x += -1 * event.motion.xrel;
993 case SDL_QUIT: // window closed
1001 if(le_current_level != NULL)
1003 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 &&
1004 event.motion.y > 0 && event.motion.y < screen->h)))
1006 le_mouse_pressed[LEFT] = false;
1007 le_mouse_pressed[RIGHT] = false;
1009 if(show_menu == false)
1011 /* Check for button events */
1012 button_event(&le_test_level_bt,&event);
1013 if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
1015 button_event(&le_save_level_bt,&event);
1016 if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
1017 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
1018 button_event(&le_next_level_bt,&event);
1019 if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
1021 if(le_level < le_level_subset.levels)
1023 le_goto_level(++le_level);
1030 sprintf(str,"Level %d doesn't exist.",le_level+1);
1031 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
1032 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
1033 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
1037 while(SDL_PollEvent(&event))
1040 case SDL_KEYDOWN: // key pressed
1041 switch(event.key.keysym.sym)
1044 level_default(&new_lev);
1045 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
1046 le_level_subset.levels = le_level;
1047 le_goto_level(le_level);
1064 button_event(&le_previous_level_bt,&event);
1065 if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1068 le_goto_level(--le_level);
1070 button_event(&le_rubber_bt,&event);
1071 if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1072 le_current_tile = 0;
1073 button_event(&le_select_mode_one_bt,&event);
1074 if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1075 le_selection_mode = CURSOR;
1076 button_event(&le_select_mode_two_bt,&event);
1077 if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1078 le_selection_mode = SQUARE;
1080 button_event(&le_bad_bt,&event);
1081 if(button_get_state(&le_bad_bt) == BUTTON_CLICKED)
1083 le_bad_panel.hidden = false;
1084 le_fgd_panel.hidden = true;
1085 le_bkgd_panel.hidden = true;
1088 button_event(&le_fgd_bt,&event);
1089 if(button_get_state(&le_fgd_bt) == BUTTON_CLICKED)
1091 le_bad_panel.hidden = true;
1092 le_fgd_panel.hidden = false;
1093 le_bkgd_panel.hidden = true;
1095 button_event(&le_bkgd_bt,&event);
1096 if(button_get_state(&le_bkgd_bt) == BUTTON_CLICKED)
1098 le_bad_panel.hidden = true;
1099 le_fgd_panel.hidden = true;
1100 le_bkgd_panel.hidden = false;
1102 button_event(&le_settings_bt,&event);
1103 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1105 if(show_menu == false)
1107 update_level_settings_menu();
1108 Menu::set_current(level_settings_menu);
1113 Menu::set_current(leveleditor_menu);
1117 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1119 if(button_get_state(pbutton) == BUTTON_CLICKED)
1122 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1123 c = 'G' + pbutton->tag;
1124 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1125 c = 'g' + pbutton->tag - 4;
1126 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1127 c = 'C' + pbutton->tag - 8;
1128 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1129 c = 'c' + pbutton->tag - 12;
1131 le_current_tile = c;
1134 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1136 if(button_get_state(pbutton) == BUTTON_CLICKED)
1139 if(pbutton->tag == 0)
1141 else if(pbutton->tag == 1)
1143 else if(pbutton->tag == 2)
1145 else if(pbutton->tag == 3)
1147 else if(pbutton->tag == 4)
1149 else if(pbutton->tag == 5)
1151 else if(pbutton->tag == 6)
1153 else if(pbutton->tag == 7)
1155 else if(pbutton->tag == 8)
1157 else if(pbutton->tag == 9)
1159 else if(pbutton->tag == 10)
1161 else if(pbutton->tag == 11)
1163 else if(pbutton->tag == 12)
1165 else if(pbutton->tag == 13)
1167 else if(pbutton->tag == 14)
1169 else if(pbutton->tag == 15)
1171 else if(pbutton->tag == 16)
1173 else if(pbutton->tag == 17)
1176 le_current_tile = c;
1179 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1181 if(button_get_state(pbutton) == BUTTON_CLICKED)
1184 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1185 c = '0' + pbutton->tag;
1187 le_current_tile = c;
1193 button_event(&le_settings_bt,&event);
1194 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1196 if(show_menu == false)
1198 update_level_settings_menu();
1199 Menu::set_current(level_settings_menu);
1204 Menu::set_current(leveleditor_menu);
1210 if(show_menu == false)
1212 button_event(&le_move_left_bt,&event);
1213 button_event(&le_move_right_bt,&event);
1215 if(le_mouse_pressed[LEFT])
1217 le_change(cursor_x, cursor_y, TM_IA, le_current_tile);
1222 if(show_menu == false)
1224 if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1228 else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1233 if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1237 else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1245 void le_highlight_selection()
1249 if(selection.x1 < selection.x2)
1259 if(selection.y1 < selection.y2)
1275 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1278 void le_change(float x, float y, int tm, unsigned int c)
1280 if(le_current_level != NULL)
1286 /* level_changed = true; */
1288 switch(le_selection_mode)
1291 level_change(le_current_level,x,y,tm,c);
1296 /* if there is a bad guy over there, remove it */
1297 for(i = 0; i < bad_guys.size(); ++i)
1298 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1299 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1301 if(c == '0') /* if it's a bad guy */
1302 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1304 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1306 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1310 if(selection.x1 < selection.x2)
1320 if(selection.y1 < selection.y2)
1336 /* if there is a bad guy over there, remove it */
1337 for(i = 0; i < bad_guys.size(); ++i)
1338 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1339 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1340 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1342 for(xx = x1; xx <= x2; xx++)
1343 for(yy = y1; yy <= y2; yy++)
1345 level_change(le_current_level, xx*32, yy*32, tm, c);
1347 if(c == '0') // if it's a bad guy
1348 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1350 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1352 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1363 level_save(le_current_level,"test",le_level);
1364 gameloop("test",le_level, ST_GL_TEST);
1365 Menu::set_current(leveleditor_menu);
1367 level_load_gfx(le_current_level);
1374 unsigned int i, done;
1376 " - This is SuperTux's built-in level editor -",
1377 "It has been designed to be light and easy to use from the start.",
1379 "When you first load the level editor you are given a menu where you",
1380 "can load level subsets, create a new level subset, edit the current",
1381 "subset's settings, or simply quit the editor. You can access this menu",
1382 "from the level editor at any time by pressing the escape key.",
1384 "To your right is your button bar. The center of this contains many",
1385 "tiles you can use to make your level. To select a tile, click on it",
1386 "with your left mouse button; your selection will be shown in the",
1387 "bottom right corner of the button box. Click anywhere on your level",
1388 "with the left mouse button to place that tile down. If you right click",
1389 "a tile in the button bar, you can find out what its keyboard shortcut",
1390 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1391 "background, and enemy tiles. The eraser lets you remove tiles.",
1392 "The left and right arrow keys scroll back and forth through your level.",
1393 "The button with the wrench and screwdriver, lets you change the",
1394 "settings of your level, including how long it is or what music it will",
1395 "play. When you are ready to give your level a test, click on the little",
1396 "running Tux. If you like the changes you have made to your level,",
1397 "press the red save key to keep them.",
1398 "To change which level in your subset you are editing, press the white",
1399 "up and down arrow keys at the top of the button box.",
1401 "Have fun making levels! If you make some good ones, send them to us on",
1402 "the SuperTux mailing list!",
1407 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1409 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1410 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1412 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1420 while(SDL_PollEvent(&event))
1423 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1424 case SDL_KEYDOWN: // key pressed