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