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