- removed menu_process_current()
[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
42
43 /* definitions that affect gameplay */
44 #define KEY_CURSOR_SPEED 32
45 #define KEY_CURSOR_FASTSPEED 64
46
47 /* when pagedown/up pressed speed:*/
48 #define PAGE_CURSOR_SPEED 13*32
49
50 #define MOUSE_LEFT_MARGIN 80
51 #define MOUSE_RIGHT_MARGIN (560-32)
52 /* right_margin should noticed that the cursor is 32 pixels,
53    so it should subtract that value */
54 #define MOUSE_POS_SPEED 20
55
56 /* look */
57 #define SELECT_W 2 // size of the selections lines
58 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
59
60 /* own declerations */
61 /* crutial ones (main loop) */
62 int le_init();
63 void le_quit();
64 void le_drawlevel();
65 void le_drawinterface();
66 void le_checkevents();
67 void le_change(float x, float y, int tm, unsigned int c);
68 void le_testlevel();
69 void le_showhelp();
70 void le_set_defaults(void);
71 void le_activate_bad_guys(void);
72
73 void le_highlight_selection();
74
75 void apply_level_settings_menu();
76 void update_subset_settings_menu();
77 void save_subset_settings_menu();
78
79 static Level* le_current_level;
80
81 struct LevelEditorWorld
82 {
83   std::vector<BadGuy> bad_guys;
84   void arrays_free(void)
85   {
86     bad_guys.clear();
87   }
88
89   void add_bad_guy(float x, float y, BadGuyKind kind)
90   {
91     bad_guys.push_back(BadGuy());
92     BadGuy& new_bad_guy = bad_guys.back();
93   
94     new_bad_guy.init(x,y,kind);
95   }
96
97   void activate_bad_guys()
98   {
99     for (std::vector<BadGuyData>::iterator i = le_current_level->badguy_data.begin();
100          i != le_current_level->badguy_data.end();
101          ++i)
102       {
103         add_bad_guy(i->x, i->y, i->kind);
104       }
105   }
106 };
107
108 /* leveleditor internals */
109 static string_list_type level_subsets;
110 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
111 static int pos_x, cursor_x, cursor_y, fire;
112 static int le_level;
113 static LevelEditorWorld le_world;
114 static st_subset le_level_subset;
115 static int le_show_grid;
116 static int le_frame;
117 static Surface* le_selection;
118 static int done;
119 static unsigned int le_current_tile;
120 static bool le_mouse_pressed[2];
121 static Button* le_save_level_bt;
122 static Button* le_exit_bt;
123 static Button* le_test_level_bt;
124 static Button* le_next_level_bt;
125 static Button* le_previous_level_bt;
126 static Button* le_move_right_bt;
127 static Button* le_move_left_bt;
128 static Button* le_rubber_bt;
129 static Button* le_select_mode_one_bt;
130 static Button* le_select_mode_two_bt;
131 static Button* le_settings_bt;
132 static Button* le_tilegroup_bt;
133 static ButtonPanel* le_tilemap_panel;
134 static Menu* leveleditor_menu;
135 static Menu* subset_load_menu;
136 static Menu* subset_new_menu;
137 static Menu* subset_settings_menu;
138 static Menu* level_settings_menu;
139 static Menu* select_tilegroup_menu;
140 static Timer select_tilegroup_menu_effect;
141 static std::map<std::string, ButtonPanel* > tilegroups_map;
142 static std::string cur_tilegroup;
143
144 static square selection;
145 static int le_selection_mode;
146 static SDL_Event event;
147 TileMapType active_tm;
148
149 void le_set_defaults()
150 {
151   if(le_current_level != NULL)
152     {
153       /* Set defaults: */
154
155       if(le_current_level->time_left == 0)
156         le_current_level->time_left = 255;
157     }
158 }
159
160 int leveleditor(int levelnb)
161 {
162   int last_time, now_time, i;
163
164   le_level = levelnb;
165   if(le_init() != 0)
166     return 1;
167
168   /* Clear screen: */
169
170   clearscreen(0, 0, 0);
171   updatescreen();
172
173   while (SDL_PollEvent(&event))
174     {}
175
176   while(true)
177     {
178       last_time = SDL_GetTicks();
179       le_frame++;
180
181       le_checkevents();
182
183       if(Menu::current() == select_tilegroup_menu)
184         {
185           if(select_tilegroup_menu_effect.check())
186             {
187               select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
188                                              82,-0.5,0.5);
189             }
190           else
191             select_tilegroup_menu->set_pos(screen->w - 64,82,-0.5,0.5);
192         }
193
194       if(le_current_level != NULL)
195         {
196           /* making events results to be in order */
197           if(pos_x < 0)
198             pos_x = 0;
199           if(pos_x > (le_current_level->width * 32) - screen->w)
200             pos_x = (le_current_level->width * 32) - screen->w;
201
202           /* draw the level */
203           le_drawlevel();
204         }
205       else
206         clearscreen(0, 0, 0);
207
208       /* draw editor interface */
209       le_drawinterface();
210
211       if(Menu::current())
212         {
213           Menu::current()->action();
214           Menu::current()->draw();
215
216           if(Menu::current() == leveleditor_menu)
217             {
218               switch (leveleditor_menu->check())
219                 {
220                 case 2:
221                   Menu::set_current(0);
222                   break;
223                 case 3:
224                   update_subset_settings_menu();
225                   break;
226                 case 7:
227                   done = 1;
228                   break;
229                 }
230             }
231           else if(Menu::current() == 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                   
240                 default:
241                   //show_menu = true;
242                   break;
243                 }
244             }
245           else if(Menu::current() == select_tilegroup_menu)
246             {
247               int it = -1;
248               switch (it = select_tilegroup_menu->check())
249                 {
250                 default:
251                   if(it != -1)
252                     {
253                       if(select_tilegroup_menu->item[it].kind == MN_ACTION)
254                         cur_tilegroup = select_tilegroup_menu->item[it].text;
255                   
256                       Menu::set_current(0);
257                     }
258                   break;
259                 }
260             }
261           else if(Menu::current() == subset_load_menu)
262             {
263               switch (i = subset_load_menu->check())
264                 {
265                 case 0:
266                   break;
267                 default:
268                   if(i != -1)
269                     {
270                       le_level_subset.load(level_subsets.item[i-2]);
271                       leveleditor_menu->item[3].kind = MN_GOTO;
272                       le_level = 1;
273                       le_world.arrays_free();
274                       le_current_level = new Level;
275                       if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
276                         {
277                           le_quit();
278                           return 1;
279                         }
280                       le_set_defaults();
281                       le_current_level->load_gfx();
282                       le_world.activate_bad_guys();
283
284                       // FIXME:?
285                       Menu::set_current(leveleditor_menu);
286                     }
287                   break;
288                 }
289             }
290           else if(Menu::current() == subset_new_menu)
291             {
292               if(subset_new_menu->item[2].input[0] == '\0')
293                 subset_new_menu->item[3].kind = MN_DEACTIVE;
294               else
295                 {
296                   subset_new_menu->item[3].kind = MN_ACTION;
297
298                   switch (i = subset_new_menu->check())
299                     {
300                     case 3:
301                       st_subset::create(subset_new_menu->item[2].input);
302                       le_level_subset.load(subset_new_menu->item[2].input);
303                       leveleditor_menu->item[3].kind = MN_GOTO;
304                       le_level = 1;
305                       le_world.arrays_free();
306                       le_current_level = new Level;
307                       if(le_current_level->load(le_level_subset.name.c_str(), le_level) != 0)
308                         {
309                           le_quit();
310                           return 1;
311                         }
312                       le_set_defaults();
313                       le_current_level->load_gfx();
314                       le_world.activate_bad_guys();
315                       subset_new_menu->item[2].change_input("");
316                       // FIXME:? show_menu = true;
317                       Menu::set_current(leveleditor_menu);
318                       break;
319                     }
320                 }
321             }
322           else if(Menu::current() == subset_settings_menu)
323             {
324               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  )
325                 subset_settings_menu->item[5].kind = MN_DEACTIVE;
326               else
327                 subset_settings_menu->item[5].kind = MN_ACTION;
328
329               switch (i = subset_settings_menu->check())
330                 {
331                 case 5:
332                   save_subset_settings_menu();
333                   //FIXME:show_menu = true;
334                   Menu::set_current(leveleditor_menu);
335                   break;
336                 }
337             }
338         }
339
340       mouse_cursor->draw();
341
342 printf("done: %i\n", done);
343
344       if(done)
345         {
346 printf("done\n");
347           le_quit();
348           return 0;
349         }
350
351       ++global_frame_counter;
352         
353       SDL_Delay(25);
354       now_time = SDL_GetTicks();
355       if (now_time < last_time + FPS)
356         SDL_Delay(last_time + FPS - now_time);  /* delay some time */
357
358       flipscreen();
359     }
360
361   return done;
362 }
363
364 int le_init()
365 {
366   int i;
367   level_subsets = dsubdirs("/levels", "info");
368
369   active_tm = TM_IA;
370   
371   le_show_grid = true;
372
373   /*  level_changed = NO;*/
374   fire = DOWN;
375   done = 0;
376   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
377   le_level_changed = false;
378   le_current_level = NULL;
379
380   le_current_tile = 0;
381   le_mouse_pressed[LEFT] = false;
382   le_mouse_pressed[RIGHT] = false;
383
384   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
385
386   select_tilegroup_menu_effect.init(false);
387
388   /* Load buttons */
389   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
390   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F6,screen->w-32,32);
391   le_next_level_bt = new Button("/images/icons/up.png","Next level", SDLK_PAGEUP,screen->w-64,0);
392   le_previous_level_bt = new Button("/images/icons/down.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
393   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
394   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
395   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,64);
396   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
397   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
398   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,0,0);
399   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
400   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,80);
401   
402   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
403   le_tilemap_panel->set_button_size(32,10);
404   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_F4,0,0),TM_BG);
405   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_F4,0,0),TM_IA);
406   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_F4,0,0),TM_FG); 
407   
408   leveleditor_menu = new Menu();
409   subset_load_menu = new Menu();
410   subset_new_menu  = new Menu();
411   subset_settings_menu = new Menu();
412   level_settings_menu  = new Menu();
413   select_tilegroup_menu  = new Menu();
414
415   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
416   leveleditor_menu->additem(MN_HL,"",0,0);
417   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0);
418   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu);
419   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
420   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
421   leveleditor_menu->additem(MN_HL,"",0,0);
422   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0);
423
424   Menu::set_current(leveleditor_menu);
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(!Menu::current())
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 (Menu::current())
795         {
796           Menu::current()->event(event);
797         }
798       else
799         {
800           mouse_cursor->set_state(MC_NORMAL);
801
802           /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
803           if(event.type == SDL_KEYDOWN 
804              || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
805                  && (event.motion.x > 0 
806                      && event.motion.x < screen->w - 64 &&
807                      event.motion.y > 0 && event.motion.y < screen->h)))
808             {
809               switch(event.type)
810                 {
811                 case SDL_KEYDOWN:       // key pressed
812                   key = event.key.keysym.sym;
813                   switch(key)
814                     {
815                     case SDLK_LEFT:
816                       if(fire == DOWN)
817                         cursor_x -= KEY_CURSOR_SPEED;
818                       else
819                         cursor_x -= KEY_CURSOR_FASTSPEED;
820
821                       if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
822                         pos_x = cursor_x - MOUSE_LEFT_MARGIN;
823
824                       break;
825                     case SDLK_RIGHT:
826                       if(fire == DOWN)
827                         cursor_x += KEY_CURSOR_SPEED;
828                       else
829                         cursor_x += KEY_CURSOR_FASTSPEED;
830
831                       if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
832                         pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
833
834                       break;
835                     case SDLK_UP:
836                       if(fire == DOWN)
837                         cursor_y -= KEY_CURSOR_SPEED;
838                       else
839                         cursor_y -= KEY_CURSOR_FASTSPEED;
840
841                       if(cursor_y < 0)
842                         cursor_y = 0;
843                       break;
844                     case SDLK_DOWN:
845                       if(fire == DOWN)
846                         cursor_y += KEY_CURSOR_SPEED;
847                       else
848                         cursor_y += KEY_CURSOR_FASTSPEED;
849
850                       if(cursor_y > screen->h-32)
851                         cursor_y = screen->h-32;
852                       break;
853                     case SDLK_LCTRL:
854                       fire =UP;
855                       break;
856                     case SDLK_F1:
857                       le_showhelp();
858                       break;
859                     case SDLK_HOME:
860                       cursor_x = 0;
861                       pos_x = cursor_x;
862                       break;
863                     case SDLK_END:
864                       cursor_x = (le_current_level->width * 32) - 32;
865                       pos_x = cursor_x;
866                       break;
867                     case SDLK_F9:
868                       le_show_grid = !le_show_grid;
869                       break;
870                     default:
871                       break;
872                     }
873                   break;
874                 case SDL_KEYUP: /* key released */
875                   switch(event.key.keysym.sym)
876                     {
877                     case SDLK_LCTRL:
878                       fire = DOWN;
879                       break;
880                     default:
881                       break;
882                     }
883                   break;
884                 case SDL_MOUSEBUTTONDOWN:
885                   if(event.button.button == SDL_BUTTON_LEFT)
886                     {
887                       le_mouse_pressed[LEFT] = true;
888
889                       selection.x1 = event.motion.x + pos_x;
890                       selection.y1 = event.motion.y;
891                       selection.x2 = event.motion.x + pos_x;
892                       selection.y2 = event.motion.y;
893                     }
894                   else if(event.button.button == SDL_BUTTON_RIGHT)
895                     {
896                       le_mouse_pressed[RIGHT] = true;
897                     }
898                   break;
899                 case SDL_MOUSEBUTTONUP:
900                   if(event.button.button == SDL_BUTTON_LEFT)
901                     le_mouse_pressed[LEFT] = false;
902                   else if(event.button.button == SDL_BUTTON_RIGHT)
903                     le_mouse_pressed[RIGHT] = false;
904                   break;
905                 case SDL_MOUSEMOTION:
906
907                   if(!Menu::current())
908                     {
909                       x = event.motion.x;
910                       y = event.motion.y;
911
912                       cursor_x = ((int)(pos_x + x) / 32) * 32;
913                       cursor_y = ((int) y / 32) * 32;
914
915                       if(le_mouse_pressed[LEFT])
916                         {
917                           selection.x2 = x + pos_x;
918                           selection.y2 = y;
919                         }
920
921                       if(le_mouse_pressed[RIGHT])
922                         {
923                           pos_x += -1 * event.motion.xrel;
924                         }
925                     }
926                   break;
927                 case SDL_QUIT:  // window closed
928                   done = 1;
929                   break;
930                 default:
931                   break;
932                 }
933             }
934         }
935
936       if(le_current_level != NULL)
937         {
938           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 &&
939                                                                                                                                  event.motion.y > 0 && event.motion.y < screen->h)))
940             {
941               le_mouse_pressed[LEFT] = false;
942               le_mouse_pressed[RIGHT] = false;
943
944               if(!Menu::current())
945                 {
946                   /* Check for button events */
947                   le_test_level_bt->event(event);
948                   if(le_test_level_bt->get_state() == BUTTON_CLICKED)
949                     le_testlevel();
950                   le_save_level_bt->event(event);
951                   if(le_save_level_bt->get_state() == BUTTON_CLICKED)
952                     le_current_level->save(le_level_subset.name.c_str(),le_level);
953                   le_exit_bt->event(event);
954                   if(le_exit_bt->get_state() == BUTTON_CLICKED)
955                     {
956                       Menu::set_current(leveleditor_menu);
957                     }
958                   le_next_level_bt->event(event);
959                   if(le_next_level_bt->get_state() == BUTTON_CLICKED)
960                     {
961                       if(le_level < le_level_subset.levels)
962                         {
963                           le_goto_level(++le_level);
964                         }
965                       else
966                         {
967                           Level new_lev;
968                           char str[1024];
969                           int d = 0;
970                           sprintf(str,"Level %d doesn't exist.",le_level+1);
971                           white_text->drawf(str,0,-18,A_HMIDDLE,A_VMIDDLE,2);
972                           white_text->drawf("Do you want to create it?",0,0,A_HMIDDLE,A_VMIDDLE,2);
973                           red_text->drawf("(Y)es/(N)o",0,20,A_HMIDDLE,A_VMIDDLE,2);
974                           flipscreen();
975                           while(d == 0)
976                             {
977                               while(SDL_PollEvent(&event))
978                                 switch(event.type)
979                                   {
980                                   case SDL_KEYDOWN:             // key pressed
981                                     switch(event.key.keysym.sym)
982                                       {
983                                       case SDLK_y:
984                                         new_lev.init_defaults();
985                                         new_lev.save(le_level_subset.name.c_str(),++le_level);
986                                         le_level_subset.levels = le_level;
987                                         le_goto_level(le_level);
988                                         d = 1;
989                                         break;
990                                       case SDLK_n:
991                                         d = 1;
992                                         break;
993                                       default:
994                                         break;
995                                       }
996                                     break;
997                                   default:
998                                     break;
999                                   }
1000                               SDL_Delay(50);
1001                             }
1002                         }
1003                     }
1004                   le_previous_level_bt->event(event);
1005                   if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1006                     {
1007                       if(le_level > 1)
1008                         le_goto_level(--le_level);
1009                     }
1010                   le_rubber_bt->event(event);
1011                   if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1012                     le_current_tile = 0;
1013                   le_select_mode_one_bt->event(event);
1014                   if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1015                     le_selection_mode = CURSOR;
1016                   le_select_mode_two_bt->event(event);
1017                   if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1018                     le_selection_mode = SQUARE;
1019
1020                   le_tilegroup_bt->event(event);
1021                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1022                     {
1023                       Menu::set_current(select_tilegroup_menu);
1024                       select_tilegroup_menu_effect.start(200);
1025                       select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1026                     }
1027
1028                   le_settings_bt->event(event);
1029                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1030                     {
1031                       update_level_settings_menu();
1032                       Menu::set_current(level_settings_menu);
1033                     }
1034                   if(!cur_tilegroup.empty())
1035                     if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1036                       {
1037                         if(pbutton->get_state() == BUTTON_CLICKED)
1038                           {
1039                             le_current_tile = pbutton->get_tag();
1040                           }
1041                       }
1042                   if((pbutton = le_tilemap_panel->event(event)) != NULL)
1043                     {
1044                       if(pbutton->get_state() == BUTTON_CLICKED)
1045                         {
1046                           active_tm = static_cast<TileMapType>(pbutton->get_tag());
1047                         }
1048                     }
1049                 }
1050               else
1051                 {
1052                   le_settings_bt->event(event);
1053                   if(le_settings_bt->get_state() == BUTTON_CLICKED)
1054                     {
1055                       Menu::set_current(0);
1056                     }
1057                   le_tilegroup_bt->event(event);
1058                   if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1059                     {
1060                       Menu::set_current(0);
1061                     }
1062                 }
1063             }
1064           
1065           if(!Menu::current())
1066             {
1067               le_move_left_bt->event(event);
1068               le_move_right_bt->event(event);
1069
1070               if(le_mouse_pressed[LEFT])
1071                 {
1072                   le_change(cursor_x, cursor_y, active_tm, le_current_tile);
1073                 }
1074             }
1075         }
1076     }
1077   if(!Menu::current())
1078     {
1079       if(le_move_left_bt->get_state() == BUTTON_PRESSED)
1080         {
1081           pos_x -= 192;
1082         }
1083       else if(le_move_left_bt->get_state() == BUTTON_HOVER)
1084         {
1085           pos_x -= 64;
1086         }
1087
1088       if(le_move_right_bt->get_state() == BUTTON_PRESSED)
1089         {
1090           pos_x += 192;
1091         }
1092       else if(le_move_right_bt->get_state() == BUTTON_HOVER)
1093         {
1094           pos_x += 64;
1095         }
1096     }
1097
1098 }
1099
1100 void le_highlight_selection()
1101 {
1102   int x1, x2, y1, y2;
1103
1104   if(selection.x1 < selection.x2)
1105     {
1106       x1 = selection.x1;
1107       x2 = selection.x2;
1108     }
1109   else
1110     {
1111       x1 = selection.x2;
1112       x2 = selection.x1;
1113     }
1114   if(selection.y1 < selection.y2)
1115     {
1116       y1 = selection.y1;
1117       y2 = selection.y2;
1118     }
1119   else
1120     {
1121       y1 = selection.y2;
1122       y2 = selection.y1;
1123     }
1124
1125   x1 /= 32;
1126   x2 /= 32;
1127   y1 /= 32;
1128   y2 /= 32;
1129
1130   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1131 }
1132
1133 void le_change(float x, float y, int tm, unsigned int c)
1134 {
1135   if(le_current_level != NULL)
1136     {
1137       int xx,yy;
1138       int x1, x2, y1, y2;
1139       unsigned int i;
1140
1141       /*  level_changed = true; */
1142
1143       switch(le_selection_mode)
1144         {
1145         case CURSOR:
1146           le_current_level->change(x,y,tm,c);
1147
1148           yy = ((int)y / 32);
1149           xx = ((int)x / 32);
1150
1151           /* if there is a bad guy over there, remove it */
1152           for(i = 0; i < le_world.bad_guys.size(); ++i)
1153             if(xx == le_world.bad_guys[i].base.x/32 && yy == le_world.bad_guys[i].base.y/32)
1154               le_world.bad_guys.erase(le_world.bad_guys.begin() + i);
1155
1156           if(c == '0')  /* if it's a bad guy */
1157             le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1158           else if(c == '1')
1159             le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1160           else if(c == '2')
1161             le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1162
1163           break;
1164         case SQUARE:
1165           if(selection.x1 < selection.x2)
1166             {
1167               x1 = selection.x1;
1168               x2 = selection.x2;
1169             }
1170           else
1171             {
1172               x1 = selection.x2;
1173               x2 = selection.x1;
1174             }
1175           if(selection.y1 < selection.y2)
1176             {
1177               y1 = selection.y1;
1178               y2 = selection.y2;
1179             }
1180           else
1181             {
1182               y1 = selection.y2;
1183               y2 = selection.y1;
1184             }
1185
1186           x1 /= 32;
1187           x2 /= 32;
1188           y1 /= 32;
1189           y2 /= 32;
1190
1191           /* if there is a bad guy over there, remove it */
1192           for(i = 0; i < le_world.bad_guys.size(); ++i)
1193             if(le_world.bad_guys[i].base.x/32 >= x1 && le_world.bad_guys[i].base.x/32 <= x2
1194                && le_world.bad_guys[i].base.y/32 >= y1 && le_world.bad_guys[i].base.y/32 <= y2)
1195               le_world.bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(&le_world.bad_guys[i]));
1196
1197           for(xx = x1; xx <= x2; xx++)
1198             for(yy = y1; yy <= y2; yy++)
1199               {
1200                 le_current_level->change(xx*32, yy*32, tm, c);
1201
1202                 if(c == '0')  // if it's a bad guy
1203                   le_world.add_bad_guy(xx*32, yy*32, BAD_BSOD);
1204                 else if(c == '1')
1205                   le_world.add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1206                 else if(c == '2')
1207                   le_world.add_bad_guy(xx*32, yy*32, BAD_MONEY);
1208               }
1209           break;
1210         default:
1211           break;
1212         }
1213     }
1214 }
1215
1216 void le_testlevel()
1217 {
1218   le_current_level->save("test", le_level);
1219   
1220   GameSession session("test",le_level, ST_GL_TEST);
1221   session.run();
1222
1223   Menu::set_current(leveleditor_menu);
1224   le_world.arrays_free();
1225   le_current_level->load_gfx();
1226   le_world.activate_bad_guys();
1227 }
1228
1229 void le_showhelp()
1230 {
1231   SDL_Event event;
1232   unsigned int i, done_;
1233   char *text[] = {
1234                    "  - This is SuperTux's built-in level editor -",
1235                    "It has been designed to be light and easy to use from the start.",
1236                    "",
1237                    "When you first load the level editor you are given a menu where you",
1238                    "can load level subsets, create a new level subset, edit the current",
1239                    "subset's settings, or simply quit the editor. You can access this menu",
1240                    "from the level editor at any time by pressing the escape key.",
1241                    "",
1242                    "To your right is your button bar. The center of this contains many",
1243                    "tiles you can use to make your level. To select a tile, click on it",
1244                    "with your left mouse button; your selection will be shown in the",
1245                    "bottom right corner of the button box. Click anywhere on your level",
1246                    "with the left mouse button to place that tile down. If you right click",
1247                    "a tile in the button bar, you can find out what its keyboard shortcut",
1248                    "is. The three buttons FGD, BGD and EMY let you pick from foreground,",
1249                    "background, and enemy tiles. The eraser lets you remove tiles.",
1250                    "The left and right arrow keys scroll back and forth through your level.",
1251                    "The button with the wrench and screwdriver, lets you change the",
1252                    "settings of your level, including how long it is or what music it will",
1253                    "play. When you are ready to give your level a test, click on the little",
1254                    "running Tux. If you like the changes you have made to your level,",
1255                    "press the red save key to keep them.",
1256                    "To change which level in your subset you are editing, press the white",
1257                    "up and down arrow keys at the top of the button box.",
1258                    "",
1259                    "Have fun making levels! If you make some good ones, send them to us on",
1260                    "the SuperTux mailing list!",
1261                    "- SuperTux team"
1262                  };
1263
1264
1265   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1266
1267   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1268     white_small_text->draw(text[i], 5, 80+(i*white_small_text->h), 1);
1269
1270   gold_text->drawf("Press Any Key to Continue", 0, 440, A_HMIDDLE, A_TOP, 1);
1271
1272   flipscreen();
1273
1274   done_ = 0;
1275
1276   while(done_ == 0)
1277     {
1278       done_ = wait_for_event(event);
1279       SDL_Delay(50);
1280     }
1281 }