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