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