ed06a5dc81513bd0c8a383036cbd5a1aea253372
[supertux.git] / src / leveleditor.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
5 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 #include <map>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <SDL.h>
29 #include <SDL_image.h>
30 #include "leveleditor.h"
31
32 #include "screen.h"
33 #include "defines.h"
34 #include "globals.h"
35 #include "setup.h"
36 #include "menu.h"
37 #include "level.h"
38 #include "gameloop.h"
39 #include "badguy.h"
40 #include "scene.h"
41 #include "button.h"
42 #include "tile.h"
43 #include "resources.h"
44 #include "music_manager.h"
45 #include "background.h"
46 #include "display_manager.h"
47
48 /* definitions to aid development */
49
50 /* definitions that affect gameplay */
51 #define KEY_CURSOR_SPEED 32
52 #define KEY_CURSOR_FASTSPEED 64
53
54 /* when pagedown/up pressed speed:*/
55 #define PAGE_CURSOR_SPEED 13*32
56
57 #define MOUSE_LEFT_MARGIN 80
58 #define MOUSE_RIGHT_MARGIN (560-32)
59
60 /* scolling speed */
61 #define KEYBOARD_SPEED 140
62 #define MOUSE_SPEED    40
63
64 /* look */
65 #define SELECT_W 2 // size of the selections lines
66 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
67
68 /* own declerations */
69 /* crutial ones (main loop) */
70 int le_init();
71 void le_quit();
72 int le_load_level_subset(char *filename);
73 void le_drawlevel();
74 void le_drawinterface();
75 void le_checkevents();
76 void le_change(float x, float y, int tm, unsigned int c);
77 void le_testlevel();
78 void le_showhelp();
79 void le_set_defaults(void);
80 void le_activate_bad_guys(void);
81 void le_goto_level(int levelnb);
82 void le_highlight_selection();
83
84 void apply_level_settings_menu();
85 void update_subset_settings_menu();
86 void save_subset_settings_menu();
87
88 struct TileOrObject
89 {
90   TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
91
92   void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
93   void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
94   //Returns true for a tile
95   bool IsTile() { return is_tile; };
96   //Returns true for a GameObject
97   bool IsObject() { return !is_tile; };
98
99
100   void Init() { tile = 0; obj = NULL; is_tile = true; };
101
102   bool is_tile; //true for tile (false for object)
103   unsigned int tile;
104   GameObject* obj;
105 };
106
107 /* leveleditor internals */
108 static string_list_type level_subsets;
109 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
110 static bool show_minimap;
111 static bool show_selections;
112 static bool le_help_shown;
113 static int pos_x, pos_y, cursor_x, cursor_y;
114 static int le_level;
115 static World* le_world;
116 static LevelSubset* le_level_subset;
117 static int le_show_grid;
118 static int le_frame;
119 static Surface* le_selection;
120 static int done;
121 static TileOrObject le_current;
122 static bool le_mouse_pressed[2];
123 static bool le_mouse_clicked[2];
124 static Button* le_save_level_bt;
125 static Button* le_exit_bt;
126 static Button* le_test_level_bt;
127 static Button* le_next_level_bt;
128 static Button* le_previous_level_bt;
129 static Button* le_move_right_bt;
130 static Button* le_move_left_bt;
131 static Button* le_move_up_bt;
132 static Button* le_move_down_bt;
133 static Button* le_rubber_bt;
134 static Button* le_select_mode_one_bt;
135 static Button* le_select_mode_two_bt;
136 static Button* le_settings_bt;
137 static Button* le_tilegroup_bt;
138 static Button* le_objects_bt;
139 static Button* le_object_select_bt;
140 static Button* le_object_properties_bt;
141 static ButtonPanel* le_tilemap_panel;
142 static Menu* leveleditor_menu;
143 static Menu* subset_load_menu;
144 static Menu* subset_new_menu;
145 static Menu* subset_settings_menu;
146 static Menu* level_settings_menu;
147 static Menu* select_tilegroup_menu;
148 static Menu* select_objects_menu;
149 static Timer select_tilegroup_menu_effect;
150 static Timer select_objects_menu_effect;
151 static Timer display_level_info;
152 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
153 static ButtonPanelMap tilegroups_map;
154 static ButtonPanelMap objects_map;
155 static std::string cur_tilegroup;
156 static std::string cur_objects;
157 static MouseCursor* mouse_select_object;
158 static MovingObject* selected_game_object;
159
160 static square selection;
161 static SelectionMode le_selection_mode;
162 static SDL_Event event;
163 TileMapType active_tm;
164
165 int leveleditor(char* filename)
166 {
167   int last_time, now_time, i;
168
169   le_level = 1;
170
171   if(le_init() != 0)
172     return 1;
173
174   /* Clear screen: */
175
176   clearscreen(0, 0, 0);
177   updatescreen();
178
179   music_manager->halt_music();
180
181   while (SDL_PollEvent(&event))
182   {}
183
184   if(filename != NULL)
185     if(le_load_level_subset(filename))
186       return 1;
187
188   while(true)
189   {
190     last_time = SDL_GetTicks();
191     le_frame++;
192
193     le_checkevents();
194
195     if(Menu::current() == select_tilegroup_menu)
196     {
197       if(select_tilegroup_menu_effect.check())
198       {
199         select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
200                                        66,-0.5,0.5);
201       }
202       else
203         select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
204     }
205     else if(Menu::current() == select_objects_menu)
206     {
207       if(select_objects_menu_effect.check())
208       {
209         select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
210       }
211       else
212         select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
213     }
214
215     if(le_world != NULL)
216     {
217       /* making events results to be in order */
218
219       /* draw the level */
220       le_drawlevel();
221     }
222     else
223       clearscreen(0, 0, 0);
224
225     /* draw editor interface */
226     le_drawinterface();
227
228     Menu* menu = Menu::current();
229     if(menu)
230     {
231       menu->draw();
232       menu->action();
233
234       if(menu == leveleditor_menu)
235       {
236         switch (leveleditor_menu->check())
237         {
238         case MNID_RETURNLEVELEDITOR:
239           if(le_world != NULL)
240             Menu::set_current(0);
241           else
242             Menu::set_current(leveleditor_menu);
243           break;
244         case MNID_SUBSETSETTINGS:
245           update_subset_settings_menu();
246           break;
247         case MNID_QUITLEVELEDITOR:
248           done = 1;
249           break;
250         }
251       }
252       else if(menu == level_settings_menu)
253       {
254         switch (level_settings_menu->check())
255         {
256         case MNID_APPLY:
257           apply_level_settings_menu();
258           Menu::set_current(NULL);
259           break;
260
261         default:
262           break;
263         }
264       }
265       else if(menu == select_tilegroup_menu)
266       {
267         int it = -1;
268         switch (it = select_tilegroup_menu->check())
269         {
270         default:
271           if(it >= 0)
272           {
273             cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
274             Menu::set_current(0);
275             cur_objects = "";
276
277           }
278           break;
279         }
280       }
281       else if(menu == select_objects_menu)
282       {
283         int it = -1;
284         switch (it = select_objects_menu->check())
285         {
286         default:
287           if(it >= 0)
288           {
289             cur_objects = select_objects_menu->get_item_by_id(it).text;
290             cur_tilegroup = "";
291
292             Menu::set_current(0);
293           }
294           break;
295         }
296       }
297       else if(menu == subset_load_menu)
298       {
299         switch (i = subset_load_menu->check())
300         {
301         case 0:
302           break;
303         default:
304           if(i >= 1)
305           {
306             if(le_load_level_subset(level_subsets.item[i-1]))
307               return 1;
308           }
309           break;
310         }
311       }
312       else if(menu == subset_new_menu)
313       {
314         if(subset_new_menu->item[2].input[0] == '\0')
315           subset_new_menu->item[3].kind = MN_DEACTIVE;
316         else
317         {
318           subset_new_menu->item[3].kind = MN_ACTION;
319
320           switch (i = subset_new_menu->check())
321           {
322           case MNID_CREATESUBSET:
323             LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
324             le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
325             leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
326             le_goto_level(1);
327             subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
328
329             Menu::set_current(subset_settings_menu);
330             break;
331           }
332         }
333       }
334       else if(menu == subset_settings_menu)
335       {
336         if(le_level_subset->title.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETTITLE).input) == 0 && le_level_subset->description.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETDESCRIPTION).input) == 0  )
337           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
338         else
339           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
340
341         switch (i = subset_settings_menu->check())
342         {
343         case MNID_SUBSETSAVECHANGES:
344           save_subset_settings_menu();
345           Menu::set_current(leveleditor_menu);
346           break;
347         }
348       }
349     }
350
351     MouseCursor::current()->draw();
352
353     if(done)
354     {
355       le_quit();
356       return 0;
357     }
358
359     ++global_frame_counter;
360
361     SDL_Delay(25);
362     now_time = SDL_GetTicks();
363     if (now_time < last_time + FPS)
364       SDL_Delay(last_time + FPS - now_time);    /* delay some time */
365
366     flipscreen();
367   }
368
369   return done;
370 }
371
372 int le_load_level_subset(char *filename)
373 {
374   le_level_subset->load(filename);
375   leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
376   le_level = 1;
377   le_goto_level(1);
378
379   //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
380
381   Menu::set_current(NULL);
382
383   return 0;
384 }
385
386 void le_init_menus()
387 {
388   int i;
389
390   leveleditor_menu = new Menu();
391   subset_load_menu = new Menu();
392   subset_new_menu  = new Menu();
393   subset_settings_menu = new Menu();
394   level_settings_menu  = new Menu();
395   select_tilegroup_menu  = new Menu();
396   select_objects_menu = new Menu();
397
398   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
399   leveleditor_menu->additem(MN_HL,"",0,0);
400   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
401   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
402   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
403   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
404   leveleditor_menu->additem(MN_HL,"",0,0);
405   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
406
407   Menu::set_current(leveleditor_menu);
408
409   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
410   subset_load_menu->additem(MN_HL, "", 0, 0);
411
412   for(i = 0; i < level_subsets.num_items; ++i)
413   {
414     subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
415   }
416   subset_load_menu->additem(MN_HL,"",0,0);
417   subset_load_menu->additem(MN_BACK,"Back",0,0);
418
419   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
420   subset_new_menu->additem(MN_HL,"",0,0);
421   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
422   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
423   subset_new_menu->additem(MN_HL,"",0,0);
424   subset_new_menu->additem(MN_BACK,"Back",0,0);
425
426   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
427   subset_settings_menu->additem(MN_HL,"",0,0);
428   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
429   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
430   subset_settings_menu->additem(MN_HL,"",0,0);
431   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
432   subset_settings_menu->additem(MN_HL,"",0,0);
433   subset_settings_menu->additem(MN_BACK,"Back",0,0);
434
435   level_settings_menu->arrange_left = true;
436   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
437   level_settings_menu->additem(MN_HL,"",0,0);
438   level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
439   level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
440   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
441   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
442   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
443   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
444   level_settings_menu->additem(MN_NUMFIELD,    "Height  ",0,0,MNID_HEIGHT);
445   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
446   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
447   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
448   level_settings_menu->additem(MN_NUMFIELD,    "Top Red     ",0,0,MNID_TopRed);
449   level_settings_menu->additem(MN_NUMFIELD,    "Top Green   ",0,0,MNID_TopGreen);
450   level_settings_menu->additem(MN_NUMFIELD,    "Top Blue    ",0,0,MNID_TopBlue);
451   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red  ",0,0,MNID_BottomRed);
452   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
453   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue ",0,0,MNID_BottomBlue);
454   level_settings_menu->additem(MN_HL,"",0,0);
455   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
456
457   select_tilegroup_menu->arrange_left = true;
458   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
459   select_tilegroup_menu->additem(MN_HL,"",0,0);
460   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
461   int tileid = 1;
462   for(std::set<TileGroup>::iterator it = tilegroups->begin();
463         it != tilegroups->end(); ++it )
464     {
465       select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
466       tileid++;
467       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
468       i = 0;
469
470       for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
471           sit != (*it).tiles.end(); ++sit, ++i)
472       {
473         std::string imagefile = "/images/tilesets/" ;
474         bool only_editor_image = false;
475         if(!TileManager::instance()->get(*sit)->filenames.empty())
476         {
477           imagefile += TileManager::instance()->get(*sit)->filenames[0];
478         }
479         else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
480         {
481           imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
482           only_editor_image = true;
483         }
484         else
485         {
486           imagefile += "notile.png";
487         }
488         Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
489                                     0, 0, 32, 32);
490         if(!only_editor_image)
491           if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
492           {
493             imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
494             button->add_icon(imagefile,32,32);
495           }
496         tilegroups_map[it->name]->additem(button, *sit);
497       }
498     }
499   select_tilegroup_menu->additem(MN_HL,"",0,0);
500
501   select_objects_menu->arrange_left = true;
502   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
503   select_objects_menu->additem(MN_HL,"",0,0);
504   // TODO fix this
505 #if 0
506   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
507   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
508
509   DisplayManager dummy;
510   for(int i = 0; i < NUM_BadGuyKinds; ++i)
511   {
512     BadGuy bad_tmp(dummy, 0,0,BadGuyKind(i),false);
513     objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
514     objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
515         BadGuy(dummy,
516           objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
517           objects_map["BadGuys"]->manipulate_button(i)->get_pos().y,
518           BadGuyKind(i), false));
519   }
520 #endif
521
522   select_objects_menu->additem(MN_HL,"",0,0);
523
524 }
525
526 int le_init()
527 {
528   level_subsets = dsubdirs("/levels", "level1.stl");
529   le_level_subset = new LevelSubset;
530
531   le_world = NULL;
532   selected_game_object = NULL;
533
534   active_tm = TM_IA;
535   le_show_grid = true;
536   show_selections = true;
537
538   done = 0;
539   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
540   le_level_changed = false;
541   le_help_shown = false;
542
543   le_mouse_pressed[LEFT] = false;
544   le_mouse_pressed[RIGHT] = false;
545
546   le_mouse_clicked[LEFT] = false;
547   le_mouse_clicked[RIGHT] = false;
548
549   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
550
551   select_tilegroup_menu_effect.init(false);
552   select_objects_menu_effect.init(false);
553   display_level_info.init(false);
554
555   /* Load buttons */
556   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
557   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
558   le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
559   le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
560   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
561   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
562   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
563   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
564   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
565   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
566   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
567   le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
568   le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
569   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
570   le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
571   le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
572   le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
573   le_object_properties_bt->set_active(false);
574
575   mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
576   mouse_select_object->set_mid(16,16);
577
578   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
579   le_tilemap_panel->set_button_size(32,10);
580   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
581   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0),TM_IA);
582   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
583   le_tilemap_panel->highlight_last(true);
584   le_tilemap_panel->set_last_clicked(TM_IA);
585
586   le_current.Init();
587
588   le_init_menus();
589
590   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
591
592
593   return 0;
594 }
595
596 void update_level_settings_menu()
597 {
598   char str[80];
599   int i;
600
601   level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_world->get_level()->name.c_str());
602   level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_world->get_level()->author.c_str());
603
604   string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
605   string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
606   string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
607   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
608   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
609   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
610
611   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_world->get_level()->song_title.c_str())) != -1)
612     level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
613   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_world->get_level()->bkgd_image.c_str())) != -1)
614     level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
615   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_world->get_level()->particle_system.c_str())) != -1)
616     level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;
617
618   sprintf(str,"%d",le_world->get_level()->width);
619   level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
620   sprintf(str,"%d",le_world->get_level()->height);
621   level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
622   sprintf(str,"%d",le_world->get_level()->time_left);
623   level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
624   sprintf(str,"%2.0f",le_world->get_level()->gravity);
625   level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
626   sprintf(str,"%d",le_world->get_level()->bkgd_speed);
627   level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
628   sprintf(str,"%d",le_world->get_level()->bkgd_top.red);
629   level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
630   sprintf(str,"%d",le_world->get_level()->bkgd_top.green);
631   level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
632   sprintf(str,"%d",le_world->get_level()->bkgd_top.blue);
633   level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
634   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.red);
635   level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
636   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.green);
637   level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
638   sprintf(str,"%d",le_world->get_level()->bkgd_bottom.blue);
639   level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
640 }
641
642 void update_subset_settings_menu()
643 {
644   subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
645   subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
646 }
647
648 void apply_level_settings_menu()
649 {
650   int i;
651   i = false;
652   le_level_changed = true;
653
654   le_world->get_level()->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
655   le_world->get_level()->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
656
657   if(le_world->get_level()->bkgd_image.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
658   {
659     le_world->get_level()->bkgd_image = string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list);
660     i = true;
661   }
662
663   if(le_world->get_level()->particle_system.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
664   {
665     le_world->get_level()->particle_system = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
666   }
667
668   if(i)
669   {
670     le_world->get_level()->load_gfx();
671   }
672
673   le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
674
675   le_world->get_level()->resize(
676       atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input),
677       atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
678   le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
679   le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
680   le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input);
681   le_world->get_level()->bkgd_top.red = atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input);
682   le_world->get_level()->bkgd_top.green = atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input);
683   le_world->get_level()->bkgd_top.blue = atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input);
684   le_world->get_level()->bkgd_bottom.red = atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input);
685   le_world->get_level()->bkgd_bottom.green = atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input);
686   le_world->get_level()->bkgd_bottom.blue = atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input);
687 }
688
689 void save_subset_settings_menu()
690 {
691   le_level_subset->title = subset_settings_menu->item[2].input;
692   le_level_subset->description = subset_settings_menu->item[3].input;
693   le_level_subset->save();
694   le_level_changed = false;
695 }
696
697 void le_unload_level()
698 {
699   if(le_level_changed)
700   {
701     le_drawlevel();
702     le_drawinterface();
703     char str[1024];
704     sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str());
705     if(confirm_dialog(str))
706     {
707       le_world->get_level()->save(le_level_subset->name.c_str(), le_level,
708           le_world);
709     }
710   }
711
712   delete le_world;
713   le_level_changed = false;
714 }
715
716 void le_goto_level(int levelnb)
717 {
718   le_unload_level();
719   le_world = new World(le_level_subset->name, levelnb);
720   display_level_info.start(2500);
721   le_level = levelnb;
722 }
723
724 void le_quit(void)
725 {
726   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
727
728   le_unload_level();
729   delete le_selection;
730   delete leveleditor_menu;
731   delete subset_load_menu;
732   delete subset_new_menu;
733   delete subset_settings_menu;
734   delete level_settings_menu;
735   delete select_tilegroup_menu;
736   delete select_objects_menu;
737   delete le_save_level_bt;
738   delete le_exit_bt;
739   delete le_test_level_bt;
740   delete le_next_level_bt;
741   delete le_previous_level_bt;
742   delete le_move_right_bt;
743   delete le_move_left_bt;
744   delete le_move_up_bt;
745   delete le_move_down_bt;
746   delete le_rubber_bt;
747   delete le_select_mode_one_bt;
748   delete le_select_mode_two_bt;
749   delete le_settings_bt;
750   delete le_tilegroup_bt;
751   delete le_objects_bt;
752   delete le_tilemap_panel;
753   delete le_object_select_bt;
754   delete le_object_properties_bt;
755   delete mouse_select_object;
756
757   delete le_level_subset;
758   le_level_subset = 0;
759
760   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
761       i != tilegroups_map.end(); ++i)
762   {
763     delete i->second;
764   }
765   for(ButtonPanelMap::iterator i = objects_map.begin();
766       i != objects_map.end(); ++i)
767   {
768     delete i->second;
769   }
770 }
771
772 void le_drawminimap()
773 {
774   if(le_world == NULL)
775     return;
776
777   int mini_tile_width;
778   if(screen->w - 64 > le_world->get_level()->width * 4)
779     mini_tile_width = 4;
780   else if(screen->w - 64 > le_world->get_level()->width * 2)
781     mini_tile_width = 2;
782   else
783     mini_tile_width = 1;
784   int left_offset = (screen->w - 64 - le_world->get_level()->width*mini_tile_width) / 2;
785
786   int mini_tile_height;
787   if(screen->h - 64 > le_world->get_level()->height * 4)
788     mini_tile_height = 4;
789   else if(screen->h - 64 > le_world->get_level()->height * 2)
790     mini_tile_height = 2;
791   else
792     mini_tile_height = 1;
793
794   Level* level = le_world->get_level();
795   for (int y = 0; y < le_world->get_level()->height; ++y)
796     for (int x = 0; x < le_world->get_level()->width; ++x)
797     {
798
799       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
800           mini_tile_width , 4, level->bg_tiles[y * level->width + x]);
801
802       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
803           mini_tile_width , 4, level->ia_tiles[y * level->width + x]);
804
805       Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4,
806           mini_tile_width , 4, level->fg_tiles[y + level->width + x]);
807
808     }
809
810   fillrect(left_offset, 0, le_world->get_level()->width*mini_tile_width, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 128);
811
812   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 19*mini_tile_width, 2, 200, 200, 200, 200);
813   fillrect(left_offset + (pos_x/32)*mini_tile_width, 0, 2, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 200);
814   fillrect(left_offset + (pos_x/32)*mini_tile_width + 19*mini_tile_width - 2, 0, 2, le_world->get_level()->height*mini_tile_height, 200, 200, 200, 200);
815   fillrect(left_offset + (pos_x/32)*mini_tile_width, le_world->get_level()->height*mini_tile_height-2, 19*mini_tile_width, 2, 200, 200, 200, 200);
816
817 }
818
819 void le_drawinterface()
820 {
821   int x,y;
822   char str[80];
823
824   if(le_world != NULL)
825   {
826     /* draw a grid (if selected) */
827     if(le_show_grid)
828     {
829       for(x = 0; x < VISIBLE_TILES_X; x++)
830         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
831       for(y = 0; y < VISIBLE_TILES_Y; y++)
832         fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
833     }
834   }
835
836   if(show_minimap) // use_gl because the minimap isn't shown correctly in software mode. Any idea? FIXME Possible reasons: SDL_SoftStretch is a hack itsself || an alpha blitting issue SDL can't handle in software mode
837     le_drawminimap();
838
839   if(show_selections && MouseCursor::current() != mouse_select_object)
840   {
841     if(le_selection_mode == CURSOR)
842     {
843       if(le_current.IsTile())
844         le_selection->draw(cursor_x - pos_x, cursor_y - pos_y);
845     }
846     else if(le_selection_mode == SQUARE)
847     {
848       int w, h;
849       le_highlight_selection();
850       /* draw current selection */
851       w = selection.x2 - selection.x1;
852       h = selection.y2 - selection.y1;
853       fillrect(selection.x1 - pos_x, selection.y1 - pos_y, w, SELECT_W, SELECT_CLR);
854       fillrect(selection.x1 - pos_x + w, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
855       fillrect(selection.x1 - pos_x, selection.y1 - pos_y + h, w, SELECT_W, SELECT_CLR);
856       fillrect(selection.x1 - pos_x, selection.y1 - pos_y, SELECT_W, h, SELECT_CLR);
857     }
858   }
859
860
861   /* draw button bar */
862   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
863
864   if(le_current.IsTile())
865   {
866     Tile::draw(screen->w - 32, screen->h - 32, le_current.tile);
867     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
868       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);
869   }
870 #if 0 // XXX FIXME TODO
871   if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
872   {
873     le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
874     le_current.obj->draw_on_screen(cursor_x,cursor_y);
875   }
876 #endif
877
878   if(mouse_select_object && selected_game_object != NULL)
879   {
880     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,selected_game_object->base.width,3,255,0,0,255);
881     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
882     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y+selected_game_object->base.height,selected_game_object->base.width,3,255,0,0,255);
883     fillrect(selected_game_object->base.x-pos_x+selected_game_object->base.width,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
884   }
885
886   if(le_world != NULL)
887   {
888     le_save_level_bt->draw();
889     le_exit_bt->draw();
890     le_test_level_bt->draw();
891     le_next_level_bt->draw();
892     le_previous_level_bt->draw();
893     le_rubber_bt->draw();
894     if(le_selection_mode == SQUARE)
895       le_select_mode_one_bt->draw();
896     else if(le_selection_mode == CURSOR)
897       le_select_mode_two_bt->draw();
898     le_settings_bt->draw();
899     le_move_right_bt->draw();
900     le_move_left_bt->draw();
901     le_move_up_bt->draw();
902     le_move_down_bt->draw();
903     le_tilegroup_bt->draw();
904     le_objects_bt->draw();
905     if(!cur_tilegroup.empty())
906       tilegroups_map[cur_tilegroup]->draw();
907     else if(!cur_objects.empty())
908     {
909       objects_map[cur_objects]->draw();
910     }
911
912     le_tilemap_panel->draw();
913
914     if(!cur_objects.empty())
915     {
916       le_object_select_bt->draw();
917       le_object_properties_bt->draw();
918     }
919
920     sprintf(str, "%d/%d", le_level,le_level_subset->levels);
921     white_text->drawf(str, (le_level_subset->levels < 10) ? -10 : 0, 16, A_RIGHT, A_TOP, 0);
922
923     if(!le_help_shown)
924       white_small_text->draw("F1 for Help", 10, 430, 1);
925
926     if(display_level_info.check())
927       white_text->drawf(le_world->get_level()->name.c_str(), 0, 0, A_HMIDDLE, A_TOP, 0);
928   }
929   else
930   {
931     if(!Menu::current())
932       white_small_text->draw("No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1);
933     else
934       white_small_text->draw("No Level Subset loaded", 10, 430, 1);
935   }
936
937 }
938
939 void le_drawlevel()
940 {
941   unsigned int y,x;
942   Uint8 a;
943
944   /* Draw the real background */
945   le_world->background->draw(le_world->displaymanager.get_viewport(),
946       LAYER_BACKGROUND0);
947
948   if(le_current.IsTile())
949   {
950     Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
951     if(!TileManager::instance()->get(le_current.tile)->images.empty())
952       fillrect(cursor_x-pos_x,cursor_y-pos_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);
953   }
954 #if 0 // XXX FIXME TODO
955   if(le_current.IsObject())
956   {
957     le_current.obj->move_to(cursor_x, cursor_y);
958   }
959 #endif
960
961   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
962
963   Level* level = le_world->get_level();
964   for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_world->get_level()->height; ++y)
965     for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
966     {
967
968       if(active_tm == TM_BG)
969         a = 255;
970       else
971         a = 128;
972
973       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
974           level->bg_tiles[ (y + (int)(pos_y / 32)) * level->width + 
975           (x + (int)(pos_x / 32))],a);
976
977       if(active_tm == TM_IA)
978         a = 255;
979       else
980         a = 128;
981
982       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
983           level->ia_tiles[ (y + (int)(pos_y / 32)) * level->width +       
984           (x + (int)(pos_x / 32))],a);
985
986       
987       if(active_tm == TM_FG)
988         a = 255;
989       else
990         a = 128;
991
992       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
993           level->fg_tiles[ (y + (int)(pos_y / 32)) * level->width +       
994           (x + (int)(pos_x / 32))],a);
995
996       /* draw whats inside stuff when cursor is selecting those */
997       /* (draw them all the time - is this the right behaviour?) */
998       Tile* edit_image = TileManager::instance()->get(
999           level->ia_tiles
1000           [ (y + (int)(pos_y / 32)) * level->width + (x + (int)(pos_x / 32))]);
1001       if(edit_image && !edit_image->editor_images.empty())
1002         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
1003
1004     }
1005
1006   /* Draw the Bad guys: */
1007   for (std::vector<GameObject*>::iterator it = le_world->gameobjects.begin();
1008        it != le_world->gameobjects.end(); ++it)
1009   {
1010     BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
1011     if(badguy == 0)
1012       continue;
1013     
1014     /* to support frames: img_bsod_left[(frame / 5) % 4] */
1015     ViewPort viewport;
1016     viewport.set_translation(Vector(pos_x, pos_y));
1017     badguy->draw(viewport, 0);
1018   }
1019
1020   /* Draw the player: */
1021   /* for now, the position is fixed at (100, 240) */
1022   largetux.walk_right->draw( 100 - pos_x, 240 - pos_y);
1023 }
1024
1025 void le_change_object_properties(GameObject *pobj)
1026 {
1027   Surface* cap_screen = Surface::CaptureScreen();
1028   Menu* object_properties_menu = new Menu();
1029   bool loop = true;
1030
1031   object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0);
1032   object_properties_menu->additem(MN_HL,"",0,0);
1033
1034   BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1035   if(pobj != 0)
1036   {
1037     object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
1038     for(int i = 0; i < NUM_BadGuyKinds; ++i)
1039     {
1040       string_list_add_item(object_properties_menu->get_item_by_id(1).list,
1041           badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
1042       if(pbad->kind == i)
1043         object_properties_menu->get_item_by_id(1).list->active_item = i;
1044     }
1045     object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
1046   }
1047
1048   object_properties_menu->additem(MN_HL,"",0,0);
1049   object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
1050
1051   Menu::set_current(object_properties_menu);
1052
1053   while(loop)
1054   {
1055     SDL_Event event;
1056
1057     while (SDL_PollEvent(&event))
1058     {
1059       object_properties_menu->event(event);
1060     }
1061
1062     cap_screen->draw(0,0);
1063
1064     object_properties_menu->draw();
1065     object_properties_menu->action();
1066
1067     switch (object_properties_menu->check())
1068     {
1069     case 3:
1070       {
1071       BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1072       if(pbad != 0) {
1073         BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1074         pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
1075         pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
1076       }
1077       loop = false;
1078       break;
1079       }
1080     default:
1081       break;
1082     }
1083
1084     if(Menu::current() == NULL)
1085       loop = false;
1086
1087     mouse_cursor->draw();
1088     flipscreen();
1089     SDL_Delay(25);
1090   }
1091
1092   delete cap_screen;
1093   Menu::set_current(0);
1094   delete object_properties_menu;
1095 }
1096
1097
1098 void le_checkevents()
1099 {
1100   SDLKey key;
1101   SDLMod keymod;
1102   Button* pbutton;
1103   int x,y;
1104
1105   keymod = SDL_GetModState();
1106
1107   while(SDL_PollEvent(&event))
1108   {
1109     if (Menu::current())
1110     {
1111       Menu::current()->event(event);
1112       if(!le_world && !Menu::current())
1113         Menu::set_current(leveleditor_menu);
1114     }
1115     else
1116     {
1117       mouse_cursor->set_state(MC_NORMAL);
1118
1119       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1120       if(event.type == SDL_KEYDOWN
1121           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1122               && (event.motion.x > 0
1123                   && event.motion.x < screen->w - 64 &&
1124                   event.motion.y > 0 && event.motion.y < screen->h)))
1125       {
1126         switch(event.type)
1127         {
1128         case SDL_KEYDOWN:       // key pressed
1129           key = event.key.keysym.sym;
1130           switch(key)
1131           {
1132           case SDLK_ESCAPE:
1133             Menu::set_current(leveleditor_menu);
1134             break;
1135           case SDLK_F1:
1136             if(le_world != NULL)
1137               le_showhelp();
1138             break;
1139           case SDLK_HOME:
1140             cursor_x = 0;
1141             pos_x = cursor_x;
1142             break;
1143           case SDLK_END:
1144             cursor_x = (le_world->get_level()->width * 32) - 32;
1145             pos_x = cursor_x;
1146             break;
1147           case SDLK_F9:
1148             le_show_grid = !le_show_grid;
1149             break;
1150           default:
1151             break;
1152           }
1153           break;
1154         case SDL_MOUSEBUTTONDOWN:
1155           if(event.button.button == SDL_BUTTON_LEFT)
1156           {
1157             le_mouse_pressed[LEFT] = true;
1158
1159             selection.x1 = event.motion.x + pos_x;
1160             selection.y1 = event.motion.y + pos_y;
1161             selection.x2 = event.motion.x + pos_x;
1162             selection.y2 = event.motion.y + pos_y;
1163           }
1164           else if(event.button.button == SDL_BUTTON_RIGHT)
1165           {
1166             le_mouse_pressed[RIGHT] = true;
1167           }
1168           break;
1169         case SDL_MOUSEBUTTONUP:
1170           if(event.button.button == SDL_BUTTON_LEFT)
1171           {
1172             le_mouse_pressed[LEFT] = false;
1173             le_mouse_clicked[LEFT] = true;
1174           }
1175           else if(event.button.button == SDL_BUTTON_RIGHT)
1176           {
1177             le_mouse_pressed[RIGHT] = false;
1178             le_mouse_clicked[RIGHT] = true;
1179           }
1180           break;
1181         case SDL_MOUSEMOTION:
1182
1183           if(!Menu::current())
1184           {
1185             x = event.motion.x;
1186             y = event.motion.y;
1187
1188             if(le_current.IsTile())
1189             {
1190               cursor_x = ((int)(pos_x + x) / 32) * 32;
1191               cursor_y = ((int)(pos_y + y) / 32) * 32;
1192             }
1193             else
1194             {
1195               cursor_x = x;
1196               cursor_y = y;
1197             }
1198
1199             if(le_mouse_pressed[LEFT])
1200             {
1201               selection.x2 = x + pos_x;
1202               selection.y2 = y + pos_y;
1203             }
1204
1205             if(le_mouse_pressed[RIGHT])
1206             {
1207               pos_x += -1 * event.motion.xrel;
1208               pos_y += -1 * event.motion.yrel;
1209             }
1210           }
1211           break;
1212         default:
1213           break;
1214         }
1215       }
1216       else if(event.type == SDL_QUIT) /* window closing */
1217       {
1218       done = 1;
1219       }
1220     }
1221
1222     if(le_world != NULL)
1223     {
1224       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 &&
1225           event.motion.y > 0 && event.motion.y < screen->h)))
1226       {
1227         le_mouse_pressed[LEFT] = false;
1228         le_mouse_pressed[RIGHT] = false;
1229
1230         if(!Menu::current())
1231         {
1232           /* Check for button events */
1233           le_test_level_bt->event(event);
1234           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1235             le_testlevel();
1236           le_save_level_bt->event(event);
1237           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1238             le_world->get_level()->save(le_level_subset->name.c_str(),le_level,
1239                 le_world);
1240           le_exit_bt->event(event);
1241           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1242           {
1243             Menu::set_current(leveleditor_menu);
1244           }
1245           le_next_level_bt->event(event);
1246           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1247           {
1248             if(le_level < le_level_subset->levels)
1249             {
1250               le_goto_level(le_level+1);
1251             }
1252             else
1253             {
1254               Level new_lev;
1255               char str[1024];
1256               sprintf(str,"Level %d doesn't exist. Create it?",le_level+1);
1257               if(confirm_dialog(str))
1258               {
1259                 new_lev.init_defaults();
1260                 new_lev.save(le_level_subset->name.c_str(),le_level+1, le_world);
1261                 le_level_subset->levels = le_level;
1262                 le_goto_level(le_level);
1263               }
1264             }
1265           }
1266           le_previous_level_bt->event(event);
1267           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1268           {
1269             if(le_level > 1)
1270               le_goto_level(le_level -1);
1271           }
1272           le_rubber_bt->event(event);
1273           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1274             le_current.Tile(0);
1275
1276           if(!cur_objects.empty())
1277           {
1278             le_object_select_bt->event(event);
1279             if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1280             {
1281               MouseCursor::set_current(mouse_select_object);
1282             }
1283
1284             le_object_properties_bt->event(event);
1285             if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1286             {
1287               le_change_object_properties(selected_game_object);
1288             }
1289           }
1290
1291
1292           if(le_selection_mode == SQUARE)
1293           {
1294             le_select_mode_one_bt->event(event);
1295             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1296               le_selection_mode = CURSOR;
1297           }
1298           else
1299           {
1300             le_select_mode_two_bt->event(event);
1301             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1302               le_selection_mode = SQUARE;
1303           }
1304           ButtonPanelMap::iterator it;
1305           le_tilegroup_bt->event(event);
1306           switch (le_tilegroup_bt->get_state())
1307           {
1308           case BUTTON_CLICKED:
1309             Menu::set_current(select_tilegroup_menu);
1310             select_tilegroup_menu_effect.start(200);
1311             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1312             break;
1313           case BUTTON_WHEELUP:
1314             if(cur_tilegroup.empty())
1315             {
1316               cur_tilegroup = tilegroups_map.begin()->first;
1317             }
1318             else
1319             {
1320               it = tilegroups_map.find(cur_tilegroup);
1321               if((++it) == tilegroups_map.end())
1322               {
1323                 cur_tilegroup = tilegroups_map.begin()->first;
1324               }
1325               else
1326               {
1327                 cur_tilegroup = (*it).first;
1328               }
1329             }
1330
1331             cur_objects = "";
1332             break;
1333           case BUTTON_WHEELDOWN:
1334             it = tilegroups_map.find(cur_tilegroup);
1335             if(it == tilegroups_map.begin())
1336             {
1337               cur_tilegroup = tilegroups_map.rbegin()->first;
1338               cur_objects = "";
1339               break;
1340             }
1341             if(--it != --tilegroups_map.begin())
1342               cur_tilegroup = (*it).first;
1343             else
1344               cur_tilegroup = tilegroups_map.rbegin()->first;
1345
1346             cur_objects = "";
1347             break;
1348           default:
1349             break;
1350           }
1351
1352           le_objects_bt->event(event);
1353           switch (le_objects_bt->get_state())
1354           {
1355           case BUTTON_CLICKED:
1356             Menu::set_current(select_objects_menu);
1357             select_objects_menu_effect.start(200);
1358             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1359             break;
1360           case BUTTON_WHEELUP:
1361             it = objects_map.find(cur_objects);
1362             if(it == objects_map.end())
1363             {
1364               cur_objects = objects_map.begin()->first;
1365               cur_tilegroup = "";
1366               break;
1367             }
1368             if(++it != objects_map.end())
1369               cur_objects = (*it).first;
1370             else
1371               cur_objects = objects_map.begin()->first;
1372
1373             cur_tilegroup = "";
1374             break;
1375           case BUTTON_WHEELDOWN:
1376             it = objects_map.find(cur_objects);
1377             if(it == objects_map.begin())
1378             {
1379               cur_objects = objects_map.rbegin()->first;
1380               cur_tilegroup = "";
1381               break;
1382             }
1383             if(--it != --objects_map.begin())
1384               cur_objects = (*it).first;
1385             else
1386               cur_objects = objects_map.rbegin()->first;
1387
1388             cur_tilegroup = "";
1389             break;
1390             break;
1391           default:
1392             break;
1393           }
1394
1395           le_settings_bt->event(event);
1396           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1397           {
1398             update_level_settings_menu();
1399             Menu::set_current(level_settings_menu);
1400           }
1401           if(!cur_tilegroup.empty())
1402           {
1403             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1404             {
1405               if(pbutton->get_state() == BUTTON_CLICKED)
1406               {
1407                 le_current.Tile(pbutton->get_tag());
1408               }
1409             }
1410           }
1411           else if(!cur_objects.empty())
1412           {
1413             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1414             {
1415               if(pbutton->get_state() == BUTTON_CLICKED)
1416               {
1417 #if 0   // TODO fixme!!
1418                 le_current.Object(pbutton->get_drawable());
1419 #endif
1420               }
1421             }
1422           }
1423
1424           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1425           {
1426             if(pbutton->get_state() == BUTTON_CLICKED)
1427             {
1428               active_tm = static_cast<TileMapType>(pbutton->get_tag());
1429             }
1430           }
1431         }
1432         else
1433         {
1434           le_settings_bt->event(event);
1435           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1436           {
1437             Menu::set_current(0);
1438           }
1439           le_tilegroup_bt->event(event);
1440           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1441           {
1442             Menu::set_current(0);
1443           }
1444           le_objects_bt->event(event);
1445           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1446           {
1447             Menu::set_current(0);
1448           }
1449         }
1450       }
1451
1452       if(!Menu::current() && !show_minimap)
1453       {
1454         if(le_mouse_pressed[LEFT])
1455         {
1456           if(MouseCursor::current() != mouse_select_object)
1457           {
1458             if(le_current.IsTile())
1459               le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1460           }
1461         }
1462         else if(le_mouse_clicked[LEFT])
1463         {
1464           if(MouseCursor::current() == mouse_select_object)
1465           {
1466             bool object_got_hit = false;
1467             base_type cursor_base;
1468             if(le_current.IsTile())
1469             {
1470             cursor_base.x = cursor_x;
1471             cursor_base.y = cursor_y;
1472             }
1473             else if(le_current.IsObject())
1474             {
1475             cursor_base.x = cursor_x + pos_x;
1476             cursor_base.y = cursor_y + pos_y;       
1477             }
1478             cursor_base.width = 32;
1479             cursor_base.height = 32;
1480
1481             for(std::vector<GameObject*>::iterator it =
1482                 le_world->gameobjects.begin();
1483                 it != le_world->gameobjects.end(); ++it) {
1484               MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
1485               if(!mobj)
1486                 continue;
1487
1488               if(rectcollision(cursor_base, mobj->base))
1489               {
1490                 selected_game_object = mobj;
1491                 object_got_hit = true;
1492                 break;
1493               }
1494             }
1495
1496             if(!object_got_hit)
1497             {
1498               selected_game_object = NULL;
1499               le_object_properties_bt->set_active(false);
1500             }
1501             else
1502               le_object_properties_bt->set_active(true);
1503
1504             MouseCursor::set_current(mouse_cursor);
1505
1506           }
1507           else
1508           {
1509 #if 0 // FIXME TODO
1510             if(le_current.IsObject())
1511             {
1512               le_level_changed  = true;
1513               std::string type = le_current.obj->type();
1514               if(type == "BadGuy")
1515               {
1516                 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1517
1518                 le_world->bad_guys.push_back(new BadGuy(cursor_x+scroll_x, cursor_y,pbadguy->kind,false));
1519                 le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back());
1520               }
1521             }
1522 #endif
1523           }
1524           
1525           le_mouse_clicked[LEFT] = false;
1526
1527         }
1528       }
1529     }
1530   }
1531   if(!Menu::current())
1532   {
1533     show_minimap = false;
1534
1535     le_move_left_bt->event(event);
1536     le_move_right_bt->event(event);
1537     le_move_up_bt->event(event);
1538     le_move_down_bt->event(event);
1539     switch(le_move_left_bt->get_state())
1540     {
1541     case BUTTON_PRESSED:
1542       pos_x -= KEYBOARD_SPEED;
1543       show_minimap = true;
1544       break;
1545     case BUTTON_HOVER:
1546       pos_x -= MOUSE_SPEED;
1547       show_minimap = true;
1548       break;
1549     case BUTTON_CLICKED:
1550       show_minimap = true;
1551       break;
1552     default:
1553       break;
1554     }
1555
1556     switch(le_move_right_bt->get_state())
1557     {
1558     case BUTTON_PRESSED:
1559       pos_x += KEYBOARD_SPEED;
1560       show_minimap = true;
1561       break;
1562     case BUTTON_HOVER:
1563       pos_x += MOUSE_SPEED;
1564       show_minimap = true;
1565       break;
1566     case BUTTON_CLICKED:
1567       show_minimap = true;
1568       break;
1569     default:
1570       break;
1571     }
1572
1573     switch(le_move_up_bt->get_state())
1574     {
1575     case BUTTON_PRESSED:
1576       pos_y -= KEYBOARD_SPEED;
1577       show_minimap = true;
1578       break;
1579     case BUTTON_HOVER:
1580       pos_y -= MOUSE_SPEED;
1581       show_minimap = true;
1582       break;
1583     case BUTTON_CLICKED:
1584       show_minimap = true;
1585       break;
1586     default:
1587       break;
1588     }
1589
1590     switch(le_move_down_bt->get_state())
1591     {
1592     case BUTTON_PRESSED:
1593       pos_y += KEYBOARD_SPEED;
1594       show_minimap = true;
1595       break;
1596     case BUTTON_HOVER:
1597       pos_y += MOUSE_SPEED;
1598       show_minimap = true;
1599       break;
1600     case BUTTON_CLICKED:
1601       show_minimap = true;
1602       break;
1603     default:
1604       break;
1605     }
1606
1607       /* checking if pos_x and pos_y is within the limits... */
1608       if(pos_x > (le_world->get_level()->width * 32 + 32*2) - screen->w)
1609         pos_x = (le_world->get_level()->width * 32 + 32*2) - screen->w;
1610       if(pos_x < 0)
1611         pos_x = 0;
1612
1613       if(pos_y > (le_world->get_level()->height * 32) - screen->h)
1614         pos_y = (le_world->get_level()->height * 32) - screen->h;
1615       if(pos_y < 0)
1616         pos_y = 0;
1617
1618   }
1619
1620 }
1621
1622 void le_highlight_selection()
1623 {
1624   int x1, x2, y1, y2;
1625
1626   if(selection.x1 < selection.x2)
1627   {
1628     x1 = selection.x1;
1629     x2 = selection.x2;
1630   }
1631   else
1632   {
1633     x1 = selection.x2;
1634     x2 = selection.x1;
1635   }
1636   if(selection.y1 < selection.y2)
1637   {
1638     y1 = selection.y1;
1639     y2 = selection.y2;
1640   }
1641   else
1642   {
1643     y1 = selection.y2;
1644     y2 = selection.y1;
1645   }
1646
1647   x1 /= 32;
1648   x2 /= 32;
1649   y1 /= 32;
1650   y2 /= 32;
1651
1652   fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1653 }
1654
1655 void le_change(float x, float y, int tm, unsigned int c)
1656 {
1657   if(le_world != NULL)
1658   {
1659     int xx,yy;
1660     int x1, x2, y1, y2;
1661
1662     le_level_changed = true;
1663
1664     switch(le_selection_mode)
1665     {
1666     case CURSOR:
1667       le_world->get_level()->change(x,y,tm,c);
1668
1669       base_type cursor_base;
1670       cursor_base.x = x;
1671       cursor_base.y = y;
1672       cursor_base.width = 32;
1673       cursor_base.height = 32;
1674
1675       /* if there is a bad guy over there, remove it */
1676       // XXX TODO
1677 #if 0
1678       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i)
1679         if(rectcollision(cursor_base,(*it)->base))
1680         {
1681           delete (*it);
1682           le_world->bad_guys.erase(it);
1683           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1684           break;
1685         }
1686 #endif
1687
1688       break;
1689     case SQUARE:
1690       if(selection.x1 < selection.x2)
1691       {
1692         x1 = selection.x1;
1693         x2 = selection.x2;
1694       }
1695       else
1696       {
1697         x1 = selection.x2;
1698         x2 = selection.x1;
1699       }
1700       if(selection.y1 < selection.y2)
1701       {
1702         y1 = selection.y1;
1703         y2 = selection.y2;
1704       }
1705       else
1706       {
1707         y1 = selection.y2;
1708         y2 = selection.y1;
1709       }
1710
1711       x1 /= 32;
1712       x2 /= 32;
1713       y1 /= 32;
1714       y2 /= 32;
1715
1716       /* if there is a bad guy over there, remove it */
1717       // TODO FIXME
1718 #if 0
1719       for(std::list<BadGuy*>::iterator it = le_world->bad_guys.begin();
1720           it != le_world->bad_guys.end(); /* will be at end of loop */)
1721       {
1722         if((*it)->base.x/32 >= x1 && (*it)->base.x/32 <= x2
1723             && (*it)->base.y/32 >= y1 && (*it)->base.y/32 <= y2)
1724         {
1725           delete (*it);
1726           it = le_world->bad_guys.erase(it);
1727           le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i);
1728           continue;
1729         }
1730         else
1731         {
1732           ++i;
1733           ++it;
1734         }
1735       }
1736 #endif
1737
1738       for(xx = x1; xx <= x2; xx++)
1739         for(yy = y1; yy <= y2; yy++)
1740         {
1741           le_world->get_level()->change(xx*32, yy*32, tm, c);
1742
1743         }
1744       break;
1745     default:
1746       break;
1747     }
1748   }
1749 }
1750
1751 void le_testlevel()
1752 {
1753   //Make sure a time value is set when testing the level
1754   if(le_world->get_level()->time_left == 0)
1755     le_world->get_level()->time_left = 250;
1756
1757   le_world->get_level()->save("test", le_level, le_world);
1758
1759   GameSession session("test",le_level, ST_GL_TEST);
1760   session.run();
1761   player_status.reset();
1762
1763   music_manager->halt_music();
1764
1765   Menu::set_current(NULL);
1766   World::set_current(le_world);
1767 }
1768
1769 void le_showhelp()
1770 {
1771   bool tmp_show_grid = le_show_grid;
1772   SelectionMode temp_le_selection_mode = le_selection_mode;
1773   le_selection_mode = NONE;
1774   show_selections = true;
1775   le_show_grid = false;
1776   le_help_shown = true;
1777
1778   drawgradient(Color(0,0,0), Color(255,255,255));
1779   le_drawinterface();
1780
1781   SDL_Event event;
1782   unsigned int i, done_;
1783   char *text[] = {
1784
1785                    " - Supertux level editor tutorial - ",
1786                    "",
1787                    "To make your map, click the       ",
1788                    "tilegroup button and choose a     ",
1789                    "tilegroup.",
1790                    "Pick a tile and simply hold down  ",
1791                    "the left mouse button over the map",
1792                    "to \"paint\" your selection over",
1793                    "the screen.",
1794                    "",
1795                    "There are three layers for painting",
1796                    "tiles upon, Background layer,",
1797                    "the Interactive layer, and the",
1798                    "Foreground layer, which can be",
1799                    "toggled by the BkGrd, IntAct and",
1800                    "FrGrd buttons. The Foreground and",
1801                    "Background layers do not effect",
1802                    "Tux in the gameplay, but lie in",
1803                    "front of him or lie behind him in",
1804                    "his adventures.",
1805                  };
1806
1807   char *text2[] = {
1808
1809                     " - Supertux level editor tutorial - ",
1810                     "",
1811                     "The tiles placed on",
1812                     "the Interactive layer are those",
1813                     "which actually effect Tux in the",
1814                     "game.",
1815                     "",
1816                     "Click the objects menu to put ",
1817                     "bad guys and other objects in the",
1818                     "game. Unlike placing tiles, you",
1819                     "cannot \"paint\" enemies. Click",
1820                     "them onto the screen one at a time.",
1821                     "",
1822                     "To change the settings of your",
1823                     "level, click the button with the",
1824                     "screwdriver and wrench. From here",
1825                     "you can change the background,",
1826                     "music, length of the level,",
1827                     "and more."
1828                   };
1829
1830   char *text3[] = {
1831
1832                     " - Supertux level editor tutorial - ",
1833                     "",
1834                     "You may have more than one level.",
1835                     "Pressing the up and down buttons",
1836                     "above the button bar lets you",
1837                     "choose which one you are working on.",
1838                     "",
1839                     "If you would like to speed up your",
1840                     "level editing, a useful trick is",
1841                     "to learn the keyboard shortcuts.",
1842                     "They are easy to learn, just right-",
1843                     "click on the buttons.",
1844                     "",
1845                     "Have fun making levels! If you make",
1846                     "some good ones, send them to us on",
1847                     "the SuperTux mailing list!",
1848                     "- SuperTux team"
1849                   };
1850
1851
1852
1853   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1854
1855   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1856     white_text->draw(text[i], 5, 80+(i*white_text->h), 1);
1857
1858   gold_text->drawf("Press Anything to Continue - Page 1/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1859
1860   flipscreen();
1861
1862   done_ = 0;
1863
1864   while(done_ == 0)
1865   {
1866     done_ = wait_for_event(event);
1867     SDL_Delay(50);
1868   }
1869
1870   drawgradient(Color(0,0,0), Color(255,255,255));
1871   le_drawinterface();
1872
1873
1874   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1875
1876   for(i = 0; i < sizeof(text2)/sizeof(char *); i++)
1877     white_text->draw(text2[i], 5, 80+(i*white_text->h), 1);
1878
1879   gold_text->drawf("Press Anything to Continue - Page 2/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1880
1881   flipscreen();
1882
1883   done_ = 0;
1884
1885   while(done_ == 0)
1886   {
1887     done_ = wait_for_event(event);
1888     SDL_Delay(50);
1889   }
1890
1891   drawgradient(Color(0,0,0), Color(255,255,255));
1892   le_drawinterface();
1893
1894
1895   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1896
1897   for(i = 0; i < sizeof(text3)/sizeof(char *); i++)
1898     white_text->draw(text3[i], 5, 80+(i*white_text->h), 1);
1899
1900   gold_text->drawf("Press Anything to Continue - Page 3/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1901
1902   flipscreen();
1903
1904   done_ = 0;
1905
1906   while(done_ == 0)
1907   {
1908     done_ = wait_for_event(event);
1909     SDL_Delay(50);
1910   }
1911
1912   show_selections = true;
1913   le_show_grid = tmp_show_grid;
1914   le_selection_mode = temp_le_selection_mode;
1915   le_help_shown = false;
1916 }