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_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->dn_tiles[y][x] >= '0' && le_current_level->dn_tiles[y][x] <= '9')
133 add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(le_current_level->dn_tiles[y][x] - '0'));
139 void le_set_defaults()
141 if(le_current_level != NULL)
145 if(le_current_level->time_left == 0)
146 le_current_level->time_left = 255;
150 int leveleditor(int levelnb)
152 int last_time, now_time, i;
160 clearscreen(0, 0, 0);
163 while (SDL_PollEvent(&event))
168 last_time = SDL_GetTicks();
173 if(le_current_level != NULL)
175 /* making events results to be in order */
178 if(pos_x > (le_current_level->width * 32) - screen->w)
179 pos_x = (le_current_level->width * 32) - screen->w;
185 clearscreen(0, 0, 0);
187 /* draw editor interface */
192 menu_process_current();
193 if(current_menu == leveleditor_menu)
195 switch (leveleditor_menu->check())
201 update_subset_settings_menu();
204 done = DONE_LEVELEDITOR;
208 else if(current_menu == level_settings_menu)
210 switch (level_settings_menu->check())
213 apply_level_settings_menu();
214 Menu::set_current(leveleditor_menu);
221 else if(current_menu == subset_load_menu)
223 switch (i = subset_load_menu->check())
230 le_level_subset.load(level_subsets.item[i-2]);
231 leveleditor_menu->item[3].kind = MN_GOTO;
235 le_current_level = new st_level;
236 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
241 le_update_buttons(le_current_level->theme.c_str());
243 level_load_gfx(le_current_level);
244 le_activate_bad_guys();
250 else if(current_menu == subset_new_menu)
252 if(subset_new_menu->item[2].input[0] == '\0')
253 subset_new_menu->item[3].kind = MN_DEACTIVE;
256 subset_new_menu->item[3].kind = MN_ACTION;
258 switch (i = subset_new_menu->check())
261 st_subset::create(subset_new_menu->item[2].input);
262 le_level_subset.load(subset_new_menu->item[2].input);
263 leveleditor_menu->item[3].kind = MN_GOTO;
267 le_current_level = new st_level;
268 if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
273 le_update_buttons(le_current_level->theme.c_str());
275 level_load_gfx(le_current_level);
276 le_activate_bad_guys();
277 menu_item_change_input(&subset_new_menu->item[2],"");
283 else if(current_menu == subset_settings_menu)
285 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 )
286 subset_settings_menu->item[5].kind = MN_DEACTIVE;
288 subset_settings_menu->item[5].kind = MN_ACTION;
290 switch (i = subset_settings_menu->check())
293 save_subset_settings_menu();
306 if(done == DONE_QUIT)
313 now_time = SDL_GetTicks();
314 if (now_time < last_time + FPS)
315 SDL_Delay(last_time + FPS - now_time); /* delay some time */
324 void le_update_buttons(const char *theme)
330 string_list_type bkgd_files;
331 string_list_type fgd_files;
333 sprintf(pathname,"images/themes/%s",theme);
334 bkgd_files = dfiles(pathname,"bkgd-", NULL);
335 string_list_sort(&bkgd_files);
337 le_bkgd_panel.hidden = true;
339 for(i = 0; i < bkgd_files.num_items; ++i)
341 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
342 button_change_icon(&le_bkgd_panel.item[i],filename);
345 sprintf(pathname,"images/themes/%s",theme);
346 fgd_files = dfiles(pathname,"solid", NULL);
347 string_list_sort(&fgd_files);
349 for(i = 0; i < fgd_files.num_items; ++i)
351 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
352 button_change_icon(&le_fgd_panel.item[i],filename);
355 string_list_free(&fgd_files);
356 fgd_files = dfiles(pathname,"brick", NULL);
357 string_list_sort(&fgd_files);
359 for(i = 0; i < fgd_files.num_items; ++i)
361 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
362 button_change_icon(&le_fgd_panel.item[i+14],filename);
371 string_list_type fgd_files;
372 string_list_type bkgd_files;
373 string_list_type bad_files;
374 level_subsets = dsubdirs("/levels", "info");
378 /* level_changed = NO;*/
381 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
382 le_level_changed = false;
383 le_current_level = NULL;
386 le_mouse_pressed[LEFT] = false;
387 le_mouse_pressed[RIGHT] = false;
389 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
392 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
393 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
394 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
395 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
396 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
397 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
398 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
399 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
400 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
401 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
402 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
403 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
404 button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
406 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
407 string_list_sort(&bkgd_files);
409 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
410 le_bkgd_panel.hidden = true;
412 for(i = 0; i < bkgd_files.num_items; ++i)
414 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
415 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
418 string_list_free(&bkgd_files);
419 bkgd_files = dfiles("images/shared","cloud-", NULL);
420 string_list_sort(&bkgd_files);
422 for(i = 0; i < bkgd_files.num_items; ++i)
424 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
425 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
428 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
429 string_list_sort(&fgd_files);
431 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
432 for(i = 0; i < fgd_files.num_items; ++i)
434 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
435 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
438 string_list_free(&fgd_files);
439 string_list_add_item(&fgd_files,"waves-0.png");
440 string_list_add_item(&fgd_files,"water.png");
441 string_list_add_item(&fgd_files,"pole.png");
442 string_list_add_item(&fgd_files,"poletop.png");
443 string_list_add_item(&fgd_files,"flag-0.png");
444 string_list_add_item(&fgd_files,"box-empty.png");
445 string_list_add_item(&fgd_files,"mints.png");
446 string_list_add_item(&fgd_files,"distro-0.png");
447 string_list_add_item(&fgd_files,"golden-herring.png");
448 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+4),0,0),i+4);
456 string_list_free(&fgd_files);
457 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
458 string_list_sort(&fgd_files);
460 for(i = 0; i < fgd_files.num_items; ++i)
462 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
463 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
466 string_list_free(&fgd_files);
467 string_list_add_item(&fgd_files,"distro-0.png");
468 string_list_add_item(&fgd_files,"distro-0.png");
469 for(i = 0; i < fgd_files.num_items; ++i)
471 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
472 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
475 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
476 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
477 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
478 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
479 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
481 string_list_init(&bad_files);
482 string_list_add_item(&bad_files,"bsod-left-0.png");
483 string_list_add_item(&bad_files,"laptop-left-0.png");
484 string_list_add_item(&bad_files,"bag-left-0.png");
485 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
486 le_bad_panel.hidden = true;
488 for(i = 0; i < bad_files.num_items; ++i)
490 sprintf(filename,"images/shared/%s",bad_files.item[i]);
491 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
494 leveleditor_menu = new Menu();
495 subset_load_menu = new Menu();
496 subset_new_menu = new Menu();
497 subset_settings_menu = new Menu();
498 level_settings_menu = new Menu();
500 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
501 leveleditor_menu->additem(MN_HL,"",0,0);
502 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
503 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
504 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
505 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
506 leveleditor_menu->additem(MN_HL,"",0,0);
507 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
510 Menu::set_current(leveleditor_menu);
513 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
514 subset_load_menu->additem(MN_HL, "", 0, 0);
516 for(i = 0; i < level_subsets.num_items; ++i)
518 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
520 subset_load_menu->additem(MN_HL,"",0,0);
521 subset_load_menu->additem(MN_BACK,"Back",0,0);
523 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
524 subset_new_menu->additem(MN_HL,"",0,0);
525 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
526 subset_new_menu->additem(MN_ACTION,"Create",0,0);
527 subset_new_menu->additem(MN_HL,"",0,0);
528 subset_new_menu->additem(MN_BACK,"Back",0,0);
530 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
531 subset_settings_menu->additem(MN_HL,"",0,0);
532 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
533 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
534 subset_settings_menu->additem(MN_HL,"",0,0);
535 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
536 subset_settings_menu->additem(MN_HL,"",0,0);
537 subset_settings_menu->additem(MN_BACK,"Back",0,0);
539 level_settings_menu->arrange_left = true;
540 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
541 level_settings_menu->additem(MN_HL,"",0,0);
542 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
543 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
544 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
545 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
546 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
547 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
548 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
549 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
550 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
551 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
552 level_settings_menu->additem(MN_HL,"",0,0);
553 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
555 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
560 void update_level_settings_menu()
565 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
566 sprintf(str,"%d",le_current_level->width);
568 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
569 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
570 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
571 string_list_add_item(level_settings_menu->item[5].list,"");
572 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
573 level_settings_menu->item[3].list->active_item = i;
574 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
575 level_settings_menu->item[4].list->active_item = i;
576 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
577 level_settings_menu->item[5].list->active_item = i;
579 menu_item_change_input(&level_settings_menu->item[6], str);
580 sprintf(str,"%d",le_current_level->time_left);
581 menu_item_change_input(&level_settings_menu->item[7], str);
582 sprintf(str,"%2.0f",le_current_level->gravity);
583 menu_item_change_input(&level_settings_menu->item[8], str);
584 sprintf(str,"%d",le_current_level->bkgd_red);
585 menu_item_change_input(&level_settings_menu->item[9], str);
586 sprintf(str,"%d",le_current_level->bkgd_green);
587 menu_item_change_input(&level_settings_menu->item[10], str);
588 sprintf(str,"%d",le_current_level->bkgd_blue);
589 menu_item_change_input(&level_settings_menu->item[11], str);
592 void update_subset_settings_menu()
594 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
595 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
598 void apply_level_settings_menu()
603 le_current_level->name = level_settings_menu->item[2].input;
605 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
607 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
611 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
613 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
614 le_update_buttons(le_current_level->theme.c_str());
621 level_load_gfx(le_current_level);
624 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
626 level_change_size(le_current_level, atoi(level_settings_menu->item[6].input));
627 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
628 le_current_level->gravity = atof(level_settings_menu->item[8].input);
629 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
630 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
631 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
634 void save_subset_settings_menu()
636 le_level_subset.title = subset_settings_menu->item[2].input;
637 le_level_subset.description = subset_settings_menu->item[3].input;
638 le_level_subset.save();
641 void le_goto_level(int levelnb)
646 level_free(le_current_level);
647 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
649 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
658 le_update_buttons(le_current_level->theme.c_str());
661 level_load_gfx(le_current_level);
663 le_activate_bad_guys();
668 /*if(level_changed == true)
669 if(askforsaving() == CANCEL)
672 SDL_EnableKeyRepeat(0, 0); // disables key repeating
674 texture_free(&le_selection);
675 delete leveleditor_menu;
676 delete subset_load_menu;
677 delete subset_new_menu;
678 delete subset_settings_menu;
679 delete level_settings_menu;
680 button_panel_free(&le_bkgd_panel);
681 button_panel_free(&le_fgd_panel);
682 button_panel_free(&le_bad_panel);
683 button_free(&le_save_level_bt);
684 button_free(&le_test_level_bt);
685 button_free(&le_next_level_bt);
686 button_free(&le_previous_level_bt);
687 button_free(&le_move_right_bt);
688 button_free(&le_move_left_bt);
689 button_free(&le_rubber_bt);
690 button_free(&le_select_mode_one_bt);
691 button_free(&le_select_mode_two_bt);
692 button_free(&le_settings_bt);
693 button_free(&le_bad_bt);
694 button_free(&le_bkgd_bt);
695 button_free(&le_fgd_bt);
697 if(le_current_level != NULL)
700 level_free(le_current_level);
706 void le_drawinterface()
711 if(le_current_level != NULL)
713 /* draw a grid (if selected) */
716 for(x = 0; x < 19; x++)
717 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
718 for(y = 0; y < 15; y++)
719 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
723 if(le_selection_mode == CURSOR)
724 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
725 else if(le_selection_mode == SQUARE)
728 le_highlight_selection();
729 /* draw current selection */
730 w = selection.x2 - selection.x1;
731 h = selection.y2 - selection.y1;
732 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
733 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
734 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
735 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
739 /* draw button bar */
740 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
741 drawshape(19 * 32, 14 * 32, le_current_tile);
742 switch(le_current_tile)
745 texture_draw(&img_mints, 19 * 32, 14 * 32);
748 texture_draw(&img_golden_herring,19 * 32, 14 * 32);
753 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
756 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
759 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
762 texture_draw(&img_money_left[0],19 * 32, 14 * 32);
768 if(le_current_level != NULL)
770 button_draw(&le_save_level_bt);
771 button_draw(&le_test_level_bt);
772 button_draw(&le_next_level_bt);
773 button_draw(&le_previous_level_bt);
774 button_draw(&le_rubber_bt);
775 button_draw(&le_select_mode_one_bt);
776 button_draw(&le_select_mode_two_bt);
777 button_draw(&le_settings_bt);
778 button_draw(&le_move_right_bt);
779 button_draw(&le_move_left_bt);
780 button_draw(&le_bad_bt);
781 button_draw(&le_bkgd_bt);
782 button_draw(&le_fgd_bt);
783 button_panel_draw(&le_bkgd_panel);
784 button_panel_draw(&le_fgd_panel);
785 button_panel_draw(&le_bad_panel);
787 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
788 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
790 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
794 if(show_menu == false)
795 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
797 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
804 unsigned int y,x,i,s;
806 /* Draw the real background */
807 if(le_current_level->bkgd_image[0] != '\0')
810 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
811 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
815 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
818 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
820 for (y = 0; y < 15; ++y)
821 for (x = 0; x < 20; ++x)
823 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]);
825 /* draw whats inside stuff when cursor is selecting those */
826 /* (draw them all the time - is this the right behaviour?) */
827 switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)])
830 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
833 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
838 texture_draw(&img_distro[(global_frame_counter / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
845 /* Draw the Bad guys: */
846 for (i = 0; i < bad_guys.size(); ++i)
848 /* to support frames: img_bsod_left[(frame / 5) % 4] */
849 if(bad_guys[i].kind == BAD_BSOD)
850 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
851 else if(bad_guys[i].kind == BAD_LAPTOP)
852 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
853 else if (bad_guys[i].kind == BAD_MONEY)
854 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
858 /* Draw the player: */
859 /* for now, the position is fixed at (0, 240) */
860 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 0 - pos_x, 240);
863 void le_checkevents()
867 button_type* pbutton;
870 keymod = SDL_GetModState();
872 while(SDL_PollEvent(&event))
874 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
875 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
876 event.motion.y > 0 && event.motion.y < screen->h)))
881 case SDL_KEYDOWN: // key pressed
882 key = event.key.keysym.sym;
885 menu_event(&event.key.keysym);
886 if(key == SDLK_ESCAPE)
889 Menu::set_current(leveleditor_menu);
903 cursor_x -= KEY_CURSOR_SPEED;
905 cursor_x -= KEY_CURSOR_FASTSPEED;
907 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
908 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
913 cursor_x += KEY_CURSOR_SPEED;
915 cursor_x += KEY_CURSOR_FASTSPEED;
917 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
918 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
923 cursor_y -= KEY_CURSOR_SPEED;
925 cursor_y -= KEY_CURSOR_FASTSPEED;
932 cursor_y += KEY_CURSOR_SPEED;
934 cursor_y += KEY_CURSOR_FASTSPEED;
936 if(cursor_y > screen->h-32)
937 cursor_y = screen->h-32;
950 cursor_x = (le_current_level->width * 32) - 32;
954 le_show_grid = !le_show_grid;
960 case SDL_KEYUP: /* key released */
961 switch(event.key.keysym.sym)
970 case SDL_MOUSEBUTTONDOWN:
971 if(event.button.button == SDL_BUTTON_LEFT)
973 le_mouse_pressed[LEFT] = true;
975 selection.x1 = event.motion.x + pos_x;
976 selection.y1 = event.motion.y;
977 selection.x2 = event.motion.x + pos_x;
978 selection.y2 = event.motion.y;
980 else if(event.button.button == SDL_BUTTON_RIGHT)
981 le_mouse_pressed[RIGHT] = true;
983 case SDL_MOUSEBUTTONUP:
984 if(event.button.button == SDL_BUTTON_LEFT)
985 le_mouse_pressed[LEFT] = false;
986 else if(event.button.button == SDL_BUTTON_RIGHT)
987 le_mouse_pressed[RIGHT] = false;
989 case SDL_MOUSEMOTION:
995 cursor_x = ((int)(pos_x + x) / 32) * 32;
996 cursor_y = ((int) y / 32) * 32;
998 if(le_mouse_pressed[LEFT])
1000 selection.x2 = x + pos_x;
1004 if(le_mouse_pressed[RIGHT])
1006 pos_x += -1 * event.motion.xrel;
1010 case SDL_QUIT: // window closed
1018 if(le_current_level != NULL)
1020 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 &&
1021 event.motion.y > 0 && event.motion.y < screen->h)))
1023 le_mouse_pressed[LEFT] = false;
1024 le_mouse_pressed[RIGHT] = false;
1026 if(show_menu == false)
1028 /* Check for button events */
1029 button_event(&le_test_level_bt,&event);
1030 if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
1032 button_event(&le_save_level_bt,&event);
1033 if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
1034 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
1035 button_event(&le_next_level_bt,&event);
1036 if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
1038 if(le_level < le_level_subset.levels)
1040 le_goto_level(++le_level);
1047 sprintf(str,"Level %d doesn't exist.",le_level+1);
1048 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
1049 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
1050 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
1054 while(SDL_PollEvent(&event))
1057 case SDL_KEYDOWN: // key pressed
1058 switch(event.key.keysym.sym)
1061 level_default(&new_lev);
1062 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
1063 le_level_subset.levels = le_level;
1064 le_goto_level(le_level);
1081 button_event(&le_previous_level_bt,&event);
1082 if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1085 le_goto_level(--le_level);
1087 button_event(&le_rubber_bt,&event);
1088 if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1089 le_current_tile = 0;
1090 button_event(&le_select_mode_one_bt,&event);
1091 if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1092 le_selection_mode = CURSOR;
1093 button_event(&le_select_mode_two_bt,&event);
1094 if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1095 le_selection_mode = SQUARE;
1097 button_event(&le_bad_bt,&event);
1098 if(button_get_state(&le_bad_bt) == BUTTON_CLICKED)
1100 le_bad_panel.hidden = false;
1101 le_fgd_panel.hidden = true;
1102 le_bkgd_panel.hidden = true;
1105 button_event(&le_fgd_bt,&event);
1106 if(button_get_state(&le_fgd_bt) == BUTTON_CLICKED)
1108 le_bad_panel.hidden = true;
1109 le_fgd_panel.hidden = false;
1110 le_bkgd_panel.hidden = true;
1112 button_event(&le_bkgd_bt,&event);
1113 if(button_get_state(&le_bkgd_bt) == BUTTON_CLICKED)
1115 le_bad_panel.hidden = true;
1116 le_fgd_panel.hidden = true;
1117 le_bkgd_panel.hidden = false;
1119 button_event(&le_settings_bt,&event);
1120 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1122 if(show_menu == false)
1124 update_level_settings_menu();
1125 Menu::set_current(level_settings_menu);
1130 Menu::set_current(leveleditor_menu);
1134 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1136 if(button_get_state(pbutton) == BUTTON_CLICKED)
1139 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1140 c = 'G' + pbutton->tag;
1141 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1142 c = 'g' + pbutton->tag - 4;
1143 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1144 c = 'C' + pbutton->tag - 8;
1145 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1146 c = 'c' + pbutton->tag - 12;
1148 le_current_tile = c;
1151 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1153 if(button_get_state(pbutton) == BUTTON_CLICKED)
1156 if(pbutton->tag == 0)
1158 else if(pbutton->tag == 1)
1160 else if(pbutton->tag == 2)
1162 else if(pbutton->tag == 3)
1164 else if(pbutton->tag == 4)
1166 else if(pbutton->tag == 5)
1168 else if(pbutton->tag == 6)
1170 else if(pbutton->tag == 7)
1172 else if(pbutton->tag == 8)
1174 else if(pbutton->tag == 9)
1176 else if(pbutton->tag == 10)
1178 else if(pbutton->tag == 11)
1180 else if(pbutton->tag == 12)
1182 else if(pbutton->tag == 13)
1184 else if(pbutton->tag == 14)
1186 else if(pbutton->tag == 15)
1188 else if(pbutton->tag == 16)
1190 else if(pbutton->tag == 17)
1193 le_current_tile = c;
1196 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1198 if(button_get_state(pbutton) == BUTTON_CLICKED)
1201 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1202 c = '0' + pbutton->tag;
1204 le_current_tile = c;
1210 button_event(&le_settings_bt,&event);
1211 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1213 if(show_menu == false)
1215 update_level_settings_menu();
1216 Menu::set_current(level_settings_menu);
1221 Menu::set_current(leveleditor_menu);
1227 if(show_menu == false)
1229 button_event(&le_move_left_bt,&event);
1230 button_event(&le_move_right_bt,&event);
1232 if(le_mouse_pressed[LEFT])
1234 le_change(cursor_x, cursor_y, TM_IA, le_current_tile);
1239 if(show_menu == false)
1241 if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1245 else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1250 if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1254 else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1262 void le_highlight_selection()
1266 if(selection.x1 < selection.x2)
1276 if(selection.y1 < selection.y2)
1292 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1295 void le_change(float x, float y, int tm, unsigned int c)
1297 if(le_current_level != NULL)
1303 /* level_changed = true; */
1305 switch(le_selection_mode)
1308 level_change(le_current_level,x,y,tm,c);
1313 /* if there is a bad guy over there, remove it */
1314 for(i = 0; i < bad_guys.size(); ++i)
1315 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1316 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1318 if(c == '0') /* if it's a bad guy */
1319 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1321 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1323 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1327 if(selection.x1 < selection.x2)
1337 if(selection.y1 < selection.y2)
1353 /* if there is a bad guy over there, remove it */
1354 for(i = 0; i < bad_guys.size(); ++i)
1355 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1356 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1357 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1359 for(xx = x1; xx <= x2; xx++)
1360 for(yy = y1; yy <= y2; yy++)
1362 level_change(le_current_level, xx*32, yy*32, tm, c);
1364 if(c == '0') // if it's a bad guy
1365 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1367 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1369 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1380 level_save(le_current_level,"test",le_level);
1381 gameloop("test",le_level, ST_GL_TEST);
1382 Menu::set_current(leveleditor_menu);
1384 level_load_gfx(le_current_level);
1386 le_activate_bad_guys();
1392 unsigned int i, done;
1394 " - This is SuperTux's built-in level editor -",
1395 "It has been designed to be light and easy to use from the start.",
1397 "When you first load the level editor you are given a menu where you",
1398 "can load level subsets, create a new level subset, edit the current",
1399 "subset's settings, or simply quit the editor. You can access this menu",
1400 "from the level editor at any time by pressing the escape key.",
1402 "To your right is your button bar. The center of this contains many",
1403 "tiles you can use to make your level. To select a tile, click on it",
1404 "with your left mouse button; your selection will be shown in the",
1405 "bottom right corner of the button box. Click anywhere on your level",
1406 "with the left mouse button to place that tile down. If you right click",
1407 "a tile in the button bar, you can find out what its keyboard shortcut",
1408 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1409 "background, and enemy tiles. The eraser lets you remove tiles.",
1410 "The left and right arrow keys scroll back and forth through your level.",
1411 "The button with the wrench and screwdriver, lets you change the",
1412 "settings of your level, including how long it is or what music it will",
1413 "play. When you are ready to give your level a test, click on the little",
1414 "running Tux. If you like the changes you have made to your level,",
1415 "press the red save key to keep them.",
1416 "To change which level in your subset you are editing, press the white",
1417 "up and down arrow keys at the top of the button box.",
1419 "Have fun making levels! If you make some good ones, send them to us on",
1420 "the SuperTux mailing list!",
1425 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1427 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1428 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1430 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1438 while(SDL_PollEvent(&event))
1441 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1442 case SDL_KEYDOWN: // key pressed