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 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* le_save_level_bt;
96 static Button* le_exit_bt;
97 static Button* le_test_level_bt;
98 static Button* le_next_level_bt;
99 static Button* le_previous_level_bt;
100 static Button* le_move_right_bt;
101 static Button* le_move_left_bt;
102 static Button* le_rubber_bt;
103 static Button* le_select_mode_one_bt;
104 static Button* le_select_mode_two_bt;
105 static Button* le_settings_bt;
106 static Button* le_tilegroup_bt;
107 static ButtonPanel* le_tilemap_panel;
108 static Menu* leveleditor_menu;
109 static Menu* subset_load_menu;
110 static Menu* subset_new_menu;
111 static Menu* subset_settings_menu;
112 static Menu* level_settings_menu;
113 static Menu* select_tilegroup_menu;
114 static Timer select_tilegroup_menu_effect;
115 static std::map<std::string, ButtonPanel* > tilegroups_map;
116 static std::string cur_tilegroup;
118 static square selection;
119 static int le_selection_mode;
120 static SDL_Event event;
121 TileMapType active_tm;
123 void le_set_defaults()
125 if(le_current_level != NULL)
129 if(le_current_level->time_left == 0)
130 le_current_level->time_left = 255;
134 int leveleditor(int levelnb)
136 int last_time, now_time, i;
144 clearscreen(0, 0, 0);
147 while (SDL_PollEvent(&event))
152 last_time = SDL_GetTicks();
157 if(current_menu == select_tilegroup_menu)
159 if(select_tilegroup_menu_effect.check())
161 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
165 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
168 if(le_current_level != NULL)
170 /* making events results to be in order */
173 if(pos_x > (le_current_level->width * 32) - screen->w)
174 pos_x = (le_current_level->width * 32) - screen->w;
180 clearscreen(0, 0, 0);
182 /* draw editor interface */
187 menu_process_current();
188 if(current_menu == leveleditor_menu)
190 switch (leveleditor_menu->check())
196 update_subset_settings_menu();
199 done = DONE_LEVELEDITOR;
203 else if(current_menu == level_settings_menu)
205 switch (level_settings_menu->check())
208 apply_level_settings_menu();
209 Menu::set_current(leveleditor_menu);
216 else if(current_menu == select_tilegroup_menu)
219 switch (it = select_tilegroup_menu->check())
224 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
225 cur_tilegroup = select_tilegroup_menu->item[it].text;
232 else if(current_menu == subset_load_menu)
234 switch (i = subset_load_menu->check())
241 le_level_subset.load(level_subsets.item[i-2]);
242 leveleditor_menu->item[3].kind = MN_GOTO;
244 global_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 global_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 global_world.arrays_free();
277 le_current_level = new Level;
278 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
284 le_current_level->load_gfx();
285 global_world.activate_bad_guys();
286 menu_item_change_input(&subset_new_menu->item[2],"");
292 else if(current_menu == subset_settings_menu)
294 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 )
295 subset_settings_menu->item[5].kind = MN_DEACTIVE;
297 subset_settings_menu->item[5].kind = MN_ACTION;
299 switch (i = subset_settings_menu->check())
302 save_subset_settings_menu();
309 mouse_cursor->draw();
317 if(done == DONE_QUIT)
323 ++global_frame_counter;
326 now_time = SDL_GetTicks();
327 if (now_time < last_time + FPS)
328 SDL_Delay(last_time + FPS - now_time); /* delay some time */
339 level_subsets = dsubdirs("/levels", "info");
345 /* level_changed = NO;*/
348 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
349 le_level_changed = false;
350 le_current_level = NULL;
353 le_mouse_pressed[LEFT] = false;
354 le_mouse_pressed[RIGHT] = false;
356 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
358 select_tilegroup_menu_effect.init(false);
361 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
362 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
363 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
364 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
365 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
366 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
367 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
368 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
369 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
370 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
371 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
372 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
374 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
375 le_tilemap_panel->set_button_size(32,10);
376 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
377 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
378 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
380 leveleditor_menu = new Menu();
381 subset_load_menu = new Menu();
382 subset_new_menu = new Menu();
383 subset_settings_menu = new Menu();
384 level_settings_menu = new Menu();
385 select_tilegroup_menu = new Menu();
387 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
388 leveleditor_menu->additem(MN_HL,"",0,0);
389 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
390 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
391 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
392 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
393 leveleditor_menu->additem(MN_HL,"",0,0);
394 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
397 Menu::set_current(leveleditor_menu);
400 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
401 subset_load_menu->additem(MN_HL, "", 0, 0);
403 for(i = 0; i < level_subsets.num_items; ++i)
405 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
407 subset_load_menu->additem(MN_HL,"",0,0);
408 subset_load_menu->additem(MN_BACK,"Back",0,0);
410 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
411 subset_new_menu->additem(MN_HL,"",0,0);
412 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
413 subset_new_menu->additem(MN_ACTION,"Create",0,0);
414 subset_new_menu->additem(MN_HL,"",0,0);
415 subset_new_menu->additem(MN_BACK,"Back",0,0);
417 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
418 subset_settings_menu->additem(MN_HL,"",0,0);
419 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
420 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
421 subset_settings_menu->additem(MN_HL,"",0,0);
422 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
423 subset_settings_menu->additem(MN_HL,"",0,0);
424 subset_settings_menu->additem(MN_BACK,"Back",0,0);
426 level_settings_menu->arrange_left = true;
427 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
428 level_settings_menu->additem(MN_HL,"",0,0);
429 level_settings_menu->additem(MN_TEXTFIELD,"Name ",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,"Red ",0,0);
437 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
438 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
439 level_settings_menu->additem(MN_HL,"",0,0);
440 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
442 select_tilegroup_menu->arrange_left = true;
443 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
444 select_tilegroup_menu->additem(MN_HL,"",0,0);
445 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
446 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
449 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
450 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
452 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
453 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));
455 select_tilegroup_menu->additem(MN_HL,"",0,0);
457 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
462 void update_level_settings_menu()
467 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
468 sprintf(str,"%d",le_current_level->width);
470 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
471 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
472 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
473 string_list_add_item(level_settings_menu->item[5].list,"");
474 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
475 level_settings_menu->item[3].list->active_item = i;
476 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
477 level_settings_menu->item[4].list->active_item = i;
478 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
479 level_settings_menu->item[5].list->active_item = i;
481 menu_item_change_input(&level_settings_menu->item[6], str);
482 sprintf(str,"%d",le_current_level->time_left);
483 menu_item_change_input(&level_settings_menu->item[7], str);
484 sprintf(str,"%2.0f",le_current_level->gravity);
485 menu_item_change_input(&level_settings_menu->item[8], str);
486 sprintf(str,"%d",le_current_level->bkgd_red);
487 menu_item_change_input(&level_settings_menu->item[9], str);
488 sprintf(str,"%d",le_current_level->bkgd_green);
489 menu_item_change_input(&level_settings_menu->item[10], str);
490 sprintf(str,"%d",le_current_level->bkgd_blue);
491 menu_item_change_input(&level_settings_menu->item[11], str);
494 void update_subset_settings_menu()
496 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
497 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
500 void apply_level_settings_menu()
505 le_current_level->name = level_settings_menu->item[2].input;
507 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
509 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
513 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
515 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
521 le_current_level->free_gfx();
522 le_current_level->load_gfx();
525 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
527 le_current_level->change_size(atoi(level_settings_menu->item[6].input));
528 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
529 le_current_level->gravity = atof(level_settings_menu->item[8].input);
530 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
531 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
532 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
535 void save_subset_settings_menu()
537 le_level_subset.title = subset_settings_menu->item[2].input;
538 le_level_subset.description = subset_settings_menu->item[3].input;
539 le_level_subset.save();
542 void le_goto_level(int levelnb)
544 global_world.arrays_free();
546 le_current_level->cleanup();
547 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
549 le_current_level->load(le_level_subset.name.c_str(), le_level);
558 le_current_level->free_gfx();
559 le_current_level->load_gfx();
561 global_world.activate_bad_guys();
566 /*if(level_changed == true)
567 if(askforsaving() == CANCEL)
570 SDL_EnableKeyRepeat(0, 0); // disables key repeating
572 texture_free(&le_selection);
573 delete leveleditor_menu;
574 delete subset_load_menu;
575 delete subset_new_menu;
576 delete subset_settings_menu;
577 delete level_settings_menu;
578 delete select_tilegroup_menu;
579 delete le_save_level_bt;
581 delete le_test_level_bt;
582 delete le_next_level_bt;
583 delete le_previous_level_bt;
584 delete le_move_right_bt;
585 delete le_move_left_bt;
587 delete le_select_mode_one_bt;
588 delete le_select_mode_two_bt;
589 delete le_settings_bt;
590 delete le_tilegroup_bt;
591 delete le_tilemap_panel;
593 if(le_current_level != NULL)
595 le_current_level->free_gfx();
596 le_current_level->cleanup();
597 global_world.arrays_free();
602 void le_drawinterface()
607 if(le_current_level != NULL)
609 /* draw a grid (if selected) */
612 for(x = 0; x < 19; x++)
613 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
614 for(y = 0; y < 15; y++)
615 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
619 if(le_selection_mode == CURSOR)
620 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
621 else if(le_selection_mode == SQUARE)
624 le_highlight_selection();
625 /* draw current selection */
626 w = selection.x2 - selection.x1;
627 h = selection.y2 - selection.y1;
628 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
629 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
630 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
631 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
635 /* draw button bar */
636 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
637 Tile::draw(19 * 32, 14 * 32, le_current_tile);
639 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
640 texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
642 if(le_current_level != NULL)
644 le_save_level_bt->draw();
646 le_test_level_bt->draw();
647 le_next_level_bt->draw();
648 le_previous_level_bt->draw();
649 le_rubber_bt->draw();
650 le_select_mode_one_bt->draw();
651 le_select_mode_two_bt->draw();
652 le_settings_bt->draw();
653 le_move_right_bt->draw();
654 le_move_left_bt->draw();
655 le_tilegroup_bt->draw();
656 if(!cur_tilegroup.empty())
657 tilegroups_map[cur_tilegroup]->draw();
658 le_tilemap_panel->draw();
660 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
661 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
663 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
667 if(show_menu == false)
668 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
670 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
677 unsigned int y,x,i,s;
680 /* Draw the real background */
681 if(le_current_level->bkgd_image[0] != '\0')
684 texture_draw_part(&le_current_level->img_bkgd,s,0,0,0,
685 le_current_level->img_bkgd.w - s - 32, le_current_level->img_bkgd.h);
686 texture_draw_part(&le_current_level->img_bkgd,0,0,screen->w - s - 32 ,0,s,
687 le_current_level->img_bkgd.h);
691 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
694 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
696 for (y = 0; y < 15; ++y)
697 for (x = 0; x < 20; ++x)
700 if(active_tm == TM_BG)
705 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
707 if(active_tm == TM_IA)
712 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
714 if(active_tm == TM_FG)
719 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
721 /* draw whats inside stuff when cursor is selecting those */
722 /* (draw them all the time - is this the right behaviour?) */
723 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
724 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);
728 /* Draw the Bad guys: */
729 for (i = 0; i < global_world.bad_guys.size(); ++i)
731 /* to support frames: img_bsod_left[(frame / 5) % 4] */
734 global_world.bad_guys[i].draw();
738 /* Draw the player: */
739 /* for now, the position is fixed at (100, 240) */
740 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
743 void le_checkevents()
750 keymod = SDL_GetModState();
752 while(SDL_PollEvent(&event))
757 mouse_cursor->set_state(MC_NORMAL);
759 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
760 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
761 event.motion.y > 0 && event.motion.y < screen->h)))
765 case SDL_KEYDOWN: // key pressed
766 key = event.key.keysym.sym;
769 if(key == SDLK_ESCAPE)
772 Menu::set_current(leveleditor_menu);
786 cursor_x -= KEY_CURSOR_SPEED;
788 cursor_x -= KEY_CURSOR_FASTSPEED;
790 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
791 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
796 cursor_x += KEY_CURSOR_SPEED;
798 cursor_x += KEY_CURSOR_FASTSPEED;
800 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
801 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
806 cursor_y -= KEY_CURSOR_SPEED;
808 cursor_y -= KEY_CURSOR_FASTSPEED;
815 cursor_y += KEY_CURSOR_SPEED;
817 cursor_y += KEY_CURSOR_FASTSPEED;
819 if(cursor_y > screen->h-32)
820 cursor_y = screen->h-32;
833 cursor_x = (le_current_level->width * 32) - 32;
837 le_show_grid = !le_show_grid;
843 case SDL_KEYUP: /* key released */
844 switch(event.key.keysym.sym)
853 case SDL_MOUSEBUTTONDOWN:
854 if(event.button.button == SDL_BUTTON_LEFT)
856 le_mouse_pressed[LEFT] = true;
858 selection.x1 = event.motion.x + pos_x;
859 selection.y1 = event.motion.y;
860 selection.x2 = event.motion.x + pos_x;
861 selection.y2 = event.motion.y;
863 else if(event.button.button == SDL_BUTTON_RIGHT)
865 le_mouse_pressed[RIGHT] = true;
868 case SDL_MOUSEBUTTONUP:
869 if(event.button.button == SDL_BUTTON_LEFT)
870 le_mouse_pressed[LEFT] = false;
871 else if(event.button.button == SDL_BUTTON_RIGHT)
872 le_mouse_pressed[RIGHT] = false;
874 case SDL_MOUSEMOTION:
880 cursor_x = ((int)(pos_x + x) / 32) * 32;
881 cursor_y = ((int) y / 32) * 32;
883 if(le_mouse_pressed[LEFT])
885 selection.x2 = x + pos_x;
889 if(le_mouse_pressed[RIGHT])
891 pos_x += -1 * event.motion.xrel;
895 case SDL_QUIT: // window closed
903 if(le_current_level != NULL)
905 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 &&
906 event.motion.y > 0 && event.motion.y < screen->h)))
908 le_mouse_pressed[LEFT] = false;
909 le_mouse_pressed[RIGHT] = false;
911 if(show_menu == false)
913 /* Check for button events */
914 le_test_level_bt->event(event);
915 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
917 le_save_level_bt->event(event);
918 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
919 le_current_level->save(le_level_subset.name.c_str(),le_level);
920 le_exit_bt->event(event);
921 if(le_exit_bt->get_state() == BUTTON_CLICKED)
923 Menu::set_current(leveleditor_menu);
926 le_next_level_bt->event(event);
927 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
929 if(le_level < le_level_subset.levels)
931 le_goto_level(++le_level);
938 sprintf(str,"Level %d doesn't exist.",le_level+1);
939 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
940 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
941 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
945 while(SDL_PollEvent(&event))
948 case SDL_KEYDOWN: // key pressed
949 switch(event.key.keysym.sym)
952 new_lev.init_defaults();
953 new_lev.save(le_level_subset.name.c_str(),++le_level);
954 le_level_subset.levels = le_level;
955 le_goto_level(le_level);
972 le_previous_level_bt->event(event);
973 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
976 le_goto_level(--le_level);
978 le_rubber_bt->event(event);
979 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
981 le_select_mode_one_bt->event(event);
982 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
983 le_selection_mode = CURSOR;
984 le_select_mode_two_bt->event(event);
985 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
986 le_selection_mode = SQUARE;
988 le_tilegroup_bt->event(event);
989 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
991 Menu::set_current(select_tilegroup_menu);
992 select_tilegroup_menu_effect.start(200);
993 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
997 le_settings_bt->event(event);
998 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1000 update_level_settings_menu();
1001 Menu::set_current(level_settings_menu);
1004 if(!cur_tilegroup.empty())
1005 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1007 if(pbutton->get_state() == BUTTON_CLICKED)
1009 le_current_tile = pbutton->get_tag();
1012 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1014 if(pbutton->get_state() == BUTTON_CLICKED)
1016 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1022 le_settings_bt->event(event);
1023 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1025 Menu::set_current(leveleditor_menu);
1028 le_tilegroup_bt->event(event);
1029 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1031 Menu::set_current(leveleditor_menu);
1036 if(show_menu == false)
1038 le_move_left_bt->event(event);
1039 le_move_right_bt->event(event);
1041 if(le_mouse_pressed[LEFT])
1043 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1048 if(show_menu == false)
1050 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1054 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1059 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1063 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1071 void le_highlight_selection()
1075 if(selection.x1 < selection.x2)
1085 if(selection.y1 < selection.y2)
1101 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1104 void le_change(float x, float y, int tm, unsigned int c)
1106 if(le_current_level != NULL)
1112 /* level_changed = true; */
1114 switch(le_selection_mode)
1117 le_current_level->change(x,y,tm,c);
1122 /* if there is a bad guy over there, remove it */
1123 for(i = 0; i < global_world.bad_guys.size(); ++i)
1124 if(xx == global_world.bad_guys[i].base.x/32 && yy == global_world.bad_guys[i].base.y/32)
1125 global_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&global_world.bad_guys[i]));
1127 if(c == '0') /* if it's a bad guy */
1128 global_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1130 global_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1132 global_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1136 if(selection.x1 < selection.x2)
1146 if(selection.y1 < selection.y2)
1162 /* if there is a bad guy over there, remove it */
1163 for(i = 0; i < global_world.bad_guys.size(); ++i)
1164 if(global_world.bad_guys[i].base.x/32 >= x1 && global_world.bad_guys[i].base.x/32 <= x2
1165 && global_world.bad_guys[i].base.y/32 >= y1 && global_world.bad_guys[i].base.y/32 <= y2)
1166 global_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&global_world.bad_guys[i]));
1168 for(xx = x1; xx <= x2; xx++)
1169 for(yy = y1; yy <= y2; yy++)
1171 le_current_level->change(xx*32, yy*32, tm, c);
1173 if(c == '0') // if it's a bad guy
1174 global_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1176 global_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1178 global_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1189 le_current_level->save("test", le_level);
1191 GameSession session("test",le_level, ST_GL_TEST);
1194 Menu::set_current(leveleditor_menu);
1195 global_world.arrays_free();
1196 le_current_level->load_gfx();
1198 global_world.activate_bad_guys();
1204 unsigned int i, done;
1206 " - This is SuperTux's built-in level editor -",
1207 "It has been designed to be light and easy to use from the start.",
1209 "When you first load the level editor you are given a menu where you",
1210 "can load level subsets, create a new level subset, edit the current",
1211 "subset's settings, or simply quit the editor. You can access this menu",
1212 "from the level editor at any time by pressing the escape key.",
1214 "To your right is your button bar. The center of this contains many",
1215 "tiles you can use to make your level. To select a tile, click on it",
1216 "with your left mouse button; your selection will be shown in the",
1217 "bottom right corner of the button box. Click anywhere on your level",
1218 "with the left mouse button to place that tile down. If you right click",
1219 "a tile in the button bar, you can find out what its keyboard shortcut",
1220 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1221 "background, and enemy tiles. The eraser lets you remove tiles.",
1222 "The left and right arrow keys scroll back and forth through your level.",
1223 "The button with the wrench and screwdriver, lets you change the",
1224 "settings of your level, including how long it is or what music it will",
1225 "play. When you are ready to give your level a test, click on the little",
1226 "running Tux. If you like the changes you have made to your level,",
1227 "press the red save key to keep them.",
1228 "To change which level in your subset you are editing, press the white",
1229 "up and down arrow keys at the top of the button box.",
1231 "Have fun making levels! If you make some good ones, send them to us on",
1232 "the SuperTux mailing list!",
1237 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1239 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1240 text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1242 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1250 done = wait_for_event(event);