1 /***************************************************************************
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
8 ***************************************************************************/
10 /* December 28, 2003 - March 15, 2004 */
12 /* leveleditor.c - A built-in level editor for SuperTux
13 Ricardo Cruz <rick2@aeiou.pt>
14 Tobias Glaesser <tobi.web@gmx.de> */
24 #include <SDL_image.h>
25 #include "leveleditor.h"
39 #include "resources.h"
41 /* definitions to aid development */
42 #define DONE_LEVELEDITOR 1
44 #define DONE_CHANGELEVEL 3
46 /* definitions that affect gameplay */
47 #define KEY_CURSOR_SPEED 32
48 #define KEY_CURSOR_FASTSPEED 64
50 /* when pagedown/up pressed speed:*/
51 #define PAGE_CURSOR_SPEED 13*32
53 #define MOUSE_LEFT_MARGIN 80
54 #define MOUSE_RIGHT_MARGIN (560-32)
55 /* right_margin should noticed that the cursor is 32 pixels,
56 so it should subtract that value */
57 #define MOUSE_POS_SPEED 20
60 #define SELECT_W 2 // size of the selections lines
61 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
63 /* own declerations */
64 /* crutial ones (main loop) */
68 void le_drawinterface();
69 void le_checkevents();
70 void le_change(float x, float y, int tm, unsigned int c);
73 void le_set_defaults(void);
74 void le_activate_bad_guys(void);
76 void le_highlight_selection();
78 void apply_level_settings_menu();
79 void update_subset_settings_menu();
80 void save_subset_settings_menu();
82 /* leveleditor internals */
83 static string_list_type level_subsets;
84 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
85 static int pos_x, cursor_x, cursor_y, fire;
87 static Level* le_current_level;
88 static World le_world;
89 static st_subset le_level_subset;
90 static int le_show_grid;
92 static texture_type le_selection;
94 static unsigned int le_current_tile;
95 static bool le_mouse_pressed[2];
96 static Button* le_save_level_bt;
97 static Button* le_exit_bt;
98 static Button* le_test_level_bt;
99 static Button* le_next_level_bt;
100 static Button* le_previous_level_bt;
101 static Button* le_move_right_bt;
102 static Button* le_move_left_bt;
103 static Button* le_rubber_bt;
104 static Button* le_select_mode_one_bt;
105 static Button* le_select_mode_two_bt;
106 static Button* le_settings_bt;
107 static Button* le_tilegroup_bt;
108 static ButtonPanel* le_tilemap_panel;
109 static Menu* leveleditor_menu;
110 static Menu* subset_load_menu;
111 static Menu* subset_new_menu;
112 static Menu* subset_settings_menu;
113 static Menu* level_settings_menu;
114 static Menu* select_tilegroup_menu;
115 static Timer select_tilegroup_menu_effect;
116 static std::map<std::string, ButtonPanel* > tilegroups_map;
117 static std::string cur_tilegroup;
119 static square selection;
120 static int le_selection_mode;
121 static SDL_Event event;
122 TileMapType active_tm;
124 void le_set_defaults()
126 if(le_current_level != NULL)
130 if(le_current_level->time_left == 0)
131 le_current_level->time_left = 255;
135 int leveleditor(int levelnb)
137 int last_time, now_time, i;
145 clearscreen(0, 0, 0);
148 while (SDL_PollEvent(&event))
153 last_time = SDL_GetTicks();
158 if(current_menu == select_tilegroup_menu)
160 if(select_tilegroup_menu_effect.check())
162 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
166 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
169 if(le_current_level != NULL)
171 /* making events results to be in order */
174 if(pos_x > (le_current_level->width * 32) - screen->w)
175 pos_x = (le_current_level->width * 32) - screen->w;
181 clearscreen(0, 0, 0);
183 /* draw editor interface */
188 menu_process_current();
189 if(current_menu == leveleditor_menu)
191 switch (leveleditor_menu->check())
197 update_subset_settings_menu();
200 done = DONE_LEVELEDITOR;
204 else if(current_menu == level_settings_menu)
206 switch (level_settings_menu->check())
209 apply_level_settings_menu();
210 Menu::set_current(leveleditor_menu);
217 else if(current_menu == select_tilegroup_menu)
220 switch (it = select_tilegroup_menu->check())
225 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
226 cur_tilegroup = select_tilegroup_menu->item[it].text;
233 else if(current_menu == subset_load_menu)
235 switch (i = subset_load_menu->check())
242 le_level_subset.load(level_subsets.item[i-2]);
243 leveleditor_menu->item[3].kind = MN_GOTO;
245 le_world.arrays_free();
246 le_current_level = new Level;
247 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
253 le_current_level->load_gfx();
254 le_world.activate_bad_guys();
260 else if(current_menu == subset_new_menu)
262 if(subset_new_menu->item[2].input[0] == '\0')
263 subset_new_menu->item[3].kind = MN_DEACTIVE;
266 subset_new_menu->item[3].kind = MN_ACTION;
268 switch (i = subset_new_menu->check())
271 st_subset::create(subset_new_menu->item[2].input);
272 le_level_subset.load(subset_new_menu->item[2].input);
273 leveleditor_menu->item[3].kind = MN_GOTO;
275 le_world.arrays_free();
276 le_current_level = new Level;
277 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
283 le_current_level->load_gfx();
284 le_world.activate_bad_guys();
285 menu_item_change_input(&subset_new_menu->item[2],"");
291 else if(current_menu == subset_settings_menu)
293 if(le_level_subset.title.compare(subset_settings_menu->item[2].input) == 0 && le_level_subset.description.compare(subset_settings_menu->item[3].input) == 0 )
294 subset_settings_menu->item[5].kind = MN_DEACTIVE;
296 subset_settings_menu->item[5].kind = MN_ACTION;
298 switch (i = subset_settings_menu->check())
301 save_subset_settings_menu();
308 mouse_cursor->draw();
316 if(done == DONE_QUIT)
322 ++global_frame_counter;
325 now_time = SDL_GetTicks();
326 if (now_time < last_time + FPS)
327 SDL_Delay(last_time + FPS - now_time); /* delay some time */
338 level_subsets = dsubdirs("/levels", "info");
344 /* level_changed = NO;*/
347 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
348 le_level_changed = false;
349 le_current_level = NULL;
352 le_mouse_pressed[LEFT] = false;
353 le_mouse_pressed[RIGHT] = false;
355 texture_load(&le_selection, datadir + "/images/leveleditor/select.png", USE_ALPHA);
357 select_tilegroup_menu_effect.init(false);
360 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
361 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
362 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
363 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
364 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
365 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
366 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
367 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
368 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
369 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
370 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
371 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
373 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
374 le_tilemap_panel->set_button_size(32,10);
375 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
376 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
377 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
379 leveleditor_menu = new Menu();
380 subset_load_menu = new Menu();
381 subset_new_menu = new Menu();
382 subset_settings_menu = new Menu();
383 level_settings_menu = new Menu();
384 select_tilegroup_menu = new Menu();
386 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
387 leveleditor_menu->additem(MN_HL,"",0,0);
388 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
389 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
390 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
391 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
392 leveleditor_menu->additem(MN_HL,"",0,0);
393 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
396 Menu::set_current(leveleditor_menu);
399 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
400 subset_load_menu->additem(MN_HL, "", 0, 0);
402 for(i = 0; i < level_subsets.num_items; ++i)
404 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
406 subset_load_menu->additem(MN_HL,"",0,0);
407 subset_load_menu->additem(MN_BACK,"Back",0,0);
409 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
410 subset_new_menu->additem(MN_HL,"",0,0);
411 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
412 subset_new_menu->additem(MN_ACTION,"Create",0,0);
413 subset_new_menu->additem(MN_HL,"",0,0);
414 subset_new_menu->additem(MN_BACK,"Back",0,0);
416 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
417 subset_settings_menu->additem(MN_HL,"",0,0);
418 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
419 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
420 subset_settings_menu->additem(MN_HL,"",0,0);
421 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
422 subset_settings_menu->additem(MN_HL,"",0,0);
423 subset_settings_menu->additem(MN_BACK,"Back",0,0);
425 level_settings_menu->arrange_left = true;
426 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
427 level_settings_menu->additem(MN_HL,"",0,0);
428 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
429 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
430 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
431 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
432 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
433 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
434 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
435 level_settings_menu->additem(MN_NUMFIELD,"Red ",0,0);
436 level_settings_menu->additem(MN_NUMFIELD,"Green ",0,0);
437 level_settings_menu->additem(MN_NUMFIELD,"Blue ",0,0);
438 level_settings_menu->additem(MN_HL,"",0,0);
439 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
441 select_tilegroup_menu->arrange_left = true;
442 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
443 select_tilegroup_menu->additem(MN_HL,"",0,0);
444 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
445 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
448 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
449 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
451 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
452 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));
454 select_tilegroup_menu->additem(MN_HL,"",0,0);
456 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
461 void update_level_settings_menu()
466 menu_item_change_input(&level_settings_menu->item[2], le_current_level->name.c_str());
467 sprintf(str,"%d",le_current_level->width);
469 string_list_copy(level_settings_menu->item[3].list, dsubdirs("images/themes", "solid0.png"));
470 string_list_copy(level_settings_menu->item[4].list, dfiles("music/",NULL, "-fast"));
471 string_list_copy(level_settings_menu->item[5].list, dfiles("images/background",NULL, NULL));
472 string_list_add_item(level_settings_menu->item[5].list,"");
473 if((i = string_list_find(level_settings_menu->item[3].list,le_current_level->theme.c_str())) != -1)
474 level_settings_menu->item[3].list->active_item = i;
475 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->song_title.c_str())) != -1)
476 level_settings_menu->item[4].list->active_item = i;
477 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->bkgd_image.c_str())) != -1)
478 level_settings_menu->item[5].list->active_item = i;
480 menu_item_change_input(&level_settings_menu->item[6], str);
481 sprintf(str,"%d",le_current_level->time_left);
482 menu_item_change_input(&level_settings_menu->item[7], str);
483 sprintf(str,"%2.0f",le_current_level->gravity);
484 menu_item_change_input(&level_settings_menu->item[8], str);
485 sprintf(str,"%d",le_current_level->bkgd_red);
486 menu_item_change_input(&level_settings_menu->item[9], str);
487 sprintf(str,"%d",le_current_level->bkgd_green);
488 menu_item_change_input(&level_settings_menu->item[10], str);
489 sprintf(str,"%d",le_current_level->bkgd_blue);
490 menu_item_change_input(&level_settings_menu->item[11], str);
493 void update_subset_settings_menu()
495 menu_item_change_input(&subset_settings_menu->item[2], le_level_subset.title.c_str());
496 menu_item_change_input(&subset_settings_menu->item[3], le_level_subset.description.c_str());
499 void apply_level_settings_menu()
504 le_current_level->name = level_settings_menu->item[2].input;
506 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[5].list)) != 0)
508 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[5].list);
512 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[3].list)) != 0)
514 le_current_level->theme = string_list_active(level_settings_menu->item[3].list);
520 le_current_level->free_gfx();
521 le_current_level->load_gfx();
524 le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
526 le_current_level->change_size(atoi(level_settings_menu->item[6].input));
527 le_current_level->time_left = atoi(level_settings_menu->item[7].input);
528 le_current_level->gravity = atof(level_settings_menu->item[8].input);
529 le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input);
530 le_current_level->bkgd_green = atoi(level_settings_menu->item[10].input);
531 le_current_level->bkgd_blue = atoi(level_settings_menu->item[11].input);
534 void save_subset_settings_menu()
536 le_level_subset.title = subset_settings_menu->item[2].input;
537 le_level_subset.description = subset_settings_menu->item[3].input;
538 le_level_subset.save();
541 void le_goto_level(int levelnb)
543 le_world.arrays_free();
545 le_current_level->cleanup();
546 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
548 le_current_level->load(le_level_subset.name.c_str(), le_level);
557 le_current_level->free_gfx();
558 le_current_level->load_gfx();
560 le_world.activate_bad_guys();
565 /*if(level_changed == true)
566 if(askforsaving() == CANCEL)
569 SDL_EnableKeyRepeat(0, 0); // disables key repeating
571 texture_free(&le_selection);
572 delete leveleditor_menu;
573 delete subset_load_menu;
574 delete subset_new_menu;
575 delete subset_settings_menu;
576 delete level_settings_menu;
577 delete select_tilegroup_menu;
578 delete le_save_level_bt;
580 delete le_test_level_bt;
581 delete le_next_level_bt;
582 delete le_previous_level_bt;
583 delete le_move_right_bt;
584 delete le_move_left_bt;
586 delete le_select_mode_one_bt;
587 delete le_select_mode_two_bt;
588 delete le_settings_bt;
589 delete le_tilegroup_bt;
590 delete le_tilemap_panel;
592 if(le_current_level != NULL)
594 le_current_level->free_gfx();
595 le_current_level->cleanup();
596 le_world.arrays_free();
600 void le_drawinterface()
605 if(le_current_level != NULL)
607 /* draw a grid (if selected) */
610 for(x = 0; x < 19; x++)
611 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
612 for(y = 0; y < 15; y++)
613 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
617 if(le_selection_mode == CURSOR)
618 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
619 else if(le_selection_mode == SQUARE)
622 le_highlight_selection();
623 /* draw current selection */
624 w = selection.x2 - selection.x1;
625 h = selection.y2 - selection.y1;
626 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
627 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
628 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
629 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
633 /* draw button bar */
634 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
635 Tile::draw(19 * 32, 14 * 32, le_current_tile);
637 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
638 texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
640 if(le_current_level != NULL)
642 le_save_level_bt->draw();
644 le_test_level_bt->draw();
645 le_next_level_bt->draw();
646 le_previous_level_bt->draw();
647 le_rubber_bt->draw();
648 le_select_mode_one_bt->draw();
649 le_select_mode_two_bt->draw();
650 le_settings_bt->draw();
651 le_move_right_bt->draw();
652 le_move_left_bt->draw();
653 le_tilegroup_bt->draw();
654 if(!cur_tilegroup.empty())
655 tilegroups_map[cur_tilegroup]->draw();
656 le_tilemap_panel->draw();
658 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
659 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
661 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
665 if(show_menu == false)
666 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
668 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
675 unsigned int y,x,i,s;
678 /* Draw the real background */
679 if(le_current_level->bkgd_image[0] != '\0')
682 texture_draw_part(&le_current_level->img_bkgd,s,0,0,0,
683 le_current_level->img_bkgd.w - s - 32, le_current_level->img_bkgd.h);
684 texture_draw_part(&le_current_level->img_bkgd,0,0,screen->w - s - 32 ,0,s,
685 le_current_level->img_bkgd.h);
689 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
692 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
694 for (y = 0; y < 15; ++y)
695 for (x = 0; x < 20; ++x)
698 if(active_tm == TM_BG)
703 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
705 if(active_tm == TM_IA)
710 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
712 if(active_tm == TM_FG)
717 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
719 /* draw whats inside stuff when cursor is selecting those */
720 /* (draw them all the time - is this the right behaviour?) */
721 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
722 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);
726 /* Draw the Bad guys: */
727 for (i = 0; i < le_world.bad_guys.size(); ++i)
729 /* to support frames: img_bsod_left[(frame / 5) % 4] */
732 le_world.bad_guys[i].draw();
736 /* Draw the player: */
737 /* for now, the position is fixed at (100, 240) */
738 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
741 void le_checkevents()
748 keymod = SDL_GetModState();
750 while(SDL_PollEvent(&event))
755 mouse_cursor->set_state(MC_NORMAL);
757 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
758 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
759 event.motion.y > 0 && event.motion.y < screen->h)))
763 case SDL_KEYDOWN: // key pressed
764 key = event.key.keysym.sym;
767 if(key == SDLK_ESCAPE)
770 Menu::set_current(leveleditor_menu);
784 cursor_x -= KEY_CURSOR_SPEED;
786 cursor_x -= KEY_CURSOR_FASTSPEED;
788 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
789 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
794 cursor_x += KEY_CURSOR_SPEED;
796 cursor_x += KEY_CURSOR_FASTSPEED;
798 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
799 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
804 cursor_y -= KEY_CURSOR_SPEED;
806 cursor_y -= KEY_CURSOR_FASTSPEED;
813 cursor_y += KEY_CURSOR_SPEED;
815 cursor_y += KEY_CURSOR_FASTSPEED;
817 if(cursor_y > screen->h-32)
818 cursor_y = screen->h-32;
831 cursor_x = (le_current_level->width * 32) - 32;
835 le_show_grid = !le_show_grid;
841 case SDL_KEYUP: /* key released */
842 switch(event.key.keysym.sym)
851 case SDL_MOUSEBUTTONDOWN:
852 if(event.button.button == SDL_BUTTON_LEFT)
854 le_mouse_pressed[LEFT] = true;
856 selection.x1 = event.motion.x + pos_x;
857 selection.y1 = event.motion.y;
858 selection.x2 = event.motion.x + pos_x;
859 selection.y2 = event.motion.y;
861 else if(event.button.button == SDL_BUTTON_RIGHT)
863 le_mouse_pressed[RIGHT] = true;
866 case SDL_MOUSEBUTTONUP:
867 if(event.button.button == SDL_BUTTON_LEFT)
868 le_mouse_pressed[LEFT] = false;
869 else if(event.button.button == SDL_BUTTON_RIGHT)
870 le_mouse_pressed[RIGHT] = false;
872 case SDL_MOUSEMOTION:
878 cursor_x = ((int)(pos_x + x) / 32) * 32;
879 cursor_y = ((int) y / 32) * 32;
881 if(le_mouse_pressed[LEFT])
883 selection.x2 = x + pos_x;
887 if(le_mouse_pressed[RIGHT])
889 pos_x += -1 * event.motion.xrel;
893 case SDL_QUIT: // window closed
901 if(le_current_level != NULL)
903 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 &&
904 event.motion.y > 0 && event.motion.y < screen->h)))
906 le_mouse_pressed[LEFT] = false;
907 le_mouse_pressed[RIGHT] = false;
909 if(show_menu == false)
911 /* Check for button events */
912 le_test_level_bt->event(event);
913 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
915 le_save_level_bt->event(event);
916 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
917 le_current_level->save(le_level_subset.name.c_str(),le_level);
918 le_exit_bt->event(event);
919 if(le_exit_bt->get_state() == BUTTON_CLICKED)
921 Menu::set_current(leveleditor_menu);
924 le_next_level_bt->event(event);
925 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
927 if(le_level < le_level_subset.levels)
929 le_goto_level(++le_level);
936 sprintf(str,"Level %d doesn't exist.",le_level+1);
937 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
938 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
939 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
943 while(SDL_PollEvent(&event))
946 case SDL_KEYDOWN: // key pressed
947 switch(event.key.keysym.sym)
950 new_lev.init_defaults();
951 new_lev.save(le_level_subset.name.c_str(),++le_level);
952 le_level_subset.levels = le_level;
953 le_goto_level(le_level);
970 le_previous_level_bt->event(event);
971 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
974 le_goto_level(--le_level);
976 le_rubber_bt->event(event);
977 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
979 le_select_mode_one_bt->event(event);
980 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
981 le_selection_mode = CURSOR;
982 le_select_mode_two_bt->event(event);
983 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
984 le_selection_mode = SQUARE;
986 le_tilegroup_bt->event(event);
987 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
989 Menu::set_current(select_tilegroup_menu);
990 select_tilegroup_menu_effect.start(200);
991 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
995 le_settings_bt->event(event);
996 if(le_settings_bt->get_state() == BUTTON_CLICKED)
998 update_level_settings_menu();
999 Menu::set_current(level_settings_menu);
1002 if(!cur_tilegroup.empty())
1003 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1005 if(pbutton->get_state() == BUTTON_CLICKED)
1007 le_current_tile = pbutton->get_tag();
1010 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1012 if(pbutton->get_state() == BUTTON_CLICKED)
1014 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1020 le_settings_bt->event(event);
1021 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1023 Menu::set_current(leveleditor_menu);
1026 le_tilegroup_bt->event(event);
1027 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1029 Menu::set_current(leveleditor_menu);
1034 if(show_menu == false)
1036 le_move_left_bt->event(event);
1037 le_move_right_bt->event(event);
1039 if(le_mouse_pressed[LEFT])
1041 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1046 if(show_menu == false)
1048 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1052 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1057 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1061 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1069 void le_highlight_selection()
1073 if(selection.x1 < selection.x2)
1083 if(selection.y1 < selection.y2)
1099 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1102 void le_change(float x, float y, int tm, unsigned int c)
1104 if(le_current_level != NULL)
1110 /* level_changed = true; */
1112 switch(le_selection_mode)
1115 le_current_level->change(x,y,tm,c);
1120 /* if there is a bad guy over there, remove it */
1121 for(i = 0; i < le_world.bad_guys.size(); ++i)
1122 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1123 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1125 if(c == '0') /* if it's a bad guy */
1126 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1128 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1130 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1134 if(selection.x1 < selection.x2)
1144 if(selection.y1 < selection.y2)
1160 /* if there is a bad guy over there, remove it */
1161 for(i = 0; i < le_world.bad_guys.size(); ++i)
1162 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1163 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1164 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1166 for(xx = x1; xx <= x2; xx++)
1167 for(yy = y1; yy <= y2; yy++)
1169 le_current_level->change(xx*32, yy*32, tm, c);
1171 if(c == '0') // if it's a bad guy
1172 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1174 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1176 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1187 le_current_level->save("test", le_level);
1189 GameSession session("test",le_level, ST_GL_TEST);
1192 Menu::set_current(leveleditor_menu);
1193 le_world.arrays_free();
1194 le_current_level->load_gfx();
1195 le_world.activate_bad_guys();
1201 unsigned int i, done;
1203 " - This is SuperTux's built-in level editor -",
1204 "It has been designed to be light and easy to use from the start.",
1206 "When you first load the level editor you are given a menu where you",
1207 "can load level subsets, create a new level subset, edit the current",
1208 "subset's settings, or simply quit the editor. You can access this menu",
1209 "from the level editor at any time by pressing the escape key.",
1211 "To your right is your button bar. The center of this contains many",
1212 "tiles you can use to make your level. To select a tile, click on it",
1213 "with your left mouse button; your selection will be shown in the",
1214 "bottom right corner of the button box. Click anywhere on your level",
1215 "with the left mouse button to place that tile down. If you right click",
1216 "a tile in the button bar, you can find out what its keyboard shortcut",
1217 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1218 "background, and enemy tiles. The eraser lets you remove tiles.",
1219 "The left and right arrow keys scroll back and forth through your level.",
1220 "The button with the wrench and screwdriver, lets you change the",
1221 "settings of your level, including how long it is or what music it will",
1222 "play. When you are ready to give your level a test, click on the little",
1223 "running Tux. If you like the changes you have made to your level,",
1224 "press the red save key to keep them.",
1225 "To change which level in your subset you are editing, press the white",
1226 "up and down arrow keys at the top of the button box.",
1228 "Have fun making levels! If you make some good ones, send them to us on",
1229 "the SuperTux mailing list!",
1234 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1236 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1237 text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1239 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1247 done = wait_for_event(event);