bc521cf9609ed80b5f864917bc824bcdb4ca9a34
[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
45 /* definitions to aid development */
46
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 void le_drawlevel();
70 void le_drawinterface();
71 void le_checkevents();
72 void le_change(float x, float y, int tm, unsigned int c);
73 void le_testlevel();
74 void le_showhelp();
75 void le_set_defaults(void);
76 void le_activate_bad_guys(void);
77
78 void le_highlight_selection();
79
80 void apply_level_settings_menu();
81 void update_subset_settings_menu();
82 void save_subset_settings_menu();
83
84 static Level* le_current_level;
85
86 struct LevelEditorWorld
87 {
88   std::vector<BadGuy> bad_guys;
89   void arrays_free(void)
90   {
91     bad_guys.clear();
92   }
93
94   void add_bad_guy(float x, float y, BadGuyKind kind)
95   {
96     bad_guys.push_back(BadGuy());
97     BadGuy& new_bad_guy = bad_guys.back();
98   
99     new_bad_guy.init(x,y,kind);
100   }
101
102   void activate_bad_guys()
103   {
104     for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
105          i != le_current_level->badguy_data.end();
106          ++i)
107       {
108         add_bad_guy(i->x, i->y, i->kind);
109       }
110   }
111 };
112
113 /* leveleditor internals */
114 static string_list_type level_subsets;
115 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
116 static int pos_x, cursor_x, cursor_y, fire;
117 static int le_level;
118 static LevelEditorWorld le_world;
119 static st_subset le_level_subset;
120 static int le_show_grid;
121 static int le_frame;
122 static Surface* le_selection;
123 static int done;
124 static unsigned int le_current_tile;
125 static bool le_mouse_pressed[2];
126 static Button* le_save_level_bt;
127 static Button* le_exit_bt;
128 static Button* le_test_level_bt;
129 static Button* le_next_level_bt;
130 static Button* le_previous_level_bt;
131 static Button* le_move_right_bt;
132 static Button* le_move_left_bt;
133 static Button* le_rubber_bt;
134 static Button* le_select_mode_one_bt;
135 static Button* le_select_mode_two_bt;
136 static Button* le_settings_bt;
137 static Button* le_tilegroup_bt;
138 static ButtonPanel* le_tilemap_panel;
139 static Menu* leveleditor_menu;
140 static Menu* subset_load_menu;
141 static Menu* subset_new_menu;
142 static Menu* subset_settings_menu;
143 static Menu* level_settings_menu;
144 static Menu* select_tilegroup_menu;
145 static Timer select_tilegroup_menu_effect;
146 static std::map<std::string, ButtonPanel* > tilegroups_map;
147 static std::string cur_tilegroup;
148
149 static square selection;
150 static int le_selection_mode;
151 static SDL_Event event;
152 TileMapType active_tm;
153
154 void le_set_defaults()
155 {
156   if(le_current_level != NULL)
157     {
158       /* Set defaults: */
159
160       if(le_current_level->time_left == 0)
161         le_current_level->time_left = 255;
162     }
163 }
164
165 int leveleditor(int levelnb)
166 {
167   int last_time, now_time, i;
168
169   le_level = levelnb;
170   if(le_init() != 0)
171     return 1;
172
173   /* Clear screen: */
174
175   clearscreen(0, 0, 0);
176   updatescreen();
177
178   while (SDL_PollEvent(&event))
179     {}
180
181   while(true)
182     {
183       last_time = SDL_GetTicks();
184       le_frame++;
185
186       le_checkevents();
187
188       if(Menu::current() == select_tilegroup_menu)
189         {
190           if(select_tilegroup_menu_effect.check())
191             {
192               select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
193                                              82,-0.5,0.5);
194             }
195           else
196             select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
197         }
198
199       if(le_current_level != NULL)
200         {
201           /* making events results to be in order */
202           if(pos_x < 0)
203             pos_x = 0;
204           if(pos_x > (le_current_level->width * 32) - screen->w)
205             pos_x = (le_current_level->width * 32) - screen->w;
206
207           /* draw the level */
208           le_drawlevel();
209         }
210       else
211         clearscreen(0, 0, 0);
212
213       /* draw editor interface */
214       le_drawinterface();
215
216       Menu* menu = Menu::current();
217       if(menu)
218         {
219           menu->draw();
220           menu->action();
221
222           if(menu == leveleditor_menu)
223             {
224               switch (leveleditor_menu->check())
225                 {
226                 case 2:
227                   Menu::set_current(0);
228                   break;
229                 case 3:
230                   update_subset_settings_menu();
231                   break;
232                 case 7:
233                   done = 1;
234                   break;
235                 }
236             }
237           else if(menu == level_settings_menu)
238             {
239               switch (level_settings_menu->check())
240                 {
241                 case 17:
242                   apply_level_settings_menu();
243                   Menu::set_current(leveleditor_menu);
244                   break;
245                   
246                 default:
247                   //show_menu = true;
248                   break;
249                 }
250             }
251           else if(menu == select_tilegroup_menu)
252             {
253               int it = -1;
254               switch (it = select_tilegroup_menu->check())
255                 {
256                 default:
257                   if(it != -1)
258                     {
259                       if(select_tilegroup_menu->item[it].kind == MN_ACTION)
260                         cur_tilegroup = select_tilegroup_menu->item[it].text;
261                   
262                       Menu::set_current(0);
263                     }
264                   break;
265                 }
266             }
267           else if(menu == subset_load_menu)
268             {
269               switch (i = subset_load_menu->check())
270                 {
271                 case 0:
272                   break;
273                 default:
274                   if(i != -1)
275                     {
276                       le_level_subset.load(level_subsets.item[i-2]);
277                       leveleditor_menu->item[3].kind = MN_GOTO;
278                       le_level = 1;
279                       le_world.arrays_free();
280                       le_current_level = new Level;
281                       if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
282                         {
283                           le_quit();
284                           return 1;
285                         }
286                       le_set_defaults();
287                       le_current_level->load_gfx();
288                       le_world.activate_bad_guys();
289
290                       // FIXME:?
291                       Menu::set_current(leveleditor_menu);
292                     }
293                   break;
294                 }
295             }
296           else if(menu == subset_new_menu)
297             {
298               if(subset_new_menu->item[2].input[0] == '\0')
299                 subset_new_menu->item[3].kind = MN_DEACTIVE;
300               else
301                 {
302                   subset_new_menu->item[3].kind = MN_ACTION;
303
304                   switch (i = subset_new_menu->check())
305                     {
306                     case 3:
307                       st_subset::create(subset_new_menu->item[2].input);
308                       le_level_subset.load(subset_new_menu->item[2].input);
309                       leveleditor_menu->item[3].kind = MN_GOTO;
310                       le_level = 1;
311                       le_world.arrays_free();
312                       le_current_level = new Level;
313                       if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
314                         {
315                           le_quit();
316                           return 1;
317                         }
318                       le_set_defaults();
319                       le_current_level->load_gfx();
320                       le_world.activate_bad_guys();
321                       subset_new_menu->item[2].change_input("");
322                       // FIXME:? show_menu = true;
323                       Menu::set_current(leveleditor_menu);
324                       break;
325                     }
326                 }
327             }
328           else if(menu == subset_settings_menu)
329             {
330               if(le_level_subset.title.compare(subset_settings_menu->item[2].input) == 0 && le_level_subset.description.compare(subset_settings_menu->item[3].input) == 0  )
331                 subset_settings_menu->item[5].kind = MN_DEACTIVE;
332               else
333                 subset_settings_menu->item[5].kind = MN_ACTION;
334
335               switch (i = subset_settings_menu->check())
336                 {
337                 case 5:
338                   save_subset_settings_menu();
339                   //FIXME:show_menu = true;
340                   Menu::set_current(leveleditor_menu);
341                   break;
342                 }
343             }
344         }
345
346       mouse_cursor->draw();
347
348       if(done)
349         {
350           le_quit();
351           return 0;
352         }
353
354       ++global_frame_counter;
355         
356       SDL_Delay(25);
357       now_time = SDL_GetTicks();
358       if (now_time < last_time + FPS)
359         SDL_Delay(last_time + FPS - now_time);  /* delay some time */
360
361       flipscreen();
362     }
363
364   return done;
365 }
366
367 int le_init()
368 {
369   int i;
370   level_subsets = dsubdirs("/levels", "info");
371
372   active_tm = TM_IA;
373   
374   le_show_grid = true;
375
376   /*  level_changed = NO;*/
377   fire = DOWN;
378   done = 0;
379   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
380   le_level_changed = false;
381   le_current_level = NULL;
382
383   le_current_tile = 0;
384   le_mouse_pressed[LEFT] = false;
385   le_mouse_pressed[RIGHT] = false;
386
387   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
388
389   select_tilegroup_menu_effect.init(false);
390
391   /* Load buttons */
392   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
393   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
394   le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
395   le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
396   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
397   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
398   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
399   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
400   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
401   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
402   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
403   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
404   
405   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
406   le_tilemap_panel->set_button_size(32,10);
407   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
408   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
409   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG); 
410   
411   leveleditor_menu = new Menu();
412   subset_load_menu = new Menu();
413   subset_new_menu  = new Menu();
414   subset_settings_menu = new Menu();
415   level_settings_menu  = new Menu();
416   select_tilegroup_menu  = new Menu();
417
418   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
419   leveleditor_menu->additem(MN_HL,"",0,0);
420   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
421   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
422   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
423   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
424   leveleditor_menu->additem(MN_HL,"",0,0);
425   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
426
427   Menu::set_current(leveleditor_menu);
428   
429   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
430   subset_load_menu->additem(MN_HL, "", 0, 0);
431
432   for(i = 0; i < level_subsets.num_items; ++i)
433     {
434       subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0);
435     }
436   subset_load_menu->additem(MN_HL,"",0,0);
437   subset_load_menu->additem(MN_BACK,"Back",0,0);
438
439   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
440   subset_new_menu->additem(MN_HL,"",0,0);
441   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
442   subset_new_menu->additem(MN_ACTION,"Create",0,0);
443   subset_new_menu->additem(MN_HL,"",0,0);
444   subset_new_menu->additem(MN_BACK,"Back",0,0);
445
446   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
447   subset_settings_menu->additem(MN_HL,"",0,0);
448   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
449   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
450   subset_settings_menu->additem(MN_HL,"",0,0);
451   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
452   subset_settings_menu->additem(MN_HL,"",0,0);
453   subset_settings_menu->additem(MN_BACK,"Back",0,0);
454
455   level_settings_menu->arrange_left = true;
456   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
457   level_settings_menu->additem(MN_HL,"",0,0);
458   level_settings_menu->additem(MN_TEXTFIELD,"Name    ",0,0);
459   level_settings_menu->additem(MN_TEXTFIELD,"Author  ",0,0);
460   level_settings_menu->additem(MN_STRINGSELECT,"Theme   ",0,0);
461   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0);
462   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
463   level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
464   level_settings_menu->additem(MN_NUMFIELD,"Time   ",0,0);
465   level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
466   level_settings_menu->additem(MN_NUMFIELD,"Top Red    ",0,0);
467   level_settings_menu->additem(MN_NUMFIELD,"Top Green  ",0,0);
468   level_settings_menu->additem(MN_NUMFIELD,"Top Blue   ",0,0);
469   level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
470   level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
471   level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
472   level_settings_menu->additem(MN_HL,"",0,0);
473   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
474
475   select_tilegroup_menu->arrange_left = true;
476   select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
477   select_tilegroup_menu->additem(MN_HL,"",0,0);
478   std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
479   for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
480     {
481
482       select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
483       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
484       i = 0;
485       for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
486         tilegroups_map[(*it).name]->additem(new Button(const_cast<char*>(("images/tilesets/" + TileManager::instance()->get(*sit)->filenames[0]).c_str()), const_cast<char*>((*it).name.c_str()),(SDLKey)(i+'a'),0,0,32,32),(*sit));
487     }
488   select_tilegroup_menu->additem(MN_HL,"",0,0);
489
490   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
491
492   return 0;
493 }
494
495 void update_level_settings_menu()
496 {
497   char str[80];
498   int i;
499
500   level_settings_menu->item[2].change_input(le_current_level->name.c_str());
501   level_settings_menu->item[3].change_input(le_current_level->author.c_str());
502   sprintf(str,"%d",le_current_level->width);
503
504   string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
505   string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
506   string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
507   string_list_add_item(level_settings_menu->item[6].list,"");
508   if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
509     level_settings_menu->item[3].list->active_item = i;
510   if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
511     level_settings_menu->item[4].list->active_item = i;
512   if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
513     level_settings_menu->item[5].list->active_item = i;
514
515   level_settings_menu->item[7].change_input(str);
516   sprintf(str,"%d",le_current_level->time_left);
517   level_settings_menu->item[8].change_input(str);
518   sprintf(str,"%2.0f",le_current_level->gravity);
519   level_settings_menu->item[9].change_input(str);
520   sprintf(str,"%d",le_current_level->bkgd_top.red);
521   level_settings_menu->item[10].change_input(str);
522   sprintf(str,"%d",le_current_level->bkgd_top.green);
523   level_settings_menu->item[11].change_input(str);
524   sprintf(str,"%d",le_current_level->bkgd_top.blue);
525   level_settings_menu->item[12].change_input(str);
526   sprintf(str,"%d",le_current_level->bkgd_bottom.red);
527   level_settings_menu->item[13].change_input(str);
528   sprintf(str,"%d",le_current_level->bkgd_bottom.green);
529   level_settings_menu->item[14].change_input(str);
530   sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
531   level_settings_menu->item[15].change_input(str);
532 }
533
534 void update_subset_settings_menu()
535 {
536   subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
537   subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
538 }
539
540 void apply_level_settings_menu()
541 {
542   int i;
543   i = false;
544
545   le_current_level->name = level_settings_menu->item[2].input;
546   le_current_level->author = level_settings_menu->item[3].input;
547
548   if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
549     {
550       le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
551       i = true;
552     }
553
554   if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
555     {
556       le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
557       i = true;
558     }
559
560   if(i)
561     {
562       le_current_level->free_gfx();
563       le_current_level->load_gfx();
564     }
565
566   le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
567
568   le_current_level->change_size(atoi(level_settings_menu->item[7].input));
569   le_current_level->time_left = atoi(level_settings_menu->item[8].input);
570   le_current_level->gravity = atof(level_settings_menu->item[9].input);
571   le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
572   le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
573   le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
574   le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
575   le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
576   le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
577 }
578
579 void save_subset_settings_menu()
580 {
581   le_level_subset.title = subset_settings_menu->item[2].input;
582   le_level_subset.description = subset_settings_menu->item[3].input;
583   le_level_subset.save();
584 }
585
586 void le_goto_level(int levelnb)
587 {
588   le_world.arrays_free();
589
590   le_current_level->cleanup();
591   if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
592     {
593       le_current_level->load(le_level_subset.name.c_str(), le_level);
594     }
595   else
596     {
597       le_level = levelnb;
598     }
599
600   le_set_defaults();
601
602   le_current_level->free_gfx();
603   le_current_level->load_gfx();
604
605   le_world.activate_bad_guys();
606 }
607
608 void le_quit(void)
609 {
610   /*if(level_changed == true)
611     if(askforsaving() == CANCEL)
612       return;*/ //FIXME
613
614   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
615
616   delete le_selection;
617   delete leveleditor_menu;
618   delete subset_load_menu;
619   delete subset_new_menu;
620   delete subset_settings_menu;
621   delete level_settings_menu;
622   delete select_tilegroup_menu;
623   delete le_save_level_bt;
624   delete le_exit_bt;
625   delete le_test_level_bt;
626   delete le_next_level_bt;
627   delete le_previous_level_bt;
628   delete le_move_right_bt;
629   delete le_move_left_bt;
630   delete le_rubber_bt;
631   delete le_select_mode_one_bt;
632   delete le_select_mode_two_bt;
633   delete le_settings_bt;
634   delete le_tilegroup_bt;
635   delete le_tilemap_panel;
636
637   if(le_current_level != NULL)
638     {
639       le_current_level->free_gfx();
640       le_current_level->cleanup();
641       le_world.arrays_free();
642     }
643 }
644
645 void le_drawinterface()
646 {
647   int x,y;
648   char str[80];
649
650   if(le_current_level != NULL)
651     {
652       /* draw a grid (if selected) */
653       if(le_show_grid)
654         {
655           for(x = 0; x < 19; x++)
656             fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
657           for(y = 0; y < 15; y++)
658             fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
659         }
660     }
661
662   if(le_selection_mode == CURSOR)
663     le_selection->draw( cursor_x - pos_x, cursor_y);
664   else if(le_selection_mode == SQUARE)
665     {
666       int w, h;
667       le_highlight_selection();
668       /* draw current selection */
669       w = selection.x2 - selection.x1;
670       h = selection.y2 - selection.y1;
671       fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
672       fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
673       fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
674       fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
675     }
676
677
678   /* draw button bar */
679   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
680   Tile::draw(19 * 32, 14 * 32, le_current_tile);
681   
682         if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
683         TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
684
685   if(le_current_level != NULL)
686     {
687       le_save_level_bt->draw();
688       le_exit_bt->draw();
689       le_test_level_bt->draw();
690       le_next_level_bt->draw();
691       le_previous_level_bt->draw();
692       le_rubber_bt->draw();
693       le_select_mode_one_bt->draw();
694       le_select_mode_two_bt->draw();
695       le_settings_bt->draw();
696       le_move_right_bt->draw();
697       le_move_left_bt->draw();
698       le_tilegroup_bt->draw();
699       if(!cur_tilegroup.empty())
700       tilegroups_map[cur_tilegroup]->draw();
701       le_tilemap_panel->draw();
702
703       sprintf(str, "%d/%d", le_level,le_level_subset.levels);
704       white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
705
706       white_small_text->draw("F1 for Help", 10, 430, 1);
707     }
708   else
709     {
710       if(!Menu::current())
711         white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
712       else
713         white_small_text->draw("No Level Subset loaded", 10, 430, 1);
714     }
715
716 }
717
718 void le_drawlevel()
719 {
720   unsigned int y,x,i,s;
721   Uint8 a;
722
723   /* Draw the real background */
724   if(le_current_level->bkgd_image[0] != '\0')
725     {
726       s = pos_x / 30;
727       le_current_level->img_bkgd->draw_part(s,0,0,0,
728                                             le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
729       le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
730                                             le_current_level->img_bkgd->h);
731     }
732   else
733     {
734           drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
735     }
736
737   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
738
739   for (y = 0; y < 15; ++y)
740     for (x = 0; x < 20; ++x)
741       {
742       
743         if(active_tm == TM_BG)
744         a = 255;
745         else
746         a = 128;
747       
748         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
749         
750         if(active_tm == TM_IA)
751         a = 255;
752         else
753         a = 128;
754         
755         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
756
757         if(active_tm == TM_FG)
758         a = 255;
759         else
760         a = 128;
761         
762         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
763         
764         /* draw whats inside stuff when cursor is selecting those */
765         /* (draw them all the time - is this the right behaviour?) */
766         if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
767         TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32);
768
769       }
770
771   /* Draw the Bad guys: */
772   for (i = 0; i < le_world.bad_guys.size(); ++i)
773     {
774       /* to support frames: img_bsod_left[(frame / 5) % 4] */
775       
776       scroll_x = pos_x;
777       le_world.bad_guys[i].draw();
778     }
779
780
781   /* Draw the player: */
782   /* for now, the position is fixed at (100, 240) */
783   tux_right[(global_frame_counter / 5) % 3]->draw( 100 - pos_x, 240);
784 }
785
786 void le_checkevents()
787 {
788   SDLKey key;
789   SDLMod keymod;
790   Button* pbutton;
791   int x,y;
792
793   keymod = SDL_GetModState();
794
795   while(SDL_PollEvent(&event))
796     {
797       if (Menu::current())
798         {
799           Menu::current()->event(event);
800         }
801       else
802         {
803           mouse_cursor->set_state(MC_NORMAL);
804
805           /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
806           if(event.type == SDL_KEYDOWN 
807              || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
808                  && (event.motion.x > 0 
809                      && event.motion.x < screen->w - 64 &&
810                      event.motion.y > 0 && event.motion.y < screen->h)))
811             {
812               switch(event.type)
813                 {
814                 case SDL_KEYDOWN:       // key pressed
815                   key = event.key.keysym.sym;
816                   switch(key)
817                     {
818                     case SDLK_ESCAPE:
819                       Menu::set_current(leveleditor_menu);
820                     case SDLK_LEFT:
821                       if(fire == DOWN)
822                         cursor_x -= KEY_CURSOR_SPEED;
823                       else
824                         cursor_x -= KEY_CURSOR_FASTSPEED;
825
826                       if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
827                         pos_x = cursor_x - MOUSE_LEFT_MARGIN;
828
829                       break;
830                     case SDLK_RIGHT:
831                       if(fire == DOWN)
832                         cursor_x += KEY_CURSOR_SPEED;
833                       else
834                         cursor_x += KEY_CURSOR_FASTSPEED;
835
836                       if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
837                         pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
838
839                       break;
840                     case SDLK_UP:
841                       if(fire == DOWN)
842                         cursor_y -= KEY_CURSOR_SPEED;
843                       else
844                         cursor_y -= KEY_CURSOR_FASTSPEED;
845
846                       if(cursor_y < 0)
847                         cursor_y = 0;
848                       break;
849                     case SDLK_DOWN:
850                       if(fire == DOWN)
851                         cursor_y += KEY_CURSOR_SPEED;
852                       else
853                         cursor_y += KEY_CURSOR_FASTSPEED;
854
855                       if(cursor_y > screen->h-32)
856                         cursor_y = screen->h-32;
857                       break;
858                     case SDLK_LCTRL:
859                       fire =UP;
860                       break;
861                     case SDLK_F1:
862                       le_showhelp();
863                       break;
864                     case SDLK_HOME:
865                       cursor_x = 0;
866                       pos_x = cursor_x;
867                       break;
868                     case SDLK_END:
869                       cursor_x = (le_current_level->width * 32) - 32;
870                       pos_x = cursor_x;
871                       break;
872                     case SDLK_F9:
873                       le_show_grid = !le_show_grid;
874                       break;
875                     default:
876                       break;
877                     }
878                   break;
879                 case SDL_KEYUP: /* key released */
880                   switch(event.key.keysym.sym)
881                     {
882                     case SDLK_LCTRL:
883                       fire = DOWN;
884                       break;
885                     default:
886                       break;
887                     }
888                   break;
889                 case SDL_MOUSEBUTTONDOWN:
890                   if(event.button.button == SDL_BUTTON_LEFT)
891                     {
892                       le_mouse_pressed[LEFT] = true;
893
894                       selection.x1 = event.motion.x + pos_x;
895                       selection.y1 = event.motion.y;
896                       selection.x2 = event.motion.x + pos_x;
897                       selection.y2 = event.motion.y;
898                     }
899                   else if(event.button.button == SDL_BUTTON_RIGHT)
900                     {
901                       le_mouse_pressed[RIGHT] = true;
902                     }
903                   break;
904                 case SDL_MOUSEBUTTONUP:
905                   if(event.button.button == SDL_BUTTON_LEFT)
906                     le_mouse_pressed[LEFT] = false;
907                   else if(event.button.button == SDL_BUTTON_RIGHT)
908                     le_mouse_pressed[RIGHT] = false;
909                   break;
910                 case SDL_MOUSEMOTION:
911
912                   if(!Menu::current())
913                     {
914                       x = event.motion.x;
915                       y = event.motion.y;
916
917                       cursor_x = ((int)(pos_x + x) / 32) * 32;
918                       cursor_y = ((int) y / 32) * 32;
919
920                       if(le_mouse_pressed[LEFT])
921                         {
922                           selection.x2 = x + pos_x;
923                           selection.y2 = y;
924                         }
925
926                       if(le_mouse_pressed[RIGHT])
927                         {
928                           pos_x += -1 * event.motion.xrel;
929                         }
930                     }
931                   break;
932                 case SDL_QUIT:  // window closed
933                   done = 1;
934                   break;
935                 default:
936                   break;
937                 }
938             }
939         }
940
941       if(le_current_level != NULL)
942         {
943           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 &&
944                                                                                                                                  event.motion.y > 0 && event.motion.y < screen->h)))
945             {
946               le_mouse_pressed[LEFT] = false;
947               le_mouse_pressed[RIGHT] = false;
948
949               if(!Menu::current())
950                 {
951                   /* Check for button events */
952                   le_test_level_bt->event(event);
953                   if(le_test_level_bt->get_state() == BUTTON_CLICKED)
954                     le_testlevel();
955                   le_save_level_bt->event(event);
956                   if(le_save_level_bt->get_state() == BUTTON_CLICKED)
957                     le_current_level->save(le_level_subset.name.c_str(),le_level);
958                   le_exit_bt->event(event);
959                   if(le_exit_bt->get_state() == BUTTON_CLICKED)
960                     {
961                       Menu::set_current(leveleditor_menu);
962                     }
963                   le_next_level_bt->event(event);
964                   if(le_next_level_bt->get_state() == BUTTON_CLICKED)
965                     {
966                       if(le_level < le_level_subset.levels)
967                         {
968                           le_goto_level(++le_level);
969                         }
970                       else
971                         {
972                           Level new_lev;
973                           char str[1024];
974                           int d = 0;
975                           sprintf(str,"Level %d doesn't exist.",le_level+1);
976                           white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
977                           white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
978                           red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
979                           flipscreen();
980                           while(d == 0)
981                             {
982                               while(SDL_PollEvent(&event))
983                                 switch(event.type)
984                                   {
985                                   case SDL_KEYDOWN:             // key pressed
986                                     switch(event.key.keysym.sym)
987                                       {
988                                       case SDLK_y:
989                                         new_lev.init_defaults();
990                                         new_lev.save(le_level_subset.name.c_str(),++le_level);
991                                         le_level_subset.levels = le_level;
992                                         le_goto_level(le_level);
993                                         d = 1;
994                                         break;
995                                       case SDLK_n:
996                                         d = 1;
997                                         break;
998                                       default:
999                                         break;
1000                                       }
1001                                     break;
1002                                   default:
1003                                     break;
1004                                   }
1005                               SDL_Delay(50);
1006                             }
1007                         }
1008                     }
1009                   le_previous_level_bt->event(event);
1010                   if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1011                     {
1012                       if(le_level > 1)
1013                         le_goto_level(--le_level);
1014                     }
1015                   le_rubber_bt->event(event);
1016                   if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1017                     le_current_tile = 0;
1018                   le_select_mode_one_bt->event(event);
1019                   if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1020                     le_selection_mode = CURSOR;
1021                   le_select_mode_two_bt->event(event);
1022                   if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1023                     le_selection_mode = SQUARE;
1024
1025                   le_tilegroup_bt->event(event);
1026                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1027                     {
1028                       Menu::set_current(select_tilegroup_menu);
1029                       select_tilegroup_menu_effect.start(200);
1030                       select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1031                     }
1032
1033                   le_settings_bt->event(event);
1034                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1035                     {
1036                       update_level_settings_menu();
1037                       Menu::set_current(level_settings_menu);
1038                     }
1039                   if(!cur_tilegroup.empty())
1040                     if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1041                       {
1042                         if(pbutton->get_state() == BUTTON_CLICKED)
1043                           {
1044                             le_current_tile = pbutton->get_tag();
1045                           }
1046                       }
1047                   if((pbutton = le_tilemap_panel->event(event)) != NULL)
1048                     {
1049                       if(pbutton->get_state() == BUTTON_CLICKED)
1050                         {
1051                           active_tm = static_cast<TileMapType>(pbutton->get_tag());
1052                         }
1053                     }
1054                 }
1055               else
1056                 {
1057                   le_settings_bt->event(event);
1058                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1059                     {
1060                       Menu::set_current(0);
1061                     }
1062                   le_tilegroup_bt->event(event);
1063                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1064                     {
1065                       Menu::set_current(0);
1066                     }
1067                 }
1068             }
1069           
1070           if(!Menu::current())
1071             {
1072               le_move_left_bt->event(event);
1073               le_move_right_bt->event(event);
1074
1075               if(le_mouse_pressed[LEFT])
1076                 {
1077                   le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1078                 }
1079             }
1080         }
1081     }
1082   if(!Menu::current())
1083     {
1084       if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1085         {
1086           pos_x -= 192;
1087         }
1088       else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1089         {
1090           pos_x -= 64;
1091         }
1092
1093       if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1094         {
1095           pos_x += 192;
1096         }
1097       else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1098         {
1099           pos_x += 64;
1100         }
1101     }
1102
1103 }
1104
1105 void le_highlight_selection()
1106 {
1107   int x1, x2, y1, y2;
1108
1109   if(selection.x1 < selection.x2)
1110     {
1111       x1 = selection.x1;
1112       x2 = selection.x2;
1113     }
1114   else
1115     {
1116       x1 = selection.x2;
1117       x2 = selection.x1;
1118     }
1119   if(selection.y1 < selection.y2)
1120     {
1121       y1 = selection.y1;
1122       y2 = selection.y2;
1123     }
1124   else
1125     {
1126       y1 = selection.y2;
1127       y2 = selection.y1;
1128     }
1129
1130   x1 /= 32;
1131   x2 /= 32;
1132   y1 /= 32;
1133   y2 /= 32;
1134
1135   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1136 }
1137
1138 void le_change(float x, float y, int tm, unsigned int c)
1139 {
1140   if(le_current_level != NULL)
1141     {
1142       int xx,yy;
1143       int x1, x2, y1, y2;
1144       unsigned int i;
1145
1146       /*  level_changed = true; */
1147
1148       switch(le_selection_mode)
1149         {
1150         case CURSOR:
1151           le_current_level->change(x,y,tm,c);
1152
1153           yy = ((int)y / 32);
1154           xx = ((int)x / 32);
1155
1156           /* if there is a bad guy over there, remove it */
1157           for(i = 0; i < le_world.bad_guys.size(); ++i)
1158             if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1159               le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1160
1161           if(c == '0')  /* if it's a bad guy */
1162             le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1163           else if(c == '1')
1164             le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1165           else if(c == '2')
1166             le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1167
1168           break;
1169         case SQUARE:
1170           if(selection.x1 < selection.x2)
1171             {
1172               x1 = selection.x1;
1173               x2 = selection.x2;
1174             }
1175           else
1176             {
1177               x1 = selection.x2;
1178               x2 = selection.x1;
1179             }
1180           if(selection.y1 < selection.y2)
1181             {
1182               y1 = selection.y1;
1183               y2 = selection.y2;
1184             }
1185           else
1186             {
1187               y1 = selection.y2;
1188               y2 = selection.y1;
1189             }
1190
1191           x1 /= 32;
1192           x2 /= 32;
1193           y1 /= 32;
1194           y2 /= 32;
1195
1196           /* if there is a bad guy over there, remove it */
1197           for(i = 0; i < le_world.bad_guys.size(); ++i)
1198             if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1199                && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1200               le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1201
1202           for(xx = x1; xx <= x2; xx++)
1203             for(yy = y1; yy <= y2; yy++)
1204               {
1205                 le_current_level->change(xx*32, yy*32, tm, c);
1206
1207                 if(c == '0')  // if it's a bad guy
1208                   le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1209                 else if(c == '1')
1210                   le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1211                 else if(c == '2')
1212                   le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1213               }
1214           break;
1215         default:
1216           break;
1217         }
1218     }
1219 }
1220
1221 void le_testlevel()
1222 {
1223   le_current_level->save("test", le_level);
1224   
1225   GameSession session("test",le_level, ST_GL_TEST);
1226   session.run();
1227
1228   Menu::set_current(leveleditor_menu);
1229   le_world.arrays_free();
1230   le_current_level->load_gfx();
1231   le_world.activate_bad_guys();
1232 }
1233
1234 void le_showhelp()
1235 {
1236   SDL_Event event;
1237   unsigned int i, done_;
1238   char *text[] = {
1239                    "  - This is SuperTux's built-in level editor -",
1240                    "It has been designed to be light and easy to use from the start.",
1241                    "",
1242                    "When you first load the level editor you are given a menu where you",
1243                    "can load level subsets, create a new level subset, edit the current",
1244                    "subset's settings, or simply quit the editor. You can access this menu",
1245                    "from the level editor at any time by pressing the escape key.",
1246                    "",
1247                    "To your right is your button bar. The center of this contains many",
1248                    "tiles you can use to make your level. To select a tile, click on it",
1249                    "with your left mouse button; your selection will be shown in the",
1250                    "bottom right corner of the button box. Click anywhere on your level",
1251                    "with the left mouse button to place that tile down. If you right click",
1252                    "a tile in the button bar, you can find out what its keyboard shortcut",
1253                    "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1254                    "background, and enemy tiles. The eraser lets you remove tiles.",
1255                    "The left and right arrow keys scroll back and forth through your level.",
1256                    "The button with the wrench and screwdriver, lets you change the",
1257                    "settings of your level, including how long it is or what music it will",
1258                    "play. When you are ready to give your level a test, click on the little",
1259                    "running Tux. If you like the changes you have made to your level,",
1260                    "press the red save key to keep them.",
1261                    "To change which level in your subset you are editing, press the white",
1262                    "up and down arrow keys at the top of the button box.",
1263                    "",
1264                    "Have fun making levels! If you make some good ones, send them to us on",
1265                    "the SuperTux mailing list!",
1266                    "- SuperTux team"
1267                  };
1268
1269
1270   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1271
1272   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1273     white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1274
1275   gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1276
1277   flipscreen();
1278
1279   done_ = 0;
1280
1281   while(done_ == 0)
1282     {
1283       done_ = wait_for_event(event);
1284       SDL_Delay(50);
1285     }
1286 }