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