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