New flying platform object.
[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 <algorithm>
31 #include "leveleditor.h"
32
33 #include "screen.h"
34 #include "defines.h"
35 #include "globals.h"
36 #include "setup.h"
37 #include "menu.h"
38 #include "level.h"
39 #include "gameloop.h"
40 #include "badguy.h"
41 #include "scene.h"
42 #include "button.h"
43 #include "tile.h"
44 #include "resources.h"
45 #include "music_manager.h"
46 #include "background.h"
47 #include "display_manager.h"
48
49 /* definitions to aid development */
50
51 /* definitions that affect gameplay */
52 #define KEY_CURSOR_SPEED 32
53 #define KEY_CURSOR_FASTSPEED 64
54
55 /* when pagedown/up pressed speed:*/
56 #define PAGE_CURSOR_SPEED 13*32
57
58 #define MOUSE_LEFT_MARGIN 80
59 #define MOUSE_RIGHT_MARGIN (560-32)
60
61 /* scolling speed */
62 #define KEYBOARD_SPEED 140
63 #define MOUSE_SPEED    40
64
65 /* look */
66 #define SELECT_W 2 // size of the selections lines
67 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
68
69 /* own declerations */
70 /* crutial ones (main loop) */
71 int le_init();
72 void le_quit();
73 int le_load_level_subset(char *filename);
74 void le_drawlevel();
75 void le_drawinterface();
76 void le_checkevents();
77 void le_change(float x, float y, int tm, unsigned int c);
78 void le_testlevel();
79 void le_showhelp();
80 void le_set_defaults(void);
81 void le_activate_bad_guys(void);
82 void le_goto_level(int levelnb);
83 void le_highlight_selection();
84
85 void apply_level_settings_menu();
86 void update_subset_settings_menu();
87 void save_subset_settings_menu();
88
89 struct TileOrObject
90 {
91   TileOrObject() : tile(0), obj(NULL) { is_tile = true; };
92
93   void Tile(unsigned int set_to) { tile = set_to; is_tile = true; }
94   void Object(GameObject* pobj) { obj = pobj; is_tile = false; }
95   //Returns true for a tile
96   bool IsTile() { return is_tile; };
97   //Returns true for a GameObject
98   bool IsObject() { return !is_tile; };
99
100
101   void Init() { tile = 0; obj = NULL; is_tile = true; };
102
103   bool is_tile; //true for tile (false for object)
104   unsigned int tile;
105   GameObject* obj;
106 };
107
108 /* leveleditor internals */
109 static string_list_type level_subsets;
110 static bool le_level_changed;  /* if changes, ask for saving, when quiting*/
111 static bool show_minimap;
112 static bool show_selections;
113 static bool le_help_shown;
114 static int pos_x, pos_y, cursor_x, cursor_y;
115 static int le_level;
116 static World* le_world;
117 static LevelSubset* le_level_subset;
118 static int le_show_grid;
119 static int le_frame;
120 static Surface* le_selection;
121 static int done;
122 static TileOrObject le_current;
123 static bool le_mouse_pressed[2];
124 static bool le_mouse_clicked[2];
125 static Button* le_save_level_bt;
126 static Button* le_exit_bt;
127 static Button* le_test_level_bt;
128 static Button* le_next_level_bt;
129 static Button* le_previous_level_bt;
130 static Button* le_move_right_bt;
131 static Button* le_move_left_bt;
132 static Button* le_move_up_bt;
133 static Button* le_move_down_bt;
134 static Button* le_rubber_bt;
135 static Button* le_select_mode_one_bt;
136 static Button* le_select_mode_two_bt;
137 static Button* le_settings_bt;
138 static Button* le_tilegroup_bt;
139 static Button* le_objects_bt;
140 static Button* le_object_select_bt;
141 static Button* le_object_properties_bt;
142 static ButtonPanel* le_tilemap_panel;
143 static Menu* leveleditor_menu;
144 static Menu* subset_load_menu;
145 static Menu* subset_new_menu;
146 static Menu* subset_settings_menu;
147 static Menu* level_settings_menu;
148 static Menu* select_tilegroup_menu;
149 static Menu* select_objects_menu;
150 static Timer select_tilegroup_menu_effect;
151 static Timer select_objects_menu_effect;
152 static Timer display_level_info;
153 typedef std::map<std::string, ButtonPanel*> ButtonPanelMap;
154 static ButtonPanelMap tilegroups_map;
155 static ButtonPanelMap objects_map;
156 static std::string cur_tilegroup;
157 static std::string cur_objects;
158 static MouseCursor* mouse_select_object;
159 static MovingObject* selected_game_object;
160
161 static square selection;
162 static SelectionMode le_selection_mode;
163 static SDL_Event event;
164 TileMapType active_tm;
165
166 int leveleditor(char* filename)
167 {
168   int last_time, now_time, i;
169
170   le_level = 1;
171
172   if(le_init() != 0)
173     return 1;
174
175   /* Clear screen: */
176
177   clearscreen(0, 0, 0);
178   updatescreen();
179
180   music_manager->halt_music();
181
182   while (SDL_PollEvent(&event))
183   {}
184
185   if(filename != NULL)
186     if(le_load_level_subset(filename))
187       return 1;
188
189   while(true)
190   {
191     last_time = SDL_GetTicks();
192     le_frame++;
193
194     le_checkevents();
195
196     if(Menu::current() == select_tilegroup_menu)
197     {
198       if(select_tilegroup_menu_effect.check())
199       {
200         select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
201                                        66,-0.5,0.5);
202       }
203       else
204         select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
205     }
206     else if(Menu::current() == select_objects_menu)
207     {
208       if(select_objects_menu_effect.check())
209       {
210         select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
211       }
212       else
213         select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
214     }
215
216     if(le_world != NULL)
217     {
218       /* making events results to be in order */
219
220       /* draw the level */
221       le_drawlevel();
222     }
223     else
224       clearscreen(0, 0, 0);
225
226     /* draw editor interface */
227     le_drawinterface();
228
229     Menu* menu = Menu::current();
230     if(menu)
231     {
232       menu->draw();
233       menu->action();
234
235       if(menu == leveleditor_menu)
236       {
237         switch (leveleditor_menu->check())
238         {
239         case MNID_RETURNLEVELEDITOR:
240           if(le_world != NULL)
241             Menu::set_current(0);
242           else
243             Menu::set_current(leveleditor_menu);
244           break;
245         case MNID_SUBSETSETTINGS:
246           update_subset_settings_menu();
247           break;
248         case MNID_QUITLEVELEDITOR:
249           done = 1;
250           break;
251         }
252       }
253       else if(menu == level_settings_menu)
254       {
255         switch (level_settings_menu->check())
256         {
257         case MNID_APPLY:
258           apply_level_settings_menu();
259           Menu::set_current(NULL);
260           break;
261
262         default:
263           break;
264         }
265       }
266       else if(menu == select_tilegroup_menu)
267       {
268         int it = -1;
269         switch (it = select_tilegroup_menu->check())
270         {
271         default:
272           if(it >= 0)
273           {
274             cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
275             Menu::set_current(0);
276             cur_objects = "";
277
278           }
279           break;
280         }
281       }
282       else if(menu == select_objects_menu)
283       {
284         int it = -1;
285         switch (it = select_objects_menu->check())
286         {
287         default:
288           if(it >= 0)
289           {
290             cur_objects = select_objects_menu->get_item_by_id(it).text;
291             cur_tilegroup = "";
292
293             Menu::set_current(0);
294           }
295           break;
296         }
297       }
298       else if(menu == subset_load_menu)
299       {
300         switch (i = subset_load_menu->check())
301         {
302         case 0:
303           break;
304         default:
305           if(i >= 1)
306           {
307             if(le_load_level_subset(level_subsets.item[i-1]))
308               return 1;
309           }
310           break;
311         }
312       }
313       else if(menu == subset_new_menu)
314       {
315         if(subset_new_menu->item[2].input[0] == '\0')
316           subset_new_menu->item[3].kind = MN_DEACTIVE;
317         else
318         {
319           subset_new_menu->item[3].kind = MN_ACTION;
320
321           switch (i = subset_new_menu->check())
322           {
323           case MNID_CREATESUBSET:
324             LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
325             le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
326             leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
327             le_goto_level(1);
328             subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
329
330             Menu::set_current(subset_settings_menu);
331             break;
332           }
333         }
334       }
335       else if(menu == subset_settings_menu)
336       {
337         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  )
338           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
339         else
340           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
341
342         switch (i = subset_settings_menu->check())
343         {
344         case MNID_SUBSETSAVECHANGES:
345           save_subset_settings_menu();
346           Menu::set_current(leveleditor_menu);
347           break;
348         }
349       }
350     }
351
352     MouseCursor::current()->draw();
353
354     if(done)
355     {
356       le_quit();
357       return 0;
358     }
359
360     ++global_frame_counter;
361
362     SDL_Delay(25);
363     now_time = SDL_GetTicks();
364     if (now_time < last_time + FPS)
365       SDL_Delay(last_time + FPS - now_time);    /* delay some time */
366
367     flipscreen();
368   }
369
370   return done;
371 }
372
373 int le_load_level_subset(char *filename)
374 {
375   le_level_subset->load(filename);
376   leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
377   le_level = 1;
378   le_goto_level(1);
379
380   //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
381
382   Menu::set_current(NULL);
383
384   return 0;
385 }
386
387 void le_init_menus()
388 {
389   int i;
390
391   leveleditor_menu = new Menu();
392   subset_load_menu = new Menu();
393   subset_new_menu  = new Menu();
394   subset_settings_menu = new Menu();
395   level_settings_menu  = new Menu();
396   select_tilegroup_menu  = new Menu();
397   select_objects_menu = new Menu();
398
399   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
400   leveleditor_menu->additem(MN_HL,"",0,0);
401   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
402   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
403   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
404   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
405   leveleditor_menu->additem(MN_HL,"",0,0);
406   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
407
408   Menu::set_current(leveleditor_menu);
409
410   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
411   subset_load_menu->additem(MN_HL, "", 0, 0);
412
413   for(i = 0; i < level_subsets.num_items; ++i)
414   {
415     subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
416   }
417   subset_load_menu->additem(MN_HL,"",0,0);
418   subset_load_menu->additem(MN_BACK,"Back",0,0);
419
420   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
421   subset_new_menu->additem(MN_HL,"",0,0);
422   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
423   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
424   subset_new_menu->additem(MN_HL,"",0,0);
425   subset_new_menu->additem(MN_BACK,"Back",0,0);
426
427   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
428   subset_settings_menu->additem(MN_HL,"",0,0);
429   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
430   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
431   subset_settings_menu->additem(MN_HL,"",0,0);
432   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
433   subset_settings_menu->additem(MN_HL,"",0,0);
434   subset_settings_menu->additem(MN_BACK,"Back",0,0);
435
436   level_settings_menu->arrange_left = true;
437   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
438   level_settings_menu->additem(MN_HL,"",0,0);
439   level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
440   level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
441   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
442   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
443   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
444   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
445   level_settings_menu->additem(MN_NUMFIELD,    "Height  ",0,0,MNID_HEIGHT);
446   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
447   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
448   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
449   level_settings_menu->additem(MN_NUMFIELD,    "Top Red     ",0,0,MNID_TopRed);
450   level_settings_menu->additem(MN_NUMFIELD,    "Top Green   ",0,0,MNID_TopGreen);
451   level_settings_menu->additem(MN_NUMFIELD,    "Top Blue    ",0,0,MNID_TopBlue);
452   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red  ",0,0,MNID_BottomRed);
453   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
454   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue ",0,0,MNID_BottomBlue);
455   level_settings_menu->additem(MN_HL,"",0,0);
456   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
457
458   select_tilegroup_menu->arrange_left = true;
459   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
460   select_tilegroup_menu->additem(MN_HL,"",0,0);
461   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
462   int tileid = 1;
463   for(std::set<TileGroup>::iterator it = tilegroups->begin();
464         it != tilegroups->end(); ++it )
465     {
466       select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
467       tileid++;
468       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
469       i = 0;
470
471       for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
472           sit != (*it).tiles.end(); ++sit, ++i)
473       {
474         std::string imagefile = "/images/tilesets/" ;
475         bool only_editor_image = false;
476         if(!TileManager::instance()->get(*sit)->filenames.empty())
477         {
478           imagefile += TileManager::instance()->get(*sit)->filenames[0];
479         }
480         else if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
481         {
482           imagefile += TileManager::instance()->get(*sit)->editor_filenames[0];
483           only_editor_image = true;
484         }
485         else
486         {
487           imagefile += "notile.png";
488         }
489         Button* button = new Button(imagefile, it->name, SDLKey(SDLK_a + i),
490                                     0, 0, 32, 32);
491         if(!only_editor_image)
492           if(!TileManager::instance()->get(*sit)->editor_filenames.empty())
493           {
494             imagefile = "/images/tilesets/" + TileManager::instance()->get(*sit)->editor_filenames[0];
495             button->add_icon(imagefile,32,32);
496           }
497         tilegroups_map[it->name]->additem(button, *sit);
498       }
499     }
500   select_tilegroup_menu->additem(MN_HL,"",0,0);
501
502   select_objects_menu->arrange_left = true;
503   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
504   select_objects_menu->additem(MN_HL,"",0,0);
505   // TODO fix this
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, BadGuyKind(i), 0, 0);
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           BadGuyKind(i),
517           objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
518           objects_map["BadGuys"]->manipulate_button(i)->get_pos().y
519           ));
520   }
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: Do we have a new solution for draw_on_screen()?
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: Do we have a new solution for move_to()?
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 XXX: New solution for this?
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             // FIXME TODO
1510             if(le_current.IsObject())
1511             {
1512               le_level_changed  = true;
1513               std::string type = le_current.obj->type();
1514
1515               if(type == "BadGuy")
1516               {
1517                 ViewPort viewport(le_world->displaymanager.get_viewport());
1518                 DisplayManager dummy;
1519                 BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1520
1521                 le_world->bad_guys.push_back(new BadGuy(dummy, pbadguy->kind, cursor_x + viewport.get_translation().x, cursor_y + viewport.get_translation().y));
1522                 le_world->gameobjects.push_back(le_world->bad_guys.back());
1523               }
1524             }
1525
1526           }
1527           
1528           le_mouse_clicked[LEFT] = false;
1529
1530         }
1531       }
1532     }
1533   }
1534   if(!Menu::current())
1535   {
1536     show_minimap = false;
1537
1538     le_move_left_bt->event(event);
1539     le_move_right_bt->event(event);
1540     le_move_up_bt->event(event);
1541     le_move_down_bt->event(event);
1542     switch(le_move_left_bt->get_state())
1543     {
1544     case BUTTON_PRESSED:
1545       pos_x -= KEYBOARD_SPEED;
1546       show_minimap = true;
1547       break;
1548     case BUTTON_HOVER:
1549       pos_x -= MOUSE_SPEED;
1550       show_minimap = true;
1551       break;
1552     case BUTTON_CLICKED:
1553       show_minimap = true;
1554       break;
1555     default:
1556       break;
1557     }
1558
1559     switch(le_move_right_bt->get_state())
1560     {
1561     case BUTTON_PRESSED:
1562       pos_x += KEYBOARD_SPEED;
1563       show_minimap = true;
1564       break;
1565     case BUTTON_HOVER:
1566       pos_x += MOUSE_SPEED;
1567       show_minimap = true;
1568       break;
1569     case BUTTON_CLICKED:
1570       show_minimap = true;
1571       break;
1572     default:
1573       break;
1574     }
1575
1576     switch(le_move_up_bt->get_state())
1577     {
1578     case BUTTON_PRESSED:
1579       pos_y -= KEYBOARD_SPEED;
1580       show_minimap = true;
1581       break;
1582     case BUTTON_HOVER:
1583       pos_y -= MOUSE_SPEED;
1584       show_minimap = true;
1585       break;
1586     case BUTTON_CLICKED:
1587       show_minimap = true;
1588       break;
1589     default:
1590       break;
1591     }
1592
1593     switch(le_move_down_bt->get_state())
1594     {
1595     case BUTTON_PRESSED:
1596       pos_y += KEYBOARD_SPEED;
1597       show_minimap = true;
1598       break;
1599     case BUTTON_HOVER:
1600       pos_y += MOUSE_SPEED;
1601       show_minimap = true;
1602       break;
1603     case BUTTON_CLICKED:
1604       show_minimap = true;
1605       break;
1606     default:
1607       break;
1608     }
1609
1610       /* checking if pos_x and pos_y is within the limits... */
1611       if(pos_x > (le_world->get_level()->width * 32 + 32*2) - screen->w)
1612         pos_x = (le_world->get_level()->width * 32 + 32*2) - screen->w;
1613       if(pos_x < 0)
1614         pos_x = 0;
1615
1616       if(pos_y > (le_world->get_level()->height * 32) - screen->h)
1617         pos_y = (le_world->get_level()->height * 32) - screen->h;
1618       if(pos_y < 0)
1619         pos_y = 0;
1620
1621   }
1622
1623 }
1624
1625 void le_highlight_selection()
1626 {
1627   int x1, x2, y1, y2;
1628
1629   if(selection.x1 < selection.x2)
1630   {
1631     x1 = selection.x1;
1632     x2 = selection.x2;
1633   }
1634   else
1635   {
1636     x1 = selection.x2;
1637     x2 = selection.x1;
1638   }
1639   if(selection.y1 < selection.y2)
1640   {
1641     y1 = selection.y1;
1642     y2 = selection.y2;
1643   }
1644   else
1645   {
1646     y1 = selection.y2;
1647     y2 = selection.y1;
1648   }
1649
1650   x1 /= 32;
1651   x2 /= 32;
1652   y1 /= 32;
1653   y2 /= 32;
1654
1655   fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1656 }
1657
1658 void le_change(float x, float y, int tm, unsigned int c)
1659 {
1660   if(le_world != NULL)
1661   {
1662     int xx,yy;
1663     int x1, x2, y1, y2;
1664
1665     le_level_changed = true;
1666
1667     switch(le_selection_mode)
1668     {
1669     case CURSOR:
1670       le_world->get_level()->change(x,y,tm,c);
1671
1672       base_type cursor_base;
1673       cursor_base.x = x;
1674       cursor_base.y = y;
1675       cursor_base.width = 32;
1676       cursor_base.height = 32;
1677
1678       /* if there is a bad guy over there, remove it */
1679       // XXX TODO
1680       for(std::vector<GameObject*>::iterator it = le_world->gameobjects.begin();
1681             it != le_world->gameobjects.end(); ++it)
1682         if ((*it)->type() == "BadGuy")
1683         {
1684           BadGuy* pbadguy = dynamic_cast<BadGuy*>((*it));
1685           if(rectcollision(cursor_base, pbadguy->base))
1686           {
1687             delete (*it);
1688             //le_world->bad_guys.erase(it);
1689             le_world->gameobjects.erase(std::remove(le_world->gameobjects.begin(), le_world->gameobjects.end(), *it), le_world->gameobjects.end());
1690             break;
1691           }
1692         }
1693
1694       break;
1695     case SQUARE:
1696       if(selection.x1 < selection.x2)
1697       {
1698         x1 = selection.x1;
1699         x2 = selection.x2;
1700       }
1701       else
1702       {
1703         x1 = selection.x2;
1704         x2 = selection.x1;
1705       }
1706       if(selection.y1 < selection.y2)
1707       {
1708         y1 = selection.y1;
1709         y2 = selection.y2;
1710       }
1711       else
1712       {
1713         y1 = selection.y2;
1714         y2 = selection.y1;
1715       }
1716
1717       x1 /= 32;
1718       x2 /= 32;
1719       y1 /= 32;
1720       y2 /= 32;
1721
1722       /* if there is a bad guy over there, remove it */
1723       // TODO FIXME
1724       for(std::vector<GameObject*>::iterator it = le_world->gameobjects.begin();
1725           it != le_world->gameobjects.end(); ++it /* will be at end of loop */)
1726       {
1727         if ((*it)->type() == "BadGuy")
1728         {
1729           MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);
1730           if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
1731               && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
1732           {
1733             delete (*it);
1734             //it = le_world->gameobjects.erase(it);
1735             le_world->gameobjects.erase(std::remove(le_world->gameobjects.begin(), le_world->gameobjects.end(), *it), le_world->gameobjects.end());
1736             continue;
1737           }
1738           else
1739           {
1740             ++it;
1741           }
1742         }
1743       }
1744
1745       for(xx = x1; xx <= x2; xx++)
1746         for(yy = y1; yy <= y2; yy++)
1747         {
1748           le_world->get_level()->change(xx*32, yy*32, tm, c);
1749
1750         }
1751       break;
1752     default:
1753       break;
1754     }
1755   }
1756 }
1757
1758 void le_testlevel()
1759 {
1760   //Make sure a time value is set when testing the level
1761   if(le_world->get_level()->time_left == 0)
1762     le_world->get_level()->time_left = 250;
1763
1764   le_world->get_level()->save("test", le_level, le_world);
1765
1766   GameSession session("test",le_level, ST_GL_TEST);
1767   session.run();
1768   player_status.reset();
1769
1770   music_manager->halt_music();
1771
1772   Menu::set_current(NULL);
1773   World::set_current(le_world);
1774 }
1775
1776 void le_showhelp()
1777 {
1778   bool tmp_show_grid = le_show_grid;
1779   SelectionMode temp_le_selection_mode = le_selection_mode;
1780   le_selection_mode = NONE;
1781   show_selections = true;
1782   le_show_grid = false;
1783   le_help_shown = true;
1784
1785   drawgradient(Color(0,0,0), Color(255,255,255));
1786   le_drawinterface();
1787
1788   SDL_Event event;
1789   unsigned int i, done_;
1790   char *text[] = {
1791
1792                    " - Supertux level editor tutorial - ",
1793                    "",
1794                    "To make your map, click the       ",
1795                    "tilegroup button and choose a     ",
1796                    "tilegroup.",
1797                    "Pick a tile and simply hold down  ",
1798                    "the left mouse button over the map",
1799                    "to \"paint\" your selection over",
1800                    "the screen.",
1801                    "",
1802                    "There are three layers for painting",
1803                    "tiles upon, Background layer,",
1804                    "the Interactive layer, and the",
1805                    "Foreground layer, which can be",
1806                    "toggled by the BkGrd, IntAct and",
1807                    "FrGrd buttons. The Foreground and",
1808                    "Background layers do not effect",
1809                    "Tux in the gameplay, but lie in",
1810                    "front of him or lie behind him in",
1811                    "his adventures.",
1812                  };
1813
1814   char *text2[] = {
1815
1816                     " - Supertux level editor tutorial - ",
1817                     "",
1818                     "The tiles placed on",
1819                     "the Interactive layer are those",
1820                     "which actually effect Tux in the",
1821                     "game.",
1822                     "",
1823                     "Click the objects menu to put ",
1824                     "bad guys and other objects in the",
1825                     "game. Unlike placing tiles, you",
1826                     "cannot \"paint\" enemies. Click",
1827                     "them onto the screen one at a time.",
1828                     "",
1829                     "To change the settings of your",
1830                     "level, click the button with the",
1831                     "screwdriver and wrench. From here",
1832                     "you can change the background,",
1833                     "music, length of the level,",
1834                     "and more."
1835                   };
1836
1837   char *text3[] = {
1838
1839                     " - Supertux level editor tutorial - ",
1840                     "",
1841                     "You may have more than one level.",
1842                     "Pressing the up and down buttons",
1843                     "above the button bar lets you",
1844                     "choose which one you are working on.",
1845                     "",
1846                     "If you would like to speed up your",
1847                     "level editing, a useful trick is",
1848                     "to learn the keyboard shortcuts.",
1849                     "They are easy to learn, just right-",
1850                     "click on the buttons.",
1851                     "",
1852                     "Have fun making levels! If you make",
1853                     "some good ones, send them to us on",
1854                     "the SuperTux mailing list!",
1855                     "- SuperTux team"
1856                   };
1857
1858
1859
1860   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1861
1862   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1863     white_text->draw(text[i], 5, 80+(i*white_text->h), 1);
1864
1865   gold_text->drawf("Press Anything to Continue - Page 1/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1866
1867   flipscreen();
1868
1869   done_ = 0;
1870
1871   while(done_ == 0)
1872   {
1873     done_ = wait_for_event(event);
1874     SDL_Delay(50);
1875   }
1876
1877   drawgradient(Color(0,0,0), Color(255,255,255));
1878   le_drawinterface();
1879
1880
1881   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1882
1883   for(i = 0; i < sizeof(text2)/sizeof(char *); i++)
1884     white_text->draw(text2[i], 5, 80+(i*white_text->h), 1);
1885
1886   gold_text->drawf("Press Anything to Continue - Page 2/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1887
1888   flipscreen();
1889
1890   done_ = 0;
1891
1892   while(done_ == 0)
1893   {
1894     done_ = wait_for_event(event);
1895     SDL_Delay(50);
1896   }
1897
1898   drawgradient(Color(0,0,0), Color(255,255,255));
1899   le_drawinterface();
1900
1901
1902   blue_text->drawf("- Help -", 0, 30, A_HMIDDLE, A_TOP, 2);
1903
1904   for(i = 0; i < sizeof(text3)/sizeof(char *); i++)
1905     white_text->draw(text3[i], 5, 80+(i*white_text->h), 1);
1906
1907   gold_text->drawf("Press Anything to Continue - Page 3/3", 0, 0, A_LEFT, A_BOTTOM, 1);
1908
1909   flipscreen();
1910
1911   done_ = 0;
1912
1913   while(done_ == 0)
1914   {
1915     done_ = wait_for_event(event);
1916     SDL_Delay(50);
1917   }
1918
1919   show_selections = true;
1920   le_show_grid = tmp_show_grid;
1921   le_selection_mode = temp_le_selection_mode;
1922   le_help_shown = false;
1923 }