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);
787 if(le_current.IsObject())
790 if(le_current_level != NULL)
792 le_save_level_bt->draw();
794 le_test_level_bt->draw();
795 le_next_level_bt->draw();
796 le_previous_level_bt->draw();
797 le_rubber_bt->draw();
798 if(le_selection_mode == SQUARE)
799 le_select_mode_one_bt->draw();
800 else if(le_selection_mode == CURSOR)
801 le_select_mode_two_bt->draw();
802 le_settings_bt->draw();
803 le_move_right_bt->draw();
804 le_move_left_bt->draw();
805 le_tilegroup_bt->draw();
806 le_objects_bt->draw();
807 if(!cur_tilegroup.empty())
808 tilegroups_map[cur_tilegroup]->draw();
809 else if(!cur_objects.empty())
811 objects_map[cur_objects]->draw();
814 le_tilemap_panel->draw();
816 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
817 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
819 white_small_text->draw("F1 for Help", 10, 430, 1);
824 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
826 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
833 unsigned int y,x,i,s;
836 /* Draw the real background */
837 if(le_current_level->bkgd_image[0] != '\0')
840 le_current_level->img_bkgd->draw_part(s,0,0,0,
841 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
842 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
843 le_current_level->img_bkgd->h);
847 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
850 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
852 for (y = 0; y < 15; ++y)
853 for (x = 0; x < 20; ++x)
856 if(active_tm == TM_BG)
861 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
863 if(active_tm == TM_IA)
868 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
870 if(active_tm == TM_FG)
875 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
877 /* draw whats inside stuff when cursor is selecting those */
878 /* (draw them all the time - is this the right behaviour?) */
879 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
880 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);
884 /* Draw the Bad guys: */
885 for (i = 0; i < le_world.bad_guys.size(); ++i)
887 /* to support frames: img_bsod_left[(frame / 5) % 4] */
890 le_world.bad_guys[i].draw();
894 /* Draw the player: */
895 /* for now, the position is fixed at (100, 240) */
896 largetux.walk_right->draw( 100 - pos_x, 240);
899 void le_checkevents()
906 keymod = SDL_GetModState();
908 while(SDL_PollEvent(&event))
912 Menu::current()->event(event);
916 mouse_cursor->set_state(MC_NORMAL);
918 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
919 if(event.type == SDL_KEYDOWN
920 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
921 && (event.motion.x > 0
922 && event.motion.x < screen->w - 64 &&
923 event.motion.y > 0 && event.motion.y < screen->h)))
927 case SDL_KEYDOWN: // key pressed
928 key = event.key.keysym.sym;
932 Menu::set_current(leveleditor_menu);
935 cursor_x -= KEY_CURSOR_SPEED;
937 cursor_x -= KEY_CURSOR_FASTSPEED;
939 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
940 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
945 cursor_x += KEY_CURSOR_SPEED;
947 cursor_x += KEY_CURSOR_FASTSPEED;
949 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
950 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
955 cursor_y -= KEY_CURSOR_SPEED;
957 cursor_y -= KEY_CURSOR_FASTSPEED;
964 cursor_y += KEY_CURSOR_SPEED;
966 cursor_y += KEY_CURSOR_FASTSPEED;
968 if(cursor_y > screen->h-32)
969 cursor_y = screen->h-32;
982 cursor_x = (le_current_level->width * 32) - 32;
986 le_show_grid = !le_show_grid;
992 case SDL_KEYUP: /* key released */
993 switch(event.key.keysym.sym)
1002 case SDL_MOUSEBUTTONDOWN:
1003 if(event.button.button == SDL_BUTTON_LEFT)
1005 le_mouse_pressed[LEFT] = true;
1007 selection.x1 = event.motion.x + pos_x;
1008 selection.y1 = event.motion.y;
1009 selection.x2 = event.motion.x + pos_x;
1010 selection.y2 = event.motion.y;
1012 else if(event.button.button == SDL_BUTTON_RIGHT)
1014 le_mouse_pressed[RIGHT] = true;
1017 case SDL_MOUSEBUTTONUP:
1018 if(event.button.button == SDL_BUTTON_LEFT)
1019 le_mouse_pressed[LEFT] = false;
1020 else if(event.button.button == SDL_BUTTON_RIGHT)
1021 le_mouse_pressed[RIGHT] = false;
1023 case SDL_MOUSEMOTION:
1025 if(!Menu::current())
1030 if(le_current.IsTile())
1032 cursor_x = ((int)(pos_x + x) / 32) * 32;
1033 cursor_y = ((int) y / 32) * 32;
1041 if(le_mouse_pressed[LEFT])
1043 selection.x2 = x + pos_x;
1047 if(le_mouse_pressed[RIGHT])
1049 pos_x += -1 * event.motion.xrel;
1053 case SDL_QUIT: // window closed
1062 if(le_current_level != NULL)
1064 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 &&
1065 event.motion.y > 0 && event.motion.y < screen->h)))
1067 le_mouse_pressed[LEFT] = false;
1068 le_mouse_pressed[RIGHT] = false;
1070 if(!Menu::current())
1072 /* Check for button events */
1073 le_test_level_bt->event(event);
1074 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1076 le_save_level_bt->event(event);
1077 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1078 le_current_level->save(le_level_subset->name.c_str(),le_level);
1079 le_exit_bt->event(event);
1080 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1082 Menu::set_current(leveleditor_menu);
1084 le_next_level_bt->event(event);
1085 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1087 if(le_level < le_level_subset->levels)
1089 le_goto_level(++le_level);
1095 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1096 if(confirm_dialog(str))
1098 new_lev.init_defaults();
1099 new_lev.save(le_level_subset->name.c_str(),++le_level);
1100 le_level_subset->levels = le_level;
1101 le_goto_level(le_level);
1105 le_previous_level_bt->event(event);
1106 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1109 le_goto_level(--le_level);
1111 le_rubber_bt->event(event);
1112 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1115 if(le_selection_mode == SQUARE)
1117 le_select_mode_one_bt->event(event);
1118 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1119 le_selection_mode = CURSOR;
1123 le_select_mode_two_bt->event(event);
1124 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1125 le_selection_mode = SQUARE;
1128 le_tilegroup_bt->event(event);
1129 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1131 Menu::set_current(select_tilegroup_menu);
1132 select_tilegroup_menu_effect.start(200);
1133 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1136 le_objects_bt->event(event);
1137 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1139 Menu::set_current(select_objects_menu);
1140 select_objects_menu_effect.start(200);
1141 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1144 le_settings_bt->event(event);
1145 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1147 update_level_settings_menu();
1148 Menu::set_current(level_settings_menu);
1150 if(!cur_tilegroup.empty())
1152 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1154 if(pbutton->get_state() == BUTTON_CLICKED)
1156 le_current.Tile(pbutton->get_tag());
1160 else if(!cur_objects.empty())
1162 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1164 if(pbutton->get_state() == BUTTON_CLICKED)
1166 le_current.Object(pbutton->get_game_object());
1171 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1173 if(pbutton->get_state() == BUTTON_CLICKED)
1175 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1181 le_settings_bt->event(event);
1182 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1184 Menu::set_current(0);
1186 le_tilegroup_bt->event(event);
1187 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1189 Menu::set_current(0);
1194 if(!Menu::current())
1196 le_move_left_bt->event(event);
1197 le_move_right_bt->event(event);
1199 if(le_mouse_pressed[LEFT])
1201 if(le_current.IsTile())
1202 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1203 else if(le_current.IsObject())
1205 std::string type = le_current.obj->type();
1206 if(type == "BadGuy")
1208 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1210 le_world.bad_guys.push_back(BadGuy(cursor_x, cursor_y,pbadguy->kind,false));
1211 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1218 if(!Menu::current())
1220 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1224 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1229 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1233 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1241 void le_highlight_selection()
1245 if(selection.x1 < selection.x2)
1255 if(selection.y1 < selection.y2)
1271 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1274 void le_change(float x, float y, int tm, unsigned int c)
1276 if(le_current_level != NULL)
1282 /* level_changed = true; */
1284 switch(le_selection_mode)
1287 le_current_level->change(x,y,tm,c);
1289 base_type cursor_base;
1292 cursor_base.width = 32;
1293 cursor_base.height = 32;
1295 /* if there is a bad guy over there, remove it */
1296 for(i = 0; i < le_world.bad_guys.size(); ++i)
1297 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1299 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1300 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1305 if(selection.x1 < selection.x2)
1315 if(selection.y1 < selection.y2)
1331 /* if there is a bad guy over there, remove it */
1332 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1333 i != le_world.bad_guys.end(); /* will be at end of loop */)
1335 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1336 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1338 i = le_world.bad_guys.erase(i);
1347 for(xx = x1; xx <= x2; xx++)
1348 for(yy = y1; yy <= y2; yy++)
1350 le_current_level->change(xx*32, yy*32, tm, c);
1362 le_current_level->save("test", le_level);
1364 GameSession session("test",le_level, ST_GL_TEST);
1366 player_status.reset();
1368 music_manager->halt_music();
1370 Menu::set_current(leveleditor_menu);
1371 le_world.arrays_free();
1372 le_current_level->load_gfx();
1373 le_world.activate_bad_guys();
1379 unsigned int i, done_;
1381 " - This is SuperTux's built-in level editor -",
1382 "It has been designed to be light and easy to use from the start.",
1384 "When you first load the level editor you are given a menu where you",
1385 "can load level subsets, create a new level subset, edit the current",
1386 "subset's settings, or simply quit the editor. You can access this menu",
1387 "from the level editor at any time by pressing the escape key.",
1389 "To your right is your button bar. The center of this contains many",
1390 "tiles you can use to make your level. To select a tile, click on it",
1391 "with your left mouse button; your selection will be shown in the",
1392 "bottom right corner of the button box. Click anywhere on your level",
1393 "with the left mouse button to place that tile down. If you right click",
1394 "a tile in the button bar, you can find out what its keyboard shortcut",
1395 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1396 "background, and enemy tiles. The eraser lets you remove tiles.",
1397 "The left and right arrow keys scroll back and forth through your level.",
1398 "The button with the wrench and screwdriver, lets you change the",
1399 "settings of your level, including how long it is or what music it will",
1400 "play. When you are ready to give your level a test, click on the little",
1401 "running Tux. If you like the changes you have made to your level,",
1402 "press the red save key to keep them.",
1403 "To change which level in your subset you are editing, press the white",
1404 "up and down arrow keys at the top of the button box.",
1406 "Have fun making levels! If you make some good ones, send them to us on",
1407 "the SuperTux mailing list!",
1412 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1414 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1415 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1417 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1425 done_ = wait_for_event(event);