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::current()->action();
214 Menu::current()->draw();
216 if(Menu::current() == leveleditor_menu)
218 switch (leveleditor_menu->check())
221 Menu::set_current(0);
224 update_subset_settings_menu();
231 else if(Menu::current() == level_settings_menu)
233 switch (level_settings_menu->check())
236 apply_level_settings_menu();
237 Menu::set_current(leveleditor_menu);
245 else if(Menu::current() == select_tilegroup_menu)
248 switch (it = select_tilegroup_menu->check())
253 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
254 cur_tilegroup = select_tilegroup_menu->item[it].text;
256 Menu::set_current(0);
261 else if(Menu::current() == subset_load_menu)
263 switch (i = subset_load_menu->check())
270 le_level_subset.load(level_subsets.item[i-2]);
271 leveleditor_menu->item[3].kind = MN_GOTO;
273 le_world.arrays_free();
274 le_current_level = new Level;
275 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
281 le_current_level->load_gfx();
282 le_world.activate_bad_guys();
285 Menu::set_current(leveleditor_menu);
290 else if(Menu::current() == subset_new_menu)
292 if(subset_new_menu->item[2].input[0] == '\0')
293 subset_new_menu->item[3].kind = MN_DEACTIVE;
296 subset_new_menu->item[3].kind = MN_ACTION;
298 switch (i = subset_new_menu->check())
301 st_subset::create(subset_new_menu->item[2].input);
302 le_level_subset.load(subset_new_menu->item[2].input);
303 leveleditor_menu->item[3].kind = MN_GOTO;
305 le_world.arrays_free();
306 le_current_level = new Level;
307 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
313 le_current_level->load_gfx();
314 le_world.activate_bad_guys();
315 subset_new_menu->item[2].change_input("");
316 // FIXME:? show_menu = true;
317 Menu::set_current(leveleditor_menu);
322 else if(Menu::current() == subset_settings_menu)
324 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 )
325 subset_settings_menu->item[5].kind = MN_DEACTIVE;
327 subset_settings_menu->item[5].kind = MN_ACTION;
329 switch (i = subset_settings_menu->check())
332 save_subset_settings_menu();
333 //FIXME:show_menu = true;
334 Menu::set_current(leveleditor_menu);
340 mouse_cursor->draw();
342 printf("done: %i\n", done);
351 ++global_frame_counter;
354 now_time = SDL_GetTicks();
355 if (now_time < last_time + FPS)
356 SDL_Delay(last_time + FPS - now_time); /* delay some time */
367 level_subsets = dsubdirs("/levels", "info");
373 /* level_changed = NO;*/
376 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
377 le_level_changed = false;
378 le_current_level = NULL;
381 le_mouse_pressed[LEFT] = false;
382 le_mouse_pressed[RIGHT] = false;
384 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
386 select_tilegroup_menu_effect.init(false);
389 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
390 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
391 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
392 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
393 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
394 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
395 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
396 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
397 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
398 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
399 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
400 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
402 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
403 le_tilemap_panel->set_button_size(32,10);
404 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
405 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
406 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
408 leveleditor_menu = new Menu();
409 subset_load_menu = new Menu();
410 subset_new_menu = new Menu();
411 subset_settings_menu = new Menu();
412 level_settings_menu = new Menu();
413 select_tilegroup_menu = new Menu();
415 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
416 leveleditor_menu->additem(MN_HL,"",0,0);
417 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
418 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
419 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
420 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
421 leveleditor_menu->additem(MN_HL,"",0,0);
422 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
424 Menu::set_current(leveleditor_menu);
426 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
427 subset_load_menu->additem(MN_HL, "", 0, 0);
429 for(i = 0; i < level_subsets.num_items; ++i)
431 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
433 subset_load_menu->additem(MN_HL,"",0,0);
434 subset_load_menu->additem(MN_BACK,"Back",0,0);
436 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
437 subset_new_menu->additem(MN_HL,"",0,0);
438 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
439 subset_new_menu->additem(MN_ACTION,"Create",0,0);
440 subset_new_menu->additem(MN_HL,"",0,0);
441 subset_new_menu->additem(MN_BACK,"Back",0,0);
443 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
444 subset_settings_menu->additem(MN_HL,"",0,0);
445 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
446 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
447 subset_settings_menu->additem(MN_HL,"",0,0);
448 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
449 subset_settings_menu->additem(MN_HL,"",0,0);
450 subset_settings_menu->additem(MN_BACK,"Back",0,0);
452 level_settings_menu->arrange_left = true;
453 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
454 level_settings_menu->additem(MN_HL,"",0,0);
455 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
456 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
457 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
458 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
459 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
460 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
461 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
462 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
463 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
464 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
465 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
466 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
467 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
468 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
469 level_settings_menu->additem(MN_HL,"",0,0);
470 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
472 select_tilegroup_menu->arrange_left = true;
473 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
474 select_tilegroup_menu->additem(MN_HL,"",0,0);
475 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
476 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
479 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
480 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
482 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
483 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));
485 select_tilegroup_menu->additem(MN_HL,"",0,0);
487 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
492 void update_level_settings_menu()
497 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
498 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
499 sprintf(str,"%d",le_current_level->width);
501 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
502 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
503 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
504 string_list_add_item(level_settings_menu->item[6].list,"");
505 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
506 level_settings_menu->item[3].list->active_item = i;
507 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
508 level_settings_menu->item[4].list->active_item = i;
509 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
510 level_settings_menu->item[5].list->active_item = i;
512 level_settings_menu->item[7].change_input(str);
513 sprintf(str,"%d",le_current_level->time_left);
514 level_settings_menu->item[8].change_input(str);
515 sprintf(str,"%2.0f",le_current_level->gravity);
516 level_settings_menu->item[9].change_input(str);
517 sprintf(str,"%d",le_current_level->bkgd_top.red);
518 level_settings_menu->item[10].change_input(str);
519 sprintf(str,"%d",le_current_level->bkgd_top.green);
520 level_settings_menu->item[11].change_input(str);
521 sprintf(str,"%d",le_current_level->bkgd_top.blue);
522 level_settings_menu->item[12].change_input(str);
523 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
524 level_settings_menu->item[13].change_input(str);
525 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
526 level_settings_menu->item[14].change_input(str);
527 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
528 level_settings_menu->item[15].change_input(str);
531 void update_subset_settings_menu()
533 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
534 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
537 void apply_level_settings_menu()
542 le_current_level->name = level_settings_menu->item[2].input;
543 le_current_level->author = level_settings_menu->item[3].input;
545 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
547 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
551 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
553 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
559 le_current_level->free_gfx();
560 le_current_level->load_gfx();
563 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
565 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
566 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
567 le_current_level->gravity = atof(level_settings_menu->item[9].input);
568 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
569 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
570 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
571 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
572 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
573 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
576 void save_subset_settings_menu()
578 le_level_subset.title = subset_settings_menu->item[2].input;
579 le_level_subset.description = subset_settings_menu->item[3].input;
580 le_level_subset.save();
583 void le_goto_level(int levelnb)
585 le_world.arrays_free();
587 le_current_level->cleanup();
588 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
590 le_current_level->load(le_level_subset.name.c_str(), le_level);
599 le_current_level->free_gfx();
600 le_current_level->load_gfx();
602 le_world.activate_bad_guys();
607 /*if(level_changed == true)
608 if(askforsaving() == CANCEL)
611 SDL_EnableKeyRepeat(0, 0); // disables key repeating
614 delete leveleditor_menu;
615 delete subset_load_menu;
616 delete subset_new_menu;
617 delete subset_settings_menu;
618 delete level_settings_menu;
619 delete select_tilegroup_menu;
620 delete le_save_level_bt;
622 delete le_test_level_bt;
623 delete le_next_level_bt;
624 delete le_previous_level_bt;
625 delete le_move_right_bt;
626 delete le_move_left_bt;
628 delete le_select_mode_one_bt;
629 delete le_select_mode_two_bt;
630 delete le_settings_bt;
631 delete le_tilegroup_bt;
632 delete le_tilemap_panel;
634 if(le_current_level != NULL)
636 le_current_level->free_gfx();
637 le_current_level->cleanup();
638 le_world.arrays_free();
642 void le_drawinterface()
647 if(le_current_level != NULL)
649 /* draw a grid (if selected) */
652 for(x = 0; x < 19; x++)
653 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
654 for(y = 0; y < 15; y++)
655 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
659 if(le_selection_mode == CURSOR)
660 le_selection->draw( cursor_x - pos_x, cursor_y);
661 else if(le_selection_mode == SQUARE)
664 le_highlight_selection();
665 /* draw current selection */
666 w = selection.x2 - selection.x1;
667 h = selection.y2 - selection.y1;
668 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
669 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
670 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
671 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
675 /* draw button bar */
676 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
677 Tile::draw(19 * 32, 14 * 32, le_current_tile);
679 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
680 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
682 if(le_current_level != NULL)
684 le_save_level_bt->draw();
686 le_test_level_bt->draw();
687 le_next_level_bt->draw();
688 le_previous_level_bt->draw();
689 le_rubber_bt->draw();
690 le_select_mode_one_bt->draw();
691 le_select_mode_two_bt->draw();
692 le_settings_bt->draw();
693 le_move_right_bt->draw();
694 le_move_left_bt->draw();
695 le_tilegroup_bt->draw();
696 if(!cur_tilegroup.empty())
697 tilegroups_map[cur_tilegroup]->draw();
698 le_tilemap_panel->draw();
700 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
701 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
703 white_small_text->draw("F1 for Help", 10, 430, 1);
708 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
710 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
717 unsigned int y,x,i,s;
720 /* Draw the real background */
721 if(le_current_level->bkgd_image[0] != '\0')
724 le_current_level->img_bkgd->draw_part(s,0,0,0,
725 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
726 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
727 le_current_level->img_bkgd->h);
731 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
734 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
736 for (y = 0; y < 15; ++y)
737 for (x = 0; x < 20; ++x)
740 if(active_tm == TM_BG)
745 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
747 if(active_tm == TM_IA)
752 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
754 if(active_tm == TM_FG)
759 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
761 /* draw whats inside stuff when cursor is selecting those */
762 /* (draw them all the time - is this the right behaviour?) */
763 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
764 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);
768 /* Draw the Bad guys: */
769 for (i = 0; i < le_world.bad_guys.size(); ++i)
771 /* to support frames: img_bsod_left[(frame / 5) % 4] */
774 le_world.bad_guys[i].draw();
778 /* Draw the player: */
779 /* for now, the position is fixed at (100, 240) */
780 tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
783 void le_checkevents()
790 keymod = SDL_GetModState();
792 while(SDL_PollEvent(&event))
796 Menu::current()->event(event);
800 mouse_cursor->set_state(MC_NORMAL);
802 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
803 if(event.type == SDL_KEYDOWN
804 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
805 && (event.motion.x > 0
806 && event.motion.x < screen->w - 64 &&
807 event.motion.y > 0 && event.motion.y < screen->h)))
811 case SDL_KEYDOWN: // key pressed
812 key = event.key.keysym.sym;
817 cursor_x -= KEY_CURSOR_SPEED;
819 cursor_x -= KEY_CURSOR_FASTSPEED;
821 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
822 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
827 cursor_x += KEY_CURSOR_SPEED;
829 cursor_x += KEY_CURSOR_FASTSPEED;
831 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
832 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
837 cursor_y -= KEY_CURSOR_SPEED;
839 cursor_y -= KEY_CURSOR_FASTSPEED;
846 cursor_y += KEY_CURSOR_SPEED;
848 cursor_y += KEY_CURSOR_FASTSPEED;
850 if(cursor_y > screen->h-32)
851 cursor_y = screen->h-32;
864 cursor_x = (le_current_level->width * 32) - 32;
868 le_show_grid = !le_show_grid;
874 case SDL_KEYUP: /* key released */
875 switch(event.key.keysym.sym)
884 case SDL_MOUSEBUTTONDOWN:
885 if(event.button.button == SDL_BUTTON_LEFT)
887 le_mouse_pressed[LEFT] = true;
889 selection.x1 = event.motion.x + pos_x;
890 selection.y1 = event.motion.y;
891 selection.x2 = event.motion.x + pos_x;
892 selection.y2 = event.motion.y;
894 else if(event.button.button == SDL_BUTTON_RIGHT)
896 le_mouse_pressed[RIGHT] = true;
899 case SDL_MOUSEBUTTONUP:
900 if(event.button.button == SDL_BUTTON_LEFT)
901 le_mouse_pressed[LEFT] = false;
902 else if(event.button.button == SDL_BUTTON_RIGHT)
903 le_mouse_pressed[RIGHT] = false;
905 case SDL_MOUSEMOTION:
912 cursor_x = ((int)(pos_x + x) / 32) * 32;
913 cursor_y = ((int) y / 32) * 32;
915 if(le_mouse_pressed[LEFT])
917 selection.x2 = x + pos_x;
921 if(le_mouse_pressed[RIGHT])
923 pos_x += -1 * event.motion.xrel;
927 case SDL_QUIT: // window closed
936 if(le_current_level != NULL)
938 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 &&
939 event.motion.y > 0 && event.motion.y < screen->h)))
941 le_mouse_pressed[LEFT] = false;
942 le_mouse_pressed[RIGHT] = false;
946 /* Check for button events */
947 le_test_level_bt->event(event);
948 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
950 le_save_level_bt->event(event);
951 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
952 le_current_level->save(le_level_subset.name.c_str(),le_level);
953 le_exit_bt->event(event);
954 if(le_exit_bt->get_state() == BUTTON_CLICKED)
956 Menu::set_current(leveleditor_menu);
958 le_next_level_bt->event(event);
959 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
961 if(le_level < le_level_subset.levels)
963 le_goto_level(++le_level);
970 sprintf(str,"Level %d doesn't exist.",le_level+1);
971 white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
972 white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
973 red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
977 while(SDL_PollEvent(&event))
980 case SDL_KEYDOWN: // key pressed
981 switch(event.key.keysym.sym)
984 new_lev.init_defaults();
985 new_lev.save(le_level_subset.name.c_str(),++le_level);
986 le_level_subset.levels = le_level;
987 le_goto_level(le_level);
1004 le_previous_level_bt->event(event);
1005 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1008 le_goto_level(--le_level);
1010 le_rubber_bt->event(event);
1011 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1012 le_current_tile = 0;
1013 le_select_mode_one_bt->event(event);
1014 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1015 le_selection_mode = CURSOR;
1016 le_select_mode_two_bt->event(event);
1017 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1018 le_selection_mode = SQUARE;
1020 le_tilegroup_bt->event(event);
1021 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1023 Menu::set_current(select_tilegroup_menu);
1024 select_tilegroup_menu_effect.start(200);
1025 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1028 le_settings_bt->event(event);
1029 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1031 update_level_settings_menu();
1032 Menu::set_current(level_settings_menu);
1034 if(!cur_tilegroup.empty())
1035 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1037 if(pbutton->get_state() == BUTTON_CLICKED)
1039 le_current_tile = pbutton->get_tag();
1042 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1044 if(pbutton->get_state() == BUTTON_CLICKED)
1046 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1052 le_settings_bt->event(event);
1053 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1055 Menu::set_current(0);
1057 le_tilegroup_bt->event(event);
1058 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1060 Menu::set_current(0);
1065 if(!Menu::current())
1067 le_move_left_bt->event(event);
1068 le_move_right_bt->event(event);
1070 if(le_mouse_pressed[LEFT])
1072 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1077 if(!Menu::current())
1079 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1083 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1088 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1092 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1100 void le_highlight_selection()
1104 if(selection.x1 < selection.x2)
1114 if(selection.y1 < selection.y2)
1130 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1133 void le_change(float x, float y, int tm, unsigned int c)
1135 if(le_current_level != NULL)
1141 /* level_changed = true; */
1143 switch(le_selection_mode)
1146 le_current_level->change(x,y,tm,c);
1151 /* if there is a bad guy over there, remove it */
1152 for(i = 0; i < le_world.bad_guys.size(); ++i)
1153 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1154 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1156 if(c == '0') /* if it's a bad guy */
1157 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1159 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1161 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1165 if(selection.x1 < selection.x2)
1175 if(selection.y1 < selection.y2)
1191 /* if there is a bad guy over there, remove it */
1192 for(i = 0; i < le_world.bad_guys.size(); ++i)
1193 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1194 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1195 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1197 for(xx = x1; xx <= x2; xx++)
1198 for(yy = y1; yy <= y2; yy++)
1200 le_current_level->change(xx*32, yy*32, tm, c);
1202 if(c == '0') // if it's a bad guy
1203 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1205 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1207 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1218 le_current_level->save("test", le_level);
1220 GameSession session("test",le_level, ST_GL_TEST);
1223 Menu::set_current(leveleditor_menu);
1224 le_world.arrays_free();
1225 le_current_level->load_gfx();
1226 le_world.activate_bad_guys();
1232 unsigned int i, done_;
1234 " - This is SuperTux's built-in level editor -",
1235 "It has been designed to be light and easy to use from the start.",
1237 "When you first load the level editor you are given a menu where you",
1238 "can load level subsets, create a new level subset, edit the current",
1239 "subset's settings, or simply quit the editor. You can access this menu",
1240 "from the level editor at any time by pressing the escape key.",
1242 "To your right is your button bar. The center of this contains many",
1243 "tiles you can use to make your level. To select a tile, click on it",
1244 "with your left mouse button; your selection will be shown in the",
1245 "bottom right corner of the button box. Click anywhere on your level",
1246 "with the left mouse button to place that tile down. If you right click",
1247 "a tile in the button bar, you can find out what its keyboard shortcut",
1248 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1249 "background, and enemy tiles. The eraser lets you remove tiles.",
1250 "The left and right arrow keys scroll back and forth through your level.",
1251 "The button with the wrench and screwdriver, lets you change the",
1252 "settings of your level, including how long it is or what music it will",
1253 "play. When you are ready to give your level a test, click on the little",
1254 "running Tux. If you like the changes you have made to your level,",
1255 "press the red save key to keep them.",
1256 "To change which level in your subset you are editing, press the white",
1257 "up and down arrow keys at the top of the button box.",
1259 "Have fun making levels! If you make some good ones, send them to us on",
1260 "the SuperTux mailing list!",
1265 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1267 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1268 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1270 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1278 done_ = wait_for_event(event);