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"
44 #include "music_manager.h"
46 /* definitions to aid development */
48 /* definitions that affect gameplay */
49 #define KEY_CURSOR_SPEED 32
50 #define KEY_CURSOR_FASTSPEED 64
52 /* when pagedown/up pressed speed:*/
53 #define PAGE_CURSOR_SPEED 13*32
55 #define MOUSE_LEFT_MARGIN 80
56 #define MOUSE_RIGHT_MARGIN (560-32)
57 /* right_margin should noticed that the cursor is 32 pixels,
58 so it should subtract that value */
59 #define MOUSE_POS_SPEED 20
62 #define SELECT_W 2 // size of the selections lines
63 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
65 /* own declerations */
66 /* crutial ones (main loop) */
70 void le_drawinterface();
71 void le_checkevents();
72 void le_change(float x, float y, int tm, unsigned int c);
75 void le_set_defaults(void);
76 void le_activate_bad_guys(void);
78 void le_highlight_selection();
80 void apply_level_settings_menu();
81 void update_subset_settings_menu();
82 void save_subset_settings_menu();
84 static Level* le_current_level;
86 struct LevelEditorWorld
88 std::vector<BadGuy> bad_guys;
89 void arrays_free(void)
94 void add_bad_guy(float x, float y, BadGuyKind kind)
96 bad_guys.push_back(BadGuy(x,y,kind, false /* stay_on_platform */));
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 LevelSubset 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 music_manager->halt_music();
177 while (SDL_PollEvent(&event))
182 last_time = SDL_GetTicks();
187 if(Menu::current() == select_tilegroup_menu)
189 if(select_tilegroup_menu_effect.check())
191 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
195 select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
198 if(le_current_level != NULL)
200 /* making events results to be in order */
203 if(pos_x > (le_current_level->width * 32) - screen->w)
204 pos_x = (le_current_level->width * 32) - screen->w;
210 clearscreen(0, 0, 0);
212 /* draw editor interface */
215 Menu* menu = Menu::current();
221 if(menu == leveleditor_menu)
223 switch (leveleditor_menu->check())
225 case MNID_RETURNLEVELEDITOR:
226 Menu::set_current(0);
228 case MNID_SUBSETSETTINGS:
229 update_subset_settings_menu();
231 case MNID_QUITLEVELEDITOR:
236 else if(menu == level_settings_menu)
238 switch (level_settings_menu->check())
240 case MNID_SUBSETSETTINGS:
241 apply_level_settings_menu();
242 Menu::set_current(leveleditor_menu);
250 else if(menu == select_tilegroup_menu)
253 switch (it = select_tilegroup_menu->check())
258 if(select_tilegroup_menu->item[it].kind == MN_ACTION)
259 cur_tilegroup = select_tilegroup_menu->item[it].text;
261 Menu::set_current(0);
266 else if(menu == subset_load_menu)
268 switch (i = subset_load_menu->check())
275 le_level_subset.load(level_subsets.item[i-2]);
276 leveleditor_menu->item[3].kind = MN_GOTO;
278 le_world.arrays_free();
279 le_current_level = new Level;
280 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
286 le_current_level->load_gfx();
287 le_world.activate_bad_guys();
290 Menu::set_current(leveleditor_menu);
295 else if(menu == subset_new_menu)
297 if(subset_new_menu->item[2].input[0] == '\0')
298 subset_new_menu->item[3].kind = MN_DEACTIVE;
301 subset_new_menu->item[3].kind = MN_ACTION;
303 switch (i = subset_new_menu->check())
306 LevelSubset::create(subset_new_menu->item[2].input);
307 le_level_subset.load(subset_new_menu->item[2].input);
308 leveleditor_menu->item[3].kind = MN_GOTO;
310 le_world.arrays_free();
311 le_current_level = new Level;
312 if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
318 le_current_level->load_gfx();
319 le_world.activate_bad_guys();
320 subset_new_menu->item[2].change_input("");
321 // FIXME:? show_menu = true;
322 Menu::set_current(leveleditor_menu);
327 else if(menu == subset_settings_menu)
329 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 )
330 subset_settings_menu->item[5].kind = MN_DEACTIVE;
332 subset_settings_menu->item[5].kind = MN_ACTION;
334 switch (i = subset_settings_menu->check())
337 save_subset_settings_menu();
338 //FIXME:show_menu = true;
339 Menu::set_current(leveleditor_menu);
345 mouse_cursor->draw();
353 ++global_frame_counter;
356 now_time = SDL_GetTicks();
357 if (now_time < last_time + FPS)
358 SDL_Delay(last_time + FPS - now_time); /* delay some time */
369 level_subsets = dsubdirs("/levels", "info");
375 /* level_changed = NO;*/
378 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
379 le_level_changed = false;
380 le_current_level = NULL;
383 le_mouse_pressed[LEFT] = false;
384 le_mouse_pressed[RIGHT] = false;
386 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
388 select_tilegroup_menu_effect.init(false);
391 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
392 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
393 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
394 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
395 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
396 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
397 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
398 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
399 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
400 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
401 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
402 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
404 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
405 le_tilemap_panel->set_button_size(32,10);
406 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
407 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
408 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
410 leveleditor_menu = new Menu();
411 subset_load_menu = new Menu();
412 subset_new_menu = new Menu();
413 subset_settings_menu = new Menu();
414 level_settings_menu = new Menu();
415 select_tilegroup_menu = new Menu();
417 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
418 leveleditor_menu->additem(MN_HL,"",0,0);
419 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
420 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
421 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
422 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
423 leveleditor_menu->additem(MN_HL,"",0,0);
424 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
426 Menu::set_current(leveleditor_menu);
428 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
429 subset_load_menu->additem(MN_HL, "", 0, 0);
431 for(i = 0; i < level_subsets.num_items; ++i)
433 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
435 subset_load_menu->additem(MN_HL,"",0,0);
436 subset_load_menu->additem(MN_BACK,"Back",0,0);
438 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
439 subset_new_menu->additem(MN_HL,"",0,0);
440 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
441 subset_new_menu->additem(MN_ACTION,"Create",0,0);
442 subset_new_menu->additem(MN_HL,"",0,0);
443 subset_new_menu->additem(MN_BACK,"Back",0,0);
445 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
446 subset_settings_menu->additem(MN_HL,"",0,0);
447 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
448 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
449 subset_settings_menu->additem(MN_HL,"",0,0);
450 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
451 subset_settings_menu->additem(MN_HL,"",0,0);
452 subset_settings_menu->additem(MN_BACK,"Back",0,0);
454 level_settings_menu->arrange_left = true;
455 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
456 level_settings_menu->additem(MN_HL,"",0,0);
457 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
458 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
459 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
460 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
461 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
462 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
463 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
464 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
465 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
466 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
467 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
468 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
469 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
470 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
471 level_settings_menu->additem(MN_HL,"",0,0);
472 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
474 select_tilegroup_menu->arrange_left = true;
475 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
476 select_tilegroup_menu->additem(MN_HL,"",0,0);
477 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
478 for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
481 select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
482 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
484 for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
485 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));
487 select_tilegroup_menu->additem(MN_HL,"",0,0);
489 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
494 void update_level_settings_menu()
499 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
500 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
501 sprintf(str,"%d",le_current_level->width);
503 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
504 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
505 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
506 string_list_add_item(level_settings_menu->item[6].list,"");
507 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
508 level_settings_menu->item[3].list->active_item = i;
509 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
510 level_settings_menu->item[4].list->active_item = i;
511 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
512 level_settings_menu->item[5].list->active_item = i;
514 level_settings_menu->item[7].change_input(str);
515 sprintf(str,"%d",le_current_level->time_left);
516 level_settings_menu->item[8].change_input(str);
517 sprintf(str,"%2.0f",le_current_level->gravity);
518 level_settings_menu->item[9].change_input(str);
519 sprintf(str,"%d",le_current_level->bkgd_top.red);
520 level_settings_menu->item[10].change_input(str);
521 sprintf(str,"%d",le_current_level->bkgd_top.green);
522 level_settings_menu->item[11].change_input(str);
523 sprintf(str,"%d",le_current_level->bkgd_top.blue);
524 level_settings_menu->item[12].change_input(str);
525 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
526 level_settings_menu->item[13].change_input(str);
527 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
528 level_settings_menu->item[14].change_input(str);
529 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
530 level_settings_menu->item[15].change_input(str);
533 void update_subset_settings_menu()
535 subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
536 subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
539 void apply_level_settings_menu()
544 le_current_level->name = level_settings_menu->item[2].input;
545 le_current_level->author = level_settings_menu->item[3].input;
547 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
549 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
553 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
555 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
561 le_current_level->free_gfx();
562 le_current_level->load_gfx();
565 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
567 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
568 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
569 le_current_level->gravity = atof(level_settings_menu->item[9].input);
570 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
571 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
572 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
573 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
574 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
575 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
578 void save_subset_settings_menu()
580 le_level_subset.title = subset_settings_menu->item[2].input;
581 le_level_subset.description = subset_settings_menu->item[3].input;
582 le_level_subset.save();
585 void le_goto_level(int levelnb)
587 le_world.arrays_free();
589 le_current_level->cleanup();
590 if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
592 le_current_level->load(le_level_subset.name.c_str(), le_level);
601 le_current_level->free_gfx();
602 le_current_level->load_gfx();
604 le_world.activate_bad_guys();
609 /*if(level_changed == true)
610 if(askforsaving() == CANCEL)
613 SDL_EnableKeyRepeat(0, 0); // disables key repeating
616 delete leveleditor_menu;
617 delete subset_load_menu;
618 delete subset_new_menu;
619 delete subset_settings_menu;
620 delete level_settings_menu;
621 delete select_tilegroup_menu;
622 delete le_save_level_bt;
624 delete le_test_level_bt;
625 delete le_next_level_bt;
626 delete le_previous_level_bt;
627 delete le_move_right_bt;
628 delete le_move_left_bt;
630 delete le_select_mode_one_bt;
631 delete le_select_mode_two_bt;
632 delete le_settings_bt;
633 delete le_tilegroup_bt;
634 delete le_tilemap_panel;
636 if(le_current_level != NULL)
638 le_current_level->free_gfx();
639 le_current_level->cleanup();
640 le_world.arrays_free();
644 void le_drawinterface()
649 if(le_current_level != NULL)
651 /* draw a grid (if selected) */
654 for(x = 0; x < 19; x++)
655 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
656 for(y = 0; y < 15; y++)
657 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
661 if(le_selection_mode == CURSOR)
662 le_selection->draw( cursor_x - pos_x, cursor_y);
663 else if(le_selection_mode == SQUARE)
666 le_highlight_selection();
667 /* draw current selection */
668 w = selection.x2 - selection.x1;
669 h = selection.y2 - selection.y1;
670 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
671 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
672 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
673 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
677 /* draw button bar */
678 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
679 Tile::draw(19 * 32, 14 * 32, le_current_tile);
681 if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
682 TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
684 if(le_current_level != NULL)
686 le_save_level_bt->draw();
688 le_test_level_bt->draw();
689 le_next_level_bt->draw();
690 le_previous_level_bt->draw();
691 le_rubber_bt->draw();
692 le_select_mode_one_bt->draw();
693 le_select_mode_two_bt->draw();
694 le_settings_bt->draw();
695 le_move_right_bt->draw();
696 le_move_left_bt->draw();
697 le_tilegroup_bt->draw();
698 if(!cur_tilegroup.empty())
699 tilegroups_map[cur_tilegroup]->draw();
700 le_tilemap_panel->draw();
702 sprintf(str, "%d/%d", le_level,le_level_subset.levels);
703 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
705 white_small_text->draw("F1 for Help", 10, 430, 1);
710 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
712 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
719 unsigned int y,x,i,s;
722 /* Draw the real background */
723 if(le_current_level->bkgd_image[0] != '\0')
726 le_current_level->img_bkgd->draw_part(s,0,0,0,
727 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
728 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
729 le_current_level->img_bkgd->h);
733 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
736 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
738 for (y = 0; y < 15; ++y)
739 for (x = 0; x < 20; ++x)
742 if(active_tm == TM_BG)
747 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
749 if(active_tm == TM_IA)
754 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
756 if(active_tm == TM_FG)
761 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
763 /* draw whats inside stuff when cursor is selecting those */
764 /* (draw them all the time - is this the right behaviour?) */
765 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
766 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);
770 /* Draw the Bad guys: */
771 for (i = 0; i < le_world.bad_guys.size(); ++i)
773 /* to support frames: img_bsod_left[(frame / 5) % 4] */
776 le_world.bad_guys[i].draw();
780 /* Draw the player: */
781 /* for now, the position is fixed at (100, 240) */
782 largetux.walk_right->draw( 100 - pos_x, 240);
785 void le_checkevents()
792 keymod = SDL_GetModState();
794 while(SDL_PollEvent(&event))
798 Menu::current()->event(event);
802 mouse_cursor->set_state(MC_NORMAL);
804 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
805 if(event.type == SDL_KEYDOWN
806 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
807 && (event.motion.x > 0
808 && event.motion.x < screen->w - 64 &&
809 event.motion.y > 0 && event.motion.y < screen->h)))
813 case SDL_KEYDOWN: // key pressed
814 key = event.key.keysym.sym;
818 Menu::set_current(leveleditor_menu);
821 cursor_x -= KEY_CURSOR_SPEED;
823 cursor_x -= KEY_CURSOR_FASTSPEED;
825 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
826 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
831 cursor_x += KEY_CURSOR_SPEED;
833 cursor_x += KEY_CURSOR_FASTSPEED;
835 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
836 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
841 cursor_y -= KEY_CURSOR_SPEED;
843 cursor_y -= KEY_CURSOR_FASTSPEED;
850 cursor_y += KEY_CURSOR_SPEED;
852 cursor_y += KEY_CURSOR_FASTSPEED;
854 if(cursor_y > screen->h-32)
855 cursor_y = screen->h-32;
868 cursor_x = (le_current_level->width * 32) - 32;
872 le_show_grid = !le_show_grid;
878 case SDL_KEYUP: /* key released */
879 switch(event.key.keysym.sym)
888 case SDL_MOUSEBUTTONDOWN:
889 if(event.button.button == SDL_BUTTON_LEFT)
891 le_mouse_pressed[LEFT] = true;
893 selection.x1 = event.motion.x + pos_x;
894 selection.y1 = event.motion.y;
895 selection.x2 = event.motion.x + pos_x;
896 selection.y2 = event.motion.y;
898 else if(event.button.button == SDL_BUTTON_RIGHT)
900 le_mouse_pressed[RIGHT] = true;
903 case SDL_MOUSEBUTTONUP:
904 if(event.button.button == SDL_BUTTON_LEFT)
905 le_mouse_pressed[LEFT] = false;
906 else if(event.button.button == SDL_BUTTON_RIGHT)
907 le_mouse_pressed[RIGHT] = false;
909 case SDL_MOUSEMOTION:
916 cursor_x = ((int)(pos_x + x) / 32) * 32;
917 cursor_y = ((int) y / 32) * 32;
919 if(le_mouse_pressed[LEFT])
921 selection.x2 = x + pos_x;
925 if(le_mouse_pressed[RIGHT])
927 pos_x += -1 * event.motion.xrel;
931 case SDL_QUIT: // window closed
940 if(le_current_level != NULL)
942 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 &&
943 event.motion.y > 0 && event.motion.y < screen->h)))
945 le_mouse_pressed[LEFT] = false;
946 le_mouse_pressed[RIGHT] = false;
950 /* Check for button events */
951 le_test_level_bt->event(event);
952 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
954 le_save_level_bt->event(event);
955 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
956 le_current_level->save(le_level_subset.name.c_str(),le_level);
957 le_exit_bt->event(event);
958 if(le_exit_bt->get_state() == BUTTON_CLICKED)
960 Menu::set_current(leveleditor_menu);
962 le_next_level_bt->event(event);
963 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
965 if(le_level < le_level_subset.levels)
967 le_goto_level(++le_level);
973 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
974 if(confirm_dialog(str))
976 new_lev.init_defaults();
977 new_lev.save(le_level_subset.name.c_str(),++le_level);
978 le_level_subset.levels = le_level;
979 le_goto_level(le_level);
983 le_previous_level_bt->event(event);
984 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
987 le_goto_level(--le_level);
989 le_rubber_bt->event(event);
990 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
992 le_select_mode_one_bt->event(event);
993 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
994 le_selection_mode = CURSOR;
995 le_select_mode_two_bt->event(event);
996 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
997 le_selection_mode = SQUARE;
999 le_tilegroup_bt->event(event);
1000 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1002 Menu::set_current(select_tilegroup_menu);
1003 select_tilegroup_menu_effect.start(200);
1004 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1007 le_settings_bt->event(event);
1008 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1010 update_level_settings_menu();
1011 Menu::set_current(level_settings_menu);
1013 if(!cur_tilegroup.empty())
1014 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1016 if(pbutton->get_state() == BUTTON_CLICKED)
1018 le_current_tile = pbutton->get_tag();
1021 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1023 if(pbutton->get_state() == BUTTON_CLICKED)
1025 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1031 le_settings_bt->event(event);
1032 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1034 Menu::set_current(0);
1036 le_tilegroup_bt->event(event);
1037 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1039 Menu::set_current(0);
1044 if(!Menu::current())
1046 le_move_left_bt->event(event);
1047 le_move_right_bt->event(event);
1049 if(le_mouse_pressed[LEFT])
1051 le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1056 if(!Menu::current())
1058 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1062 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1067 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1071 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1079 void le_highlight_selection()
1083 if(selection.x1 < selection.x2)
1093 if(selection.y1 < selection.y2)
1109 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1112 void le_change(float x, float y, int tm, unsigned int c)
1114 if(le_current_level != NULL)
1120 /* level_changed = true; */
1122 switch(le_selection_mode)
1125 le_current_level->change(x,y,tm,c);
1130 /* if there is a bad guy over there, remove it */
1131 for(i = 0; i < le_world.bad_guys.size(); ++i)
1132 if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1133 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1135 if(c == '0') /* if it's a bad guy */
1136 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1138 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1140 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1144 if(selection.x1 < selection.x2)
1154 if(selection.y1 < selection.y2)
1170 /* if there is a bad guy over there, remove it */
1171 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1172 i != le_world.bad_guys.end(); /* will be at end of loop */) {
1173 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1174 && i->base.y/32 >= y1 && i->base.y/32 <= y2) {
1175 i = le_world.bad_guys.erase(i);
1182 for(xx = x1; xx <= x2; xx++)
1183 for(yy = y1; yy <= y2; yy++)
1185 le_current_level->change(xx*32, yy*32, tm, c);
1187 if(c == '0') // if it's a bad guy
1188 le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1190 le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1192 le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1203 le_current_level->save("test", le_level);
1205 GameSession session("test",le_level, ST_GL_TEST);
1208 music_manager->halt_music();
1210 Menu::set_current(leveleditor_menu);
1211 le_world.arrays_free();
1212 le_current_level->load_gfx();
1213 le_world.activate_bad_guys();
1219 unsigned int i, done_;
1221 " - This is SuperTux's built-in level editor -",
1222 "It has been designed to be light and easy to use from the start.",
1224 "When you first load the level editor you are given a menu where you",
1225 "can load level subsets, create a new level subset, edit the current",
1226 "subset's settings, or simply quit the editor. You can access this menu",
1227 "from the level editor at any time by pressing the escape key.",
1229 "To your right is your button bar. The center of this contains many",
1230 "tiles you can use to make your level. To select a tile, click on it",
1231 "with your left mouse button; your selection will be shown in the",
1232 "bottom right corner of the button box. Click anywhere on your level",
1233 "with the left mouse button to place that tile down. If you right click",
1234 "a tile in the button bar, you can find out what its keyboard shortcut",
1235 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1236 "background, and enemy tiles. The eraser lets you remove tiles.",
1237 "The left and right arrow keys scroll back and forth through your level.",
1238 "The button with the wrench and screwdriver, lets you change the",
1239 "settings of your level, including how long it is or what music it will",
1240 "play. When you are ready to give your level a test, click on the little",
1241 "running Tux. If you like the changes you have made to your level,",
1242 "press the red save key to keep them.",
1243 "To change which level in your subset you are editing, press the white",
1244 "up and down arrow keys at the top of the button box.",
1246 "Have fun making levels! If you make some good ones, send them to us on",
1247 "the SuperTux mailing list!",
1252 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1254 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1255 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1257 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1265 done_ = wait_for_event(event);