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