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())
277 apply_level_settings_menu();
278 Menu::set_current(NULL);
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,MNID_NAME);
475 level_settings_menu->additem(MN_TEXTFIELD,"Author ",0,0,MNID_AUTHOR);
476 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
477 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
478 level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0,MNID_LENGTH);
479 level_settings_menu->additem(MN_NUMFIELD,"Time ",0,0,MNID_TIME);
480 level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0,MNID_GRAVITY);
481 level_settings_menu->additem(MN_NUMFIELD,"Top Red ",0,0,MNID_TopRed);
482 level_settings_menu->additem(MN_NUMFIELD,"Top Green ",0,0,MNID_TopGreen);
483 level_settings_menu->additem(MN_NUMFIELD,"Top Blue ",0,0,MNID_TopBlue);
484 level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0,MNID_BottomRed);
485 level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0,MNID_BottomGreen);
486 level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0,MNID_BottomBlue);
487 level_settings_menu->additem(MN_HL,"",0,0);
488 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
490 select_tilegroup_menu->arrange_left = true;
491 select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
492 select_tilegroup_menu->additem(MN_HL,"",0,0);
493 std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
495 for(std::vector<TileGroup>::iterator it = tilegroups->begin();
496 it != tilegroups->end(); ++it )
498 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
500 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
503 for(std::vector<int>::iterator sit = (*it).tiles.begin();
504 sit != (*it).tiles.end(); ++sit, ++i)
506 std::string imagefile = "/images/tilesets/" ;
507 imagefile += TileManager::instance()->get(*sit)->filenames[0];
508 Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
510 tilegroups_map[it->name]->additem(button, *sit);
513 select_tilegroup_menu->additem(MN_HL,"",0,0);
515 select_objects_menu->arrange_left = true;
516 select_objects_menu->additem(MN_LABEL,"Select Objects",0,0);
517 select_objects_menu->additem(MN_HL,"",0,0);
518 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
519 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
521 for(int i = 0; i < NUM_BadGuyKinds; ++i)
523 BadGuy bad_tmp(0,0,BadGuyKind(i),false);
524 objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
525 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));
528 select_objects_menu->additem(MN_HL,"",0,0);
534 level_subsets = dsubdirs("/levels", "info");
536 le_level_subset = new LevelSubset;
542 /* level_changed = NO;*/
545 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
546 le_level_changed = false;
547 le_current_level = NULL;
549 le_mouse_pressed[LEFT] = false;
550 le_mouse_pressed[RIGHT] = false;
552 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
554 select_tilegroup_menu_effect.init(false);
555 select_objects_menu_effect.init(false);
558 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
559 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
560 le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
561 le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
562 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
563 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
564 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
565 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
566 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
567 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
568 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
569 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
570 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
572 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
573 le_tilemap_panel->set_button_size(32,10);
574 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
575 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
576 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG);
580 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
585 void update_level_settings_menu()
590 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_current_level->name.c_str());
591 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_current_level->author.c_str());
593 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
594 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
595 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
597 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_current_level->song_title.c_str())) != -1)
598 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
599 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_current_level->bkgd_image.c_str())) != -1)
600 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
602 sprintf(str,"%d",le_current_level->width);
603 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
604 sprintf(str,"%d",le_current_level->time_left);
605 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
606 sprintf(str,"%2.0f",le_current_level->gravity);
607 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
608 sprintf(str,"%d",le_current_level->bkgd_top.red);
609 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
610 sprintf(str,"%d",le_current_level->bkgd_top.green);
611 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
612 sprintf(str,"%d",le_current_level->bkgd_top.blue);
613 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
614 sprintf(str,"%d",le_current_level->bkgd_bottom.red);
615 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
616 sprintf(str,"%d",le_current_level->bkgd_bottom.green);
617 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
618 sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
619 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
622 void update_subset_settings_menu()
624 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
625 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
628 void apply_level_settings_menu()
633 le_current_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
634 le_current_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
636 if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
638 le_current_level->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
644 le_current_level->load_gfx();
647 le_current_level->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
649 le_current_level->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
650 le_current_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_BGIMG).input);
651 le_current_level->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
652 le_current_level->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
653 le_current_level->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
654 le_current_level->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
655 le_current_level->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
656 le_current_level->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
657 le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
660 void save_subset_settings_menu()
662 le_level_subset->title = subset_settings_menu->item[2].input;
663 le_level_subset->description = subset_settings_menu->item[3].input;
664 le_level_subset->save();
667 void le_goto_level(int levelnb)
669 le_world.arrays_free();
671 le_current_level->cleanup();
672 if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
674 le_current_level->load(le_level_subset->name.c_str(), le_level);
683 le_current_level->load_gfx();
685 le_world.activate_bad_guys();
690 /*if(level_changed == true)
691 if(askforsaving() == CANCEL)
694 SDL_EnableKeyRepeat(0, 0); // disables key repeating
697 delete leveleditor_menu;
698 delete subset_load_menu;
699 delete subset_new_menu;
700 delete subset_settings_menu;
701 delete level_settings_menu;
702 delete select_tilegroup_menu;
703 delete select_objects_menu;
704 delete le_save_level_bt;
706 delete le_test_level_bt;
707 delete le_next_level_bt;
708 delete le_previous_level_bt;
709 delete le_move_right_bt;
710 delete le_move_left_bt;
712 delete le_select_mode_one_bt;
713 delete le_select_mode_two_bt;
714 delete le_settings_bt;
715 delete le_tilegroup_bt;
716 delete le_objects_bt;
717 delete le_tilemap_panel;
719 delete le_current_level;
720 le_current_level = 0;
721 delete le_level_subset;
724 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
725 i != tilegroups_map.end(); ++i)
729 for(ButtonPanelMap::iterator i = objects_map.begin();
730 i != objects_map.end(); ++i)
736 void le_drawinterface()
741 if(le_current_level != NULL)
743 /* draw a grid (if selected) */
746 for(x = 0; x < 19; x++)
747 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
748 for(y = 0; y < 15; y++)
749 fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
753 if(le_selection_mode == CURSOR)
754 le_selection->draw( cursor_x - pos_x, cursor_y);
755 else if(le_selection_mode == SQUARE)
758 le_highlight_selection();
759 /* draw current selection */
760 w = selection.x2 - selection.x1;
761 h = selection.y2 - selection.y1;
762 fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
763 fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
764 fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
765 fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
769 /* draw button bar */
770 fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
772 if(le_current.IsTile())
774 Tile::draw(19 * 32, 14 * 32, le_current.tile);
775 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
776 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
779 //if(le_current.IsObject())
782 if(le_current_level != NULL)
784 le_save_level_bt->draw();
786 le_test_level_bt->draw();
787 le_next_level_bt->draw();
788 le_previous_level_bt->draw();
789 le_rubber_bt->draw();
790 if(le_selection_mode == SQUARE)
791 le_select_mode_one_bt->draw();
792 else if(le_selection_mode == CURSOR)
793 le_select_mode_two_bt->draw();
794 le_settings_bt->draw();
795 le_move_right_bt->draw();
796 le_move_left_bt->draw();
797 le_tilegroup_bt->draw();
798 le_objects_bt->draw();
799 if(!cur_tilegroup.empty())
800 tilegroups_map[cur_tilegroup]->draw();
801 else if(!cur_objects.empty())
803 objects_map[cur_objects]->draw();
806 le_tilemap_panel->draw();
808 sprintf(str, "%d/%d", le_level,le_level_subset->levels);
809 white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
811 white_small_text->draw("F1 for Help", 10, 430, 1);
816 white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
818 white_small_text->draw("No Level Subset loaded", 10, 430, 1);
825 unsigned int y,x,i,s;
828 /* Draw the real background */
829 if(le_current_level->bkgd_image[0] != '\0')
832 le_current_level->img_bkgd->draw_part(s,0,0,0,
833 le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
834 le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
835 le_current_level->img_bkgd->h);
839 drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
842 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
844 for (y = 0; y < 15; ++y)
845 for (x = 0; x < 20; ++x)
848 if(active_tm == TM_BG)
853 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
855 if(active_tm == TM_IA)
860 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
862 if(active_tm == TM_FG)
867 Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
869 /* draw whats inside stuff when cursor is selecting those */
870 /* (draw them all the time - is this the right behaviour?) */
871 if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
872 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);
876 /* Draw the Bad guys: */
877 for (i = 0; i < le_world.bad_guys.size(); ++i)
879 /* to support frames: img_bsod_left[(frame / 5) % 4] */
882 le_world.bad_guys[i].draw();
886 /* Draw the player: */
887 /* for now, the position is fixed at (100, 240) */
888 largetux.walk_right->draw( 100 - pos_x, 240);
891 void le_checkevents()
898 keymod = SDL_GetModState();
900 while(SDL_PollEvent(&event))
904 Menu::current()->event(event);
908 mouse_cursor->set_state(MC_NORMAL);
910 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
911 if(event.type == SDL_KEYDOWN
912 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
913 && (event.motion.x > 0
914 && event.motion.x < screen->w - 64 &&
915 event.motion.y > 0 && event.motion.y < screen->h)))
919 case SDL_KEYDOWN: // key pressed
920 key = event.key.keysym.sym;
924 Menu::set_current(leveleditor_menu);
927 cursor_x -= KEY_CURSOR_SPEED;
929 cursor_x -= KEY_CURSOR_FASTSPEED;
931 if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
932 pos_x = cursor_x - MOUSE_LEFT_MARGIN;
937 cursor_x += KEY_CURSOR_SPEED;
939 cursor_x += KEY_CURSOR_FASTSPEED;
941 if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
942 pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
947 cursor_y -= KEY_CURSOR_SPEED;
949 cursor_y -= KEY_CURSOR_FASTSPEED;
956 cursor_y += KEY_CURSOR_SPEED;
958 cursor_y += KEY_CURSOR_FASTSPEED;
960 if(cursor_y > screen->h-32)
961 cursor_y = screen->h-32;
974 cursor_x = (le_current_level->width * 32) - 32;
978 le_show_grid = !le_show_grid;
984 case SDL_KEYUP: /* key released */
985 switch(event.key.keysym.sym)
994 case SDL_MOUSEBUTTONDOWN:
995 if(event.button.button == SDL_BUTTON_LEFT)
997 le_mouse_pressed[LEFT] = true;
999 selection.x1 = event.motion.x + pos_x;
1000 selection.y1 = event.motion.y;
1001 selection.x2 = event.motion.x + pos_x;
1002 selection.y2 = event.motion.y;
1004 else if(event.button.button == SDL_BUTTON_RIGHT)
1006 le_mouse_pressed[RIGHT] = true;
1009 case SDL_MOUSEBUTTONUP:
1010 if(event.button.button == SDL_BUTTON_LEFT)
1011 le_mouse_pressed[LEFT] = false;
1012 else if(event.button.button == SDL_BUTTON_RIGHT)
1013 le_mouse_pressed[RIGHT] = false;
1015 case SDL_MOUSEMOTION:
1017 if(!Menu::current())
1022 if(le_current.IsTile())
1024 cursor_x = ((int)(pos_x + x) / 32) * 32;
1025 cursor_y = ((int) y / 32) * 32;
1033 if(le_mouse_pressed[LEFT])
1035 selection.x2 = x + pos_x;
1039 if(le_mouse_pressed[RIGHT])
1041 pos_x += -1 * event.motion.xrel;
1045 case SDL_QUIT: // window closed
1054 if(le_current_level != NULL)
1056 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 &&
1057 event.motion.y > 0 && event.motion.y < screen->h)))
1059 le_mouse_pressed[LEFT] = false;
1060 le_mouse_pressed[RIGHT] = false;
1062 if(!Menu::current())
1064 /* Check for button events */
1065 le_test_level_bt->event(event);
1066 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1068 le_save_level_bt->event(event);
1069 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1070 le_current_level->save(le_level_subset->name.c_str(),le_level);
1071 le_exit_bt->event(event);
1072 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1074 Menu::set_current(leveleditor_menu);
1076 le_next_level_bt->event(event);
1077 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1079 if(le_level < le_level_subset->levels)
1081 le_goto_level(++le_level);
1087 sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1088 if(confirm_dialog(str))
1090 new_lev.init_defaults();
1091 new_lev.save(le_level_subset->name.c_str(),++le_level);
1092 le_level_subset->levels = le_level;
1093 le_goto_level(le_level);
1097 le_previous_level_bt->event(event);
1098 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1101 le_goto_level(--le_level);
1103 le_rubber_bt->event(event);
1104 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1107 if(le_selection_mode == SQUARE)
1109 le_select_mode_one_bt->event(event);
1110 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1111 le_selection_mode = CURSOR;
1115 le_select_mode_two_bt->event(event);
1116 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1117 le_selection_mode = SQUARE;
1120 le_tilegroup_bt->event(event);
1121 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1123 Menu::set_current(select_tilegroup_menu);
1124 select_tilegroup_menu_effect.start(200);
1125 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1128 le_objects_bt->event(event);
1129 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1131 Menu::set_current(select_objects_menu);
1132 select_objects_menu_effect.start(200);
1133 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1136 le_settings_bt->event(event);
1137 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1139 update_level_settings_menu();
1140 Menu::set_current(level_settings_menu);
1142 if(!cur_tilegroup.empty())
1144 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1146 if(pbutton->get_state() == BUTTON_CLICKED)
1148 le_current.Tile(pbutton->get_tag());
1152 else if(!cur_objects.empty())
1154 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1156 if(pbutton->get_state() == BUTTON_CLICKED)
1158 le_current.Object(pbutton->get_game_object());
1163 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1165 if(pbutton->get_state() == BUTTON_CLICKED)
1167 active_tm = static_cast<TileMapType>(pbutton->get_tag());
1173 le_settings_bt->event(event);
1174 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1176 Menu::set_current(0);
1178 le_tilegroup_bt->event(event);
1179 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1181 Menu::set_current(0);
1186 if(!Menu::current())
1188 le_move_left_bt->event(event);
1189 le_move_right_bt->event(event);
1191 if(le_mouse_pressed[LEFT])
1193 if(le_current.IsTile())
1194 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1195 else if(le_current.IsObject())
1197 std::string type = le_current.obj->type();
1198 if(type == "BadGuy")
1200 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1202 le_world.bad_guys.push_back(BadGuy(cursor_x, cursor_y,pbadguy->kind,false));
1203 le_current_level->badguy_data.push_back(&le_world.bad_guys.back());
1210 if(!Menu::current())
1212 if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1216 else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1221 if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1225 else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1233 void le_highlight_selection()
1237 if(selection.x1 < selection.x2)
1247 if(selection.y1 < selection.y2)
1263 fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1266 void le_change(float x, float y, int tm, unsigned int c)
1268 if(le_current_level != NULL)
1274 /* level_changed = true; */
1276 switch(le_selection_mode)
1279 le_current_level->change(x,y,tm,c);
1281 base_type cursor_base;
1284 cursor_base.width = 32;
1285 cursor_base.height = 32;
1287 /* if there is a bad guy over there, remove it */
1288 for(i = 0; i < le_world.bad_guys.size(); ++i)
1289 if(rectcollision(cursor_base,le_world.bad_guys[i].base))
1291 le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1292 le_current_level->badguy_data.erase(le_current_level->badguy_data.begin() + i);
1297 if(selection.x1 < selection.x2)
1307 if(selection.y1 < selection.y2)
1323 /* if there is a bad guy over there, remove it */
1324 for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin();
1325 i != le_world.bad_guys.end(); /* will be at end of loop */)
1327 if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1328 && i->base.y/32 >= y1 && i->base.y/32 <= y2)
1330 i = le_world.bad_guys.erase(i);
1339 for(xx = x1; xx <= x2; xx++)
1340 for(yy = y1; yy <= y2; yy++)
1342 le_current_level->change(xx*32, yy*32, tm, c);
1354 le_current_level->save("test", le_level);
1356 GameSession session("test",le_level, ST_GL_TEST);
1358 player_status.reset();
1360 music_manager->halt_music();
1362 Menu::set_current(leveleditor_menu);
1363 le_world.arrays_free();
1364 le_current_level->load_gfx();
1365 le_world.activate_bad_guys();
1371 unsigned int i, done_;
1373 " - This is SuperTux's built-in level editor -",
1374 "It has been designed to be light and easy to use from the start.",
1376 "When you first load the level editor you are given a menu where you",
1377 "can load level subsets, create a new level subset, edit the current",
1378 "subset's settings, or simply quit the editor. You can access this menu",
1379 "from the level editor at any time by pressing the escape key.",
1381 "To your right is your button bar. The center of this contains many",
1382 "tiles you can use to make your level. To select a tile, click on it",
1383 "with your left mouse button; your selection will be shown in the",
1384 "bottom right corner of the button box. Click anywhere on your level",
1385 "with the left mouse button to place that tile down. If you right click",
1386 "a tile in the button bar, you can find out what its keyboard shortcut",
1387 "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1388 "background, and enemy tiles. The eraser lets you remove tiles.",
1389 "The left and right arrow keys scroll back and forth through your level.",
1390 "The button with the wrench and screwdriver, lets you change the",
1391 "settings of your level, including how long it is or what music it will",
1392 "play. When you are ready to give your level a test, click on the little",
1393 "running Tux. If you like the changes you have made to your level,",
1394 "press the red save key to keep them.",
1395 "To change which level in your subset you are editing, press the white",
1396 "up and down arrow keys at the top of the button box.",
1398 "Have fun making levels! If you make some good ones, send them to us on",
1399 "the SuperTux mailing list!",
1404 blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1406 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1407 white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1409 gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1417 done_ = wait_for_event(event);