133664a60c22161ec850df2566b8d186cea2af19
[supertux.git] / src / leveleditor.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
5 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
6 //
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.
11 //
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.
16 //
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.
20
21 #include <map>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <SDL.h>
29 #include <SDL_image.h>
30 #include "leveleditor.h"
31
32 #include "screen.h"
33 #include "defines.h"
34 #include "globals.h"
35 #include "setup.h"
36 #include "menu.h"
37 #include "level.h"
38 #include "gameloop.h"
39 #include "badguy.h"
40 #include "scene.h"
41 #include "button.h"
42 #include "tile.h"
43 #include "resources.h"
44 #include "music_manager.h"
45
46 /* definitions to aid development */
47
48 /* definitions that affect gameplay */
49 #define KEY_CURSOR_SPEED 32
50 #define KEY_CURSOR_FASTSPEED 64
51
52 /* when pagedown/up pressed speed:*/
53 #define PAGE_CURSOR_SPEED 13*32
54
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
60
61 /* look */
62 #define SELECT_W 2 // size of the selections lines
63 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
64
65 /* own declerations */
66 /* crutial ones (main loop) */
67 int le_init();
68 void le_quit();
69 int le_load_level_subset(char *filename);
70 void le_drawlevel();
71 void le_drawinterface();
72 void le_checkevents();
73 void le_change(float x, float y, int tm, unsigned int c);
74 void le_testlevel();
75 void le_showhelp();
76 void le_set_defaults(void);
77 void le_activate_bad_guys(void);
78 void le_goto_level(int levelnb);
79 void le_highlight_selection();
80
81 void apply_level_settings_menu();
82 void update_subset_settings_menu();
83 void save_subset_settings_menu();
84
85 struct TileOrObject
86 {
87   TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
88
89   void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
90   void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
91   //Returns true for a tile
92   bool IsTile() { return is_tile; };
93   //Returns true for a GameObject
94   bool IsObject() { return !is_tile; };
95   void Init() { tile = 0; obj = NULL; is_tile = true; };
96
97   bool is_tile; //true for tile (false for object)
98   unsigned int tile;
99   GameObject* obj;
100 };
101
102 /* leveleditor internals */
103 static string_list_type level_subsets;
104 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
105 static bool show_minimap;
106 static bool le_help_shown;
107 static int pos_x, cursor_x, cursor_y, fire;
108 static int le_level;
109 static World* le_world;
110 static LevelSubset* le_level_subset;
111 static int le_show_grid;
112 static int le_frame;
113 static Surface* le_selection;
114 static int done;
115 static TileOrObject le_current;
116 static bool le_mouse_pressed[2];
117 static bool le_mouse_clicked[2];
118 static Button* le_save_level_bt;
119 static Button* le_exit_bt;
120 static Button* le_test_level_bt;
121 static Button* le_next_level_bt;
122 static Button* le_previous_level_bt;
123 static Button* le_move_right_bt;
124 static Button* le_move_left_bt;
125 static Button* le_rubber_bt;
126 static Button* le_select_mode_one_bt;
127 static Button* le_select_mode_two_bt;
128 static Button* le_settings_bt;
129 static Button* le_tilegroup_bt;
130 static Button* le_objects_bt;
131 static ButtonPanel* le_tilemap_panel;
132 static Menu* leveleditor_menu;
133 static Menu* subset_load_menu;
134 static Menu* subset_new_menu;
135 static Menu* subset_settings_menu;
136 static Menu* level_settings_menu;
137 static Menu* select_tilegroup_menu;
138 static Menu* select_objects_menu;
139 static Timer select_tilegroup_menu_effect;
140 static Timer select_objects_menu_effect;
141 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
142 static ButtonPanelMap tilegroups_map;
143 static ButtonPanelMap objects_map;
144 static std::string cur_tilegroup;
145 static std::string cur_objects;
146
147 static square selection;
148 static int le_selection_mode;
149 static SDL_Event event;
150 TileMapType active_tm;
151
152 int leveleditor(char* filename)
153 {
154   int last_time, now_time, i;
155
156   le_level = 1;
157
158   if(le_init() != 0)
159     return 1;
160
161   /* Clear screen: */
162
163   clearscreen(0, 0, 0);
164   updatescreen();
165
166   music_manager->halt_music();
167
168   while (SDL_PollEvent(&event))
169   {}
170
171   if(filename != NULL)
172     if(le_load_level_subset(filename))
173       return 1;
174
175   while(true)
176   {
177     last_time = SDL_GetTicks();
178     le_frame++;
179
180     le_checkevents();
181
182     if(Menu::current() == select_tilegroup_menu)
183     {
184       if(select_tilegroup_menu_effect.check())
185       {
186         select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
187                                        66,-0.5,0.5);
188       }
189       else
190         select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
191     }
192     else if(Menu::current() == select_objects_menu)
193     {
194       if(select_objects_menu_effect.check())
195       {
196         select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
197       }
198       else
199         select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
200     }
201
202     if(le_world != NULL)
203     {
204       /* making events results to be in order */
205       if(pos_x < 0)
206         pos_x = 0;
207       if(pos_x > (le_world->get_level()->width * 32) - screen->w)
208         pos_x = (le_world->get_level()->width * 32) - screen->w;
209
210       /* draw the level */
211       le_drawlevel();
212     }
213     else
214       clearscreen(0, 0, 0);
215
216     /* draw editor interface */
217     le_drawinterface();
218
219     Menu* menu = Menu::current();
220     if(menu)
221     {
222       menu->draw();
223       menu->action();
224
225       if(menu == leveleditor_menu)
226       {
227         switch (leveleditor_menu->check())
228         {
229         case MNID_RETURNLEVELEDITOR:
230           if(le_world != NULL)
231             Menu::set_current(0);
232           else
233             Menu::set_current(leveleditor_menu);
234           break;
235         case MNID_SUBSETSETTINGS:
236           update_subset_settings_menu();
237           break;
238         case MNID_QUITLEVELEDITOR:
239           done = 1;
240           break;
241         }
242       }
243       else if(menu == level_settings_menu)
244       {
245         switch (level_settings_menu->check())
246         {
247         case MNID_APPLY:
248           apply_level_settings_menu();
249           Menu::set_current(NULL);
250           break;
251
252         default:
253           break;
254         }
255       }
256       else if(menu == select_tilegroup_menu)
257       {
258         int it = -1;
259         switch (it = select_tilegroup_menu->check())
260         {
261         default:
262           if(it >= 0)
263           {
264             cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
265             Menu::set_current(0);
266             cur_objects = "";
267
268           }
269           break;
270         }
271       }
272       else if(menu == select_objects_menu)
273       {
274         int it = -1;
275         switch (it = select_objects_menu->check())
276         {
277         default:
278           if(it >= 0)
279           {
280             cur_objects = select_objects_menu->get_item_by_id(it).text;
281             cur_tilegroup = "";
282
283             Menu::set_current(0);
284           }
285           break;
286         }
287       }
288       else if(menu == subset_load_menu)
289       {
290         switch (i = subset_load_menu->check())
291         {
292         case 0:
293           break;
294         default:
295           if(i >= 1)
296           {
297             if(le_load_level_subset(level_subsets.item[i-1]))
298               return 1;
299           }
300           break;
301         }
302       }
303       else if(menu == subset_new_menu)
304       {
305         if(subset_new_menu->item[2].input[0] == '\0')
306           subset_new_menu->item[3].kind = MN_DEACTIVE;
307         else
308         {
309           subset_new_menu->item[3].kind = MN_ACTION;
310
311           switch (i = subset_new_menu->check())
312           {
313           case MNID_CREATESUBSET:
314             LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
315             le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
316             leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
317             le_goto_level(1);
318             subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
319
320             Menu::set_current(subset_settings_menu);
321             break;
322           }
323         }
324       }
325       else if(menu == subset_settings_menu)
326       {
327         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  )
328           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
329         else
330           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
331
332         switch (i = subset_settings_menu->check())
333         {
334         case MNID_SUBSETSAVECHANGES:
335           save_subset_settings_menu();
336           Menu::set_current(leveleditor_menu);
337           break;
338         }
339       }
340     }
341
342     mouse_cursor->draw();
343
344     if(done)
345     {
346       le_quit();
347       return 0;
348     }
349
350     ++global_frame_counter;
351
352     SDL_Delay(25);
353     now_time = SDL_GetTicks();
354     if (now_time < last_time + FPS)
355       SDL_Delay(last_time + FPS - now_time);    /* delay some time */
356
357     flipscreen();
358   }
359
360   return done;
361 }
362
363 int le_load_level_subset(char *filename)
364 {
365   le_level_subset->load(filename);
366   leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
367   le_level = 1;
368   le_goto_level(1);
369
370   //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
371
372   Menu::set_current(NULL);
373
374   return 0;
375 }
376
377 void le_init_menus()
378 {
379   int i;
380
381   leveleditor_menu = new Menu();
382   subset_load_menu = new Menu();
383   subset_new_menu  = new Menu();
384   subset_settings_menu = new Menu();
385   level_settings_menu  = new Menu();
386   select_tilegroup_menu  = new Menu();
387   select_objects_menu = new Menu();
388
389   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
390   leveleditor_menu->additem(MN_HL,"",0,0);
391   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
392   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
393   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
394   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
395   leveleditor_menu->additem(MN_HL,"",0,0);
396   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
397
398   Menu::set_current(leveleditor_menu);
399
400   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
401   subset_load_menu->additem(MN_HL, "", 0, 0);
402
403   for(i = 0; i < level_subsets.num_items; ++i)
404   {
405     subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
406   }
407   subset_load_menu->additem(MN_HL,"",0,0);
408   subset_load_menu->additem(MN_BACK,"Back",0,0);
409
410   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
411   subset_new_menu->additem(MN_HL,"",0,0);
412   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
413   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
414   subset_new_menu->additem(MN_HL,"",0,0);
415   subset_new_menu->additem(MN_BACK,"Back",0,0);
416
417   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
418   subset_settings_menu->additem(MN_HL,"",0,0);
419   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
420   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
421   subset_settings_menu->additem(MN_HL,"",0,0);
422   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
423   subset_settings_menu->additem(MN_HL,"",0,0);
424   subset_settings_menu->additem(MN_BACK,"Back",0,0);
425
426   level_settings_menu->arrange_left = true;
427   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
428   level_settings_menu->additem(MN_HL,"",0,0);
429   level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
430   level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
431   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
432   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
433   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
434   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
435   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
436   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
437   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
438   level_settings_menu->additem(MN_NUMFIELD,    "Top Red    ",0,0,MNID_TopRed);
439   level_settings_menu->additem(MN_NUMFIELD,    "Top Green  ",0,0,MNID_TopGreen);
440   level_settings_menu->additem(MN_NUMFIELD,    "Top Blue   ",0,0,MNID_TopBlue);
441   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red ",0,0,MNID_BottomRed);
442   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
443   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue",0,0,MNID_BottomBlue);
444   level_settings_menu->additem(MN_HL,"",0,0);
445   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
446
447   select_tilegroup_menu->arrange_left = true;
448   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
449   select_tilegroup_menu->additem(MN_HL,"",0,0);
450   select_tilegroup_menu->additem(MN_ACTION,"asd",0,0);
451   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
452   int tileid = 1;
453   for(std::set<TileGroup>::iterator it = tilegroups->begin();
454         it != tilegroups->end(); ++it )
455     {
456       select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
457       tileid++;
458       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
459       i = 0;
460
461       for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
462           sit != (*it).tiles.end(); ++sit, ++i)
463       {
464         std::string imagefile = "/images/tilesets/" ;
465         bool only_editor_image = false;
466         if(!TileManager::instance()->get(*sit)->filenames.empty())
467         {
468           imagefile += TileManager::instance()->get(*sit)->filenames[0];
469         }
470         else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
471         {
472           imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
473           only_editor_image = true;
474         }
475         else
476         {
477           imagefile += "notile.png";
478         }
479         Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
480                                     0, 0, 32, 32);
481         if(!only_editor_image)
482           if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
483           {
484             imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
485             button->add_icon(imagefile,32,32);
486           }
487         tilegroups_map[it->name]->additem(button, *sit);
488       }
489     }
490   select_tilegroup_menu->additem(MN_HL,"",0,0);
491
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);
495   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
496   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
497
498   for(int i = 0; i < NUM_BadGuyKinds; ++i)
499   {
500     BadGuy bad_tmp(0,0,BadGuyKind(i),false);
501     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
502     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));
503   }
504
505   select_objects_menu->additem(MN_HL,"",0,0);
506
507 }
508
509 int le_init()
510 {
511
512
513   level_subsets = dsubdirs("/levels", "level1.stl");
514   le_level_subset = new LevelSubset;
515
516   le_world = NULL;
517
518   active_tm = TM_IA;
519   le_show_grid = true;
520   scroll_x = 0;
521
522   fire = DOWN;
523   done = 0;
524   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
525   le_level_changed = false;
526   le_help_shown = false;
527
528   le_mouse_pressed[LEFT] = false;
529   le_mouse_pressed[RIGHT] = false;
530
531   le_mouse_clicked[LEFT] = false;
532   le_mouse_clicked[RIGHT] = false;
533
534   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
535
536   select_tilegroup_menu_effect.init(false);
537   select_objects_menu_effect.init(false);
538
539   /* Load buttons */
540   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
541   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
542   le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
543   le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
544   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
545   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
546   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
547   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
548   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
549   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
550   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
551   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
552   le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F7,screen->w-64,80);
553
554   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
555   le_tilemap_panel->set_button_size(32,10);
556   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
557   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0),TM_IA);
558   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
559   le_tilemap_panel->highlight_last(true);
560   le_tilemap_panel->set_last_clicked(TM_IA);
561
562   le_current.Init();
563
564   le_init_menus();
565
566   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
567
568
569   return 0;
570 }
571
572 void update_level_settings_menu()
573 {
574   char str[80];
575   int i;
576
577   level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_world->get_level()->name.c_str());
578   level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_world->get_level()->author.c_str());
579
580   string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
581   string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
582   string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
583   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
584   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
585   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
586
587   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_world->get_level()->song_title.c_str())) != -1)
588     level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
589   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_world->get_level()->bkgd_image.c_str())) != -1)
590     level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
591   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_world->get_level()->particle_system.c_str())) != -1)
592     level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
593
594   sprintf(str,"%d",le_world->get_level()->width);
595   level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
596   sprintf(str,"%d",le_world->get_level()->time_left);
597   level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
598   sprintf(str,"%2.0f",le_world->get_level()->gravity);
599   level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
600   sprintf(str,"%d",le_world->get_level()->bkgd_speed);
601   level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
602   sprintf(str,"%d",le_world->get_level()->bkgd_top.red);
603   level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
604   sprintf(str,"%d",le_world->get_level()->bkgd_top.green);
605   level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
606   sprintf(str,"%d",le_world->get_level()->bkgd_top.blue);
607   level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
608   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.red);
609   level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
610   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.green);
611   level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
612   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.blue);
613   level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
614 }
615
616 void update_subset_settings_menu()
617 {
618   subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
619   subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
620 }
621
622 void apply_level_settings_menu()
623 {
624   int i;
625   i = false;
626
627   le_world->get_level()->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
628   le_world->get_level()->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
629
630   if(le_world->get_level()->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
631   {
632     le_world->get_level()->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
633     i = true;
634   }
635
636   if(le_world->get_level()->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
637   {
638     le_world->get_level()->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
639   }
640
641   if(i)
642   {
643     le_world->get_level()->load_gfx();
644   }
645
646   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
647
648   le_world->get_level()->change_size(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input));
649   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
650   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
651   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
652   le_world->get_level()->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
653   le_world->get_level()->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
654   le_world->get_level()->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
655   le_world->get_level()->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
656   le_world->get_level()->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
657   le_world->get_level()->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
658 }
659
660 void save_subset_settings_menu()
661 {
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();
665 }
666
667 void le_unload_level()
668 {
669   if(le_level_changed)
670   {
671     le_drawlevel();
672     le_drawinterface();
673     char str[1024];
674     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
675     if(confirm_dialog(str))
676     {
677       le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
678     }
679   }
680
681   delete le_world;
682   le_level_changed = false;  
683 }
684
685 void le_goto_level(int levelnb)
686 {
687   le_unload_level();
688   le_world = new World(le_level_subset->name, levelnb);
689 }
690
691 void le_quit(void)
692 {
693   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
694
695   le_unload_level();
696   delete le_selection;
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;
705   delete le_exit_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;
711   delete le_rubber_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;
718
719   delete le_level_subset;
720   le_level_subset = 0;
721
722   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
723       i != tilegroups_map.end(); ++i)
724   {
725     delete i->second;
726   }
727   for(ButtonPanelMap::iterator i = objects_map.begin();
728       i != objects_map.end(); ++i)
729   {
730     delete i->second;
731   }
732 }
733
734 void le_drawminimap()
735 {
736   if(le_world == NULL)
737     return;
738
739   int mini_tile_width;
740   if(screen->w - 64 > le_world->get_level()->width * 4)
741     mini_tile_width = 4;
742   else if(screen->w - 64 > le_world->get_level()->width * 2)
743     mini_tile_width = 2;
744   else
745     mini_tile_width = 1;
746   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
747
748   for (int y = 0; y < 15; ++y)
749     for (int x = 0; x < le_world->get_level()->width; ++x)
750     {
751
752       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]);
753
754       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]);
755
756       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]);
757
758     }
759
760   fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, 15*4, 200, 200, 200, 128);
761
762   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
763   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, 15*4, 200, 200, 200, 200);
764   fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, 15*4, 200, 200, 200, 200);
765   fillrect(left_offset + (pos_x/32)*mini_tile_width, 15*4-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
766
767 }
768
769 void le_drawinterface()
770 {
771   int x,y;
772   char str[80];
773
774   if(le_world != NULL)
775   {
776     /* draw a grid (if selected) */
777     if(le_show_grid)
778     {
779       for(x = 0; x < 19; x++)
780         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
781       for(y = 0; y < 15; y++)
782         fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
783     }
784   }
785
786   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
787     le_drawminimap();
788
789   if(le_selection_mode == CURSOR)
790   {
791     if(le_current.IsTile())
792       le_selection->draw( cursor_x - pos_x, cursor_y);
793   }
794   else if(le_selection_mode == SQUARE)
795   {
796     int w, h;
797     le_highlight_selection();
798     /* draw current selection */
799     w = selection.x2 - selection.x1;
800     h = selection.y2 - selection.y1;
801     fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
802     fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
803     fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
804     fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
805   }
806
807
808   /* draw button bar */
809   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
810
811   if(le_current.IsTile())
812   {
813     Tile::draw(19 * 32, 14 * 32, le_current.tile);
814     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
815       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
816   }
817   if(le_current.IsObject())
818   {
819     le_current.obj->draw_on_screen(19 * 32, 14 * 32);
820     le_current.obj->draw_on_screen(cursor_x,cursor_y);
821   }
822
823   if(le_world != NULL)
824   {
825     le_save_level_bt->draw();
826     le_exit_bt->draw();
827     le_test_level_bt->draw();
828     le_next_level_bt->draw();
829     le_previous_level_bt->draw();
830     le_rubber_bt->draw();
831     if(le_selection_mode == SQUARE)
832       le_select_mode_one_bt->draw();
833     else if(le_selection_mode == CURSOR)
834       le_select_mode_two_bt->draw();
835     le_settings_bt->draw();
836     le_move_right_bt->draw();
837     le_move_left_bt->draw();
838     le_tilegroup_bt->draw();
839     le_objects_bt->draw();
840     if(!cur_tilegroup.empty())
841       tilegroups_map[cur_tilegroup]->draw();
842     else if(!cur_objects.empty())
843     {
844       objects_map[cur_objects]->draw();
845     }
846
847     le_tilemap_panel->draw();
848
849     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
850     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
851
852     if(!le_help_shown)
853       white_small_text->draw("F1 for Help", 10, 430, 1);
854   }
855   else
856   {
857     if(!Menu::current())
858       white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
859     else
860       white_small_text->draw("No Level Subset loaded", 10, 430, 1);
861   }
862
863 }
864
865 void le_drawlevel()
866 {
867   unsigned int y,x,s;
868   Uint8 a;
869
870   /* Draw the real background */
871   if(le_world->get_level()->bkgd_image[0] != '\0')
872   {
873     s = (int)((float)pos_x * ((float)le_world->get_level()->bkgd_speed/60.)) % screen->w;
874     le_world->get_level()->img_bkgd->draw_part(s,0,0,0,
875         le_world->get_level()->img_bkgd->w - s - 32, le_world->get_level()->img_bkgd->h);
876     le_world->get_level()->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
877         le_world->get_level()->img_bkgd->h);
878   }
879   else
880   {
881     drawgradient(le_world->get_level()->bkgd_top, le_world->get_level()->bkgd_bottom);
882   }
883
884   if(le_current.IsTile())
885   {
886     Tile::draw(cursor_x-pos_x, cursor_y,le_current.tile,128);
887     if(!TileManager::instance()->get(le_current.tile)->images.empty())
888       fillrect(cursor_x-pos_x,cursor_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);
889   }
890   if(le_current.IsObject())
891   {
892     le_current.obj->move_to(cursor_x, cursor_y);
893   }
894
895   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
896
897   for (y = 0; y < 15; ++y)
898     for (x = 0; x < 20; ++x)
899     {
900
901       if(active_tm == TM_BG)
902         a = 255;
903       else
904         a = 128;
905
906       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->bg_tiles[y][x + (int)(pos_x / 32)],a);
907
908       if(active_tm == TM_IA)
909         a = 255;
910       else
911         a = 128;
912
913       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)],a);
914
915       if(active_tm == TM_FG)
916         a = 255;
917       else
918         a = 128;
919
920       Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_world->get_level()->fg_tiles[y][x + (int)(pos_x / 32)],a);
921
922       /* draw whats inside stuff when cursor is selecting those */
923       /* (draw them all the time - is this the right behaviour?) */
924       Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y][x + (int)(pos_x / 32)]);
925       if(edit_image && !edit_image->editor_images.empty())
926         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
927
928     }
929
930   /* Draw the Bad guys: */
931   for (std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it)
932   {
933     /* to support frames: img_bsod_left[(frame / 5) % 4] */
934
935     scroll_x = pos_x;
936     (*it)->draw();
937   }
938
939
940   /* Draw the player: */
941   /* for now, the position is fixed at (100, 240) */
942   largetux.walk_right->draw( 100 - pos_x, 240);
943 }
944
945 void le_change_object_properties(GameObject *pobj)
946 {
947   Menu* object_properties_menu = new Menu();
948
949   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
950   object_properties_menu->additem(MN_HL,"",0,0);
951   /*object_properties_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
952   object_properties_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
953   object_properties_menu->additem(MN_HL,"",0,0);
954   object_properties_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);*/
955   object_properties_menu->additem(MN_HL,"",0,0);
956   object_properties_menu->additem(MN_BACK,"Apply",0,0);
957
958   delete object_properties_menu;
959 }
960
961
962 void le_checkevents()
963 {
964   SDLKey key;
965   SDLMod keymod;
966   Button* pbutton;
967   int x,y;
968
969   keymod = SDL_GetModState();
970
971   while(SDL_PollEvent(&event))
972   {
973     if (Menu::current())
974     {
975       Menu::current()->event(event);
976       if(!le_world && !Menu::current())
977         Menu::set_current(leveleditor_menu);
978     }
979     else
980     {
981       mouse_cursor->set_state(MC_NORMAL);
982
983       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
984       if(event.type == SDL_KEYDOWN
985           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
986               && (event.motion.x > 0
987                   && event.motion.x < screen->w - 64 &&
988                   event.motion.y > 0 && event.motion.y < screen->h)))
989       {
990         switch(event.type)
991         {
992         case SDL_KEYDOWN:       // key pressed
993           key = event.key.keysym.sym;
994           switch(key)
995           {
996           case SDLK_ESCAPE:
997             Menu::set_current(leveleditor_menu);
998             break;
999           case SDLK_LEFT:
1000             if(fire == DOWN)
1001               cursor_x -= KEY_CURSOR_SPEED;
1002             else
1003               cursor_x -= KEY_CURSOR_FASTSPEED;
1004
1005             if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
1006               pos_x = cursor_x - MOUSE_LEFT_MARGIN;
1007
1008             break;
1009           case SDLK_RIGHT:
1010             if(fire == DOWN)
1011               cursor_x += KEY_CURSOR_SPEED;
1012             else
1013               cursor_x += KEY_CURSOR_FASTSPEED;
1014
1015             if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
1016               pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
1017
1018             break;
1019           case SDLK_UP:
1020             if(fire == DOWN)
1021               cursor_y -= KEY_CURSOR_SPEED;
1022             else
1023               cursor_y -= KEY_CURSOR_FASTSPEED;
1024
1025             if(cursor_y < 0)
1026               cursor_y = 0;
1027             break;
1028           case SDLK_DOWN:
1029             if(fire == DOWN)
1030               cursor_y += KEY_CURSOR_SPEED;
1031             else
1032               cursor_y += KEY_CURSOR_FASTSPEED;
1033
1034             if(cursor_y > screen->h-32)
1035               cursor_y = screen->h-32;
1036             break;
1037           case SDLK_LCTRL:
1038             fire =UP;
1039             break;
1040           case SDLK_F1:
1041             if(le_world != NULL)
1042               le_showhelp();
1043             break;
1044           case SDLK_HOME:
1045             cursor_x = 0;
1046             pos_x = cursor_x;
1047             break;
1048           case SDLK_END:
1049             cursor_x = (le_world->get_level()->width * 32) - 32;
1050             pos_x = cursor_x;
1051             break;
1052           case SDLK_F9:
1053             le_show_grid = !le_show_grid;
1054             break;
1055           default:
1056             break;
1057           }
1058           break;
1059         case SDL_KEYUP: /* key released */
1060           switch(event.key.keysym.sym)
1061           {
1062           case SDLK_LCTRL:
1063             fire = DOWN;
1064             break;
1065           default:
1066             break;
1067           }
1068           break;
1069         case SDL_MOUSEBUTTONDOWN:
1070           if(event.button.button == SDL_BUTTON_LEFT)
1071           {
1072             le_mouse_pressed[LEFT] = true;
1073
1074             selection.x1 = event.motion.x + pos_x;
1075             selection.y1 = event.motion.y;
1076             selection.x2 = event.motion.x + pos_x;
1077             selection.y2 = event.motion.y;
1078           }
1079           else if(event.button.button == SDL_BUTTON_RIGHT)
1080           {
1081             le_mouse_pressed[RIGHT] = true;
1082           }
1083           break;
1084         case SDL_MOUSEBUTTONUP:
1085           if(event.button.button == SDL_BUTTON_LEFT)
1086           {
1087             le_mouse_pressed[LEFT] = false;
1088             le_mouse_clicked[LEFT] = true;
1089           }
1090           else if(event.button.button == SDL_BUTTON_RIGHT)
1091           {
1092             le_mouse_pressed[RIGHT] = false;
1093             le_mouse_clicked[RIGHT] = true;
1094           }
1095           break;
1096         case SDL_MOUSEMOTION:
1097
1098           if(!Menu::current())
1099           {
1100             x = event.motion.x;
1101             y = event.motion.y;
1102
1103             if(le_current.IsTile())
1104             {
1105               cursor_x = ((int)(pos_x + x) / 32) * 32;
1106               cursor_y = ((int) y / 32) * 32;
1107             }
1108             else
1109             {
1110               cursor_x = x;
1111               cursor_y = y;
1112             }
1113
1114             if(le_mouse_pressed[LEFT])
1115             {
1116               selection.x2 = x + pos_x;
1117               selection.y2 = y;
1118             }
1119
1120             if(le_mouse_pressed[RIGHT])
1121             {
1122               pos_x += -1 * event.motion.xrel;
1123             }
1124           }
1125           break;
1126         case SDL_QUIT:  // window closed
1127           done = 1;
1128           break;
1129         default:
1130           break;
1131         }
1132       }
1133     }
1134
1135     if(le_world != NULL)
1136     {
1137       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 &&
1138           event.motion.y > 0 && event.motion.y < screen->h)))
1139       {
1140         le_mouse_pressed[LEFT] = false;
1141         le_mouse_pressed[RIGHT] = false;
1142
1143         if(!Menu::current())
1144         {
1145           /* Check for button events */
1146           le_test_level_bt->event(event);
1147           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1148             le_testlevel();
1149           le_save_level_bt->event(event);
1150           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1151             le_world->get_level()->save(le_level_subset->name.c_str(),le_level);
1152           le_exit_bt->event(event);
1153           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1154           {
1155             Menu::set_current(leveleditor_menu);
1156           }
1157           le_next_level_bt->event(event);
1158           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1159           {
1160             if(le_level < le_level_subset->levels)
1161             {
1162               le_goto_level(++le_level);
1163             }
1164             else
1165             {
1166               Level new_lev;
1167               char str[1024];
1168               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1169               if(confirm_dialog(str))
1170               {
1171                 new_lev.init_defaults();
1172                 new_lev.save(le_level_subset->name.c_str(),++le_level);
1173                 le_level_subset->levels = le_level;
1174                 le_goto_level(le_level);
1175               }
1176             }
1177           }
1178           le_previous_level_bt->event(event);
1179           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1180           {
1181             if(le_level > 1)
1182               le_goto_level(--le_level);
1183           }
1184           le_rubber_bt->event(event);
1185           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1186             le_current.Tile(0);
1187
1188           if(le_selection_mode == SQUARE)
1189           {
1190             le_select_mode_one_bt->event(event);
1191             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1192               le_selection_mode = CURSOR;
1193           }
1194           else
1195           {
1196             le_select_mode_two_bt->event(event);
1197             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1198               le_selection_mode = SQUARE;
1199           }
1200           ButtonPanelMap::iterator it;
1201           le_tilegroup_bt->event(event);
1202           switch (le_tilegroup_bt->get_state())
1203           {
1204           case BUTTON_CLICKED:
1205             Menu::set_current(select_tilegroup_menu);
1206             select_tilegroup_menu_effect.start(200);
1207             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1208             break;
1209           case BUTTON_WHEELUP:
1210             if(cur_tilegroup.empty())
1211             {
1212               cur_tilegroup = tilegroups_map.begin()->first;
1213             }
1214             else
1215             {
1216               it = tilegroups_map.find(cur_tilegroup);
1217               if((++it) == tilegroups_map.end())
1218               {
1219                 cur_tilegroup = tilegroups_map.begin()->first;
1220               }
1221               else
1222               {
1223                 cur_tilegroup = (*it).first;
1224               }
1225             }
1226
1227             cur_objects = "";
1228             break;
1229           case BUTTON_WHEELDOWN:
1230             it = tilegroups_map.find(cur_tilegroup);
1231             if(it == tilegroups_map.begin())
1232             {
1233               cur_tilegroup = tilegroups_map.rbegin()->first;
1234               cur_objects = "";
1235               break;
1236             }
1237             if(--it != --tilegroups_map.begin())
1238               cur_tilegroup = (*it).first;
1239             else
1240               cur_tilegroup = tilegroups_map.rbegin()->first;
1241
1242             cur_objects = "";
1243             break;
1244           default:
1245             break;
1246           }
1247
1248           le_objects_bt->event(event);
1249           switch (le_objects_bt->get_state())
1250           {
1251           case BUTTON_CLICKED:
1252             Menu::set_current(select_objects_menu);
1253             select_objects_menu_effect.start(200);
1254             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1255             break;
1256           case BUTTON_WHEELUP:
1257             it = objects_map.find(cur_objects);
1258             if(it == objects_map.end())
1259             {
1260               cur_objects = objects_map.begin()->first;
1261               cur_tilegroup = "";
1262               break;
1263             }
1264             if(++it != objects_map.end())
1265               cur_objects = (*it).first;
1266             else
1267               cur_objects = objects_map.begin()->first;
1268
1269             cur_tilegroup = "";
1270             break;
1271           case BUTTON_WHEELDOWN:
1272             it = objects_map.find(cur_objects);
1273             if(it == objects_map.begin())
1274             {
1275               cur_objects = objects_map.rbegin()->first;
1276               cur_tilegroup = "";
1277               break;
1278             }
1279             if(--it != --objects_map.begin())
1280               cur_objects = (*it).first;
1281             else
1282               cur_objects = objects_map.rbegin()->first;
1283
1284             cur_tilegroup = "";
1285             break;
1286             break;
1287           default:
1288             break;
1289           }
1290
1291           le_settings_bt->event(event);
1292           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1293           {
1294             update_level_settings_menu();
1295             Menu::set_current(level_settings_menu);
1296           }
1297           if(!cur_tilegroup.empty())
1298           {
1299             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1300             {
1301               if(pbutton->get_state() == BUTTON_CLICKED)
1302               {
1303                 le_current.Tile(pbutton->get_tag());
1304               }
1305             }
1306           }
1307           else if(!cur_objects.empty())
1308           {
1309             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1310             {
1311               if(pbutton->get_state() == BUTTON_CLICKED)
1312               {
1313                 le_current.Object(pbutton->get_game_object());
1314               }
1315             }
1316           }
1317
1318           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1319           {
1320             if(pbutton->get_state() == BUTTON_CLICKED)
1321             {
1322               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1323             }
1324           }
1325         }
1326         else
1327         {
1328           le_settings_bt->event(event);
1329           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1330           {
1331             Menu::set_current(0);
1332           }
1333           le_tilegroup_bt->event(event);
1334           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1335           {
1336             Menu::set_current(0);
1337           }
1338           le_objects_bt->event(event);
1339           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1340           {
1341             Menu::set_current(0);
1342           }
1343         }
1344       }
1345
1346       if(!Menu::current() && !show_minimap)
1347       {
1348         if(le_mouse_pressed[LEFT])
1349         {
1350           if(le_current.IsTile())
1351             le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1352         }
1353         else if(le_mouse_clicked[LEFT])
1354         {
1355           if(le_current.IsObject())
1356           {
1357             le_level_changed  = true;
1358             std::string type = le_current.obj->type();
1359             if(type == "BadGuy")
1360             {
1361               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1362
1363               le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1364               le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1365             }
1366           }
1367           le_mouse_clicked[LEFT] = false;
1368         }
1369       }
1370     }
1371   }
1372   if(!Menu::current())
1373   {
1374     show_minimap = false;
1375
1376     le_move_left_bt->event(event);
1377     le_move_right_bt->event(event);
1378     switch(le_move_left_bt->get_state())
1379     {
1380     case BUTTON_PRESSED:
1381       pos_x -= 192;
1382       show_minimap = true;
1383       break;
1384     case BUTTON_HOVER:
1385       pos_x -= 32;
1386       show_minimap = true;
1387       break;
1388     case BUTTON_CLICKED:
1389       show_minimap = true;
1390       break;
1391     default:
1392       break;
1393     }
1394
1395     switch(le_move_right_bt->get_state())
1396     {
1397     case BUTTON_PRESSED:
1398       pos_x += 192;
1399       show_minimap = true;
1400       break;
1401     case BUTTON_HOVER:
1402       pos_x += 32;
1403       show_minimap = true;
1404       break;
1405     case BUTTON_CLICKED:
1406       show_minimap = true;
1407       break;
1408     default:
1409       break;
1410     }
1411
1412   }
1413
1414 }
1415
1416 void le_highlight_selection()
1417 {
1418   int x1, x2, y1, y2;
1419
1420   if(selection.x1 < selection.x2)
1421   {
1422     x1 = selection.x1;
1423     x2 = selection.x2;
1424   }
1425   else
1426   {
1427     x1 = selection.x2;
1428     x2 = selection.x1;
1429   }
1430   if(selection.y1 < selection.y2)
1431   {
1432     y1 = selection.y1;
1433     y2 = selection.y2;
1434   }
1435   else
1436   {
1437     y1 = selection.y2;
1438     y2 = selection.y1;
1439   }
1440
1441   x1 /= 32;
1442   x2 /= 32;
1443   y1 /= 32;
1444   y2 /= 32;
1445
1446   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1447 }
1448
1449 void le_change(float x, float y, int tm, unsigned int c)
1450 {
1451   if(le_world != NULL)
1452   {
1453     int xx,yy;
1454     int x1, x2, y1, y2;
1455     unsigned int i = 0;
1456
1457     le_level_changed = true;
1458     
1459     switch(le_selection_mode)
1460     {
1461     case CURSOR:
1462       le_world->get_level()->change(x,y,tm,c);
1463
1464       base_type cursor_base;
1465       cursor_base.x = x;
1466       cursor_base.y = y;
1467       cursor_base.width = 32;
1468       cursor_base.height = 32;
1469
1470       /* if there is a bad guy over there, remove it */
1471       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1472         if(rectcollision(cursor_base,(*it)->base))
1473         {
1474           delete (*it);
1475           le_world->bad_guys.erase(it);
1476           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1477           break;
1478         }
1479
1480       break;
1481     case SQUARE:
1482       if(selection.x1 < selection.x2)
1483       {
1484         x1 = selection.x1;
1485         x2 = selection.x2;
1486       }
1487       else
1488       {
1489         x1 = selection.x2;
1490         x2 = selection.x1;
1491       }
1492       if(selection.y1 < selection.y2)
1493       {
1494         y1 = selection.y1;
1495         y2 = selection.y2;
1496       }
1497       else
1498       {
1499         y1 = selection.y2;
1500         y2 = selection.y1;
1501       }
1502
1503       x1 /= 32;
1504       x2 /= 32;
1505       y1 /= 32;
1506       y2 /= 32;
1507
1508       /* if there is a bad guy over there, remove it */
1509       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
1510           it != le_world->bad_guys.end(); /* will be at end of loop */)
1511       {
1512         if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
1513             && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
1514         {
1515           delete (*it);
1516           it = le_world->bad_guys.erase(it);
1517           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1518           continue;
1519         }
1520         else
1521         {
1522           ++i;
1523           ++it;
1524         }
1525       }
1526
1527       for(xx = x1; xx <= x2; xx++)
1528         for(yy = y1; yy <= y2; yy++)
1529         {
1530           le_world->get_level()->change(xx*32, yy*32, tm, c);
1531
1532         }
1533       break;
1534     default:
1535       break;
1536     }
1537   }
1538 }
1539
1540 void le_testlevel()
1541 {
1542   //Make sure a time value is set when testing the level
1543   if(le_world->get_level()->time_left == 0)
1544     le_world->get_level()->time_left = 250;
1545
1546   le_world->get_level()->save("test", le_level);
1547
1548   GameSession session("test",le_level, ST_GL_TEST);
1549   session.run();
1550   player_status.reset();
1551
1552   music_manager->halt_music();
1553
1554   Menu::set_current(NULL);
1555   World::set_current(le_world);
1556 }
1557
1558 void le_showhelp()
1559 {
1560   bool tmp_show_grid = le_show_grid;
1561   int temp_le_selection_mode = le_selection_mode;
1562   le_selection_mode = NONE;
1563   le_show_grid = false;
1564   le_help_shown = true;
1565
1566   drawgradient(Color(0,0,0), Color(255,255,255));
1567   le_drawinterface();
1568
1569   SDL_Event event;
1570   unsigned int i, done_;
1571   char *text[] = {
1572
1573                    " - Supertux level editor tutorial - ",
1574                    "",
1575                    "To make your map, click the       ",
1576                    "tilegroup button and choose a     ",
1577                    "tilegroup.",
1578                    "Pick a tile and simply hold down  ",
1579                    "the left mouse button over the map",
1580                    "to \"paint\" your selection over",
1581                    "the screen.",
1582                    "There are three layers for painting",
1583                    "tiles upon, Background layer,",
1584                    "the Interactive layer, and the",
1585                    "Foreground layer, which can be",
1586                    "toggled by the BkGrd, IntAct and",
1587                    "FrGrd buttons. The Foreground and",
1588                    "Background layers do not effect",
1589                    "Tux in the gameplay, but lie in",
1590                    "front of him or lie behind him in",
1591                    "his adventures.",
1592                  };
1593
1594   char *text2[] = {
1595
1596                     " - Supertux level editor tutorial - ",
1597                     "",
1598                     "The tiles placed on",
1599                     "the Interactive layer are those",
1600                     "which actually effect Tux in the",
1601                     "game.",
1602                     "Click the objects menu to put ",
1603                     "bad guys and other objects in the",
1604                     "game. Unlike placing tiles, you",
1605                     "cannot \"paint\" enemies. Click",
1606                     "them onto the screen one at a time.",
1607                     "To change the settings of your",
1608                     "level, click the button with the",
1609                     "screwdriver and wrench. From here",
1610                     "you can change the background,",
1611                     "music, length of the level, and more.",
1612                     "You may have more than one levelset.",
1613                     "Pressing the up and down buttons",
1614                     "above the button bar lets you choose",
1615                     "which one you are working on.",
1616                     "If you would like to speed up your",
1617                     "level editing, a useful trick is",
1618                     "to learn the keyboard shortcuts. They",
1619                     "are easy to learn, just right-",
1620                     "Have fun making levels! If you make",
1621                     "some good ones, send them to us on",
1622                     "the SuperTux mailing list!",
1623                     "- SuperTux team"
1624                   };
1625
1626
1627   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1628
1629   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1630     white_text->draw(text[i], 5, 80+(i*white_text->h), 1);
1631
1632   gold_text->drawf("Press Any Key to Continue - Page 1/2", 0, 0, A_LEFT, A_BOTTOM, 1);
1633
1634   flipscreen();
1635
1636   done_ = 0;
1637
1638   while(done_ == 0)
1639   {
1640     done_ = wait_for_event(event);
1641     SDL_Delay(50);
1642   }
1643
1644   drawgradient(Color(0,0,0), Color(255,255,255));
1645   le_drawinterface();
1646
1647
1648   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1649
1650   for(i = 0; i < sizeof(text2)/sizeof(char *); i++)
1651     white_text->draw(text2[i], 5, 80+(i*white_text->h), 1);
1652
1653   gold_text->drawf("Press Any Key to Continue - Page 2/2", 0, 0, A_LEFT, A_BOTTOM, 1);
1654
1655   flipscreen();
1656
1657   done_ = 0;
1658
1659   while(done_ == 0)
1660   {
1661     done_ = wait_for_event(event);
1662     SDL_Delay(50);
1663   }
1664
1665   le_show_grid = tmp_show_grid;
1666   le_help_shown = false;
1667   le_selection_mode = temp_le_selection_mode;
1668 }