b0598be1cc3d327b843f74af61b94539bdf12f3c
[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 st_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                       arrays_free();
246                       loadshared();
247                       le_current_level = new st_level;
248                       if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
249                         {
250                           le_quit();
251                           return 1;
252                         }
253                       le_set_defaults();
254                       level_load_gfx(le_current_level);
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                       arrays_free();
277                       loadshared();
278                       le_current_level = new st_level;
279                       if(level_load(le_current_level, le_level_subset.name.c_str(), le_level) != 0)
280                         {
281                           le_quit();
282                           return 1;
283                         }
284                       le_set_defaults();
285                       level_load_gfx(le_current_level);
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       level_free_gfx();
523       level_load_gfx(le_current_level);
524     }
525
526   le_current_level->song_title = string_list_active(level_settings_menu->item[4].list);
527
528   level_change_size(le_current_level, 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   arrays_free();
546
547   level_free(le_current_level);
548   if(level_load(le_current_level, le_level_subset.name.c_str(), levelnb) != 0)
549     {
550       level_load(le_current_level, le_level_subset.name.c_str(), le_level);
551     }
552   else
553     {
554       le_level = levelnb;
555     }
556
557   le_set_defaults();
558
559
560   level_free_gfx();
561   level_load_gfx(le_current_level);
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       level_free_gfx();
597       level_free(le_current_level);
598       unloadshared();
599       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(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h);
686       texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h);
687     }
688   else
689     {
690       clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
691     }
692
693   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
694
695   for (y = 0; y < 15; ++y)
696     for (x = 0; x < 20; ++x)
697       {
698       
699         if(active_tm == TM_BG)
700         a = 255;
701         else
702         a = 128;
703       
704         drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->bg_tiles[y][x + (int)(pos_x / 32)],a);
705         
706         if(active_tm == TM_IA)
707         a = 255;
708         else
709         a = 128;
710         
711         drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)],a);
712
713         if(active_tm == TM_FG)
714         a = 255;
715         else
716         a = 128;
717         
718         drawshape(32*x - fmodf(pos_x, 32), y * 32, le_current_level->fg_tiles[y][x + (int)(pos_x / 32)],a);
719         
720         /* draw whats inside stuff when cursor is selecting those */
721         /* (draw them all the time - is this the right behaviour?) */
722         if(TileManager::instance()->get(le_current_level->ia_tiles[y][x + (int)(pos_x / 32)])->editor_images.size() > 0)
723         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);
724
725       }
726
727   /* Draw the Bad guys: */
728   for (i = 0; i < bad_guys.size(); ++i)
729     {
730       /* to support frames: img_bsod_left[(frame / 5) % 4] */
731       
732       scroll_x = pos_x;
733       bad_guys[i].draw();
734     }
735
736
737   /* Draw the player: */
738   /* for now, the position is fixed at (100, 240) */
739   texture_draw(&tux_right[(global_frame_counter / 5) % 3], 100 - pos_x, 240);
740 }
741
742 void le_checkevents()
743 {
744   SDLKey key;
745   SDLMod keymod;
746   Button* pbutton;
747   int x,y;
748
749   keymod = SDL_GetModState();
750
751   while(SDL_PollEvent(&event))
752     {
753       if(show_menu)
754         menu_event(event);
755       else
756         mouse_cursor->set_state(MC_NORMAL);
757
758       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
759       if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
760                                        event.motion.y > 0 && event.motion.y < screen->h)))
761         {
762           switch(event.type)
763             {
764             case SDL_KEYDOWN:   // key pressed
765               key = event.key.keysym.sym;
766               if(show_menu)
767                 {
768                   if(key == SDLK_ESCAPE)
769                     {
770                       show_menu = false;
771                       Menu::set_current(leveleditor_menu);
772                     }
773                   break;
774                 }
775               switch(key)
776                 {
777                 case SDLK_ESCAPE:
778                   if(!show_menu)
779                     show_menu = true;
780                   else
781                     show_menu = false;
782                   break;
783                 case SDLK_LEFT:
784                   if(fire == DOWN)
785                     cursor_x -= KEY_CURSOR_SPEED;
786                   else
787                     cursor_x -= KEY_CURSOR_FASTSPEED;
788
789                   if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
790                     pos_x = cursor_x - MOUSE_LEFT_MARGIN;
791
792                   break;
793                 case SDLK_RIGHT:
794                   if(fire == DOWN)
795                     cursor_x += KEY_CURSOR_SPEED;
796                   else
797                     cursor_x += KEY_CURSOR_FASTSPEED;
798
799                   if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
800                     pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
801
802                   break;
803                 case SDLK_UP:
804                   if(fire == DOWN)
805                     cursor_y -= KEY_CURSOR_SPEED;
806                   else
807                     cursor_y -= KEY_CURSOR_FASTSPEED;
808
809                   if(cursor_y < 0)
810                     cursor_y = 0;
811                   break;
812                 case SDLK_DOWN:
813                   if(fire == DOWN)
814                     cursor_y += KEY_CURSOR_SPEED;
815                   else
816                     cursor_y += KEY_CURSOR_FASTSPEED;
817
818                   if(cursor_y > screen->h-32)
819                     cursor_y = screen->h-32;
820                   break;
821                 case SDLK_LCTRL:
822                   fire =UP;
823                   break;
824                 case SDLK_F1:
825                   le_showhelp();
826                   break;
827                 case SDLK_HOME:
828                   cursor_x = 0;
829                   pos_x = cursor_x;
830                   break;
831                 case SDLK_END:
832                   cursor_x = (le_current_level->width * 32) - 32;
833                   pos_x = cursor_x;
834                   break;
835                 case SDLK_F9:
836                   le_show_grid = !le_show_grid;
837                   break;
838                 default:
839                   break;
840                 }
841               break;
842             case SDL_KEYUP:     /* key released */
843               switch(event.key.keysym.sym)
844                 {
845                 case SDLK_LCTRL:
846                   fire = DOWN;
847                   break;
848                 default:
849                   break;
850                 }
851               break;
852             case SDL_MOUSEBUTTONDOWN:
853               if(event.button.button == SDL_BUTTON_LEFT)
854                 {
855                   le_mouse_pressed[LEFT] = true;
856
857                   selection.x1 = event.motion.x + pos_x;
858                   selection.y1 = event.motion.y;
859                   selection.x2 = event.motion.x + pos_x;
860                   selection.y2 = event.motion.y;
861                 }
862               else if(event.button.button == SDL_BUTTON_RIGHT)
863                 {
864                 switch(active_tm)
865                 {
866                 case TM_BG:
867                    active_tm = TM_IA;
868                    break;
869                 case TM_IA:
870                    active_tm = TM_FG;
871                    break;
872                 case TM_FG:
873                    active_tm = TM_BG;
874                    break;
875                 default:
876                    break;
877                 }
878                 le_mouse_pressed[RIGHT] = true;
879                 }
880               break;
881             case SDL_MOUSEBUTTONUP:
882               if(event.button.button == SDL_BUTTON_LEFT)
883                 le_mouse_pressed[LEFT] = false;
884               else if(event.button.button == SDL_BUTTON_RIGHT)
885                 le_mouse_pressed[RIGHT] = false;
886               break;
887             case SDL_MOUSEMOTION:
888               if(!show_menu)
889                 {
890                   x = event.motion.x;
891                   y = event.motion.y;
892
893                   cursor_x = ((int)(pos_x + x) / 32) * 32;
894                   cursor_y = ((int) y / 32) * 32;
895
896                   if(le_mouse_pressed[LEFT])
897                     {
898                       selection.x2 = x + pos_x;
899                       selection.y2 = y;
900                     }
901
902                   if(le_mouse_pressed[RIGHT])
903                     {
904                       pos_x += -1 * event.motion.xrel;
905                     }
906                 }
907               break;
908             case SDL_QUIT:      // window closed
909               done = DONE_QUIT;
910               break;
911             default:
912               break;
913             }
914         }
915
916       if(le_current_level != NULL)
917         {
918           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 &&
919               event.motion.y > 0 && event.motion.y < screen->h)))
920             {
921               le_mouse_pressed[LEFT] = false;
922               le_mouse_pressed[RIGHT] = false;
923
924               if(show_menu == false)
925                 {
926                   /* Check for button events */
927                   le_test_level_bt->event(event);
928                   if(le_test_level_bt->get_state() == BUTTON_CLICKED)
929                     le_testlevel();
930                   le_save_level_bt->event(event);
931                   if(le_save_level_bt->get_state() == BUTTON_CLICKED)
932                     level_save(le_current_level,le_level_subset.name.c_str(),le_level);
933                   le_exit_bt->event(event);
934                   if(le_exit_bt->get_state() == BUTTON_CLICKED)
935                   {
936                     Menu::set_current(leveleditor_menu);
937                     show_menu = true;
938                     }
939                   le_next_level_bt->event(event);
940                   if(le_next_level_bt->get_state() == BUTTON_CLICKED)
941                     {
942                       if(le_level < le_level_subset.levels)
943                         {
944                           le_goto_level(++le_level);
945                         }
946                       else
947                         {
948                           st_level new_lev;
949                           char str[1024];
950                           int d = 0;
951                           sprintf(str,"Level %d doesn't exist.",le_level+1);
952                           text_drawf(&white_text,str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
953                           text_drawf(&white_text,"Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
954                           text_drawf(&red_text,"(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
955                           flipscreen();
956                           while(d == 0)
957                             {
958                               while(SDL_PollEvent(&event))
959                                 switch(event.type)
960                                   {
961                                   case SDL_KEYDOWN:             // key pressed
962                                     switch(event.key.keysym.sym)
963                                       {
964                                       case SDLK_y:
965                                         level_default(&new_lev);
966                                         level_save(&new_lev,le_level_subset.name.c_str(),++le_level);
967                                         le_level_subset.levels = le_level;
968                                         le_goto_level(le_level);
969                                         d = 1;
970                                         break;
971                                       case SDLK_n:
972                                         d = 1;
973                                         break;
974                                       default:
975                                         break;
976                                       }
977                                     break;
978                                   default:
979                                     break;
980                                   }
981                               SDL_Delay(50);
982                             }
983                         }
984                     }
985                   le_previous_level_bt->event(event);
986                   if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
987                     {
988                       if(le_level > 1)
989                         le_goto_level(--le_level);
990                     }
991                   le_rubber_bt->event(event);
992                   if(le_rubber_bt->get_state() == BUTTON_CLICKED)
993                     le_current_tile = 0;
994                   le_select_mode_one_bt->event(event);
995                   if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
996                     le_selection_mode = CURSOR;
997                   le_select_mode_two_bt->event(event);
998                   if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
999                     le_selection_mode = SQUARE;
1000
1001                   le_tilegroup_bt->event(event);
1002                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1003                     {
1004                       Menu::set_current(select_tilegroup_menu);
1005                       timer_start(&select_tilegroup_menu_effect,200);
1006                       select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1007                       show_menu = true;
1008                     }
1009
1010                   le_settings_bt->event(event);
1011                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1012                     {
1013                       update_level_settings_menu();
1014                       Menu::set_current(level_settings_menu);
1015                       show_menu = true;
1016                     }
1017                   if(!cur_tilegroup.empty())
1018                   if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1019                   {
1020                     if(pbutton->get_state() == BUTTON_CLICKED)
1021                       {
1022                       le_current_tile = pbutton->get_tag();
1023                       }
1024                   }
1025                   if((pbutton = le_tilemap_panel->event(event)) != NULL)
1026                   {
1027                     if(pbutton->get_state() == BUTTON_CLICKED)
1028                       {
1029                       active_tm = static_cast<TileMapType>(pbutton->get_tag());
1030                       }
1031                   }
1032                 }
1033               else
1034                 {
1035                   le_settings_bt->event(event);
1036                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1037                     {
1038                       Menu::set_current(leveleditor_menu);
1039                       show_menu = false;
1040                     }
1041                   le_tilegroup_bt->event(event);
1042                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1043                     {
1044                       Menu::set_current(leveleditor_menu);
1045                       show_menu = false;
1046                     }
1047                 }
1048             }
1049           if(show_menu == false)
1050             {
1051               le_move_left_bt->event(event);
1052               le_move_right_bt->event(event);
1053
1054               if(le_mouse_pressed[LEFT])
1055                 {
1056                   le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1057                 }
1058             }
1059         }
1060     }
1061   if(show_menu == false)
1062     {
1063       if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1064         {
1065           pos_x -= 192;
1066         }
1067       else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1068         {
1069           pos_x -= 96;
1070         }
1071
1072       if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1073         {
1074           pos_x += 192;
1075         }
1076       else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1077         {
1078           pos_x += 96;
1079         }
1080     }
1081
1082 }
1083
1084 void le_highlight_selection()
1085 {
1086   int x1, x2, y1, y2;
1087
1088   if(selection.x1 < selection.x2)
1089     {
1090       x1 = selection.x1;
1091       x2 = selection.x2;
1092     }
1093   else
1094     {
1095       x1 = selection.x2;
1096       x2 = selection.x1;
1097     }
1098   if(selection.y1 < selection.y2)
1099     {
1100       y1 = selection.y1;
1101       y2 = selection.y2;
1102     }
1103   else
1104     {
1105       y1 = selection.y2;
1106       y2 = selection.y1;
1107     }
1108
1109   x1 /= 32;
1110   x2 /= 32;
1111   y1 /= 32;
1112   y2 /= 32;
1113
1114   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1115 }
1116
1117 void le_change(float x, float y, int tm, unsigned int c)
1118 {
1119   if(le_current_level != NULL)
1120     {
1121       int xx,yy;
1122       int x1, x2, y1, y2;
1123       unsigned int i;
1124
1125       /*  level_changed = true; */
1126
1127       switch(le_selection_mode)
1128         {
1129         case CURSOR:
1130           level_change(le_current_level,x,y,tm,c);
1131
1132           yy = ((int)y / 32);
1133           xx = ((int)x / 32);
1134
1135           /* if there is a bad guy over there, remove it */
1136           for(i = 0; i < bad_guys.size(); ++i)
1137             if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
1138               bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1139
1140           if(c == '0')  /* if it's a bad guy */
1141             add_bad_guy(xx*32, yy*32, BAD_BSOD);
1142           else if(c == '1')
1143             add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1144           else if(c == '2')
1145             add_bad_guy(xx*32, yy*32, BAD_MONEY);
1146
1147           break;
1148         case SQUARE:
1149           if(selection.x1 < selection.x2)
1150             {
1151               x1 = selection.x1;
1152               x2 = selection.x2;
1153             }
1154           else
1155             {
1156               x1 = selection.x2;
1157               x2 = selection.x1;
1158             }
1159           if(selection.y1 < selection.y2)
1160             {
1161               y1 = selection.y1;
1162               y2 = selection.y2;
1163             }
1164           else
1165             {
1166               y1 = selection.y2;
1167               y2 = selection.y1;
1168             }
1169
1170           x1 /= 32;
1171           x2 /= 32;
1172           y1 /= 32;
1173           y2 /= 32;
1174
1175           /* if there is a bad guy over there, remove it */
1176           for(i = 0; i < bad_guys.size(); ++i)
1177             if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1178                 && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1179               bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&bad_guys[i]));
1180
1181           for(xx = x1; xx <= x2; xx++)
1182             for(yy = y1; yy <= y2; yy++)
1183               {
1184                 level_change(le_current_level, xx*32, yy*32, tm, c);
1185
1186                 if(c == '0')  // if it's a bad guy
1187                   add_bad_guy(xx*32, yy*32, BAD_BSOD);
1188                 else if(c == '1')
1189                   add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1190                 else if(c == '2')
1191                   add_bad_guy(xx*32, yy*32, BAD_MONEY);
1192               }
1193           break;
1194         default:
1195           break;
1196         }
1197     }
1198 }
1199
1200 void le_testlevel()
1201 {
1202   level_save(le_current_level,"test",le_level);
1203   gameloop("test",le_level, ST_GL_TEST);
1204   Menu::set_current(leveleditor_menu);
1205   arrays_free();
1206   level_load_gfx(le_current_level);
1207   loadshared();
1208   activate_bad_guys(le_current_level);
1209 }
1210
1211 void le_showhelp()
1212 {
1213   SDL_Event event;
1214   unsigned int i, done;
1215   char *text[] = {
1216                    "  - This is SuperTux's built-in level editor -",
1217                    "It has been designed to be light and easy to use from the start.",
1218                    "",
1219                    "When you first load the level editor you are given a menu where you",
1220                    "can load level subsets, create a new level subset, edit the current",
1221                    "subset's settings, or simply quit the editor. You can access this menu",
1222                    "from the level editor at any time by pressing the escape key.",
1223                    "",
1224                    "To your right is your button bar. The center of this contains many",
1225                    "tiles you can use to make your level. To select a tile, click on it",
1226                    "with your left mouse button; your selection will be shown in the",
1227                    "bottom right corner of the button box. Click anywhere on your level",
1228                    "with the left mouse button to place that tile down. If you right click",
1229                    "a tile in the button bar, you can find out what its keyboard shortcut",
1230                    "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1231                    "background, and enemy tiles. The eraser lets you remove tiles.",
1232                    "The left and right arrow keys scroll back and forth through your level.",
1233                    "The button with the wrench and screwdriver, lets you change the",
1234                    "settings of your level, including how long it is or what music it will",
1235                    "play. When you are ready to give your level a test, click on the little",
1236                    "running Tux. If you like the changes you have made to your level,",
1237                    "press the red save key to keep them.",
1238                    "To change which level in your subset you are editing, press the white",
1239                    "up and down arrow keys at the top of the button box.",
1240                    "",
1241                    "Have fun making levels! If you make some good ones, send them to us on",
1242                    "the SuperTux mailing list!",
1243                    "- SuperTux team"
1244                  };
1245
1246
1247   text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1248
1249   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1250     text_draw(&white_small_text, text[i], 5, 80+(i*12), 1);
1251
1252   text_drawf(&gold_text, "Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1253
1254   flipscreen();
1255
1256   done = 0;
1257
1258   while(done == 0)
1259     {
1260       while(SDL_PollEvent(&event))
1261         switch(event.type)
1262           {
1263           case SDL_MOUSEBUTTONDOWN:             // mouse pressed
1264           case SDL_KEYDOWN:             // key pressed
1265             done = 1;
1266             break;
1267           default:
1268             break;
1269           }
1270       SDL_Delay(50);
1271     }
1272 }