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_type 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(timer_check(&select_tilegroup_menu_effect))
161 select_tilegroup_menu->set_pos(screen->w - 64 + timer_get_left(&select_tilegroup_menu_effect),82,-0.5,0.5);
164 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
167 if(le_current_level != NULL)
169 /* making events results to be in order */
172 if(pos_x > (le_current_level->width * 32) - screen->w)
173 pos_x = (le_current_level->width * 32) - screen->w;
179 clearscreen(0, 0, 0);
181 /* draw editor interface */
186 menu_process_current();
187 if(current_menu == leveleditor_menu)
189 switch (leveleditor_menu->check())
195 update_subset_settings_menu();
198 done = DONE_LEVELEDITOR;
202 else if(current_menu == level_settings_menu)
204 switch (level_settings_menu->check())
207 apply_level_settings_menu();
208 Menu::set_current(leveleditor_menu);
215 else if(current_menu == select_tilegroup_menu)
218 switch (it = select_tilegroup_menu->check())
223 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
224 cur_tilegroup = select_tilegroup_menu->item[it].text;
231 else if(current_menu == subset_load_menu)
233 switch (i = subset_load_menu->check())
240 le_level_subset.load(level_subsets.item[i-2]);
241 leveleditor_menu->item[3].kind = MN_GOTO;
243 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();
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 global_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 timer_init(&select_tilegroup_menu_effect,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 global_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 global_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 global_world.arrays_free();
601 void le_drawinterface()
606 if(le_current_level != NULL)
608 /* draw a grid (if selected) */
611 for(x = 0; x < 19; x++)
612 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
613 for(y = 0; y < 15; y++)
614 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
618 if(le_selection_mode == CURSOR)
619 texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
620 else if(le_selection_mode == SQUARE)
623 le_highlight_selection();
624 /* draw current selection */
625 w = selection.x2 - selection.x1;
626 h = selection.y2 - selection.y1;
627 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
628 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
629 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
630 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
634 /* draw button bar */
635 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
636 Tile::draw(19 * 32, 14 * 32, le_current_tile);
638 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
639 texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
641 if(le_current_level != NULL)
643 le_save_level_bt->draw();
645 le_test_level_bt->draw();
646 le_next_level_bt->draw();
647 le_previous_level_bt->draw();
648 le_rubber_bt->draw();
649 le_select_mode_one_bt->draw();
650 le_select_mode_two_bt->draw();
651 le_settings_bt->draw();
652 le_move_right_bt->draw();
653 le_move_left_bt->draw();
654 le_tilegroup_bt->draw();
655 if(!cur_tilegroup.empty())
656 tilegroups_map[cur_tilegroup]->draw();
657 le_tilemap_panel->draw();
659 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
660 text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
662 text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
666 if(show_menu == false)
667 text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
669 text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
676 unsigned int y,x,i,s;
679 /* Draw the real background */
680 if(le_current_level->bkgd_image[0] != '\0')
683 texture_draw_part(&le_current_level->img_bkgd,s,0,0,0,
684 le_current_level->img_bkgd.w - s - 32, le_current_level->img_bkgd.h);
685 texture_draw_part(&le_current_level->img_bkgd,0,0,screen->w - s - 32 ,0,s,
686 le_current_level->img_bkgd.h);
690 clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
693 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
695 for (y = 0; y < 15; ++y)
696 for (x = 0; x < 20; ++x)
699 if(active_tm == TM_BG)
704 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
706 if(active_tm == TM_IA)
711 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
713 if(active_tm == TM_FG)
718 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
720 /* draw whats inside stuff when cursor is selecting those */
721 /* (draw them all the time - is this the right behaviour?) */
722 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
723 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);
727 /* Draw the Bad guys: */
728 for (i = 0; i < global_world.bad_guys.size(); ++i)
730 /* to support frames: img_bsod_left[(frame / 5) % 4] */
733 global_world.bad_guys[i].draw();
737 /* Draw the player: */
738 /* for now, the position is fixed at (100, 240) */
739 texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
742 void le_checkevents()
749 keymod = SDL_GetModState();
751 while(SDL_PollEvent(&event))
756 mouse_cursor->set_state(MC_NORMAL);
758 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
759 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
760 event.motion.y > 0 && event.motion.y < screen->h)))
764 case SDL_KEYDOWN: // key pressed
765 key = event.key.keysym.sym;
768 if(key == SDLK_ESCAPE)
771 Menu::set_current(leveleditor_menu);
785 cursor_x -= KEY_CURSOR_SPEED;
787 cursor_x -= KEY_CURSOR_FASTSPEED;
789 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
790 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
795 cursor_x += KEY_CURSOR_SPEED;
797 cursor_x += KEY_CURSOR_FASTSPEED;
799 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
800 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
805 cursor_y -= KEY_CURSOR_SPEED;
807 cursor_y -= KEY_CURSOR_FASTSPEED;
814 cursor_y += KEY_CURSOR_SPEED;
816 cursor_y += KEY_CURSOR_FASTSPEED;
818 if(cursor_y > screen->h-32)
819 cursor_y = screen->h-32;
832 cursor_x = (le_current_level->width * 32) - 32;
836 le_show_grid = !le_show_grid;
842 case SDL_KEYUP: /* key released */
843 switch(event.key.keysym.sym)
852 case SDL_MOUSEBUTTONDOWN:
853 if(event.button.button == SDL_BUTTON_LEFT)
855 le_mouse_pressed[LEFT] = true;
857 selection.x1 = event.motion.x + pos_x;
858 selection.y1 = event.motion.y;
859 selection.x2 = event.motion.x + pos_x;
860 selection.y2 = event.motion.y;
862 else if(event.button.button == SDL_BUTTON_RIGHT)
864 le_mouse_pressed[RIGHT] = true;
867 case SDL_MOUSEBUTTONUP:
868 if(event.button.button == SDL_BUTTON_LEFT)
869 le_mouse_pressed[LEFT] = false;
870 else if(event.button.button == SDL_BUTTON_RIGHT)
871 le_mouse_pressed[RIGHT] = false;
873 case SDL_MOUSEMOTION:
879 cursor_x = ((int)(pos_x + x) / 32) * 32;
880 cursor_y = ((int) y / 32) * 32;
882 if(le_mouse_pressed[LEFT])
884 selection.x2 = x + pos_x;
888 if(le_mouse_pressed[RIGHT])
890 pos_x += -1 * event.motion.xrel;
894 case SDL_QUIT: // window closed
902 if(le_current_level != NULL)
904 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 &&
905 event.motion.y > 0 && event.motion.y < screen->h)))
907 le_mouse_pressed[LEFT] = false;
908 le_mouse_pressed[RIGHT] = false;
910 if(show_menu == false)
912 /* Check for button events */
913 le_test_level_bt->event(event);
914 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
916 le_save_level_bt->event(event);
917 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
918 le_current_level->save(le_level_subset.name.c_str(),le_level);
919 le_exit_bt->event(event);
920 if(le_exit_bt->get_state() == BUTTON_CLICKED)
922 Menu::set_current(leveleditor_menu);
925 le_next_level_bt->event(event);
926 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
928 if(le_level < le_level_subset.levels)
930 le_goto_level(++le_level);
937 sprintf(str,"Level %d doesn't exist.",le_level+1);
938 text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
939 text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
940 text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
944 while(SDL_PollEvent(&event))
947 case SDL_KEYDOWN: // key pressed
948 switch(event.key.keysym.sym)
951 new_lev.init_defaults();
952 new_lev.save(le_level_subset.name.c_str(),++le_level);
953 le_level_subset.levels = le_level;
954 le_goto_level(le_level);
971 le_previous_level_bt->event(event);
972 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
975 le_goto_level(--le_level);
977 le_rubber_bt->event(event);
978 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
980 le_select_mode_one_bt->event(event);
981 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
982 le_selection_mode = CURSOR;
983 le_select_mode_two_bt->event(event);
984 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
985 le_selection_mode = SQUARE;
987 le_tilegroup_bt->event(event);
988 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
990 Menu::set_current(select_tilegroup_menu);
991 timer_start(&select_tilegroup_menu_effect,200);
992 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
996 le_settings_bt->event(event);
997 if(le_settings_bt->get_state() == BUTTON_CLICKED)
999 update_level_settings_menu();
1000 Menu::set_current(level_settings_menu);
1003 if(!cur_tilegroup.empty())
1004 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1006 if(pbutton->get_state() == BUTTON_CLICKED)
1008 le_current_tile = pbutton->get_tag();
1011 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1013 if(pbutton->get_state() == BUTTON_CLICKED)
1015 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1021 le_settings_bt->event(event);
1022 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1024 Menu::set_current(leveleditor_menu);
1027 le_tilegroup_bt->event(event);
1028 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1030 Menu::set_current(leveleditor_menu);
1035 if(show_menu == false)
1037 le_move_left_bt->event(event);
1038 le_move_right_bt->event(event);
1040 if(le_mouse_pressed[LEFT])
1042 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1047 if(show_menu == false)
1049 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1053 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1058 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1062 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1070 void le_highlight_selection()
1074 if(selection.x1 < selection.x2)
1084 if(selection.y1 < selection.y2)
1100 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1103 void le_change(float x, float y, int tm, unsigned int c)
1105 if(le_current_level != NULL)
1111 /* level_changed = true; */
1113 switch(le_selection_mode)
1116 le_current_level->change(x,y,tm,c);
1121 /* if there is a bad guy over there, remove it */
1122 for(i = 0; i < global_world.bad_guys.size(); ++i)
1123 if(xx == global_world.bad_guys[i].base.x/32 && yy == global_world.bad_guys[i].base.y/32)
1124 global_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&global_world.bad_guys[i]));
1126 if(c == '0') /* if it's a bad guy */
1127 global_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1129 global_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1131 global_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1135 if(selection.x1 < selection.x2)
1145 if(selection.y1 < selection.y2)
1161 /* if there is a bad guy over there, remove it */
1162 for(i = 0; i < global_world.bad_guys.size(); ++i)
1163 if(global_world.bad_guys[i].base.x/32 >= x1 && global_world.bad_guys[i].base.x/32 <= x2
1164 && global_world.bad_guys[i].base.y/32 >= y1 && global_world.bad_guys[i].base.y/32 <= y2)
1165 global_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&global_world.bad_guys[i]));
1167 for(xx = x1; xx <= x2; xx++)
1168 for(yy = y1; yy <= y2; yy++)
1170 le_current_level->change(xx*32, yy*32, tm, c);
1172 if(c == '0') // if it's a bad guy
1173 global_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1175 global_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1177 global_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1188 le_current_level->save("test", le_level);
1190 GameSession session("test",le_level, ST_GL_TEST);
1193 Menu::set_current(leveleditor_menu);
1194 global_world.arrays_free();
1195 le_current_level->load_gfx();
1197 global_world.activate_bad_guys();
1203 unsigned int i, done;
1205 " - This is SuperTux's built-in level editor -",
1206 "It has been designed to be light and easy to use from the start.",
1208 "When you first load the level editor you are given a menu where you",
1209 "can load level subsets, create a new level subset, edit the current",
1210 "subset's settings, or simply quit the editor. You can access this menu",
1211 "from the level editor at any time by pressing the escape key.",
1213 "To your right is your button bar. The center of this contains many",
1214 "tiles you can use to make your level. To select a tile, click on it",
1215 "with your left mouse button; your selection will be shown in the",
1216 "bottom right corner of the button box. Click anywhere on your level",
1217 "with the left mouse button to place that tile down. If you right click",
1218 "a tile in the button bar, you can find out what its keyboard shortcut",
1219 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1220 "background, and enemy tiles. The eraser lets you remove tiles.",
1221 "The left and right arrow keys scroll back and forth through your level.",
1222 "The button with the wrench and screwdriver, lets you change the",
1223 "settings of your level, including how long it is or what music it will",
1224 "play. When you are ready to give your level a test, click on the little",
1225 "running Tux. If you like the changes you have made to your level,",
1226 "press the red save key to keep them.",
1227 "To change which level in your subset you are editing, press the white",
1228 "up and down arrow keys at the top of the button box.",
1230 "Have fun making levels! If you make some good ones, send them to us on",
1231 "the SuperTux mailing list!",
1236 text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1238 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1239 text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1241 text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1249 done = wait_for_event(event);