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);
112 TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
114 void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
115 void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
116 //Returns true for a tile
117 bool IsTile() { return is_tile; };
118 //Returns true for a GameObject
119 bool IsObject() { return !is_tile; };
121 bool is_tile; //true for tile (false for object)
126 /* leveleditor internals */
127 static string_list_type level_subsets;
128 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
129 static int pos_x, cursor_x, cursor_y, fire;
131 static LevelEditorWorld le_world;
132 static LevelSubset* le_level_subset;
133 static int le_show_grid;
135 static Surface* le_selection;
137 static TileOrObject le_current;
138 static bool le_mouse_pressed[2];
139 static Button* le_save_level_bt;
140 static Button* le_exit_bt;
141 static Button* le_test_level_bt;
142 static Button* le_next_level_bt;
143 static Button* le_previous_level_bt;
144 static Button* le_move_right_bt;
145 static Button* le_move_left_bt;
146 static Button* le_rubber_bt;
147 static Button* le_select_mode_one_bt;
148 static Button* le_select_mode_two_bt;
149 static Button* le_settings_bt;
150 static Button* le_tilegroup_bt;
151 static Button* le_objects_bt;
152 static ButtonPanel* le_tilemap_panel;
153 static Menu* leveleditor_menu;
154 static Menu* subset_load_menu;
155 static Menu* subset_new_menu;
156 static Menu* subset_settings_menu;
157 static Menu* level_settings_menu;
158 static Menu* select_tilegroup_menu;
159 static Menu* select_objects_menu;
160 static Timer select_tilegroup_menu_effect;
161 static Timer select_objects_menu_effect;
162 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
163 static ButtonPanelMap tilegroups_map;
164 static ButtonPanelMap objects_map;
165 static std::string cur_tilegroup;
166 static std::string cur_objects;
168 static square selection;
169 static int le_selection_mode;
170 static SDL_Event event;
171 TileMapType active_tm;
173 // menu items for subset creation menu
178 void le_set_defaults()
180 if(le_current_level != NULL)
184 if(le_current_level->time_left == 0)
185 le_current_level->time_left = 255;
189 int leveleditor(int levelnb)
191 int last_time, now_time, i;
199 clearscreen(0, 0, 0);
202 music_manager->halt_music();
204 while (SDL_PollEvent(&event))
209 last_time = SDL_GetTicks();
214 if(Menu::current() == select_tilegroup_menu)
216 if(select_tilegroup_menu_effect.check())
218 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
222 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
224 else if(Menu::current() == select_objects_menu)
226 if(select_objects_menu_effect.check())
228 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
231 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
234 if(le_current_level != NULL)
236 /* making events results to be in order */
239 if(pos_x > (le_current_level->width * 32) - screen->w)
240 pos_x = (le_current_level->width * 32) - screen->w;
246 clearscreen(0, 0, 0);
248 /* draw editor interface */
251 Menu* menu = Menu::current();
257 if(menu == leveleditor_menu)
259 switch (leveleditor_menu->check())
261 case MNID_RETURNLEVELEDITOR:
262 Menu::set_current(0);
264 case MNID_SUBSETSETTINGS:
265 update_subset_settings_menu();
267 case MNID_QUITLEVELEDITOR:
272 else if(menu == level_settings_menu)
274 switch (level_settings_menu->check())
276 case MNID_SUBSETSETTINGS:
277 apply_level_settings_menu();
278 Menu::set_current(leveleditor_menu);
286 else if(menu == select_tilegroup_menu)
289 switch (it = select_tilegroup_menu->check())
295 = select_tilegroup_menu->get_item_by_id(it).text;
296 Menu::set_current(0);
303 else if(menu == select_objects_menu)
306 switch (it = select_objects_menu->check())
311 cur_objects = select_objects_menu->get_item_by_id(it).text;
312 cur_tilegroup.clear();
314 Menu::set_current(0);
319 else if(menu == subset_load_menu)
321 switch (i = subset_load_menu->check())
328 le_level_subset->load(level_subsets.item[i-1]);
329 leveleditor_menu->item[3].kind = MN_GOTO;
331 le_world.arrays_free();
332 delete le_current_level;
333 le_current_level = new Level;
334 if(le_current_level->load(le_level_subset->name, le_level) != 0)
340 le_current_level->load_gfx();
341 le_world.activate_bad_guys();
344 Menu::set_current(leveleditor_menu);
349 else if(menu == subset_new_menu)
351 if(subset_new_menu->item[2].input[0] == '\0')
352 subset_new_menu->item[3].kind = MN_DEACTIVE;
355 subset_new_menu->item[3].kind = MN_ACTION;
357 switch (i = subset_new_menu->check())
359 case MNID_CREATESUBSET:
360 LevelSubset::create(subset_new_menu->item[2].input);
361 le_level_subset->load(subset_new_menu->item[2].input);
362 leveleditor_menu->item[3].kind = MN_GOTO;
364 le_world.arrays_free();
365 delete le_current_level;
366 le_current_level = new Level;
367 if(le_current_level->load(le_level_subset->name, le_level) != 0)
373 le_current_level->load_gfx();
374 le_world.activate_bad_guys();
375 subset_new_menu->item[2].change_input("");
376 // FIXME:? show_menu = true;
377 Menu::set_current(leveleditor_menu);
382 else if(menu == subset_settings_menu)
384 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 )
385 subset_settings_menu->item[5].kind = MN_DEACTIVE;
387 subset_settings_menu->item[5].kind = MN_ACTION;
389 switch (i = subset_settings_menu->check())
392 save_subset_settings_menu();
393 //FIXME:show_menu = true;
394 Menu::set_current(leveleditor_menu);
400 mouse_cursor->draw();
408 ++global_frame_counter;
411 now_time = SDL_GetTicks();
412 if (now_time < last_time + FPS)
413 SDL_Delay(last_time + FPS - now_time); /* delay some time */
426 leveleditor_menu = new Menu();
427 subset_load_menu = new Menu();
428 subset_new_menu = new Menu();
429 subset_settings_menu = new Menu();
430 level_settings_menu = new Menu();
431 select_tilegroup_menu = new Menu();
432 select_objects_menu = new Menu();
434 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
435 leveleditor_menu->additem(MN_HL,"",0,0);
436 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
437 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
438 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
439 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
440 leveleditor_menu->additem(MN_HL,"",0,0);
441 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
443 Menu::set_current(leveleditor_menu);
445 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
446 subset_load_menu->additem(MN_HL, "", 0, 0);
448 for(i = 0; i < level_subsets.num_items; ++i)
450 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
452 subset_load_menu->additem(MN_HL,"",0,0);
453 subset_load_menu->additem(MN_BACK,"Back",0,0);
455 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
456 subset_new_menu->additem(MN_HL,"",0,0);
457 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
458 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
459 subset_new_menu->additem(MN_HL,"",0,0);
460 subset_new_menu->additem(MN_BACK,"Back",0,0);
462 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
463 subset_settings_menu->additem(MN_HL,"",0,0);
464 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
465 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
466 subset_settings_menu->additem(MN_HL,"",0,0);
467 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
468 subset_settings_menu->additem(MN_HL,"",0,0);
469 subset_settings_menu->additem(MN_BACK,"Back",0,0);
471 level_settings_menu->arrange_left = true;
472 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
473 level_settings_menu->additem(MN_HL,"",0,0);
474 level_settings_menu->additem(MN_TEXTFIELD,"Name ",0,0);
475 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0);
476 level_settings_menu->additem(MN_STRINGSELECT,"Theme ",0,0);
477 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0);
478 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
479 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
480 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0);
481 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
482 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0);
483 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0);
484 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0);
485 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
486 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
487 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
488 level_settings_menu->additem(MN_HL,"",0,0);
489 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
491 select_tilegroup_menu->arrange_left = true;
492 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
493 select_tilegroup_menu->additem(MN_HL,"",0,0);
494 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
496 for(std::vector<TileGroup>::iterator it = tilegroups->begin();
497 it != tilegroups->end(); ++it )
499 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
501 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
504 for(std::vector<int>::iterator sit = (*it).tiles.begin();
505 sit != (*it).tiles.end(); ++sit, ++i)
507 std::string imagefile = "/images/tilesets/" ;
508 imagefile += TileManager::instance()->get(*sit)->filenames[0];
509 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
511 tilegroups_map[it->name]->additem(button, *sit);
514 select_tilegroup_menu->additem(MN_HL,"",0,0);
516 select_objects_menu->arrange_left = true;
517 select_objects_menu->additem(MN_LABEL,"Select Objects",0,0);
518 select_objects_menu->additem(MN_HL,"",0,0);
519 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
520 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
522 for(int i = 0; i < NUM_BadGuyKinds; ++i)
524 BadGuy bad_tmp(0,0,BadGuyKind(i),false);
525 objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
526 objects_map["BadGuys"]->manipulate_button(i)->set_game_object(new BadGuy(objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,objects_map["BadGuys"]->manipulate_button(i)->get_pos().y,BadGuyKind(i),false));
529 select_objects_menu->additem(MN_HL,"",0,0);
535 level_subsets = dsubdirs("/levels", "info");
537 le_level_subset = new LevelSubset;
543 /* level_changed = NO;*/
546 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
547 le_level_changed = false;
548 le_current_level = NULL;
550 le_mouse_pressed[LEFT] = false;
551 le_mouse_pressed[RIGHT] = false;
553 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
555 select_tilegroup_menu_effect.init(false);
556 select_objects_menu_effect.init(false);
559 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
560 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
561 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
562 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
563 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
564 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
565 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
566 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
567 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
568 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
569 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
570 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
571 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
573 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
574 le_tilemap_panel->set_button_size(32,10);
575 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
576 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
577 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
581 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
586 void update_level_settings_menu()
591 level_settings_menu->item[2].change_input(le_current_level->name.c_str());
592 level_settings_menu->item[3].change_input(le_current_level->author.c_str());
593 sprintf(str,"%d",le_current_level->width);
595 string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
596 string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
597 string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
598 string_list_add_item(level_settings_menu->item[6].list,"");
599 if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
600 level_settings_menu->item[3].list->active_item = i;
601 if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
602 level_settings_menu->item[4].list->active_item = i;
603 if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
604 level_settings_menu->item[5].list->active_item = i;
606 level_settings_menu->item[7].change_input(str);
607 sprintf(str,"%d",le_current_level->time_left);
608 level_settings_menu->item[8].change_input(str);
609 sprintf(str,"%2.0f",le_current_level->gravity);
610 level_settings_menu->item[9].change_input(str);
611 sprintf(str,"%d",le_current_level->bkgd_top.red);
612 level_settings_menu->item[10].change_input(str);
613 sprintf(str,"%d",le_current_level->bkgd_top.green);
614 level_settings_menu->item[11].change_input(str);
615 sprintf(str,"%d",le_current_level->bkgd_top.blue);
616 level_settings_menu->item[12].change_input(str);
617 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
618 level_settings_menu->item[13].change_input(str);
619 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
620 level_settings_menu->item[14].change_input(str);
621 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
622 level_settings_menu->item[15].change_input(str);
625 void update_subset_settings_menu()
627 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
628 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
631 void apply_level_settings_menu()
636 le_current_level->name = level_settings_menu->item[2].input;
637 le_current_level->author = level_settings_menu->item[3].input;
639 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
641 le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
645 if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
647 le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
653 le_current_level->load_gfx();
656 le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
658 le_current_level->change_size(atoi(level_settings_menu->item[7].input));
659 le_current_level->time_left = atoi(level_settings_menu->item[8].input);
660 le_current_level->gravity = atof(level_settings_menu->item[9].input);
661 le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
662 le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
663 le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
664 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
665 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
666 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
669 void save_subset_settings_menu()
671 le_level_subset->title = subset_settings_menu->item[2].input;
672 le_level_subset->description = subset_settings_menu->item[3].input;
673 le_level_subset->save();
676 void le_goto_level(int levelnb)
678 le_world.arrays_free();
680 le_current_level->cleanup();
681 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
683 le_current_level->load(le_level_subset->name.c_str(), le_level);
692 le_current_level->load_gfx();
694 le_world.activate_bad_guys();
699 /*if(level_changed == true)
700 if(askforsaving() == CANCEL)
703 SDL_EnableKeyRepeat(0, 0); // disables key repeating
706 delete leveleditor_menu;
707 delete subset_load_menu;
708 delete subset_new_menu;
709 delete subset_settings_menu;
710 delete level_settings_menu;
711 delete select_tilegroup_menu;
712 delete select_objects_menu;
713 delete le_save_level_bt;
715 delete le_test_level_bt;
716 delete le_next_level_bt;
717 delete le_previous_level_bt;
718 delete le_move_right_bt;
719 delete le_move_left_bt;
721 delete le_select_mode_one_bt;
722 delete le_select_mode_two_bt;
723 delete le_settings_bt;
724 delete le_tilegroup_bt;
725 delete le_objects_bt;
726 delete le_tilemap_panel;
728 delete le_current_level;
729 le_current_level = 0;
730 delete le_level_subset;
733 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
734 i != tilegroups_map.end(); ++i)
738 for(ButtonPanelMap::iterator i = objects_map.begin();
739 i != objects_map.end(); ++i)
745 void le_drawinterface()
750 if(le_current_level != NULL)
752 /* draw a grid (if selected) */
755 for(x = 0; x < 19; x++)
756 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
757 for(y = 0; y < 15; y++)
758 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
762 if(le_selection_mode == CURSOR)
763 le_selection->draw( cursor_x - pos_x, cursor_y);
764 else if(le_selection_mode == SQUARE)
767 le_highlight_selection();
768 /* draw current selection */
769 w = selection.x2 - selection.x1;
770 h = selection.y2 - selection.y1;
771 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
772 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
773 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
774 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
778 /* draw button bar */
779 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
781 if(le_current.IsTile())
783 Tile::draw(19 * 32, 14 * 32, le_current.tile);
784 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
785 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
788 //if(le_current.IsObject())
791 if(le_current_level != NULL)
793 le_save_level_bt->draw();
795 le_test_level_bt->draw();
796 le_next_level_bt->draw();
797 le_previous_level_bt->draw();
798 le_rubber_bt->draw();
799 if(le_selection_mode == SQUARE)
800 le_select_mode_one_bt->draw();
801 else if(le_selection_mode == CURSOR)
802 le_select_mode_two_bt->draw();
803 le_settings_bt->draw();
804 le_move_right_bt->draw();
805 le_move_left_bt->draw();
806 le_tilegroup_bt->draw();
807 le_objects_bt->draw();
808 if(!cur_tilegroup.empty())
809 tilegroups_map[cur_tilegroup]->draw();
810 else if(!cur_objects.empty())
812 objects_map[cur_objects]->draw();
815 le_tilemap_panel->draw();
817 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
818 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
820 white_small_text->draw("F1 for Help", 10, 430, 1);
825 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
827 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
834 unsigned int y,x,i,s;
837 /* Draw the real background */
838 if(le_current_level->bkgd_image[0] != '\0')
841 le_current_level->img_bkgd->draw_part(s,0,0,0,
842 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
843 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
844 le_current_level->img_bkgd->h);
848 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
851 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
853 for (y = 0; y < 15; ++y)
854 for (x = 0; x < 20; ++x)
857 if(active_tm == TM_BG)
862 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
864 if(active_tm == TM_IA)
869 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
871 if(active_tm == TM_FG)
876 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
878 /* draw whats inside stuff when cursor is selecting those */
879 /* (draw them all the time - is this the right behaviour?) */
880 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
881 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);
885 /* Draw the Bad guys: */
886 for (i = 0; i < le_world.bad_guys.size(); ++i)
888 /* to support frames: img_bsod_left[(frame / 5) % 4] */
891 le_world.bad_guys[i].draw();
895 /* Draw the player: */
896 /* for now, the position is fixed at (100, 240) */
897 largetux.walk_right->draw( 100 - pos_x, 240);
900 void le_checkevents()
907 keymod = SDL_GetModState();
909 while(SDL_PollEvent(&event))
913 Menu::current()->event(event);
917 mouse_cursor->set_state(MC_NORMAL);
919 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
920 if(event.type == SDL_KEYDOWN
921 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
922 && (event.motion.x > 0
923 && event.motion.x < screen->w - 64 &&
924 event.motion.y > 0 && event.motion.y < screen->h)))
928 case SDL_KEYDOWN: // key pressed
929 key = event.key.keysym.sym;
933 Menu::set_current(leveleditor_menu);
936 cursor_x -= KEY_CURSOR_SPEED;
938 cursor_x -= KEY_CURSOR_FASTSPEED;
940 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
941 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
946 cursor_x += KEY_CURSOR_SPEED;
948 cursor_x += KEY_CURSOR_FASTSPEED;
950 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
951 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
956 cursor_y -= KEY_CURSOR_SPEED;
958 cursor_y -= KEY_CURSOR_FASTSPEED;
965 cursor_y += KEY_CURSOR_SPEED;
967 cursor_y += KEY_CURSOR_FASTSPEED;
969 if(cursor_y > screen->h-32)
970 cursor_y = screen->h-32;
983 cursor_x = (le_current_level->width * 32) - 32;
987 le_show_grid = !le_show_grid;
993 case SDL_KEYUP: /* key released */
994 switch(event.key.keysym.sym)
1003 case SDL_MOUSEBUTTONDOWN:
1004 if(event.button.button == SDL_BUTTON_LEFT)
1006 le_mouse_pressed[LEFT] = true;
1008 selection.x1 = event.motion.x + pos_x;
1009 selection.y1 = event.motion.y;
1010 selection.x2 = event.motion.x + pos_x;
1011 selection.y2 = event.motion.y;
1013 else if(event.button.button == SDL_BUTTON_RIGHT)
1015 le_mouse_pressed[RIGHT] = true;
1018 case SDL_MOUSEBUTTONUP:
1019 if(event.button.button == SDL_BUTTON_LEFT)
1020 le_mouse_pressed[LEFT] = false;
1021 else if(event.button.button == SDL_BUTTON_RIGHT)
1022 le_mouse_pressed[RIGHT] = false;
1024 case SDL_MOUSEMOTION:
1026 if(!Menu::current())
1031 if(le_current.IsTile())
1033 cursor_x = ((int)(pos_x + x) / 32) * 32;
1034 cursor_y = ((int) y / 32) * 32;
1042 if(le_mouse_pressed[LEFT])
1044 selection.x2 = x + pos_x;
1048 if(le_mouse_pressed[RIGHT])
1050 pos_x += -1 * event.motion.xrel;
1054 case SDL_QUIT: // window closed
1063 if(le_current_level != NULL)
1065 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 &&
1066 event.motion.y > 0 && event.motion.y < screen->h)))
1068 le_mouse_pressed[LEFT] = false;
1069 le_mouse_pressed[RIGHT] = false;
1071 if(!Menu::current())
1073 /* Check for button events */
1074 le_test_level_bt->event(event);
1075 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1077 le_save_level_bt->event(event);
1078 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1079 le_current_level->save(le_level_subset->name.c_str(),le_level);
1080 le_exit_bt->event(event);
1081 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1083 Menu::set_current(leveleditor_menu);
1085 le_next_level_bt->event(event);
1086 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1088 if(le_level < le_level_subset->levels)
1090 le_goto_level(++le_level);
1096 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1097 if(confirm_dialog(str))
1099 new_lev.init_defaults();
1100 new_lev.save(le_level_subset->name.c_str(),++le_level);
1101 le_level_subset->levels = le_level;
1102 le_goto_level(le_level);
1106 le_previous_level_bt->event(event);
1107 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1110 le_goto_level(--le_level);
1112 le_rubber_bt->event(event);
1113 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1116 if(le_selection_mode == SQUARE)
1118 le_select_mode_one_bt->event(event);
1119 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1120 le_selection_mode = CURSOR;
1124 le_select_mode_two_bt->event(event);
1125 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1126 le_selection_mode = SQUARE;
1129 le_tilegroup_bt->event(event);
1130 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1132 Menu::set_current(select_tilegroup_menu);
1133 select_tilegroup_menu_effect.start(200);
1134 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1137 le_objects_bt->event(event);
1138 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1140 Menu::set_current(select_objects_menu);
1141 select_objects_menu_effect.start(200);
1142 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1145 le_settings_bt->event(event);
1146 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1148 update_level_settings_menu();
1149 Menu::set_current(level_settings_menu);
1151 if(!cur_tilegroup.empty())
1153 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1155 if(pbutton->get_state() == BUTTON_CLICKED)
1157 le_current.Tile(pbutton->get_tag());
1161 else if(!cur_objects.empty())
1163 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1165 if(pbutton->get_state() == BUTTON_CLICKED)
1167 le_current.Object(pbutton->get_game_object());
1172 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1174 if(pbutton->get_state() == BUTTON_CLICKED)
1176 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1182 le_settings_bt->event(event);
1183 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1185 Menu::set_current(0);
1187 le_tilegroup_bt->event(event);
1188 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1190 Menu::set_current(0);
1195 if(!Menu::current())
1197 le_move_left_bt->event(event);
1198 le_move_right_bt->event(event);
1200 if(le_mouse_pressed[LEFT])
1202 if(le_current.IsTile())
1203 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1204 else if(le_current.IsObject())
1206 std::string type = le_current.obj->type();
1207 if(type == "BadGuy")
1209 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1211 le_world.bad_guys.push_back(BadGuy(cursor_x, cursor_y,pbadguy->kind,false));
1212 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1219 if(!Menu::current())
1221 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1225 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1230 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1234 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1242 void le_highlight_selection()
1246 if(selection.x1 < selection.x2)
1256 if(selection.y1 < selection.y2)
1272 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1275 void le_change(float x, float y, int tm, unsigned int c)
1277 if(le_current_level != NULL)
1283 /* level_changed = true; */
1285 switch(le_selection_mode)
1288 le_current_level->change(x,y,tm,c);
1290 base_type cursor_base;
1293 cursor_base.width = 32;
1294 cursor_base.height = 32;
1296 /* if there is a bad guy over there, remove it */
1297 for(i = 0; i < le_world.bad_guys.size(); ++i)
1298 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1300 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1301 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1306 if(selection.x1 < selection.x2)
1316 if(selection.y1 < selection.y2)
1332 /* if there is a bad guy over there, remove it */
1333 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1334 i != le_world.bad_guys.end(); /* will be at end of loop */)
1336 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1337 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1339 i = le_world.bad_guys.erase(i);
1348 for(xx = x1; xx <= x2; xx++)
1349 for(yy = y1; yy <= y2; yy++)
1351 le_current_level->change(xx*32, yy*32, tm, c);
1363 le_current_level->save("test", le_level);
1365 GameSession session("test",le_level, ST_GL_TEST);
1367 player_status.reset();
1369 music_manager->halt_music();
1371 Menu::set_current(leveleditor_menu);
1372 le_world.arrays_free();
1373 le_current_level->load_gfx();
1374 le_world.activate_bad_guys();
1380 unsigned int i, done_;
1382 " - This is SuperTux's built-in level editor -",
1383 "It has been designed to be light and easy to use from the start.",
1385 "When you first load the level editor you are given a menu where you",
1386 "can load level subsets, create a new level subset, edit the current",
1387 "subset's settings, or simply quit the editor. You can access this menu",
1388 "from the level editor at any time by pressing the escape key.",
1390 "To your right is your button bar. The center of this contains many",
1391 "tiles you can use to make your level. To select a tile, click on it",
1392 "with your left mouse button; your selection will be shown in the",
1393 "bottom right corner of the button box. Click anywhere on your level",
1394 "with the left mouse button to place that tile down. If you right click",
1395 "a tile in the button bar, you can find out what its keyboard shortcut",
1396 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1397 "background, and enemy tiles. The eraser lets you remove tiles.",
1398 "The left and right arrow keys scroll back and forth through your level.",
1399 "The button with the wrench and screwdriver, lets you change the",
1400 "settings of your level, including how long it is or what music it will",
1401 "play. When you are ready to give your level a test, click on the little",
1402 "running Tux. If you like the changes you have made to your level,",
1403 "press the red save key to keep them.",
1404 "To change which level in your subset you are editing, press the white",
1405 "up and down arrow keys at the top of the button box.",
1407 "Have fun making levels! If you make some good ones, send them to us on",
1408 "the SuperTux mailing list!",
1413 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1415 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1416 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1418 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1426 done_ = wait_for_event(event);