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