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();
278 mouse_cursor->draw();
287 if(done == DONE_QUIT)
294 now_time = SDL_GetTicks();
295 if (now_time < last_time + FPS)
296 SDL_Delay(last_time + FPS - now_time); /* delay some time */
305 void le_update_buttons(const char *theme)
311 string_list_type bkgd_files;
312 string_list_type fgd_files;
314 sprintf(pathname,"images/themes/%s",theme);
315 bkgd_files = dfiles(pathname,"bkgd-", NULL);
316 string_list_sort(&bkgd_files);
318 le_bkgd_panel.hidden = true;
320 for(i = 0; i < bkgd_files.num_items; ++i)
322 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
323 button_change_icon(&le_bkgd_panel.item[i],filename);
326 sprintf(pathname,"images/themes/%s",theme);
327 fgd_files = dfiles(pathname,"solid", NULL);
328 string_list_sort(&fgd_files);
330 for(i = 0; i < fgd_files.num_items; ++i)
332 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
333 button_change_icon(&le_fgd_panel.item[i],filename);
336 string_list_free(&fgd_files);
337 fgd_files = dfiles(pathname,"brick", NULL);
338 string_list_sort(&fgd_files);
340 for(i = 0; i < fgd_files.num_items; ++i)
342 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
343 button_change_icon(&le_fgd_panel.item[i+14],filename);
352 string_list_type fgd_files;
353 string_list_type bkgd_files;
354 string_list_type bad_files;
355 level_subsets = dsubdirs("/levels", "info");
359 /* level_changed = NO;*/
362 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
363 le_level_changed = false;
364 le_current_level = NULL;
367 le_mouse_pressed[LEFT] = false;
368 le_mouse_pressed[RIGHT] = false;
370 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
373 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
374 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
375 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
376 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
377 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
378 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
379 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
380 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
381 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
382 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
383 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
384 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
385 button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
387 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
388 string_list_sort(&bkgd_files);
390 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
391 le_bkgd_panel.hidden = true;
393 for(i = 0; i < bkgd_files.num_items; ++i)
395 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
396 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
399 string_list_free(&bkgd_files);
400 bkgd_files = dfiles("images/shared","cloud-", NULL);
401 string_list_sort(&bkgd_files);
403 for(i = 0; i < bkgd_files.num_items; ++i)
405 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
406 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
409 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
410 string_list_sort(&fgd_files);
412 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
413 for(i = 0; i < fgd_files.num_items; ++i)
415 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
416 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
419 string_list_free(&fgd_files);
420 string_list_add_item(&fgd_files,"waves-0.png");
421 string_list_add_item(&fgd_files,"water.png");
422 string_list_add_item(&fgd_files,"pole.png");
423 string_list_add_item(&fgd_files,"poletop.png");
424 string_list_add_item(&fgd_files,"flag-0.png");
425 string_list_add_item(&fgd_files,"box-empty.png");
426 string_list_add_item(&fgd_files,"mints.png");
427 string_list_add_item(&fgd_files,"distro-0.png");
428 string_list_add_item(&fgd_files,"golden-herring.png");
429 string_list_add_item(&fgd_files,"distro-0.png");
431 for(i = 0; i < fgd_files.num_items; ++i)
433 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
434 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
437 string_list_free(&fgd_files);
438 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
439 string_list_sort(&fgd_files);
441 for(i = 0; i < fgd_files.num_items; ++i)
443 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
444 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
447 string_list_free(&fgd_files);
448 string_list_add_item(&fgd_files,"distro-0.png");
449 string_list_add_item(&fgd_files,"distro-0.png");
450 for(i = 0; i < fgd_files.num_items; ++i)
452 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
453 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
456 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
457 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
458 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
459 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
460 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
462 string_list_init(&bad_files);
463 string_list_add_item(&bad_files,"bsod-left-0.png");
464 string_list_add_item(&bad_files,"laptop-left-0.png");
465 string_list_add_item(&bad_files,"bag-left-0.png");
466 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
467 le_bad_panel.hidden = true;
469 for(i = 0; i < bad_files.num_items; ++i)
471 sprintf(filename,"images/shared/%s",bad_files.item[i]);
472 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
475 leveleditor_menu = new Menu();
476 subset_load_menu = new Menu();
477 subset_new_menu = new Menu();
478 subset_settings_menu = new Menu();
479 level_settings_menu = new Menu();
481 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
482 leveleditor_menu->additem(MN_HL,"",0,0);
483 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
484 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
485 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
486 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
487 leveleditor_menu->additem(MN_HL,"",0,0);
488 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
491 Menu::set_current(leveleditor_menu);
494 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
495 subset_load_menu->additem(MN_HL, "", 0, 0);
497 for(i = 0; i < level_subsets.num_items; ++i)
499 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
501 subset_load_menu->additem(MN_HL,"",0,0);
502 subset_load_menu->additem(MN_BACK,"Back",0,0);
504 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
505 subset_new_menu->additem(MN_HL,"",0,0);
506 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
507 subset_new_menu->additem(MN_ACTION,"Create",0,0);
508 subset_new_menu->additem(MN_HL,"",0,0);
509 subset_new_menu->additem(MN_BACK,"Back",0,0);
511 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
512 subset_settings_menu->additem(MN_HL,"",0,0);
513 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
514 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
515 subset_settings_menu->additem(MN_HL,"",0,0);
516 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
517 subset_settings_menu->additem(MN_HL,"",0,0);
518 subset_settings_menu->additem(MN_BACK,"Back",0,0);
520 level_settings_menu->arrange_left = true;
521 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
522 level_settings_menu->additem(MN_HL,"",0,0);
523 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
524 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
525 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
526 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
527 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
528 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
529 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
530 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
531 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
532 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
533 level_settings_menu->additem(MN_HL,"",0,0);
534 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
536 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
541 void update_level_settings_menu()
546 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
547 sprintf(str,"%d",le_current_level->width);
549 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
550 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
551 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
552 string_list_add_item(level_settings_menu->item[5].list,"");
553 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
554 level_settings_menu->item[3].list->active_item = i;
555 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
556 level_settings_menu->item[4].list->active_item = i;
557 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
558 level_settings_menu->item[5].list->active_item = i;
560 menu_item_change_input(&level_settings_menu->item[6], str);
561 sprintf(str,"%d",le_current_level->time_left);
562 menu_item_change_input(&level_settings_menu->item[7], str);
563 sprintf(str,"%2.0f",le_current_level->gravity);
564 menu_item_change_input(&level_settings_menu->item[8], str);
565 sprintf(str,"%d",le_current_level->bkgd_red);
566 menu_item_change_input(&level_settings_menu->item[9], str);
567 sprintf(str,"%d",le_current_level->bkgd_green);
568 menu_item_change_input(&level_settings_menu->item[10], str);
569 sprintf(str,"%d",le_current_level->bkgd_blue);
570 menu_item_change_input(&level_settings_menu->item[11], str);
573 void update_subset_settings_menu()
575 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
576 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
579 void apply_level_settings_menu()
584 le_current_level->name = level_settings_menu->item[2].input;
586 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
588 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
592 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
594 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
595 le_update_buttons(le_current_level->theme.c_str());
602 level_load_gfx(le_current_level);
605 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
607 level_change_size(le_current_level, atoi(level_settings_menu->item[6].input));
608 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
609 le_current_level->gravity = atof(level_settings_menu->item[8].input);
610 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
611 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
612 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
615 void save_subset_settings_menu()
617 le_level_subset.title = subset_settings_menu->item[2].input;
618 le_level_subset.description = subset_settings_menu->item[3].input;
619 le_level_subset.save();
622 void le_goto_level(int levelnb)
627 level_free(le_current_level);
628 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
630 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
639 le_update_buttons(le_current_level->theme.c_str());
642 level_load_gfx(le_current_level);
647 /*if(level_changed == true)
648 if(askforsaving() == CANCEL)
651 SDL_EnableKeyRepeat(0, 0); // disables key repeating
653 texture_free(&le_selection);
654 delete leveleditor_menu;
655 delete subset_load_menu;
656 delete subset_new_menu;
657 delete subset_settings_menu;
658 delete level_settings_menu;
659 button_panel_free(&le_bkgd_panel);
660 button_panel_free(&le_fgd_panel);
661 button_panel_free(&le_bad_panel);
662 button_free(&le_save_level_bt);
663 button_free(&le_test_level_bt);
664 button_free(&le_next_level_bt);
665 button_free(&le_previous_level_bt);
666 button_free(&le_move_right_bt);
667 button_free(&le_move_left_bt);
668 button_free(&le_rubber_bt);
669 button_free(&le_select_mode_one_bt);
670 button_free(&le_select_mode_two_bt);
671 button_free(&le_settings_bt);
672 button_free(&le_bad_bt);
673 button_free(&le_bkgd_bt);
674 button_free(&le_fgd_bt);
676 if(le_current_level != NULL)
679 level_free(le_current_level);
685 void le_drawinterface()
690 if(le_current_level != NULL)
692 /* draw a grid (if selected) */
695 for(x = 0; x < 19; x++)
696 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
697 for(y = 0; y < 15; y++)
698 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
702 if(le_selection_mode == CURSOR)
703 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
704 else if(le_selection_mode == SQUARE)
707 le_highlight_selection();
708 /* draw current selection */
709 w = selection.x2 - selection.x1;
710 h = selection.y2 - selection.y1;
711 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
712 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
713 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
714 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
718 /* draw button bar */
719 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
720 drawshape(19 * 32, 14 * 32, le_current_tile);
721 switch(le_current_tile)
724 texture_draw(&img_mints, 19 * 32, 14 * 32);
727 texture_draw(&img_golden_herring,19 * 32, 14 * 32);
732 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
735 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
738 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
741 texture_draw(&img_money_left[0],19 * 32, 14 * 32);
747 if(le_current_level != NULL)
749 button_draw(&le_save_level_bt);
750 button_draw(&le_test_level_bt);
751 button_draw(&le_next_level_bt);
752 button_draw(&le_previous_level_bt);
753 button_draw(&le_rubber_bt);
754 button_draw(&le_select_mode_one_bt);
755 button_draw(&le_select_mode_two_bt);
756 button_draw(&le_settings_bt);
757 button_draw(&le_move_right_bt);
758 button_draw(&le_move_left_bt);
759 button_draw(&le_bad_bt);
760 button_draw(&le_bkgd_bt);
761 button_draw(&le_fgd_bt);
762 button_panel_draw(&le_bkgd_panel);
763 button_panel_draw(&le_fgd_panel);
764 button_panel_draw(&le_bad_panel);
766 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
767 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
769 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
773 if(show_menu == false)
774 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
776 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
783 unsigned int y,x,i,s;
785 /* Draw the real background */
786 if(le_current_level->bkgd_image[0] != '\0')
789 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
790 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
794 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
797 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
799 for (y = 0; y < 15; ++y)
800 for (x = 0; x < 20; ++x)
802 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]);
804 /* draw whats inside stuff when cursor is selecting those */
805 /* (draw them all the time - is this the right behaviour?) */
806 switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)])
809 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
812 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
817 texture_draw(&img_distro[(global_frame_counter / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
824 /* Draw the Bad guys: */
825 for (i = 0; i < bad_guys.size(); ++i)
827 /* to support frames: img_bsod_left[(frame / 5) % 4] */
828 if(bad_guys[i].kind == BAD_BSOD)
829 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
830 else if(bad_guys[i].kind == BAD_LAPTOP)
831 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
832 else if (bad_guys[i].kind == BAD_MONEY)
833 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
837 /* Draw the player: */
838 /* for now, the position is fixed at (0, 240) */
839 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 0 - pos_x, 240);
842 void le_checkevents()
846 button_type* pbutton;
849 keymod = SDL_GetModState();
851 while(SDL_PollEvent(&event))
856 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
857 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
858 event.motion.y > 0 && event.motion.y < screen->h)))
862 case SDL_KEYDOWN: // key pressed
863 key = event.key.keysym.sym;
866 if(key == SDLK_ESCAPE)
869 Menu::set_current(leveleditor_menu);
883 cursor_x -= KEY_CURSOR_SPEED;
885 cursor_x -= KEY_CURSOR_FASTSPEED;
887 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
888 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
893 cursor_x += KEY_CURSOR_SPEED;
895 cursor_x += KEY_CURSOR_FASTSPEED;
897 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
898 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
903 cursor_y -= KEY_CURSOR_SPEED;
905 cursor_y -= KEY_CURSOR_FASTSPEED;
912 cursor_y += KEY_CURSOR_SPEED;
914 cursor_y += KEY_CURSOR_FASTSPEED;
916 if(cursor_y > screen->h-32)
917 cursor_y = screen->h-32;
930 cursor_x = (le_current_level->width * 32) - 32;
934 le_show_grid = !le_show_grid;
940 case SDL_KEYUP: /* key released */
941 switch(event.key.keysym.sym)
950 case SDL_MOUSEBUTTONDOWN:
951 if(event.button.button == SDL_BUTTON_LEFT)
953 le_mouse_pressed[LEFT] = true;
955 selection.x1 = event.motion.x + pos_x;
956 selection.y1 = event.motion.y;
957 selection.x2 = event.motion.x + pos_x;
958 selection.y2 = event.motion.y;
960 else if(event.button.button == SDL_BUTTON_RIGHT)
961 le_mouse_pressed[RIGHT] = true;
963 case SDL_MOUSEBUTTONUP:
964 if(event.button.button == SDL_BUTTON_LEFT)
965 le_mouse_pressed[LEFT] = false;
966 else if(event.button.button == SDL_BUTTON_RIGHT)
967 le_mouse_pressed[RIGHT] = false;
969 case SDL_MOUSEMOTION:
975 cursor_x = ((int)(pos_x + x) / 32) * 32;
976 cursor_y = ((int) y / 32) * 32;
978 if(le_mouse_pressed[LEFT])
980 selection.x2 = x + pos_x;
984 if(le_mouse_pressed[RIGHT])
986 pos_x += -1 * event.motion.xrel;
990 case SDL_QUIT: // window closed
998 if(le_current_level != NULL)
1000 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 &&
1001 event.motion.y > 0 && event.motion.y < screen->h)))
1003 le_mouse_pressed[LEFT] = false;
1004 le_mouse_pressed[RIGHT] = false;
1006 if(show_menu == false)
1008 /* Check for button events */
1009 button_event(&le_test_level_bt,&event);
1010 if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
1012 button_event(&le_save_level_bt,&event);
1013 if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
1014 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
1015 button_event(&le_next_level_bt,&event);
1016 if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
1018 if(le_level < le_level_subset.levels)
1020 le_goto_level(++le_level);
1027 sprintf(str,"Level %d doesn't exist.",le_level+1);
1028 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
1029 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
1030 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
1034 while(SDL_PollEvent(&event))
1037 case SDL_KEYDOWN: // key pressed
1038 switch(event.key.keysym.sym)
1041 level_default(&new_lev);
1042 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
1043 le_level_subset.levels = le_level;
1044 le_goto_level(le_level);
1061 button_event(&le_previous_level_bt,&event);
1062 if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1065 le_goto_level(--le_level);
1067 button_event(&le_rubber_bt,&event);
1068 if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1069 le_current_tile = 0;
1070 button_event(&le_select_mode_one_bt,&event);
1071 if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1072 le_selection_mode = CURSOR;
1073 button_event(&le_select_mode_two_bt,&event);
1074 if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1075 le_selection_mode = SQUARE;
1077 button_event(&le_bad_bt,&event);
1078 if(button_get_state(&le_bad_bt) == BUTTON_CLICKED)
1080 le_bad_panel.hidden = false;
1081 le_fgd_panel.hidden = true;
1082 le_bkgd_panel.hidden = true;
1085 button_event(&le_fgd_bt,&event);
1086 if(button_get_state(&le_fgd_bt) == BUTTON_CLICKED)
1088 le_bad_panel.hidden = true;
1089 le_fgd_panel.hidden = false;
1090 le_bkgd_panel.hidden = true;
1092 button_event(&le_bkgd_bt,&event);
1093 if(button_get_state(&le_bkgd_bt) == BUTTON_CLICKED)
1095 le_bad_panel.hidden = true;
1096 le_fgd_panel.hidden = true;
1097 le_bkgd_panel.hidden = false;
1099 button_event(&le_settings_bt,&event);
1100 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1102 if(show_menu == false)
1104 update_level_settings_menu();
1105 Menu::set_current(level_settings_menu);
1110 Menu::set_current(leveleditor_menu);
1114 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1116 if(button_get_state(pbutton) == BUTTON_CLICKED)
1119 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1120 c = 'G' + pbutton->tag;
1121 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1122 c = 'g' + pbutton->tag - 4;
1123 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1124 c = 'C' + pbutton->tag - 8;
1125 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1126 c = 'c' + pbutton->tag - 12;
1128 le_current_tile = c;
1131 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1133 if(button_get_state(pbutton) == BUTTON_CLICKED)
1136 if(pbutton->tag == 0)
1138 else if(pbutton->tag == 1)
1140 else if(pbutton->tag == 2)
1142 else if(pbutton->tag == 3)
1144 else if(pbutton->tag == 4)
1146 else if(pbutton->tag == 5)
1148 else if(pbutton->tag == 6)
1150 else if(pbutton->tag == 7)
1152 else if(pbutton->tag == 8)
1154 else if(pbutton->tag == 9)
1156 else if(pbutton->tag == 10)
1158 else if(pbutton->tag == 11)
1160 else if(pbutton->tag == 12)
1162 else if(pbutton->tag == 13)
1164 else if(pbutton->tag == 14)
1166 else if(pbutton->tag == 15)
1168 else if(pbutton->tag == 16)
1170 else if(pbutton->tag == 17)
1173 le_current_tile = c;
1176 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1178 if(button_get_state(pbutton) == BUTTON_CLICKED)
1181 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1182 c = '0' + pbutton->tag;
1184 le_current_tile = c;
1190 button_event(&le_settings_bt,&event);
1191 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1193 if(show_menu == false)
1195 update_level_settings_menu();
1196 Menu::set_current(level_settings_menu);
1201 Menu::set_current(leveleditor_menu);
1207 if(show_menu == false)
1209 button_event(&le_move_left_bt,&event);
1210 button_event(&le_move_right_bt,&event);
1212 if(le_mouse_pressed[LEFT])
1214 le_change(cursor_x, cursor_y, TM_IA, le_current_tile);
1219 if(show_menu == false)
1221 if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1225 else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1230 if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1234 else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1242 void le_highlight_selection()
1246 if(selection.x1 < selection.x2)
1256 if(selection.y1 < selection.y2)
1272 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1275 void le_change(float x, float y, int tm, unsigned int c)
1277 if(le_current_level != NULL)
1283 /* level_changed = true; */
1285 switch(le_selection_mode)
1288 level_change(le_current_level,x,y,tm,c);
1293 /* if there is a bad guy over there, remove it */
1294 for(i = 0; i < bad_guys.size(); ++i)
1295 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1296 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1298 if(c == '0') /* if it's a bad guy */
1299 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1301 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1303 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1307 if(selection.x1 < selection.x2)
1317 if(selection.y1 < selection.y2)
1333 /* if there is a bad guy over there, remove it */
1334 for(i = 0; i < bad_guys.size(); ++i)
1335 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1336 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1337 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1339 for(xx = x1; xx <= x2; xx++)
1340 for(yy = y1; yy <= y2; yy++)
1342 level_change(le_current_level, xx*32, yy*32, tm, c);
1344 if(c == '0') // if it's a bad guy
1345 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1347 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1349 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1360 level_save(le_current_level,"test",le_level);
1361 gameloop("test",le_level, ST_GL_TEST);
1362 Menu::set_current(leveleditor_menu);
1364 level_load_gfx(le_current_level);
1371 unsigned int i, done;
1373 " - This is SuperTux's built-in level editor -",
1374 "It has been designed to be light and easy to use from the start.",
1376 "When you first load the level editor you are given a menu where you",
1377 "can load level subsets, create a new level subset, edit the current",
1378 "subset's settings, or simply quit the editor. You can access this menu",
1379 "from the level editor at any time by pressing the escape key.",
1381 "To your right is your button bar. The center of this contains many",
1382 "tiles you can use to make your level. To select a tile, click on it",
1383 "with your left mouse button; your selection will be shown in the",
1384 "bottom right corner of the button box. Click anywhere on your level",
1385 "with the left mouse button to place that tile down. If you right click",
1386 "a tile in the button bar, you can find out what its keyboard shortcut",
1387 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1388 "background, and enemy tiles. The eraser lets you remove tiles.",
1389 "The left and right arrow keys scroll back and forth through your level.",
1390 "The button with the wrench and screwdriver, lets you change the",
1391 "settings of your level, including how long it is or what music it will",
1392 "play. When you are ready to give your level a test, click on the little",
1393 "running Tux. If you like the changes you have made to your level,",
1394 "press the red save key to keep them.",
1395 "To change which level in your subset you are editing, press the white",
1396 "up and down arrow keys at the top of the button box.",
1398 "Have fun making levels! If you make some good ones, send them to us on",
1399 "the SuperTux mailing list!",
1404 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1406 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1407 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1409 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1417 while(SDL_PollEvent(&event))
1420 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1421 case SDL_KEYDOWN: // key pressed