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