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"
38 #include "resources.h"
40 /* definitions to aid development */
43 /* definitions that affect gameplay */
44 #define KEY_CURSOR_SPEED 32
45 #define KEY_CURSOR_FASTSPEED 64
47 /* when pagedown/up pressed speed:*/
48 #define PAGE_CURSOR_SPEED 13*32
50 #define MOUSE_LEFT_MARGIN 80
51 #define MOUSE_RIGHT_MARGIN (560-32)
52 /* right_margin should noticed that the cursor is 32 pixels,
53 so it should subtract that value */
54 #define MOUSE_POS_SPEED 20
57 #define SELECT_W 2 // size of the selections lines
58 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
60 /* own declerations */
61 /* crutial ones (main loop) */
65 void le_drawinterface();
66 void le_checkevents();
67 void le_change(float x, float y, int tm, unsigned int c);
70 void le_set_defaults(void);
71 void le_activate_bad_guys(void);
73 void le_highlight_selection();
75 void apply_level_settings_menu();
76 void update_subset_settings_menu();
77 void save_subset_settings_menu();
79 static Level* le_current_level;
81 struct LevelEditorWorld
83 std::vector<BadGuy> bad_guys;
84 void arrays_free(void)
89 void add_bad_guy(float x, float y, BadGuyKind kind)
91 bad_guys.push_back(BadGuy());
92 BadGuy& new_bad_guy = bad_guys.back();
94 new_bad_guy.init(x,y,kind);
97 void activate_bad_guys()
99 for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
100 i != le_current_level->badguy_data.end();
103 add_bad_guy(i->x, i->y, i->kind);
108 /* leveleditor internals */
109 static string_list_type level_subsets;
110 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
111 static int pos_x, cursor_x, cursor_y, fire;
113 static LevelEditorWorld le_world;
114 static st_subset le_level_subset;
115 static int le_show_grid;
117 static Surface* le_selection;
119 static unsigned int le_current_tile;
120 static bool le_mouse_pressed[2];
121 static Button* le_save_level_bt;
122 static Button* le_exit_bt;
123 static Button* le_test_level_bt;
124 static Button* le_next_level_bt;
125 static Button* le_previous_level_bt;
126 static Button* le_move_right_bt;
127 static Button* le_move_left_bt;
128 static Button* le_rubber_bt;
129 static Button* le_select_mode_one_bt;
130 static Button* le_select_mode_two_bt;
131 static Button* le_settings_bt;
132 static Button* le_tilegroup_bt;
133 static ButtonPanel* le_tilemap_panel;
134 static Menu* leveleditor_menu;
135 static Menu* subset_load_menu;
136 static Menu* subset_new_menu;
137 static Menu* subset_settings_menu;
138 static Menu* level_settings_menu;
139 static Menu* select_tilegroup_menu;
140 static Timer select_tilegroup_menu_effect;
141 static std::map<std::string, ButtonPanel* > tilegroups_map;
142 static std::string cur_tilegroup;
144 static square selection;
145 static int le_selection_mode;
146 static SDL_Event event;
147 TileMapType active_tm;
149 void le_set_defaults()
151 if(le_current_level != NULL)
155 if(le_current_level->time_left == 0)
156 le_current_level->time_left = 255;
160 int leveleditor(int levelnb)
162 int last_time, now_time, i;
170 clearscreen(0, 0, 0);
173 while (SDL_PollEvent(&event))
178 last_time = SDL_GetTicks();
183 if(Menu::current() == select_tilegroup_menu)
185 if(select_tilegroup_menu_effect.check())
187 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
191 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
194 if(le_current_level != NULL)
196 /* making events results to be in order */
199 if(pos_x > (le_current_level->width * 32) - screen->w)
200 pos_x = (le_current_level->width * 32) - screen->w;
206 clearscreen(0, 0, 0);
208 /* draw editor interface */
213 menu_process_current();
214 if(Menu::current() == leveleditor_menu)
216 switch (leveleditor_menu->check())
219 Menu::set_current(0);
222 update_subset_settings_menu();
229 else if(Menu::current() == level_settings_menu)
231 switch (level_settings_menu->check())
234 apply_level_settings_menu();
235 Menu::set_current(leveleditor_menu);
243 else if(Menu::current() == select_tilegroup_menu)
246 switch (it = select_tilegroup_menu->check())
251 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
252 cur_tilegroup = select_tilegroup_menu->item[it].text;
254 Menu::set_current(0);
259 else if(Menu::current() == subset_load_menu)
261 switch (i = subset_load_menu->check())
268 le_level_subset.load(level_subsets.item[i-2]);
269 leveleditor_menu->item[3].kind = MN_GOTO;
271 le_world.arrays_free();
272 le_current_level = new Level;
273 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
279 le_current_level->load_gfx();
280 le_world.activate_bad_guys();
283 Menu::set_current(leveleditor_menu);
288 else if(Menu::current() == subset_new_menu)
290 if(subset_new_menu->item[2].input[0] == '\0')
291 subset_new_menu->item[3].kind = MN_DEACTIVE;
294 subset_new_menu->item[3].kind = MN_ACTION;
296 switch (i = subset_new_menu->check())
299 st_subset::create(subset_new_menu->item[2].input);
300 le_level_subset.load(subset_new_menu->item[2].input);
301 leveleditor_menu->item[3].kind = MN_GOTO;
303 le_world.arrays_free();
304 le_current_level = new Level;
305 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
311 le_current_level->load_gfx();
312 le_world.activate_bad_guys();
313 subset_new_menu->item[2].change_input("");
314 // FIXME:? show_menu = true;
315 Menu::set_current(leveleditor_menu);
320 else if(Menu::current() == subset_settings_menu)
322 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 )
323 subset_settings_menu->item[5].kind = MN_DEACTIVE;
325 subset_settings_menu->item[5].kind = MN_ACTION;
327 switch (i = subset_settings_menu->check())
330 save_subset_settings_menu();
331 //FIXME:show_menu = true;
332 Menu::set_current(leveleditor_menu);
338 mouse_cursor->draw();
340 printf("done: %i\n", done);
349 ++global_frame_counter;
352 now_time = SDL_GetTicks();
353 if (now_time < last_time + FPS)
354 SDL_Delay(last_time + FPS - now_time); /* delay some time */
365 level_subsets = dsubdirs("/levels", "info");
371 /* level_changed = NO;*/
374 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
375 le_level_changed = false;
376 le_current_level = NULL;
379 le_mouse_pressed[LEFT] = false;
380 le_mouse_pressed[RIGHT] = false;
382 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
384 select_tilegroup_menu_effect.init(false);
387 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
388 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
389 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
390 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
391 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
392 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
393 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
394 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
395 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
396 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
397 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
398 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
400 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
401 le_tilemap_panel->set_button_size(32,10);
402 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
403 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
404 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
406 leveleditor_menu = new Menu();
407 subset_load_menu = new Menu();
408 subset_new_menu = new Menu();
409 subset_settings_menu = new Menu();
410 level_settings_menu = new Menu();
411 select_tilegroup_menu = new Menu();
413 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
414 leveleditor_menu->additem(MN_HL,"",0,0);
415 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
416 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
417 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
418 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
419 leveleditor_menu->additem(MN_HL,"",0,0);
420 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
422 Menu::set_current(leveleditor_menu);
424 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
425 subset_load_menu->additem(MN_HL, "", 0, 0);
427 for(i = 0; i < level_subsets.num_items; ++i)
429 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
431 subset_load_menu->additem(MN_HL,"",0,0);
432 subset_load_menu->additem(MN_BACK,"Back",0,0);
434 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
435 subset_new_menu->additem(MN_HL,"",0,0);
436 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
437 subset_new_menu->additem(MN_ACTION,"Create",0,0);
438 subset_new_menu->additem(MN_HL,"",0,0);
439 subset_new_menu->additem(MN_BACK,"Back",0,0);
441 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
442 subset_settings_menu->additem(MN_HL,"",0,0);
443 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
444 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
445 subset_settings_menu->additem(MN_HL,"",0,0);
446 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
447 subset_settings_menu->additem(MN_HL,"",0,0);
448 subset_settings_menu->additem(MN_BACK,"Back",0,0);
450 level_settings_menu->arrange_left = true;
451 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
452 level_settings_menu->additem(MN_HL,"",0,0);
453 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
454 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
455 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
456 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
457 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
458 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
459 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
460 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
461 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
462 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
463 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
464 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
465 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
466 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
467 level_settings_menu->additem(MN_HL,"",0,0);
468 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
470 select_tilegroup_menu->arrange_left = true;
471 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
472 select_tilegroup_menu->additem(MN_HL,"",0,0);
473 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
474 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
477 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
478 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
480 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
481 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));
483 select_tilegroup_menu->additem(MN_HL,"",0,0);
485 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
490 void update_level_settings_menu()
495 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
496 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
497 sprintf(str,"%d",le_current_level->width);
499 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
500 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
501 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
502 string_list_add_item(level_settings_menu->item[6].list,"");
503 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
504 level_settings_menu->item[3].list->active_item = i;
505 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
506 level_settings_menu->item[4].list->active_item = i;
507 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
508 level_settings_menu->item[5].list->active_item = i;
510 level_settings_menu->item[7].change_input(str);
511 sprintf(str,"%d",le_current_level->time_left);
512 level_settings_menu->item[8].change_input(str);
513 sprintf(str,"%2.0f",le_current_level->gravity);
514 level_settings_menu->item[9].change_input(str);
515 sprintf(str,"%d",le_current_level->bkgd_top.red);
516 level_settings_menu->item[10].change_input(str);
517 sprintf(str,"%d",le_current_level->bkgd_top.green);
518 level_settings_menu->item[11].change_input(str);
519 sprintf(str,"%d",le_current_level->bkgd_top.blue);
520 level_settings_menu->item[12].change_input(str);
521 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
522 level_settings_menu->item[13].change_input(str);
523 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
524 level_settings_menu->item[14].change_input(str);
525 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
526 level_settings_menu->item[15].change_input(str);
529 void update_subset_settings_menu()
531 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
532 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
535 void apply_level_settings_menu()
540 le_current_level->name = level_settings_menu->item[2].input;
541 le_current_level->author = level_settings_menu->item[3].input;
543 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
545 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
549 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
551 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
557 le_current_level->free_gfx();
558 le_current_level->load_gfx();
561 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
563 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
564 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
565 le_current_level->gravity = atof(level_settings_menu->item[9].input);
566 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
567 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
568 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
569 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
570 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
571 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
574 void save_subset_settings_menu()
576 le_level_subset.title = subset_settings_menu->item[2].input;
577 le_level_subset.description = subset_settings_menu->item[3].input;
578 le_level_subset.save();
581 void le_goto_level(int levelnb)
583 le_world.arrays_free();
585 le_current_level->cleanup();
586 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
588 le_current_level->load(le_level_subset.name.c_str(), le_level);
597 le_current_level->free_gfx();
598 le_current_level->load_gfx();
600 le_world.activate_bad_guys();
605 /*if(level_changed == true)
606 if(askforsaving() == CANCEL)
609 SDL_EnableKeyRepeat(0, 0); // disables key repeating
612 delete leveleditor_menu;
613 delete subset_load_menu;
614 delete subset_new_menu;
615 delete subset_settings_menu;
616 delete level_settings_menu;
617 delete select_tilegroup_menu;
618 delete le_save_level_bt;
620 delete le_test_level_bt;
621 delete le_next_level_bt;
622 delete le_previous_level_bt;
623 delete le_move_right_bt;
624 delete le_move_left_bt;
626 delete le_select_mode_one_bt;
627 delete le_select_mode_two_bt;
628 delete le_settings_bt;
629 delete le_tilegroup_bt;
630 delete le_tilemap_panel;
632 if(le_current_level != NULL)
634 le_current_level->free_gfx();
635 le_current_level->cleanup();
636 le_world.arrays_free();
640 void le_drawinterface()
645 if(le_current_level != NULL)
647 /* draw a grid (if selected) */
650 for(x = 0; x < 19; x++)
651 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
652 for(y = 0; y < 15; y++)
653 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
657 if(le_selection_mode == CURSOR)
658 le_selection->draw( cursor_x - pos_x, cursor_y);
659 else if(le_selection_mode == SQUARE)
662 le_highlight_selection();
663 /* draw current selection */
664 w = selection.x2 - selection.x1;
665 h = selection.y2 - selection.y1;
666 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
667 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
668 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
669 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
673 /* draw button bar */
674 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
675 Tile::draw(19 * 32, 14 * 32, le_current_tile);
677 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
678 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
680 if(le_current_level != NULL)
682 le_save_level_bt->draw();
684 le_test_level_bt->draw();
685 le_next_level_bt->draw();
686 le_previous_level_bt->draw();
687 le_rubber_bt->draw();
688 le_select_mode_one_bt->draw();
689 le_select_mode_two_bt->draw();
690 le_settings_bt->draw();
691 le_move_right_bt->draw();
692 le_move_left_bt->draw();
693 le_tilegroup_bt->draw();
694 if(!cur_tilegroup.empty())
695 tilegroups_map[cur_tilegroup]->draw();
696 le_tilemap_panel->draw();
698 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
699 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
701 white_small_text->draw("F1 for Help", 10, 430, 1);
706 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
708 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
715 unsigned int y,x,i,s;
718 /* Draw the real background */
719 if(le_current_level->bkgd_image[0] != '\0')
722 le_current_level->img_bkgd->draw_part(s,0,0,0,
723 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
724 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
725 le_current_level->img_bkgd->h);
729 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
732 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
734 for (y = 0; y < 15; ++y)
735 for (x = 0; x < 20; ++x)
738 if(active_tm == TM_BG)
743 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
745 if(active_tm == TM_IA)
750 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
752 if(active_tm == TM_FG)
757 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
759 /* draw whats inside stuff when cursor is selecting those */
760 /* (draw them all the time - is this the right behaviour?) */
761 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
762 TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
766 /* Draw the Bad guys: */
767 for (i = 0; i < le_world.bad_guys.size(); ++i)
769 /* to support frames: img_bsod_left[(frame / 5) % 4] */
772 le_world.bad_guys[i].draw();
776 /* Draw the player: */
777 /* for now, the position is fixed at (100, 240) */
778 tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
781 void le_checkevents()
788 keymod = SDL_GetModState();
790 while(SDL_PollEvent(&event))
794 Menu::current()->event(event);
798 mouse_cursor->set_state(MC_NORMAL);
800 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
801 if(event.type == SDL_KEYDOWN
802 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
803 && (event.motion.x > 0
804 && event.motion.x < screen->w - 64 &&
805 event.motion.y > 0 && event.motion.y < screen->h)))
809 case SDL_KEYDOWN: // key pressed
810 key = event.key.keysym.sym;
815 cursor_x -= KEY_CURSOR_SPEED;
817 cursor_x -= KEY_CURSOR_FASTSPEED;
819 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
820 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
825 cursor_x += KEY_CURSOR_SPEED;
827 cursor_x += KEY_CURSOR_FASTSPEED;
829 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
830 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
835 cursor_y -= KEY_CURSOR_SPEED;
837 cursor_y -= KEY_CURSOR_FASTSPEED;
844 cursor_y += KEY_CURSOR_SPEED;
846 cursor_y += KEY_CURSOR_FASTSPEED;
848 if(cursor_y > screen->h-32)
849 cursor_y = screen->h-32;
862 cursor_x = (le_current_level->width * 32) - 32;
866 le_show_grid = !le_show_grid;
872 case SDL_KEYUP: /* key released */
873 switch(event.key.keysym.sym)
882 case SDL_MOUSEBUTTONDOWN:
883 if(event.button.button == SDL_BUTTON_LEFT)
885 le_mouse_pressed[LEFT] = true;
887 selection.x1 = event.motion.x + pos_x;
888 selection.y1 = event.motion.y;
889 selection.x2 = event.motion.x + pos_x;
890 selection.y2 = event.motion.y;
892 else if(event.button.button == SDL_BUTTON_RIGHT)
894 le_mouse_pressed[RIGHT] = true;
897 case SDL_MOUSEBUTTONUP:
898 if(event.button.button == SDL_BUTTON_LEFT)
899 le_mouse_pressed[LEFT] = false;
900 else if(event.button.button == SDL_BUTTON_RIGHT)
901 le_mouse_pressed[RIGHT] = false;
903 case SDL_MOUSEMOTION:
910 cursor_x = ((int)(pos_x + x) / 32) * 32;
911 cursor_y = ((int) y / 32) * 32;
913 if(le_mouse_pressed[LEFT])
915 selection.x2 = x + pos_x;
919 if(le_mouse_pressed[RIGHT])
921 pos_x += -1 * event.motion.xrel;
925 case SDL_QUIT: // window closed
934 if(le_current_level != NULL)
936 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 &&
937 event.motion.y > 0 && event.motion.y < screen->h)))
939 le_mouse_pressed[LEFT] = false;
940 le_mouse_pressed[RIGHT] = false;
944 /* Check for button events */
945 le_test_level_bt->event(event);
946 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
948 le_save_level_bt->event(event);
949 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
950 le_current_level->save(le_level_subset.name.c_str(),le_level);
951 le_exit_bt->event(event);
952 if(le_exit_bt->get_state() == BUTTON_CLICKED)
954 Menu::set_current(leveleditor_menu);
956 le_next_level_bt->event(event);
957 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
959 if(le_level < le_level_subset.levels)
961 le_goto_level(++le_level);
968 sprintf(str,"Level %d doesn't exist.",le_level+1);
969 white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
970 white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
971 red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
975 while(SDL_PollEvent(&event))
978 case SDL_KEYDOWN: // key pressed
979 switch(event.key.keysym.sym)
982 new_lev.init_defaults();
983 new_lev.save(le_level_subset.name.c_str(),++le_level);
984 le_level_subset.levels = le_level;
985 le_goto_level(le_level);
1002 le_previous_level_bt->event(event);
1003 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1006 le_goto_level(--le_level);
1008 le_rubber_bt->event(event);
1009 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1010 le_current_tile = 0;
1011 le_select_mode_one_bt->event(event);
1012 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1013 le_selection_mode = CURSOR;
1014 le_select_mode_two_bt->event(event);
1015 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1016 le_selection_mode = SQUARE;
1018 le_tilegroup_bt->event(event);
1019 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1021 Menu::set_current(select_tilegroup_menu);
1022 select_tilegroup_menu_effect.start(200);
1023 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1026 le_settings_bt->event(event);
1027 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1029 update_level_settings_menu();
1030 Menu::set_current(level_settings_menu);
1032 if(!cur_tilegroup.empty())
1033 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1035 if(pbutton->get_state() == BUTTON_CLICKED)
1037 le_current_tile = pbutton->get_tag();
1040 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1042 if(pbutton->get_state() == BUTTON_CLICKED)
1044 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1050 le_settings_bt->event(event);
1051 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1053 Menu::set_current(0);
1055 le_tilegroup_bt->event(event);
1056 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1058 Menu::set_current(0);
1063 if(!Menu::current())
1065 le_move_left_bt->event(event);
1066 le_move_right_bt->event(event);
1068 if(le_mouse_pressed[LEFT])
1070 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1075 if(!Menu::current())
1077 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1081 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1086 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1090 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1098 void le_highlight_selection()
1102 if(selection.x1 < selection.x2)
1112 if(selection.y1 < selection.y2)
1128 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1131 void le_change(float x, float y, int tm, unsigned int c)
1133 if(le_current_level != NULL)
1139 /* level_changed = true; */
1141 switch(le_selection_mode)
1144 le_current_level->change(x,y,tm,c);
1149 /* if there is a bad guy over there, remove it */
1150 for(i = 0; i < le_world.bad_guys.size(); ++i)
1151 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1152 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1154 if(c == '0') /* if it's a bad guy */
1155 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1157 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1159 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1163 if(selection.x1 < selection.x2)
1173 if(selection.y1 < selection.y2)
1189 /* if there is a bad guy over there, remove it */
1190 for(i = 0; i < le_world.bad_guys.size(); ++i)
1191 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1192 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1193 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1195 for(xx = x1; xx <= x2; xx++)
1196 for(yy = y1; yy <= y2; yy++)
1198 le_current_level->change(xx*32, yy*32, tm, c);
1200 if(c == '0') // if it's a bad guy
1201 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1203 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1205 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1216 le_current_level->save("test", le_level);
1218 GameSession session("test",le_level, ST_GL_TEST);
1221 Menu::set_current(leveleditor_menu);
1222 le_world.arrays_free();
1223 le_current_level->load_gfx();
1224 le_world.activate_bad_guys();
1230 unsigned int i, done_;
1232 " - This is SuperTux's built-in level editor -",
1233 "It has been designed to be light and easy to use from the start.",
1235 "When you first load the level editor you are given a menu where you",
1236 "can load level subsets, create a new level subset, edit the current",
1237 "subset's settings, or simply quit the editor. You can access this menu",
1238 "from the level editor at any time by pressing the escape key.",
1240 "To your right is your button bar. The center of this contains many",
1241 "tiles you can use to make your level. To select a tile, click on it",
1242 "with your left mouse button; your selection will be shown in the",
1243 "bottom right corner of the button box. Click anywhere on your level",
1244 "with the left mouse button to place that tile down. If you right click",
1245 "a tile in the button bar, you can find out what its keyboard shortcut",
1246 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1247 "background, and enemy tiles. The eraser lets you remove tiles.",
1248 "The left and right arrow keys scroll back and forth through your level.",
1249 "The button with the wrench and screwdriver, lets you change the",
1250 "settings of your level, including how long it is or what music it will",
1251 "play. When you are ready to give your level a test, click on the little",
1252 "running Tux. If you like the changes you have made to your level,",
1253 "press the red save key to keep them.",
1254 "To change which level in your subset you are editing, press the white",
1255 "up and down arrow keys at the top of the button box.",
1257 "Have fun making levels! If you make some good ones, send them to us on",
1258 "the SuperTux mailing list!",
1263 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1265 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1266 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1268 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1276 done_ = wait_for_event(event);