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