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