d7ddc42d43be79b0e05018cc68897b69216d0f3d
[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_init();
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_init();
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   arrays_init();
582
583   level_free(le_current_level);
584   if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
585     {
586       level_load(le_current_level, le_level_subset.name.c_str(), le_level);
587     }
588   else
589     {
590       le_level = levelnb;
591     }
592
593   le_set_defaults();
594
595   le_update_buttons(le_current_level->theme.c_str());
596
597   level_free_gfx();
598   level_load_gfx(le_current_level);
599 }
600
601 void le_quit(void)
602 {
603   /*if(level_changed == true)
604     if(askforsaving() == CANCEL)
605       return;*/ //FIXME
606
607   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
608
609   texture_free(&le_selection);
610   delete leveleditor_menu;
611   delete subset_load_menu;
612   delete subset_new_menu;
613   delete subset_settings_menu;
614   delete level_settings_menu;
615   delete select_tilegroup_menu;
616   button_free(&le_save_level_bt);
617   button_free(&le_test_level_bt);
618   button_free(&le_next_level_bt);
619   button_free(&le_previous_level_bt);
620   button_free(&le_move_right_bt);
621   button_free(&le_move_left_bt);
622   button_free(&le_rubber_bt);
623   button_free(&le_select_mode_one_bt);
624   button_free(&le_select_mode_two_bt);
625   button_free(&le_settings_bt);
626   button_free(&le_tilegroup_bt);
627
628   if(le_current_level != NULL)
629     {
630       level_free_gfx();
631       level_free(le_current_level);
632       unloadshared();
633       arrays_free();
634     }
635 }
636
637 void le_drawinterface()
638 {
639   int x,y;
640   char str[80];
641
642   if(le_current_level != NULL)
643     {
644       /* draw a grid (if selected) */
645       if(le_show_grid)
646         {
647           for(x = 0; x < 19; x++)
648             fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
649           for(y = 0; y < 15; y++)
650             fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
651         }
652     }
653
654   if(le_selection_mode == CURSOR)
655     texture_draw(&le_selection, cursor_x - pos_x, cursor_y);
656   else if(le_selection_mode == SQUARE)
657     {
658       int w, h;
659       le_highlight_selection();
660       /* draw current selection */
661       w = selection.x2 - selection.x1;
662       h = selection.y2 - selection.y1;
663       fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
664       fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
665       fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
666       fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
667     }
668
669
670   /* draw button bar */
671   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
672   drawshape(19 * 32, 14 * 32, le_current_tile);
673   switch(le_current_tile)
674     {
675     case 'B':
676       texture_draw(&img_mints, 19 * 32, 14 * 32);
677       break;
678     case '!':
679       texture_draw(&img_golden_herring,19 * 32, 14 * 32);
680       break;
681     case 'x':
682     case 'y':
683     case 'A':
684       texture_draw(&img_distro[(le_frame / 5) % 4], 19 * 32, 14 * 32);
685       break;
686     case '0':
687       texture_draw(&img_bsod_left[(le_frame / 5) % 4],19 * 32, 14 * 32);
688       break;
689     case '1':
690       texture_draw(&img_laptop_left[(le_frame / 5) % 3],19 * 32, 14 * 32);
691       break;
692     case '2':
693       texture_draw(&img_money_left[0],19 * 32, 14 * 32);
694       break;
695     default:
696       break;
697     }
698
699   if(le_current_level != NULL)
700     {
701       button_draw(&le_save_level_bt);
702       button_draw(&le_test_level_bt);
703       button_draw(&le_next_level_bt);
704       button_draw(&le_previous_level_bt);
705       button_draw(&le_rubber_bt);
706       button_draw(&le_select_mode_one_bt);
707       button_draw(&le_select_mode_two_bt);
708       button_draw(&le_settings_bt);
709       button_draw(&le_move_right_bt);
710       button_draw(&le_move_left_bt);
711       button_draw(&le_tilegroup_bt);
712       button_panel_draw(&tilegroups_map[cur_tilegroup]);
713
714       sprintf(str, "%d/%d", le_level,le_level_subset.levels);
715       text_drawf(&white_text, str, -8, 16, A_RIGHT, A_TOP, 1);
716
717       text_draw(&white_small_text, "F1 for Help", 10, 430, 1);
718     }
719   else
720     {
721       if(show_menu == false)
722         text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
723       else
724         text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1);
725     }
726
727 }
728
729 void le_drawlevel()
730 {
731   unsigned int y,x,i,s;
732
733   /* Draw the real background */
734   if(le_current_level->bkgd_image[0] != '\0')
735     {
736       s = pos_x / 30;
737       texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
738       texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
739     }
740   else
741     {
742       clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
743     }
744
745   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
746
747   for (y = 0; y < 15; ++y)
748     for (x = 0; x < 20; ++x)
749       {
750         drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]);
751
752         /* draw whats inside stuff when cursor is selecting those */
753         /* (draw them all the time - is this the right behaviour?) */
754         switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)])
755           {
756           case 'B':
757             texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32);
758             break;
759           case '!':
760             texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32);
761             break;
762           case 'x':
763           case 'y':
764           case 'A':
765             texture_draw(&img_distro[(global_frame_counter / 5) % 4], x * 32 - ((int)pos_x % 32), y*32);
766             break;
767           default:
768             break;
769           }
770       }
771
772   /* Draw the Bad guys: */
773   for (i = 0; i < bad_guys.size(); ++i)
774     {
775       /* to support frames: img_bsod_left[(frame / 5) % 4] */
776       if(bad_guys[i].kind == BAD_BSOD)
777         texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
778       else if(bad_guys[i].kind == BAD_LAPTOP)
779         texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
780       else if (bad_guys[i].kind == BAD_MONEY)
781         texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y);
782     }
783
784
785   /* Draw the player: */
786   /* for now, the position is fixed at (0, 240) */
787   texture_draw(&tux_right[(global_frame_counter / 5) % 3], 0 - pos_x, 240);
788 }
789
790 void le_checkevents()
791 {
792   SDLKey key;
793   SDLMod keymod;
794   button_type* pbutton;
795   int x,y;
796
797   keymod = SDL_GetModState();
798
799   while(SDL_PollEvent(&event))
800     {
801       if(show_menu)
802         menu_event(event);
803       else
804         mouse_cursor->set_state(MC_NORMAL);
805
806       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
807       if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
808                                        event.motion.y > 0 && event.motion.y < screen->h)))
809         {
810           switch(event.type)
811             {
812             case SDL_KEYDOWN:   // key pressed
813               key = event.key.keysym.sym;
814               if(show_menu)
815                 {
816                   if(key == SDLK_ESCAPE)
817                     {
818                       show_menu = false;
819                       Menu::set_current(leveleditor_menu);
820                     }
821                   break;
822                 }
823               switch(key)
824                 {
825                 case SDLK_ESCAPE:
826                   if(!show_menu)
827                     show_menu = true;
828                   else
829                     show_menu = false;
830                   break;
831                 case SDLK_LEFT:
832                   if(fire == DOWN)
833                     cursor_x -= KEY_CURSOR_SPEED;
834                   else
835                     cursor_x -= KEY_CURSOR_FASTSPEED;
836
837                   if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
838                     pos_x = cursor_x - MOUSE_LEFT_MARGIN;
839
840                   break;
841                 case SDLK_RIGHT:
842                   if(fire == DOWN)
843                     cursor_x += KEY_CURSOR_SPEED;
844                   else
845                     cursor_x += KEY_CURSOR_FASTSPEED;
846
847                   if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
848                     pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
849
850                   break;
851                 case SDLK_UP:
852                   if(fire == DOWN)
853                     cursor_y -= KEY_CURSOR_SPEED;
854                   else
855                     cursor_y -= KEY_CURSOR_FASTSPEED;
856
857                   if(cursor_y < 0)
858                     cursor_y = 0;
859                   break;
860                 case SDLK_DOWN:
861                   if(fire == DOWN)
862                     cursor_y += KEY_CURSOR_SPEED;
863                   else
864                     cursor_y += KEY_CURSOR_FASTSPEED;
865
866                   if(cursor_y > screen->h-32)
867                     cursor_y = screen->h-32;
868                   break;
869                 case SDLK_LCTRL:
870                   fire =UP;
871                   break;
872                 case SDLK_F1:
873                   le_showhelp();
874                   break;
875                 case SDLK_HOME:
876                   cursor_x = 0;
877                   pos_x = cursor_x;
878                   break;
879                 case SDLK_END:
880                   cursor_x = (le_current_level->width * 32) - 32;
881                   pos_x = cursor_x;
882                   break;
883                 case SDLK_F9:
884                   le_show_grid = !le_show_grid;
885                   break;
886                 default:
887                   break;
888                 }
889               break;
890             case SDL_KEYUP:     /* key released */
891               switch(event.key.keysym.sym)
892                 {
893                 case SDLK_LCTRL:
894                   fire = DOWN;
895                   break;
896                 default:
897                   break;
898                 }
899               break;
900             case SDL_MOUSEBUTTONDOWN:
901               if(event.button.button == SDL_BUTTON_LEFT)
902                 {
903                   le_mouse_pressed[LEFT] = true;
904
905                   selection.x1 = event.motion.x + pos_x;
906                   selection.y1 = event.motion.y;
907                   selection.x2 = event.motion.x + pos_x;
908                   selection.y2 = event.motion.y;
909                 }
910               else if(event.button.button == SDL_BUTTON_RIGHT)
911                 le_mouse_pressed[RIGHT] = true;
912               break;
913             case SDL_MOUSEBUTTONUP:
914               if(event.button.button == SDL_BUTTON_LEFT)
915                 le_mouse_pressed[LEFT] = false;
916               else if(event.button.button == SDL_BUTTON_RIGHT)
917                 le_mouse_pressed[RIGHT] = false;
918               break;
919             case SDL_MOUSEMOTION:
920               if(!show_menu)
921                 {
922                   x = event.motion.x;
923                   y = event.motion.y;
924
925                   cursor_x = ((int)(pos_x + x) / 32) * 32;
926                   cursor_y = ((int) y / 32) * 32;
927
928                   if(le_mouse_pressed[LEFT])
929                     {
930                       selection.x2 = x + pos_x;
931                       selection.y2 = y;
932                     }
933
934                   if(le_mouse_pressed[RIGHT])
935                     {
936                       pos_x += -1 * event.motion.xrel;
937                     }
938                 }
939               break;
940             case SDL_QUIT:      // window closed
941               done = DONE_QUIT;
942               break;
943             default:
944               break;
945             }
946         }
947
948       if(le_current_level != NULL)
949         {
950           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 &&
951               event.motion.y > 0 && event.motion.y < screen->h)))
952             {
953               le_mouse_pressed[LEFT] = false;
954               le_mouse_pressed[RIGHT] = false;
955
956               if(show_menu == false)
957                 {
958                   /* Check for button events */
959                   button_event(&le_test_level_bt,&event);
960                   if(button_get_state(&le_test_level_bt) == BUTTON_CLICKED)
961                     le_testlevel();
962                   button_event(&le_save_level_bt,&event);
963                   if(button_get_state(&le_save_level_bt) == BUTTON_CLICKED)
964                     level_save(le_current_level,le_level_subset.name.c_str(),le_level);
965                   button_event(&le_next_level_bt,&event);
966                   if(button_get_state(&le_next_level_bt) == BUTTON_CLICKED)
967                     {
968                       if(le_level < le_level_subset.levels)
969                         {
970                           le_goto_level(++le_level);
971                         }
972                       else
973                         {
974                           st_level new_lev;
975                           char str[1024];
976                           int d = 0;
977                           sprintf(str,"Level %d doesn't exist.",le_level+1);
978                           text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
979                           text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
980                           text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
981                           flipscreen();
982                           while(d == 0)
983                             {
984                               while(SDL_PollEvent(&event))
985                                 switch(event.type)
986                                   {
987                                   case SDL_KEYDOWN:             // key pressed
988                                     switch(event.key.keysym.sym)
989                                       {
990                                       case SDLK_y:
991                                         level_default(&new_lev);
992                                         level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
993                                         le_level_subset.levels = le_level;
994                                         le_goto_level(le_level);
995                                         d = 1;
996                                         break;
997                                       case SDLK_n:
998                                         d = 1;
999                                         break;
1000                                       default:
1001                                         break;
1002                                       }
1003                                     break;
1004                                   default:
1005                                     break;
1006                                   }
1007                               SDL_Delay(50);
1008                             }
1009                         }
1010                     }
1011                   button_event(&le_previous_level_bt,&event);
1012                   if(button_get_state(&le_previous_level_bt) == BUTTON_CLICKED)
1013                     {
1014                       if(le_level > 1)
1015                         le_goto_level(--le_level);
1016                     }
1017                   button_event(&le_rubber_bt,&event);
1018                   if(button_get_state(&le_rubber_bt) == BUTTON_CLICKED)
1019                     le_current_tile = 0;
1020                   button_event(&le_select_mode_one_bt,&event);
1021                   if(button_get_state(&le_select_mode_one_bt) == BUTTON_CLICKED)
1022                     le_selection_mode = CURSOR;
1023                   button_event(&le_select_mode_two_bt,&event);
1024                   if(button_get_state(&le_select_mode_two_bt) == BUTTON_CLICKED)
1025                     le_selection_mode = SQUARE;
1026
1027                   button_event(&le_tilegroup_bt,&event);
1028                   if(button_get_state(&le_tilegroup_bt) == BUTTON_CLICKED)
1029                     {
1030                       Menu::set_current(select_tilegroup_menu);
1031                       timer_start(&select_tilegroup_menu_effect,200);
1032                       select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1033                       show_menu = true;
1034                     }
1035
1036                   button_event(&le_settings_bt,&event);
1037                   if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1038                     {
1039                       update_level_settings_menu();
1040                       Menu::set_current(level_settings_menu);
1041                       show_menu = true;
1042                     }
1043                   if((pbutton = button_panel_event(&tilegroups_map[cur_tilegroup],&event)) != NULL)
1044                   {
1045                     if(button_get_state(pbutton) == BUTTON_CLICKED)
1046                       {
1047                       le_current_tile = pbutton->tag;
1048                       }
1049                   }
1050                   /*if((pbutton = button_panel_event(&le_bkgd_panel,&event)) != NULL)
1051                     {
1052                       if(button_get_state(pbutton) == BUTTON_CLICKED)
1053                         {
1054                           char c = '\0';
1055                           if(pbutton->tag >= 0 && pbutton->tag <= 3)
1056                             c = 'G' + pbutton->tag;
1057                           else if(pbutton->tag >= 4 && pbutton->tag <= 7)
1058                             c = 'g' + pbutton->tag - 4;
1059                           else if(pbutton->tag >= 8 && pbutton->tag <= 11)
1060                             c = 'C' + pbutton->tag - 8;
1061                           else if(pbutton->tag >= 12 && pbutton->tag <= 15)
1062                             c = 'c' + pbutton->tag - 12;
1063                           if(c != '\0')
1064                             le_current_tile = c;
1065                         }
1066                     }*/
1067                 }
1068               else
1069                 {
1070                   button_event(&le_settings_bt,&event);
1071                   if(button_get_state(&le_settings_bt) == BUTTON_CLICKED)
1072                     {
1073                       Menu::set_current(leveleditor_menu);
1074                       show_menu = false;
1075                     }
1076                   button_event(&le_tilegroup_bt,&event);
1077                   if(button_get_state(&le_tilegroup_bt) == BUTTON_CLICKED)
1078                     {
1079                       Menu::set_current(leveleditor_menu);
1080                       show_menu = false;
1081                     }
1082                 }
1083             }
1084           if(show_menu == false)
1085             {
1086               button_event(&le_move_left_bt,&event);
1087               button_event(&le_move_right_bt,&event);
1088
1089               if(le_mouse_pressed[LEFT])
1090                 {
1091                   le_change(cursor_x, cursor_y, TM_IA, le_current_tile);
1092                 }
1093             }
1094         }
1095     }
1096   if(show_menu == false)
1097     {
1098       if(button_get_state(&le_move_left_bt) == BUTTON_PRESSED)
1099         {
1100           pos_x -= 192;
1101         }
1102       else if(button_get_state(&le_move_left_bt) == BUTTON_HOVER)
1103         {
1104           pos_x -= 96;
1105         }
1106
1107       if(button_get_state(&le_move_right_bt) == BUTTON_PRESSED)
1108         {
1109           pos_x += 192;
1110         }
1111       else if(button_get_state(&le_move_right_bt) == BUTTON_HOVER)
1112         {
1113           pos_x += 96;
1114         }
1115     }
1116
1117 }
1118
1119 void le_highlight_selection()
1120 {
1121   int x1, x2, y1, y2;
1122
1123   if(selection.x1 < selection.x2)
1124     {
1125       x1 = selection.x1;
1126       x2 = selection.x2;
1127     }
1128   else
1129     {
1130       x1 = selection.x2;
1131       x2 = selection.x1;
1132     }
1133   if(selection.y1 < selection.y2)
1134     {
1135       y1 = selection.y1;
1136       y2 = selection.y2;
1137     }
1138   else
1139     {
1140       y1 = selection.y2;
1141       y2 = selection.y1;
1142     }
1143
1144   x1 /= 32;
1145   x2 /= 32;
1146   y1 /= 32;
1147   y2 /= 32;
1148
1149   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1150 }
1151
1152 void le_change(float x, float y, int tm, unsigned int c)
1153 {
1154   if(le_current_level != NULL)
1155     {
1156       int xx,yy;
1157       int x1, x2, y1, y2;
1158       unsigned int i;
1159
1160       /*  level_changed = true; */
1161
1162       switch(le_selection_mode)
1163         {
1164         case CURSOR:
1165           level_change(le_current_level,x,y,tm,c);
1166
1167           yy = ((int)y / 32);
1168           xx = ((int)x / 32);
1169
1170           /* if there is a bad guy over there, remove it */
1171           for(i = 0; i < bad_guys.size(); ++i)
1172             if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1173               bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1174
1175           if(c == '0')  /* if it's a bad guy */
1176             add_bad_guy(xx*32, yy*32, BAD_BSOD);
1177           else if(c == '1')
1178             add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1179           else if(c == '2')
1180             add_bad_guy(xx*32, yy*32, BAD_MONEY);
1181
1182           break;
1183         case SQUARE:
1184           if(selection.x1 < selection.x2)
1185             {
1186               x1 = selection.x1;
1187               x2 = selection.x2;
1188             }
1189           else
1190             {
1191               x1 = selection.x2;
1192               x2 = selection.x1;
1193             }
1194           if(selection.y1 < selection.y2)
1195             {
1196               y1 = selection.y1;
1197               y2 = selection.y2;
1198             }
1199           else
1200             {
1201               y1 = selection.y2;
1202               y2 = selection.y1;
1203             }
1204
1205           x1 /= 32;
1206           x2 /= 32;
1207           y1 /= 32;
1208           y2 /= 32;
1209
1210           /* if there is a bad guy over there, remove it */
1211           for(i = 0; i < bad_guys.size(); ++i)
1212             if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1213                 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1214               bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1215
1216           for(xx = x1; xx <= x2; xx++)
1217             for(yy = y1; yy <= y2; yy++)
1218               {
1219                 level_change(le_current_level, xx*32, yy*32, tm, c);
1220
1221                 if(c == '0')  // if it's a bad guy
1222                   add_bad_guy(xx*32, yy*32, BAD_BSOD);
1223                 else if(c == '1')
1224                   add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1225                 else if(c == '2')
1226                   add_bad_guy(xx*32, yy*32, BAD_MONEY);
1227               }
1228           break;
1229         default:
1230           break;
1231         }
1232     }
1233 }
1234
1235 void le_testlevel()
1236 {
1237   level_save(le_current_level,"test",le_level);
1238   gameloop("test",le_level, ST_GL_TEST);
1239   Menu::set_current(leveleditor_menu);
1240   arrays_init();
1241   level_load_gfx(le_current_level);
1242   loadshared();
1243 }
1244
1245 void le_showhelp()
1246 {
1247   SDL_Event event;
1248   unsigned int i, done;
1249   char *text[] = {
1250                    "  - This is SuperTux's built-in level editor -",
1251                    "It has been designed to be light and easy to use from the start.",
1252                    "",
1253                    "When you first load the level editor you are given a menu where you",
1254                    "can load level subsets, create a new level subset, edit the current",
1255                    "subset's settings, or simply quit the editor. You can access this menu",
1256                    "from the level editor at any time by pressing the escape key.",
1257                    "",
1258                    "To your right is your button bar. The center of this contains many",
1259                    "tiles you can use to make your level. To select a tile, click on it",
1260                    "with your left mouse button; your selection will be shown in the",
1261                    "bottom right corner of the button box. Click anywhere on your level",
1262                    "with the left mouse button to place that tile down. If you right click",
1263                    "a tile in the button bar, you can find out what its keyboard shortcut",
1264                    "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1265                    "background, and enemy tiles. The eraser lets you remove tiles.",
1266                    "The left and right arrow keys scroll back and forth through your level.",
1267                    "The button with the wrench and screwdriver, lets you change the",
1268                    "settings of your level, including how long it is or what music it will",
1269                    "play. When you are ready to give your level a test, click on the little",
1270                    "running Tux. If you like the changes you have made to your level,",
1271                    "press the red save key to keep them.",
1272                    "To change which level in your subset you are editing, press the white",
1273                    "up and down arrow keys at the top of the button box.",
1274                    "",
1275                    "Have fun making levels! If you make some good ones, send them to us on",
1276                    "the SuperTux mailing list!",
1277                    "- SuperTux team"
1278                  };
1279
1280
1281   text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1282
1283   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1284     text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1285
1286   text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1287
1288   flipscreen();
1289
1290   done = 0;
1291
1292   while(done == 0)
1293     {
1294       while(SDL_PollEvent(&event))
1295         switch(event.type)
1296           {
1297           case SDL_MOUSEBUTTONDOWN:             // mouse pressed
1298           case SDL_KEYDOWN:             // key pressed
1299             done = 1;
1300             break;
1301           default:
1302             break;
1303           }
1304       SDL_Delay(50);
1305     }
1306 }