68c3b33cb19fda0435284a9722667ff290c5e488
[supertux.git] / src / leveleditor.c
1 /***************************************************************************
2  *                                                                         *
3  *   This program is free software; you can redistribute it and/or modify  *
4  *   it under the terms of the GNU General Public License as published by  *
5  *   the Free Software Foundation; either version 2 of the License, or     *
6  *   (at your option) any later version.                                   *
7  *                                                                         *
8  ***************************************************************************/
9
10 /*  December 28, 2003 - February 1st, 2004 */
11
12 /* leveleditor.c - A built-in level editor for SuperTux
13  by Ricardo Cruz <rick2@aeiou.pt>                      */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <SDL.h>
21 #include <SDL_image.h>
22 #include "leveleditor.h"
23
24 #include "screen.h"
25 #include "defines.h"
26 #include "globals.h"
27 #include "setup.h"
28 #include "menu.h"
29 #include "level.h"
30 #include "badguy.h"
31 #include "scene.h"
32 #include "button.h"
33
34 /* definitions to aid development */
35 #define DONE_LEVELEDITOR 1
36 #define DONE_QUIT        2
37 #define DONE_CHANGELEVEL 3
38
39 /* definitions that affect gameplay */
40 #define KEY_CURSOR_SPEED 32
41 #define KEY_CURSOR_FASTSPEED 64
42
43 /* when pagedown/up pressed speed:*/
44 #define PAGE_CURSOR_SPEED 13*32
45
46 #define MOUSE_LEFT_MARGIN 80
47 #define MOUSE_RIGHT_MARGIN (560-32)
48 /* right_margin should noticed that the cursor is 32 pixels,
49    so it should subtract that value */
50 #define MOUSE_POS_SPEED 20
51
52 /* look */
53 #define SELECT_W 2 // size of the selections lines
54 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
55
56 /* gameloop funcs declerations */
57
58 void loadshared(void);
59 void unloadshared(void);
60
61 /* own declerations */
62 /* crutial ones (main loop) */
63 int le_init();
64 void le_quit();
65 void le_drawlevel();
66 void le_drawinterface();
67 void le_checkevents();
68 void le_change(float x, float y, unsigned char c);
69 void le_testlevel();
70 void le_showhelp();
71 void le_set_defaults(void);
72 void le_activate_bad_guys(void);
73
74 void le_highlight_selection();
75
76 /* leveleditor internals */
77 static char **level_subsets;
78 static int subsets_num;
79 static int le_level_changed;  /* if changes, ask for saving, when quiting*/
80 static int pos_x, cursor_x, cursor_y, cursor_tile, fire;
81 static int le_level;
82 static st_level* le_current_level;
83 static st_subset le_level_subset;
84 static int le_show_grid;
85 static int le_frame;
86 static texture_type le_selection;
87 static int done;
88 static char le_current_tile;
89 static int le_mouse_pressed;
90 static button_type le_test_level_bt;
91 static button_type le_next_level_bt;
92 static button_type le_previous_level_bt;
93 static button_type le_rubber_bt;
94 static button_type le_select_mode_one_bt;
95 static button_type le_select_mode_two_bt;
96 static button_type le_bad_bsod_bt;
97 static button_type le_settings_bt;
98 static button_panel_type le_bt_panel;
99 static menu_type leveleditor_menu;
100 static menu_type subset_load_menu;
101 static menu_type subset_new_menu;
102 static menu_type subset_settings_menu;
103 static menu_type level_settings_menu;
104
105 static square selection;
106 static int le_selection_mode;
107 static SDL_Event event;
108
109 void le_activate_bad_guys(void)
110 {
111   int x,y;
112
113   /* Activate bad guys: */
114
115   /* as oposed to the gameloop.c func, this one doesn't remove
116   the badguys from tiles                                    */
117
118   for (y = 0; y < 15; ++y)
119     for (x = 0; x < le_current_level->width; ++x)
120       if (le_current_level->tiles[y][x] >= '0' && le_current_level->tiles[y][x] <= '9')
121         add_bad_guy(x * 32, y * 32, le_current_level->tiles[y][x] - '0');
122 }
123
124 void le_set_defaults()
125 {
126   if(le_current_level != NULL)
127     {
128       /* Set defaults: */
129
130       if(le_current_level->time_left == 0)
131         le_current_level->time_left = 255;
132     }
133 }
134
135 /* FIXME: Needs to be implemented. It should ask the user for the level(file)name and then let him create a new level based on this. */
136 void newlevel()
137 {}
138
139 /* FIXME: It should let select the user a level, which is in the leveldirectory and then load it. */
140 void selectlevel()
141 {}
142
143 int leveleditor(int levelnb)
144 {
145   int last_time, now_time, i;
146
147   le_level = levelnb;
148   if(le_init() != 0)
149     return 1;
150
151   /* Clear screen: */
152
153   clearscreen(0, 0, 0);
154   updatescreen();
155
156   while (SDL_PollEvent(&event))
157   {}
158
159   while(YES)
160     {
161       last_time = SDL_GetTicks();
162       le_frame++;
163
164       le_checkevents();
165
166       if(le_current_level != NULL)
167         {
168           /* making events results to be in order */
169           if(pos_x < 0)
170             pos_x = 0;
171           if(pos_x > (le_current_level->width * 32) - screen->w)
172             pos_x = (le_current_level->width * 32) - screen->w;
173
174           /* draw the level */
175           le_drawlevel();
176         }
177       else
178         clearscreen(0, 0, 0);
179
180       /* draw editor interface */
181       le_drawinterface();
182
183       if(show_menu)
184         {
185           menu_process_current();
186           if(current_menu == &leveleditor_menu)
187             {
188               switch (menu_check(&leveleditor_menu))
189                 {
190                 case 2:
191                   show_menu = NO;
192                   break;
193                 case 7:
194                   done = DONE_LEVELEDITOR;
195                   break;
196                 }
197             }
198           else if(current_menu == &level_settings_menu)
199             {
200               switch (menu_check(&level_settings_menu))
201                 {
202                 case 0:
203                   break;
204                 case 1:
205                   show_menu = YES;
206                   break;
207                 case 4:
208                   break;
209                 case 11:
210                   strcpy(le_current_level->name,level_settings_menu.item[1].input);
211                   break;
212                 }
213             }
214           else if(current_menu == &subset_load_menu)
215             {
216               switch (i = menu_check(&subset_load_menu))
217                 {
218                 case 0:
219                   break;
220                 default:
221                   if(i != -1)
222                     {
223                       subset_load(&le_level_subset,level_subsets[i-2]);
224                       leveleditor_menu.item[3].kind = MN_GOTO;
225                       le_level = 1;
226                       arrays_init();
227                       loadshared();
228                       le_current_level = (st_level*) malloc(sizeof(st_level));
229                       if(level_load(le_current_level, le_level_subset.name, le_level) != 0)
230                         {
231                           le_quit();
232                           return 1;
233                         }
234                       le_set_defaults();
235                       level_load_gfx(le_current_level);
236                       le_activate_bad_guys();
237                       show_menu = YES;
238                     }
239                   break;
240                 }
241             }
242         }
243
244       if(done)
245         {
246           le_quit();
247           return 0;
248         }
249
250       if(done == DONE_QUIT)
251         {
252           le_quit();
253           return 1;
254         }
255
256       SDL_Delay(25);
257       now_time = SDL_GetTicks();
258       if (now_time < last_time + FPS)
259         SDL_Delay(last_time + FPS - now_time);  /* delay some time */
260
261       flipscreen();
262     }
263
264   return done;
265 }
266
267 int le_init()
268 {
269   int i;
270   char str[80];
271   level_subsets = NULL;
272   level_subsets = dsubdirs("/levels", "info", &subsets_num);
273
274   le_show_grid = YES;
275   
276   /*  level_changed = NO;*/
277   fire = DOWN;
278   done = 0;
279   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
280   le_level_changed = NO;
281   
282   /*
283     subset_load(&le_level_subset,"default");
284     arrays_init();
285     loadshared();
286     le_set_defaults();
287    
288    
289     if(level_load(&le_current_level, le_level_subset.name, le_level) != 0)
290       {
291         le_quit();
292         return 1;
293       }
294     if(le_current_level.time_left == 0)
295       le_current_level.time_left = 255;
296    
297     level_load_gfx(&le_current_level);
298       le_activate_bad_guys();
299     */
300   le_current_level = NULL;
301
302   le_current_tile = '.';
303   le_mouse_pressed = NO;
304
305   texture_load(&le_selection,DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA);
306
307   /* Load buttons */
308   button_load(&le_next_level_bt,"/images/icons/up.png","Test Level", SDLK_PAGEUP,screen->w-64,0);
309   button_load(&le_previous_level_bt,"/images/icons/down.png","Test Level",SDLK_PAGEDOWN,screen->w-32,0);
310   button_load(&le_rubber_bt,"/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-64,32);
311   button_load(&le_select_mode_one_bt,"/images/icons/select-mode1.png","Select Tile",SDLK_F3,screen->w-64,16);
312   button_load(&le_select_mode_two_bt,"/images/icons/select-mode2.png","Select Tiles",SDLK_F3,screen->w-32,16);
313   button_load(&le_test_level_bt,"/images/icons/test-level.png","Test Level",SDLK_F4,screen->w-64,screen->h - 64);
314   button_load(&le_settings_bt,"/images/icons/settings.png","Level settings",SDLK_0,screen->w-32,screen->h - 64);
315   button_panel_init(&le_bt_panel, screen->w - 64,64, 64, 380);
316
317   menu_init(&leveleditor_menu);
318   menu_additem(&leveleditor_menu,menu_item_create(MN_LABEL,"Level Editor Menu",0,0));
319   menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
320   menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Return To Level Editor",0,0));
321   menu_additem(&leveleditor_menu,menu_item_create(MN_DEACTIVE,"Level Subset Settings",0,&subset_settings_menu));
322   menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"Load Level Subset",0,&subset_load_menu));
323   menu_additem(&leveleditor_menu,menu_item_create(MN_GOTO,"New Level Subset",0,&subset_new_menu));
324   menu_additem(&leveleditor_menu,menu_item_create(MN_HL,"",0,0));
325   menu_additem(&leveleditor_menu,menu_item_create(MN_ACTION,"Quit Level Editor",0,0));
326
327   menu_reset();
328   menu_set_current(&leveleditor_menu);
329   show_menu = YES;
330     
331   menu_init(&subset_load_menu);
332   menu_additem(&subset_load_menu,menu_item_create(MN_LABEL,"Load Level Subset",0,0));
333   menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
334   for(i = 0; i < subsets_num; ++i)
335     {
336       menu_additem(&subset_load_menu,menu_item_create(MN_ACTION,level_subsets[i],0,0));
337     }
338   menu_additem(&subset_load_menu,menu_item_create(MN_HL,"",0,0));
339   menu_additem(&subset_load_menu,menu_item_create(MN_BACK,"Back",0,0));
340
341   menu_init(&subset_new_menu);
342   menu_additem(&subset_new_menu,menu_item_create(MN_LABEL,"New Level Subset",0,0));
343   menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
344   menu_additem(&subset_new_menu,menu_item_create(MN_TEXTFIELD,"Enter Name",0,0));
345   menu_additem(&subset_new_menu,menu_item_create(MN_ACTION,"Create",0,0));
346   menu_additem(&subset_new_menu,menu_item_create(MN_HL,"",0,0));
347   menu_additem(&subset_new_menu,menu_item_create(MN_BACK,"Back",0,0));
348
349   menu_init(&subset_settings_menu);
350   menu_additem(&subset_settings_menu,menu_item_create(MN_LABEL,"Level Subset Settings",0,0));
351   menu_additem(&subset_settings_menu,menu_item_create(MN_HL,"",0,0));
352   menu_additem(&subset_settings_menu,menu_item_create(MN_BACK,"Back",0,0));
353
354   menu_init(&level_settings_menu);
355   level_settings_menu.arrange_left = YES;
356   menu_additem(&level_settings_menu,menu_item_create(MN_LABEL,"Level Settings",0,0));
357   menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
358   menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Name:",0,0));
359   menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Theme:",0,0));
360   menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Song:",0,0));
361   menu_additem(&level_settings_menu,menu_item_create(MN_TEXTFIELD,"Background:",0,0));
362   menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Length: ",0,0));
363   menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Time:   ",0,0));
364   menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Gravity:",0,0));
365   menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Red:    ",0,0));
366   menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Green:  ",0,0));
367   menu_additem(&level_settings_menu,menu_item_create(MN_NUMFIELD,"Blue:   ",0,0));
368   menu_additem(&level_settings_menu,menu_item_create(MN_HL,"",0,0));
369   menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Apply Changes",0,0));
370   /*menu_additem(&level_settings_menu,menu_item_create(MN_GOTO,"Load Game",0,&load_game_menu));
371   menu_additem(&level_settings_menu,menu_item_create(MN_GOTO,"Options",0,&options_menu));
372   menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Level editor",0,0));
373   menu_additem(&level_settings_menu,menu_item_create(MN_ACTION,"Quit",0,0));*/
374
375   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
376
377   return 0;
378 }
379
380 void update_level_settings()
381 {
382   char str[80];
383
384   menu_item_change_input(&level_settings_menu.item[1], le_current_level->name);
385   sprintf(str,"%d",le_current_level->width);
386   menu_item_change_input(&level_settings_menu.item[5], str);
387   sprintf(str,"%d",le_current_level->time_left);
388   menu_item_change_input(&level_settings_menu.item[6], str);
389   sprintf(str,"%2.0f",le_current_level->gravity);
390   menu_item_change_input(&level_settings_menu.item[7], str);
391   sprintf(str,"%d",le_current_level->bkgd_red);
392   menu_item_change_input(&level_settings_menu.item[8], str);
393   sprintf(str,"%d",le_current_level->bkgd_green);
394   menu_item_change_input(&level_settings_menu.item[9], str);
395   sprintf(str,"%d",le_current_level->bkgd_blue);
396   menu_item_change_input(&level_settings_menu.item[10], str);
397 }
398
399 void le_goto_level(int levelnb)
400 {
401
402   level_free(le_current_level);
403   if(level_load(le_current_level, le_level_subset.name, levelnb) != 0)
404     {
405       level_load(le_current_level, le_level_subset.name, le_level);
406     }
407   else
408     {
409       le_level = levelnb;
410     }
411
412   le_set_defaults();
413
414   level_free_gfx();
415   level_load_gfx(le_current_level);
416
417   le_activate_bad_guys();
418 }
419
420 void le_quit(void)
421 {
422   /*if(level_changed == YES)
423     if(askforsaving() == CANCEL)
424       return;*/ //FIXME
425
426   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
427
428   button_free(&le_test_level_bt);
429   texture_free(&le_selection);
430   menu_free(&leveleditor_menu);
431
432   if(le_current_level != NULL)
433     {
434       level_free_gfx();
435       level_free(le_current_level);
436       unloadshared();
437       arrays_free();
438     }
439 }
440
441 void le_drawinterface()
442 {
443   int x,y;
444   char str[80];
445
446   if(le_current_level != NULL)
447     {
448       /* draw a grid (if selected) */
449       if(le_show_grid)
450         {
451           for(x = 0; x < 19; x++)
452             fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
453           for(y = 0; y < 15; y++)
454             fillrect(0, y*32, screen->w - 32, 1, 225, 225, 225,255);
455         }
456     }
457
458   if(le_selection_mode == CURSOR)
459     texture_draw(&le_selection, cursor_x - pos_x, cursor_y, NO_UPDATE);
460   else if(le_selection_mode == SQUARE)
461     {
462       int w, h;
463       le_highlight_selection();
464       /* draw current selection */
465       w = selection.x2 - selection.x1;
466       h = selection.y2 - selection.y1;
467       fillrect(selection.x1 - pos_x, selection.y1, w, SELECT_W, SELECT_CLR);
468       fillrect(selection.x1 - pos_x + w, selection.y1, SELECT_W, h, SELECT_CLR);
469       fillrect(selection.x1 - pos_x, selection.y1 + h, w, SELECT_W, SELECT_CLR);
470       fillrect(selection.x1 - pos_x, selection.y1, SELECT_W, h, SELECT_CLR);
471     }
472
473
474   /* draw button bar */
475   fillrect(screen->w - 64, 0, 64, screen->h, 50, 50, 50,255);
476   drawshape(19 * 32, 14 * 32, le_current_tile);
477
478   if(le_current_level != NULL)
479     {
480       button_draw(&le_test_level_bt);
481       button_draw(&le_next_level_bt);
482       button_draw(&le_previous_level_bt);
483       button_draw(&le_rubber_bt);
484       button_draw(&le_select_mode_one_bt);
485       button_draw(&le_select_mode_two_bt);
486       button_draw(&le_bad_bsod_bt);
487       button_draw(&le_settings_bt);
488       button_panel_draw(&le_bt_panel);
489
490       sprintf(str, "%d/%d", le_level,le_level_subset.levels);
491       text_draw(&white_text, "LEV", 0, 0, 1, NO_UPDATE);
492       text_draw(&gold_text, str, 80, 0, 1, NO_UPDATE);
493
494       text_draw(&white_small_text, "F1 for Help", 10, 430, 1, NO_UPDATE);
495     }
496   else
497     {
498       if(show_menu == NO)
499         text_draw(&white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", 10, 430, 1, NO_UPDATE);
500       else
501         text_draw(&white_small_text, "No Level Subset loaded", 10, 430, 1, NO_UPDATE);
502     }
503
504 }
505
506 void le_drawlevel()
507 {
508   int y,x,i,s;
509   static char str[LEVEL_NAME_MAX];
510
511   /* Draw the real background */
512   if(le_current_level->bkgd_image[0] != '\0')
513     {
514       s = pos_x / 30;
515       texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s - 32, img_bkgd.h, NO_UPDATE);
516       texture_draw_part(&img_bkgd,0,0,screen->w - s - 32 ,0,s,img_bkgd.h, NO_UPDATE);
517     }
518   else
519     {
520       clearscreen(le_current_level->bkgd_red, le_current_level->bkgd_green, le_current_level->bkgd_blue);
521     }
522
523   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
524
525   for (y = 0; y < 15; ++y)
526     for (x = 0; x < 20; ++x)
527       {
528         drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->tiles[y][x + (int)(pos_x / 32)]);
529
530         /* draw whats inside stuff when cursor is selecting those */
531         /* (draw them all the time - is this the right behaviour?) */
532         switch(le_current_level->tiles[y][x + (int)(pos_x/32)])
533           {
534           case 'B':
535             texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
536             break;
537           case '!':
538             texture_draw(&img_golden_herring, x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
539             break;
540           case 'x':
541           case 'y':
542           case 'A':
543             texture_draw(&img_distro[(frame / 5) % 4], x * 32 - ((int)pos_x % 32), y*32, NO_UPDATE);
544             break;
545           default:
546             break;
547           }
548       }
549
550   /* Draw the Bad guys: */
551   for (i = 0; i < num_bad_guys; ++i)
552     {
553       if(bad_guys[i].base.alive == NO)
554         continue;
555       /* to support frames: img_bsod_left[(frame / 5) % 4] */
556       if(bad_guys[i].kind == BAD_BSOD)
557         texture_draw(&img_bsod_left[(le_frame / 5) % 4], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
558       else if(bad_guys[i].kind == BAD_LAPTOP)
559         texture_draw(&img_laptop_left[(le_frame / 5) % 3], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
560       else if (bad_guys[i].kind == BAD_MONEY)
561         texture_draw(&img_money_left[(le_frame / 5) % 2], bad_guys[i].base.x - pos_x, bad_guys[i].base.y, NO_UPDATE);
562     }
563
564
565   /* Draw the player: */
566   /* for now, the position is fixed at (0, 240) */
567   texture_draw(&tux_right[(frame / 5) % 3], 0 - pos_x, 240, NO_UPDATE);
568 }
569
570 void le_checkevents()
571 {
572   SDLKey key;
573   SDLMod keymod;
574   int x,y;
575
576   keymod = SDL_GetModState();
577
578   while(SDL_PollEvent(&event))
579     {
580       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
581       if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > 0 && event.motion.x < screen->w - 64 &&
582                                        event.motion.y > 0 && event.motion.y < screen->h)))
583         {
584
585           switch(event.type)
586             {
587             case SDL_KEYDOWN:   // key pressed
588               key = event.key.keysym.sym;
589               if(show_menu)
590                 {
591                   menu_event(&event.key.keysym);
592                   break;
593                 }
594               switch(key)
595                 {
596                 case SDLK_ESCAPE:
597                   if(!show_menu)
598                     show_menu = YES;
599                   else
600                     show_menu = NO;
601                   break;
602                 case SDLK_LEFT:
603                   if(fire == DOWN)
604                     cursor_x -= KEY_CURSOR_SPEED;
605                   else
606                     cursor_x -= KEY_CURSOR_FASTSPEED;
607
608                   if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
609                     pos_x = cursor_x - MOUSE_LEFT_MARGIN;
610
611                   break;
612                 case SDLK_RIGHT:
613                   if(fire == DOWN)
614                     cursor_x += KEY_CURSOR_SPEED;
615                   else
616                     cursor_x += KEY_CURSOR_FASTSPEED;
617
618                   if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
619                     pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
620
621                   break;
622                 case SDLK_UP:
623                   if(fire == DOWN)
624                     cursor_y -= KEY_CURSOR_SPEED;
625                   else
626                     cursor_y -= KEY_CURSOR_FASTSPEED;
627
628                   if(cursor_y < 0)
629                     cursor_y = 0;
630                   break;
631                 case SDLK_DOWN:
632                   if(fire == DOWN)
633                     cursor_y += KEY_CURSOR_SPEED;
634                   else
635                     cursor_y += KEY_CURSOR_FASTSPEED;
636
637                   if(cursor_y > screen->h-32)
638                     cursor_y = screen->h-32;
639                   break;
640                 case SDLK_LCTRL:
641                   fire =UP;
642                   break;
643                 case SDLK_F1:
644                   le_showhelp();
645                   break;
646                 case SDLK_HOME:
647                   cursor_x = 0;
648                   pos_x = cursor_x;
649                   break;
650                 case SDLK_END:
651                   cursor_x = (le_current_level->width * 32) - 32;
652                   pos_x = cursor_x;
653                   break;
654                 case SDLK_PAGEUP:
655                   cursor_x -= PAGE_CURSOR_SPEED;
656
657                   if(cursor_x < pos_x + MOUSE_LEFT_MARGIN)
658                     pos_x = cursor_x - MOUSE_LEFT_MARGIN;
659
660                   break;
661                 case SDLK_PAGEDOWN:
662                   cursor_x += PAGE_CURSOR_SPEED;
663
664                   if(cursor_x > pos_x + MOUSE_RIGHT_MARGIN-32)
665                     pos_x = cursor_x - MOUSE_RIGHT_MARGIN+32;
666
667                   break;
668                 case SDLK_F9:
669                   le_show_grid = !le_show_grid;
670                   break;
671                 case SDLK_PERIOD:
672                   le_change(cursor_x, cursor_y, '.');
673                   break;
674                 case SDLK_a:
675                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
676                     le_current_tile = 'A';
677                   else
678                     le_current_tile = 'a';
679                   break;
680                 case SDLK_b:
681                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
682                     le_change(cursor_x, cursor_y, 'B');
683                   break;
684                 case SDLK_c:
685                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
686                     le_change(cursor_x, cursor_y, 'C');
687                   else
688                     le_change(cursor_x, cursor_y, 'c');
689                   break;
690                 case SDLK_d:
691                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
692                     le_change(cursor_x, cursor_y, 'D');
693                   else
694                     le_change(cursor_x, cursor_y, 'd');
695                   break;
696                 case SDLK_e:
697                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
698                     le_change(cursor_x, cursor_y, 'E');
699                   else
700                     le_change(cursor_x, cursor_y, 'e');
701                   break;
702                 case SDLK_f:
703                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
704                     le_change(cursor_x, cursor_y, 'F');
705                   else
706                     le_change(cursor_x, cursor_y, 'f');
707                   break;
708                 case SDLK_g:
709                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
710                     le_change(cursor_x, cursor_y, 'G');
711                   else
712                     le_change(cursor_x, cursor_y, 'g');
713                   break;
714                 case SDLK_h:
715                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
716                     le_change(cursor_x, cursor_y, 'H');
717                   else
718                     le_change(cursor_x, cursor_y, 'h');
719                   break;
720                 case SDLK_i:
721                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
722                     le_change(cursor_x, cursor_y, 'I');
723                   else
724                     le_change(cursor_x, cursor_y, 'i');
725                   break;
726                 case SDLK_j:
727                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
728                     le_change(cursor_x, cursor_y, 'J');
729                   else
730                     le_change(cursor_x, cursor_y, 'j');
731                   break;
732                 case SDLK_x:
733                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
734                     le_change(cursor_x, cursor_y, 'X');
735                   else
736                     le_change(cursor_x, cursor_y, 'x');
737                   break;
738                 case SDLK_y:
739                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
740                     le_change(cursor_x, cursor_y, 'Y');
741                   else
742                     le_change(cursor_x, cursor_y, 'y');
743                   break;
744                 case SDLK_LEFTBRACKET:
745                   le_change(cursor_x, cursor_y, '[');
746                   break;
747                 case SDLK_RIGHTBRACKET:
748                   le_change(cursor_x, cursor_y, ']');
749                   break;
750                 case SDLK_HASH:
751                 case SDLK_3:
752                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
753                     le_change(cursor_x, cursor_y, '#');
754                   break;
755                 case SDLK_DOLLAR:
756                 case SDLK_4:
757                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
758                     le_change(cursor_x, cursor_y, '$');
759                   break;
760                 case SDLK_BACKSLASH:
761                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
762                     le_change(cursor_x, cursor_y, '|');
763                   else
764                     le_change(cursor_x, cursor_y, '\\');
765                   break;
766                 case SDLK_CARET:
767                   le_change(cursor_x, cursor_y, '^');
768                   break;
769                 case SDLK_AMPERSAND:
770                 case SDLK_6:
771                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
772                     le_change(cursor_x, cursor_y, '&');
773                   break;
774                 case SDLK_EQUALS:
775                 case SDLK_0:
776                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
777                     le_change(cursor_x, cursor_y, '=');
778                   else          /* let's add a bad guy */
779                     le_change(cursor_x, cursor_y, '0');
780                   break;
781                 case SDLK_1:
782                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
783                     le_change(cursor_x, cursor_y, '!');
784                   else          /* let's add a bad guy */
785                     le_change(cursor_x, cursor_y, '1');
786                   break;
787                 case SDLK_2:
788                   le_change(cursor_x, cursor_y, '2');
789                   break;
790                 case SDLK_PLUS:
791                   if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
792                     le_change(cursor_x, cursor_y, '*');
793                   break;
794                 default:
795                   break;
796                 }
797               break;
798             case SDL_KEYUP:     /* key released */
799               switch(event.key.keysym.sym)
800                 {
801                 case SDLK_LCTRL:
802                   fire = DOWN;
803                   break;
804                 default:
805                   break;
806                 }
807               break;
808             case SDL_MOUSEBUTTONDOWN:
809               if(event.button.button == SDL_BUTTON_LEFT)
810                 {
811                   le_mouse_pressed = YES;
812
813                   selection.x1 = event.motion.x + pos_x;
814                   selection.y1 = event.motion.y;
815                   selection.x2 = event.motion.x + pos_x;
816                   selection.y2 = event.motion.y;
817                 }
818               break;
819             case SDL_MOUSEBUTTONUP:
820               if(event.button.button == SDL_BUTTON_LEFT)
821                 {
822                   le_mouse_pressed = NO;
823                 }
824               break;
825             case SDL_MOUSEMOTION:
826               if(!show_menu)
827                 {
828                   x = event.motion.x;
829                   y = event.motion.y;
830
831                   cursor_x = ((int)(pos_x + x) / 32) * 32;
832                   cursor_y = ((int) y / 32) * 32;
833
834                   if(le_mouse_pressed == YES)
835                     {
836                       selection.x2 = x + pos_x;
837                       selection.y2 = y;
838                     }
839                 }
840               break;
841             case SDL_QUIT:      // window closed
842               done = DONE_QUIT;
843               break;
844             default:
845               break;
846             }
847         }
848
849
850     }
851
852   if(le_current_level != NULL)
853     {
854       if(event.type == SDL_KEYDOWN || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > screen->w-64 && event.motion.x < screen->w &&
855                                        event.motion.y > 0 && event.motion.y < screen->h)))
856         {
857           /* Check for button events */
858           button_event(&le_test_level_bt,&event);
859           if(button_get_state(&le_test_level_bt) == BN_CLICKED)
860             le_testlevel();
861           button_event(&le_next_level_bt,&event);
862           if(button_get_state(&le_next_level_bt) == BN_CLICKED)
863             {
864               if(le_level < le_level_subset.levels)
865                 le_goto_level(++le_level);
866             }
867           button_event(&le_previous_level_bt,&event);
868           if(button_get_state(&le_previous_level_bt) == BN_CLICKED)
869             {
870               if(le_level > 1)
871                 le_goto_level(--le_level);
872             }
873           button_event(&le_rubber_bt,&event);
874           if(button_get_state(&le_rubber_bt) == BN_CLICKED)
875             le_current_tile = '.';
876           button_event(&le_select_mode_one_bt,&event);
877           if(button_get_state(&le_select_mode_one_bt) == BN_CLICKED)
878             le_selection_mode = CURSOR;
879           button_event(&le_select_mode_two_bt,&event);
880           if(button_get_state(&le_select_mode_two_bt) == BN_CLICKED)
881             le_selection_mode = SQUARE;
882           button_event(&le_bad_bsod_bt,&event);
883           if(button_get_state(&le_bad_bsod_bt) == BN_CLICKED)
884             le_current_tile = '0';
885           button_event(&le_settings_bt,&event);
886           if(button_get_state(&le_settings_bt) == BN_CLICKED)
887             {
888               if(show_menu == NO)
889                 {
890                   menu_set_current(&level_settings_menu);
891                   show_menu = YES;
892                 }
893               else
894                 {
895                   menu_set_current(&leveleditor_menu);
896                   show_menu = NO;
897                 }
898             }
899         }
900     }
901
902   if(le_mouse_pressed)
903     {
904       le_change(cursor_x, cursor_y, le_current_tile);
905     }
906
907 }
908
909 void le_highlight_selection()
910 {
911   int x,y,i;
912   int x1, x2, y1, y2;
913
914   if(selection.x1 < selection.x2)
915     {
916       x1 = selection.x1;
917       x2 = selection.x2;
918     }
919   else
920     {
921       x1 = selection.x2;
922       x2 = selection.x1;
923     }
924   if(selection.y1 < selection.y2)
925     {
926       y1 = selection.y1;
927       y2 = selection.y2;
928     }
929   else
930     {
931       y1 = selection.y2;
932       y2 = selection.y1;
933     }
934
935   x1 /= 32;
936   x2 /= 32;
937   y1 /= 32;
938   y2 /= 32;
939
940   fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
941 }
942
943 void le_change(float x, float y, unsigned char c)
944 {
945   if(le_current_level != NULL)
946     {
947       int xx,yy,i;
948       int x1, x2, y1, y2;
949
950       /*  level_changed = YES; */
951
952       switch(le_selection_mode)
953         {
954         case CURSOR:
955           level_change(le_current_level,x,y,c);
956
957           yy = ((int)y / 32);
958           xx = ((int)x / 32);
959
960           /* if there is a bad guy over there, remove it */
961           for(i = 0; i < num_bad_guys; ++i)
962             if (bad_guys[i].base.alive)
963               if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
964                 bad_guys[i].base.alive = NO;
965
966           if(c == '0')  /* if it's a bad guy */
967             add_bad_guy(xx*32, yy*32, BAD_BSOD);
968           else if(c == '1')
969             add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
970           else if(c == '2')
971             add_bad_guy(xx*32, yy*32, BAD_MONEY);
972
973           break;
974         case SQUARE:
975           if(selection.x1 < selection.x2)
976             {
977               x1 = selection.x1;
978               x2 = selection.x2;
979             }
980           else
981             {
982               x1 = selection.x2;
983               x2 = selection.x1;
984             }
985           if(selection.y1 < selection.y2)
986             {
987               y1 = selection.y1;
988               y2 = selection.y2;
989             }
990           else
991             {
992               y1 = selection.y2;
993               y2 = selection.y1;
994             }
995
996           x1 /= 32;
997           x2 /= 32;
998           y1 /= 32;
999           y2 /= 32;
1000
1001           /* if there is a bad guy over there, remove it */
1002           for(i = 0; i < num_bad_guys; ++i)
1003             if(bad_guys[i].base.alive)
1004               if(bad_guys[i].base.x/32 >= x1 && bad_guys[i].base.x/32 <= x2
1005                   && bad_guys[i].base.y/32 >= y1 && bad_guys[i].base.y/32 <= y2)
1006                 bad_guys[i].base.alive = NO;
1007
1008           for(xx = x1; xx <= x2; xx++)
1009             for(yy = y1; yy <= y2; yy++)
1010               {
1011                 level_change(le_current_level, xx*32, yy*32, c);
1012
1013                 if(c == '0')  // if it's a bad guy
1014                   add_bad_guy(xx*32, yy*32, BAD_BSOD);
1015                 else if(c == '1')
1016                   add_bad_guy(xx*32, yy*32, BAD_LAPTOP);
1017                 else if(c == '2')
1018                   add_bad_guy(xx*32, yy*32, BAD_MONEY);
1019               }
1020           break;
1021         default:
1022           break;
1023         }
1024     }
1025 }
1026
1027 void le_testlevel()
1028 {
1029   level_save(le_current_level,"test",le_level);
1030   gameloop("test",le_level, ST_GL_TEST);
1031   menu_set_current(&leveleditor_menu);
1032   arrays_init();
1033   level_load_gfx(le_current_level);
1034   loadshared();
1035   le_activate_bad_guys();
1036 }
1037
1038 void le_showhelp()
1039 {
1040   SDL_Event event;
1041   int i, done;
1042   char *text[] = {
1043                    "X/x - Brick0",
1044                    "Y/y - Brick1",
1045                    "A/B/! - Box full",
1046                    "a - Box empty",
1047                    "C-F - Cloud0",
1048                    "c-f - Cloud1",
1049                    "G-J - Bkgd0",
1050                    "g-j - Bkgd1",
1051                    "# - Solid0",
1052                    "[ - Solid1",
1053                    "= - Solid2",
1054                    "] - Solid3",
1055                    "$ - Distro",
1056                    "^ - Waves",
1057                    "* - Poletop",
1058                    "| - Pole",
1059                    "\\ - Flag",
1060                    "& - Water",
1061                    "0-2 - BadGuys",
1062                    "./Del - Remove tile",
1063                    "F9 - Show/Hide Grid",
1064                    "F3 - Change Selection Mode",
1065                    "Esc - Menu"};
1066
1067
1068   text_drawf(&blue_text, "- Help -", 0, 30, A_HMIDDLE, A_TOP, 2, NO_UPDATE);
1069   text_draw(&gold_text, "Keys:", 80, 60, 1, NO_UPDATE);
1070
1071   for(i = 0; i < sizeof(text)/sizeof(char *); i++)
1072     text_draw(&white_text, text[i], 40, 90+(i*16), 1, NO_UPDATE);
1073
1074   text_drawf(&gold_text, "Press Any Key to Continue", 0, 460, A_HMIDDLE, A_TOP, 1, NO_UPDATE);
1075
1076   flipscreen();
1077
1078   done = 0;
1079
1080   while(done == 0)
1081     while(SDL_PollEvent(&event))
1082       switch(event.type)
1083         {
1084         case SDL_MOUSEBUTTONDOWN:               // mouse pressed
1085         case SDL_KEYDOWN:               // key pressed
1086           done = 1;
1087           break;
1088         default:
1089           break;
1090         }
1091 }