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