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