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"
40 /* definitions to aid development */
41 #define DONE_LEVELEDITOR 1
43 #define DONE_CHANGELEVEL 3
45 /* definitions that affect gameplay */
46 #define KEY_CURSOR_SPEED 32
47 #define KEY_CURSOR_FASTSPEED 64
49 /* when pagedown/up pressed speed:*/
50 #define PAGE_CURSOR_SPEED 13*32
52 #define MOUSE_LEFT_MARGIN 80
53 #define MOUSE_RIGHT_MARGIN (560-32)
54 /* right_margin should noticed that the cursor is 32 pixels,
55 so it should subtract that value */
56 #define MOUSE_POS_SPEED 20
59 #define SELECT_W 2 // size of the selections lines
60 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
62 /* gameloop funcs declerations */
64 void loadshared(void);
65 void unloadshared(void);
67 /* own declerations */
68 /* crutial ones (main loop) */
72 void le_drawinterface();
73 void le_checkevents();
74 void le_change(float x, float y, int tm, unsigned int c);
77 void le_set_defaults(void);
78 void le_activate_bad_guys(void);
80 void le_highlight_selection();
82 void apply_level_settings_menu();
83 void update_subset_settings_menu();
84 void save_subset_settings_menu();
86 /* leveleditor internals */
87 static string_list_type level_subsets;
88 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
89 static int pos_x, cursor_x, cursor_y, fire;
91 static Level* le_current_level;
92 static st_subset le_level_subset;
93 static int le_show_grid;
95 static texture_type le_selection;
97 static unsigned int le_current_tile;
98 static bool le_mouse_pressed[2];
99 static Button* le_save_level_bt;
100 static Button* le_exit_bt;
101 static Button* le_test_level_bt;
102 static Button* le_next_level_bt;
103 static Button* le_previous_level_bt;
104 static Button* le_move_right_bt;
105 static Button* le_move_left_bt;
106 static Button* le_rubber_bt;
107 static Button* le_select_mode_one_bt;
108 static Button* le_select_mode_two_bt;
109 static Button* le_settings_bt;
110 static Button* le_tilegroup_bt;
111 static ButtonPanel* le_tilemap_panel;
112 static Menu* leveleditor_menu;
113 static Menu* subset_load_menu;
114 static Menu* subset_new_menu;
115 static Menu* subset_settings_menu;
116 static Menu* level_settings_menu;
117 static Menu* select_tilegroup_menu;
118 static timer_type select_tilegroup_menu_effect;
119 static std::map<std::string, ButtonPanel* > tilegroups_map;
120 static std::string cur_tilegroup;
122 static square selection;
123 static int le_selection_mode;
124 static SDL_Event event;
125 TileMapType active_tm;
127 void le_set_defaults()
129 if(le_current_level != NULL)
133 if(le_current_level->time_left == 0)
134 le_current_level->time_left = 255;
138 int leveleditor(int levelnb)
140 int last_time, now_time, i;
148 clearscreen(0, 0, 0);
151 while (SDL_PollEvent(&event))
156 last_time = SDL_GetTicks();
161 if(current_menu == select_tilegroup_menu)
163 if(timer_check(&select_tilegroup_menu_effect))
165 select_tilegroup_menu->set_pos(screen->w - 64 + timer_get_left(&select_tilegroup_menu_effect),82,-0.5,0.5);
168 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
171 if(le_current_level != NULL)
173 /* making events results to be in order */
176 if(pos_x > (le_current_level->width * 32) - screen->w)
177 pos_x = (le_current_level->width * 32) - screen->w;
183 clearscreen(0, 0, 0);
185 /* draw editor interface */
190 menu_process_current();
191 if(current_menu == leveleditor_menu)
193 switch (leveleditor_menu->check())
199 update_subset_settings_menu();
202 done = DONE_LEVELEDITOR;
206 else if(current_menu == level_settings_menu)
208 switch (level_settings_menu->check())
211 apply_level_settings_menu();
212 Menu::set_current(leveleditor_menu);
219 else if(current_menu == select_tilegroup_menu)
222 switch (it = select_tilegroup_menu->check())
227 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
228 cur_tilegroup = select_tilegroup_menu->item[it].text;
235 else if(current_menu == subset_load_menu)
237 switch (i = subset_load_menu->check())
244 le_level_subset.load(level_subsets.item[i-2]);
245 leveleditor_menu->item[3].kind = MN_GOTO;
249 le_current_level = new Level;
250 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
256 le_current_level->load_gfx();
257 world.activate_bad_guys();
263 else if(current_menu == subset_new_menu)
265 if(subset_new_menu->item[2].input[0] == '\0')
266 subset_new_menu->item[3].kind = MN_DEACTIVE;
269 subset_new_menu->item[3].kind = MN_ACTION;
271 switch (i = subset_new_menu->check())
274 st_subset::create(subset_new_menu->item[2].input);
275 le_level_subset.load(subset_new_menu->item[2].input);
276 leveleditor_menu->item[3].kind = MN_GOTO;
280 le_current_level = new Level;
281 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
287 le_current_level->load_gfx();
288 world.activate_bad_guys();
289 menu_item_change_input(&subset_new_menu->item[2],"");
295 else if(current_menu == subset_settings_menu)
297 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 )
298 subset_settings_menu->item[5].kind = MN_DEACTIVE;
300 subset_settings_menu->item[5].kind = MN_ACTION;
302 switch (i = subset_settings_menu->check())
305 save_subset_settings_menu();
312 mouse_cursor->draw();
320 if(done == DONE_QUIT)
326 ++global_frame_counter;
329 now_time = SDL_GetTicks();
330 if (now_time < last_time + FPS)
331 SDL_Delay(last_time + FPS - now_time); /* delay some time */
342 level_subsets = dsubdirs("/levels", "info");
348 /* level_changed = NO;*/
351 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
352 le_level_changed = false;
353 le_current_level = NULL;
356 le_mouse_pressed[LEFT] = false;
357 le_mouse_pressed[RIGHT] = false;
359 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
361 timer_init(&select_tilegroup_menu_effect,false);
364 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
365 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
366 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
367 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
368 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
369 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
370 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
371 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
372 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
373 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
374 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
375 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
377 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
378 le_tilemap_panel->set_button_size(32,10);
379 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
380 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
381 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
383 leveleditor_menu = new Menu();
384 subset_load_menu = new Menu();
385 subset_new_menu = new Menu();
386 subset_settings_menu = new Menu();
387 level_settings_menu = new Menu();
388 select_tilegroup_menu = new Menu();
390 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
391 leveleditor_menu->additem(MN_HL,"",0,0);
392 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
393 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
394 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
395 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
396 leveleditor_menu->additem(MN_HL,"",0,0);
397 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
400 Menu::set_current(leveleditor_menu);
403 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
404 subset_load_menu->additem(MN_HL, "", 0, 0);
406 for(i = 0; i < level_subsets.num_items; ++i)
408 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
410 subset_load_menu->additem(MN_HL,"",0,0);
411 subset_load_menu->additem(MN_BACK,"Back",0,0);
413 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
414 subset_new_menu->additem(MN_HL,"",0,0);
415 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
416 subset_new_menu->additem(MN_ACTION,"Create",0,0);
417 subset_new_menu->additem(MN_HL,"",0,0);
418 subset_new_menu->additem(MN_BACK,"Back",0,0);
420 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
421 subset_settings_menu->additem(MN_HL,"",0,0);
422 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
423 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
424 subset_settings_menu->additem(MN_HL,"",0,0);
425 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
426 subset_settings_menu->additem(MN_HL,"",0,0);
427 subset_settings_menu->additem(MN_BACK,"Back",0,0);
429 level_settings_menu->arrange_left = true;
430 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
431 level_settings_menu->additem(MN_HL,"",0,0);
432 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
433 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
434 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
435 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
436 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
437 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
438 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
439 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
440 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
441 level_settings_menu->additem(MN_NUMFIELD,"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 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
471 sprintf(str,"%d",le_current_level->width);
473 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
474 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
475 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
476 string_list_add_item(level_settings_menu->item[5].list,"");
477 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
478 level_settings_menu->item[3].list->active_item = i;
479 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
480 level_settings_menu->item[4].list->active_item = i;
481 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
482 level_settings_menu->item[5].list->active_item = i;
484 menu_item_change_input(&level_settings_menu->item[6], str);
485 sprintf(str,"%d",le_current_level->time_left);
486 menu_item_change_input(&level_settings_menu->item[7], str);
487 sprintf(str,"%2.0f",le_current_level->gravity);
488 menu_item_change_input(&level_settings_menu->item[8], str);
489 sprintf(str,"%d",le_current_level->bkgd_red);
490 menu_item_change_input(&level_settings_menu->item[9], str);
491 sprintf(str,"%d",le_current_level->bkgd_green);
492 menu_item_change_input(&level_settings_menu->item[10], str);
493 sprintf(str,"%d",le_current_level->bkgd_blue);
494 menu_item_change_input(&level_settings_menu->item[11], str);
497 void update_subset_settings_menu()
499 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
500 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
503 void apply_level_settings_menu()
508 le_current_level->name = level_settings_menu->item[2].input;
510 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
512 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
516 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
518 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
524 le_current_level->free_gfx();
525 le_current_level->load_gfx();
528 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
530 le_current_level->change_size(atoi(level_settings_menu->item[6].input));
531 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
532 le_current_level->gravity = atof(level_settings_menu->item[8].input);
533 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
534 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
535 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
538 void save_subset_settings_menu()
540 le_level_subset.title = subset_settings_menu->item[2].input;
541 le_level_subset.description = subset_settings_menu->item[3].input;
542 le_level_subset.save();
545 void le_goto_level(int levelnb)
549 le_current_level->cleanup();
550 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
552 le_current_level->load(le_level_subset.name.c_str(), le_level);
561 le_current_level->free_gfx();
562 le_current_level->load_gfx();
564 world.activate_bad_guys();
569 /*if(level_changed == true)
570 if(askforsaving() == CANCEL)
573 SDL_EnableKeyRepeat(0, 0); // disables key repeating
575 texture_free(&le_selection);
576 delete leveleditor_menu;
577 delete subset_load_menu;
578 delete subset_new_menu;
579 delete subset_settings_menu;
580 delete level_settings_menu;
581 delete select_tilegroup_menu;
582 delete le_save_level_bt;
584 delete le_test_level_bt;
585 delete le_next_level_bt;
586 delete le_previous_level_bt;
587 delete le_move_right_bt;
588 delete le_move_left_bt;
590 delete le_select_mode_one_bt;
591 delete le_select_mode_two_bt;
592 delete le_settings_bt;
593 delete le_tilegroup_bt;
594 delete le_tilemap_panel;
596 if(le_current_level != NULL)
598 le_current_level->free_gfx();
599 le_current_level->cleanup();
605 void le_drawinterface()
610 if(le_current_level != NULL)
612 /* draw a grid (if selected) */
615 for(x = 0; x < 19; x++)
616 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
617 for(y = 0; y < 15; y++)
618 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
622 if(le_selection_mode == CURSOR)
623 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
624 else if(le_selection_mode == SQUARE)
627 le_highlight_selection();
628 /* draw current selection */
629 w = selection.x2 - selection.x1;
630 h = selection.y2 - selection.y1;
631 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
632 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
633 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
634 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
638 /* draw button bar */
639 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
640 Tile::draw(19 * 32, 14 * 32, le_current_tile);
642 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
643 texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
645 if(le_current_level != NULL)
647 le_save_level_bt->draw();
649 le_test_level_bt->draw();
650 le_next_level_bt->draw();
651 le_previous_level_bt->draw();
652 le_rubber_bt->draw();
653 le_select_mode_one_bt->draw();
654 le_select_mode_two_bt->draw();
655 le_settings_bt->draw();
656 le_move_right_bt->draw();
657 le_move_left_bt->draw();
658 le_tilegroup_bt->draw();
659 if(!cur_tilegroup.empty())
660 tilegroups_map[cur_tilegroup]->draw();
661 le_tilemap_panel->draw();
663 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
664 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
666 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
670 if(show_menu == false)
671 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
673 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
680 unsigned int y,x,i,s;
683 /* Draw the real background */
684 if(le_current_level->bkgd_image[0] != '\0')
687 texture_draw_part(&le_current_level->img_bkgd,s,0,0,0,
688 le_current_level->img_bkgd.w - s - 32, le_current_level->img_bkgd.h);
689 texture_draw_part(&le_current_level->img_bkgd,0,0,screen->w - s - 32 ,0,s,
690 le_current_level->img_bkgd.h);
694 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
697 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
699 for (y = 0; y < 15; ++y)
700 for (x = 0; x < 20; ++x)
703 if(active_tm == TM_BG)
708 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
710 if(active_tm == TM_IA)
715 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
717 if(active_tm == TM_FG)
722 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
724 /* draw whats inside stuff when cursor is selecting those */
725 /* (draw them all the time - is this the right behaviour?) */
726 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
727 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);
731 /* Draw the Bad guys: */
732 for (i = 0; i < world.bad_guys.size(); ++i)
734 /* to support frames: img_bsod_left[(frame / 5) % 4] */
737 world.bad_guys[i].draw();
741 /* Draw the player: */
742 /* for now, the position is fixed at (100, 240) */
743 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
746 void le_checkevents()
753 keymod = SDL_GetModState();
755 while(SDL_PollEvent(&event))
760 mouse_cursor->set_state(MC_NORMAL);
762 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
763 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
764 event.motion.y > 0 && event.motion.y < screen->h)))
768 case SDL_KEYDOWN: // key pressed
769 key = event.key.keysym.sym;
772 if(key == SDLK_ESCAPE)
775 Menu::set_current(leveleditor_menu);
789 cursor_x -= KEY_CURSOR_SPEED;
791 cursor_x -= KEY_CURSOR_FASTSPEED;
793 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
794 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
799 cursor_x += KEY_CURSOR_SPEED;
801 cursor_x += KEY_CURSOR_FASTSPEED;
803 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
804 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
809 cursor_y -= KEY_CURSOR_SPEED;
811 cursor_y -= KEY_CURSOR_FASTSPEED;
818 cursor_y += KEY_CURSOR_SPEED;
820 cursor_y += KEY_CURSOR_FASTSPEED;
822 if(cursor_y > screen->h-32)
823 cursor_y = screen->h-32;
836 cursor_x = (le_current_level->width * 32) - 32;
840 le_show_grid = !le_show_grid;
846 case SDL_KEYUP: /* key released */
847 switch(event.key.keysym.sym)
856 case SDL_MOUSEBUTTONDOWN:
857 if(event.button.button == SDL_BUTTON_LEFT)
859 le_mouse_pressed[LEFT] = true;
861 selection.x1 = event.motion.x + pos_x;
862 selection.y1 = event.motion.y;
863 selection.x2 = event.motion.x + pos_x;
864 selection.y2 = event.motion.y;
866 else if(event.button.button == SDL_BUTTON_RIGHT)
868 le_mouse_pressed[RIGHT] = true;
871 case SDL_MOUSEBUTTONUP:
872 if(event.button.button == SDL_BUTTON_LEFT)
873 le_mouse_pressed[LEFT] = false;
874 else if(event.button.button == SDL_BUTTON_RIGHT)
875 le_mouse_pressed[RIGHT] = false;
877 case SDL_MOUSEMOTION:
883 cursor_x = ((int)(pos_x + x) / 32) * 32;
884 cursor_y = ((int) y / 32) * 32;
886 if(le_mouse_pressed[LEFT])
888 selection.x2 = x + pos_x;
892 if(le_mouse_pressed[RIGHT])
894 pos_x += -1 * event.motion.xrel;
898 case SDL_QUIT: // window closed
906 if(le_current_level != NULL)
908 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 &&
909 event.motion.y > 0 && event.motion.y < screen->h)))
911 le_mouse_pressed[LEFT] = false;
912 le_mouse_pressed[RIGHT] = false;
914 if(show_menu == false)
916 /* Check for button events */
917 le_test_level_bt->event(event);
918 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
920 le_save_level_bt->event(event);
921 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
922 le_current_level->save(le_level_subset.name.c_str(),le_level);
923 le_exit_bt->event(event);
924 if(le_exit_bt->get_state() == BUTTON_CLICKED)
926 Menu::set_current(leveleditor_menu);
929 le_next_level_bt->event(event);
930 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
932 if(le_level < le_level_subset.levels)
934 le_goto_level(++le_level);
941 sprintf(str,"Level %d doesn't exist.",le_level+1);
942 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
943 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
944 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
948 while(SDL_PollEvent(&event))
951 case SDL_KEYDOWN: // key pressed
952 switch(event.key.keysym.sym)
955 new_lev.init_defaults();
956 new_lev.save(le_level_subset.name.c_str(),++le_level);
957 le_level_subset.levels = le_level;
958 le_goto_level(le_level);
975 le_previous_level_bt->event(event);
976 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
979 le_goto_level(--le_level);
981 le_rubber_bt->event(event);
982 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
984 le_select_mode_one_bt->event(event);
985 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
986 le_selection_mode = CURSOR;
987 le_select_mode_two_bt->event(event);
988 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
989 le_selection_mode = SQUARE;
991 le_tilegroup_bt->event(event);
992 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
994 Menu::set_current(select_tilegroup_menu);
995 timer_start(&select_tilegroup_menu_effect,200);
996 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1000 le_settings_bt->event(event);
1001 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1003 update_level_settings_menu();
1004 Menu::set_current(level_settings_menu);
1007 if(!cur_tilegroup.empty())
1008 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1010 if(pbutton->get_state() == BUTTON_CLICKED)
1012 le_current_tile = pbutton->get_tag();
1015 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1017 if(pbutton->get_state() == BUTTON_CLICKED)
1019 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1025 le_settings_bt->event(event);
1026 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1028 Menu::set_current(leveleditor_menu);
1031 le_tilegroup_bt->event(event);
1032 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1034 Menu::set_current(leveleditor_menu);
1039 if(show_menu == false)
1041 le_move_left_bt->event(event);
1042 le_move_right_bt->event(event);
1044 if(le_mouse_pressed[LEFT])
1046 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1051 if(show_menu == false)
1053 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1057 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1062 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1066 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1074 void le_highlight_selection()
1078 if(selection.x1 < selection.x2)
1088 if(selection.y1 < selection.y2)
1104 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1107 void le_change(float x, float y, int tm, unsigned int c)
1109 if(le_current_level != NULL)
1115 /* level_changed = true; */
1117 switch(le_selection_mode)
1120 le_current_level->change(x,y,tm,c);
1125 /* if there is a bad guy over there, remove it */
1126 for(i = 0; i < world.bad_guys.size(); ++i)
1127 if(xx == world.bad_guys[i].base.x/32 && yy == world.bad_guys[i].base.y/32)
1128 world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&world.bad_guys[i]));
1130 if(c == '0') /* if it's a bad guy */
1131 world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1133 world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1135 world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1139 if(selection.x1 < selection.x2)
1149 if(selection.y1 < selection.y2)
1165 /* if there is a bad guy over there, remove it */
1166 for(i = 0; i < world.bad_guys.size(); ++i)
1167 if(world.bad_guys[i].base.x/32 >= x1 && world.bad_guys[i].base.x/32 <= x2
1168 && world.bad_guys[i].base.y/32 >= y1 && world.bad_guys[i].base.y/32 <= y2)
1169 world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&world.bad_guys[i]));
1171 for(xx = x1; xx <= x2; xx++)
1172 for(yy = y1; yy <= y2; yy++)
1174 le_current_level->change(xx*32, yy*32, tm, c);
1176 if(c == '0') // if it's a bad guy
1177 world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1179 world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1181 world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1192 le_current_level->save("test", le_level);
1194 GameSession session("test",le_level, ST_GL_TEST);
1197 Menu::set_current(leveleditor_menu);
1198 world.arrays_free();
1199 le_current_level->load_gfx();
1201 world.activate_bad_guys();
1207 unsigned int i, done;
1209 " - This is SuperTux's built-in level editor -",
1210 "It has been designed to be light and easy to use from the start.",
1212 "When you first load the level editor you are given a menu where you",
1213 "can load level subsets, create a new level subset, edit the current",
1214 "subset's settings, or simply quit the editor. You can access this menu",
1215 "from the level editor at any time by pressing the escape key.",
1217 "To your right is your button bar. The center of this contains many",
1218 "tiles you can use to make your level. To select a tile, click on it",
1219 "with your left mouse button; your selection will be shown in the",
1220 "bottom right corner of the button box. Click anywhere on your level",
1221 "with the left mouse button to place that tile down. If you right click",
1222 "a tile in the button bar, you can find out what its keyboard shortcut",
1223 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1224 "background, and enemy tiles. The eraser lets you remove tiles.",
1225 "The left and right arrow keys scroll back and forth through your level.",
1226 "The button with the wrench and screwdriver, lets you change the",
1227 "settings of your level, including how long it is or what music it will",
1228 "play. When you are ready to give your level a test, click on the little",
1229 "running Tux. If you like the changes you have made to your level,",
1230 "press the red save key to keep them.",
1231 "To change which level in your subset you are editing, press the white",
1232 "up and down arrow keys at the top of the button box.",
1234 "Have fun making levels! If you make some good ones, send them to us on",
1235 "the SuperTux mailing list!",
1240 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1242 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1243 text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1245 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1253 done = wait_for_event(event);