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