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();
286 if(done == DONE_QUIT)
293 now_time = SDL_GetTicks();
294 if (now_time < last_time + FPS)
295 SDL_Delay(last_time + FPS - now_time); /* delay some time */
304 void le_update_buttons(const char *theme)
310 string_list_type bkgd_files;
311 string_list_type fgd_files;
313 sprintf(pathname,"images/themes/%s",theme);
314 bkgd_files = dfiles(pathname,"bkgd-", NULL);
315 string_list_sort(&bkgd_files);
317 le_bkgd_panel.hidden = true;
319 for(i = 0; i < bkgd_files.num_items; ++i)
321 sprintf(filename,"%s/%s",pathname,bkgd_files.item[i]);
322 button_change_icon(&le_bkgd_panel.item[i],filename);
325 sprintf(pathname,"images/themes/%s",theme);
326 fgd_files = dfiles(pathname,"solid", NULL);
327 string_list_sort(&fgd_files);
329 for(i = 0; i < fgd_files.num_items; ++i)
331 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
332 button_change_icon(&le_fgd_panel.item[i],filename);
335 string_list_free(&fgd_files);
336 fgd_files = dfiles(pathname,"brick", NULL);
337 string_list_sort(&fgd_files);
339 for(i = 0; i < fgd_files.num_items; ++i)
341 sprintf(filename,"%s/%s",pathname,fgd_files.item[i]);
342 button_change_icon(&le_fgd_panel.item[i+14],filename);
351 string_list_type fgd_files;
352 string_list_type bkgd_files;
353 string_list_type bad_files;
354 level_subsets = dsubdirs("/levels", "info");
358 /* level_changed = NO;*/
361 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
362 le_level_changed = false;
363 le_current_level = NULL;
366 le_mouse_pressed[LEFT] = false;
367 le_mouse_pressed[RIGHT] = false;
369 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
372 button_load(&le_save_level_bt,"/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
373 button_load(&le_next_level_bt,"/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
374 button_load(&le_previous_level_bt,"/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
375 button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
376 button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
377 button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
378 button_load(&le_test_level_bt,"/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
379 button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
380 button_load(&le_move_left_bt,"/images/icons/left.png","Move left",SDLK_LEFT,0,0);
381 button_load(&le_move_right_bt,"/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
382 button_load(&le_fgd_bt,"/images/icons/fgd.png","Foreground tiles", SDLK_F7,screen->w-64,82);
383 button_load(&le_bkgd_bt,"/images/icons/bgd.png","Background tiles", SDLK_F8,screen->w-43,82);
384 button_load(&le_bad_bt,"/images/icons/emy.png","Enemies", SDLK_F9,screen->w-22,82);
386 bkgd_files = dfiles("images/themes/antarctica","bkgd-", NULL);
387 string_list_sort(&bkgd_files);
389 button_panel_init(&le_bkgd_panel, screen->w - 64,98, 64, 318);
390 le_bkgd_panel.hidden = true;
392 for(i = 0; i < bkgd_files.num_items; ++i)
394 sprintf(filename,"images/themes/antarctica/%s",bkgd_files.item[i]);
395 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i),0,0),i);
398 string_list_free(&bkgd_files);
399 bkgd_files = dfiles("images/shared","cloud-", NULL);
400 string_list_sort(&bkgd_files);
402 for(i = 0; i < bkgd_files.num_items; ++i)
404 sprintf(filename,"images/shared/%s",bkgd_files.item[i]);
405 button_panel_additem(&le_bkgd_panel,button_create(filename, "Background Tile",(SDLKey)((int)key+i+8),0,0),i+8);
408 fgd_files = dfiles("images/themes/antarctica","solid", NULL);
409 string_list_sort(&fgd_files);
411 button_panel_init(&le_fgd_panel, screen->w - 64,98, 64, 318);
412 for(i = 0; i < fgd_files.num_items; ++i)
414 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
415 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i),0,0),i);
418 string_list_free(&fgd_files);
419 string_list_add_item(&fgd_files,"waves-0.png");
420 string_list_add_item(&fgd_files,"water.png");
421 string_list_add_item(&fgd_files,"pole.png");
422 string_list_add_item(&fgd_files,"poletop.png");
423 string_list_add_item(&fgd_files,"flag-0.png");
424 string_list_add_item(&fgd_files,"box-empty.png");
425 string_list_add_item(&fgd_files,"mints.png");
426 string_list_add_item(&fgd_files,"distro-0.png");
427 string_list_add_item(&fgd_files,"golden-herring.png");
428 string_list_add_item(&fgd_files,"distro-0.png");
430 for(i = 0; i < fgd_files.num_items; ++i)
432 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
433 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+4),0,0),i+4);
436 string_list_free(&fgd_files);
437 fgd_files = dfiles("images/themes/antarctica","brick", NULL);
438 string_list_sort(&fgd_files);
440 for(i = 0; i < fgd_files.num_items; ++i)
442 sprintf(filename,"images/themes/antarctica/%s",fgd_files.item[i]);
443 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+14),0,0),i+14);
446 string_list_free(&fgd_files);
447 string_list_add_item(&fgd_files,"distro-0.png");
448 string_list_add_item(&fgd_files,"distro-0.png");
449 for(i = 0; i < fgd_files.num_items; ++i)
451 sprintf(filename,"images/shared/%s",fgd_files.item[i]);
452 button_panel_additem(&le_fgd_panel,button_create(filename, "Foreground Tile",(SDLKey)((int)key+i+16),0,0),i+16);
455 le_fgd_panel.item[10].bkgd = &le_fgd_panel.item[9].icon;
456 le_fgd_panel.item[11].bkgd = &le_fgd_panel.item[9].icon;
457 le_fgd_panel.item[12].bkgd = &le_fgd_panel.item[9].icon;
458 le_fgd_panel.item[16].bkgd = &le_fgd_panel.item[14].icon;
459 le_fgd_panel.item[17].bkgd = &le_fgd_panel.item[15].icon;
461 string_list_init(&bad_files);
462 string_list_add_item(&bad_files,"bsod-left-0.png");
463 string_list_add_item(&bad_files,"laptop-left-0.png");
464 string_list_add_item(&bad_files,"bag-left-0.png");
465 button_panel_init(&le_bad_panel, screen->w - 64,98, 64, 318);
466 le_bad_panel.hidden = true;
468 for(i = 0; i < bad_files.num_items; ++i)
470 sprintf(filename,"images/shared/%s",bad_files.item[i]);
471 button_panel_additem(&le_bad_panel,button_create(filename, "Bad Guy",(SDLKey)((int)key+i),0,0),i);
474 leveleditor_menu = new Menu();
475 subset_load_menu = new Menu();
476 subset_new_menu = new Menu();
477 subset_settings_menu = new Menu();
478 level_settings_menu = new Menu();
480 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
481 leveleditor_menu->additem(MN_HL,"",0,0);
482 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
483 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
484 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
485 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
486 leveleditor_menu->additem(MN_HL,"",0,0);
487 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
490 Menu::set_current(leveleditor_menu);
493 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
494 subset_load_menu->additem(MN_HL, "", 0, 0);
496 for(i = 0; i < level_subsets.num_items; ++i)
498 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
500 subset_load_menu->additem(MN_HL,"",0,0);
501 subset_load_menu->additem(MN_BACK,"Back",0,0);
503 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
504 subset_new_menu->additem(MN_HL,"",0,0);
505 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
506 subset_new_menu->additem(MN_ACTION,"Create",0,0);
507 subset_new_menu->additem(MN_HL,"",0,0);
508 subset_new_menu->additem(MN_BACK,"Back",0,0);
510 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
511 subset_settings_menu->additem(MN_HL,"",0,0);
512 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
513 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
514 subset_settings_menu->additem(MN_HL,"",0,0);
515 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
516 subset_settings_menu->additem(MN_HL,"",0,0);
517 subset_settings_menu->additem(MN_BACK,"Back",0,0);
519 level_settings_menu->arrange_left = true;
520 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
521 level_settings_menu->additem(MN_HL,"",0,0);
522 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
523 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
524 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
525 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
526 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
527 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
528 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
529 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
530 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
531 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
532 level_settings_menu->additem(MN_HL,"",0,0);
533 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
535 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
540 void update_level_settings_menu()
545 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
546 sprintf(str,"%d",le_current_level->width);
548 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
549 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
550 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
551 string_list_add_item(level_settings_menu->item[5].list,"");
552 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
553 level_settings_menu->item[3].list->active_item = i;
554 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
555 level_settings_menu->item[4].list->active_item = i;
556 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
557 level_settings_menu->item[5].list->active_item = i;
559 menu_item_change_input(&level_settings_menu->item[6], str);
560 sprintf(str,"%d",le_current_level->time_left);
561 menu_item_change_input(&level_settings_menu->item[7], str);
562 sprintf(str,"%2.0f",le_current_level->gravity);
563 menu_item_change_input(&level_settings_menu->item[8], str);
564 sprintf(str,"%d",le_current_level->bkgd_red);
565 menu_item_change_input(&level_settings_menu->item[9], str);
566 sprintf(str,"%d",le_current_level->bkgd_green);
567 menu_item_change_input(&level_settings_menu->item[10], str);
568 sprintf(str,"%d",le_current_level->bkgd_blue);
569 menu_item_change_input(&level_settings_menu->item[11], str);
572 void update_subset_settings_menu()
574 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
575 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
578 void apply_level_settings_menu()
583 le_current_level->name = level_settings_menu->item[2].input;
585 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
587 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
591 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
593 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
594 le_update_buttons(le_current_level->theme.c_str());
601 level_load_gfx(le_current_level);
604 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
606 level_change_size(le_current_level, atoi(level_settings_menu->item[6].input));
607 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
608 le_current_level->gravity = atof(level_settings_menu->item[8].input);
609 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
610 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
611 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
614 void save_subset_settings_menu()
616 le_level_subset.title = subset_settings_menu->item[2].input;
617 le_level_subset.description = subset_settings_menu->item[3].input;
618 le_level_subset.save();
621 void le_goto_level(int levelnb)
626 level_free(le_current_level);
627 if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
629 level_load(le_current_level, le_level_subset.name.c_str(), le_level);
638 le_update_buttons(le_current_level->theme.c_str());
641 level_load_gfx(le_current_level);
646 /*if(level_changed == true)
647 if(askforsaving() == CANCEL)
650 SDL_EnableKeyRepeat(0, 0); // disables key repeating
652 texture_free(&le_selection);
653 delete leveleditor_menu;
654 delete subset_load_menu;
655 delete subset_new_menu;
656 delete subset_settings_menu;
657 delete level_settings_menu;
658 button_panel_free(&le_bkgd_panel);
659 button_panel_free(&le_fgd_panel);
660 button_panel_free(&le_bad_panel);
661 button_free(&le_save_level_bt);
662 button_free(&le_test_level_bt);
663 button_free(&le_next_level_bt);
664 button_free(&le_previous_level_bt);
665 button_free(&le_move_right_bt);
666 button_free(&le_move_left_bt);
667 button_free(&le_rubber_bt);
668 button_free(&le_select_mode_one_bt);
669 button_free(&le_select_mode_two_bt);
670 button_free(&le_settings_bt);
671 button_free(&le_bad_bt);
672 button_free(&le_bkgd_bt);
673 button_free(&le_fgd_bt);
675 if(le_current_level != NULL)
678 level_free(le_current_level);
684 void le_drawinterface()
689 if(le_current_level != NULL)
691 /* draw a grid (if selected) */
694 for(x = 0; x < 19; x++)
695 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
696 for(y = 0; y < 15; y++)
697 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
701 if(le_selection_mode == CURSOR)
702 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
703 else if(le_selection_mode == SQUARE)
706 le_highlight_selection();
707 /* draw current selection */
708 w = selection.x2 - selection.x1;
709 h = selection.y2 - selection.y1;
710 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
711 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
712 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
713 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
717 /* draw button bar */
718 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
719 drawshape(19 * 32, 14 * 32, le_current_tile);
720 switch(le_current_tile)
723 texture_draw(&img_mints, 19 * 32, 14 * 32);
726 texture_draw(&img_golden_herring,19 * 32, 14 * 32);
731 texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
734 texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
737 texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
740 texture_draw(&img_money_left[0],19 * 32, 14 * 32);
746 if(le_current_level != NULL)
748 button_draw(&le_save_level_bt);
749 button_draw(&le_test_level_bt);
750 button_draw(&le_next_level_bt);
751 button_draw(&le_previous_level_bt);
752 button_draw(&le_rubber_bt);
753 button_draw(&le_select_mode_one_bt);
754 button_draw(&le_select_mode_two_bt);
755 button_draw(&le_settings_bt);
756 button_draw(&le_move_right_bt);
757 button_draw(&le_move_left_bt);
758 button_draw(&le_bad_bt);
759 button_draw(&le_bkgd_bt);
760 button_draw(&le_fgd_bt);
761 button_panel_draw(&le_bkgd_panel);
762 button_panel_draw(&le_fgd_panel);
763 button_panel_draw(&le_bad_panel);
765 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
766 text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
768 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
772 if(show_menu == false)
773 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
775 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
782 unsigned int y,x,i,s;
784 /* Draw the real background */
785 if(le_current_level->bkgd_image[0] != '\0')
788 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
789 texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
793 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
796 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
798 for (y = 0; y < 15; ++y)
799 for (x = 0; x < 20; ++x)
801 drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]);
803 /* draw whats inside stuff when cursor is selecting those */
804 /* (draw them all the time - is this the right behaviour?) */
805 switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)])
808 texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
811 texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
816 texture_draw(&img_distro[(global_frame_counter / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
823 /* Draw the Bad guys: */
824 for (i = 0; i < bad_guys.size(); ++i)
826 /* to support frames: img_bsod_left[(frame / 5) % 4] */
827 if(bad_guys[i].kind == BAD_BSOD)
828 texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
829 else if(bad_guys[i].kind == BAD_LAPTOP)
830 texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
831 else if (bad_guys[i].kind == BAD_MONEY)
832 texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
836 /* Draw the player: */
837 /* for now, the position is fixed at (0, 240) */
838 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 0 - pos_x, 240);
841 void le_checkevents()
845 button_type* pbutton;
848 keymod = SDL_GetModState();
850 while(SDL_PollEvent(&event))
852 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
853 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
854 event.motion.y > 0 && event.motion.y < screen->h)))
859 case SDL_KEYDOWN: // key pressed
860 key = event.key.keysym.sym;
864 if(key == SDLK_ESCAPE)
867 Menu::set_current(leveleditor_menu);
881 cursor_x -= KEY_CURSOR_SPEED;
883 cursor_x -= KEY_CURSOR_FASTSPEED;
885 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
886 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
891 cursor_x += KEY_CURSOR_SPEED;
893 cursor_x += KEY_CURSOR_FASTSPEED;
895 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
896 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
901 cursor_y -= KEY_CURSOR_SPEED;
903 cursor_y -= KEY_CURSOR_FASTSPEED;
910 cursor_y += KEY_CURSOR_SPEED;
912 cursor_y += KEY_CURSOR_FASTSPEED;
914 if(cursor_y > screen->h-32)
915 cursor_y = screen->h-32;
928 cursor_x = (le_current_level->width * 32) - 32;
932 le_show_grid = !le_show_grid;
938 case SDL_KEYUP: /* key released */
939 switch(event.key.keysym.sym)
948 case SDL_MOUSEBUTTONDOWN:
949 if(event.button.button == SDL_BUTTON_LEFT)
951 le_mouse_pressed[LEFT] = true;
953 selection.x1 = event.motion.x + pos_x;
954 selection.y1 = event.motion.y;
955 selection.x2 = event.motion.x + pos_x;
956 selection.y2 = event.motion.y;
958 else if(event.button.button == SDL_BUTTON_RIGHT)
959 le_mouse_pressed[RIGHT] = true;
961 case SDL_MOUSEBUTTONUP:
962 if(event.button.button == SDL_BUTTON_LEFT)
963 le_mouse_pressed[LEFT] = false;
964 else if(event.button.button == SDL_BUTTON_RIGHT)
965 le_mouse_pressed[RIGHT] = false;
967 case SDL_MOUSEMOTION:
973 cursor_x = ((int)(pos_x + x) / 32) * 32;
974 cursor_y = ((int) y / 32) * 32;
976 if(le_mouse_pressed[LEFT])
978 selection.x2 = x + pos_x;
982 if(le_mouse_pressed[RIGHT])
984 pos_x += -1 * event.motion.xrel;
988 case SDL_QUIT: // window closed
996 if(le_current_level != NULL)
998 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 &&
999 event.motion.y > 0 && event.motion.y < screen->h)))
1001 le_mouse_pressed[LEFT] = false;
1002 le_mouse_pressed[RIGHT] = false;
1004 if(show_menu == false)
1006 /* Check for button events */
1007 button_event(&le_test_level_bt,&event);
1008 if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
1010 button_event(&le_save_level_bt,&event);
1011 if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
1012 level_save(le_current_level,le_level_subset.name.c_str(),le_level);
1013 button_event(&le_next_level_bt,&event);
1014 if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
1016 if(le_level < le_level_subset.levels)
1018 le_goto_level(++le_level);
1025 sprintf(str,"Level %d doesn't exist.",le_level+1);
1026 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
1027 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
1028 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
1032 while(SDL_PollEvent(&event))
1035 case SDL_KEYDOWN: // key pressed
1036 switch(event.key.keysym.sym)
1039 level_default(&new_lev);
1040 level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
1041 le_level_subset.levels = le_level;
1042 le_goto_level(le_level);
1059 button_event(&le_previous_level_bt,&event);
1060 if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1063 le_goto_level(--le_level);
1065 button_event(&le_rubber_bt,&event);
1066 if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1067 le_current_tile = 0;
1068 button_event(&le_select_mode_one_bt,&event);
1069 if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1070 le_selection_mode = CURSOR;
1071 button_event(&le_select_mode_two_bt,&event);
1072 if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1073 le_selection_mode = SQUARE;
1075 button_event(&le_bad_bt,&event);
1076 if(button_get_state(&le_bad_bt) == BUTTON_CLICKED)
1078 le_bad_panel.hidden = false;
1079 le_fgd_panel.hidden = true;
1080 le_bkgd_panel.hidden = true;
1083 button_event(&le_fgd_bt,&event);
1084 if(button_get_state(&le_fgd_bt) == BUTTON_CLICKED)
1086 le_bad_panel.hidden = true;
1087 le_fgd_panel.hidden = false;
1088 le_bkgd_panel.hidden = true;
1090 button_event(&le_bkgd_bt,&event);
1091 if(button_get_state(&le_bkgd_bt) == BUTTON_CLICKED)
1093 le_bad_panel.hidden = true;
1094 le_fgd_panel.hidden = true;
1095 le_bkgd_panel.hidden = false;
1097 button_event(&le_settings_bt,&event);
1098 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1100 if(show_menu == false)
1102 update_level_settings_menu();
1103 Menu::set_current(level_settings_menu);
1108 Menu::set_current(leveleditor_menu);
1112 if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1114 if(button_get_state(pbutton) == BUTTON_CLICKED)
1117 if(pbutton->tag >= 0 && pbutton->tag <= 3)
1118 c = 'G' + pbutton->tag;
1119 else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1120 c = 'g' + pbutton->tag - 4;
1121 else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1122 c = 'C' + pbutton->tag - 8;
1123 else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1124 c = 'c' + pbutton->tag - 12;
1126 le_current_tile = c;
1129 if((pbutton = button_panel_event(&le_fgd_panel,&event)) != NULL)
1131 if(button_get_state(pbutton) == BUTTON_CLICKED)
1134 if(pbutton->tag == 0)
1136 else if(pbutton->tag == 1)
1138 else if(pbutton->tag == 2)
1140 else if(pbutton->tag == 3)
1142 else if(pbutton->tag == 4)
1144 else if(pbutton->tag == 5)
1146 else if(pbutton->tag == 6)
1148 else if(pbutton->tag == 7)
1150 else if(pbutton->tag == 8)
1152 else if(pbutton->tag == 9)
1154 else if(pbutton->tag == 10)
1156 else if(pbutton->tag == 11)
1158 else if(pbutton->tag == 12)
1160 else if(pbutton->tag == 13)
1162 else if(pbutton->tag == 14)
1164 else if(pbutton->tag == 15)
1166 else if(pbutton->tag == 16)
1168 else if(pbutton->tag == 17)
1171 le_current_tile = c;
1174 if((pbutton = button_panel_event(&le_bad_panel,&event)) != NULL)
1176 if(button_get_state(pbutton) == BUTTON_CLICKED)
1179 if(pbutton->tag >= 0 && pbutton->tag <= 2)
1180 c = '0' + pbutton->tag;
1182 le_current_tile = c;
1188 button_event(&le_settings_bt,&event);
1189 if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1191 if(show_menu == false)
1193 update_level_settings_menu();
1194 Menu::set_current(level_settings_menu);
1199 Menu::set_current(leveleditor_menu);
1205 if(show_menu == false)
1207 button_event(&le_move_left_bt,&event);
1208 button_event(&le_move_right_bt,&event);
1210 if(le_mouse_pressed[LEFT])
1212 le_change(cursor_x, cursor_y, TM_IA, le_current_tile);
1217 if(show_menu == false)
1219 if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1223 else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1228 if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1232 else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1240 void le_highlight_selection()
1244 if(selection.x1 < selection.x2)
1254 if(selection.y1 < selection.y2)
1270 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1273 void le_change(float x, float y, int tm, unsigned int c)
1275 if(le_current_level != NULL)
1281 /* level_changed = true; */
1283 switch(le_selection_mode)
1286 level_change(le_current_level,x,y,tm,c);
1291 /* if there is a bad guy over there, remove it */
1292 for(i = 0; i < bad_guys.size(); ++i)
1293 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1294 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1296 if(c == '0') /* if it's a bad guy */
1297 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1299 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1301 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1305 if(selection.x1 < selection.x2)
1315 if(selection.y1 < selection.y2)
1331 /* if there is a bad guy over there, remove it */
1332 for(i = 0; i < bad_guys.size(); ++i)
1333 if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1334 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1335 bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1337 for(xx = x1; xx <= x2; xx++)
1338 for(yy = y1; yy <= y2; yy++)
1340 level_change(le_current_level, xx*32, yy*32, tm, c);
1342 if(c == '0') // if it's a bad guy
1343 add_bad_guy(xx*32, yy*32, BAD_BSOD);
1345 add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1347 add_bad_guy(xx*32, yy*32, BAD_MONEY);
1358 level_save(le_current_level,"test",le_level);
1359 gameloop("test",le_level, ST_GL_TEST);
1360 Menu::set_current(leveleditor_menu);
1362 level_load_gfx(le_current_level);
1369 unsigned int i, done;
1371 " - This is SuperTux's built-in level editor -",
1372 "It has been designed to be light and easy to use from the start.",
1374 "When you first load the level editor you are given a menu where you",
1375 "can load level subsets, create a new level subset, edit the current",
1376 "subset's settings, or simply quit the editor. You can access this menu",
1377 "from the level editor at any time by pressing the escape key.",
1379 "To your right is your button bar. The center of this contains many",
1380 "tiles you can use to make your level. To select a tile, click on it",
1381 "with your left mouse button; your selection will be shown in the",
1382 "bottom right corner of the button box. Click anywhere on your level",
1383 "with the left mouse button to place that tile down. If you right click",
1384 "a tile in the button bar, you can find out what its keyboard shortcut",
1385 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1386 "background, and enemy tiles. The eraser lets you remove tiles.",
1387 "The left and right arrow keys scroll back and forth through your level.",
1388 "The button with the wrench and screwdriver, lets you change the",
1389 "settings of your level, including how long it is or what music it will",
1390 "play. When you are ready to give your level a test, click on the little",
1391 "running Tux. If you like the changes you have made to your level,",
1392 "press the red save key to keep them.",
1393 "To change which level in your subset you are editing, press the white",
1394 "up and down arrow keys at the top of the button box.",
1396 "Have fun making levels! If you make some good ones, send them to us on",
1397 "the SuperTux mailing list!",
1402 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1404 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1405 text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1407 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1415 while(SDL_PollEvent(&event))
1418 case SDL_MOUSEBUTTONDOWN: // mouse pressed
1419 case SDL_KEYDOWN: // key pressed