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.
30 #include <SDL_image.h>
32 #include "leveleditor.h"
34 #include "screen/screen.h"
48 #include "resources.h"
49 #include "background.h"
51 /* definitions to aid development */
53 /* definitions that affect gameplay */
54 #define KEY_CURSOR_SPEED 32
55 #define KEY_CURSOR_FASTSPEED 64
57 /* when pagedown/up pressed speed:*/
58 #define PAGE_CURSOR_SPEED 13*32
60 #define MOUSE_LEFT_MARGIN 80
61 #define MOUSE_RIGHT_MARGIN (560-32)
64 #define KEYBOARD_SPEED 140
65 #define MOUSE_SPEED 40
68 #define SELECT_W 2 // size of the selections lines
69 #define SELECT_CLR 0, 255, 0, 255 // lines color (R, G, B, A)
71 enum { TM_IA, TM_BG, TM_FG };
73 /* own declerations */
74 /* crutial ones (main loop) */
77 int le_load_level_subset(char *filename);
78 void le_drawlevel(DrawingContext& context);
79 void le_drawinterface(DrawingContext& context);
80 void le_checkevents();
81 void le_change(float x, float y, int tm, unsigned int c);
84 void le_set_defaults(void);
85 void le_activate_bad_guys(void);
86 void le_goto_level(int levelnb);
87 void le_highlight_selection();
89 void apply_level_settings_menu();
90 void update_subset_settings_menu();
91 void save_subset_settings_menu();
95 TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
97 void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
98 void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
99 //Returns true for a tile
100 bool IsTile() { return is_tile; };
101 //Returns true for a GameObject
102 bool IsObject() { return !is_tile; };
105 void Init() { tile = 0; obj = NULL; is_tile = true; };
107 bool is_tile; //true for tile (false for object)
112 /* leveleditor internals */
113 static string_list_type level_subsets;
114 static bool le_level_changed; /* if changes, ask for saving, when quiting*/
115 static bool show_minimap;
116 static bool show_selections;
117 static bool le_help_shown;
118 static int pos_x, pos_y, cursor_x, cursor_y;
119 static int le_levelnb;
120 static Level* le_level;
121 static LevelSubset* le_level_subset;
122 static int le_show_grid;
124 static Surface* le_selection;
126 static TileOrObject le_current;
127 static bool le_mouse_pressed[2];
128 static bool le_mouse_clicked[2];
129 static Button* le_save_level_bt;
130 static Button* le_exit_bt;
131 static Button* le_test_level_bt;
132 static Button* le_next_level_bt;
133 static Button* le_previous_level_bt;
134 static Button* le_move_right_bt;
135 static Button* le_move_left_bt;
136 static Button* le_move_up_bt;
137 static Button* le_move_down_bt;
138 static Button* le_rubber_bt;
139 static Button* le_select_mode_one_bt;
140 static Button* le_select_mode_two_bt;
141 static Button* le_settings_bt;
142 static Button* le_tilegroup_bt;
143 static Button* le_objects_bt;
144 static Button* le_object_select_bt;
145 static Button* le_object_properties_bt;
146 static ButtonPanel* le_tilemap_panel;
147 static int active_tm;
148 static Menu* leveleditor_menu;
149 static Menu* subset_load_menu;
150 static Menu* subset_new_menu;
151 static Menu* subset_settings_menu;
152 static Menu* level_settings_menu;
153 static Menu* select_tilegroup_menu;
154 static Menu* select_objects_menu;
155 static Timer select_tilegroup_menu_effect;
156 static Timer select_objects_menu_effect;
157 static Timer display_level_info;
158 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
159 static ButtonPanelMap tilegroups_map;
160 static ButtonPanelMap objects_map;
161 static std::string cur_tilegroup;
162 static std::string cur_objects;
163 static MouseCursor* mouse_select_object;
164 static MovingObject* selected_game_object;
166 static square selection;
167 static SelectionMode le_selection_mode;
168 static SDL_Event event;
170 int leveleditor(char* filename)
172 int last_time, now_time, i;
173 DrawingContext context;
181 sound_manager->halt_music();
183 while (SDL_PollEvent(&event))
187 if(le_load_level_subset(filename))
192 last_time = SDL_GetTicks();
197 if(Menu::current() == select_tilegroup_menu)
199 if(select_tilegroup_menu_effect.check())
201 select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
205 select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
207 else if(Menu::current() == select_objects_menu)
209 if(select_objects_menu_effect.check())
211 select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
214 select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
219 /* making events results to be in order */
222 le_drawlevel(context);
225 fillrect(0, 0, screen->w, screen->h, 0, 0, 0);
227 /* draw editor interface */
228 le_drawinterface(context);
230 Menu* menu = Menu::current();
236 if(menu == leveleditor_menu)
238 switch (leveleditor_menu->check())
240 case MNID_RETURNLEVELEDITOR:
242 Menu::set_current(0);
244 Menu::set_current(leveleditor_menu);
246 case MNID_SUBSETSETTINGS:
247 update_subset_settings_menu();
249 case MNID_QUITLEVELEDITOR:
254 else if(menu == level_settings_menu)
256 switch (level_settings_menu->check())
259 apply_level_settings_menu();
260 Menu::set_current(NULL);
267 else if(menu == select_tilegroup_menu)
270 switch (it = select_tilegroup_menu->check())
275 cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
276 Menu::set_current(0);
283 else if(menu == select_objects_menu)
286 switch (it = select_objects_menu->check())
291 cur_objects = select_objects_menu->get_item_by_id(it).text;
294 Menu::set_current(0);
299 else if(menu == subset_load_menu)
301 switch (i = subset_load_menu->check())
308 if(le_load_level_subset(level_subsets.item[i-1]))
314 else if(menu == subset_new_menu)
316 if(subset_new_menu->item[2].input[0] == '\0')
317 subset_new_menu->item[3].kind = MN_DEACTIVE;
320 subset_new_menu->item[3].kind = MN_ACTION;
322 switch (i = subset_new_menu->check())
324 case MNID_CREATESUBSET:
325 LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
326 le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
327 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
329 subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
331 Menu::set_current(subset_settings_menu);
336 else if(menu == subset_settings_menu)
338 if(le_level_subset->title.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETTITLE).input) == 0 && le_level_subset->description.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETDESCRIPTION).input) == 0 )
339 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
341 subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
343 switch (i = subset_settings_menu->check())
345 case MNID_SUBSETSAVECHANGES:
346 save_subset_settings_menu();
347 Menu::set_current(leveleditor_menu);
353 MouseCursor::current()->draw(context);
361 ++global_frame_counter;
364 now_time = SDL_GetTicks();
365 if (now_time < last_time + FPS)
366 SDL_Delay(last_time + FPS - now_time); /* delay some time */
368 context.do_drawing();
374 int le_load_level_subset(char *filename)
376 le_level_subset->load(filename);
377 leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
379 le_goto_level(le_levelnb);
381 //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
383 Menu::set_current(NULL);
392 leveleditor_menu = new Menu();
393 subset_load_menu = new Menu();
394 subset_new_menu = new Menu();
395 subset_settings_menu = new Menu();
396 level_settings_menu = new Menu();
397 select_tilegroup_menu = new Menu();
398 select_objects_menu = new Menu();
400 leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
401 leveleditor_menu->additem(MN_HL,"",0,0);
402 leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
403 leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
404 leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
405 leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
406 leveleditor_menu->additem(MN_HL,"",0,0);
407 leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
409 Menu::set_current(leveleditor_menu);
411 subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
412 subset_load_menu->additem(MN_HL, "", 0, 0);
414 for(i = 0; i < level_subsets.num_items; ++i)
416 subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
418 subset_load_menu->additem(MN_HL,"",0,0);
419 subset_load_menu->additem(MN_BACK,"Back",0,0);
421 subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
422 subset_new_menu->additem(MN_HL,"",0,0);
423 subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
424 subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
425 subset_new_menu->additem(MN_HL,"",0,0);
426 subset_new_menu->additem(MN_BACK,"Back",0,0);
428 subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
429 subset_settings_menu->additem(MN_HL,"",0,0);
430 subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
431 subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
432 subset_settings_menu->additem(MN_HL,"",0,0);
433 subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
434 subset_settings_menu->additem(MN_HL,"",0,0);
435 subset_settings_menu->additem(MN_BACK,"Back",0,0);
437 level_settings_menu->arrange_left = true;
438 level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
439 level_settings_menu->additem(MN_HL,"",0,0);
440 level_settings_menu->additem(MN_TEXTFIELD, "Name ",0,0,MNID_NAME);
441 level_settings_menu->additem(MN_TEXTFIELD, "Author ",0,0,MNID_AUTHOR);
442 level_settings_menu->additem(MN_STRINGSELECT,"Song ",0,0,MNID_SONG);
443 level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
444 level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
445 level_settings_menu->additem(MN_NUMFIELD, "Length ",0,0,MNID_LENGTH);
446 level_settings_menu->additem(MN_NUMFIELD, "Height ",0,0,MNID_HEIGHT);
447 level_settings_menu->additem(MN_NUMFIELD, "Time ",0,0,MNID_TIME);
448 level_settings_menu->additem(MN_NUMFIELD, "Gravity ",0,0,MNID_GRAVITY);
449 level_settings_menu->additem(MN_NUMFIELD, "Bg-Img-Speed",0,0,MNID_BGSPEED);
450 level_settings_menu->additem(MN_NUMFIELD, "Top Red ",0,0,MNID_TopRed);
451 level_settings_menu->additem(MN_NUMFIELD, "Top Green ",0,0,MNID_TopGreen);
452 level_settings_menu->additem(MN_NUMFIELD, "Top Blue ",0,0,MNID_TopBlue);
453 level_settings_menu->additem(MN_NUMFIELD, "Bottom Red ",0,0,MNID_BottomRed);
454 level_settings_menu->additem(MN_NUMFIELD, "Bottom Green",0,0,MNID_BottomGreen);
455 level_settings_menu->additem(MN_NUMFIELD, "Bottom Blue ",0,0,MNID_BottomBlue);
456 level_settings_menu->additem(MN_HL,"",0,0);
457 level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
459 select_tilegroup_menu->arrange_left = true;
460 select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
461 select_tilegroup_menu->additem(MN_HL,"",0,0);
462 std::set<TileGroup>* tilegroups = TileManager::tilegroups();
464 for(std::set<TileGroup>::iterator it = tilegroups->begin();
465 it != tilegroups->end(); ++it )
467 select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
469 tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
472 for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
473 sit != (*it).tiles.end(); ++sit, ++i)
475 Tile& tile = *(TileManager::instance()->get(*sit));
477 if(tile.editor_images.size() > 0)
478 image = tile.editor_images[0];
479 else if(tile.images.size() > 0)
480 image = tile.images[0];
482 // TODO use some notile image...
485 Button* button = new Button(image, it->name, SDLKey(SDLK_a + i),
487 tilegroups_map[it->name]->additem(button, *sit);
490 select_tilegroup_menu->additem(MN_HL,"",0,0);
492 select_objects_menu->arrange_left = true;
493 select_objects_menu->additem(MN_LABEL,"Objects",0,0);
494 select_objects_menu->additem(MN_HL,"",0,0);
496 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
497 objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
499 for(int i = 0; i < NUM_BadGuyKinds; ++i)
501 // BadGuy bad_tmp(BadGuyKind(i), 0, 0);
502 // objects_map["BadGuys"]->additem(new Button(0, "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
503 /* FIXME: maybe addbutton should already have a parameter for the surface
504 objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
505 BadGuy(BadGuyKind(i),
506 objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
507 objects_map["BadGuys"]->manipulate_button(i)->get_pos().y
511 select_objects_menu->additem(MN_HL,"",0,0);
517 level_subsets = dsubdirs("/levels", "level1.stl");
518 le_level_subset = new LevelSubset;
522 selected_game_object = NULL;
526 show_selections = true;
529 le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
530 le_level_changed = false;
531 le_help_shown = false;
533 le_mouse_pressed[LEFT] = false;
534 le_mouse_pressed[RIGHT] = false;
536 le_mouse_clicked[LEFT] = false;
537 le_mouse_clicked[RIGHT] = false;
539 le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
541 select_tilegroup_menu_effect.init(false);
542 select_objects_menu_effect.init(false);
543 display_level_info.init(false);
546 le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
547 le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
548 le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
549 le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
550 le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
551 le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
552 le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
553 le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
554 le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
555 le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
556 le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
557 le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
558 le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
559 le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
560 le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
561 le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
562 le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
563 le_object_properties_bt->set_active(false);
565 mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
566 mouse_select_object->set_mid(16,16);
568 le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
569 le_tilemap_panel->set_button_size(32,10);
570 le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
571 le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0), TM_IA);
572 le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
573 le_tilemap_panel->highlight_last(true);
574 le_tilemap_panel->set_last_clicked(TM_IA);
580 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
586 void update_level_settings_menu()
591 level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_level->name.c_str());
592 level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_level->author.c_str());
594 string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
595 string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
596 string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
597 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
598 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
599 string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
601 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_level->get_sector("main")->song_title.c_str())) != -1)
602 level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
603 if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_level->get_sector("main")->background->get_image().c_str())) != -1)
604 level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
605 /* if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_level->get_sector("main")->particlesystem.c_str())) != -1)
606 level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;*/
608 sprintf(str,"%d",le_level->get_sector("main")->solids->get_width());
609 level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
610 sprintf(str,"%d",le_level->get_sector("main")->solids->get_height());
611 level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
612 sprintf(str,"%d",le_level->time_left);
613 level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
614 sprintf(str,"%2.0f",le_level->get_sector("main")->gravity);
615 level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
616 sprintf(str,"%d",le_level->get_sector("main")->background->get_speed());
617 level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
618 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().red);
619 level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
620 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().green);
621 level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
622 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().blue);
623 level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
624 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().red);
625 level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
626 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().green);
627 level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
628 sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().blue);
629 level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
632 void update_subset_settings_menu()
634 subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
635 subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
638 void apply_level_settings_menu()
642 le_level_changed = true;
644 le_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
645 le_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
647 if(le_level->get_sector("main")->background->get_image().compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
649 le_level->get_sector("main")->background->set_image(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list), atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input));
653 /* if(le_level->get_sector("main")->particlesystem.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
655 le_level->->get_sector("main")->particlesystem = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
660 le_level->load_gfx();
663 le_level->get_sector("main")->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
665 le_level->get_sector("main")->solids->resize(
666 atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input),
667 atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
668 le_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
669 le_level->get_sector("main")->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
670 le_level->get_sector("main")->background->set_gradient(Color(
671 atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input),
672 atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input),
673 atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input)), Color(
674 atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input),
675 atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input),
676 atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input)));
679 void save_subset_settings_menu()
681 le_level_subset->title = subset_settings_menu->item[2].input;
682 le_level_subset->description = subset_settings_menu->item[3].input;
683 le_level_subset->save();
684 le_level_changed = false;
687 void le_unload_level()
692 sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
693 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
694 if(confirm_dialog(surf, str))
696 le_level->save(le_level_subset->get_level_filename(le_levelnb));
703 le_level_changed = false;
706 void le_goto_level(int levelnb)
709 le_level = new Level();
710 le_level->load(le_level_subset->get_level_filename(levelnb));
711 display_level_info.start(2500);
712 le_levelnb = levelnb;
717 SDL_EnableKeyRepeat(0, 0); // disables key repeating
721 delete leveleditor_menu;
722 delete subset_load_menu;
723 delete subset_new_menu;
724 delete subset_settings_menu;
725 delete level_settings_menu;
726 delete select_tilegroup_menu;
727 delete select_objects_menu;
728 delete le_save_level_bt;
730 delete le_test_level_bt;
731 delete le_next_level_bt;
732 delete le_previous_level_bt;
733 delete le_move_right_bt;
734 delete le_move_left_bt;
735 delete le_move_up_bt;
736 delete le_move_down_bt;
738 delete le_select_mode_one_bt;
739 delete le_select_mode_two_bt;
740 delete le_settings_bt;
741 delete le_tilegroup_bt;
742 delete le_objects_bt;
743 delete le_tilemap_panel;
744 delete le_object_select_bt;
745 delete le_object_properties_bt;
746 delete mouse_select_object;
748 delete le_level_subset;
751 for(ButtonPanelMap::iterator i = tilegroups_map.begin();
752 i != tilegroups_map.end(); ++i)
756 for(ButtonPanelMap::iterator i = objects_map.begin();
757 i != objects_map.end(); ++i)
763 void le_drawminimap()
766 // if(le_level == NULL)
770 if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 4)
772 else if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 2)
776 int left_offset = (screen->w - 64 - le_level->get_sector("main")->solids->get_width()*mini_tile_width) / 2;
778 int mini_tile_height;
779 if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 4)
780 mini_tile_height = 4;
781 else if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 2)
782 mini_tile_height = 2;
784 mini_tile_height = 1;
786 for (unsigned int y = 0; y < le_level->get_sector("main")->solids->get_height(); ++y)
787 for (unsigned int x = 0; x < le_level->get_sector("main")->solids->get_width(); ++x)
790 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
791 mini_tile_width , mini_tile_height, le_level->bg_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
793 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
794 mini_tile_width , mini_tile_height, le_level->ia_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
796 Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
797 mini_tile_width , mini_tile_height, le_level->fg_tiles[y + le_level->get_sector("main")->solids->get_width() + x]);
801 fillrect(left_offset, 0,
802 le_level->get_sector("main")->solids->get_width()*mini_tile_width, le_level->get_sector("main")->solids->get_height()*mini_tile_height,
805 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
806 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
808 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
809 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
811 fillrect(left_offset + (pos_x/32)*mini_tile_width + (VISIBLE_TILES_X-3)*mini_tile_width - 2, (pos_y/32)*mini_tile_height,
812 2, (VISIBLE_TILES_Y-1)*mini_tile_height,
814 fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height + (VISIBLE_TILES_Y-1)*mini_tile_height - 2,
815 (VISIBLE_TILES_X-3)*mini_tile_width, 2,
820 void le_drawinterface(DrawingContext &context)
827 /* draw a grid (if selected) */
830 for(x = 0; x < VISIBLE_TILES_X; x++)
831 fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
832 for(y = 0; y < VISIBLE_TILES_Y; y++)
833 fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
837 if(show_minimap) // use_gl because the minimap isn't shown correctly in software mode. Any idea? FIXME Possible reasons: SDL_SoftStretch is a hack itsself || an alpha blitting issue SDL can't handle in software mode
840 if(show_selections && MouseCursor::current() != mouse_select_object)
842 if(le_selection_mode == CURSOR)
844 if(le_current.IsTile())
845 context.draw_surface(le_selection, Vector(cursor_x - pos_x, cursor_y - pos_y), LAYER_GUI);
847 else if(le_selection_mode == SQUARE)
850 le_highlight_selection();
851 /* draw current selection */
852 w = selection.x2 - selection.x1;
853 h = selection.y2 - selection.y1;
854 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
855 context.draw_filled_rect(Vector(selection.x1 - pos_x + w, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
856 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y + h), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
857 context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
862 /* draw button bar */
863 context.draw_filled_rect(Vector(screen->w - 64, 0), Vector(64, screen->h), Color(50, 50, 50,255), LAYER_GUI);
865 if(le_current.IsTile())
867 // le_level->get_sector("main")->solids->draw(context);
869 /*screen->w - 32, screen->h - 32, le_current.tile);
870 if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
871 TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);*/
873 #if 0 // XXX FIXME TODO: Do we have a new solution for draw_on_screen()?
874 if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
876 le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
877 le_current.obj->draw_on_screen(cursor_x,cursor_y);
881 if(mouse_select_object && selected_game_object != NULL)
883 fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,selected_game_object->base.width,3,255,0,0,255);
884 fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
885 fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y+selected_game_object->base.height,selected_game_object->base.width,3,255,0,0,255);
886 fillrect(selected_game_object->base.x-pos_x+selected_game_object->base.width,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
891 le_save_level_bt->draw(context);
892 le_exit_bt->draw(context);
893 le_test_level_bt->draw(context);
894 le_next_level_bt->draw(context);
895 le_previous_level_bt->draw(context);
896 le_rubber_bt->draw(context);
897 if(le_selection_mode == SQUARE)
898 le_select_mode_one_bt->draw(context);
899 else if(le_selection_mode == CURSOR)
900 le_select_mode_two_bt->draw(context);
901 le_settings_bt->draw(context);
902 le_move_right_bt->draw(context);
903 le_move_left_bt->draw(context);
904 le_move_up_bt->draw(context);
905 le_move_down_bt->draw(context);
906 le_tilegroup_bt->draw(context);
907 le_objects_bt->draw(context);
908 if(!cur_tilegroup.empty())
909 tilegroups_map[cur_tilegroup]->draw(context);
910 else if(!cur_objects.empty())
912 objects_map[cur_objects]->draw(context);
915 le_tilemap_panel->draw(context);
917 if(!cur_objects.empty())
919 le_object_select_bt->draw(context);
920 le_object_properties_bt->draw(context);
923 sprintf(str, "%d/%d", le_levelnb,le_level_subset->levels);
924 context.draw_text(white_text, str, Vector((le_level_subset->levels < 10) ? -10 : 0, 16), LAYER_GUI);
927 context.draw_text(white_small_text, "F1 for Help", Vector(10, 430), LAYER_GUI);
929 if(display_level_info.check())
930 context.draw_text_center(white_text, le_level->name.c_str(), Vector(0, 0), LAYER_GUI);
935 context.draw_text(white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", Vector(10, 430), LAYER_GUI);
937 context.draw_text(white_small_text, "No Level Subset loaded", Vector(10, 430), LAYER_GUI);
942 void le_drawlevel(DrawingContext& context)
947 /* Draw the real background */
948 le_level->get_sector("main")->background->draw(context);
950 if(le_current.IsTile())
952 le_level->get_sector("main")->solids->draw(context);
954 Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
955 if(!TileManager::instance()->get(le_current.tile)->images.empty())
956 fillrect(cursor_x-pos_x,cursor_y-pos_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);*/
958 #if 0 // XXX FIXME TODO: Do we have a new solution for move_to()?
959 if(le_current.IsObject())
961 le_current.obj->move_to(cursor_x, cursor_y);
965 /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
968 le_level->get_sector("main")->solids->draw(context);
970 // FIXME: make tiles to be drawn semi-transparent when not selected
972 for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_level->get_section("main")->height; ++y)
973 for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
976 if(active_tm == TM_BG)
981 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
982 le_level->bg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
983 (x + (int)(pos_x / 32))],a);
985 if(active_tm == TM_IA)
990 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
991 le_level->ia_tiles[ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width +
992 (x + (int)(pos_x / 32))],a);
995 if(active_tm == TM_FG)
1000 Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
1001 le_level->fg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +
1002 (x + (int)(pos_x / 32))],a);
1004 /* draw whats inside stuff when cursor is selecting those */
1005 /* (draw them all the time - is this the right behaviour?) */
1006 Tile* edit_image = TileManager::instance()->get(
1008 [ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width + (x + (int)(pos_x / 32))]);
1009 if(edit_image && !edit_image->editor_images.empty())
1010 edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
1014 /* Draw the Bad guys: */
1015 for (std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1016 it != le_level->get_sector("main")->gameobjects.end(); ++it)
1018 BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
1022 /* to support frames: img_bsod_left[(frame / 5) % 4] */
1023 badguy->draw(context);
1026 /* Draw the player: */
1027 /* for now, the position is fixed at (100, 240) */
1028 largetux.walk_right->draw(context, Vector(100 - pos_x, 240 - pos_y), LAYER_OBJECTS-1);
1031 void le_change_object_properties(GameObject *pobj)
1033 DrawingContext context;
1035 Menu* object_properties_menu = new Menu();
1038 std::string type = typeid(pobj).name();
1039 object_properties_menu->additem(MN_LABEL, type + " Properties",0,0);
1040 object_properties_menu->additem(MN_HL,"",0,0);
1042 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1045 object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
1046 for(int i = 0; i < NUM_BadGuyKinds; ++i)
1048 string_list_add_item(object_properties_menu->get_item_by_id(1).list,
1049 badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
1051 object_properties_menu->get_item_by_id(1).list->active_item = i;
1053 object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
1056 object_properties_menu->additem(MN_HL,"",0,0);
1057 object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
1059 Menu::set_current(object_properties_menu);
1065 while (SDL_PollEvent(&event))
1067 object_properties_menu->event(event);
1070 //cap_screen->draw(0,0);
1072 object_properties_menu->draw(context);
1073 object_properties_menu->action();
1075 switch (object_properties_menu->check())
1079 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1081 BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1082 pbad->kind = badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
1083 pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
1092 if(Menu::current() == NULL)
1095 mouse_cursor->draw(context);
1096 // context.draw_filled_rect();
1100 //delete cap_screen;
1101 Menu::set_current(0);
1102 delete object_properties_menu;
1106 void le_checkevents()
1113 keymod = SDL_GetModState();
1115 while(SDL_PollEvent(&event))
1117 if (Menu::current())
1119 Menu::current()->event(event);
1120 if(!le_level && !Menu::current())
1121 Menu::set_current(leveleditor_menu);
1125 mouse_cursor->set_state(MC_NORMAL);
1127 /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1128 if(event.type == SDL_KEYDOWN
1129 || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1130 && (event.motion.x > 0
1131 && event.motion.x < screen->w - 64 &&
1132 event.motion.y > 0 && event.motion.y < screen->h)))
1136 case SDL_KEYDOWN: // key pressed
1137 key = event.key.keysym.sym;
1141 Menu::set_current(leveleditor_menu);
1144 if(le_level != NULL)
1152 cursor_x = (le_level->get_sector("main")->solids->get_width() * 32) - 32;
1156 le_show_grid = !le_show_grid;
1162 case SDL_MOUSEBUTTONDOWN:
1163 if(event.button.button == SDL_BUTTON_LEFT)
1165 le_mouse_pressed[LEFT] = true;
1167 selection.x1 = event.motion.x + pos_x;
1168 selection.y1 = event.motion.y + pos_y;
1169 selection.x2 = event.motion.x + pos_x;
1170 selection.y2 = event.motion.y + pos_y;
1172 else if(event.button.button == SDL_BUTTON_RIGHT)
1174 le_mouse_pressed[RIGHT] = true;
1177 case SDL_MOUSEBUTTONUP:
1178 if(event.button.button == SDL_BUTTON_LEFT)
1180 le_mouse_pressed[LEFT] = false;
1181 le_mouse_clicked[LEFT] = true;
1183 else if(event.button.button == SDL_BUTTON_RIGHT)
1185 le_mouse_pressed[RIGHT] = false;
1186 le_mouse_clicked[RIGHT] = true;
1189 case SDL_MOUSEMOTION:
1191 if(!Menu::current())
1196 if(le_current.IsTile())
1198 cursor_x = ((int)(pos_x + x) / 32) * 32;
1199 cursor_y = ((int)(pos_y + y) / 32) * 32;
1207 if(le_mouse_pressed[LEFT])
1209 selection.x2 = x + pos_x;
1210 selection.y2 = y + pos_y;
1213 if(le_mouse_pressed[RIGHT])
1215 pos_x += -1 * event.motion.xrel;
1216 pos_y += -1 * event.motion.yrel;
1224 else if(event.type == SDL_QUIT) /* window closing */
1230 if(le_level != NULL)
1232 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 &&
1233 event.motion.y > 0 && event.motion.y < screen->h)))
1235 le_mouse_pressed[LEFT] = false;
1236 le_mouse_pressed[RIGHT] = false;
1238 if(!Menu::current())
1240 /* Check for button events */
1241 le_test_level_bt->event(event);
1242 if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1244 le_save_level_bt->event(event);
1245 if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1246 le_level->save(le_level_subset->name.c_str());
1247 le_exit_bt->event(event);
1248 if(le_exit_bt->get_state() == BUTTON_CLICKED)
1250 Menu::set_current(leveleditor_menu);
1252 le_next_level_bt->event(event);
1253 if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1255 if(le_levelnb < le_level_subset->levels)
1257 le_goto_level(le_levelnb+1);
1263 sprintf(str,"Level %d doesn't exist. Create it?",le_levelnb+1);
1264 Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
1265 if(confirm_dialog(surf, str))
1267 new_lev.save(le_level_subset->name.c_str());
1268 le_level_subset->levels = le_levelnb;
1269 le_goto_level(le_levelnb);
1275 le_previous_level_bt->event(event);
1276 if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1279 le_goto_level(le_levelnb -1);
1281 le_rubber_bt->event(event);
1282 if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1285 if(!cur_objects.empty())
1287 le_object_select_bt->event(event);
1288 if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1290 MouseCursor::set_current(mouse_select_object);
1293 le_object_properties_bt->event(event);
1294 if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1296 le_change_object_properties(selected_game_object);
1301 if(le_selection_mode == SQUARE)
1303 le_select_mode_one_bt->event(event);
1304 if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1305 le_selection_mode = CURSOR;
1309 le_select_mode_two_bt->event(event);
1310 if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1311 le_selection_mode = SQUARE;
1313 ButtonPanelMap::iterator it;
1314 le_tilegroup_bt->event(event);
1315 switch (le_tilegroup_bt->get_state())
1317 case BUTTON_CLICKED:
1318 Menu::set_current(select_tilegroup_menu);
1319 select_tilegroup_menu_effect.start(200);
1320 select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1322 case BUTTON_WHEELUP:
1323 if(cur_tilegroup.empty())
1325 cur_tilegroup = tilegroups_map.begin()->first;
1329 it = tilegroups_map.find(cur_tilegroup);
1330 if((++it) == tilegroups_map.end())
1332 cur_tilegroup = tilegroups_map.begin()->first;
1336 cur_tilegroup = (*it).first;
1342 case BUTTON_WHEELDOWN:
1343 it = tilegroups_map.find(cur_tilegroup);
1344 if(it == tilegroups_map.begin())
1346 cur_tilegroup = tilegroups_map.rbegin()->first;
1350 if(--it != --tilegroups_map.begin())
1351 cur_tilegroup = (*it).first;
1353 cur_tilegroup = tilegroups_map.rbegin()->first;
1361 le_objects_bt->event(event);
1362 switch (le_objects_bt->get_state())
1364 case BUTTON_CLICKED:
1365 Menu::set_current(select_objects_menu);
1366 select_objects_menu_effect.start(200);
1367 select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1369 case BUTTON_WHEELUP:
1370 it = objects_map.find(cur_objects);
1371 if(it == objects_map.end())
1373 cur_objects = objects_map.begin()->first;
1377 if(++it != objects_map.end())
1378 cur_objects = (*it).first;
1380 cur_objects = objects_map.begin()->first;
1384 case BUTTON_WHEELDOWN:
1385 it = objects_map.find(cur_objects);
1386 if(it == objects_map.begin())
1388 cur_objects = objects_map.rbegin()->first;
1392 if(--it != --objects_map.begin())
1393 cur_objects = (*it).first;
1395 cur_objects = objects_map.rbegin()->first;
1404 le_settings_bt->event(event);
1405 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1407 update_level_settings_menu();
1408 Menu::set_current(level_settings_menu);
1410 if(!cur_tilegroup.empty())
1412 if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1414 if(pbutton->get_state() == BUTTON_CLICKED)
1416 le_current.Tile(pbutton->get_tag());
1420 else if(!cur_objects.empty())
1422 if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1424 if(pbutton->get_state() == BUTTON_CLICKED)
1426 #if 0 // TODO FIXME XXX: New solution for this?
1427 le_current.Object(pbutton->get_drawable());
1433 if((pbutton = le_tilemap_panel->event(event)) != NULL)
1435 if(pbutton->get_state() == BUTTON_CLICKED)
1437 active_tm = pbutton->get_tag();
1443 le_settings_bt->event(event);
1444 if(le_settings_bt->get_state() == BUTTON_CLICKED)
1446 Menu::set_current(0);
1448 le_tilegroup_bt->event(event);
1449 if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1451 Menu::set_current(0);
1453 le_objects_bt->event(event);
1454 if(le_objects_bt->get_state() == BUTTON_CLICKED)
1456 Menu::set_current(0);
1461 if(!Menu::current() && !show_minimap)
1463 if(le_mouse_pressed[LEFT])
1465 if(MouseCursor::current() != mouse_select_object)
1467 if(le_current.IsTile())
1468 le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1471 else if(le_mouse_clicked[LEFT])
1473 if(MouseCursor::current() == mouse_select_object)
1475 bool object_got_hit = false;
1476 base_type cursor_base;
1477 if(le_current.IsTile())
1479 cursor_base.x = cursor_x;
1480 cursor_base.y = cursor_y;
1482 else if(le_current.IsObject())
1484 cursor_base.x = cursor_x + pos_x;
1485 cursor_base.y = cursor_y + pos_y;
1487 cursor_base.width = 32;
1488 cursor_base.height = 32;
1490 for(std::vector<GameObject*>::iterator it =
1491 le_level->get_sector("main")->gameobjects.begin();
1492 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1493 MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
1497 if(rectcollision(cursor_base, mobj->base))
1499 selected_game_object = mobj;
1500 object_got_hit = true;
1507 selected_game_object = NULL;
1508 le_object_properties_bt->set_active(false);
1511 le_object_properties_bt->set_active(true);
1513 MouseCursor::set_current(mouse_cursor);
1520 //FIXME: objects interactions with the level editor should have a major improvement
1521 if(le_current.IsObject())
1523 le_level_changed = true;
1524 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1528 Camera& camera = *le_level->get_sector("main")->camera;
1530 le_level->get_sector("main")->bad_guys.push_back(
1531 new BadGuy(pbadguy->kind,
1532 cursor_x + camera.get_translation().x,
1533 cursor_y + camera.get_translation().y));
1534 le_level->get_sector("main")->gameobjects.push_back(le_level->get_sector("main")->bad_guys.back());
1541 le_mouse_clicked[LEFT] = false;
1547 if(!Menu::current())
1549 show_minimap = false;
1551 if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB)
1552 show_minimap = true;
1554 le_move_left_bt->event(event);
1555 le_move_right_bt->event(event);
1556 le_move_up_bt->event(event);
1557 le_move_down_bt->event(event);
1558 switch(le_move_left_bt->get_state())
1560 case BUTTON_PRESSED:
1561 pos_x -= KEYBOARD_SPEED;
1562 show_minimap = true;
1565 pos_x -= MOUSE_SPEED;
1566 show_minimap = true;
1568 case BUTTON_CLICKED:
1569 show_minimap = true;
1575 switch(le_move_right_bt->get_state())
1577 case BUTTON_PRESSED:
1578 pos_x += KEYBOARD_SPEED;
1579 show_minimap = true;
1582 pos_x += MOUSE_SPEED;
1583 show_minimap = true;
1585 case BUTTON_CLICKED:
1586 show_minimap = true;
1592 switch(le_move_up_bt->get_state())
1594 case BUTTON_PRESSED:
1595 pos_y -= KEYBOARD_SPEED;
1596 show_minimap = true;
1599 pos_y -= MOUSE_SPEED;
1600 show_minimap = true;
1602 case BUTTON_CLICKED:
1603 show_minimap = true;
1609 switch(le_move_down_bt->get_state())
1611 case BUTTON_PRESSED:
1612 pos_y += KEYBOARD_SPEED;
1613 show_minimap = true;
1616 pos_y += MOUSE_SPEED;
1617 show_minimap = true;
1619 case BUTTON_CLICKED:
1620 show_minimap = true;
1626 /* checking if pos_x and pos_y is within the limits... */
1627 if((unsigned)pos_x > (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w)
1628 pos_x = (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w;
1632 if((unsigned)pos_y > (le_level->get_sector("main")->solids->get_height() * 32) - screen->h)
1633 pos_y = (le_level->get_sector("main")->solids->get_height() * 32) - screen->h;
1639 void le_highlight_selection()
1643 if(selection.x1 < selection.x2)
1653 if(selection.y1 < selection.y2)
1669 fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1672 void le_change(float x, float y, int tm, unsigned int c)
1674 if(le_level != NULL)
1679 le_level_changed = true;
1681 switch(le_selection_mode)
1684 le_change(x,y,tm,c);
1686 base_type cursor_base;
1689 cursor_base.width = 32;
1690 cursor_base.height = 32;
1692 /* if there is a bad guy over there, remove it */
1694 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1695 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1696 BadGuy* badguy = dynamic_cast<BadGuy*>((*it));
1699 if(rectcollision(cursor_base, badguy->base))
1702 le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(),
1703 le_level->get_sector("main")->gameobjects.end(), *it),
1704 le_level->get_sector("main")->gameobjects.end());
1712 if(selection.x1 < selection.x2)
1722 if(selection.y1 < selection.y2)
1738 /* if there is a bad guy over there, remove it */
1740 for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1741 it != le_level->get_sector("main")->gameobjects.end(); ++it /* will be at end of loop */)
1743 MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);
1746 if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
1747 && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
1750 le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(), le_level->get_sector("main")->gameobjects.end(), *it), le_level->get_sector("main")->gameobjects.end());
1760 for(xx = x1; xx <= x2; xx++)
1761 for(yy = y1; yy <= y2; yy++)
1763 le_change(xx*32, yy*32, tm, c);
1775 //Make sure a time value is set when testing the level
1776 if(le_level->time_left == 0)
1777 le_level->time_left = 250;
1779 le_level->save("test.stl");
1781 GameSession session("test.stl", ST_GL_TEST);
1783 player_status.reset();
1785 sound_manager->halt_music();
1787 Menu::set_current(NULL);
1792 DrawingContext context;
1794 bool tmp_show_grid = le_show_grid;
1795 SelectionMode temp_le_selection_mode = le_selection_mode;
1796 le_selection_mode = NONE;
1797 show_selections = true;
1798 le_show_grid = false;
1799 le_help_shown = true;
1806 " - Supertux level editor tutorial - ",
1808 "To make your map, click the ",
1809 "tilegroup button and choose a ",
1811 "Pick a tile and simply hold down ",
1812 "the left mouse button over the map",
1813 "to \"paint\" your selection over",
1816 "There are three layers for painting",
1817 "tiles upon, Background layer,",
1818 "the Interactive layer, and the",
1819 "Foreground layer, which can be",
1820 "toggled by the BkGrd, IntAct and",
1821 "FrGrd buttons. The Foreground and",
1822 "Background layers do not effect",
1823 "Tux in the gameplay, but lie in",
1824 "front of him or lie behind him in",
1830 " - Supertux level editor tutorial - ",
1832 "The tiles placed on",
1833 "the Interactive layer are those",
1834 "which actually effect Tux in the",
1837 "Click the objects menu to put ",
1838 "bad guys and other objects in the",
1839 "game. Unlike placing tiles, you",
1840 "cannot \"paint\" enemies. Click",
1841 "them onto the screen one at a time.",
1843 "To change the settings of your",
1844 "level, click the button with the",
1845 "screwdriver and wrench. From here",
1846 "you can change the background,",
1847 "music, length of the level,",
1853 " - Supertux level editor tutorial - ",
1855 "You may have more than one level.",
1856 "Pressing the up and down buttons",
1857 "above the button bar lets you",
1858 "choose which one you are working on.",
1860 "If you would like to speed up your",
1861 "level editing, a useful trick is",
1862 "to learn the keyboard shortcuts.",
1863 "They are easy to learn, just right-",
1864 "click on the buttons.",
1866 "Have fun making levels! If you make",
1867 "some good ones, send them to us on",
1868 "the SuperTux mailing list!",
1872 char **text[] = { text1, text2, text3 };
1875 for(int i = 0; i < 3; i++)
1877 context.draw_gradient(Color(0,0,0), Color(255,255,255), LAYER_BACKGROUND0);
1878 le_drawinterface(context);
1880 context.draw_text_center(blue_text, "- Help -", Vector(0, 30), LAYER_GUI);
1882 for(unsigned int t = 0; t < sizeof(text[i])/sizeof(char *); t++)
1883 context.draw_text(white_text, text[i][t], Vector(5, 80+(t*white_text->get_height())), LAYER_GUI);
1885 sprintf(str,"Press any key to continue - Page %d/%d?", i, sizeof(text));
1886 context.draw_text(gold_text, str, Vector(0, 0), LAYER_GUI);
1888 context.do_drawing();
1894 done_ = wait_for_event(event);
1899 show_selections = true;
1900 le_show_grid = tmp_show_grid;
1901 le_selection_mode = temp_le_selection_mode;
1902 le_help_shown = false;