Added "author" field for levels.
[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 17:
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_TEXTFIELD,"Author  ",0,0);
430   level_settings_menu->additem(MN_STRINGSELECT,"Theme   ",0,0);
431   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0);
432   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0);
433   level_settings_menu->additem(MN_NUMFIELD,"Length ",0,0);
434   level_settings_menu->additem(MN_NUMFIELD,"Time   ",0,0);
435   level_settings_menu->additem(MN_NUMFIELD,"Gravity",0,0);
436   level_settings_menu->additem(MN_NUMFIELD,"Top Red    ",0,0);
437   level_settings_menu->additem(MN_NUMFIELD,"Top Green  ",0,0);
438   level_settings_menu->additem(MN_NUMFIELD,"Top Blue   ",0,0);
439   level_settings_menu->additem(MN_NUMFIELD,"Bottom Red ",0,0);
440   level_settings_menu->additem(MN_NUMFIELD,"Bottom Green",0,0);
441   level_settings_menu->additem(MN_NUMFIELD,"Bottom Blue",0,0);
442   level_settings_menu->additem(MN_HL,"",0,0);
443   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0);
444
445   select_tilegroup_menu->arrange_left = true;
446   select_tilegroup_menu->additem(MN_LABEL,"Select Tilegroup",0,0);
447   select_tilegroup_menu->additem(MN_HL,"",0,0);
448   std::vector<TileGroup>* tilegroups = TileManager::tilegroups();
449   for(std::vector<TileGroup>::iterator it = tilegroups->begin(); it != tilegroups->end(); ++it )
450     {
451
452       select_tilegroup_menu->additem(MN_ACTION,const_cast<char*>((*it).name.c_str()),0,0);
453       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
454       i = 0;
455       for(std::vector<int>::iterator sit = (*it).tiles.begin(); sit != (*it).tiles.end(); ++sit, ++i)
456         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));
457     }
458   select_tilegroup_menu->additem(MN_HL,"",0,0);
459
460   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
461
462   return 0;
463 }
464
465 void update_level_settings_menu()
466 {
467   char str[80];
468   int i;
469
470   level_settings_menu->item[2].change_input(le_current_level->name.c_str());
471   level_settings_menu->item[3].change_input(le_current_level->author.c_str());
472   sprintf(str,"%d",le_current_level->width);
473
474   string_list_copy(level_settings_menu->item[4].list, dsubdirs("images/themes", "solid0.png"));
475   string_list_copy(level_settings_menu->item[5].list, dfiles("music/",NULL, "-fast"));
476   string_list_copy(level_settings_menu->item[6].list, dfiles("images/background",NULL, NULL));
477   string_list_add_item(level_settings_menu->item[6].list,"");
478   if((i = string_list_find(level_settings_menu->item[4].list,le_current_level->theme.c_str())) != -1)
479     level_settings_menu->item[3].list->active_item = i;
480   if((i = string_list_find(level_settings_menu->item[5].list,le_current_level->song_title.c_str())) != -1)
481     level_settings_menu->item[4].list->active_item = i;
482   if((i = string_list_find(level_settings_menu->item[6].list,le_current_level->bkgd_image.c_str())) != -1)
483     level_settings_menu->item[5].list->active_item = i;
484
485   level_settings_menu->item[7].change_input(str);
486   sprintf(str,"%d",le_current_level->time_left);
487   level_settings_menu->item[8].change_input(str);
488   sprintf(str,"%2.0f",le_current_level->gravity);
489   level_settings_menu->item[9].change_input(str);
490   sprintf(str,"%d",le_current_level->bkgd_top_red);
491   level_settings_menu->item[10].change_input(str);
492   sprintf(str,"%d",le_current_level->bkgd_top_green);
493   level_settings_menu->item[11].change_input(str);
494   sprintf(str,"%d",le_current_level->bkgd_top_blue);
495   level_settings_menu->item[12].change_input(str);
496   sprintf(str,"%d",le_current_level->bkgd_bottom_red);
497   level_settings_menu->item[13].change_input(str);
498   sprintf(str,"%d",le_current_level->bkgd_bottom_green);
499   level_settings_menu->item[14].change_input(str);
500   sprintf(str,"%d",le_current_level->bkgd_bottom_blue);
501   level_settings_menu->item[15].change_input(str);
502 }
503
504 void update_subset_settings_menu()
505 {
506   subset_settings_menu->item[2].change_input(le_level_subset.title.c_str());
507   subset_settings_menu->item[3].change_input(le_level_subset.description.c_str());
508 }
509
510 void apply_level_settings_menu()
511 {
512   int i;
513   i = false;
514
515   le_current_level->name = level_settings_menu->item[2].input;
516   le_current_level->author = level_settings_menu->item[3].input;
517
518   if(le_current_level->bkgd_image.compare(string_list_active(level_settings_menu->item[6].list)) != 0)
519     {
520       le_current_level->bkgd_image = string_list_active(level_settings_menu->item[6].list);
521       i = true;
522     }
523
524   if(le_current_level->theme.compare(string_list_active(level_settings_menu->item[4].list)) != 0)
525     {
526       le_current_level->theme = string_list_active(level_settings_menu->item[4].list);
527       i = true;
528     }
529
530   if(i)
531     {
532       le_current_level->free_gfx();
533       le_current_level->load_gfx();
534     }
535
536   le_current_level->song_title = string_list_active(level_settings_menu->item[5].list);
537
538   le_current_level->change_size(atoi(level_settings_menu->item[7].input));
539   le_current_level->time_left = atoi(level_settings_menu->item[8].input);
540   le_current_level->gravity = atof(level_settings_menu->item[9].input);
541   le_current_level->bkgd_top_red = atoi(level_settings_menu->item[10].input);
542   le_current_level->bkgd_top_green = atoi(level_settings_menu->item[11].input);
543   le_current_level->bkgd_top_blue = atoi(level_settings_menu->item[12].input);
544   le_current_level->bkgd_bottom_red = atoi(level_settings_menu->item[13].input);
545   le_current_level->bkgd_bottom_green = atoi(level_settings_menu->item[14].input);
546   le_current_level->bkgd_bottom_blue = atoi(level_settings_menu->item[15].input);
547 }
548
549 void save_subset_settings_menu()
550 {
551   le_level_subset.title = subset_settings_menu->item[2].input;
552   le_level_subset.description = subset_settings_menu->item[3].input;
553   le_level_subset.save();
554 }
555
556 void le_goto_level(int levelnb)
557 {
558   le_world.arrays_free();
559
560   le_current_level->cleanup();
561   if(le_current_level->load(le_level_subset.name.c_str(), levelnb) != 0)
562     {
563       le_current_level->load(le_level_subset.name.c_str(), le_level);
564     }
565   else
566     {
567       le_level = levelnb;
568     }
569
570   le_set_defaults();
571
572   le_current_level->free_gfx();
573   le_current_level->load_gfx();
574
575   le_world.activate_bad_guys();
576 }
577
578 void le_quit(void)
579 {
580   /*if(level_changed == true)
581     if(askforsaving() == CANCEL)
582       return;*/ //FIXME
583
584   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
585
586   texture_free(&le_selection);
587   delete leveleditor_menu;
588   delete subset_load_menu;
589   delete subset_new_menu;
590   delete subset_settings_menu;
591   delete level_settings_menu;
592   delete select_tilegroup_menu;
593   delete le_save_level_bt;
594   delete le_exit_bt;
595   delete le_test_level_bt;
596   delete le_next_level_bt;
597   delete le_previous_level_bt;
598   delete le_move_right_bt;
599   delete le_move_left_bt;
600   delete le_rubber_bt;
601   delete le_select_mode_one_bt;
602   delete le_select_mode_two_bt;
603   delete le_settings_bt;
604   delete le_tilegroup_bt;
605   delete le_tilemap_panel;
606
607   if(le_current_level != NULL)
608     {
609       le_current_level->free_gfx();
610       le_current_level->cleanup();
611       le_world.arrays_free();
612     }
613 }
614
615 void le_drawinterface()
616 {
617   int x,y;
618   char str[80];
619
620   if(le_current_level != NULL)
621     {
622       /* draw a grid (if selected) */
623       if(le_show_grid)
624         {
625           for(x = 0; x < 19; x++)
626             fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
627           for(y = 0; y < 15; y++)
628             fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
629         }
630     }
631
632   if(le_selection_mode == CURSOR)
633     texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
634   else if(le_selection_mode == SQUARE)
635     {
636       int w, h;
637       le_highlight_selection();
638       /* draw current selection */
639       w = selection.x2 - selection.x1;
640       h = selection.y2 - selection.y1;
641       fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
642       fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
643       fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
644       fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
645     }
646
647
648   /* draw button bar */
649   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
650   Tile::draw(19 * 32, 14 * 32, le_current_tile);
651   
652         if(TileManager::instance()->get(le_current_tile)->editor_images.size() > 0)
653         texture_draw(&TileManager::instance()->get(le_current_tile)->editor_images[0], 19 * 32, 14 * 32);
654
655   if(le_current_level != NULL)
656     {
657       le_save_level_bt->draw();
658       le_exit_bt->draw();
659       le_test_level_bt->draw();
660       le_next_level_bt->draw();
661       le_previous_level_bt->draw();
662       le_rubber_bt->draw();
663       le_select_mode_one_bt->draw();
664       le_select_mode_two_bt->draw();
665       le_settings_bt->draw();
666       le_move_right_bt->draw();
667       le_move_left_bt->draw();
668       le_tilegroup_bt->draw();
669       if(!cur_tilegroup.empty())
670       tilegroups_map[cur_tilegroup]->draw();
671       le_tilemap_panel->draw();
672
673       sprintf(str, "%d/%d", le_level,le_level_subset.levels);
674       text_drawf(&white_text, str, -10, 16, A_RIGHT, A_TOP, 0);
675
676       text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
677     }
678   else
679     {
680       if(show_menu == false)
681         text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
682       else
683         text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
684     }
685
686 }
687
688 void le_drawlevel()
689 {
690   unsigned int y,x,i,s;
691   Uint8 a;
692
693   /* Draw the real background */
694   if(le_current_level->bkgd_image[0] != '\0')
695     {
696       s = pos_x / 30;
697       texture_draw_part(&le_current_level->img_bkgd,s,0,0,0,
698                         le_current_level->img_bkgd.w - s - 32, le_current_level->img_bkgd.h);
699       texture_draw_part(&le_current_level->img_bkgd,0,0,screen->w - s - 32 ,0,s,
700                         le_current_level->img_bkgd.h);
701     }
702   else
703     {
704           drawgradient(le_current_level->bkgd_top_red, le_current_level->bkgd_top_green, le_current_level->bkgd_top_blue, 
705                    le_current_level->bkgd_bottom_red, le_current_level->bkgd_bottom_green, le_current_level->bkgd_bottom_blue);
706     }
707
708   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
709
710   for (y = 0; y < 15; ++y)
711     for (x = 0; x < 20; ++x)
712       {
713       
714         if(active_tm == TM_BG)
715         a = 255;
716         else
717         a = 128;
718       
719         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
720         
721         if(active_tm == TM_IA)
722         a = 255;
723         else
724         a = 128;
725         
726         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
727
728         if(active_tm == TM_FG)
729         a = 255;
730         else
731         a = 128;
732         
733         Tile::draw(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
734         
735         /* draw whats inside stuff when cursor is selecting those */
736         /* (draw them all the time - is this the right behaviour?) */
737         if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
738         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);
739
740       }
741
742   /* Draw the Bad guys: */
743   for (i = 0; i < le_world.bad_guys.size(); ++i)
744     {
745       /* to support frames: img_bsod_left[(frame / 5) % 4] */
746       
747       scroll_x = pos_x;
748       le_world.bad_guys[i].draw();
749     }
750
751
752   /* Draw the player: */
753   /* for now, the position is fixed at (100, 240) */
754   texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
755 }
756
757 void le_checkevents()
758 {
759   SDLKey key;
760   SDLMod keymod;
761   Button* pbutton;
762   int x,y;
763
764   keymod = SDL_GetModState();
765
766   while(SDL_PollEvent(&event))
767     {
768       if(show_menu)
769         current_menu->event(event);
770       else
771         mouse_cursor->set_state(MC_NORMAL);
772
773       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
774       if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
775                                        event.motion.y > 0 && event.motion.y < screen->h)))
776         {
777           switch(event.type)
778             {
779             case SDL_KEYDOWN:   // key pressed
780               key = event.key.keysym.sym;
781               if(show_menu)
782                 {
783                   if(key == SDLK_ESCAPE)
784                     {
785                       show_menu = false;
786                       Menu::set_current(leveleditor_menu);
787                     }
788                   break;
789                 }
790               switch(key)
791                 {
792                 case SDLK_ESCAPE:
793                   if(!show_menu)
794                     show_menu = true;
795                   else
796                     show_menu = false;
797                   break;
798                 case SDLK_LEFT:
799                   if(fire == DOWN)
800                     cursor_x -= KEY_CURSOR_SPEED;
801                   else
802                     cursor_x -= KEY_CURSOR_FASTSPEED;
803
804                   if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
805                     pos_x = cursor_x - MOUSE_LEFT_MARGIN;
806
807                   break;
808                 case SDLK_RIGHT:
809                   if(fire == DOWN)
810                     cursor_x += KEY_CURSOR_SPEED;
811                   else
812                     cursor_x += KEY_CURSOR_FASTSPEED;
813
814                   if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
815                     pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
816
817                   break;
818                 case SDLK_UP:
819                   if(fire == DOWN)
820                     cursor_y -= KEY_CURSOR_SPEED;
821                   else
822                     cursor_y -= KEY_CURSOR_FASTSPEED;
823
824                   if(cursor_y < 0)
825                     cursor_y = 0;
826                   break;
827                 case SDLK_DOWN:
828                   if(fire == DOWN)
829                     cursor_y += KEY_CURSOR_SPEED;
830                   else
831                     cursor_y += KEY_CURSOR_FASTSPEED;
832
833                   if(cursor_y > screen->h-32)
834                     cursor_y = screen->h-32;
835                   break;
836                 case SDLK_LCTRL:
837                   fire =UP;
838                   break;
839                 case SDLK_F1:
840                   le_showhelp();
841                   break;
842                 case SDLK_HOME:
843                   cursor_x = 0;
844                   pos_x = cursor_x;
845                   break;
846                 case SDLK_END:
847                   cursor_x = (le_current_level->width * 32) - 32;
848                   pos_x = cursor_x;
849                   break;
850                 case SDLK_F9:
851                   le_show_grid = !le_show_grid;
852                   break;
853                 default:
854                   break;
855                 }
856               break;
857             case SDL_KEYUP:     /* key released */
858               switch(event.key.keysym.sym)
859                 {
860                 case SDLK_LCTRL:
861                   fire = DOWN;
862                   break;
863                 default:
864                   break;
865                 }
866               break;
867             case SDL_MOUSEBUTTONDOWN:
868               if(event.button.button == SDL_BUTTON_LEFT)
869                 {
870                   le_mouse_pressed[LEFT] = true;
871
872                   selection.x1 = event.motion.x + pos_x;
873                   selection.y1 = event.motion.y;
874                   selection.x2 = event.motion.x + pos_x;
875                   selection.y2 = event.motion.y;
876                 }
877               else if(event.button.button == SDL_BUTTON_RIGHT)
878                 {
879                 le_mouse_pressed[RIGHT] = true;
880                 }
881               break;
882             case SDL_MOUSEBUTTONUP:
883               if(event.button.button == SDL_BUTTON_LEFT)
884                 le_mouse_pressed[LEFT] = false;
885               else if(event.button.button == SDL_BUTTON_RIGHT)
886                 le_mouse_pressed[RIGHT] = false;
887               break;
888             case SDL_MOUSEMOTION:
889               if(!show_menu)
890                 {
891                   x = event.motion.x;
892                   y = event.motion.y;
893
894                   cursor_x = ((int)(pos_x + x) / 32) * 32;
895                   cursor_y = ((int) y / 32) * 32;
896
897                   if(le_mouse_pressed[LEFT])
898                     {
899                       selection.x2 = x + pos_x;
900                       selection.y2 = y;
901                     }
902
903                   if(le_mouse_pressed[RIGHT])
904                     {
905                       pos_x += -1 * event.motion.xrel;
906                     }
907                 }
908               break;
909             case SDL_QUIT:      // window closed
910               done = DONE_QUIT;
911               break;
912             default:
913               break;
914             }
915         }
916
917       if(le_current_level != NULL)
918         {
919           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 &&
920               event.motion.y > 0 && event.motion.y < screen->h)))
921             {
922               le_mouse_pressed[LEFT] = false;
923               le_mouse_pressed[RIGHT] = false;
924
925               if(show_menu == false)
926                 {
927                   /* Check for button events */
928                   le_test_level_bt->event(event);
929                   if(le_test_level_bt->get_state() == BUTTON_CLICKED)
930                     le_testlevel();
931                   le_save_level_bt->event(event);
932                   if(le_save_level_bt->get_state() == BUTTON_CLICKED)
933                     le_current_level->save(le_level_subset.name.c_str(),le_level);
934                   le_exit_bt->event(event);
935                   if(le_exit_bt->get_state() == BUTTON_CLICKED)
936                   {
937                     Menu::set_current(leveleditor_menu);
938                     show_menu = true;
939                     }
940                   le_next_level_bt->event(event);
941                   if(le_next_level_bt->get_state() == BUTTON_CLICKED)
942                     {
943                       if(le_level < le_level_subset.levels)
944                         {
945                           le_goto_level(++le_level);
946                         }
947                       else
948                         {
949                           Level new_lev;
950                           char str[1024];
951                           int d = 0;
952                           sprintf(str,"Level %d doesn't exist.",le_level+1);
953                           text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
954                           text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
955                           text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
956                           flipscreen();
957                           while(d == 0)
958                             {
959                               while(SDL_PollEvent(&event))
960                                 switch(event.type)
961                                   {
962                                   case SDL_KEYDOWN:             // key pressed
963                                     switch(event.key.keysym.sym)
964                                       {
965                                       case SDLK_y:
966                                         new_lev.init_defaults();
967                                         new_lev.save(le_level_subset.name.c_str(),++le_level);
968                                         le_level_subset.levels = le_level;
969                                         le_goto_level(le_level);
970                                         d = 1;
971                                         break;
972                                       case SDLK_n:
973                                         d = 1;
974                                         break;
975                                       default:
976                                         break;
977                                       }
978                                     break;
979                                   default:
980                                     break;
981                                   }
982                               SDL_Delay(50);
983                             }
984                         }
985                     }
986                   le_previous_level_bt->event(event);
987                   if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
988                     {
989                       if(le_level > 1)
990                         le_goto_level(--le_level);
991                     }
992                   le_rubber_bt->event(event);
993                   if(le_rubber_bt->get_state() == BUTTON_CLICKED)
994                     le_current_tile = 0;
995                   le_select_mode_one_bt->event(event);
996                   if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
997                     le_selection_mode = CURSOR;
998                   le_select_mode_two_bt->event(event);
999                   if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1000                     le_selection_mode = SQUARE;
1001
1002                   le_tilegroup_bt->event(event);
1003                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1004                     {
1005                       Menu::set_current(select_tilegroup_menu);
1006                       select_tilegroup_menu_effect.start(200);
1007                       select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1008                       show_menu = true;
1009                     }
1010
1011                   le_settings_bt->event(event);
1012                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1013                     {
1014                       update_level_settings_menu();
1015                       Menu::set_current(level_settings_menu);
1016                       show_menu = true;
1017                     }
1018                   if(!cur_tilegroup.empty())
1019                   if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1020                   {
1021                     if(pbutton->get_state() == BUTTON_CLICKED)
1022                       {
1023                       le_current_tile = pbutton->get_tag();
1024                       }
1025                   }
1026                   if((pbutton = le_tilemap_panel->event(event)) != NULL)
1027                   {
1028                     if(pbutton->get_state() == BUTTON_CLICKED)
1029                       {
1030                       active_tm = static_cast<TileMapType>(pbutton->get_tag());
1031                       }
1032                   }
1033                 }
1034               else
1035                 {
1036                   le_settings_bt->event(event);
1037                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1038                     {
1039                       Menu::set_current(leveleditor_menu);
1040                       show_menu = false;
1041                     }
1042                   le_tilegroup_bt->event(event);
1043                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1044                     {
1045                       Menu::set_current(leveleditor_menu);
1046                       show_menu = false;
1047                     }
1048                 }
1049             }
1050           if(show_menu == false)
1051             {
1052               le_move_left_bt->event(event);
1053               le_move_right_bt->event(event);
1054
1055               if(le_mouse_pressed[LEFT])
1056                 {
1057                   le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1058                 }
1059             }
1060         }
1061     }
1062   if(show_menu == false)
1063     {
1064       if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1065         {
1066           pos_x -= 192;
1067         }
1068       else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1069         {
1070           pos_x -= 64;
1071         }
1072
1073       if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1074         {
1075           pos_x += 192;
1076         }
1077       else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1078         {
1079           pos_x += 64;
1080         }
1081     }
1082
1083 }
1084
1085 void le_highlight_selection()
1086 {
1087   int x1, x2, y1, y2;
1088
1089   if(selection.x1 < selection.x2)
1090     {
1091       x1 = selection.x1;
1092       x2 = selection.x2;
1093     }
1094   else
1095     {
1096       x1 = selection.x2;
1097       x2 = selection.x1;
1098     }
1099   if(selection.y1 < selection.y2)
1100     {
1101       y1 = selection.y1;
1102       y2 = selection.y2;
1103     }
1104   else
1105     {
1106       y1 = selection.y2;
1107       y2 = selection.y1;
1108     }
1109
1110   x1 /= 32;
1111   x2 /= 32;
1112   y1 /= 32;
1113   y2 /= 32;
1114
1115   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1116 }
1117
1118 void le_change(float x, float y, int tm, unsigned int c)
1119 {
1120   if(le_current_level != NULL)
1121     {
1122       int xx,yy;
1123       int x1, x2, y1, y2;
1124       unsigned int i;
1125
1126       /*  level_changed = true; */
1127
1128       switch(le_selection_mode)
1129         {
1130         case CURSOR:
1131           le_current_level->change(x,y,tm,c);
1132
1133           yy = ((int)y / 32);
1134           xx = ((int)x / 32);
1135
1136           /* if there is a bad guy over there, remove it */
1137           for(i = 0; i < le_world.bad_guys.size(); ++i)
1138             if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1139               le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1140
1141           if(c == '0')  /* if it's a bad guy */
1142             le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1143           else if(c == '1')
1144             le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1145           else if(c == '2')
1146             le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1147
1148           break;
1149         case SQUARE:
1150           if(selection.x1 < selection.x2)
1151             {
1152               x1 = selection.x1;
1153               x2 = selection.x2;
1154             }
1155           else
1156             {
1157               x1 = selection.x2;
1158               x2 = selection.x1;
1159             }
1160           if(selection.y1 < selection.y2)
1161             {
1162               y1 = selection.y1;
1163               y2 = selection.y2;
1164             }
1165           else
1166             {
1167               y1 = selection.y2;
1168               y2 = selection.y1;
1169             }
1170
1171           x1 /= 32;
1172           x2 /= 32;
1173           y1 /= 32;
1174           y2 /= 32;
1175
1176           /* if there is a bad guy over there, remove it */
1177           for(i = 0; i < le_world.bad_guys.size(); ++i)
1178             if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1179                && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1180               le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1181
1182           for(xx = x1; xx <= x2; xx++)
1183             for(yy = y1; yy <= y2; yy++)
1184               {
1185                 le_current_level->change(xx*32, yy*32, tm, c);
1186
1187                 if(c == '0')  // if it's a bad guy
1188                   le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1189                 else if(c == '1')
1190                   le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1191                 else if(c == '2')
1192                   le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1193               }
1194           break;
1195         default:
1196           break;
1197         }
1198     }
1199 }
1200
1201 void le_testlevel()
1202 {
1203   le_current_level->save("test", le_level);
1204   
1205   GameSession session("test",le_level, ST_GL_TEST);
1206   session.run();
1207
1208   Menu::set_current(leveleditor_menu);
1209   le_world.arrays_free();
1210   le_current_level->load_gfx();
1211   le_world.activate_bad_guys();
1212 }
1213
1214 void le_showhelp()
1215 {
1216   SDL_Event event;
1217   unsigned int i, done;
1218   char *text[] = {
1219                    "  - This is SuperTux's built-in level editor -",
1220                    "It has been designed to be light and easy to use from the start.",
1221                    "",
1222                    "When you first load the level editor you are given a menu where you",
1223                    "can load level subsets, create a new level subset, edit the current",
1224                    "subset's settings, or simply quit the editor. You can access this menu",
1225                    "from the level editor at any time by pressing the escape key.",
1226                    "",
1227                    "To your right is your button bar. The center of this contains many",
1228                    "tiles you can use to make your level. To select a tile, click on it",
1229                    "with your left mouse button; your selection will be shown in the",
1230                    "bottom right corner of the button box. Click anywhere on your level",
1231                    "with the left mouse button to place that tile down. If you right click",
1232                    "a tile in the button bar, you can find out what its keyboard shortcut",
1233                    "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1234                    "background, and enemy tiles. The eraser lets you remove tiles.",
1235                    "The left and right arrow keys scroll back and forth through your level.",
1236                    "The button with the wrench and screwdriver, lets you change the",
1237                    "settings of your level, including how long it is or what music it will",
1238                    "play. When you are ready to give your level a test, click on the little",
1239                    "running Tux. If you like the changes you have made to your level,",
1240                    "press the red save key to keep them.",
1241                    "To change which level in your subset you are editing, press the white",
1242                    "up and down arrow keys at the top of the button box.",
1243                    "",
1244                    "Have fun making levels! If you make some good ones, send them to us on",
1245                    "the SuperTux mailing list!",
1246                    "- SuperTux team"
1247                  };
1248
1249
1250   text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1251
1252   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1253     text_draw(&white_text, text[i], 5, 80+(i*18), 1);
1254
1255   text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1256
1257   flipscreen();
1258
1259   done = 0;
1260
1261   while(done == 0)
1262     {
1263       done = wait_for_event(event);
1264       SDL_Delay(50);
1265     }
1266 }