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