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