cfa6a5e05d4ff35cfc2d9a369952d7b53b708463
[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   le_quit();
371   return done;
372 }
373
374 int le_init()
375 {
376   int i;
377   level_subsets = dsubdirs("/levels", "info");
378   
379   le_level_subset = new LevelSubset;
380
381   active_tm = TM_IA;
382   
383   le_show_grid = true;
384
385   /*  level_changed = NO;*/
386   fire = DOWN;
387   done = 0;
388   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
389   le_level_changed = false;
390   le_current_level = NULL;
391
392   le_current_tile = 0;
393   le_mouse_pressed[LEFT] = false;
394   le_mouse_pressed[RIGHT] = false;
395
396   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
397
398   select_tilegroup_menu_effect.init(false);
399
400   /* Load buttons */
401   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
402   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
403   le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
404   le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
405   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
406   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
407   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
408   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
409   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
410   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
411   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
412   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
413   
414   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
415   le_tilemap_panel->set_button_size(32,10);
416   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
417   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
418   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG); 
419   
420   leveleditor_menu = new Menu();
421   subset_load_menu = new Menu();
422   subset_new_menu  = new Menu();
423   subset_settings_menu = new Menu();
424   level_settings_menu  = new Menu();
425   select_tilegroup_menu  = new Menu();
426
427   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
428   leveleditor_menu->additem(MN_HL,"",0,0);
429   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
430   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
431   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
432   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
433   leveleditor_menu->additem(MN_HL,"",0,0);
434   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
435
436   Menu::set_current(leveleditor_menu);
437   
438   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
439   subset_load_menu->additem(MN_HL, "", 0, 0);
440
441   for(i = 0; i < level_subsets.num_items; ++i)
442     {
443       subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
444     }
445   subset_load_menu->additem(MN_HL,"",0,0);
446   subset_load_menu->additem(MN_BACK,"Back",0,0);
447
448   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
449   subset_new_menu->additem(MN_HL,"",0,0);
450   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0);
451   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
452   subset_new_menu->additem(MN_HL,"",0,0);
453   subset_new_menu->additem(MN_BACK,"Back",0,0);
454
455   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
456   subset_settings_menu->additem(MN_HL,"",0,0);
457   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0);
458   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0);
459   subset_settings_menu->additem(MN_HL,"",0,0);
460   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0);
461   subset_settings_menu->additem(MN_HL,"",0,0);
462   subset_settings_menu->additem(MN_BACK,"Back",0,0);
463
464   level_settings_menu->arrange_left = true;
465   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
466   level_settings_menu->additem(MN_HL,"",0,0);
467   level_settings_menu->additem(MN_TEXTFIELD,"Name    ",0,0);
468   level_settings_menu->additem(MN_TEXTFIELD,"Author  ",0,0);
469   level_settings_menu->additem(MN_STRINGSELECT,"Theme   ",0,0);
470   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0);
471   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
472   level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
473   level_settings_menu->additem(MN_NUMFIELD,"Time   ",0,0);
474   level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
475   level_settings_menu->additem(MN_NUMFIELD,"Top Red    ",0,0);
476   level_settings_menu->additem(MN_NUMFIELD,"Top Green  ",0,0);
477   level_settings_menu->additem(MN_NUMFIELD,"Top Blue   ",0,0);
478   level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
479   level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
480   level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
481   level_settings_menu->additem(MN_HL,"",0,0);
482   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
483
484   select_tilegroup_menu->arrange_left = true;
485   select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
486   select_tilegroup_menu->additem(MN_HL,"",0,0);
487   std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
488   int tileid = 1;
489   for(std::vector<TileGroup>::iterator it = tilegroups->begin();
490       it != tilegroups->end(); ++it )
491     {
492       select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
493       tileid++;
494       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
495       i = 0;
496       
497       for(std::vector<int>::iterator sit = (*it).tiles.begin();
498               sit != (*it).tiles.end(); ++sit, ++i)
499         {
500           std::string imagefile = "/images/tilesets/" ;
501           imagefile += TileManager::instance()->get(*sit)->filenames[0];
502           Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
503                   0, 0, 32, 32);
504           tilegroups_map[it->name]->additem(button, *sit);
505         }
506     }
507   select_tilegroup_menu->additem(MN_HL,"",0,0);
508
509   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
510
511   return 0;
512 }
513
514 void update_level_settings_menu()
515 {
516   char str[80];
517   int i;
518
519   level_settings_menu->item[2].change_input(le_current_level->name.c_str());
520   level_settings_menu->item[3].change_input(le_current_level->author.c_str());
521   sprintf(str,"%d",le_current_level->width);
522
523   string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
524   string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
525   string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
526   string_list_add_item(level_settings_menu->item[6].list,"");
527   if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
528     level_settings_menu->item[3].list->active_item = i;
529   if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
530     level_settings_menu->item[4].list->active_item = i;
531   if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
532     level_settings_menu->item[5].list->active_item = i;
533
534   level_settings_menu->item[7].change_input(str);
535   sprintf(str,"%d",le_current_level->time_left);
536   level_settings_menu->item[8].change_input(str);
537   sprintf(str,"%2.0f",le_current_level->gravity);
538   level_settings_menu->item[9].change_input(str);
539   sprintf(str,"%d",le_current_level->bkgd_top.red);
540   level_settings_menu->item[10].change_input(str);
541   sprintf(str,"%d",le_current_level->bkgd_top.green);
542   level_settings_menu->item[11].change_input(str);
543   sprintf(str,"%d",le_current_level->bkgd_top.blue);
544   level_settings_menu->item[12].change_input(str);
545   sprintf(str,"%d",le_current_level->bkgd_bottom.red);
546   level_settings_menu->item[13].change_input(str);
547   sprintf(str,"%d",le_current_level->bkgd_bottom.green);
548   level_settings_menu->item[14].change_input(str);
549   sprintf(str,"%d",le_current_level->bkgd_bottom.blue);
550   level_settings_menu->item[15].change_input(str);
551 }
552
553 void update_subset_settings_menu()
554 {
555   subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
556   subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
557 }
558
559 void apply_level_settings_menu()
560 {
561   int i;
562   i = false;
563
564   le_current_level->name = level_settings_menu->item[2].input;
565   le_current_level->author = level_settings_menu->item[3].input;
566
567   if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
568     {
569       le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
570       i = true;
571     }
572
573   if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
574     {
575       le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
576       i = true;
577     }
578
579   if(i)
580     {
581       le_current_level->free_gfx();
582       le_current_level->load_gfx();
583     }
584
585   le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
586
587   le_current_level->change_size(atoi(level_settings_menu->item[7].input));
588   le_current_level->time_left = atoi(level_settings_menu->item[8].input);
589   le_current_level->gravity = atof(level_settings_menu->item[9].input);
590   le_current_level->bkgd_top.red = atoi(level_settings_menu->item[10].input);
591   le_current_level->bkgd_top.green = atoi(level_settings_menu->item[11].input);
592   le_current_level->bkgd_top.blue = atoi(level_settings_menu->item[12].input);
593   le_current_level->bkgd_bottom.red = atoi(level_settings_menu->item[13].input);
594   le_current_level->bkgd_bottom.green = atoi(level_settings_menu->item[14].input);
595   le_current_level->bkgd_bottom.blue = atoi(level_settings_menu->item[15].input);
596 }
597
598 void save_subset_settings_menu()
599 {
600   le_level_subset->title = subset_settings_menu->item[2].input;
601   le_level_subset->description = subset_settings_menu->item[3].input;
602   le_level_subset->save();
603 }
604
605 void le_goto_level(int levelnb)
606 {
607   le_world.arrays_free();
608
609   le_current_level->cleanup();
610   if(le_current_level->load(le_level_subset->name.c_str(), levelnb) != 0)
611     {
612       le_current_level->load(le_level_subset->name.c_str(), le_level);
613     }
614   else
615     {
616       le_level = levelnb;
617     }
618
619   le_set_defaults();
620
621   le_current_level->free_gfx();
622   le_current_level->load_gfx();
623
624   le_world.activate_bad_guys();
625 }
626
627 void le_quit(void)
628 {
629   /*if(level_changed == true)
630     if(askforsaving() == CANCEL)
631       return;*/ //FIXME
632
633   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
634
635   delete le_selection;
636   delete leveleditor_menu;
637   delete subset_load_menu;
638   delete subset_new_menu;
639   delete subset_settings_menu;
640   delete level_settings_menu;
641   delete select_tilegroup_menu;
642   delete le_save_level_bt;
643   delete le_exit_bt;
644   delete le_test_level_bt;
645   delete le_next_level_bt;
646   delete le_previous_level_bt;
647   delete le_move_right_bt;
648   delete le_move_left_bt;
649   delete le_rubber_bt;
650   delete le_select_mode_one_bt;
651   delete le_select_mode_two_bt;
652   delete le_settings_bt;
653   delete le_tilegroup_bt;
654   delete le_tilemap_panel;
655
656   delete le_current_level;
657   le_current_level = 0;
658
659   for(TileGroupsMap::iterator i = tilegroups_map.begin();
660       i != tilegroups_map.end(); ++i)
661     {
662       delete i->second;
663     }
664 }
665
666 void le_drawinterface()
667 {
668   int x,y;
669   char str[80];
670
671   if(le_current_level != NULL)
672     {
673       /* draw a grid (if selected) */
674       if(le_show_grid)
675         {
676           for(x = 0; x < 19; x++)
677             fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
678           for(y = 0; y < 15; y++)
679             fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
680         }
681     }
682
683   if(le_selection_mode == CURSOR)
684     le_selection->draw( cursor_x - pos_x, cursor_y);
685   else if(le_selection_mode == SQUARE)
686     {
687       int w, h;
688       le_highlight_selection();
689       /* draw current selection */
690       w = selection.x2 - selection.x1;
691       h = selection.y2 - selection.y1;
692       fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
693       fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
694       fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
695       fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
696     }
697
698
699   /* draw button bar */
700   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
701   Tile::draw(19 * 32, 14 * 32, le_current_tile);
702   
703         if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
704         TileManager::instance()->get(le_current_tile)->editor_images[0]->draw( 19 * 32, 14 * 32);
705
706   if(le_current_level != NULL)
707     {
708       le_save_level_bt->draw();
709       le_exit_bt->draw();
710       le_test_level_bt->draw();
711       le_next_level_bt->draw();
712       le_previous_level_bt->draw();
713       le_rubber_bt->draw();
714       le_select_mode_one_bt->draw();
715       le_select_mode_two_bt->draw();
716       le_settings_bt->draw();
717       le_move_right_bt->draw();
718       le_move_left_bt->draw();
719       le_tilegroup_bt->draw();
720       if(!cur_tilegroup.empty())
721       tilegroups_map[cur_tilegroup]->draw();
722       le_tilemap_panel->draw();
723
724       sprintf(str, "%d/%d", le_level,le_level_subset->levels);
725       white_text->drawf(str, -10, 16, A_RIGHT, A_TOP, 0);
726
727       white_small_text->draw("F1 for Help", 10, 430, 1);
728     }
729   else
730     {
731       if(!Menu::current())
732         white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
733       else
734         white_small_text->draw("No Level Subset loaded", 10, 430, 1);
735     }
736
737 }
738
739 void le_drawlevel()
740 {
741   unsigned int y,x,i,s;
742   Uint8 a;
743
744   /* Draw the real background */
745   if(le_current_level->bkgd_image[0] != '\0')
746     {
747       s = pos_x / 30;
748       le_current_level->img_bkgd->draw_part(s,0,0,0,
749                                             le_current_level->img_bkgd->w - s - 32, le_current_level->img_bkgd->h);
750       le_current_level->img_bkgd->draw_part(0,0,screen->w - s - 32 ,0,s,
751                                             le_current_level->img_bkgd->h);
752     }
753   else
754     {
755           drawgradient(le_current_level->bkgd_top, le_current_level->bkgd_bottom);
756     }
757
758   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
759
760   for (y = 0; y < 15; ++y)
761     for (x = 0; x < 20; ++x)
762       {
763       
764         if(active_tm == TM_BG)
765         a = 255;
766         else
767         a = 128;
768       
769         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
770         
771         if(active_tm == TM_IA)
772         a = 255;
773         else
774         a = 128;
775         
776         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
777
778         if(active_tm == TM_FG)
779         a = 255;
780         else
781         a = 128;
782         
783         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
784         
785         /* draw whats inside stuff when cursor is selecting those */
786         /* (draw them all the time - is this the right behaviour?) */
787         if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
788         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);
789
790       }
791
792   /* Draw the Bad guys: */
793   for (i = 0; i < le_world.bad_guys.size(); ++i)
794     {
795       /* to support frames: img_bsod_left[(frame / 5) % 4] */
796       
797       scroll_x = pos_x;
798       le_world.bad_guys[i].draw();
799     }
800
801
802   /* Draw the player: */
803   /* for now, the position is fixed at (100, 240) */
804   largetux.walk_right->draw( 100 - pos_x, 240);
805 }
806
807 void le_checkevents()
808 {
809   SDLKey key;
810   SDLMod keymod;
811   Button* pbutton;
812   int x,y;
813
814   keymod = SDL_GetModState();
815
816   while(SDL_PollEvent(&event))
817     {
818       if (Menu::current())
819         {
820           Menu::current()->event(event);
821         }
822       else
823         {
824           mouse_cursor->set_state(MC_NORMAL);
825
826           /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
827           if(event.type == SDL_KEYDOWN 
828              || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
829                  && (event.motion.x > 0 
830                      && event.motion.x < screen->w - 64 &&
831                      event.motion.y > 0 && event.motion.y < screen->h)))
832             {
833               switch(event.type)
834                 {
835                 case SDL_KEYDOWN:       // key pressed
836                   key = event.key.keysym.sym;
837                   switch(key)
838                     {
839                     case SDLK_ESCAPE:
840                       Menu::set_current(leveleditor_menu);
841                     case SDLK_LEFT:
842                       if(fire == DOWN)
843                         cursor_x -= KEY_CURSOR_SPEED;
844                       else
845                         cursor_x -= KEY_CURSOR_FASTSPEED;
846
847                       if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
848                         pos_x = cursor_x - MOUSE_LEFT_MARGIN;
849
850                       break;
851                     case SDLK_RIGHT:
852                       if(fire == DOWN)
853                         cursor_x += KEY_CURSOR_SPEED;
854                       else
855                         cursor_x += KEY_CURSOR_FASTSPEED;
856
857                       if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
858                         pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
859
860                       break;
861                     case SDLK_UP:
862                       if(fire == DOWN)
863                         cursor_y -= KEY_CURSOR_SPEED;
864                       else
865                         cursor_y -= KEY_CURSOR_FASTSPEED;
866
867                       if(cursor_y < 0)
868                         cursor_y = 0;
869                       break;
870                     case SDLK_DOWN:
871                       if(fire == DOWN)
872                         cursor_y += KEY_CURSOR_SPEED;
873                       else
874                         cursor_y += KEY_CURSOR_FASTSPEED;
875
876                       if(cursor_y > screen->h-32)
877                         cursor_y = screen->h-32;
878                       break;
879                     case SDLK_LCTRL:
880                       fire =UP;
881                       break;
882                     case SDLK_F1:
883                       le_showhelp();
884                       break;
885                     case SDLK_HOME:
886                       cursor_x = 0;
887                       pos_x = cursor_x;
888                       break;
889                     case SDLK_END:
890                       cursor_x = (le_current_level->width * 32) - 32;
891                       pos_x = cursor_x;
892                       break;
893                     case SDLK_F9:
894                       le_show_grid = !le_show_grid;
895                       break;
896                     default:
897                       break;
898                     }
899                   break;
900                 case SDL_KEYUP: /* key released */
901                   switch(event.key.keysym.sym)
902                     {
903                     case SDLK_LCTRL:
904                       fire = DOWN;
905                       break;
906                     default:
907                       break;
908                     }
909                   break;
910                 case SDL_MOUSEBUTTONDOWN:
911                   if(event.button.button == SDL_BUTTON_LEFT)
912                     {
913                       le_mouse_pressed[LEFT] = true;
914
915                       selection.x1 = event.motion.x + pos_x;
916                       selection.y1 = event.motion.y;
917                       selection.x2 = event.motion.x + pos_x;
918                       selection.y2 = event.motion.y;
919                     }
920                   else if(event.button.button == SDL_BUTTON_RIGHT)
921                     {
922                       le_mouse_pressed[RIGHT] = true;
923                     }
924                   break;
925                 case SDL_MOUSEBUTTONUP:
926                   if(event.button.button == SDL_BUTTON_LEFT)
927                     le_mouse_pressed[LEFT] = false;
928                   else if(event.button.button == SDL_BUTTON_RIGHT)
929                     le_mouse_pressed[RIGHT] = false;
930                   break;
931                 case SDL_MOUSEMOTION:
932
933                   if(!Menu::current())
934                     {
935                       x = event.motion.x;
936                       y = event.motion.y;
937
938                       cursor_x = ((int)(pos_x + x) / 32) * 32;
939                       cursor_y = ((int) y / 32) * 32;
940
941                       if(le_mouse_pressed[LEFT])
942                         {
943                           selection.x2 = x + pos_x;
944                           selection.y2 = y;
945                         }
946
947                       if(le_mouse_pressed[RIGHT])
948                         {
949                           pos_x += -1 * event.motion.xrel;
950                         }
951                     }
952                   break;
953                 case SDL_QUIT:  // window closed
954                   done = 1;
955                   break;
956                 default:
957                   break;
958                 }
959             }
960         }
961
962       if(le_current_level != NULL)
963         {
964           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 &&
965                                                                                                                                  event.motion.y > 0 && event.motion.y < screen->h)))
966             {
967               le_mouse_pressed[LEFT] = false;
968               le_mouse_pressed[RIGHT] = false;
969
970               if(!Menu::current())
971                 {
972                   /* Check for button events */
973                   le_test_level_bt->event(event);
974                   if(le_test_level_bt->get_state() == BUTTON_CLICKED)
975                     le_testlevel();
976                   le_save_level_bt->event(event);
977                   if(le_save_level_bt->get_state() == BUTTON_CLICKED)
978                     le_current_level->save(le_level_subset->name.c_str(),le_level);
979                   le_exit_bt->event(event);
980                   if(le_exit_bt->get_state() == BUTTON_CLICKED)
981                     {
982                       Menu::set_current(leveleditor_menu);
983                     }
984                   le_next_level_bt->event(event);
985                   if(le_next_level_bt->get_state() == BUTTON_CLICKED)
986                     {
987                       if(le_level < le_level_subset->levels)
988                         {
989                           le_goto_level(++le_level);
990                         }
991                       else
992                         {
993                           Level new_lev;
994                           char str[1024];
995                           sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
996                           if(confirm_dialog(str))
997                             {
998                             new_lev.init_defaults();
999                             new_lev.save(le_level_subset->name.c_str(),++le_level);
1000                             le_level_subset->levels = le_level;
1001                             le_goto_level(le_level);
1002                             }
1003                         }
1004                     }
1005                   le_previous_level_bt->event(event);
1006                   if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1007                     {
1008                       if(le_level > 1)
1009                         le_goto_level(--le_level);
1010                     }
1011                   le_rubber_bt->event(event);
1012                   if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1013                     le_current_tile = 0;
1014                   le_select_mode_one_bt->event(event);
1015                   if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1016                     le_selection_mode = CURSOR;
1017                   le_select_mode_two_bt->event(event);
1018                   if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1019                     le_selection_mode = SQUARE;
1020
1021                   le_tilegroup_bt->event(event);
1022                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1023                     {
1024                       Menu::set_current(select_tilegroup_menu);
1025                       select_tilegroup_menu_effect.start(200);
1026                       select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1027                     }
1028
1029                   le_settings_bt->event(event);
1030                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1031                     {
1032                       update_level_settings_menu();
1033                       Menu::set_current(level_settings_menu);
1034                     }
1035                   if(!cur_tilegroup.empty())
1036                     if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1037                       {
1038                         if(pbutton->get_state() == BUTTON_CLICKED)
1039                           {
1040                             le_current_tile = pbutton->get_tag();
1041                           }
1042                       }
1043                   if((pbutton = le_tilemap_panel->event(event)) != NULL)
1044                     {
1045                       if(pbutton->get_state() == BUTTON_CLICKED)
1046                         {
1047                           active_tm = static_cast<TileMapType>(pbutton->get_tag());
1048                         }
1049                     }
1050                 }
1051               else
1052                 {
1053                   le_settings_bt->event(event);
1054                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1055                     {
1056                       Menu::set_current(0);
1057                     }
1058                   le_tilegroup_bt->event(event);
1059                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1060                     {
1061                       Menu::set_current(0);
1062                     }
1063                 }
1064             }
1065           
1066           if(!Menu::current())
1067             {
1068               le_move_left_bt->event(event);
1069               le_move_right_bt->event(event);
1070
1071               if(le_mouse_pressed[LEFT])
1072                 {
1073                   le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1074                 }
1075             }
1076         }
1077     }
1078   if(!Menu::current())
1079     {
1080       if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1081         {
1082           pos_x -= 192;
1083         }
1084       else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1085         {
1086           pos_x -= 64;
1087         }
1088
1089       if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1090         {
1091           pos_x += 192;
1092         }
1093       else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1094         {
1095           pos_x += 64;
1096         }
1097     }
1098
1099 }
1100
1101 void le_highlight_selection()
1102 {
1103   int x1, x2, y1, y2;
1104
1105   if(selection.x1 < selection.x2)
1106     {
1107       x1 = selection.x1;
1108       x2 = selection.x2;
1109     }
1110   else
1111     {
1112       x1 = selection.x2;
1113       x2 = selection.x1;
1114     }
1115   if(selection.y1 < selection.y2)
1116     {
1117       y1 = selection.y1;
1118       y2 = selection.y2;
1119     }
1120   else
1121     {
1122       y1 = selection.y2;
1123       y2 = selection.y1;
1124     }
1125
1126   x1 /= 32;
1127   x2 /= 32;
1128   y1 /= 32;
1129   y2 /= 32;
1130
1131   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1132 }
1133
1134 void le_change(float x, float y, int tm, unsigned int c)
1135 {
1136   if(le_current_level != NULL)
1137     {
1138       int xx,yy;
1139       int x1, x2, y1, y2;
1140       unsigned int i;
1141
1142       /*  level_changed = true; */
1143
1144       switch(le_selection_mode)
1145         {
1146         case CURSOR:
1147           le_current_level->change(x,y,tm,c);
1148
1149           yy = ((int)y / 32);
1150           xx = ((int)x / 32);
1151
1152           /* if there is a bad guy over there, remove it */
1153           for(i = 0; i < le_world.bad_guys.size(); ++i)
1154             if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1155               le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1156
1157           if(c == '0')  /* if it's a bad guy */
1158             le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1159           else if(c == '1')
1160             le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1161           else if(c == '2')
1162             le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1163
1164           break;
1165         case SQUARE:
1166           if(selection.x1 < selection.x2)
1167             {
1168               x1 = selection.x1;
1169               x2 = selection.x2;
1170             }
1171           else
1172             {
1173               x1 = selection.x2;
1174               x2 = selection.x1;
1175             }
1176           if(selection.y1 < selection.y2)
1177             {
1178               y1 = selection.y1;
1179               y2 = selection.y2;
1180             }
1181           else
1182             {
1183               y1 = selection.y2;
1184               y2 = selection.y1;
1185             }
1186
1187           x1 /= 32;
1188           x2 /= 32;
1189           y1 /= 32;
1190           y2 /= 32;
1191
1192           /* if there is a bad guy over there, remove it */
1193           for(std::vector<BadGuy>::iterator i = le_world.bad_guys.begin(); 
1194               i != le_world.bad_guys.end(); /* will be at end of loop */) {
1195             if(i->base.x/32 >= x1 && i->base.x/32 <= x2
1196                && i->base.y/32 >= y1 && i->base.y/32 <= y2) {
1197               i = le_world.bad_guys.erase(i);
1198               continue;
1199             } else {
1200               ++i;
1201             }
1202           }
1203
1204           for(xx = x1; xx <= x2; xx++)
1205             for(yy = y1; yy <= y2; yy++)
1206               {
1207                 le_current_level->change(xx*32, yy*32, tm, c);
1208
1209                 if(c == '0')  // if it's a bad guy
1210                   le_world.add_bad_guy(xx*32, yy*32, BAD_SNOWBALL);
1211                 else if(c == '1')
1212                   le_world.add_bad_guy(xx*32, yy*32, BAD_MRICEBLOCK);
1213                 else if(c == '2')
1214                   le_world.add_bad_guy(xx*32, yy*32, BAD_JUMPY);
1215               }
1216           break;
1217         default:
1218           break;
1219         }
1220     }
1221 }
1222
1223 void le_testlevel()
1224 {
1225   le_current_level->save("test", le_level);
1226   
1227   GameSession session("test",le_level, ST_GL_TEST);
1228   session.run();
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 }