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 */
41 #define DONE_LEVELEDITOR 1
44 /* definitions that affect gameplay */
45 #define KEY_CURSOR_SPEED 32
46 #define KEY_CURSOR_FASTSPEED 64
48 /* when pagedown/up pressed speed:*/
49 #define PAGE_CURSOR_SPEED 13*32
51 #define MOUSE_LEFT_MARGIN 80
52 #define MOUSE_RIGHT_MARGIN (560-32)
53 /* right_margin should noticed that the cursor is 32 pixels,
54 so it should subtract that value */
55 #define MOUSE_POS_SPEED 20
58 #define SELECT_W 2 // size of the selections lines
59 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
61 /* own declerations */
62 /* crutial ones (main loop) */
66 void le_drawinterface();
67 void le_checkevents();
68 void le_change(float x, float y, int tm, unsigned int c);
71 void le_set_defaults(void);
72 void le_activate_bad_guys(void);
74 void le_highlight_selection();
76 void apply_level_settings_menu();
77 void update_subset_settings_menu();
78 void save_subset_settings_menu();
80 static Level* le_current_level;
82 struct LevelEditorWorld
84 std::vector<BadGuy> bad_guys;
85 void arrays_free(void)
90 void add_bad_guy(float x, float y, BadGuyKind kind)
92 bad_guys.push_back(BadGuy());
93 BadGuy& new_bad_guy = bad_guys.back();
95 new_bad_guy.init(x,y,kind);
98 void activate_bad_guys()
100 for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
101 i != le_current_level->badguy_data.end();
104 add_bad_guy(i->x, i->y, i->kind);
109 /* leveleditor internals */
110 static string_list_type level_subsets;
111 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
112 static int pos_x, cursor_x, cursor_y, fire;
114 static LevelEditorWorld le_world;
115 static st_subset le_level_subset;
116 static int le_show_grid;
118 static Surface* le_selection;
120 static unsigned int le_current_tile;
121 static bool le_mouse_pressed[2];
122 static Button* le_save_level_bt;
123 static Button* le_exit_bt;
124 static Button* le_test_level_bt;
125 static Button* le_next_level_bt;
126 static Button* le_previous_level_bt;
127 static Button* le_move_right_bt;
128 static Button* le_move_left_bt;
129 static Button* le_rubber_bt;
130 static Button* le_select_mode_one_bt;
131 static Button* le_select_mode_two_bt;
132 static Button* le_settings_bt;
133 static Button* le_tilegroup_bt;
134 static ButtonPanel* le_tilemap_panel;
135 static Menu* leveleditor_menu;
136 static Menu* subset_load_menu;
137 static Menu* subset_new_menu;
138 static Menu* subset_settings_menu;
139 static Menu* level_settings_menu;
140 static Menu* select_tilegroup_menu;
141 static Timer select_tilegroup_menu_effect;
142 static std::map<std::string, ButtonPanel* > tilegroups_map;
143 static std::string cur_tilegroup;
145 static square selection;
146 static int le_selection_mode;
147 static SDL_Event event;
148 TileMapType active_tm;
150 void le_set_defaults()
152 if(le_current_level != NULL)
156 if(le_current_level->time_left == 0)
157 le_current_level->time_left = 255;
161 int leveleditor(int levelnb)
163 int last_time, now_time, i;
171 clearscreen(0, 0, 0);
174 while (SDL_PollEvent(&event))
179 last_time = SDL_GetTicks();
184 if(current_menu == select_tilegroup_menu)
186 if(select_tilegroup_menu_effect.check())
188 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
192 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
195 if(le_current_level != NULL)
197 /* making events results to be in order */
200 if(pos_x > (le_current_level->width * 32) - screen->w)
201 pos_x = (le_current_level->width * 32) - screen->w;
207 clearscreen(0, 0, 0);
209 /* draw editor interface */
214 menu_process_current();
215 if(current_menu == leveleditor_menu)
217 switch (leveleditor_menu->check())
223 update_subset_settings_menu();
226 done = DONE_LEVELEDITOR;
230 else if(current_menu == level_settings_menu)
232 switch (level_settings_menu->check())
235 apply_level_settings_menu();
236 Menu::set_current(leveleditor_menu);
243 else if(current_menu == 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;
259 else if(current_menu == 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();
286 else if(current_menu == subset_new_menu)
288 if(subset_new_menu->item[2].input[0] == '\0')
289 subset_new_menu->item[3].kind = MN_DEACTIVE;
292 subset_new_menu->item[3].kind = MN_ACTION;
294 switch (i = subset_new_menu->check())
297 st_subset::create(subset_new_menu->item[2].input);
298 le_level_subset.load(subset_new_menu->item[2].input);
299 leveleditor_menu->item[3].kind = MN_GOTO;
301 le_world.arrays_free();
302 le_current_level = new Level;
303 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
309 le_current_level->load_gfx();
310 le_world.activate_bad_guys();
311 subset_new_menu->item[2].change_input("");
317 else if(current_menu == subset_settings_menu)
319 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 )
320 subset_settings_menu->item[5].kind = MN_DEACTIVE;
322 subset_settings_menu->item[5].kind = MN_ACTION;
324 switch (i = subset_settings_menu->check())
327 save_subset_settings_menu();
334 mouse_cursor->draw();
342 ++global_frame_counter;
345 now_time = SDL_GetTicks();
346 if (now_time < last_time + FPS)
347 SDL_Delay(last_time + FPS - now_time); /* delay some time */
358 level_subsets = dsubdirs("/levels", "info");
364 /* level_changed = NO;*/
367 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
368 le_level_changed = false;
369 le_current_level = NULL;
372 le_mouse_pressed[LEFT] = false;
373 le_mouse_pressed[RIGHT] = false;
375 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
377 select_tilegroup_menu_effect.init(false);
380 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
381 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
382 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
383 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
384 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
385 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
386 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
387 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
388 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
389 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
390 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
391 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
393 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
394 le_tilemap_panel->set_button_size(32,10);
395 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
396 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
397 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
399 leveleditor_menu = new Menu();
400 subset_load_menu = new Menu();
401 subset_new_menu = new Menu();
402 subset_settings_menu = new Menu();
403 level_settings_menu = new Menu();
404 select_tilegroup_menu = new Menu();
406 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
407 leveleditor_menu->additem(MN_HL,"",0,0);
408 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
409 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
410 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
411 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
412 leveleditor_menu->additem(MN_HL,"",0,0);
413 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
416 Menu::set_current(leveleditor_menu);
419 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
420 subset_load_menu->additem(MN_HL, "", 0, 0);
422 for(i = 0; i < level_subsets.num_items; ++i)
424 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
426 subset_load_menu->additem(MN_HL,"",0,0);
427 subset_load_menu->additem(MN_BACK,"Back",0,0);
429 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
430 subset_new_menu->additem(MN_HL,"",0,0);
431 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
432 subset_new_menu->additem(MN_ACTION,"Create",0,0);
433 subset_new_menu->additem(MN_HL,"",0,0);
434 subset_new_menu->additem(MN_BACK,"Back",0,0);
436 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
437 subset_settings_menu->additem(MN_HL,"",0,0);
438 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
439 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
440 subset_settings_menu->additem(MN_HL,"",0,0);
441 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
442 subset_settings_menu->additem(MN_HL,"",0,0);
443 subset_settings_menu->additem(MN_BACK,"Back",0,0);
445 level_settings_menu->arrange_left = true;
446 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
447 level_settings_menu->additem(MN_HL,"",0,0);
448 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
449 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
450 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
451 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
452 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
453 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
454 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
455 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
456 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
457 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
458 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
459 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
460 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
461 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
462 level_settings_menu->additem(MN_HL,"",0,0);
463 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
465 select_tilegroup_menu->arrange_left = true;
466 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
467 select_tilegroup_menu->additem(MN_HL,"",0,0);
468 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
469 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
472 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
473 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
475 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
476 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));
478 select_tilegroup_menu->additem(MN_HL,"",0,0);
480 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
485 void update_level_settings_menu()
490 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
491 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
492 sprintf(str,"%d",le_current_level->width);
494 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
495 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
496 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
497 string_list_add_item(level_settings_menu->item[6].list,"");
498 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
499 level_settings_menu->item[3].list->active_item = i;
500 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
501 level_settings_menu->item[4].list->active_item = i;
502 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
503 level_settings_menu->item[5].list->active_item = i;
505 level_settings_menu->item[7].change_input(str);
506 sprintf(str,"%d",le_current_level->time_left);
507 level_settings_menu->item[8].change_input(str);
508 sprintf(str,"%2.0f",le_current_level->gravity);
509 level_settings_menu->item[9].change_input(str);
510 sprintf(str,"%d",le_current_level->bkgd_top.red);
511 level_settings_menu->item[10].change_input(str);
512 sprintf(str,"%d",le_current_level->bkgd_top.green);
513 level_settings_menu->item[11].change_input(str);
514 sprintf(str,"%d",le_current_level->bkgd_top.blue);
515 level_settings_menu->item[12].change_input(str);
516 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
517 level_settings_menu->item[13].change_input(str);
518 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
519 level_settings_menu->item[14].change_input(str);
520 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
521 level_settings_menu->item[15].change_input(str);
524 void update_subset_settings_menu()
526 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
527 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
530 void apply_level_settings_menu()
535 le_current_level->name = level_settings_menu->item[2].input;
536 le_current_level->author = level_settings_menu->item[3].input;
538 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
540 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
544 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
546 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
552 le_current_level->free_gfx();
553 le_current_level->load_gfx();
556 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
558 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
559 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
560 le_current_level->gravity = atof(level_settings_menu->item[9].input);
561 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
562 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
563 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
564 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
565 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
566 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
569 void save_subset_settings_menu()
571 le_level_subset.title = subset_settings_menu->item[2].input;
572 le_level_subset.description = subset_settings_menu->item[3].input;
573 le_level_subset.save();
576 void le_goto_level(int levelnb)
578 le_world.arrays_free();
580 le_current_level->cleanup();
581 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
583 le_current_level->load(le_level_subset.name.c_str(), le_level);
592 le_current_level->free_gfx();
593 le_current_level->load_gfx();
595 le_world.activate_bad_guys();
600 /*if(level_changed == true)
601 if(askforsaving() == CANCEL)
604 SDL_EnableKeyRepeat(0, 0); // disables key repeating
607 delete leveleditor_menu;
608 delete subset_load_menu;
609 delete subset_new_menu;
610 delete subset_settings_menu;
611 delete level_settings_menu;
612 delete select_tilegroup_menu;
613 delete le_save_level_bt;
615 delete le_test_level_bt;
616 delete le_next_level_bt;
617 delete le_previous_level_bt;
618 delete le_move_right_bt;
619 delete le_move_left_bt;
621 delete le_select_mode_one_bt;
622 delete le_select_mode_two_bt;
623 delete le_settings_bt;
624 delete le_tilegroup_bt;
625 delete le_tilemap_panel;
627 if(le_current_level != NULL)
629 le_current_level->free_gfx();
630 le_current_level->cleanup();
631 le_world.arrays_free();
635 void le_drawinterface()
640 if(le_current_level != NULL)
642 /* draw a grid (if selected) */
645 for(x = 0; x < 19; x++)
646 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
647 for(y = 0; y < 15; y++)
648 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
652 if(le_selection_mode == CURSOR)
653 le_selection->draw( cursor_x - pos_x, cursor_y);
654 else if(le_selection_mode == SQUARE)
657 le_highlight_selection();
658 /* draw current selection */
659 w = selection.x2 - selection.x1;
660 h = selection.y2 - selection.y1;
661 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
662 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
663 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
664 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
668 /* draw button bar */
669 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
670 Tile::draw(19 * 32, 14 * 32, le_current_tile);
672 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
673 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
675 if(le_current_level != NULL)
677 le_save_level_bt->draw();
679 le_test_level_bt->draw();
680 le_next_level_bt->draw();
681 le_previous_level_bt->draw();
682 le_rubber_bt->draw();
683 le_select_mode_one_bt->draw();
684 le_select_mode_two_bt->draw();
685 le_settings_bt->draw();
686 le_move_right_bt->draw();
687 le_move_left_bt->draw();
688 le_tilegroup_bt->draw();
689 if(!cur_tilegroup.empty())
690 tilegroups_map[cur_tilegroup]->draw();
691 le_tilemap_panel->draw();
693 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
694 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
696 white_small_text->draw("F1 for Help", 10, 430, 1);
700 if(show_menu == false)
701 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
703 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
710 unsigned int y,x,i,s;
713 /* Draw the real background */
714 if(le_current_level->bkgd_image[0] != '\0')
717 le_current_level->img_bkgd->draw_part(s,0,0,0,
718 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
719 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
720 le_current_level->img_bkgd->h);
724 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
727 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
729 for (y = 0; y < 15; ++y)
730 for (x = 0; x < 20; ++x)
733 if(active_tm == TM_BG)
738 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
740 if(active_tm == TM_IA)
745 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
747 if(active_tm == TM_FG)
752 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
754 /* draw whats inside stuff when cursor is selecting those */
755 /* (draw them all the time - is this the right behaviour?) */
756 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
757 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);
761 /* Draw the Bad guys: */
762 for (i = 0; i < le_world.bad_guys.size(); ++i)
764 /* to support frames: img_bsod_left[(frame / 5) % 4] */
767 le_world.bad_guys[i].draw();
771 /* Draw the player: */
772 /* for now, the position is fixed at (100, 240) */
773 tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
776 void le_checkevents()
783 keymod = SDL_GetModState();
785 while(SDL_PollEvent(&event))
787 current_menu->event(event);
789 mouse_cursor->set_state(MC_NORMAL);
791 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
792 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
793 event.motion.y > 0 && event.motion.y < screen->h)))
797 case SDL_KEYDOWN: // key pressed
798 key = event.key.keysym.sym;
803 cursor_x -= KEY_CURSOR_SPEED;
805 cursor_x -= KEY_CURSOR_FASTSPEED;
807 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
808 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
813 cursor_x += KEY_CURSOR_SPEED;
815 cursor_x += KEY_CURSOR_FASTSPEED;
817 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
818 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
823 cursor_y -= KEY_CURSOR_SPEED;
825 cursor_y -= KEY_CURSOR_FASTSPEED;
832 cursor_y += KEY_CURSOR_SPEED;
834 cursor_y += KEY_CURSOR_FASTSPEED;
836 if(cursor_y > screen->h-32)
837 cursor_y = screen->h-32;
850 cursor_x = (le_current_level->width * 32) - 32;
854 le_show_grid = !le_show_grid;
860 case SDL_KEYUP: /* key released */
861 switch(event.key.keysym.sym)
870 case SDL_MOUSEBUTTONDOWN:
871 if(event.button.button == SDL_BUTTON_LEFT)
873 le_mouse_pressed[LEFT] = true;
875 selection.x1 = event.motion.x + pos_x;
876 selection.y1 = event.motion.y;
877 selection.x2 = event.motion.x + pos_x;
878 selection.y2 = event.motion.y;
880 else if(event.button.button == SDL_BUTTON_RIGHT)
882 le_mouse_pressed[RIGHT] = true;
885 case SDL_MOUSEBUTTONUP:
886 if(event.button.button == SDL_BUTTON_LEFT)
887 le_mouse_pressed[LEFT] = false;
888 else if(event.button.button == SDL_BUTTON_RIGHT)
889 le_mouse_pressed[RIGHT] = false;
891 case SDL_MOUSEMOTION:
897 cursor_x = ((int)(pos_x + x) / 32) * 32;
898 cursor_y = ((int) y / 32) * 32;
900 if(le_mouse_pressed[LEFT])
902 selection.x2 = x + pos_x;
906 if(le_mouse_pressed[RIGHT])
908 pos_x += -1 * event.motion.xrel;
912 case SDL_QUIT: // window closed
920 if(le_current_level != NULL)
922 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 &&
923 event.motion.y > 0 && event.motion.y < screen->h)))
925 le_mouse_pressed[LEFT] = false;
926 le_mouse_pressed[RIGHT] = false;
928 if(show_menu == false)
930 /* Check for button events */
931 le_test_level_bt->event(event);
932 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
934 le_save_level_bt->event(event);
935 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
936 le_current_level->save(le_level_subset.name.c_str(),le_level);
937 le_exit_bt->event(event);
938 if(le_exit_bt->get_state() == BUTTON_CLICKED)
940 Menu::set_current(leveleditor_menu);
943 le_next_level_bt->event(event);
944 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
946 if(le_level < le_level_subset.levels)
948 le_goto_level(++le_level);
955 sprintf(str,"Level %d doesn't exist.",le_level+1);
956 white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
957 white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
958 red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
962 while(SDL_PollEvent(&event))
965 case SDL_KEYDOWN: // key pressed
966 switch(event.key.keysym.sym)
969 new_lev.init_defaults();
970 new_lev.save(le_level_subset.name.c_str(),++le_level);
971 le_level_subset.levels = le_level;
972 le_goto_level(le_level);
989 le_previous_level_bt->event(event);
990 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
993 le_goto_level(--le_level);
995 le_rubber_bt->event(event);
996 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
998 le_select_mode_one_bt->event(event);
999 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1000 le_selection_mode = CURSOR;
1001 le_select_mode_two_bt->event(event);
1002 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1003 le_selection_mode = SQUARE;
1005 le_tilegroup_bt->event(event);
1006 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1008 Menu::set_current(select_tilegroup_menu);
1009 select_tilegroup_menu_effect.start(200);
1010 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1014 le_settings_bt->event(event);
1015 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1017 update_level_settings_menu();
1018 Menu::set_current(level_settings_menu);
1021 if(!cur_tilegroup.empty())
1022 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1024 if(pbutton->get_state() == BUTTON_CLICKED)
1026 le_current_tile = pbutton->get_tag();
1029 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1031 if(pbutton->get_state() == BUTTON_CLICKED)
1033 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1039 le_settings_bt->event(event);
1040 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1042 Menu::set_current(leveleditor_menu);
1045 le_tilegroup_bt->event(event);
1046 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1048 Menu::set_current(leveleditor_menu);
1053 if(show_menu == false)
1055 le_move_left_bt->event(event);
1056 le_move_right_bt->event(event);
1058 if(le_mouse_pressed[LEFT])
1060 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1065 if(show_menu == false)
1067 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1071 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1076 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1080 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1088 void le_highlight_selection()
1092 if(selection.x1 < selection.x2)
1102 if(selection.y1 < selection.y2)
1118 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1121 void le_change(float x, float y, int tm, unsigned int c)
1123 if(le_current_level != NULL)
1129 /* level_changed = true; */
1131 switch(le_selection_mode)
1134 le_current_level->change(x,y,tm,c);
1139 /* if there is a bad guy over there, remove it */
1140 for(i = 0; i < le_world.bad_guys.size(); ++i)
1141 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1142 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1144 if(c == '0') /* if it's a bad guy */
1145 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1147 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1149 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1153 if(selection.x1 < selection.x2)
1163 if(selection.y1 < selection.y2)
1179 /* if there is a bad guy over there, remove it */
1180 for(i = 0; i < le_world.bad_guys.size(); ++i)
1181 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1182 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1183 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1185 for(xx = x1; xx <= x2; xx++)
1186 for(yy = y1; yy <= y2; yy++)
1188 le_current_level->change(xx*32, yy*32, tm, c);
1190 if(c == '0') // if it's a bad guy
1191 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1193 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1195 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1206 le_current_level->save("test", le_level);
1208 GameSession session("test",le_level, ST_GL_TEST);
1211 Menu::set_current(leveleditor_menu);
1212 le_world.arrays_free();
1213 le_current_level->load_gfx();
1214 le_world.activate_bad_guys();
1220 unsigned int i, done;
1222 " - This is SuperTux's built-in level editor -",
1223 "It has been designed to be light and easy to use from the start.",
1225 "When you first load the level editor you are given a menu where you",
1226 "can load level subsets, create a new level subset, edit the current",
1227 "subset's settings, or simply quit the editor. You can access this menu",
1228 "from the level editor at any time by pressing the escape key.",
1230 "To your right is your button bar. The center of this contains many",
1231 "tiles you can use to make your level. To select a tile, click on it",
1232 "with your left mouse button; your selection will be shown in the",
1233 "bottom right corner of the button box. Click anywhere on your level",
1234 "with the left mouse button to place that tile down. If you right click",
1235 "a tile in the button bar, you can find out what its keyboard shortcut",
1236 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1237 "background, and enemy tiles. The eraser lets you remove tiles.",
1238 "The left and right arrow keys scroll back and forth through your level.",
1239 "The button with the wrench and screwdriver, lets you change the",
1240 "settings of your level, including how long it is or what music it will",
1241 "play. When you are ready to give your level a test, click on the little",
1242 "running Tux. If you like the changes you have made to your level,",
1243 "press the red save key to keep them.",
1244 "To change which level in your subset you are editing, press the white",
1245 "up and down arrow keys at the top of the button box.",
1247 "Have fun making levels! If you make some good ones, send them to us on",
1248 "the SuperTux mailing list!",
1253 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1255 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1256 white_text->draw(text[i], 5, 80+(i*18), 1);
1258 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1266 done = wait_for_event(event);