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
43 #define DONE_CHANGELEVEL 3
45 /* definitions that affect gameplay */
46 #define KEY_CURSOR_SPEED 32
47 #define KEY_CURSOR_FASTSPEED 64
49 /* when pagedown/up pressed speed:*/
50 #define PAGE_CURSOR_SPEED 13*32
52 #define MOUSE_LEFT_MARGIN 80
53 #define MOUSE_RIGHT_MARGIN (560-32)
54 /* right_margin should noticed that the cursor is 32 pixels,
55 so it should subtract that value */
56 #define MOUSE_POS_SPEED 20
59 #define SELECT_W 2 // size of the selections lines
60 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
62 /* own declerations */
63 /* crutial ones (main loop) */
67 void le_drawinterface();
68 void le_checkevents();
69 void le_change(float x, float y, int tm, unsigned int c);
72 void le_set_defaults(void);
73 void le_activate_bad_guys(void);
75 void le_highlight_selection();
77 void apply_level_settings_menu();
78 void update_subset_settings_menu();
79 void save_subset_settings_menu();
81 static Level* le_current_level;
83 struct LevelEditorWorld
85 std::vector<BadGuy> bad_guys;
86 void arrays_free(void)
91 void add_bad_guy(float x, float y, BadGuyKind kind)
93 bad_guys.push_back(BadGuy());
94 BadGuy& new_bad_guy = bad_guys.back();
96 new_bad_guy.init(x,y,kind);
99 void activate_bad_guys()
101 for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
102 i != le_current_level->badguy_data.end();
105 add_bad_guy(i->x, i->y, i->kind);
110 /* leveleditor internals */
111 static string_list_type level_subsets;
112 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
113 static int pos_x, cursor_x, cursor_y, fire;
115 static LevelEditorWorld le_world;
116 static st_subset le_level_subset;
117 static int le_show_grid;
119 static Surface* le_selection;
121 static unsigned int le_current_tile;
122 static bool le_mouse_pressed[2];
123 static Button* le_save_level_bt;
124 static Button* le_exit_bt;
125 static Button* le_test_level_bt;
126 static Button* le_next_level_bt;
127 static Button* le_previous_level_bt;
128 static Button* le_move_right_bt;
129 static Button* le_move_left_bt;
130 static Button* le_rubber_bt;
131 static Button* le_select_mode_one_bt;
132 static Button* le_select_mode_two_bt;
133 static Button* le_settings_bt;
134 static Button* le_tilegroup_bt;
135 static ButtonPanel* le_tilemap_panel;
136 static Menu* leveleditor_menu;
137 static Menu* subset_load_menu;
138 static Menu* subset_new_menu;
139 static Menu* subset_settings_menu;
140 static Menu* level_settings_menu;
141 static Menu* select_tilegroup_menu;
142 static Timer select_tilegroup_menu_effect;
143 static std::map<std::string, ButtonPanel* > tilegroups_map;
144 static std::string cur_tilegroup;
146 static square selection;
147 static int le_selection_mode;
148 static SDL_Event event;
149 TileMapType active_tm;
151 void le_set_defaults()
153 if(le_current_level != NULL)
157 if(le_current_level->time_left == 0)
158 le_current_level->time_left = 255;
162 int leveleditor(int levelnb)
164 int last_time, now_time, i;
172 clearscreen(0, 0, 0);
175 while (SDL_PollEvent(&event))
180 last_time = SDL_GetTicks();
185 if(current_menu == select_tilegroup_menu)
187 if(select_tilegroup_menu_effect.check())
189 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
193 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
196 if(le_current_level != NULL)
198 /* making events results to be in order */
201 if(pos_x > (le_current_level->width * 32) - screen->w)
202 pos_x = (le_current_level->width * 32) - screen->w;
208 clearscreen(0, 0, 0);
210 /* draw editor interface */
215 menu_process_current();
216 if(current_menu == leveleditor_menu)
218 switch (leveleditor_menu->check())
224 update_subset_settings_menu();
227 done = DONE_LEVELEDITOR;
231 else if(current_menu == level_settings_menu)
233 switch (level_settings_menu->check())
236 apply_level_settings_menu();
237 Menu::set_current(leveleditor_menu);
244 else if(current_menu == select_tilegroup_menu)
247 switch (it = select_tilegroup_menu->check())
252 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
253 cur_tilegroup = select_tilegroup_menu->item[it].text;
260 else if(current_menu == subset_load_menu)
262 switch (i = subset_load_menu->check())
269 le_level_subset.load(level_subsets.item[i-2]);
270 leveleditor_menu->item[3].kind = MN_GOTO;
272 le_world.arrays_free();
273 le_current_level = new Level;
274 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
280 le_current_level->load_gfx();
281 le_world.activate_bad_guys();
287 else if(current_menu == subset_new_menu)
289 if(subset_new_menu->item[2].input[0] == '\0')
290 subset_new_menu->item[3].kind = MN_DEACTIVE;
293 subset_new_menu->item[3].kind = MN_ACTION;
295 switch (i = subset_new_menu->check())
298 st_subset::create(subset_new_menu->item[2].input);
299 le_level_subset.load(subset_new_menu->item[2].input);
300 leveleditor_menu->item[3].kind = MN_GOTO;
302 le_world.arrays_free();
303 le_current_level = new Level;
304 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
310 le_current_level->load_gfx();
311 le_world.activate_bad_guys();
312 subset_new_menu->item[2].change_input("");
318 else if(current_menu == subset_settings_menu)
320 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 )
321 subset_settings_menu->item[5].kind = MN_DEACTIVE;
323 subset_settings_menu->item[5].kind = MN_ACTION;
325 switch (i = subset_settings_menu->check())
328 save_subset_settings_menu();
335 mouse_cursor->draw();
343 if(done == DONE_QUIT)
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);
423 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);
707 if(show_menu == false)
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))
795 current_menu->event(event);
797 mouse_cursor->set_state(MC_NORMAL);
799 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
800 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
801 event.motion.y > 0 && event.motion.y < screen->h)))
805 case SDL_KEYDOWN: // key pressed
806 key = event.key.keysym.sym;
809 if(key == SDLK_ESCAPE)
812 Menu::set_current(leveleditor_menu);
826 cursor_x -= KEY_CURSOR_SPEED;
828 cursor_x -= KEY_CURSOR_FASTSPEED;
830 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
831 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
836 cursor_x += KEY_CURSOR_SPEED;
838 cursor_x += KEY_CURSOR_FASTSPEED;
840 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
841 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
846 cursor_y -= KEY_CURSOR_SPEED;
848 cursor_y -= KEY_CURSOR_FASTSPEED;
855 cursor_y += KEY_CURSOR_SPEED;
857 cursor_y += KEY_CURSOR_FASTSPEED;
859 if(cursor_y > screen->h-32)
860 cursor_y = screen->h-32;
873 cursor_x = (le_current_level->width * 32) - 32;
877 le_show_grid = !le_show_grid;
883 case SDL_KEYUP: /* key released */
884 switch(event.key.keysym.sym)
893 case SDL_MOUSEBUTTONDOWN:
894 if(event.button.button == SDL_BUTTON_LEFT)
896 le_mouse_pressed[LEFT] = true;
898 selection.x1 = event.motion.x + pos_x;
899 selection.y1 = event.motion.y;
900 selection.x2 = event.motion.x + pos_x;
901 selection.y2 = event.motion.y;
903 else if(event.button.button == SDL_BUTTON_RIGHT)
905 le_mouse_pressed[RIGHT] = true;
908 case SDL_MOUSEBUTTONUP:
909 if(event.button.button == SDL_BUTTON_LEFT)
910 le_mouse_pressed[LEFT] = false;
911 else if(event.button.button == SDL_BUTTON_RIGHT)
912 le_mouse_pressed[RIGHT] = false;
914 case SDL_MOUSEMOTION:
920 cursor_x = ((int)(pos_x + x) / 32) * 32;
921 cursor_y = ((int) y / 32) * 32;
923 if(le_mouse_pressed[LEFT])
925 selection.x2 = x + pos_x;
929 if(le_mouse_pressed[RIGHT])
931 pos_x += -1 * event.motion.xrel;
935 case SDL_QUIT: // window closed
943 if(le_current_level != NULL)
945 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 &&
946 event.motion.y > 0 && event.motion.y < screen->h)))
948 le_mouse_pressed[LEFT] = false;
949 le_mouse_pressed[RIGHT] = false;
951 if(show_menu == false)
953 /* Check for button events */
954 le_test_level_bt->event(event);
955 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
957 le_save_level_bt->event(event);
958 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
959 le_current_level->save(le_level_subset.name.c_str(),le_level);
960 le_exit_bt->event(event);
961 if(le_exit_bt->get_state() == BUTTON_CLICKED)
963 Menu::set_current(leveleditor_menu);
966 le_next_level_bt->event(event);
967 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
969 if(le_level < le_level_subset.levels)
971 le_goto_level(++le_level);
978 sprintf(str,"Level %d doesn't exist.",le_level+1);
979 white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
980 white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
981 red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
985 while(SDL_PollEvent(&event))
988 case SDL_KEYDOWN: // key pressed
989 switch(event.key.keysym.sym)
992 new_lev.init_defaults();
993 new_lev.save(le_level_subset.name.c_str(),++le_level);
994 le_level_subset.levels = le_level;
995 le_goto_level(le_level);
1012 le_previous_level_bt->event(event);
1013 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1016 le_goto_level(--le_level);
1018 le_rubber_bt->event(event);
1019 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1020 le_current_tile = 0;
1021 le_select_mode_one_bt->event(event);
1022 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1023 le_selection_mode = CURSOR;
1024 le_select_mode_two_bt->event(event);
1025 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1026 le_selection_mode = SQUARE;
1028 le_tilegroup_bt->event(event);
1029 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1031 Menu::set_current(select_tilegroup_menu);
1032 select_tilegroup_menu_effect.start(200);
1033 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1037 le_settings_bt->event(event);
1038 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1040 update_level_settings_menu();
1041 Menu::set_current(level_settings_menu);
1044 if(!cur_tilegroup.empty())
1045 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1047 if(pbutton->get_state() == BUTTON_CLICKED)
1049 le_current_tile = pbutton->get_tag();
1052 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1054 if(pbutton->get_state() == BUTTON_CLICKED)
1056 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1062 le_settings_bt->event(event);
1063 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1065 Menu::set_current(leveleditor_menu);
1068 le_tilegroup_bt->event(event);
1069 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1071 Menu::set_current(leveleditor_menu);
1076 if(show_menu == false)
1078 le_move_left_bt->event(event);
1079 le_move_right_bt->event(event);
1081 if(le_mouse_pressed[LEFT])
1083 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1088 if(show_menu == false)
1090 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1094 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1099 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1103 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1111 void le_highlight_selection()
1115 if(selection.x1 < selection.x2)
1125 if(selection.y1 < selection.y2)
1141 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1144 void le_change(float x, float y, int tm, unsigned int c)
1146 if(le_current_level != NULL)
1152 /* level_changed = true; */
1154 switch(le_selection_mode)
1157 le_current_level->change(x,y,tm,c);
1162 /* if there is a bad guy over there, remove it */
1163 for(i = 0; i < le_world.bad_guys.size(); ++i)
1164 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1165 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1167 if(c == '0') /* if it's a bad guy */
1168 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1170 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1172 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1176 if(selection.x1 < selection.x2)
1186 if(selection.y1 < selection.y2)
1202 /* if there is a bad guy over there, remove it */
1203 for(i = 0; i < le_world.bad_guys.size(); ++i)
1204 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1205 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1206 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1208 for(xx = x1; xx <= x2; xx++)
1209 for(yy = y1; yy <= y2; yy++)
1211 le_current_level->change(xx*32, yy*32, tm, c);
1213 if(c == '0') // if it's a bad guy
1214 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1216 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1218 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1229 le_current_level->save("test", le_level);
1231 GameSession session("test",le_level, ST_GL_TEST);
1234 Menu::set_current(leveleditor_menu);
1235 le_world.arrays_free();
1236 le_current_level->load_gfx();
1237 le_world.activate_bad_guys();
1243 unsigned int i, done;
1245 " - This is SuperTux's built-in level editor -",
1246 "It has been designed to be light and easy to use from the start.",
1248 "When you first load the level editor you are given a menu where you",
1249 "can load level subsets, create a new level subset, edit the current",
1250 "subset's settings, or simply quit the editor. You can access this menu",
1251 "from the level editor at any time by pressing the escape key.",
1253 "To your right is your button bar. The center of this contains many",
1254 "tiles you can use to make your level. To select a tile, click on it",
1255 "with your left mouse button; your selection will be shown in the",
1256 "bottom right corner of the button box. Click anywhere on your level",
1257 "with the left mouse button to place that tile down. If you right click",
1258 "a tile in the button bar, you can find out what its keyboard shortcut",
1259 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1260 "background, and enemy tiles. The eraser lets you remove tiles.",
1261 "The left and right arrow keys scroll back and forth through your level.",
1262 "The button with the wrench and screwdriver, lets you change the",
1263 "settings of your level, including how long it is or what music it will",
1264 "play. When you are ready to give your level a test, click on the little",
1265 "running Tux. If you like the changes you have made to your level,",
1266 "press the red save key to keep them.",
1267 "To change which level in your subset you are editing, press the white",
1268 "up and down arrow keys at the top of the button box.",
1270 "Have fun making levels! If you make some good ones, send them to us on",
1271 "the SuperTux mailing list!",
1276 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1278 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1279 white_text->draw(text[i], 5, 80+(i*18), 1);
1281 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1289 done = wait_for_event(event);