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