4 // Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
5 // Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <SDL_image.h>
30 #include "leveleditor.h"
43 #include "resources.h"
45 /* definitions to aid development */
47 /* definitions that affect gameplay */
48 #define KEY_CURSOR_SPEED 32
49 #define KEY_CURSOR_FASTSPEED 64
51 /* when pagedown/up pressed speed:*/
52 #define PAGE_CURSOR_SPEED 13*32
54 #define MOUSE_LEFT_MARGIN 80
55 #define MOUSE_RIGHT_MARGIN (560-32)
56 /* right_margin should noticed that the cursor is 32 pixels,
57 so it should subtract that value */
58 #define MOUSE_POS_SPEED 20
61 #define SELECT_W 2 // size of the selections lines
62 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
64 /* own declerations */
65 /* crutial ones (main loop) */
69 void le_drawinterface();
70 void le_checkevents();
71 void le_change(float x, float y, int tm, unsigned int c);
74 void le_set_defaults(void);
75 void le_activate_bad_guys(void);
77 void le_highlight_selection();
79 void apply_level_settings_menu();
80 void update_subset_settings_menu();
81 void save_subset_settings_menu();
83 static Level* le_current_level;
85 struct LevelEditorWorld
87 std::vector<BadGuy> bad_guys;
88 void arrays_free(void)
93 void add_bad_guy(float x, float y, BadGuyKind kind)
95 bad_guys.push_back(BadGuy(x,y,kind, false /* stay_on_platform */));
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(Menu::current() == 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 */
212 Menu* menu = Menu::current();
218 if(menu == leveleditor_menu)
220 switch (leveleditor_menu->check())
223 Menu::set_current(0);
226 update_subset_settings_menu();
233 else if(menu == level_settings_menu)
235 switch (level_settings_menu->check())
238 apply_level_settings_menu();
239 Menu::set_current(leveleditor_menu);
247 else if(menu == select_tilegroup_menu)
250 switch (it = select_tilegroup_menu->check())
255 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
256 cur_tilegroup = select_tilegroup_menu->item[it].text;
258 Menu::set_current(0);
263 else if(menu == subset_load_menu)
265 switch (i = subset_load_menu->check())
272 le_level_subset.load(level_subsets.item[i-2]);
273 leveleditor_menu->item[3].kind = MN_GOTO;
275 le_world.arrays_free();
276 le_current_level = new Level;
277 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
283 le_current_level->load_gfx();
284 le_world.activate_bad_guys();
287 Menu::set_current(leveleditor_menu);
292 else if(menu == subset_new_menu)
294 if(subset_new_menu->item[2].input[0] == '\0')
295 subset_new_menu->item[3].kind = MN_DEACTIVE;
298 subset_new_menu->item[3].kind = MN_ACTION;
300 switch (i = subset_new_menu->check())
303 st_subset::create(subset_new_menu->item[2].input);
304 le_level_subset.load(subset_new_menu->item[2].input);
305 leveleditor_menu->item[3].kind = MN_GOTO;
307 le_world.arrays_free();
308 le_current_level = new Level;
309 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
315 le_current_level->load_gfx();
316 le_world.activate_bad_guys();
317 subset_new_menu->item[2].change_input("");
318 // FIXME:? show_menu = true;
319 Menu::set_current(leveleditor_menu);
324 else if(menu == subset_settings_menu)
326 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 )
327 subset_settings_menu->item[5].kind = MN_DEACTIVE;
329 subset_settings_menu->item[5].kind = MN_ACTION;
331 switch (i = subset_settings_menu->check())
334 save_subset_settings_menu();
335 //FIXME:show_menu = true;
336 Menu::set_current(leveleditor_menu);
342 mouse_cursor->draw();
350 ++global_frame_counter;
353 now_time = SDL_GetTicks();
354 if (now_time < last_time + FPS)
355 SDL_Delay(last_time + FPS - now_time); /* delay some time */
366 level_subsets = dsubdirs("/levels", "info");
372 /* level_changed = NO;*/
375 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
376 le_level_changed = false;
377 le_current_level = NULL;
380 le_mouse_pressed[LEFT] = false;
381 le_mouse_pressed[RIGHT] = false;
383 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
385 select_tilegroup_menu_effect.init(false);
388 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
389 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
390 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
391 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
392 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
393 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
394 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
395 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
396 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
397 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
398 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
399 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
401 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
402 le_tilemap_panel->set_button_size(32,10);
403 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
404 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
405 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
407 leveleditor_menu = new Menu();
408 subset_load_menu = new Menu();
409 subset_new_menu = new Menu();
410 subset_settings_menu = new Menu();
411 level_settings_menu = new Menu();
412 select_tilegroup_menu = new Menu();
414 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
415 leveleditor_menu->additem(MN_HL,"",0,0);
416 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
417 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
418 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
419 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
420 leveleditor_menu->additem(MN_HL,"",0,0);
421 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
423 Menu::set_current(leveleditor_menu);
425 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
426 subset_load_menu->additem(MN_HL, "", 0, 0);
428 for(i = 0; i < level_subsets.num_items; ++i)
430 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
432 subset_load_menu->additem(MN_HL,"",0,0);
433 subset_load_menu->additem(MN_BACK,"Back",0,0);
435 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
436 subset_new_menu->additem(MN_HL,"",0,0);
437 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
438 subset_new_menu->additem(MN_ACTION,"Create",0,0);
439 subset_new_menu->additem(MN_HL,"",0,0);
440 subset_new_menu->additem(MN_BACK,"Back",0,0);
442 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
443 subset_settings_menu->additem(MN_HL,"",0,0);
444 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
445 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
446 subset_settings_menu->additem(MN_HL,"",0,0);
447 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
448 subset_settings_menu->additem(MN_HL,"",0,0);
449 subset_settings_menu->additem(MN_BACK,"Back",0,0);
451 level_settings_menu->arrange_left = true;
452 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
453 level_settings_menu->additem(MN_HL,"",0,0);
454 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
455 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
456 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
457 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
458 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
459 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
460 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
461 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
462 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
463 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
464 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
465 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
466 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
467 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
468 level_settings_menu->additem(MN_HL,"",0,0);
469 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
471 select_tilegroup_menu->arrange_left = true;
472 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
473 select_tilegroup_menu->additem(MN_HL,"",0,0);
474 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
475 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
478 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
479 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
481 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
482 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));
484 select_tilegroup_menu->additem(MN_HL,"",0,0);
486 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
491 void update_level_settings_menu()
496 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
497 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
498 sprintf(str,"%d",le_current_level->width);
500 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
501 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
502 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
503 string_list_add_item(level_settings_menu->item[6].list,"");
504 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
505 level_settings_menu->item[3].list->active_item = i;
506 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
507 level_settings_menu->item[4].list->active_item = i;
508 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
509 level_settings_menu->item[5].list->active_item = i;
511 level_settings_menu->item[7].change_input(str);
512 sprintf(str,"%d",le_current_level->time_left);
513 level_settings_menu->item[8].change_input(str);
514 sprintf(str,"%2.0f",le_current_level->gravity);
515 level_settings_menu->item[9].change_input(str);
516 sprintf(str,"%d",le_current_level->bkgd_top.red);
517 level_settings_menu->item[10].change_input(str);
518 sprintf(str,"%d",le_current_level->bkgd_top.green);
519 level_settings_menu->item[11].change_input(str);
520 sprintf(str,"%d",le_current_level->bkgd_top.blue);
521 level_settings_menu->item[12].change_input(str);
522 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
523 level_settings_menu->item[13].change_input(str);
524 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
525 level_settings_menu->item[14].change_input(str);
526 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
527 level_settings_menu->item[15].change_input(str);
530 void update_subset_settings_menu()
532 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
533 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
536 void apply_level_settings_menu()
541 le_current_level->name = level_settings_menu->item[2].input;
542 le_current_level->author = level_settings_menu->item[3].input;
544 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
546 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
550 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
552 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
558 le_current_level->free_gfx();
559 le_current_level->load_gfx();
562 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
564 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
565 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
566 le_current_level->gravity = atof(level_settings_menu->item[9].input);
567 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
568 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
569 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
570 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
571 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
572 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
575 void save_subset_settings_menu()
577 le_level_subset.title = subset_settings_menu->item[2].input;
578 le_level_subset.description = subset_settings_menu->item[3].input;
579 le_level_subset.save();
582 void le_goto_level(int levelnb)
584 le_world.arrays_free();
586 le_current_level->cleanup();
587 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
589 le_current_level->load(le_level_subset.name.c_str(), le_level);
598 le_current_level->free_gfx();
599 le_current_level->load_gfx();
601 le_world.activate_bad_guys();
606 /*if(level_changed == true)
607 if(askforsaving() == CANCEL)
610 SDL_EnableKeyRepeat(0, 0); // disables key repeating
613 delete leveleditor_menu;
614 delete subset_load_menu;
615 delete subset_new_menu;
616 delete subset_settings_menu;
617 delete level_settings_menu;
618 delete select_tilegroup_menu;
619 delete le_save_level_bt;
621 delete le_test_level_bt;
622 delete le_next_level_bt;
623 delete le_previous_level_bt;
624 delete le_move_right_bt;
625 delete le_move_left_bt;
627 delete le_select_mode_one_bt;
628 delete le_select_mode_two_bt;
629 delete le_settings_bt;
630 delete le_tilegroup_bt;
631 delete le_tilemap_panel;
633 if(le_current_level != NULL)
635 le_current_level->free_gfx();
636 le_current_level->cleanup();
637 le_world.arrays_free();
641 void le_drawinterface()
646 if(le_current_level != NULL)
648 /* draw a grid (if selected) */
651 for(x = 0; x < 19; x++)
652 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
653 for(y = 0; y < 15; y++)
654 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
658 if(le_selection_mode == CURSOR)
659 le_selection->draw( cursor_x - pos_x, cursor_y);
660 else if(le_selection_mode == SQUARE)
663 le_highlight_selection();
664 /* draw current selection */
665 w = selection.x2 - selection.x1;
666 h = selection.y2 - selection.y1;
667 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
668 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
669 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
670 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
674 /* draw button bar */
675 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
676 Tile::draw(19 * 32, 14 * 32, le_current_tile);
678 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
679 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
681 if(le_current_level != NULL)
683 le_save_level_bt->draw();
685 le_test_level_bt->draw();
686 le_next_level_bt->draw();
687 le_previous_level_bt->draw();
688 le_rubber_bt->draw();
689 le_select_mode_one_bt->draw();
690 le_select_mode_two_bt->draw();
691 le_settings_bt->draw();
692 le_move_right_bt->draw();
693 le_move_left_bt->draw();
694 le_tilegroup_bt->draw();
695 if(!cur_tilegroup.empty())
696 tilegroups_map[cur_tilegroup]->draw();
697 le_tilemap_panel->draw();
699 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
700 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
702 white_small_text->draw("F1 for Help", 10, 430, 1);
707 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
709 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
716 unsigned int y,x,i,s;
719 /* Draw the real background */
720 if(le_current_level->bkgd_image[0] != '\0')
723 le_current_level->img_bkgd->draw_part(s,0,0,0,
724 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
725 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
726 le_current_level->img_bkgd->h);
730 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
733 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
735 for (y = 0; y < 15; ++y)
736 for (x = 0; x < 20; ++x)
739 if(active_tm == TM_BG)
744 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
746 if(active_tm == TM_IA)
751 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
753 if(active_tm == TM_FG)
758 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
760 /* draw whats inside stuff when cursor is selecting those */
761 /* (draw them all the time - is this the right behaviour?) */
762 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
763 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);
767 /* Draw the Bad guys: */
768 for (i = 0; i < le_world.bad_guys.size(); ++i)
770 /* to support frames: img_bsod_left[(frame / 5) % 4] */
773 le_world.bad_guys[i].draw();
777 /* Draw the player: */
778 /* for now, the position is fixed at (100, 240) */
779 tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
782 void le_checkevents()
789 keymod = SDL_GetModState();
791 while(SDL_PollEvent(&event))
795 Menu::current()->event(event);
799 mouse_cursor->set_state(MC_NORMAL);
801 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
802 if(event.type == SDL_KEYDOWN
803 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
804 && (event.motion.x > 0
805 && event.motion.x < screen->w - 64 &&
806 event.motion.y > 0 && event.motion.y < screen->h)))
810 case SDL_KEYDOWN: // key pressed
811 key = event.key.keysym.sym;
815 Menu::set_current(leveleditor_menu);
818 cursor_x -= KEY_CURSOR_SPEED;
820 cursor_x -= KEY_CURSOR_FASTSPEED;
822 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
823 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
828 cursor_x += KEY_CURSOR_SPEED;
830 cursor_x += KEY_CURSOR_FASTSPEED;
832 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
833 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
838 cursor_y -= KEY_CURSOR_SPEED;
840 cursor_y -= KEY_CURSOR_FASTSPEED;
847 cursor_y += KEY_CURSOR_SPEED;
849 cursor_y += KEY_CURSOR_FASTSPEED;
851 if(cursor_y > screen->h-32)
852 cursor_y = screen->h-32;
865 cursor_x = (le_current_level->width * 32) - 32;
869 le_show_grid = !le_show_grid;
875 case SDL_KEYUP: /* key released */
876 switch(event.key.keysym.sym)
885 case SDL_MOUSEBUTTONDOWN:
886 if(event.button.button == SDL_BUTTON_LEFT)
888 le_mouse_pressed[LEFT] = true;
890 selection.x1 = event.motion.x + pos_x;
891 selection.y1 = event.motion.y;
892 selection.x2 = event.motion.x + pos_x;
893 selection.y2 = event.motion.y;
895 else if(event.button.button == SDL_BUTTON_RIGHT)
897 le_mouse_pressed[RIGHT] = true;
900 case SDL_MOUSEBUTTONUP:
901 if(event.button.button == SDL_BUTTON_LEFT)
902 le_mouse_pressed[LEFT] = false;
903 else if(event.button.button == SDL_BUTTON_RIGHT)
904 le_mouse_pressed[RIGHT] = false;
906 case SDL_MOUSEMOTION:
913 cursor_x = ((int)(pos_x + x) / 32) * 32;
914 cursor_y = ((int) y / 32) * 32;
916 if(le_mouse_pressed[LEFT])
918 selection.x2 = x + pos_x;
922 if(le_mouse_pressed[RIGHT])
924 pos_x += -1 * event.motion.xrel;
928 case SDL_QUIT: // window closed
937 if(le_current_level != NULL)
939 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 &&
940 event.motion.y > 0 && event.motion.y < screen->h)))
942 le_mouse_pressed[LEFT] = false;
943 le_mouse_pressed[RIGHT] = false;
947 /* Check for button events */
948 le_test_level_bt->event(event);
949 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
951 le_save_level_bt->event(event);
952 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
953 le_current_level->save(le_level_subset.name.c_str(),le_level);
954 le_exit_bt->event(event);
955 if(le_exit_bt->get_state() == BUTTON_CLICKED)
957 Menu::set_current(leveleditor_menu);
959 le_next_level_bt->event(event);
960 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
962 if(le_level < le_level_subset.levels)
964 le_goto_level(++le_level);
971 sprintf(str,"Level %d doesn't exist.",le_level+1);
972 white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
973 white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
974 red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
978 while(SDL_PollEvent(&event))
981 case SDL_KEYDOWN: // key pressed
982 switch(event.key.keysym.sym)
985 new_lev.init_defaults();
986 new_lev.save(le_level_subset.name.c_str(),++le_level);
987 le_level_subset.levels = le_level;
988 le_goto_level(le_level);
1005 le_previous_level_bt->event(event);
1006 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1009 le_goto_level(--le_level);
1011 le_rubber_bt->event(event);
1012 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1013 le_current_tile = 0;
1014 le_select_mode_one_bt->event(event);
1015 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1016 le_selection_mode = CURSOR;
1017 le_select_mode_two_bt->event(event);
1018 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1019 le_selection_mode = SQUARE;
1021 le_tilegroup_bt->event(event);
1022 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1024 Menu::set_current(select_tilegroup_menu);
1025 select_tilegroup_menu_effect.start(200);
1026 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1029 le_settings_bt->event(event);
1030 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1032 update_level_settings_menu();
1033 Menu::set_current(level_settings_menu);
1035 if(!cur_tilegroup.empty())
1036 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1038 if(pbutton->get_state() == BUTTON_CLICKED)
1040 le_current_tile = pbutton->get_tag();
1043 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1045 if(pbutton->get_state() == BUTTON_CLICKED)
1047 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1053 le_settings_bt->event(event);
1054 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1056 Menu::set_current(0);
1058 le_tilegroup_bt->event(event);
1059 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1061 Menu::set_current(0);
1066 if(!Menu::current())
1068 le_move_left_bt->event(event);
1069 le_move_right_bt->event(event);
1071 if(le_mouse_pressed[LEFT])
1073 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1078 if(!Menu::current())
1080 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1084 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1089 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1093 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1101 void le_highlight_selection()
1105 if(selection.x1 < selection.x2)
1115 if(selection.y1 < selection.y2)
1131 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1134 void le_change(float x, float y, int tm, unsigned int c)
1136 if(le_current_level != NULL)
1142 /* level_changed = true; */
1144 switch(le_selection_mode)
1147 le_current_level->change(x,y,tm,c);
1152 /* if there is a bad guy over there, remove it */
1153 for(i = 0; i < le_world.bad_guys.size(); ++i)
1154 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1155 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1157 if(c == '0') /* if it's a bad guy */
1158 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1160 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1162 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1166 if(selection.x1 < selection.x2)
1176 if(selection.y1 < selection.y2)
1192 /* if there is a bad guy over there, remove it */
1193 for(i = 0; i < le_world.bad_guys.size(); ++i)
1194 if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1195 && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1196 le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1198 for(xx = x1; xx <= x2; xx++)
1199 for(yy = y1; yy <= y2; yy++)
1201 le_current_level->change(xx*32, yy*32, tm, c);
1203 if(c == '0') // if it's a bad guy
1204 le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1206 le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1208 le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1219 le_current_level->save("test", le_level);
1221 GameSession session("test",le_level, ST_GL_TEST);
1224 Menu::set_current(leveleditor_menu);
1225 le_world.arrays_free();
1226 le_current_level->load_gfx();
1227 le_world.activate_bad_guys();
1233 unsigned int i, done_;
1235 " - This is SuperTux's built-in level editor -",
1236 "It has been designed to be light and easy to use from the start.",
1238 "When you first load the level editor you are given a menu where you",
1239 "can load level subsets, create a new level subset, edit the current",
1240 "subset's settings, or simply quit the editor. You can access this menu",
1241 "from the level editor at any time by pressing the escape key.",
1243 "To your right is your button bar. The center of this contains many",
1244 "tiles you can use to make your level. To select a tile, click on it",
1245 "with your left mouse button; your selection will be shown in the",
1246 "bottom right corner of the button box. Click anywhere on your level",
1247 "with the left mouse button to place that tile down. If you right click",
1248 "a tile in the button bar, you can find out what its keyboard shortcut",
1249 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1250 "background, and enemy tiles. The eraser lets you remove tiles.",
1251 "The left and right arrow keys scroll back and forth through your level.",
1252 "The button with the wrench and screwdriver, lets you change the",
1253 "settings of your level, including how long it is or what music it will",
1254 "play. When you are ready to give your level a test, click on the little",
1255 "running Tux. If you like the changes you have made to your level,",
1256 "press the red save key to keep them.",
1257 "To change which level in your subset you are editing, press the white",
1258 "up and down arrow keys at the top of the button box.",
1260 "Have fun making levels! If you make some good ones, send them to us on",
1261 "the SuperTux mailing list!",
1266 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1268 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1269 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1271 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1279 done_ = wait_for_event(event);