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> */
24 #include <SDL_image.h>
25 #include "leveleditor.h"
39 #include "resources.h"
41 /* definitions to aid development */
42 #define DONE_LEVELEDITOR 1
44 #define DONE_CHANGELEVEL 3
46 /* definitions that affect gameplay */
47 #define KEY_CURSOR_SPEED 32
48 #define KEY_CURSOR_FASTSPEED 64
50 /* when pagedown/up pressed speed:*/
51 #define PAGE_CURSOR_SPEED 13*32
53 #define MOUSE_LEFT_MARGIN 80
54 #define MOUSE_RIGHT_MARGIN (560-32)
55 /* right_margin should noticed that the cursor is 32 pixels,
56 so it should subtract that value */
57 #define MOUSE_POS_SPEED 20
60 #define SELECT_W 2 // size of the selections lines
61 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
63 /* own declerations */
64 /* crutial ones (main loop) */
68 void le_drawinterface();
69 void le_checkevents();
70 void le_change(float x, float y, int tm, unsigned int c);
73 void le_set_defaults(void);
74 void le_activate_bad_guys(void);
76 void le_highlight_selection();
78 void apply_level_settings_menu();
79 void update_subset_settings_menu();
80 void save_subset_settings_menu();
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 Level* le_current_level;
88 static World le_world;
89 static st_subset le_level_subset;
90 static int le_show_grid;
92 static texture_type le_selection;
94 static unsigned int le_current_tile;
95 static bool le_mouse_pressed[2];
96 static Button* le_save_level_bt;
97 static Button* le_exit_bt;
98 static Button* le_test_level_bt;
99 static Button* le_next_level_bt;
100 static Button* le_previous_level_bt;
101 static Button* le_move_right_bt;
102 static Button* le_move_left_bt;
103 static Button* le_rubber_bt;
104 static Button* le_select_mode_one_bt;
105 static Button* le_select_mode_two_bt;
106 static Button* le_settings_bt;
107 static Button* le_tilegroup_bt;
108 static ButtonPanel* le_tilemap_panel;
109 static Menu* leveleditor_menu;
110 static Menu* subset_load_menu;
111 static Menu* subset_new_menu;
112 static Menu* subset_settings_menu;
113 static Menu* level_settings_menu;
114 static Menu* select_tilegroup_menu;
115 static Timer select_tilegroup_menu_effect;
116 static std::map<std::string, ButtonPanel* > tilegroups_map;
117 static std::string cur_tilegroup;
119 static square selection;
120 static int le_selection_mode;
121 static SDL_Event event;
122 TileMapType active_tm;
124 void le_set_defaults()
126 if(le_current_level != NULL)
130 if(le_current_level->time_left == 0)
131 le_current_level->time_left = 255;
135 int leveleditor(int levelnb)
137 int last_time, now_time, i;
145 clearscreen(0, 0, 0);
148 while (SDL_PollEvent(&event))
153 last_time = SDL_GetTicks();
158 if(current_menu == select_tilegroup_menu)
160 if(select_tilegroup_menu_effect.check())
162 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
166 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
169 if(le_current_level != NULL)
171 /* making events results to be in order */
174 if(pos_x > (le_current_level->width * 32) - screen->w)
175 pos_x = (le_current_level->width * 32) - screen->w;
181 clearscreen(0, 0, 0);
183 /* draw editor interface */
188 menu_process_current();
189 if(current_menu == leveleditor_menu)
191 switch (leveleditor_menu->check())
197 update_subset_settings_menu();
200 done = DONE_LEVELEDITOR;
204 else if(current_menu == level_settings_menu)
206 switch (level_settings_menu->check())
209 apply_level_settings_menu();
210 Menu::set_current(leveleditor_menu);
217 else if(current_menu == select_tilegroup_menu)
220 switch (it = select_tilegroup_menu->check())
225 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
226 cur_tilegroup = select_tilegroup_menu->item[it].text;
233 else if(current_menu == subset_load_menu)
235 switch (i = subset_load_menu->check())
242 le_level_subset.load(level_subsets.item[i-2]);
243 leveleditor_menu->item[3].kind = MN_GOTO;
245 le_world.arrays_free();
246 le_current_level = new Level;
247 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
253 le_current_level->load_gfx();
254 le_world.activate_bad_guys();
260 else if(current_menu == subset_new_menu)
262 if(subset_new_menu->item[2].input[0] == '\0')
263 subset_new_menu->item[3].kind = MN_DEACTIVE;
266 subset_new_menu->item[3].kind = MN_ACTION;
268 switch (i = subset_new_menu->check())
271 st_subset::create(subset_new_menu->item[2].input);
272 le_level_subset.load(subset_new_menu->item[2].input);
273 leveleditor_menu->item[3].kind = MN_GOTO;
275 le_world.arrays_free();
276 le_current_level = new Level;
277 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
283 le_current_level->load_gfx();
284 le_world.activate_bad_guys();
285 subset_new_menu->item[2].change_input("");
291 else if(current_menu == subset_settings_menu)
293 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 )
294 subset_settings_menu->item[5].kind = MN_DEACTIVE;
296 subset_settings_menu->item[5].kind = MN_ACTION;
298 switch (i = subset_settings_menu->check())
301 save_subset_settings_menu();
308 mouse_cursor->draw();
316 if(done == DONE_QUIT)
322 ++global_frame_counter;
325 now_time = SDL_GetTicks();
326 if (now_time < last_time + FPS)
327 SDL_Delay(last_time + FPS - now_time); /* delay some time */
338 level_subsets = dsubdirs("/levels", "info");
344 /* level_changed = NO;*/
347 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
348 le_level_changed = false;
349 le_current_level = NULL;
352 le_mouse_pressed[LEFT] = false;
353 le_mouse_pressed[RIGHT] = false;
355 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
357 select_tilegroup_menu_effect.init(false);
360 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
361 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
362 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
363 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
364 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
365 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
366 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
367 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
368 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
369 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
370 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
371 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
373 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
374 le_tilemap_panel->set_button_size(32,10);
375 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
376 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
377 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
379 leveleditor_menu = new Menu();
380 subset_load_menu = new Menu();
381 subset_new_menu = new Menu();
382 subset_settings_menu = new Menu();
383 level_settings_menu = new Menu();
384 select_tilegroup_menu = new Menu();
386 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
387 leveleditor_menu->additem(MN_HL,"",0,0);
388 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
389 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
390 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
391 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
392 leveleditor_menu->additem(MN_HL,"",0,0);
393 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
396 Menu::set_current(leveleditor_menu);
399 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
400 subset_load_menu->additem(MN_HL, "", 0, 0);
402 for(i = 0; i < level_subsets.num_items; ++i)
404 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
406 subset_load_menu->additem(MN_HL,"",0,0);
407 subset_load_menu->additem(MN_BACK,"Back",0,0);
409 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
410 subset_new_menu->additem(MN_HL,"",0,0);
411 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
412 subset_new_menu->additem(MN_ACTION,"Create",0,0);
413 subset_new_menu->additem(MN_HL,"",0,0);
414 subset_new_menu->additem(MN_BACK,"Back",0,0);
416 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
417 subset_settings_menu->additem(MN_HL,"",0,0);
418 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
419 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
420 subset_settings_menu->additem(MN_HL,"",0,0);
421 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
422 subset_settings_menu->additem(MN_HL,"",0,0);
423 subset_settings_menu->additem(MN_BACK,"Back",0,0);
425 level_settings_menu->arrange_left = true;
426 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
427 level_settings_menu->additem(MN_HL,"",0,0);
428 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
429 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
430 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
431 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
432 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
433 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
434 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
435 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
436 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
437 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
438 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
439 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
440 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
441 level_settings_menu->additem(MN_HL,"",0,0);
442 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
444 select_tilegroup_menu->arrange_left = true;
445 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
446 select_tilegroup_menu->additem(MN_HL,"",0,0);
447 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
448 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
451 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
452 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
454 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
455 tilegroups_map[(*it).name]->additem(new Button(const_cast<char*>(("images/tilesets/" + TileManager::instance()->get(*sit)->filenames[0]).c_str()), const_cast<char*>((*it).name.c_str()),(SDLKey)(i+'a'),0,0,32,32),(*sit));
457 select_tilegroup_menu->additem(MN_HL,"",0,0);
459 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
464 void update_level_settings_menu()
469 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
470 sprintf(str,"%d",le_current_level->width);
472 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
473 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
474 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
475 string_list_add_item(level_settings_menu->item[5].list,"");
476 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
477 level_settings_menu->item[3].list->active_item = i;
478 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
479 level_settings_menu->item[4].list->active_item = i;
480 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
481 level_settings_menu->item[5].list->active_item = i;
483 level_settings_menu->item[6].change_input(str);
484 sprintf(str,"%d",le_current_level->time_left);
485 level_settings_menu->item[7].change_input(str);
486 sprintf(str,"%2.0f",le_current_level->gravity);
487 level_settings_menu->item[8].change_input(str);
488 sprintf(str,"%d",le_current_level->bkgd_top_red);
489 level_settings_menu->item[9].change_input(str);
490 sprintf(str,"%d",le_current_level->bkgd_top_green);
491 level_settings_menu->item[10].change_input(str);
492 sprintf(str,"%d",le_current_level->bkgd_top_blue);
493 level_settings_menu->item[11].change_input(str);
494 sprintf(str,"%d",le_current_level->bkgd_bottom_red);
495 level_settings_menu->item[12].change_input(str);
496 sprintf(str,"%d",le_current_level->bkgd_bottom_green);
497 level_settings_menu->item[13].change_input(str);
498 sprintf(str,"%d",le_current_level->bkgd_bottom_blue);
499 level_settings_menu->item[14].change_input(str);
502 void update_subset_settings_menu()
504 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
505 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
508 void apply_level_settings_menu()
513 le_current_level->name = level_settings_menu->item[2].input;
515 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
517 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
521 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
523 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
529 le_current_level->free_gfx();
530 le_current_level->load_gfx();
533 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
535 le_current_level->change_size(atoi(level_settings_menu->item[6].input));
536 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
537 le_current_level->gravity = atof(level_settings_menu->item[8].input);
538 le_current_level->bkgd_top_red = atoi(level_settings_menu->item[9].input);
539 le_current_level->bkgd_top_green = atoi(level_settings_menu->item[10].input);
540 le_current_level->bkgd_top_blue = atoi(level_settings_menu->item[11].input);
541 le_current_level->bkgd_bottom_red = atoi(level_settings_menu->item[12].input);
542 le_current_level->bkgd_bottom_green = atoi(level_settings_menu->item[13].input);
543 le_current_level->bkgd_bottom_blue = atoi(level_settings_menu->item[14].input);
546 void save_subset_settings_menu()
548 le_level_subset.title = subset_settings_menu->item[2].input;
549 le_level_subset.description = subset_settings_menu->item[3].input;
550 le_level_subset.save();
553 void le_goto_level(int levelnb)
555 le_world.arrays_free();
557 le_current_level->cleanup();
558 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
560 le_current_level->load(le_level_subset.name.c_str(), le_level);
569 le_current_level->free_gfx();
570 le_current_level->load_gfx();
572 le_world.activate_bad_guys();
577 /*if(level_changed == true)
578 if(askforsaving() == CANCEL)
581 SDL_EnableKeyRepeat(0, 0); // disables key repeating
583 texture_free(&le_selection);
584 delete leveleditor_menu;
585 delete subset_load_menu;
586 delete subset_new_menu;
587 delete subset_settings_menu;
588 delete level_settings_menu;
589 delete select_tilegroup_menu;
590 delete le_save_level_bt;
592 delete le_test_level_bt;
593 delete le_next_level_bt;
594 delete le_previous_level_bt;
595 delete le_move_right_bt;
596 delete le_move_left_bt;
598 delete le_select_mode_one_bt;
599 delete le_select_mode_two_bt;
600 delete le_settings_bt;
601 delete le_tilegroup_bt;
602 delete le_tilemap_panel;
604 if(le_current_level != NULL)
606 le_current_level->free_gfx();
607 le_current_level->cleanup();
608 le_world.arrays_free();
612 void le_drawinterface()
617 if(le_current_level != NULL)
619 /* draw a grid (if selected) */
622 for(x = 0; x < 19; x++)
623 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
624 for(y = 0; y < 15; y++)
625 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
629 if(le_selection_mode == CURSOR)
630 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
631 else if(le_selection_mode == SQUARE)
634 le_highlight_selection();
635 /* draw current selection */
636 w = selection.x2 - selection.x1;
637 h = selection.y2 - selection.y1;
638 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
639 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
640 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
641 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
645 /* draw button bar */
646 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
647 Tile::draw(19 * 32, 14 * 32, le_current_tile);
649 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
650 texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
652 if(le_current_level != NULL)
654 le_save_level_bt->draw();
656 le_test_level_bt->draw();
657 le_next_level_bt->draw();
658 le_previous_level_bt->draw();
659 le_rubber_bt->draw();
660 le_select_mode_one_bt->draw();
661 le_select_mode_two_bt->draw();
662 le_settings_bt->draw();
663 le_move_right_bt->draw();
664 le_move_left_bt->draw();
665 le_tilegroup_bt->draw();
666 if(!cur_tilegroup.empty())
667 tilegroups_map[cur_tilegroup]->draw();
668 le_tilemap_panel->draw();
670 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
671 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
673 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
677 if(show_menu == false)
678 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
680 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
687 unsigned int y,x,i,s;
690 /* Draw the real background */
691 if(le_current_level->bkgd_image[0] != '\0')
694 texture_draw_part(&le_current_level->img_bkgd,s,0,0,0,
695 le_current_level->img_bkgd.w - s - 32, le_current_level->img_bkgd.h);
696 texture_draw_part(&le_current_level->img_bkgd,0,0,screen->w - s - 32 ,0,s,
697 le_current_level->img_bkgd.h);
701 drawgradient(le_current_level->bkgd_top_red, le_current_level->bkgd_top_green, le_current_level->bkgd_top_blue,
702 le_current_level->bkgd_bottom_red, le_current_level->bkgd_bottom_green, le_current_level->bkgd_bottom_blue);
705 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
707 for (y = 0; y < 15; ++y)
708 for (x = 0; x < 20; ++x)
711 if(active_tm == TM_BG)
716 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
718 if(active_tm == TM_IA)
723 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
725 if(active_tm == TM_FG)
730 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
732 /* draw whats inside stuff when cursor is selecting those */
733 /* (draw them all the time - is this the right behaviour?) */
734 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
735 texture_draw(&TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images[0], x * 32 - ((int)pos_x % 32), y*32);
739 /* Draw the Bad guys: */
740 for (i = 0; i < le_world.bad_guys.size(); ++i)
742 /* to support frames: img_bsod_left[(frame / 5) % 4] */
745 le_world.bad_guys[i].draw();
749 /* Draw the player: */
750 /* for now, the position is fixed at (100, 240) */
751 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
754 void le_checkevents()
761 keymod = SDL_GetModState();
763 while(SDL_PollEvent(&event))
766 current_menu->event(event);
768 mouse_cursor->set_state(MC_NORMAL);
770 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
771 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
772 event.motion.y > 0 && event.motion.y < screen->h)))
776 case SDL_KEYDOWN: // key pressed
777 key = event.key.keysym.sym;
780 if(key == SDLK_ESCAPE)
783 Menu::set_current(leveleditor_menu);
797 cursor_x -= KEY_CURSOR_SPEED;
799 cursor_x -= KEY_CURSOR_FASTSPEED;
801 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
802 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
807 cursor_x += KEY_CURSOR_SPEED;
809 cursor_x += KEY_CURSOR_FASTSPEED;
811 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
812 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
817 cursor_y -= KEY_CURSOR_SPEED;
819 cursor_y -= KEY_CURSOR_FASTSPEED;
826 cursor_y += KEY_CURSOR_SPEED;
828 cursor_y += KEY_CURSOR_FASTSPEED;
830 if(cursor_y > screen->h-32)
831 cursor_y = screen->h-32;
844 cursor_x = (le_current_level->width * 32) - 32;
848 le_show_grid = !le_show_grid;
854 case SDL_KEYUP: /* key released */
855 switch(event.key.keysym.sym)
864 case SDL_MOUSEBUTTONDOWN:
865 if(event.button.button == SDL_BUTTON_LEFT)
867 le_mouse_pressed[LEFT] = true;
869 selection.x1 = event.motion.x + pos_x;
870 selection.y1 = event.motion.y;
871 selection.x2 = event.motion.x + pos_x;
872 selection.y2 = event.motion.y;
874 else if(event.button.button == SDL_BUTTON_RIGHT)
876 le_mouse_pressed[RIGHT] = true;
879 case SDL_MOUSEBUTTONUP:
880 if(event.button.button == SDL_BUTTON_LEFT)
881 le_mouse_pressed[LEFT] = false;
882 else if(event.button.button == SDL_BUTTON_RIGHT)
883 le_mouse_pressed[RIGHT] = false;
885 case SDL_MOUSEMOTION:
891 cursor_x = ((int)(pos_x + x) / 32) * 32;
892 cursor_y = ((int) y / 32) * 32;
894 if(le_mouse_pressed[LEFT])
896 selection.x2 = x + pos_x;
900 if(le_mouse_pressed[RIGHT])
902 pos_x += -1 * event.motion.xrel;
906 case SDL_QUIT: // window closed
914 if(le_current_level != NULL)
916 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 &&
917 event.motion.y > 0 && event.motion.y < screen->h)))
919 le_mouse_pressed[LEFT] = false;
920 le_mouse_pressed[RIGHT] = false;
922 if(show_menu == false)
924 /* Check for button events */
925 le_test_level_bt->event(event);
926 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
928 le_save_level_bt->event(event);
929 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
930 le_current_level->save(le_level_subset.name.c_str(),le_level);
931 le_exit_bt->event(event);
932 if(le_exit_bt->get_state() == BUTTON_CLICKED)
934 Menu::set_current(leveleditor_menu);
937 le_next_level_bt->event(event);
938 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
940 if(le_level < le_level_subset.levels)
942 le_goto_level(++le_level);
949 sprintf(str,"Level %d doesn't exist.",le_level+1);
950 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
951 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
952 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
956 while(SDL_PollEvent(&event))
959 case SDL_KEYDOWN: // key pressed
960 switch(event.key.keysym.sym)
963 new_lev.init_defaults();
964 new_lev.save(le_level_subset.name.c_str(),++le_level);
965 le_level_subset.levels = le_level;
966 le_goto_level(le_level);
983 le_previous_level_bt->event(event);
984 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
987 le_goto_level(--le_level);
989 le_rubber_bt->event(event);
990 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
992 le_select_mode_one_bt->event(event);
993 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
994 le_selection_mode = CURSOR;
995 le_select_mode_two_bt->event(event);
996 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
997 le_selection_mode = SQUARE;
999 le_tilegroup_bt->event(event);
1000 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1002 Menu::set_current(select_tilegroup_menu);
1003 select_tilegroup_menu_effect.start(200);
1004 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1008 le_settings_bt->event(event);
1009 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1011 update_level_settings_menu();
1012 Menu::set_current(level_settings_menu);
1015 if(!cur_tilegroup.empty())
1016 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1018 if(pbutton->get_state() == BUTTON_CLICKED)
1020 le_current_tile = pbutton->get_tag();
1023 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1025 if(pbutton->get_state() == BUTTON_CLICKED)
1027 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1033 le_settings_bt->event(event);
1034 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1036 Menu::set_current(leveleditor_menu);
1039 le_tilegroup_bt->event(event);
1040 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1042 Menu::set_current(leveleditor_menu);
1047 if(show_menu == false)
1049 le_move_left_bt->event(event);
1050 le_move_right_bt->event(event);
1052 if(le_mouse_pressed[LEFT])
1054 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1059 if(show_menu == false)
1061 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1065 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1070 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1074 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1082 void le_highlight_selection()
1086 if(selection.x1 < selection.x2)
1096 if(selection.y1 < selection.y2)
1112 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1115 void le_change(float x, float y, int tm, unsigned int c)
1117 if(le_current_level != NULL)
1123 /* level_changed = true; */
1125 switch(le_selection_mode)
1128 le_current_level->change(x,y,tm,c);
1133 /* if there is a bad guy over there, remove it */
1134 for(i = 0; i < le_world.bad_guys.size(); ++i)
1135 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1136 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1138 if(c == '0') /* if it's a bad guy */
1139 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1141 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1143 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1147 if(selection.x1 < selection.x2)
1157 if(selection.y1 < selection.y2)
1173 /* if there is a bad guy over there, remove it */
1174 for(i = 0; i < le_world.bad_guys.size(); ++i)
1175 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1176 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1177 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1179 for(xx = x1; xx <= x2; xx++)
1180 for(yy = y1; yy <= y2; yy++)
1182 le_current_level->change(xx*32, yy*32, tm, c);
1184 if(c == '0') // if it's a bad guy
1185 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1187 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1189 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1200 le_current_level->save("test", le_level);
1202 GameSession session("test",le_level, ST_GL_TEST);
1205 Menu::set_current(leveleditor_menu);
1206 le_world.arrays_free();
1207 le_current_level->load_gfx();
1208 le_world.activate_bad_guys();
1214 unsigned int i, done;
1216 " - This is SuperTux's built-in level editor -",
1217 "It has been designed to be light and easy to use from the start.",
1219 "When you first load the level editor you are given a menu where you",
1220 "can load level subsets, create a new level subset, edit the current",
1221 "subset's settings, or simply quit the editor. You can access this menu",
1222 "from the level editor at any time by pressing the escape key.",
1224 "To your right is your button bar. The center of this contains many",
1225 "tiles you can use to make your level. To select a tile, click on it",
1226 "with your left mouse button; your selection will be shown in the",
1227 "bottom right corner of the button box. Click anywhere on your level",
1228 "with the left mouse button to place that tile down. If you right click",
1229 "a tile in the button bar, you can find out what its keyboard shortcut",
1230 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1231 "background, and enemy tiles. The eraser lets you remove tiles.",
1232 "The left and right arrow keys scroll back and forth through your level.",
1233 "The button with the wrench and screwdriver, lets you change the",
1234 "settings of your level, including how long it is or what music it will",
1235 "play. When you are ready to give your level a test, click on the little",
1236 "running Tux. If you like the changes you have made to your level,",
1237 "press the red save key to keep them.",
1238 "To change which level in your subset you are editing, press the white",
1239 "up and down arrow keys at the top of the button box.",
1241 "Have fun making levels! If you make some good ones, send them to us on",
1242 "the SuperTux mailing list!",
1247 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1249 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1250 text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1252 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1260 done = wait_for_event(event);