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