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