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