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