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 Surface* 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 le_selection = new Surface(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_TEXTFIELD,"Author ",0,0);
430 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
431 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
432 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
433 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
434 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
435 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
436 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
437 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
438 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
439 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
440 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
441 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
442 level_settings_menu->additem(MN_HL,"",0,0);
443 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
445 select_tilegroup_menu->arrange_left = true;
446 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
447 select_tilegroup_menu->additem(MN_HL,"",0,0);
448 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
449 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
452 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
453 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
455 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
456 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));
458 select_tilegroup_menu->additem(MN_HL,"",0,0);
460 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
465 void update_level_settings_menu()
470 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
471 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
472 sprintf(str,"%d",le_current_level->width);
474 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
475 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
476 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
477 string_list_add_item(level_settings_menu->item[6].list,"");
478 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
479 level_settings_menu->item[3].list->active_item = i;
480 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
481 level_settings_menu->item[4].list->active_item = i;
482 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
483 level_settings_menu->item[5].list->active_item = i;
485 level_settings_menu->item[7].change_input(str);
486 sprintf(str,"%d",le_current_level->time_left);
487 level_settings_menu->item[8].change_input(str);
488 sprintf(str,"%2.0f",le_current_level->gravity);
489 level_settings_menu->item[9].change_input(str);
490 sprintf(str,"%d",le_current_level->bkgd_top_red);
491 level_settings_menu->item[10].change_input(str);
492 sprintf(str,"%d",le_current_level->bkgd_top_green);
493 level_settings_menu->item[11].change_input(str);
494 sprintf(str,"%d",le_current_level->bkgd_top_blue);
495 level_settings_menu->item[12].change_input(str);
496 sprintf(str,"%d",le_current_level->bkgd_bottom_red);
497 level_settings_menu->item[13].change_input(str);
498 sprintf(str,"%d",le_current_level->bkgd_bottom_green);
499 level_settings_menu->item[14].change_input(str);
500 sprintf(str,"%d",le_current_level->bkgd_bottom_blue);
501 level_settings_menu->item[15].change_input(str);
504 void update_subset_settings_menu()
506 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
507 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
510 void apply_level_settings_menu()
515 le_current_level->name = level_settings_menu->item[2].input;
516 le_current_level->author = level_settings_menu->item[3].input;
518 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
520 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
524 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
526 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
532 le_current_level->free_gfx();
533 le_current_level->load_gfx();
536 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
538 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
539 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
540 le_current_level->gravity = atof(level_settings_menu->item[9].input);
541 le_current_level->bkgd_top_red = atoi(level_settings_menu->item[10].input);
542 le_current_level->bkgd_top_green = atoi(level_settings_menu->item[11].input);
543 le_current_level->bkgd_top_blue = atoi(level_settings_menu->item[12].input);
544 le_current_level->bkgd_bottom_red = atoi(level_settings_menu->item[13].input);
545 le_current_level->bkgd_bottom_green = atoi(level_settings_menu->item[14].input);
546 le_current_level->bkgd_bottom_blue = atoi(level_settings_menu->item[15].input);
549 void save_subset_settings_menu()
551 le_level_subset.title = subset_settings_menu->item[2].input;
552 le_level_subset.description = subset_settings_menu->item[3].input;
553 le_level_subset.save();
556 void le_goto_level(int levelnb)
558 le_world.arrays_free();
560 le_current_level->cleanup();
561 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
563 le_current_level->load(le_level_subset.name.c_str(), le_level);
572 le_current_level->free_gfx();
573 le_current_level->load_gfx();
575 le_world.activate_bad_guys();
580 /*if(level_changed == true)
581 if(askforsaving() == CANCEL)
584 SDL_EnableKeyRepeat(0, 0); // disables key repeating
587 delete leveleditor_menu;
588 delete subset_load_menu;
589 delete subset_new_menu;
590 delete subset_settings_menu;
591 delete level_settings_menu;
592 delete select_tilegroup_menu;
593 delete le_save_level_bt;
595 delete le_test_level_bt;
596 delete le_next_level_bt;
597 delete le_previous_level_bt;
598 delete le_move_right_bt;
599 delete le_move_left_bt;
601 delete le_select_mode_one_bt;
602 delete le_select_mode_two_bt;
603 delete le_settings_bt;
604 delete le_tilegroup_bt;
605 delete le_tilemap_panel;
607 if(le_current_level != NULL)
609 le_current_level->free_gfx();
610 le_current_level->cleanup();
611 le_world.arrays_free();
615 void le_drawinterface()
620 if(le_current_level != NULL)
622 /* draw a grid (if selected) */
625 for(x = 0; x < 19; x++)
626 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
627 for(y = 0; y < 15; y++)
628 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
632 if(le_selection_mode == CURSOR)
633 le_selection->draw( cursor_x - pos_x, cursor_y);
634 else if(le_selection_mode == SQUARE)
637 le_highlight_selection();
638 /* draw current selection */
639 w = selection.x2 - selection.x1;
640 h = selection.y2 - selection.y1;
641 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
642 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
643 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
644 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
648 /* draw button bar */
649 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
650 Tile::draw(19 * 32, 14 * 32, le_current_tile);
652 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
653 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
655 if(le_current_level != NULL)
657 le_save_level_bt->draw();
659 le_test_level_bt->draw();
660 le_next_level_bt->draw();
661 le_previous_level_bt->draw();
662 le_rubber_bt->draw();
663 le_select_mode_one_bt->draw();
664 le_select_mode_two_bt->draw();
665 le_settings_bt->draw();
666 le_move_right_bt->draw();
667 le_move_left_bt->draw();
668 le_tilegroup_bt->draw();
669 if(!cur_tilegroup.empty())
670 tilegroups_map[cur_tilegroup]->draw();
671 le_tilemap_panel->draw();
673 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
674 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
676 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
680 if(show_menu == false)
681 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
683 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
690 unsigned int y,x,i,s;
693 /* Draw the real background */
694 if(le_current_level->bkgd_image[0] != '\0')
697 le_current_level->img_bkgd->draw_part(s,0,0,0,
698 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
699 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
700 le_current_level->img_bkgd->h);
704 drawgradient(le_current_level->bkgd_top_red, le_current_level->bkgd_top_green, le_current_level->bkgd_top_blue,
705 le_current_level->bkgd_bottom_red, le_current_level->bkgd_bottom_green, le_current_level->bkgd_bottom_blue);
708 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
710 for (y = 0; y < 15; ++y)
711 for (x = 0; x < 20; ++x)
714 if(active_tm == TM_BG)
719 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
721 if(active_tm == TM_IA)
726 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
728 if(active_tm == TM_FG)
733 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
735 /* draw whats inside stuff when cursor is selecting those */
736 /* (draw them all the time - is this the right behaviour?) */
737 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
738 TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
742 /* Draw the Bad guys: */
743 for (i = 0; i < le_world.bad_guys.size(); ++i)
745 /* to support frames: img_bsod_left[(frame / 5) % 4] */
748 le_world.bad_guys[i].draw();
752 /* Draw the player: */
753 /* for now, the position is fixed at (100, 240) */
754 tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
757 void le_checkevents()
764 keymod = SDL_GetModState();
766 while(SDL_PollEvent(&event))
769 current_menu->event(event);
771 mouse_cursor->set_state(MC_NORMAL);
773 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
774 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
775 event.motion.y > 0 && event.motion.y < screen->h)))
779 case SDL_KEYDOWN: // key pressed
780 key = event.key.keysym.sym;
783 if(key == SDLK_ESCAPE)
786 Menu::set_current(leveleditor_menu);
800 cursor_x -= KEY_CURSOR_SPEED;
802 cursor_x -= KEY_CURSOR_FASTSPEED;
804 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
805 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
810 cursor_x += KEY_CURSOR_SPEED;
812 cursor_x += KEY_CURSOR_FASTSPEED;
814 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
815 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
820 cursor_y -= KEY_CURSOR_SPEED;
822 cursor_y -= KEY_CURSOR_FASTSPEED;
829 cursor_y += KEY_CURSOR_SPEED;
831 cursor_y += KEY_CURSOR_FASTSPEED;
833 if(cursor_y > screen->h-32)
834 cursor_y = screen->h-32;
847 cursor_x = (le_current_level->width * 32) - 32;
851 le_show_grid = !le_show_grid;
857 case SDL_KEYUP: /* key released */
858 switch(event.key.keysym.sym)
867 case SDL_MOUSEBUTTONDOWN:
868 if(event.button.button == SDL_BUTTON_LEFT)
870 le_mouse_pressed[LEFT] = true;
872 selection.x1 = event.motion.x + pos_x;
873 selection.y1 = event.motion.y;
874 selection.x2 = event.motion.x + pos_x;
875 selection.y2 = event.motion.y;
877 else if(event.button.button == SDL_BUTTON_RIGHT)
879 le_mouse_pressed[RIGHT] = true;
882 case SDL_MOUSEBUTTONUP:
883 if(event.button.button == SDL_BUTTON_LEFT)
884 le_mouse_pressed[LEFT] = false;
885 else if(event.button.button == SDL_BUTTON_RIGHT)
886 le_mouse_pressed[RIGHT] = false;
888 case SDL_MOUSEMOTION:
894 cursor_x = ((int)(pos_x + x) / 32) * 32;
895 cursor_y = ((int) y / 32) * 32;
897 if(le_mouse_pressed[LEFT])
899 selection.x2 = x + pos_x;
903 if(le_mouse_pressed[RIGHT])
905 pos_x += -1 * event.motion.xrel;
909 case SDL_QUIT: // window closed
917 if(le_current_level != NULL)
919 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 &&
920 event.motion.y > 0 && event.motion.y < screen->h)))
922 le_mouse_pressed[LEFT] = false;
923 le_mouse_pressed[RIGHT] = false;
925 if(show_menu == false)
927 /* Check for button events */
928 le_test_level_bt->event(event);
929 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
931 le_save_level_bt->event(event);
932 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
933 le_current_level->save(le_level_subset.name.c_str(),le_level);
934 le_exit_bt->event(event);
935 if(le_exit_bt->get_state() == BUTTON_CLICKED)
937 Menu::set_current(leveleditor_menu);
940 le_next_level_bt->event(event);
941 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
943 if(le_level < le_level_subset.levels)
945 le_goto_level(++le_level);
952 sprintf(str,"Level %d doesn't exist.",le_level+1);
953 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
954 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
955 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
959 while(SDL_PollEvent(&event))
962 case SDL_KEYDOWN: // key pressed
963 switch(event.key.keysym.sym)
966 new_lev.init_defaults();
967 new_lev.save(le_level_subset.name.c_str(),++le_level);
968 le_level_subset.levels = le_level;
969 le_goto_level(le_level);
986 le_previous_level_bt->event(event);
987 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
990 le_goto_level(--le_level);
992 le_rubber_bt->event(event);
993 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
995 le_select_mode_one_bt->event(event);
996 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
997 le_selection_mode = CURSOR;
998 le_select_mode_two_bt->event(event);
999 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1000 le_selection_mode = SQUARE;
1002 le_tilegroup_bt->event(event);
1003 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1005 Menu::set_current(select_tilegroup_menu);
1006 select_tilegroup_menu_effect.start(200);
1007 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1011 le_settings_bt->event(event);
1012 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1014 update_level_settings_menu();
1015 Menu::set_current(level_settings_menu);
1018 if(!cur_tilegroup.empty())
1019 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1021 if(pbutton->get_state() == BUTTON_CLICKED)
1023 le_current_tile = pbutton->get_tag();
1026 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1028 if(pbutton->get_state() == BUTTON_CLICKED)
1030 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1036 le_settings_bt->event(event);
1037 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1039 Menu::set_current(leveleditor_menu);
1042 le_tilegroup_bt->event(event);
1043 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1045 Menu::set_current(leveleditor_menu);
1050 if(show_menu == false)
1052 le_move_left_bt->event(event);
1053 le_move_right_bt->event(event);
1055 if(le_mouse_pressed[LEFT])
1057 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1062 if(show_menu == false)
1064 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1068 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1073 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1077 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1085 void le_highlight_selection()
1089 if(selection.x1 < selection.x2)
1099 if(selection.y1 < selection.y2)
1115 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1118 void le_change(float x, float y, int tm, unsigned int c)
1120 if(le_current_level != NULL)
1126 /* level_changed = true; */
1128 switch(le_selection_mode)
1131 le_current_level->change(x,y,tm,c);
1136 /* if there is a bad guy over there, remove it */
1137 for(i = 0; i < le_world.bad_guys.size(); ++i)
1138 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1139 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1141 if(c == '0') /* if it's a bad guy */
1142 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1144 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1146 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1150 if(selection.x1 < selection.x2)
1160 if(selection.y1 < selection.y2)
1176 /* if there is a bad guy over there, remove it */
1177 for(i = 0; i < le_world.bad_guys.size(); ++i)
1178 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1179 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1180 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1182 for(xx = x1; xx <= x2; xx++)
1183 for(yy = y1; yy <= y2; yy++)
1185 le_current_level->change(xx*32, yy*32, tm, c);
1187 if(c == '0') // if it's a bad guy
1188 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1190 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1192 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1203 le_current_level->save("test", le_level);
1205 GameSession session("test",le_level, ST_GL_TEST);
1208 Menu::set_current(leveleditor_menu);
1209 le_world.arrays_free();
1210 le_current_level->load_gfx();
1211 le_world.activate_bad_guys();
1217 unsigned int i, done;
1219 " - This is SuperTux's built-in level editor -",
1220 "It has been designed to be light and easy to use from the start.",
1222 "When you first load the level editor you are given a menu where you",
1223 "can load level subsets, create a new level subset, edit the current",
1224 "subset's settings, or simply quit the editor. You can access this menu",
1225 "from the level editor at any time by pressing the escape key.",
1227 "To your right is your button bar. The center of this contains many",
1228 "tiles you can use to make your level. To select a tile, click on it",
1229 "with your left mouse button; your selection will be shown in the",
1230 "bottom right corner of the button box. Click anywhere on your level",
1231 "with the left mouse button to place that tile down. If you right click",
1232 "a tile in the button bar, you can find out what its keyboard shortcut",
1233 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1234 "background, and enemy tiles. The eraser lets you remove tiles.",
1235 "The left and right arrow keys scroll back and forth through your level.",
1236 "The button with the wrench and screwdriver, lets you change the",
1237 "settings of your level, including how long it is or what music it will",
1238 "play. When you are ready to give your level a test, click on the little",
1239 "running Tux. If you like the changes you have made to your level,",
1240 "press the red save key to keep them.",
1241 "To change which level in your subset you are editing, press the white",
1242 "up and down arrow keys at the top of the button box.",
1244 "Have fun making levels! If you make some good ones, send them to us on",
1245 "the SuperTux mailing list!",
1250 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1252 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1253 text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1255 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1263 done = wait_for_event(event);