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();
245 le_current_level = new Level;
246 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
252 le_current_level->load_gfx();
253 global_world.activate_bad_guys();
259 else if(current_menu == subset_new_menu)
261 if(subset_new_menu->item[2].input[0] == '\0')
262 subset_new_menu->item[3].kind = MN_DEACTIVE;
265 subset_new_menu->item[3].kind = MN_ACTION;
267 switch (i = subset_new_menu->check())
270 st_subset::create(subset_new_menu->item[2].input);
271 le_level_subset.load(subset_new_menu->item[2].input);
272 leveleditor_menu->item[3].kind = MN_GOTO;
274 global_world.arrays_free();
275 le_current_level = new Level;
276 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
282 le_current_level->load_gfx();
283 global_world.activate_bad_guys();
284 menu_item_change_input(&subset_new_menu->item[2],"");
290 else if(current_menu == subset_settings_menu)
292 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 )
293 subset_settings_menu->item[5].kind = MN_DEACTIVE;
295 subset_settings_menu->item[5].kind = MN_ACTION;
297 switch (i = subset_settings_menu->check())
300 save_subset_settings_menu();
307 mouse_cursor->draw();
315 if(done == DONE_QUIT)
321 ++global_frame_counter;
324 now_time = SDL_GetTicks();
325 if (now_time < last_time + FPS)
326 SDL_Delay(last_time + FPS - now_time); /* delay some time */
337 level_subsets = dsubdirs("/levels", "info");
343 /* level_changed = NO;*/
346 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
347 le_level_changed = false;
348 le_current_level = NULL;
351 le_mouse_pressed[LEFT] = false;
352 le_mouse_pressed[RIGHT] = false;
354 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
356 select_tilegroup_menu_effect.init(false);
359 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
360 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
361 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
362 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
363 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
364 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
365 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
366 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
367 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
368 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
369 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
370 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
372 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
373 le_tilemap_panel->set_button_size(32,10);
374 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
375 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
376 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
378 leveleditor_menu = new Menu();
379 subset_load_menu = new Menu();
380 subset_new_menu = new Menu();
381 subset_settings_menu = new Menu();
382 level_settings_menu = new Menu();
383 select_tilegroup_menu = new Menu();
385 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
386 leveleditor_menu->additem(MN_HL,"",0,0);
387 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
388 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
389 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
390 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
391 leveleditor_menu->additem(MN_HL,"",0,0);
392 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
395 Menu::set_current(leveleditor_menu);
398 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
399 subset_load_menu->additem(MN_HL, "", 0, 0);
401 for(i = 0; i < level_subsets.num_items; ++i)
403 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
405 subset_load_menu->additem(MN_HL,"",0,0);
406 subset_load_menu->additem(MN_BACK,"Back",0,0);
408 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
409 subset_new_menu->additem(MN_HL,"",0,0);
410 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
411 subset_new_menu->additem(MN_ACTION,"Create",0,0);
412 subset_new_menu->additem(MN_HL,"",0,0);
413 subset_new_menu->additem(MN_BACK,"Back",0,0);
415 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
416 subset_settings_menu->additem(MN_HL,"",0,0);
417 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
418 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
419 subset_settings_menu->additem(MN_HL,"",0,0);
420 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
421 subset_settings_menu->additem(MN_HL,"",0,0);
422 subset_settings_menu->additem(MN_BACK,"Back",0,0);
424 level_settings_menu->arrange_left = true;
425 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
426 level_settings_menu->additem(MN_HL,"",0,0);
427 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
428 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
429 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
430 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
431 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
432 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
433 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
434 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
435 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
436 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
437 level_settings_menu->additem(MN_HL,"",0,0);
438 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
440 select_tilegroup_menu->arrange_left = true;
441 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
442 select_tilegroup_menu->additem(MN_HL,"",0,0);
443 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
444 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
447 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
448 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
450 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
451 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));
453 select_tilegroup_menu->additem(MN_HL,"",0,0);
455 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
460 void update_level_settings_menu()
465 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
466 sprintf(str,"%d",le_current_level->width);
468 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
469 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
470 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
471 string_list_add_item(level_settings_menu->item[5].list,"");
472 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
473 level_settings_menu->item[3].list->active_item = i;
474 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
475 level_settings_menu->item[4].list->active_item = i;
476 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
477 level_settings_menu->item[5].list->active_item = i;
479 menu_item_change_input(&level_settings_menu->item[6], str);
480 sprintf(str,"%d",le_current_level->time_left);
481 menu_item_change_input(&level_settings_menu->item[7], str);
482 sprintf(str,"%2.0f",le_current_level->gravity);
483 menu_item_change_input(&level_settings_menu->item[8], str);
484 sprintf(str,"%d",le_current_level->bkgd_red);
485 menu_item_change_input(&level_settings_menu->item[9], str);
486 sprintf(str,"%d",le_current_level->bkgd_green);
487 menu_item_change_input(&level_settings_menu->item[10], str);
488 sprintf(str,"%d",le_current_level->bkgd_blue);
489 menu_item_change_input(&level_settings_menu->item[11], str);
492 void update_subset_settings_menu()
494 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
495 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
498 void apply_level_settings_menu()
503 le_current_level->name = level_settings_menu->item[2].input;
505 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
507 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
511 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
513 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
519 le_current_level->free_gfx();
520 le_current_level->load_gfx();
523 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
525 le_current_level->change_size(atoi(level_settings_menu->item[6].input));
526 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
527 le_current_level->gravity = atof(level_settings_menu->item[8].input);
528 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
529 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
530 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
533 void save_subset_settings_menu()
535 le_level_subset.title = subset_settings_menu->item[2].input;
536 le_level_subset.description = subset_settings_menu->item[3].input;
537 le_level_subset.save();
540 void le_goto_level(int levelnb)
542 global_world.arrays_free();
544 le_current_level->cleanup();
545 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
547 le_current_level->load(le_level_subset.name.c_str(), le_level);
556 le_current_level->free_gfx();
557 le_current_level->load_gfx();
559 global_world.activate_bad_guys();
564 /*if(level_changed == true)
565 if(askforsaving() == CANCEL)
568 SDL_EnableKeyRepeat(0, 0); // disables key repeating
570 texture_free(&le_selection);
571 delete leveleditor_menu;
572 delete subset_load_menu;
573 delete subset_new_menu;
574 delete subset_settings_menu;
575 delete level_settings_menu;
576 delete select_tilegroup_menu;
577 delete le_save_level_bt;
579 delete le_test_level_bt;
580 delete le_next_level_bt;
581 delete le_previous_level_bt;
582 delete le_move_right_bt;
583 delete le_move_left_bt;
585 delete le_select_mode_one_bt;
586 delete le_select_mode_two_bt;
587 delete le_settings_bt;
588 delete le_tilegroup_bt;
589 delete le_tilemap_panel;
591 if(le_current_level != NULL)
593 le_current_level->free_gfx();
594 le_current_level->cleanup();
595 global_world.arrays_free();
599 void le_drawinterface()
604 if(le_current_level != NULL)
606 /* draw a grid (if selected) */
609 for(x = 0; x < 19; x++)
610 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
611 for(y = 0; y < 15; y++)
612 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
616 if(le_selection_mode == CURSOR)
617 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
618 else if(le_selection_mode == SQUARE)
621 le_highlight_selection();
622 /* draw current selection */
623 w = selection.x2 - selection.x1;
624 h = selection.y2 - selection.y1;
625 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
626 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
627 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
628 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
632 /* draw button bar */
633 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
634 Tile::draw(19 * 32, 14 * 32, le_current_tile);
636 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
637 texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
639 if(le_current_level != NULL)
641 le_save_level_bt->draw();
643 le_test_level_bt->draw();
644 le_next_level_bt->draw();
645 le_previous_level_bt->draw();
646 le_rubber_bt->draw();
647 le_select_mode_one_bt->draw();
648 le_select_mode_two_bt->draw();
649 le_settings_bt->draw();
650 le_move_right_bt->draw();
651 le_move_left_bt->draw();
652 le_tilegroup_bt->draw();
653 if(!cur_tilegroup.empty())
654 tilegroups_map[cur_tilegroup]->draw();
655 le_tilemap_panel->draw();
657 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
658 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
660 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
664 if(show_menu == false)
665 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
667 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
674 unsigned int y,x,i,s;
677 /* Draw the real background */
678 if(le_current_level->bkgd_image[0] != '\0')
681 texture_draw_part(&le_current_level->img_bkgd,s,0,0,0,
682 le_current_level->img_bkgd.w - s - 32, le_current_level->img_bkgd.h);
683 texture_draw_part(&le_current_level->img_bkgd,0,0,screen->w - s - 32 ,0,s,
684 le_current_level->img_bkgd.h);
688 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
691 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
693 for (y = 0; y < 15; ++y)
694 for (x = 0; x < 20; ++x)
697 if(active_tm == TM_BG)
702 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
704 if(active_tm == TM_IA)
709 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
711 if(active_tm == TM_FG)
716 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
718 /* draw whats inside stuff when cursor is selecting those */
719 /* (draw them all the time - is this the right behaviour?) */
720 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
721 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);
725 /* Draw the Bad guys: */
726 for (i = 0; i < global_world.bad_guys.size(); ++i)
728 /* to support frames: img_bsod_left[(frame / 5) % 4] */
731 global_world.bad_guys[i].draw();
735 /* Draw the player: */
736 /* for now, the position is fixed at (100, 240) */
737 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
740 void le_checkevents()
747 keymod = SDL_GetModState();
749 while(SDL_PollEvent(&event))
754 mouse_cursor->set_state(MC_NORMAL);
756 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
757 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
758 event.motion.y > 0 && event.motion.y < screen->h)))
762 case SDL_KEYDOWN: // key pressed
763 key = event.key.keysym.sym;
766 if(key == SDLK_ESCAPE)
769 Menu::set_current(leveleditor_menu);
783 cursor_x -= KEY_CURSOR_SPEED;
785 cursor_x -= KEY_CURSOR_FASTSPEED;
787 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
788 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
793 cursor_x += KEY_CURSOR_SPEED;
795 cursor_x += KEY_CURSOR_FASTSPEED;
797 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
798 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
803 cursor_y -= KEY_CURSOR_SPEED;
805 cursor_y -= KEY_CURSOR_FASTSPEED;
812 cursor_y += KEY_CURSOR_SPEED;
814 cursor_y += KEY_CURSOR_FASTSPEED;
816 if(cursor_y > screen->h-32)
817 cursor_y = screen->h-32;
830 cursor_x = (le_current_level->width * 32) - 32;
834 le_show_grid = !le_show_grid;
840 case SDL_KEYUP: /* key released */
841 switch(event.key.keysym.sym)
850 case SDL_MOUSEBUTTONDOWN:
851 if(event.button.button == SDL_BUTTON_LEFT)
853 le_mouse_pressed[LEFT] = true;
855 selection.x1 = event.motion.x + pos_x;
856 selection.y1 = event.motion.y;
857 selection.x2 = event.motion.x + pos_x;
858 selection.y2 = event.motion.y;
860 else if(event.button.button == SDL_BUTTON_RIGHT)
862 le_mouse_pressed[RIGHT] = true;
865 case SDL_MOUSEBUTTONUP:
866 if(event.button.button == SDL_BUTTON_LEFT)
867 le_mouse_pressed[LEFT] = false;
868 else if(event.button.button == SDL_BUTTON_RIGHT)
869 le_mouse_pressed[RIGHT] = false;
871 case SDL_MOUSEMOTION:
877 cursor_x = ((int)(pos_x + x) / 32) * 32;
878 cursor_y = ((int) y / 32) * 32;
880 if(le_mouse_pressed[LEFT])
882 selection.x2 = x + pos_x;
886 if(le_mouse_pressed[RIGHT])
888 pos_x += -1 * event.motion.xrel;
892 case SDL_QUIT: // window closed
900 if(le_current_level != NULL)
902 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 &&
903 event.motion.y > 0 && event.motion.y < screen->h)))
905 le_mouse_pressed[LEFT] = false;
906 le_mouse_pressed[RIGHT] = false;
908 if(show_menu == false)
910 /* Check for button events */
911 le_test_level_bt->event(event);
912 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
914 le_save_level_bt->event(event);
915 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
916 le_current_level->save(le_level_subset.name.c_str(),le_level);
917 le_exit_bt->event(event);
918 if(le_exit_bt->get_state() == BUTTON_CLICKED)
920 Menu::set_current(leveleditor_menu);
923 le_next_level_bt->event(event);
924 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
926 if(le_level < le_level_subset.levels)
928 le_goto_level(++le_level);
935 sprintf(str,"Level %d doesn't exist.",le_level+1);
936 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
937 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
938 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
942 while(SDL_PollEvent(&event))
945 case SDL_KEYDOWN: // key pressed
946 switch(event.key.keysym.sym)
949 new_lev.init_defaults();
950 new_lev.save(le_level_subset.name.c_str(),++le_level);
951 le_level_subset.levels = le_level;
952 le_goto_level(le_level);
969 le_previous_level_bt->event(event);
970 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
973 le_goto_level(--le_level);
975 le_rubber_bt->event(event);
976 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
978 le_select_mode_one_bt->event(event);
979 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
980 le_selection_mode = CURSOR;
981 le_select_mode_two_bt->event(event);
982 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
983 le_selection_mode = SQUARE;
985 le_tilegroup_bt->event(event);
986 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
988 Menu::set_current(select_tilegroup_menu);
989 select_tilegroup_menu_effect.start(200);
990 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
994 le_settings_bt->event(event);
995 if(le_settings_bt->get_state() == BUTTON_CLICKED)
997 update_level_settings_menu();
998 Menu::set_current(level_settings_menu);
1001 if(!cur_tilegroup.empty())
1002 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1004 if(pbutton->get_state() == BUTTON_CLICKED)
1006 le_current_tile = pbutton->get_tag();
1009 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1011 if(pbutton->get_state() == BUTTON_CLICKED)
1013 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1019 le_settings_bt->event(event);
1020 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1022 Menu::set_current(leveleditor_menu);
1025 le_tilegroup_bt->event(event);
1026 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1028 Menu::set_current(leveleditor_menu);
1033 if(show_menu == false)
1035 le_move_left_bt->event(event);
1036 le_move_right_bt->event(event);
1038 if(le_mouse_pressed[LEFT])
1040 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1045 if(show_menu == false)
1047 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1051 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1056 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1060 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1068 void le_highlight_selection()
1072 if(selection.x1 < selection.x2)
1082 if(selection.y1 < selection.y2)
1098 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1101 void le_change(float x, float y, int tm, unsigned int c)
1103 if(le_current_level != NULL)
1109 /* level_changed = true; */
1111 switch(le_selection_mode)
1114 le_current_level->change(x,y,tm,c);
1119 /* if there is a bad guy over there, remove it */
1120 for(i = 0; i < global_world.bad_guys.size(); ++i)
1121 if(xx == global_world.bad_guys[i].base.x/32 && yy == global_world.bad_guys[i].base.y/32)
1122 global_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&global_world.bad_guys[i]));
1124 if(c == '0') /* if it's a bad guy */
1125 global_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1127 global_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1129 global_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1133 if(selection.x1 < selection.x2)
1143 if(selection.y1 < selection.y2)
1159 /* if there is a bad guy over there, remove it */
1160 for(i = 0; i < global_world.bad_guys.size(); ++i)
1161 if(global_world.bad_guys[i].base.x/32 >= x1 && global_world.bad_guys[i].base.x/32 <= x2
1162 && global_world.bad_guys[i].base.y/32 >= y1 && global_world.bad_guys[i].base.y/32 <= y2)
1163 global_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&global_world.bad_guys[i]));
1165 for(xx = x1; xx <= x2; xx++)
1166 for(yy = y1; yy <= y2; yy++)
1168 le_current_level->change(xx*32, yy*32, tm, c);
1170 if(c == '0') // if it's a bad guy
1171 global_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1173 global_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1175 global_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1186 le_current_level->save("test", le_level);
1188 GameSession session("test",le_level, ST_GL_TEST);
1191 Menu::set_current(leveleditor_menu);
1192 global_world.arrays_free();
1193 le_current_level->load_gfx();
1194 global_world.activate_bad_guys();
1200 unsigned int i, done;
1202 " - This is SuperTux's built-in level editor -",
1203 "It has been designed to be light and easy to use from the start.",
1205 "When you first load the level editor you are given a menu where you",
1206 "can load level subsets, create a new level subset, edit the current",
1207 "subset's settings, or simply quit the editor. You can access this menu",
1208 "from the level editor at any time by pressing the escape key.",
1210 "To your right is your button bar. The center of this contains many",
1211 "tiles you can use to make your level. To select a tile, click on it",
1212 "with your left mouse button; your selection will be shown in the",
1213 "bottom right corner of the button box. Click anywhere on your level",
1214 "with the left mouse button to place that tile down. If you right click",
1215 "a tile in the button bar, you can find out what its keyboard shortcut",
1216 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1217 "background, and enemy tiles. The eraser lets you remove tiles.",
1218 "The left and right arrow keys scroll back and forth through your level.",
1219 "The button with the wrench and screwdriver, lets you change the",
1220 "settings of your level, including how long it is or what music it will",
1221 "play. When you are ready to give your level a test, click on the little",
1222 "running Tux. If you like the changes you have made to your level,",
1223 "press the red save key to keep them.",
1224 "To change which level in your subset you are editing, press the white",
1225 "up and down arrow keys at the top of the button box.",
1227 "Have fun making levels! If you make some good ones, send them to us on",
1228 "the SuperTux mailing list!",
1233 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1235 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1236 text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1238 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1246 done = wait_for_event(event);