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(current_menu == select_tilegroup_menu)
185 if(select_tilegroup_menu_effect.check())
187 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
191 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
194 if(le_current_level != NULL)
196 /* making events results to be in order */
199 if(pos_x > (le_current_level->width * 32) - screen->w)
200 pos_x = (le_current_level->width * 32) - screen->w;
206 clearscreen(0, 0, 0);
208 /* draw editor interface */
213 menu_process_current();
214 if(current_menu == leveleditor_menu)
216 switch (leveleditor_menu->check())
222 update_subset_settings_menu();
229 else if(current_menu == level_settings_menu)
231 switch (level_settings_menu->check())
234 apply_level_settings_menu();
235 Menu::set_current(leveleditor_menu);
242 else if(current_menu == select_tilegroup_menu)
245 switch (it = select_tilegroup_menu->check())
250 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
251 cur_tilegroup = select_tilegroup_menu->item[it].text;
258 else if(current_menu == subset_load_menu)
260 switch (i = subset_load_menu->check())
267 le_level_subset.load(level_subsets.item[i-2]);
268 leveleditor_menu->item[3].kind = MN_GOTO;
270 le_world.arrays_free();
271 le_current_level = new Level;
272 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
278 le_current_level->load_gfx();
279 le_world.activate_bad_guys();
285 else if(current_menu == subset_new_menu)
287 if(subset_new_menu->item[2].input[0] == '\0')
288 subset_new_menu->item[3].kind = MN_DEACTIVE;
291 subset_new_menu->item[3].kind = MN_ACTION;
293 switch (i = subset_new_menu->check())
296 st_subset::create(subset_new_menu->item[2].input);
297 le_level_subset.load(subset_new_menu->item[2].input);
298 leveleditor_menu->item[3].kind = MN_GOTO;
300 le_world.arrays_free();
301 le_current_level = new Level;
302 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
308 le_current_level->load_gfx();
309 le_world.activate_bad_guys();
310 subset_new_menu->item[2].change_input("");
316 else if(current_menu == subset_settings_menu)
318 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 )
319 subset_settings_menu->item[5].kind = MN_DEACTIVE;
321 subset_settings_menu->item[5].kind = MN_ACTION;
323 switch (i = subset_settings_menu->check())
326 save_subset_settings_menu();
333 mouse_cursor->draw();
335 printf("done: %i\n", done);
344 ++global_frame_counter;
347 now_time = SDL_GetTicks();
348 if (now_time < last_time + FPS)
349 SDL_Delay(last_time + FPS - now_time); /* delay some time */
360 level_subsets = dsubdirs("/levels", "info");
366 /* level_changed = NO;*/
369 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
370 le_level_changed = false;
371 le_current_level = NULL;
374 le_mouse_pressed[LEFT] = false;
375 le_mouse_pressed[RIGHT] = false;
377 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
379 select_tilegroup_menu_effect.init(false);
382 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
383 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
384 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
385 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
386 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
387 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
388 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
389 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
390 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
391 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
392 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
393 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
395 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
396 le_tilemap_panel->set_button_size(32,10);
397 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
398 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
399 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
401 leveleditor_menu = new Menu();
402 subset_load_menu = new Menu();
403 subset_new_menu = new Menu();
404 subset_settings_menu = new Menu();
405 level_settings_menu = new Menu();
406 select_tilegroup_menu = new Menu();
408 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
409 leveleditor_menu->additem(MN_HL,"",0,0);
410 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
411 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
412 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
413 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
414 leveleditor_menu->additem(MN_HL,"",0,0);
415 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
418 Menu::set_current(leveleditor_menu);
421 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
422 subset_load_menu->additem(MN_HL, "", 0, 0);
424 for(i = 0; i < level_subsets.num_items; ++i)
426 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
428 subset_load_menu->additem(MN_HL,"",0,0);
429 subset_load_menu->additem(MN_BACK,"Back",0,0);
431 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
432 subset_new_menu->additem(MN_HL,"",0,0);
433 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
434 subset_new_menu->additem(MN_ACTION,"Create",0,0);
435 subset_new_menu->additem(MN_HL,"",0,0);
436 subset_new_menu->additem(MN_BACK,"Back",0,0);
438 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
439 subset_settings_menu->additem(MN_HL,"",0,0);
440 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
441 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
442 subset_settings_menu->additem(MN_HL,"",0,0);
443 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
444 subset_settings_menu->additem(MN_HL,"",0,0);
445 subset_settings_menu->additem(MN_BACK,"Back",0,0);
447 level_settings_menu->arrange_left = true;
448 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
449 level_settings_menu->additem(MN_HL,"",0,0);
450 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
451 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
452 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
453 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
454 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
455 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
456 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
457 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
458 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
459 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
460 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
461 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
462 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
463 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
464 level_settings_menu->additem(MN_HL,"",0,0);
465 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
467 select_tilegroup_menu->arrange_left = true;
468 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
469 select_tilegroup_menu->additem(MN_HL,"",0,0);
470 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
471 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
474 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
475 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
477 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
478 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));
480 select_tilegroup_menu->additem(MN_HL,"",0,0);
482 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
487 void update_level_settings_menu()
492 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
493 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
494 sprintf(str,"%d",le_current_level->width);
496 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
497 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
498 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
499 string_list_add_item(level_settings_menu->item[6].list,"");
500 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
501 level_settings_menu->item[3].list->active_item = i;
502 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
503 level_settings_menu->item[4].list->active_item = i;
504 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
505 level_settings_menu->item[5].list->active_item = i;
507 level_settings_menu->item[7].change_input(str);
508 sprintf(str,"%d",le_current_level->time_left);
509 level_settings_menu->item[8].change_input(str);
510 sprintf(str,"%2.0f",le_current_level->gravity);
511 level_settings_menu->item[9].change_input(str);
512 sprintf(str,"%d",le_current_level->bkgd_top.red);
513 level_settings_menu->item[10].change_input(str);
514 sprintf(str,"%d",le_current_level->bkgd_top.green);
515 level_settings_menu->item[11].change_input(str);
516 sprintf(str,"%d",le_current_level->bkgd_top.blue);
517 level_settings_menu->item[12].change_input(str);
518 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
519 level_settings_menu->item[13].change_input(str);
520 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
521 level_settings_menu->item[14].change_input(str);
522 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
523 level_settings_menu->item[15].change_input(str);
526 void update_subset_settings_menu()
528 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
529 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
532 void apply_level_settings_menu()
537 le_current_level->name = level_settings_menu->item[2].input;
538 le_current_level->author = level_settings_menu->item[3].input;
540 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
542 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
546 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
548 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
554 le_current_level->free_gfx();
555 le_current_level->load_gfx();
558 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
560 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
561 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
562 le_current_level->gravity = atof(level_settings_menu->item[9].input);
563 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
564 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
565 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
566 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
567 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
568 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
571 void save_subset_settings_menu()
573 le_level_subset.title = subset_settings_menu->item[2].input;
574 le_level_subset.description = subset_settings_menu->item[3].input;
575 le_level_subset.save();
578 void le_goto_level(int levelnb)
580 le_world.arrays_free();
582 le_current_level->cleanup();
583 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
585 le_current_level->load(le_level_subset.name.c_str(), le_level);
594 le_current_level->free_gfx();
595 le_current_level->load_gfx();
597 le_world.activate_bad_guys();
602 /*if(level_changed == true)
603 if(askforsaving() == CANCEL)
606 SDL_EnableKeyRepeat(0, 0); // disables key repeating
609 delete leveleditor_menu;
610 delete subset_load_menu;
611 delete subset_new_menu;
612 delete subset_settings_menu;
613 delete level_settings_menu;
614 delete select_tilegroup_menu;
615 delete le_save_level_bt;
617 delete le_test_level_bt;
618 delete le_next_level_bt;
619 delete le_previous_level_bt;
620 delete le_move_right_bt;
621 delete le_move_left_bt;
623 delete le_select_mode_one_bt;
624 delete le_select_mode_two_bt;
625 delete le_settings_bt;
626 delete le_tilegroup_bt;
627 delete le_tilemap_panel;
629 if(le_current_level != NULL)
631 le_current_level->free_gfx();
632 le_current_level->cleanup();
633 le_world.arrays_free();
637 void le_drawinterface()
642 if(le_current_level != NULL)
644 /* draw a grid (if selected) */
647 for(x = 0; x < 19; x++)
648 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
649 for(y = 0; y < 15; y++)
650 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
654 if(le_selection_mode == CURSOR)
655 le_selection->draw( cursor_x - pos_x, cursor_y);
656 else if(le_selection_mode == SQUARE)
659 le_highlight_selection();
660 /* draw current selection */
661 w = selection.x2 - selection.x1;
662 h = selection.y2 - selection.y1;
663 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
664 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
665 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
666 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
670 /* draw button bar */
671 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
672 Tile::draw(19 * 32, 14 * 32, le_current_tile);
674 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
675 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
677 if(le_current_level != NULL)
679 le_save_level_bt->draw();
681 le_test_level_bt->draw();
682 le_next_level_bt->draw();
683 le_previous_level_bt->draw();
684 le_rubber_bt->draw();
685 le_select_mode_one_bt->draw();
686 le_select_mode_two_bt->draw();
687 le_settings_bt->draw();
688 le_move_right_bt->draw();
689 le_move_left_bt->draw();
690 le_tilegroup_bt->draw();
691 if(!cur_tilegroup.empty())
692 tilegroups_map[cur_tilegroup]->draw();
693 le_tilemap_panel->draw();
695 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
696 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
698 white_small_text->draw("F1 for Help", 10, 430, 1);
702 if(show_menu == false)
703 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
705 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
712 unsigned int y,x,i,s;
715 /* Draw the real background */
716 if(le_current_level->bkgd_image[0] != '\0')
719 le_current_level->img_bkgd->draw_part(s,0,0,0,
720 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
721 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
722 le_current_level->img_bkgd->h);
726 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
729 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
731 for (y = 0; y < 15; ++y)
732 for (x = 0; x < 20; ++x)
735 if(active_tm == TM_BG)
740 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
742 if(active_tm == TM_IA)
747 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
749 if(active_tm == TM_FG)
754 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
756 /* draw whats inside stuff when cursor is selecting those */
757 /* (draw them all the time - is this the right behaviour?) */
758 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
759 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);
763 /* Draw the Bad guys: */
764 for (i = 0; i < le_world.bad_guys.size(); ++i)
766 /* to support frames: img_bsod_left[(frame / 5) % 4] */
769 le_world.bad_guys[i].draw();
773 /* Draw the player: */
774 /* for now, the position is fixed at (100, 240) */
775 tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
778 void le_checkevents()
785 keymod = SDL_GetModState();
787 while(SDL_PollEvent(&event))
789 current_menu->event(event);
791 mouse_cursor->set_state(MC_NORMAL);
793 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
794 if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
795 event.motion.y > 0 && event.motion.y < screen->h)))
799 case SDL_QUIT: // window closed
800 printf("window closed\n");
803 case SDL_KEYDOWN: // key pressed
804 key = event.key.keysym.sym;
809 cursor_x -= KEY_CURSOR_SPEED;
811 cursor_x -= KEY_CURSOR_FASTSPEED;
813 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
814 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
819 cursor_x += KEY_CURSOR_SPEED;
821 cursor_x += KEY_CURSOR_FASTSPEED;
823 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
824 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
829 cursor_y -= KEY_CURSOR_SPEED;
831 cursor_y -= KEY_CURSOR_FASTSPEED;
838 cursor_y += KEY_CURSOR_SPEED;
840 cursor_y += KEY_CURSOR_FASTSPEED;
842 if(cursor_y > screen->h-32)
843 cursor_y = screen->h-32;
856 cursor_x = (le_current_level->width * 32) - 32;
860 le_show_grid = !le_show_grid;
866 case SDL_KEYUP: /* key released */
867 switch(event.key.keysym.sym)
876 case SDL_MOUSEBUTTONDOWN:
877 if(event.button.button == SDL_BUTTON_LEFT)
879 le_mouse_pressed[LEFT] = true;
881 selection.x1 = event.motion.x + pos_x;
882 selection.y1 = event.motion.y;
883 selection.x2 = event.motion.x + pos_x;
884 selection.y2 = event.motion.y;
886 else if(event.button.button == SDL_BUTTON_RIGHT)
888 le_mouse_pressed[RIGHT] = true;
891 case SDL_MOUSEBUTTONUP:
892 if(event.button.button == SDL_BUTTON_LEFT)
893 le_mouse_pressed[LEFT] = false;
894 else if(event.button.button == SDL_BUTTON_RIGHT)
895 le_mouse_pressed[RIGHT] = false;
897 case SDL_MOUSEMOTION:
903 cursor_x = ((int)(pos_x + x) / 32) * 32;
904 cursor_y = ((int) y / 32) * 32;
906 if(le_mouse_pressed[LEFT])
908 selection.x2 = x + pos_x;
912 if(le_mouse_pressed[RIGHT])
914 pos_x += -1 * event.motion.xrel;
923 if(le_current_level != NULL)
925 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 &&
926 event.motion.y > 0 && event.motion.y < screen->h)))
928 le_mouse_pressed[LEFT] = false;
929 le_mouse_pressed[RIGHT] = false;
931 if(show_menu == false)
933 /* Check for button events */
934 le_test_level_bt->event(event);
935 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
937 le_save_level_bt->event(event);
938 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
939 le_current_level->save(le_level_subset.name.c_str(),le_level);
940 le_exit_bt->event(event);
941 if(le_exit_bt->get_state() == BUTTON_CLICKED)
943 Menu::set_current(leveleditor_menu);
946 le_next_level_bt->event(event);
947 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
949 if(le_level < le_level_subset.levels)
951 le_goto_level(++le_level);
958 sprintf(str,"Level %d doesn't exist.",le_level+1);
959 white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
960 white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
961 red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
965 while(SDL_PollEvent(&event))
968 case SDL_KEYDOWN: // key pressed
969 switch(event.key.keysym.sym)
972 new_lev.init_defaults();
973 new_lev.save(le_level_subset.name.c_str(),++le_level);
974 le_level_subset.levels = le_level;
975 le_goto_level(le_level);
992 le_previous_level_bt->event(event);
993 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
996 le_goto_level(--le_level);
998 le_rubber_bt->event(event);
999 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1000 le_current_tile = 0;
1001 le_select_mode_one_bt->event(event);
1002 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1003 le_selection_mode = CURSOR;
1004 le_select_mode_two_bt->event(event);
1005 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1006 le_selection_mode = SQUARE;
1008 le_tilegroup_bt->event(event);
1009 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1011 Menu::set_current(select_tilegroup_menu);
1012 select_tilegroup_menu_effect.start(200);
1013 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1017 le_settings_bt->event(event);
1018 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1020 update_level_settings_menu();
1021 Menu::set_current(level_settings_menu);
1024 if(!cur_tilegroup.empty())
1025 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1027 if(pbutton->get_state() == BUTTON_CLICKED)
1029 le_current_tile = pbutton->get_tag();
1032 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1034 if(pbutton->get_state() == BUTTON_CLICKED)
1036 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1042 le_settings_bt->event(event);
1043 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1045 Menu::set_current(leveleditor_menu);
1048 le_tilegroup_bt->event(event);
1049 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1051 Menu::set_current(leveleditor_menu);
1056 if(show_menu == false)
1058 le_move_left_bt->event(event);
1059 le_move_right_bt->event(event);
1061 if(le_mouse_pressed[LEFT])
1063 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1068 if(show_menu == false)
1070 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1074 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1079 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1083 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1091 void le_highlight_selection()
1095 if(selection.x1 < selection.x2)
1105 if(selection.y1 < selection.y2)
1121 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1124 void le_change(float x, float y, int tm, unsigned int c)
1126 if(le_current_level != NULL)
1132 /* level_changed = true; */
1134 switch(le_selection_mode)
1137 le_current_level->change(x,y,tm,c);
1142 /* if there is a bad guy over there, remove it */
1143 for(i = 0; i < le_world.bad_guys.size(); ++i)
1144 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1145 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1147 if(c == '0') /* if it's a bad guy */
1148 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1150 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1152 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1156 if(selection.x1 < selection.x2)
1166 if(selection.y1 < selection.y2)
1182 /* if there is a bad guy over there, remove it */
1183 for(i = 0; i < le_world.bad_guys.size(); ++i)
1184 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1185 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1186 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1188 for(xx = x1; xx <= x2; xx++)
1189 for(yy = y1; yy <= y2; yy++)
1191 le_current_level->change(xx*32, yy*32, tm, c);
1193 if(c == '0') // if it's a bad guy
1194 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1196 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1198 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1209 le_current_level->save("test", le_level);
1211 GameSession session("test",le_level, ST_GL_TEST);
1214 Menu::set_current(leveleditor_menu);
1215 le_world.arrays_free();
1216 le_current_level->load_gfx();
1217 le_world.activate_bad_guys();
1223 unsigned int i, done_;
1225 " - This is SuperTux's built-in level editor -",
1226 "It has been designed to be light and easy to use from the start.",
1228 "When you first load the level editor you are given a menu where you",
1229 "can load level subsets, create a new level subset, edit the current",
1230 "subset's settings, or simply quit the editor. You can access this menu",
1231 "from the level editor at any time by pressing the escape key.",
1233 "To your right is your button bar. The center of this contains many",
1234 "tiles you can use to make your level. To select a tile, click on it",
1235 "with your left mouse button; your selection will be shown in the",
1236 "bottom right corner of the button box. Click anywhere on your level",
1237 "with the left mouse button to place that tile down. If you right click",
1238 "a tile in the button bar, you can find out what its keyboard shortcut",
1239 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1240 "background, and enemy tiles. The eraser lets you remove tiles.",
1241 "The left and right arrow keys scroll back and forth through your level.",
1242 "The button with the wrench and screwdriver, lets you change the",
1243 "settings of your level, including how long it is or what music it will",
1244 "play. When you are ready to give your level a test, click on the little",
1245 "running Tux. If you like the changes you have made to your level,",
1246 "press the red save key to keep them.",
1247 "To change which level in your subset you are editing, press the white",
1248 "up and down arrow keys at the top of the button box.",
1250 "Have fun making levels! If you make some good ones, send them to us on",
1251 "the SuperTux mailing list!",
1256 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1258 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1259 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1261 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1269 done_ = wait_for_event(event);