1 /*
2     sdldisplay.c
3 
4     Copyright (C) 2010-2019 Amf
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <SDL/SDL.h>
25 #include <SDL/SDL_image.h>
26 #include <libintl.h>
27 #include <locale.h>
28 #include <ctype.h>
29 
30 #include "chroma.h"
31 #include "menu.h"
32 #include "level.h"
33 #include "display.h"
34 #include "graphics.h"
35 #include "colours.h"
36 #include "sdlfont.h"
37 #include "sdlscreen.h"
38 #include "util.h"
39 #include "actions.h"
40 #include "xmlparser.h"
41 
42 #define MOUSE_TIMEOUT_CLICK 200
43 #define MOUSE_TIMEOUT_MOVE 1000
44 
45 char options_colours[FILENAME_MAX] = COLOURS_DEFAULT;
46 char options_graphics[FILENAME_MAX] = GRAPHICS_DEFAULT;
47 int options_graphic_level = 0;
48 int options_sdl_fullscreen = 0;
49 int options_sdl_width = 0;
50 int options_sdl_height = 0;
51 int options_sdl_delay = 100;
52 int options_sdl_player_delay = 200;
53 int options_sdl_replay_delay = 200;
54 int options_sdl_undo_delay = 200;
55 int options_sdl_size_x = 0;
56 int options_sdl_size_y = 0;
57 int options_debug = 0;
58 #ifdef XOR_COMPATIBILITY
59 int options_xor_options = 0;
60 int options_xor_mode = 1;
61 int options_xor_display = 0;
62 
63 int xor_map_scale = 4;
64 int xor_map_x_offset = 0;
65 int xor_map_y_offset = 0;
66 #endif
67 
68 #ifdef ENIGMA_COMPATIBILITY
69 int options_enigma_options = 0;
70 int options_enigma_mode = 1;
71 #endif
72 
73 int actions[SDLK_LAST];
74 int actions_mouse[3][MOUSE_BUTTONS_MAX];
75 
76 int display_offset_x;
77 int display_offset_y;
78 int display_offset_pixels_x = 0;
79 int display_offset_pixels_y = 0;
80 int display_start_x;
81 int display_start_y;
82 int display_end_x;
83 int display_end_y;
84 int display_pieces_x;
85 int display_pieces_y;
86 int display_focus_x;
87 int display_focus_y;
88 int display_bar_pixels = 0;
89 float display_animation;
90 int display_animation_x;
91 int display_animation_y;
92 int display_border_x = 3;
93 int display_border_y = 3;
94 
95 struct SDL_Surface* psurfacelogo = NULL;
96 struct SDL_Surface* psurfacelogosmall = NULL;
97 
98 extern int font_height;
99 
100 extern SDL_Surface *screen_surface;
101 
102 extern int screen_width;
103 extern int screen_height;
104 extern int screen_fullscreen;
105 
106 extern int font_height;
107 extern int font_width;
108 extern int font_border;
109 extern int font_padding;
110 
111 extern int font_size_game;
112 
113 extern char *piece_name[];
114 extern char *action_name[];
115 extern char *action_shortname[];
116 
117 extern int move_x[];
118 extern int move_y[];
119 
120 extern struct graphics* pdisplaygraphics;
121 extern struct colours* pdisplaycolours;
122 
123 extern char options_graphics[];
124 extern char options_colours[];
125 
126 extern int *editor_piece_maps[];
127 
128 void display_movers(struct level* plevel, int redraw);
129 void displayshadowed_movers(struct level* plevel, int redraw);
130 
131 void displayshadowed_level(struct level* plevel);
132 
133 void display_clip(struct level* plevel, int clip);
134 void display_screensizemenu();
135 
136 void display_initactions();
137 char *display_keyname(SDLKey key);
138 void display_addkeytomenu(struct menu* pmenu, int action, char *text);
139 void display_options_keys();
140 void display_options_mouse();
141 void display_options_size();
142 void display_options_debug();
143 
144 #ifdef XOR_COMPATIBILITY
145 void xor_focus(struct level* plevel);
146 #endif
147 
148 void display_options_othergames();
149 
150 #define SCREENREDRAW_LEVEL        1
151 #define SCREENREDRAW_BAR        2
152 #define SCREENREDRAW_ALL        (SCREENREDRAW_BAR | SCREENREDRAW_LEVEL)
153 
display_init(int argc,char ** argv)154 void display_init(int argc, char **argv)
155 {
156     char buffer[256];
157     struct SDL_Surface* psurfaceicon;
158     int i, j, k, w, h;
159 
160     if(SDL_Init(SDL_INIT_VIDEO) < 0)
161     {
162         snprintf(buffer, 256, gettext("Unable to initalise SDL: %s"), SDL_GetError());
163         fatal(buffer);
164     }
165 
166     display_options_load();
167 
168     if(argc > 0)
169     {
170         for(i = 1; i < argc; i ++)
171         {
172             if(strcmp(argv[i], "--window") == 0 || strcmp(argv[i], "--windowed") == 0 || strcmp(argv[i], "-w") == 0)
173                 options_sdl_fullscreen = 0;
174 
175             if(strcmp(argv[i], "--fullscreen") == 0 || strcmp(argv[i], "-fs") == 0 || strcmp(argv[i], "-f") == 0)
176                 options_sdl_fullscreen = 1;
177 
178             if(strcmp(argv[i], "--auto") == 0 || strcmp(argv[i], "auto") == 0)
179             {
180                 options_sdl_width = 0;
181                 options_sdl_height = 0;
182             }
183 
184             if(argv[i] != NULL && isdigit(argv[i][0]))
185             {
186                 w = 0; h = 0;
187 
188                 strncpy(buffer, argv[i], sizeof(buffer));
189                 buffer[sizeof(buffer) - 1] = 0;
190 
191                 j = 0;
192                 while(j < strlen(buffer) && isdigit(buffer[j]))
193                     j ++;
194 
195                 k = j;
196 
197                 if(j != strlen(buffer))
198                 {
199                     while(j < strlen(buffer) && !isdigit(buffer[j]))
200                         j ++;
201                     if(j != strlen(buffer))
202                     {
203                         h = atoi(buffer + j);
204                     }
205                 }
206                 buffer[k] = 0;
207 
208                 w = atoi(buffer);
209 
210                 if(w != 0 && h != 0)
211                 {
212                     options_sdl_width = w;
213                     options_sdl_height = h;
214                 }
215             }
216 
217         }
218     }
219 
220     atexit(display_quit);
221 
222     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
223     SDL_EnableUNICODE(1);
224 
225     psurfaceicon = graphics_loadimage("icon.png");
226     if(psurfaceicon != NULL)
227         SDL_WM_SetIcon(psurfaceicon, NULL);
228 
229     screen_size(options_sdl_width, options_sdl_height, options_sdl_fullscreen);
230     screen_clear(255, 255, 255);
231 
232     font_init();
233     font_resize();
234     colours_init();
235     graphics_init();
236 
237 }
238 
display_quit()239 void display_quit()
240 {
241     SDL_Quit();
242 }
243 
display_piece(struct level * plevel,int p,int x,int y,int d)244 void display_piece(struct level* plevel, int p, int x, int y, int d)
245 {
246     SDL_Surface *image;
247 
248     SDL_Rect srect;
249     SDL_Rect drect;
250     int alpha;
251     int px, py;
252     int b;
253     int bimage[4];
254     int i;
255     int bsizex, bsizey, boffset;
256     int op;
257 
258     int xstart = 0, xend = 0, xsize = 0, xpos = 0;
259 
260     if(p < PIECE_SPACE || p >= PIECE_MAX)
261         return;
262 
263 #ifdef XOR_COMPATIBILITY
264     if(plevel->switched && (p == PIECE_WALL || p == PIECE_SPACE))
265         p = PIECE_DARKNESS;
266 #endif
267 
268     op = p;
269 
270     px = x * pdisplaygraphics->size_x + display_offset_pixels_x;
271     py = y * pdisplaygraphics->size_y + display_offset_pixels_y;
272     if(d != MOVE_NONE
273             && p != PIECE_SPACE && !isexplosion(p)
274 #ifdef XOR_COMPATIBILITY
275             && p != PIECE_TELEPORT
276 #endif
277             )
278     {
279         if(d == MOVE_LEFT)
280             px = px - display_animation_x;
281         if(d == MOVE_RIGHT)
282             px = px + display_animation_x;
283         if(d == MOVE_UP)
284             py = py - display_animation_y;
285         if(d == MOVE_DOWN)
286             py = py + display_animation_y;
287     }
288 
289     if(isexplosion(p) && !(pdisplaygraphics->image_flags[p] & GRAPHICS_KEY))
290     {
291         alpha = 255 * (1 - display_animation);
292         SDL_SetAlpha(pdisplaygraphics->image[p][IMAGE_PIECE], SDL_SRCALPHA, alpha);
293     }
294     if(isnewexplosion(p))
295     {
296         p += PIECE_EXPLOSION_FIRST - PIECE_EXPLOSION_NEW_FIRST;
297         if(!(pdisplaygraphics->image_flags[p] & GRAPHICS_KEY))
298         {
299             alpha = 255 * display_animation;
300             SDL_SetAlpha(pdisplaygraphics->image[p][IMAGE_PIECE], SDL_SRCALPHA, alpha);
301         }
302     }
303 
304     image = pdisplaygraphics->image[p][IMAGE_PIECE];
305 
306     srect.x = 0;
307     srect.y = 0;
308     srect.w = pdisplaygraphics->size_x;
309     srect.h = pdisplaygraphics->size_y;
310 
311     if(image->w > pdisplaygraphics->size_x)
312     {
313         xstart = 0;
314         xend = image->w / pdisplaygraphics->size_x;
315         xsize = 1;
316         xpos = 0;
317 
318         if(pdisplaygraphics->image_flags[p] & GRAPHICS_BEVEL)
319             xend -= 4;
320 
321         if(pdisplaygraphics->image_flags[p] & GRAPHICS_BEVEL16)
322             xsize = 16;
323 
324         if(pdisplaygraphics->image_flags[p] & GRAPHICS_MOVER)
325         {
326             xsize = 5;
327 
328             if(d == MOVE_LEFT)
329                 xpos += 1;
330             if(d == MOVE_UP)
331                 xpos += 2;
332             if(d == MOVE_RIGHT)
333                 xpos += 3;
334             if(d == MOVE_DOWN)
335                 xpos += 4;
336         }
337 
338         /* If we're plotting the players */
339         if(p == PIECE_PLAYER_ONE || p == PIECE_PLAYER_TWO)
340         {
341             /* and there's an image for the swapped player */
342             if(xend > xstart + xsize)
343             {
344                 /* then use it if the player is swapped out */
345                 if(plevel->player != (p & 1) && plevel->player != 2)
346                     xpos += xsize;
347             }
348         }
349 
350         if(pdisplaygraphics->image_flags[p] & GRAPHICS_BEVEL16)
351         {
352             i = 15;
353                 b = level_data(plevel, x, y) & BEVEL_ALL;
354 
355             if(b & BEVEL_U)
356                 i -= 1;
357             if(b & BEVEL_R)
358                 i -= 2;
359             if(b & BEVEL_D)
360                 i -= 4;
361             if(b & BEVEL_L)
362                 i -= 8;
363 
364             xpos += i;
365         }
366 
367         if(pdisplaygraphics->image_flags[p] & GRAPHICS_ANIMATE)
368         {
369             b = (xend - xstart) / xsize;
370 
371             if(!isexplosion(p))
372                 b = b * display_animation;
373             else
374                   b = b * ((display_animation + (isnewexplosion(op) ? 0 : 1)) * 0.5);
375 
376             xpos += b * xsize;
377         }
378         else if(pdisplaygraphics->image_flags[p] & GRAPHICS_RANDOM)
379         {
380             b = (xend - xstart) / xsize;
381 
382             if(p == PIECE_SPACE)
383                 b = (level_data(plevel, x, y) & 0xff) % b;
384             else
385                 b = ((level_data(plevel, x, y) & 0xff00) / 0x100) % b;
386 
387             xpos += b * xsize;
388         }
389         else if(pdisplaygraphics->image_flags[p] & GRAPHICS_TILE)
390         {
391             b = x % ((xend - xstart) / xsize);
392             if(b < 0)
393                 b += (xend - xstart) / xsize;
394             xpos += b * xsize;
395 
396             b = y % (image->h / pdisplaygraphics->size_y);
397             if(b < 0)
398                 b += image->h / pdisplaygraphics->size_y;
399             srect.y = b * pdisplaygraphics->size_y;
400         }
401 
402         srect.x = (xstart + xpos) * pdisplaygraphics->size_x;
403     }
404 
405     drect.x = px;
406     drect.y = py;
407     drect.w = pdisplaygraphics->size_x;
408     drect.h = pdisplaygraphics->size_y;
409 
410     /* Plot piece */
411     SDL_BlitSurface(image, &srect, screen_surface, &drect);
412 
413     /* Plot bevelling */
414     if(pdisplaygraphics->image_flags[p] & GRAPHICS_BEVEL)
415     {
416         b = level_data(plevel, x, y) & BEVEL_ALL;
417         if(b != 0)
418         {
419             bsizex = pdisplaygraphics->size_x / 2;
420             bsizey = pdisplaygraphics->size_y / 2;
421             boffset = (xend - 1) * pdisplaygraphics->size_x;
422 
423             for(i = 0; i < 4; i ++)
424                 bimage[i] = 0;
425 
426             if(b & BEVEL_L)
427             {
428                 if(b & BEVEL_U)
429                     bimage[0] = 3 * pdisplaygraphics->size_x;
430                 else
431                     bimage[0] = 1 * pdisplaygraphics->size_x;
432 
433                 if(b & BEVEL_D)
434                     bimage[2] = 3 * pdisplaygraphics->size_x;
435                 else
436                     bimage[2] = 1 * pdisplaygraphics->size_x;
437             }
438             else
439             {
440                 if(b & BEVEL_U)
441                     bimage[0] = 2 * pdisplaygraphics->size_x;
442                 if(b & BEVEL_D)
443                     bimage[2] = 2 * pdisplaygraphics->size_x;
444             }
445 
446             if(b & BEVEL_R)
447             {
448                 if(b & BEVEL_U)
449                     bimage[1] = 3 * pdisplaygraphics->size_x;
450                 else
451                     bimage[1] = 1 * pdisplaygraphics->size_x;
452 
453                 if(b & BEVEL_D)
454                     bimage[3] = 3 * pdisplaygraphics->size_x;
455                 else
456                     bimage[3] = 1 * pdisplaygraphics->size_x;
457             }
458             else
459             {
460                 if(b & BEVEL_U)
461                     bimage[1] = 2 * pdisplaygraphics->size_x;
462                 if(b & BEVEL_D)
463                     bimage[3] = 2 * pdisplaygraphics->size_x;
464             }
465 
466             if(b & BEVEL_TL)
467                 bimage[0] = 4 * pdisplaygraphics->size_x;
468             if(b & BEVEL_TR)
469                 bimage[1] = 4 * pdisplaygraphics->size_x;
470             if(b & BEVEL_BL)
471                 bimage[2] = 4 * pdisplaygraphics->size_x;
472             if(b & BEVEL_BR)
473                 bimage[3] = 4 * pdisplaygraphics->size_x;
474 
475             for(i = 0; i < 4; i ++)
476             {
477                 if(bimage[i] != 0)
478                 {
479                     srect.x = boffset + bimage[i] + ((i & 1) ? bsizex : 0);
480                     srect.y = (i & 2) ? bsizey : 0;
481                     srect.w = bsizex;
482                     srect.h = bsizey;
483 
484                     drect.x = px + ((i & 1) ? bsizex : 0);
485                     drect.y = py + ((i & 2) ? bsizey : 0);
486                     drect.w = bsizex;
487                     drect.h = bsizey;
488 
489                     SDL_BlitSurface(image, &srect, screen_surface, &drect);
490                 }
491             }
492         }
493     }
494 }
495 
display_redrawpiece(int p,int x,int y,int d)496 void display_redrawpiece(int p, int x, int y, int d)
497 {
498     int dx, dy;
499 
500     dx = x * pdisplaygraphics->size_x + display_offset_pixels_x;
501     dy = y * pdisplaygraphics->size_y + display_offset_pixels_y;
502     if(d != MOVE_NONE && p != PIECE_SPACE && !isexplosion(p))
503     {
504         if(d == MOVE_LEFT) { dx = dx - display_animation_x; }
505         if(d == MOVE_RIGHT) { dx = dx + display_animation_x; }
506         if(d == MOVE_UP) { dy = dy - display_animation_y; }
507         if(d == MOVE_DOWN) { dy = dy + display_animation_y; }
508     }
509 
510     screen_redraw(dx, dy, pdisplaygraphics->size_x, pdisplaygraphics->size_y);
511 }
512 
display_pieceabsolute(int p,int x,int y,int redraw)513 void display_pieceabsolute(int p, int x, int y, int redraw)
514 {
515     SDL_Rect srect;
516     SDL_Rect drect;
517 
518     srect.x = 0;
519     srect.y = 0;
520     srect.w = pdisplaygraphics->size_x;
521     srect.h = pdisplaygraphics->size_y;
522 
523     drect.x = x;
524     drect.y = y;
525     drect.w = pdisplaygraphics->size_x;
526     drect.h = pdisplaygraphics->size_y;
527 
528     if(p != PIECE_SPACE && p!= PIECE_CURSOR)
529         SDL_BlitSurface(pdisplaygraphics->image[PIECE_SPACE][IMAGE_PIECE], &srect, screen_surface, &drect);
530 
531     SDL_BlitSurface(pdisplaygraphics->image[p][IMAGE_PIECE], &srect, screen_surface, &drect);
532 
533     if(redraw)
534         screen_redraw(x, y, pdisplaygraphics->size_x, pdisplaygraphics->size_y);
535 }
536 
display_focus(struct level * plevel,int refocus)537 int display_focus(struct level* plevel, int refocus)
538 {
539     int ox, oy;
540     int px, py;
541 
542     int maxx, maxy;
543 
544 #ifdef XOR_COMPATIBILITY
545     if(plevel->mode == MODE_XOR && options_xor_display)
546     {
547         ox = display_offset_pixels_x;
548         oy = display_offset_pixels_y;
549 
550         display_start_x = plevel->view_x[plevel->player];
551         display_start_y = plevel->view_y[plevel->player];
552 
553         display_end_x = display_start_x + 8;
554         display_end_y = display_start_y + 8;
555 
556         display_offset_pixels_x = (screen_width - pdisplaygraphics->size_x * 8) / 2;
557         display_offset_pixels_y = (screen_height - display_bar_pixels - pdisplaygraphics->size_y * 8) / 2;
558 
559         display_offset_pixels_x -= display_start_x * pdisplaygraphics->size_x;
560         display_offset_pixels_y -= display_start_y * pdisplaygraphics->size_y;
561 
562         if(display_offset_pixels_x != ox || display_offset_pixels_y != oy)
563             return 1;
564         else
565             return 0;
566     }
567 #endif
568 
569     px = plevel->player_x[plevel->player] * pdisplaygraphics->size_x;
570     py = plevel->player_y[plevel->player] * pdisplaygraphics->size_y;
571     ox = display_offset_pixels_x;
572     oy = display_offset_pixels_y;
573 
574     display_border_x = pdisplaygraphics->size_x * 3;
575     display_border_y = pdisplaygraphics->size_y * 3;
576 
577     maxx = (plevel->size_x * pdisplaygraphics->size_x - screen_width);
578     maxy = (plevel->size_y * pdisplaygraphics->size_y - screen_height + display_bar_pixels);
579 
580     if((plevel->size_x - 1) * pdisplaygraphics->size_x < screen_width)
581     {
582         display_offset_pixels_x = (screen_width - (plevel->size_x * pdisplaygraphics->size_x)) / 2;
583     }
584     else
585     {
586         if(refocus)
587         {
588             if(px < -(display_offset_pixels_x - display_border_x))
589                 display_offset_pixels_x = -(px - display_border_x);
590             if(px >= -(display_offset_pixels_x - screen_width + display_border_x + pdisplaygraphics->size_x))
591                 display_offset_pixels_x = -(px - screen_width + display_border_x + pdisplaygraphics->size_x);
592         }
593 
594         if(display_offset_pixels_x > 0)
595             display_offset_pixels_x = 0;
596         if(display_offset_pixels_x < -maxx)
597             display_offset_pixels_x = -maxx;
598 
599     }
600 
601     if((plevel->size_y - 1) * pdisplaygraphics->size_y < screen_height)
602     {
603         display_offset_pixels_y = (screen_height - display_bar_pixels - (plevel->size_y * pdisplaygraphics->size_y)) / 2;
604     }
605     else
606     {
607         if(refocus)
608         {
609             if(py < -(display_offset_pixels_y - display_border_y))
610                 display_offset_pixels_y = -(py - display_border_y);
611             if(py >= -(display_offset_pixels_y - screen_height + display_bar_pixels + display_border_y + pdisplaygraphics->size_y))
612                 display_offset_pixels_y = -(py - screen_height + display_bar_pixels + display_border_y + pdisplaygraphics->size_y);
613         }
614 
615         if(display_offset_pixels_y > 0)
616             display_offset_pixels_y = 0;
617         if(display_offset_pixels_y < -maxy)
618             display_offset_pixels_y = -maxy;
619     }
620 
621     /* Calculate start and end points */
622     display_start_x = -display_offset_pixels_x / pdisplaygraphics->size_x;
623     display_end_x = (-display_offset_pixels_x + screen_width + pdisplaygraphics->size_x - 1) / pdisplaygraphics->size_x;
624     if(display_offset_pixels_x > 0)
625         display_start_x --;
626 
627     display_start_y = -display_offset_pixels_y / pdisplaygraphics->size_y;
628     display_end_y = (-display_offset_pixels_y + screen_height + pdisplaygraphics->size_y - display_bar_pixels - 1) / pdisplaygraphics->size_y;
629     if(display_offset_pixels_y > 0)
630         display_start_y --;
631 
632     if(pdisplaygraphics->flags & GRAPHICS_BACKGROUND)
633     {
634         if(display_start_x < 0)
635             display_start_x = 0;
636         if(display_end_x > plevel->size_x)
637             display_end_x = plevel->size_x;
638         if(display_start_y < 0)
639             display_start_y = 0;
640         if(display_end_y > plevel->size_y)
641             display_end_y = plevel->size_y;
642     }
643 
644     if(display_offset_pixels_x != ox || display_offset_pixels_y != oy)
645         return 1;
646     else
647         return 0;
648 }
649 
650 #ifdef XOR_COMPATIBILITY
display_map_piece(struct level * plevel,int p,int x,int y,int redraw)651 void display_map_piece(struct level* plevel, int p, int x, int y, int redraw)
652 {
653     SDL_Rect rect;
654 
655     rect.x = xor_map_x_offset + x * xor_map_scale;
656     rect.y = xor_map_x_offset + y * xor_map_scale;
657     rect.w = xor_map_scale;
658     rect.h = xor_map_scale;
659 
660     if(plevel->player != 2)
661     {
662     if(x < plevel->size_x / 2 && y < plevel->size_y / 2 && !(plevel->mapped & MAPPED_TOP_LEFT))
663         p = PIECE_UNKNOWN;
664     if(x >= plevel->size_x / 2 && y < plevel->size_y / 2 && !(plevel->mapped & MAPPED_TOP_RIGHT))
665         p = PIECE_UNKNOWN;
666     if(x < plevel->size_x / 2 && y >= plevel->size_y / 2 && !(plevel->mapped & MAPPED_BOTTOM_LEFT))
667         p = PIECE_UNKNOWN;
668     if(x >= plevel->size_x / 2 && y >= plevel->size_y / 2 && !(plevel->mapped & MAPPED_BOTTOM_RIGHT))
669         p = PIECE_UNKNOWN;
670     }
671 
672     switch(p)
673     {
674         case PIECE_UNKNOWN:
675             SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0x00, 0x00, 0x00));
676             break;
677 
678         case PIECE_WALL:
679             SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0x7f, 0x7f, 0x7f));
680             break;
681 
682         case PIECE_STAR:
683             SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0xff, 0xa0, 0x00));
684             if(xor_map_scale > 2)
685             {
686                 rect.x ++;
687                 rect.y ++;
688                 rect.w -= 2;
689                 rect.h -= 2;
690                 SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0xff, 0xff, 0x33));
691             }
692             break;
693 
694         case PIECE_DOOR:
695             SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0x00, 0x80, 0xff));
696             if(xor_map_scale > 2)
697             {
698                 rect.x ++;
699                 rect.y ++;
700                 rect.w -= 2;
701                 rect.h -= 2;
702                 SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0x66, 0xb3, 0xff));
703             }
704             break;
705 
706         default:
707             SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0xff, 0xff, 0xff));
708             break;
709     }
710 
711     if(redraw)
712     {
713 
714     rect.x = xor_map_x_offset + x * xor_map_scale;
715     rect.y = xor_map_x_offset + y * xor_map_scale;
716     rect.w = xor_map_scale;
717     rect.h = xor_map_scale;
718         screen_redraw(rect.x, rect.y, rect.w, rect.h);
719         }
720 }
721 
display_map(struct level * plevel)722 void display_map(struct level* plevel)
723 {
724     int i, j;
725 
726     xor_map_scale = screen_width / 256;
727     if(xor_map_scale < 1)
728         xor_map_scale = 1;
729 
730     display_clip(plevel, 0);
731 
732     for(j = 0; j < plevel->size_y; j ++)
733     {
734         for(i = 0; i < plevel->size_y; i ++)
735         {
736             display_map_piece(plevel, level_piece(plevel, i, j), i, j, 0);
737         }
738     }
739 
740     /* Redraw map */
741     screen_redraw(xor_map_x_offset, xor_map_y_offset, plevel->size_x * xor_map_scale, plevel->size_y * xor_map_scale);
742 }
743 #endif
744 
display_level(struct level * plevel,int redraw)745 void display_level(struct level* plevel, int redraw)
746 {
747     int x, y;
748     int p;
749     SDL_Rect rect;
750 
751 
752     display_focus(plevel, 0);
753 
754    if(redraw == SCREENREDRAW_ALL && (
755           (pdisplaygraphics->flags & GRAPHICS_BACKGROUND)
756 #ifdef XOR_COMPATIBILITY
757            || (plevel->mode == MODE_XOR && options_xor_display)
758 #endif
759           ))
760     {
761         rect.x = 0;
762         rect.y = 0;
763         rect.w = screen_width;
764         rect.h = screen_height - display_bar_pixels;
765 
766 #ifdef XOR_COMPATIBILITY
767         if(plevel->switched)
768             SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
769         else
770 #endif
771             SDL_FillRect(screen_surface, &rect, SDL_MapRGB(screen_surface->format, pdisplaygraphics->background[0], pdisplaygraphics->background[1], pdisplaygraphics->background[2]));
772     }
773 
774     if(pdisplaygraphics->shadows != NULL)
775     {
776         displayshadowed_level(plevel);
777 #ifdef XOR_COMPATIBILITY
778     if(plevel->mode == MODE_XOR && options_xor_display)
779         display_map(plevel);
780 #endif
781         return;
782     }
783 
784     display_clip(plevel, 1);
785 
786     for(y = display_start_y; y < display_end_y; y ++)
787     {
788         for(x = display_start_x; x < display_end_x; x ++)
789         {
790             p = level_piece(plevel, x, y);
791 
792             /* Moving pieces will be redrawn shortly */
793             if(level_moving(plevel, x, y) != MOVE_NONE)
794                 p = level_previous(plevel, x, y);
795 
796 #ifdef XOR_COMPATIBILITY
797             if(plevel->switched && (p == PIECE_WALL || p == PIECE_SPACE))
798                 p = PIECE_DARKNESS;
799 #endif
800 
801             /* If the piece is transparent, plot a background */
802             if(pdisplaygraphics->image[p][IMAGE_PIECE]->flags & SDL_SRCALPHA)
803             {
804 #ifdef XOR_COMPATIBILITY
805                 if(plevel->switched)
806                     display_piece(plevel, PIECE_DARKNESS, x, y, MOVE_NONE);
807                 else
808 #endif
809                     display_piece(plevel, PIECE_SPACE, x, y, MOVE_NONE);
810             }
811 
812             /* Plot the piece itself */
813             display_piece(plevel, p, x, y, MOVE_NONE);
814         }
815     }
816 
817     display_clip(plevel, 0);
818 
819     if(plevel->mover_first != NULL)
820         display_movers(plevel, 0);
821 
822 #ifdef XOR_COMPATIBILITY
823     if(plevel->mode == MODE_XOR && options_xor_display)
824         display_map(plevel);
825 #endif
826 
827     screen_redraw(0, 0, screen_width, screen_height);
828 
829 }
830 
display_title(struct level * plevel)831 void display_title(struct level* plevel)
832 {
833     SDL_Surface *psurface;
834     SDL_Surface *psurfacetest;
835     SDL_Rect drect;
836     int w;
837 
838     if(options_debug & DEBUG_SPEED)
839         return;
840 
841     if(plevel->title != NULL)
842     {
843         if((strncmp(gettext(plevel->title), "chroma", 6) == 0))
844             psurface = font_render(gettext(plevel->title), -8);
845         else
846             psurface = font_render(plevel->title, COLOUR_WHITE);
847 
848         if(plevel->flags & LEVELFLAG_TESTING)
849         {
850             psurfacetest = font_render(gettext("testing: "), COLOUR_CYAN);
851             w = psurfacetest->w;
852 
853             drect.x = (screen_width - psurface->w - w) / 2;
854             drect.y = screen_height - font_height;;
855             drect.w = psurfacetest->w;;
856             drect.h = psurfacetest->h;
857             SDL_FillRect(screen_surface, &drect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
858             SDL_BlitSurface(psurfacetest, NULL, screen_surface, &drect);
859             SDL_UpdateRects(screen_surface, 1, &drect);
860             SDL_FreeSurface(psurfacetest);
861         }
862         else
863             w = 0;
864 
865         drect.x = ((screen_width - psurface->w - w) / 2) + w;
866         drect.y = screen_height - font_height;
867         drect.w = psurface->w;
868         drect.h = psurface->h;
869         SDL_FillRect(screen_surface, &drect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
870         SDL_BlitSurface(psurface, NULL, screen_surface, &drect);
871         SDL_UpdateRects(screen_surface, 1, &drect);
872         SDL_FreeSurface(psurface);
873     }
874 }
875 
display_moves(struct level * plevel,struct level * plevelreplay)876 void display_moves(struct level* plevel, struct level* plevelreplay)
877 {
878     static int length = 0;
879     char buffer[256];
880     SDL_Surface *psurface;
881     SDL_Surface *pimage;
882     SDL_Rect srect, drect;
883     int w;
884     int moves, moves2;
885 
886     moves = 0;
887     if(plevel->move_current != NULL)
888         moves = plevel->move_current->count;
889 
890     moves2 = -1;
891     if(plevelreplay != NULL)
892     {
893         moves2 = 0;
894         if(plevelreplay->move_last != NULL)
895             moves2 = plevelreplay->move_last->count;
896     }
897     else if(plevel->move_current != plevel->move_last)
898     {
899         if(plevel->move_last != NULL)
900             moves2 = plevel->move_last->count;
901     }
902 
903     if(moves2 != -1)
904         sprintf(buffer, "%s%d/%d",
905                 plevel->flags & LEVELFLAG_PAUSED ? gettext("paused ") :
906                 plevelreplay != NULL ? gettext("replay ") : "",
907                 moves, moves2);
908     else
909         sprintf(buffer, "%s%d",
910                 plevel->flags & LEVELFLAG_PAUSED ? gettext("paused ") : "",
911                 moves);
912 
913     if(plevel->flags & LEVELFLAG_FAILED)
914         sprintf(buffer, gettext("failed"));
915 
916     psurface = font_render(buffer, COLOUR_CYAN);
917 
918     pimage = pdisplaygraphics->image[PIECE_PLAYER_ONE + plevel->player][IMAGE_SMALL];
919     if(pimage != NULL)
920         w = pdisplaygraphics->small_size_x;
921     else
922         w = 0;
923 
924     drect.w = length > (psurface->w + w) ? length : (psurface->w + w);
925     drect.h = psurface->h;
926     drect.x = screen_width - drect.w;
927     drect.y = screen_height - font_height;
928     SDL_FillRect(screen_surface, &drect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
929     drect.x = screen_width - w - psurface->w;
930     SDL_BlitSurface(psurface, NULL, screen_surface, &drect);
931 
932     if(pimage != NULL)
933     {
934         srect.x = 0;
935         srect.y = 0;
936         srect.w = pdisplaygraphics->small_size_x;
937         srect.h = pdisplaygraphics->small_size_y;
938 
939         /* If there is a second small image, use it for a dead player */
940         if(plevel->alive[plevel->player] == 0 && pimage->w > pdisplaygraphics->small_size_x)
941             srect.x += pdisplaygraphics->small_size_x;
942 
943         drect.x = screen_width - w;
944         if(pimage->h < font_height)
945             drect.y += (font_height - pimage->h) / 2;
946 
947         SDL_BlitSurface(pimage, &srect, screen_surface, &drect);
948     }
949 
950     drect.w = (length > psurface->w ? length : psurface->w) + w;
951     drect.h = psurface->h;
952     drect.x = screen_width - drect.w;
953     drect.y = screen_height - font_height;
954     SDL_UpdateRects(screen_surface, 1, &drect);
955     length = psurface->w + w;
956     SDL_FreeSurface(psurface);
957 }
958 
display_stars(struct level * plevel)959 void display_stars(struct level* plevel)
960 {
961     static int length = 0;
962     char buffer[256];
963 
964     SDL_Surface *psurface;
965     SDL_Rect drect;
966     SDL_Surface *pimage;
967     int w;
968     int p;
969 
970     sprintf(buffer, "%d/%d", plevel->stars_caught, plevel->stars_total);
971 
972     if(plevel->stars_exploded != 0)
973         sprintf(buffer, gettext("%d lost"), plevel->stars_exploded);
974 
975     if(plevel->flags & LEVELFLAG_SOLVED && !(plevel->flags & LEVELFLAG_FAILED))
976         sprintf(buffer, gettext("solved"));
977 
978     psurface = font_render(buffer, COLOUR_YELLOW);
979 
980     /* If solved, and there is a small door, use that */
981     if(plevel->flags & LEVELFLAG_SOLVED && !(plevel->flags & LEVELFLAG_FAILED) && pdisplaygraphics->image[PIECE_DOOR][IMAGE_SMALL] != NULL)
982         p = PIECE_DOOR;
983     /* otherwise use a small star */
984     else
985         p = PIECE_STAR;
986 
987     pimage = pdisplaygraphics->image[p][IMAGE_SMALL];
988 
989     if(pimage != NULL)
990         w = pdisplaygraphics->small_size_x;
991     else
992         w = 0;
993 
994     drect.w = length > psurface->w ? length : psurface->w + w;
995     drect.h = psurface->h;
996     drect.x = 0;
997     drect.y = screen_height - font_height;
998 
999     SDL_FillRect(screen_surface, &drect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
1000     drect.x = w;
1001     SDL_BlitSurface(psurface, NULL, screen_surface, &drect);
1002 
1003     if(pimage != NULL)
1004     {
1005         drect.x = 0;
1006         if(pimage->h < font_height)
1007             drect.y += (font_height - pimage->h) / 2;
1008 
1009         SDL_BlitSurface(pimage, NULL, screen_surface, &drect);
1010     }
1011 
1012     drect.w = (length > psurface->w ? length : psurface->w) + w;
1013     drect.h = psurface->h;
1014     drect.x = 0;
1015     drect.y = screen_height - font_height;
1016     SDL_UpdateRects(screen_surface, 1, &drect);
1017     length = psurface->w + w;
1018     SDL_FreeSurface(psurface);
1019 }
1020 
display_bevelsquare(struct level * plevel,int x,int y)1021 int display_bevelsquare(struct level* plevel, int x, int y)
1022 {
1023     int bevel;
1024 
1025     bevel = 0;
1026 
1027     if(level_piece(plevel, x, y) == PIECE_WALL)
1028     {
1029         if(level_piece(plevel, x - 1, y) != PIECE_WALL)
1030             bevel |= BEVEL_L;
1031         if(level_piece(plevel, x + 1, y) != PIECE_WALL)
1032             bevel |= BEVEL_R;
1033         if(level_piece(plevel, x, y - 1) != PIECE_WALL)
1034             bevel |= BEVEL_U;
1035         if(level_piece(plevel, x, y + 1) != PIECE_WALL)
1036             bevel |= BEVEL_D;
1037 
1038         if(((bevel & (BEVEL_L | BEVEL_U)) == 0) && level_piece(plevel, x - 1, y - 1) != PIECE_WALL)
1039             bevel |= BEVEL_TL;
1040         if(((bevel & (BEVEL_R | BEVEL_U)) == 0) && level_piece(plevel, x + 1, y - 1) != PIECE_WALL)
1041             bevel |= BEVEL_TR;
1042         if(((bevel & (BEVEL_L | BEVEL_D)) == 0) && level_piece(plevel, x - 1, y + 1) != PIECE_WALL)
1043             bevel |= BEVEL_BL;
1044         if(((bevel & (BEVEL_R | BEVEL_D)) == 0) && level_piece(plevel, x + 1, y + 1) != PIECE_WALL)
1045             bevel |= BEVEL_BR;
1046     }
1047     else
1048     {
1049         if(level_piece(plevel, x - 1, y) == PIECE_WALL)
1050             bevel |= BEVEL_L;
1051         if(level_piece(plevel, x + 1, y) == PIECE_WALL)
1052             bevel |= BEVEL_R;
1053         if(level_piece(plevel, x, y - 1) == PIECE_WALL)
1054             bevel |= BEVEL_U;
1055         if(level_piece(plevel, x, y + 1) == PIECE_WALL)
1056             bevel |= BEVEL_D;
1057 
1058         if(((bevel & (BEVEL_L | BEVEL_U)) == 0) && level_piece(plevel, x - 1, y - 1) == PIECE_WALL)
1059             bevel |= BEVEL_TL;
1060         if(((bevel & (BEVEL_R | BEVEL_U)) == 0) && level_piece(plevel, x + 1, y - 1) == PIECE_WALL)
1061             bevel |= BEVEL_TR;
1062         if(((bevel & (BEVEL_L | BEVEL_D)) == 0) && level_piece(plevel, x - 1, y + 1) == PIECE_WALL)
1063             bevel |= BEVEL_BL;
1064         if(((bevel & (BEVEL_R | BEVEL_D)) == 0) && level_piece(plevel, x + 1, y + 1) == PIECE_WALL)
1065             bevel |= BEVEL_BR;
1066     }
1067 
1068     return bevel;
1069 }
1070 
display_bevellevel(struct level * plevel)1071 void display_bevellevel(struct level* plevel)
1072 {
1073     int x, y;
1074     int bevel;
1075 
1076     for(x = 0; x < plevel->size_x; x ++)
1077     {
1078         for(y = 0; y < plevel->size_y; y ++)
1079         {
1080             bevel = level_data(plevel, x, y) & ~BEVEL_ALL;
1081             bevel = bevel | display_bevelsquare(plevel, x, y);
1082             level_setdata(plevel, x, y, bevel);
1083         }
1084     }
1085 }
1086 
1087 
display_movers(struct level * plevel,int redraw)1088 void display_movers(struct level* plevel, int redraw)
1089 {
1090     struct mover* pmover;
1091     int x, y, p, pm;
1092     int i, j;
1093     char buffer[16];
1094     int bevel;
1095     struct SDL_Surface *psurface;
1096     SDL_Rect srect, drect;
1097 
1098     if(pdisplaygraphics->shadows != NULL)
1099     {
1100         displayshadowed_movers(plevel, redraw);
1101         return;
1102     }
1103 
1104     display_clip(plevel, 1);
1105 
1106     display_animation_x = - pdisplaygraphics->size_x + (int)((float) pdisplaygraphics->size_x * display_animation);
1107     display_animation_y = - pdisplaygraphics->size_y + (int)((float) pdisplaygraphics->size_y * display_animation);
1108 
1109     /* First, plot spaces for all moving pieces */
1110     pmover = plevel->mover_first;
1111     while(pmover != NULL)
1112     {
1113 #ifdef XOR_COMPATIBILITY
1114         if(plevel->switched)
1115             display_piece(plevel, PIECE_DARKNESS, pmover->x, pmover->y, MOVE_NONE);
1116         else
1117 #endif
1118             display_piece(plevel, PIECE_SPACE, pmover->x, pmover->y, MOVE_NONE);
1119 
1120         pmover = pmover->next;
1121     }
1122 
1123     /* Plot moving piece */
1124     pmover = plevel->mover_first;
1125     while(pmover != NULL)
1126     {
1127         x = pmover->x;
1128         y = pmover->y;
1129 
1130         if(isexplosion(pmover->piece))
1131         {
1132             /* Plot any piece destroyed by the explosion, or the bomb itself */
1133             p = level_previous(plevel, x, y);
1134             pm = level_previousmoving(plevel, x, y);
1135             if(p != PIECE_SPACE)
1136                 display_piece(plevel, p, x, y, pm);
1137 
1138             /* Plot the detonator */
1139             p = level_detonator(plevel, x, y);
1140             pm = level_detonatormoving(plevel, x, y);
1141             if(p != PIECE_SPACE)
1142                 display_piece(plevel, p, x, y, pm);
1143         }
1144         /* Spaces have already been covered */
1145         else if(pmover->piece != PIECE_SPACE && pmover->piece != PIECE_GONE)
1146         {
1147             if(display_animation < 1)
1148             {
1149                 /* Pieces being collected, earth being eaten */
1150                 p = level_previous(plevel, x, y);
1151                 pm = level_previousmoving(plevel, x, y);
1152                 if((p != PIECE_SPACE && !isexplosion(p) && pm == MOVE_NONE)
1153 #ifdef XOR_COMPATIBILITY
1154                         || pmover->piece == PIECE_TELEPORT
1155 #endif
1156                   )
1157                     display_piece(plevel, p, x, y, pm);
1158             }
1159 
1160             display_piece(plevel, pmover->piece, x, y, pmover->direction);
1161         }
1162 
1163         pmover = pmover->next;
1164     }
1165 
1166     /* Plot explosions */
1167     pmover = plevel->mover_first;
1168     while(pmover != NULL)
1169     {
1170         x = pmover->x;
1171         y = pmover->y;
1172         /* Plot growing explosion */
1173         if(isexplosion(pmover->piece))
1174             display_piece(plevel, pmover->piece + PIECE_EXPLOSION_NEW_FIRST - PIECE_EXPLOSION_FIRST, x, y, MOVE_NONE);
1175 
1176         /* Plot dying explosion */
1177         p = level_previous(plevel, x, y);
1178         if(isexplosion(p) && display_animation < 1)
1179             display_piece(plevel, p, x, y, MOVE_NONE);
1180 
1181         pmover = pmover->next;
1182     }
1183 
1184     /* Plot order of movers if debugging (but not if editing) */
1185     if(options_debug & DEBUG_ORDER && display_animation < 1 && plevel->player != 2)
1186     {
1187         pmover = plevel->mover_first;
1188         i = 0;
1189         while(pmover != NULL)
1190         {
1191             if(pmover->piece != PIECE_SPACE && pmover->piece != PIECE_GONE)
1192             {
1193                 pm = pmover->direction;
1194                 if(isexplosion(pmover->piece) || isnewexplosion(pmover->piece))
1195                     pm = MOVE_NONE;
1196 
1197                 x = pmover->x * pdisplaygraphics->size_x + display_offset_pixels_x + ((-1 + display_animation) * move_x[pm] * pdisplaygraphics->size_x);
1198                 y = pmover->y * pdisplaygraphics->size_y + display_offset_pixels_y + ((-1 + display_animation) * move_y[pm] * pdisplaygraphics->size_y);
1199 
1200                 sprintf(buffer, "%X", i++);
1201                 switch(pmover->direction)
1202                 {
1203                     case MOVE_UP:
1204                         strcat(buffer, ARROW_UP);
1205                         break;
1206                     case MOVE_DOWN:
1207                         strcat(buffer, ARROW_DOWN);
1208                         break;
1209                     case MOVE_LEFT:
1210                         strcat(buffer, ARROW_LEFT);
1211                         break;
1212                     case MOVE_RIGHT:
1213                         strcat(buffer, ARROW_RIGHT);
1214                         break;
1215                     default:
1216                         break;
1217                 }
1218                 psurface = font_render(buffer, COLOUR_WHITE | COLOUR_BOLD);
1219                 srect.w = psurface->w > pdisplaygraphics->size_x ? pdisplaygraphics->size_x : psurface->w;
1220                 srect.h = psurface->h > pdisplaygraphics->size_y ? pdisplaygraphics->size_y : psurface->h;
1221                 srect.x = psurface->w - srect.w;
1222                 srect.y = 0;
1223                 drect.x = x + pdisplaygraphics->size_x - srect.w;
1224                 drect.y = y;
1225                 SDL_BlitSurface(psurface, &srect, screen_surface, &drect);
1226                 SDL_FreeSurface(psurface);
1227             }
1228             else
1229                 i ++;
1230 
1231             pmover = pmover->next;
1232         }
1233     }
1234 
1235     if(redraw == 0)
1236         return;
1237 
1238     /* Redraw screen */
1239     pmover = plevel->mover_first;
1240 
1241     while(pmover != NULL)
1242     {
1243         x = pmover->x;
1244         y = pmover->y;
1245         display_redrawpiece(pmover->piece, x, y, pmover->direction);
1246 
1247         if(isexplosion(pmover->piece))
1248         {
1249             p = level_previous(plevel, x, y);
1250             pm = level_previousmoving(plevel, x, y);
1251             if(pm != MOVE_NONE && p != PIECE_SPACE)
1252                 display_redrawpiece(p, x, y, pm);
1253 
1254             p = level_detonator(plevel, x, y);
1255             pm = level_detonatormoving(plevel, x, y);
1256             if(pm != MOVE_NONE && p != PIECE_SPACE)
1257                 display_redrawpiece(p, x, y, pm);
1258         }
1259 
1260         p = level_previous(plevel, x, y);
1261         if(isexplosion(p))
1262             display_redrawpiece(p, x, y, MOVE_NONE);
1263 
1264         pmover = pmover->next;
1265     }
1266 
1267     /* At the peak of the explosion, rebevel any walls that have been
1268        destroyed. When undoing, rebevel any walls that have been recreated. */
1269     if(display_animation == 0 || display_animation == 1)
1270     {
1271         /* When undoing, we have to create the wall prior to rebevelling, as it
1272            wouldn't otherwise exist until after the end of the animation. */
1273         pmover = plevel->mover_first;
1274         while(pmover != NULL)
1275         {
1276             if(pmover->piece == PIECE_WALL)
1277                 level_setpiece(plevel, pmover->x, pmover->y, pmover->piece);
1278             pmover = pmover->next;
1279         }
1280 
1281         pmover = plevel->mover_first;
1282         while(pmover != NULL)
1283         {
1284             x = pmover->x;
1285             y = pmover->y;
1286             if(pmover->piece == PIECE_WALL ||
1287                 (isexplosion(pmover->piece) && display_animation == 1))
1288             {
1289                 for(i = -1; i < 2; i ++)
1290                 {
1291                     for(j = - 1; j < 2; j ++)
1292                     {
1293                         bevel = display_bevelsquare(plevel, x + i, y + j);
1294                         if(bevel != (level_data(plevel, x + i, y + j) & BEVEL_ALL))
1295                         {
1296                             level_setdata(plevel, x + i, y + j, bevel | (level_data(plevel, x + i, y + j) & ~BEVEL_ALL));
1297                             p = level_piece(plevel, x + i, y + j);
1298                             if(p == PIECE_WALL)
1299                             {
1300 #ifdef XOR_COMPATIBILITY
1301                                 if(plevel->switched)
1302                                     display_piece(plevel, PIECE_DARKNESS, x + i, y + j, MOVE_NONE);
1303                                 else
1304 #endif
1305                                     display_piece(plevel, PIECE_WALL, x + i, y + j, MOVE_NONE);
1306                             }
1307                             else
1308                             {
1309 #ifdef XOR_COMPATIBILITY
1310                                 if(plevel->switched)
1311                                     display_piece(plevel, PIECE_DARKNESS, x + i, y + j, MOVE_NONE);
1312                                 else
1313 #endif
1314                                     display_piece(plevel, PIECE_SPACE, x + i, y + j, MOVE_NONE);
1315                                 /* Moving pieces will be replotted when they next move. */
1316                                 if(p != PIECE_SPACE && level_moving(plevel, x + i, y + j) == MOVE_NONE)
1317                                     display_piece(plevel, p, x + i, y + j, MOVE_NONE);
1318                             }
1319                             display_redrawpiece(p, x + i, y + j, MOVE_NONE);
1320                         }
1321                     }
1322                 }
1323             }
1324             pmover = pmover->next;
1325         }
1326     }
1327 
1328     display_clip(plevel, 0);
1329 }
1330 
display_play(struct level * plevel,struct level * plevelreplay)1331 void display_play(struct level* plevel, struct level* plevelreplay)
1332 {
1333     SDL_Event event;
1334     SDL_Surface *psurface;
1335     SDL_Rect drect;
1336     int quit;
1337     int redraw;
1338     int playermove;
1339     struct mover* pmover;
1340     Uint32 basetime;
1341     Uint32 nowtime;
1342     Uint32 pausetime = 0;
1343     int delay, delayold;
1344     int keymod;
1345     int frames = 0;
1346     int events;
1347     char buffer[256];
1348     int action;
1349     int fast;
1350 
1351     int mouse_x = 0;
1352     int mouse_y = 0;
1353     int mouse_destination_x = 0;
1354     int mouse_destination_y = 0;
1355     int mouse_button = 0;
1356     int mouse_time;
1357 
1358     int swap = 0;
1359 
1360     graphics_reload();
1361 
1362     display_bevellevel(plevel);
1363 
1364     /* Force full redraw */
1365     redraw = SCREENREDRAW_ALL;
1366 
1367     playermove = MOVE_NONE;
1368     action = ACTION_NONE;
1369     delayold = options_sdl_delay;
1370 
1371     mouse_time = SDL_GetTicks();
1372 
1373     /* Force all animation to end */
1374     basetime = SDL_GetTicks() - delayold;
1375 
1376     keymod = 0;
1377     fast = 0;
1378 
1379     plevel->flags &= ~LEVELFLAG_PAUSED;
1380 
1381     font_set_size(font_size_game);
1382     display_bar_pixels = font_height;
1383     display_focus(plevel, 1);
1384 
1385     quit = 0;
1386     while(!quit)
1387     {
1388         //////// Screen redraw ////////
1389 
1390         if(redraw & SCREENREDRAW_ALL)
1391         {
1392             font_set_size(font_size_game);
1393             display_bar_pixels = font_height;
1394         }
1395         if(redraw & SCREENREDRAW_BAR)
1396         {
1397             /* Clear bar */
1398             drect.x = 0;
1399             drect.y = screen_height - display_bar_pixels;
1400             drect.w = screen_width;
1401             drect.h = display_bar_pixels;
1402             SDL_FillRect(screen_surface, &drect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
1403 
1404             display_title(plevel);
1405             display_stars(plevel);
1406             display_moves(plevel, plevelreplay);
1407         }
1408         if(redraw & SCREENREDRAW_LEVEL)
1409             display_level(plevel, redraw);
1410 
1411         redraw = 0;
1412 
1413         //////// Delay calculation ////////
1414 
1415         /* Calculate what the delay should be, defaulting to the Move Speed. */
1416         delay = options_sdl_delay;
1417         /* If we're replaying, use the Replay Speed */
1418         if(plevelreplay != NULL && plevelreplay->moves != -1)
1419             delay = options_sdl_replay_delay;
1420         else
1421         {
1422             /* Otherwise */
1423             pmover = plevel->mover_first;
1424             while(pmover != NULL)
1425             {
1426                 /* Use the Player Speed if the player is still moving */
1427                 if(pmover->piece == PIECE_PLAYER_ONE || pmover->piece == PIECE_PLAYER_TWO)
1428                     delay = options_sdl_player_delay;
1429                 /* unless there's a piece following in their trail */
1430                 else if(pmover->piece != PIECE_SPACE && pmover->fast == 1)
1431                     delay = options_sdl_delay;
1432 
1433                 pmover = pmover->next;
1434             }
1435             /* If we're undoing, use the Undo Speed */
1436             if(plevel->flags & LEVELFLAG_UNDO)
1437                 delay = options_sdl_undo_delay;
1438         }
1439         /* If SHIFT is pressed, speed things up. */
1440         if(keymod & 1)
1441             delay = delay / 10;
1442         /* If CTRL is pressed, slow things down. */
1443         if(keymod & 2)
1444             delay = delay * 4;
1445         /* If the delay has changed, preserve our position in the animation */
1446         if(delay != delayold)
1447         {
1448             nowtime = SDL_GetTicks();
1449             if((plevel->flags & LEVELFLAG_PAUSED))
1450                 nowtime = pausetime;
1451             if(delayold != 0)
1452                 basetime = nowtime - (((nowtime - basetime) * delay) / delayold );
1453             delayold = delay;
1454         }
1455         if(fast && !(plevel->flags & LEVELFLAG_PAUSED))
1456             basetime = 0;
1457 
1458         //////// Movers ////////
1459 
1460         /* If there are movers, plot and then evolve them */
1461         if(plevel->mover_first != NULL)
1462         {
1463             nowtime = SDL_GetTicks();
1464             if((plevel->flags & LEVELFLAG_PAUSED))
1465                 nowtime = pausetime;
1466             display_animation = (float)(nowtime - basetime) / delay;
1467             if(display_animation > 1)
1468                 display_animation = 1;
1469             frames ++;
1470             display_movers(plevel, 1);
1471         }
1472 
1473         if(plevel->mover_first != NULL)
1474         {
1475             /* Is it time for the next stage of this move? */
1476             if(nowtime > basetime + delay && !(plevel->flags & LEVELFLAG_PAUSED))
1477             {
1478 #ifdef XOR_COMPATIBILITY
1479                 if(plevel->mode == MODE_XOR && options_xor_display)
1480                 {
1481                     pmover = plevel->mover_first;
1482                     while(pmover != NULL)
1483                     {
1484                         display_map_piece(plevel, pmover->piece, pmover->x, pmover->y, 1);
1485                         pmover = pmover->next;
1486                     }
1487                 }
1488 #endif
1489 
1490                 /* Evolve movers */
1491                 if(!(plevel->flags & LEVELFLAG_UNDO))
1492                 {
1493                     if(level_evolve(plevel))
1494                         redraw |= display_focus(plevel, 1) * SCREENREDRAW_LEVEL;
1495                     level_storemovers(plevel);
1496 
1497                     if(options_debug & DEBUG_SPEED)
1498                     {
1499                         sprintf(buffer, "    %4dfps (%d frames / %d ms)    ", 1000 * frames / (nowtime - basetime), frames, nowtime - basetime);
1500                         psurface = font_render(buffer, COLOUR_WHITE);
1501                         drect.x = (screen_width - psurface->w) / 2;
1502                         drect.y = screen_height - font_height;
1503                         drect.w = psurface->w;
1504                         drect.h = psurface->h;
1505                         SDL_FillRect(screen_surface, &drect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
1506                         SDL_BlitSurface(psurface, NULL, screen_surface, &drect);
1507                         SDL_UpdateRects(screen_surface, 1, &drect);
1508                         SDL_FreeSurface(psurface);
1509 
1510                         printf("%s\n", buffer);
1511                     }
1512                     frames = 0;
1513                 }
1514                 else
1515                 {
1516                     if(level_undo(plevel))
1517                         plevel->flags |= LEVELFLAG_UNDO;
1518                     else
1519                         plevel->flags &= ~LEVELFLAG_UNDO;
1520 
1521                         /* Refocus in case we've moved offscreen */
1522                         redraw |= display_focus(plevel, 1) * SCREENREDRAW_LEVEL;
1523                 }
1524 
1525                 basetime = SDL_GetTicks();
1526 
1527                 /* Reset animation in case we redraw before it is next calculated */
1528                 display_animation = 0;
1529             }
1530         }
1531 
1532         //////// Events ////////
1533 
1534         /* Hide the mouse if not used whilst in full screen mode */
1535         if(SDL_GetTicks() > mouse_time + MOUSE_TIMEOUT_MOVE)
1536             screen_cursor(0);
1537 
1538         /* Poll if there are movers, otherwise wait so as to reduce load */
1539         if(plevel->mover_first != NULL || SDL_GetTicks() < basetime + delay)
1540             events = SDL_PollEvent(&event);
1541         else
1542             events = SDL_WaitEvent(&event);
1543 
1544         while(events)
1545         {
1546             switch(event.type)
1547             {
1548                 case SDL_KEYDOWN:
1549 
1550                     switch(actions[event.key.keysym.sym])
1551                     {
1552                         case ACTION_FASTER:
1553                             keymod |= 1;
1554                             break;
1555 
1556                         case ACTION_SLOWER:
1557                             keymod |= 2;
1558                             break;
1559 
1560                         case ACTION_QUIT:
1561                             quit = 1;
1562                             break;
1563 
1564                         case ACTION_FAST:
1565                             fast = 1;
1566                             break;
1567 
1568                         case ACTION_PAUSE:
1569                             if(plevel->flags & LEVELFLAG_PAUSED)
1570                             {
1571                                 plevel->flags &= ~LEVELFLAG_PAUSED;
1572                                 basetime = SDL_GetTicks() - (pausetime - basetime);
1573                             }
1574                             else
1575                             {
1576                                 plevel->flags |= LEVELFLAG_PAUSED;
1577                                 pausetime = SDL_GetTicks();
1578                             }
1579                             redraw |= SCREENREDRAW_BAR;
1580                             break;
1581 
1582                         case ACTION_REDRAW:
1583                             redraw |= SCREENREDRAW_ALL;
1584                             break;
1585 
1586                         case ACTION_HIDE:
1587                             SDL_WM_IconifyWindow();
1588                             break;
1589 
1590                         case ACTION_UNDO:
1591                             if(plevelreplay != NULL)
1592                             {
1593                                 plevelreplay->flags |= LEVELFLAG_UNDO;
1594                                 plevelreplay->flags &= ~LEVELFLAG_PAUSED;
1595                             }
1596                             else
1597                                 action = ACTION_UNDO;
1598                             break;
1599 
1600 
1601                     case ACTION_REDO:
1602                             if(plevelreplay!= NULL)
1603                             {
1604                                 plevelreplay->flags &= ~LEVELFLAG_UNDO;
1605                                 plevelreplay->flags &= ~LEVELFLAG_PAUSED;
1606                             }
1607                             else
1608                                 action = ACTION_REDO;
1609                             break;
1610 
1611                         case ACTION_LEFT:
1612                             if(plevelreplay != NULL)
1613                             {
1614                                 plevelreplay->flags |= LEVELFLAG_UNDO;
1615                                 plevelreplay->flags &= ~LEVELFLAG_PAUSED;
1616                             }
1617                             else
1618                                 action = ACTION_LEFT;
1619                             break;
1620 
1621                         case ACTION_RIGHT:
1622                             if(plevelreplay != NULL)
1623                             {
1624                                 plevelreplay->flags &= ~LEVELFLAG_UNDO;
1625                                 plevelreplay->flags &= ~LEVELFLAG_PAUSED;
1626                             }
1627                             else
1628                                 action = ACTION_RIGHT;
1629                             break;
1630 
1631                         case ACTION_UP:
1632                             if(plevelreplay != NULL)
1633                                 plevelreplay->flags |= LEVELFLAG_PAUSED;
1634                             else
1635                                 action = ACTION_UP;
1636                             break;
1637 
1638                         case ACTION_DOWN:
1639                             if(plevelreplay != NULL)
1640                                 plevelreplay->flags |= LEVELFLAG_PAUSED;
1641                             else
1642                                 action = ACTION_DOWN;
1643                             break;
1644 
1645                         case ACTION_SWAP:
1646                             action = ACTION_SWAP;
1647                             break;
1648 
1649                         default:
1650                             break;
1651                     }
1652                     break;
1653 
1654                 case SDL_KEYUP:
1655                     switch(actions[event.key.keysym.sym])
1656                     {
1657                         case ACTION_SWAP:
1658                             swap = 0;
1659                         case ACTION_UP:
1660                         case ACTION_DOWN:
1661                         case ACTION_LEFT:
1662                         case ACTION_RIGHT:
1663                         case ACTION_UNDO:
1664                         case ACTION_REDO:
1665                             action = ACTION_NONE;
1666                             break;
1667 
1668                            case ACTION_FASTER:
1669                             keymod &= ~1;
1670                             break;
1671 
1672                         case ACTION_SLOWER:
1673                             keymod &= ~2;
1674                             break;
1675 
1676                         case ACTION_FAST:
1677                             fast = 0;
1678                             break;
1679 
1680                         default:
1681                             break;
1682                     }
1683                     break;
1684 
1685                 case SDL_QUIT:
1686                     exit(0);
1687 
1688                 case SDL_VIDEORESIZE:
1689                     screen_resizeevent(&event);
1690                     redraw = SCREENREDRAW_ALL;
1691                     break;
1692 
1693                 case SDL_ACTIVEEVENT:
1694                     if((event.active.state & SDL_APPACTIVE) && event.active.gain == 1)
1695                         redraw = SCREENREDRAW_ALL;
1696                     break;
1697 
1698                 case SDL_MOUSEBUTTONDOWN:
1699                     mouse_x = event.button.x;
1700                     mouse_y = event.button.y;
1701                     mouse_button = event.button.button;
1702                     mouse_time = SDL_GetTicks();
1703                     screen_cursor(1);
1704 
1705                     if(mouse_button > 0 && mouse_button < MOUSE_BUTTONS_MAX)
1706                         action = actions_mouse[ACTIONS_GAME][mouse_button];
1707 
1708                     if(action == ACTION_HIDE)
1709                     {
1710                         SDL_WM_IconifyWindow();
1711                         action = ACTION_NONE;
1712                     }
1713                     if(action == ACTION_QUIT)
1714                         quit = 1;
1715                     break;
1716 
1717                 case SDL_MOUSEBUTTONUP:
1718                     if(action == ACTION_MOUSE_CLICK ||
1719                             (action == ACTION_MOUSE_DRAG_OR_CLICK && (SDL_GetTicks() < mouse_time + MOUSE_TIMEOUT_CLICK)))
1720                     {
1721                         mouse_destination_x = (mouse_x - display_offset_pixels_x) / pdisplaygraphics->size_x;
1722                         mouse_destination_y = (mouse_y - display_offset_pixels_y) / pdisplaygraphics->size_y;
1723                         if(mouse_destination_x == plevel->player_x[plevel->player])
1724                         {
1725                             if(mouse_destination_y < plevel->player_y[plevel->player])
1726                                 action = ACTION_UP;
1727                             if(mouse_destination_y > plevel->player_y[plevel->player])
1728                                 action = ACTION_DOWN;
1729                         }
1730                         if(mouse_destination_y == plevel->player_y[plevel->player])
1731                         {
1732                             if(mouse_destination_x < plevel->player_x[plevel->player])
1733                                 action = ACTION_LEFT;
1734                             if(mouse_destination_x > plevel->player_x[plevel->player])
1735                                 action = ACTION_RIGHT;
1736                         }
1737                         if(mouse_destination_x == plevel->player_x[1 - plevel->player] && mouse_destination_y == plevel->player_y[1 - plevel->player])
1738                             action = ACTION_SWAP;
1739                     }
1740                     /* Buttons 4 and 5 can't be held down */
1741                     else if(mouse_button != 4 && mouse_button != 5)
1742                     {
1743                         mouse_button = 0;
1744                         action = ACTION_NONE;
1745                     }
1746                     break;
1747                 case SDL_MOUSEMOTION:
1748                     /* Are we dragging? */
1749                     if(action == ACTION_MOUSE_DRAG || action == ACTION_MOUSE_DRAG_OR_CLICK)
1750                     {
1751                         display_offset_pixels_y -= (mouse_y - event.motion.y);
1752                         display_offset_pixels_x -= (mouse_x - event.motion.x);
1753 
1754                         mouse_x = event.motion.x;
1755                         mouse_y = event.motion.y;
1756 
1757                         redraw |= SCREENREDRAW_LEVEL;
1758                     }
1759                     else
1760                     {
1761                         mouse_time = SDL_GetTicks();
1762                         screen_cursor(1);
1763                     }
1764                     break;
1765 
1766                 default:
1767                     break;
1768             }
1769             events = SDL_PollEvent(&event);
1770         }
1771 
1772         //////// Actions ////////
1773 
1774         /* Are we replaying the level? */
1775         if(plevelreplay != NULL)
1776         {
1777             /* Prevent the user from moving during the replay */
1778             playermove = MOVE_NONE;
1779 
1780             /* Is it time for another move? */
1781             if(plevel->mover_first == NULL && !(plevelreplay->flags & LEVELFLAG_PAUSED))
1782             {
1783                 /* Moving backwards through replay */
1784                 if(plevelreplay->flags & LEVELFLAG_UNDO)
1785                 {
1786                     if(level_undo(plevel))
1787                     {
1788                         plevel->flags |= LEVELFLAG_UNDO;
1789                         if(plevelreplay->move_current != NULL)
1790                             plevelreplay->move_current = plevelreplay->move_current->previous;
1791                         else
1792                             plevelreplay->move_current = plevelreplay->move_last;
1793                     }
1794                     else
1795                         plevel->flags &= ~LEVELFLAG_UNDO;
1796                 }
1797                 /* Moving forwards through replay */
1798                 else
1799                 {
1800                     if(plevelreplay->move_current != NULL)
1801                     {
1802                         playermove = plevelreplay->move_current->direction;
1803                         plevelreplay->move_current = plevelreplay->move_current->next;
1804                     }
1805                 }
1806             }
1807         }
1808         /* otherwise, see what action the user has asked for */
1809         else
1810         {
1811             playermove = MOVE_NONE;
1812 
1813             switch(action)
1814             {
1815                 case ACTION_LEFT:
1816                     playermove = MOVE_LEFT;
1817                     break;
1818                 case ACTION_RIGHT:
1819                     playermove = MOVE_RIGHT;
1820                     break;
1821                 case ACTION_UP:
1822                     playermove = MOVE_UP;
1823                     break;
1824                 case ACTION_DOWN:
1825                     playermove = MOVE_DOWN;
1826                     break;
1827                 case ACTION_SWAP:
1828                     /* Swap only once per keypress */
1829                     if(plevel->mover_first == NULL && !(plevel->flags & LEVELFLAG_PAUSED) && !swap)
1830                     {
1831                           playermove = MOVE_SWAP;
1832                         swap = 1;
1833                     }
1834                     break;
1835                 case ACTION_UNDO:
1836                     if(plevel->mover_first == NULL && !(plevel->flags & LEVELFLAG_UNDO))
1837                     {
1838                         if(level_undo(plevel))
1839                             plevel->flags |= LEVELFLAG_UNDO;
1840                         else
1841                             plevel->flags &= ~LEVELFLAG_UNDO;
1842                         playermove = MOVE_NONE;
1843                         basetime = SDL_GetTicks();
1844 
1845                         /* Refocus in case we've moved offscreen */
1846                         redraw |= display_focus(plevel, 1) * SCREENREDRAW_LEVEL;
1847                     }
1848                     break;
1849                 case ACTION_REDO:
1850                     playermove = MOVE_REDO;
1851                     break;
1852                 default:
1853                     break;
1854             }
1855         }
1856 
1857         if(mouse_button == 4 || mouse_button == 5)
1858         {
1859             action = ACTION_NONE;
1860             mouse_button = 0;
1861         }
1862 
1863         /* Can't move if we've failed or solved the level */
1864         if(plevel->flags & (LEVELFLAG_FAILED | LEVELFLAG_SOLVED))
1865             playermove = MOVE_NONE;
1866 
1867         /* If we can move, make the move */
1868         if(playermove != MOVE_NONE && plevel->mover_first == NULL && !(plevel->flags & LEVELFLAG_PAUSED))
1869         {
1870             level_move(plevel, playermove);
1871             basetime = SDL_GetTicks();
1872             redraw |= display_focus(plevel, 1) * SCREENREDRAW_LEVEL;
1873 
1874             if(mouse_destination_x != 0 || mouse_destination_y != 0)
1875             {
1876                 /* Have we reached our destination, or been blocked? */
1877                 if((plevel->player_x[plevel->player] == mouse_destination_x && plevel->player_y[plevel->player] == mouse_destination_y) || plevel->mover_first == NULL)
1878                 {
1879                     action = ACTION_NONE;
1880                     mouse_destination_x = 0;
1881                     mouse_destination_y = 0;
1882                 }
1883             }
1884         }
1885 
1886         //////// Display changes ////////
1887 
1888         if(plevel->flags & LEVELFLAG_MOVES)
1889         {
1890             display_moves(plevel, plevelreplay);
1891             plevel->flags &= ~LEVELFLAG_MOVES;
1892         }
1893 
1894         if(plevel->flags & LEVELFLAG_STARS)
1895         {
1896             display_stars(plevel);
1897             plevel->flags &= ~LEVELFLAG_STARS;
1898         }
1899 
1900 #ifdef XOR_COMPATIBILITY
1901         if(plevel->flags & LEVELFLAG_SWITCH)
1902         {
1903             redraw |= SCREENREDRAW_ALL;
1904             plevel->flags &= ~LEVELFLAG_SWITCH;
1905         }
1906 
1907         if(plevel->flags & LEVELFLAG_MAP)
1908         {
1909             plevel->flags &= ~LEVELFLAG_MAP;
1910             if(plevel->mode == MODE_XOR && options_xor_display)
1911                 display_map(plevel);
1912         }
1913 #endif
1914 
1915 
1916         if(!(plevel->flags & LEVELFLAG_SOLVED) && plevel->flags & LEVELFLAG_EXIT)
1917         {
1918             redraw |= SCREENREDRAW_BAR;
1919             plevel->flags |= LEVELFLAG_SOLVED;
1920         }
1921 
1922         if(!(plevel->flags & LEVELFLAG_FAILED) && plevel->alive[0] == 0 && plevel->alive[1] ==0)
1923         {
1924             redraw |= SCREENREDRAW_BAR;
1925             plevel->flags |= LEVELFLAG_FAILED;
1926         }
1927     }
1928 
1929     screen_cursor(1);
1930 }
1931 
display_edit(struct level * plevel)1932 void display_edit(struct level* plevel)
1933 {
1934     int quit;
1935 
1936     struct mover* pmover;
1937     struct mover* pmovertmp;
1938 
1939     static int editor_piece = 0;
1940     int redraw = 0, predraw = 0, moved = 0, pmoved = 0;
1941     int i, j;
1942     int player;
1943 
1944     int ex, ey, ep;
1945     int x, y;
1946     int bevel;
1947     int piece_start = 0;
1948     int piece_end = 0;
1949     int piece_width = 0;
1950     int piece_count = 0;
1951     int action;
1952     int effect;
1953 
1954     SDL_Event event;
1955     SDL_Rect drect;
1956     SDL_Surface *psurface;
1957 
1958     int mouse_x, mouse_y;
1959     int dx, dy;
1960 
1961     int mouse_button;
1962     int mouse_time;
1963 
1964     font_set_size(font_size_game);
1965     graphics_reload();
1966 
1967     display_bevellevel(plevel);
1968 
1969     piece_count = 0;
1970     while(editor_piece_maps[plevel->mode][piece_count] != PIECE_GONE)
1971         piece_count ++;
1972 
1973     if(editor_piece > piece_count)
1974         editor_piece = 0;
1975 
1976     /* The editor uses player 2, so store the player value */
1977     player = plevel->player;
1978 
1979     ex = plevel->player_x[2];
1980     ey = plevel->player_y[2];
1981     ep = editor_piece;
1982 
1983     mouse_x = 0;
1984     mouse_y = 0;
1985     mouse_button = 0;
1986     mouse_time = SDL_GetTicks();
1987     action = 0;
1988     effect = 0;
1989 
1990     /* Force a complete redraw */
1991     redraw = 2;
1992 
1993     display_focus(plevel, 1);
1994 
1995     quit = 0;
1996     while(!quit)
1997     {
1998         plevel->player_x[2] = plevel->player_x[2];
1999         plevel->player_y[2] = plevel->player_y[2];
2000         plevel->player = 2;
2001 
2002 #ifdef XOR_COMPATIBILITY
2003         if(plevel->mode == MODE_XOR)
2004             xor_focus(plevel);
2005 #endif
2006 
2007         /* Clear screen, and calculate size of bar */
2008         if(redraw == 2)
2009         {
2010             screen_clear(pdisplaygraphics->background[0], pdisplaygraphics->background[1], pdisplaygraphics->background[2]);
2011 
2012             piece_width = (screen_width - pdisplaygraphics->size_x - 2) / pdisplaygraphics->size_x;
2013 
2014             display_bar_pixels = pdisplaygraphics->size_y + 1;
2015 
2016             if(piece_width < piece_count)
2017             {
2018                 if(display_bar_pixels < font_height)
2019                     display_bar_pixels = font_height;
2020                 piece_width = (screen_width - pdisplaygraphics->size_x - 2) / pdisplaygraphics->size_x;
2021             }
2022             predraw = 2;
2023         }
2024 
2025         if(moved == 1)
2026             redraw |= display_focus(plevel, 1);
2027 
2028         /* Draw level */
2029         if(redraw)
2030         {
2031             display_level(plevel, SCREENREDRAW_ALL);
2032 
2033             redraw = 0;
2034             moved = 1;
2035         }
2036 
2037         /* Recalculate piece bar */
2038         if(pmoved || predraw)
2039         {
2040             if(piece_width >= piece_count)
2041             {
2042                 piece_start =0;
2043                 piece_end = piece_count;
2044             }
2045             else
2046             {
2047                 while(editor_piece < piece_start + 3 && piece_start > 0)
2048                 {
2049                     piece_start --;
2050                     piece_end = piece_start + piece_width;
2051 
2052                     predraw = 1;
2053                 }
2054 
2055                 while(editor_piece >= piece_start + piece_width - 3 && piece_end < piece_count)
2056                 {
2057                     piece_start ++;
2058                     piece_end = piece_start + piece_width;
2059 
2060                     predraw = 1;
2061                 }
2062 
2063                 piece_end = piece_start + piece_width;
2064                 if(piece_end > piece_count)
2065                     piece_end = piece_count;
2066             }
2067         }
2068 
2069         /* Redraw all of piece bar */
2070         if(predraw)
2071         {
2072             drect.x = 0;
2073             drect.w = screen_width;
2074             drect.y = screen_height - display_bar_pixels;
2075             drect.h = display_bar_pixels;
2076             SDL_FillRect(screen_surface, &drect, SDL_MapRGB(screen_surface->format, 0, 0, 0));
2077 
2078             drect.x = 0;
2079             drect.w = screen_width - pdisplaygraphics->size_x - 2;
2080             drect.y = screen_height - pdisplaygraphics->size_y;
2081             drect.h = pdisplaygraphics->size_y;
2082             SDL_SetClipRect(screen_surface, &drect);
2083             for(i = piece_start; i < piece_end; i ++)
2084             {
2085                 display_pieceabsolute(editor_piece_maps[plevel->mode][i], (i - piece_start) * pdisplaygraphics->size_x, screen_height - pdisplaygraphics->size_y, 0);
2086             }
2087             if(piece_start != 0)
2088             {
2089                 psurface = font_render(ARROW_LEFT, COLOUR_WHITE | COLOUR_BOLD);
2090                 drect.x = 0;
2091                 drect.y = screen_height - (pdisplaygraphics->size_y + font_height) / 2;
2092                 SDL_BlitSurface(psurface, NULL, screen_surface, &drect);
2093                 SDL_FreeSurface(psurface);
2094             }
2095             if(piece_end != piece_count)
2096             {
2097                 psurface = font_render(ARROW_RIGHT, COLOUR_WHITE | COLOUR_BOLD);
2098                 drect.x = piece_width * pdisplaygraphics->size_x - 2 - psurface->w;
2099                 drect.y = screen_height - (pdisplaygraphics->size_y + font_height) / 2;
2100                 SDL_BlitSurface(psurface, NULL, screen_surface, &drect);
2101                 SDL_FreeSurface(psurface);
2102             }
2103             SDL_SetClipRect(screen_surface, NULL);
2104 
2105             drect.x = 0;
2106             drect.w = screen_width;
2107             drect.y = screen_height - pdisplaygraphics->size_y;
2108             drect.h = pdisplaygraphics->size_y;
2109             SDL_UpdateRects(screen_surface, 1, &drect);
2110 
2111             pmoved = 1;
2112         }
2113 
2114         /* Redraw piece bar cursor */
2115         if(pmoved)
2116         {
2117             pmoved = 0;
2118 
2119             /* Remove cursor from previous piece */
2120             if(!predraw)
2121                 display_pieceabsolute(editor_piece_maps[plevel->mode][ep], (ep - piece_start) * pdisplaygraphics->size_x, screen_height - pdisplaygraphics->size_y, 1);
2122 
2123             /* Plot cursor */
2124             display_pieceabsolute(PIECE_CURSOR, (editor_piece - piece_start) * pdisplaygraphics->size_x, screen_height - pdisplaygraphics->size_y, predraw ? 0 : 1);
2125 
2126             /* Plot current piece in far right corner */
2127             display_pieceabsolute(editor_piece_maps[plevel->mode][editor_piece], screen_width - pdisplaygraphics->size_x, screen_height - pdisplaygraphics->size_y, predraw ? 0 : 1);
2128         }
2129 
2130         if(predraw)
2131         {
2132             drect.x = 0;
2133             drect.w = screen_width;
2134             drect.y = screen_height - display_bar_pixels;
2135             drect.h = display_bar_pixels;
2136             SDL_UpdateRects(screen_surface, 1, &drect);
2137             predraw = 0;
2138         }
2139 
2140         /* Redraw level cursor */
2141         if(moved)
2142         {
2143             moved = 0;
2144 
2145             /* Create cosmetic movers */
2146             level_setprevious(plevel, plevel->player_x[2], plevel->player_y[2], level_piece(plevel, plevel->player_x[2], plevel->player_y[2]));
2147             if(pdisplaygraphics->shadows != NULL)
2148                 mover_newundo(plevel, ex, ey, MOVE_NONE, PIECE_SPACE, PIECE_SPACE, MOVER_UNDO);
2149             else
2150                 mover_newundo(plevel, ex, ey, MOVE_NONE, level_piece(plevel, ex, ey), PIECE_SPACE, MOVER_UNDO);
2151             mover_newundo(plevel, plevel->player_x[2], plevel->player_y[2], MOVE_NONE, PIECE_CURSOR, PIECE_SPACE, MOVER_UNDO);
2152             display_animation = 0.5;
2153             display_movers(plevel, 1);
2154             level_setmoving(plevel, ex, ey, MOVE_NONE);
2155             level_setmoving(plevel, plevel->player_x[2], plevel->player_y[2], MOVE_NONE);
2156             level_setprevious(plevel, plevel->player_x[2], plevel->player_y[2], PIECE_SPACE);
2157 
2158             /* Delete cosmetic movers */
2159             pmover = plevel->mover_first;
2160             while(pmover != NULL)
2161             {
2162 #ifdef XOR_COMPATIBILITY
2163                 /* Update map if present */
2164                 if(options_xor_display && pmover->piece != PIECE_CURSOR)
2165                     display_map_piece(plevel, pmover->piece, pmover->x, pmover->y, 1);
2166 #endif
2167                 pmovertmp = pmover;
2168                 pmover = pmover->next;
2169                 free(pmovertmp);
2170             }
2171             plevel->mover_first = NULL;
2172             plevel->mover_last = NULL;
2173         }
2174 
2175         SDL_WaitEvent(&event);
2176 
2177         /* Hide the mouse if not used whilst in full screen mode */
2178         if(SDL_GetTicks() > mouse_time + MOUSE_TIMEOUT_MOVE)
2179             screen_cursor(0);
2180 
2181         /* Store previous cursor location for redrawing damaged areas */
2182         ex = plevel->player_x[2];
2183         ey = plevel->player_y[2];
2184         ep = editor_piece;
2185 
2186         switch(event.type)
2187         {
2188             case SDL_KEYDOWN:
2189                 switch(actions[event.key.keysym.sym])
2190                 {
2191                     case ACTION_QUIT:
2192                         quit = 1;
2193                         break;
2194 
2195                     case ACTION_HIDE:
2196                            SDL_WM_IconifyWindow();
2197                         break;
2198 
2199                     case ACTION_LEFT:
2200                         if(plevel->player_x[2] > 0)
2201                         {
2202                             plevel->player_x[2] --; moved = 1;
2203                         }
2204                         break;
2205 
2206                     case ACTION_RIGHT:
2207                         if(plevel->player_x[2] < plevel->size_x - 1)
2208                         {
2209                             plevel->player_x[2] ++; moved = 1;
2210                         }
2211                         break;
2212 
2213                     case ACTION_UP:
2214                         if(plevel->player_y[2] > 0)
2215                         {
2216                             plevel->player_y[2] --; moved = 1;
2217                         }
2218                         break;
2219 
2220                     case ACTION_DOWN:
2221                         if(plevel->player_y[2] < plevel->size_y -1)
2222                         {
2223                             plevel->player_y[2] ++; moved = 1;
2224                         }
2225                         break;
2226 
2227                     case ACTION_PIECE_LEFT:
2228                         effect = ACTION_PIECE_LEFT;
2229                         break;
2230 
2231                     case ACTION_PIECE_RIGHT:
2232                         effect = ACTION_PIECE_RIGHT;
2233                         break;
2234 
2235                     case ACTION_SWAP:
2236                         effect = ACTION_SWAP;
2237                         moved = 1;
2238                         break;
2239 
2240                     default:
2241                         break;
2242                 }
2243             break;
2244 
2245 
2246                 case SDL_MOUSEBUTTONDOWN:
2247                     mouse_x = event.button.x;
2248                     mouse_y = event.button.y;
2249                     mouse_button = event.button.button;
2250                     mouse_time = SDL_GetTicks();
2251                     screen_cursor(1);
2252 
2253                     if(mouse_button > 0 && mouse_button < MOUSE_BUTTONS_MAX)
2254                         action = actions_mouse[ACTIONS_EDIT][mouse_button];
2255 
2256                     switch(action)
2257                     {
2258                         case ACTION_HIDE:
2259                             SDL_WM_IconifyWindow();
2260                             action = ACTION_NONE;
2261                             break;
2262 
2263                         case ACTION_QUIT:
2264                             quit = 1;
2265                             break;
2266 
2267                         case ACTION_PIECE_LEFT:
2268                             effect = ACTION_PIECE_LEFT;
2269                             break;
2270 
2271                         case ACTION_PIECE_RIGHT:
2272                             effect = ACTION_PIECE_RIGHT;
2273                             break;
2274 
2275                         default:
2276                             break;
2277                     }
2278                     break;
2279 
2280                 case SDL_MOUSEBUTTONUP:
2281                     if(action == ACTION_MOUSE_CLICK ||
2282                             (action == ACTION_MOUSE_DRAG_OR_CLICK && ((SDL_GetTicks() < mouse_time + MOUSE_TIMEOUT_CLICK) || (mouse_y > (screen_height - display_bar_pixels)))))
2283                     {
2284                         /* Have they clicked within the piece bar? */
2285                         if(mouse_y > (screen_height - display_bar_pixels))
2286                         {
2287                             editor_piece = piece_start + ((mouse_x) / pdisplaygraphics->size_x);
2288                             pmoved = 1;
2289                         }
2290                         else
2291                         {
2292                             plevel->player_x[2] = (mouse_x - display_offset_pixels_x) / pdisplaygraphics->size_x;
2293                             plevel->player_y[2] = (mouse_y - display_offset_pixels_y) / pdisplaygraphics->size_y;
2294                             moved = 2;
2295                             effect = ACTION_SWAP;
2296                         }
2297                     }
2298 
2299                     /* Buttons 4 and 5 can't be held down */
2300                     if(mouse_button != 4 && mouse_button != 5)
2301                     {
2302                         mouse_button = 0;
2303                         action = ACTION_NONE;
2304                     }
2305                     break;
2306 
2307                 case SDL_MOUSEMOTION:
2308                     mouse_time = SDL_GetTicks();
2309                     screen_cursor(1);
2310 
2311                     if(action == ACTION_MOUSE_DRAG || action == ACTION_MOUSE_DRAG_OR_CLICK)
2312                     {
2313                         dx = mouse_x - event.motion.x;
2314                         dy = mouse_y - event.motion.y;
2315 
2316                         mouse_x = event.motion.x;
2317                         mouse_y = event.motion.y;
2318 
2319                         display_offset_pixels_y -= dy;
2320                         display_offset_pixels_x -= dx;
2321 
2322                         redraw |= 1;
2323                     }
2324                     else if(action == ACTION_MOUSE_CLICK)
2325                     {
2326 
2327                         mouse_x = event.motion.x;
2328                         mouse_y = event.motion.y;
2329                         /* Have they clicked within the piece bar? */
2330                         if(mouse_y > (screen_height - display_bar_pixels))
2331                         {
2332                             editor_piece = piece_start + ((mouse_x) / pdisplaygraphics->size_x);
2333                             pmoved = 1;
2334                         }
2335                         else
2336                         {
2337                             plevel->player_x[2] = (mouse_x - display_offset_pixels_x) / pdisplaygraphics->size_x;
2338                             plevel->player_y[2] = (mouse_y - display_offset_pixels_y) / pdisplaygraphics->size_y;
2339                             moved = 2;
2340                             effect = ACTION_SWAP;
2341                         }
2342                     }
2343                     break;
2344 
2345             case SDL_QUIT:
2346                 exit(0);
2347 
2348             case SDL_VIDEORESIZE:
2349                 screen_resizeevent(&event);
2350                 redraw = 2;
2351                 break;
2352 
2353             case SDL_ACTIVEEVENT:
2354                 if((event.active.state & SDL_APPACTIVE) && event.active.gain == 1)
2355                     redraw = 2;
2356                 break;
2357         }
2358 
2359         switch(effect)
2360         {
2361             case ACTION_PIECE_LEFT:
2362                 editor_piece --;
2363                 if(editor_piece < 0)
2364                     editor_piece = piece_count - 1;
2365                 pmoved = 1;
2366                 break;
2367 
2368             case ACTION_PIECE_RIGHT:
2369                 editor_piece ++;
2370                 if(editor_piece >= piece_count)
2371                     editor_piece = 0;
2372                 pmoved = 1;
2373                 break;
2374 
2375             case ACTION_SWAP:
2376                 bevel = 0;
2377                 if(editor_piece_maps[plevel->mode][editor_piece] == PIECE_WALL || level_piece(plevel, plevel->player_x[2], plevel->player_y[2]) == PIECE_WALL)
2378                     bevel = 1;
2379                 /* Don't allow the edges to be changed */
2380                 if(!(plevel->player_x[2] < 1 || plevel->player_x[2] > plevel->size_x - 2 || plevel->player_y[2] < 1 || plevel->player_y[2] > plevel->size_y - 2))
2381                     level_setpiece(plevel, plevel->player_x[2], plevel->player_y[2], editor_piece_maps[plevel->mode][editor_piece]);
2382 
2383                 /* Rebevel if necessary */
2384                 if(bevel == 1)
2385                 {
2386                     x = plevel->player_x[2]; y = plevel->player_y[2];
2387                     for(i = -1; i < 2; i ++)
2388                     {
2389                         for(j = - 1; j < 2; j ++)
2390                         {
2391                                 bevel = display_bevelsquare(plevel, x + i, y + j);
2392                                 if(bevel != (level_data(plevel, x + i, y + j) & BEVEL_ALL))
2393                                 {
2394                                     level_setdata(plevel, x + i, y + j, bevel | (level_data(plevel, x + i, y + j) & ~BEVEL_ALL));
2395                                     /* Redraw changed piece */
2396                                     /* The mover will get deleted when next redrawn */
2397                                     if(pdisplaygraphics->shadows != NULL)
2398                                         mover_newundo(plevel, x + i, y + j, MOVE_NONE, PIECE_SPACE, PIECE_SPACE, MOVER_UNDO);
2399                                     else
2400                                         mover_newundo(plevel, x + i, y + j, MOVE_NONE, level_piece(plevel, x + i, y + j), PIECE_SPACE, MOVER_UNDO);
2401                                 }
2402                             }
2403                         }
2404                     }
2405                 break;
2406 
2407             default:
2408                 break;
2409         }
2410         effect = ACTION_NONE;
2411     }
2412 
2413     /* Restore real player value */
2414     plevel->player = player;
2415     screen_cursor(1);
2416 }
2417 
display_type()2418 int display_type()
2419 {
2420     return DISPLAY_SDL;
2421 }
2422 
scale_delay(int delay,int change)2423 int scale_delay(int delay, int change)
2424 {
2425     int tmp;
2426     int magnitude;
2427 
2428     if(delay < 1)
2429         delay = 1;
2430 
2431     if(change == 1)
2432     {
2433         tmp = delay;
2434 
2435         while(tmp >= 100)
2436             tmp = tmp / 10;
2437 
2438         magnitude = delay / tmp;
2439 
2440         if(tmp < 20)
2441             tmp = tmp + 1;
2442         else if(tmp < 50)
2443             tmp = tmp + 2;
2444         else
2445             tmp = tmp + 5;
2446 
2447         delay = tmp * magnitude;
2448 
2449         if(delay > 1000)
2450             delay = 1;
2451     }
2452 
2453     if(change == -1)
2454     {
2455         tmp = delay;
2456 
2457         while(tmp > 100)
2458             tmp = tmp / 10;
2459 
2460         magnitude = delay / tmp;
2461 
2462         if(tmp > 50)
2463             tmp = tmp - 5;
2464         else if(tmp > 20)
2465             tmp = tmp - 2;
2466         else
2467             tmp = tmp - 1;
2468 
2469         delay = tmp * magnitude;
2470 
2471         if(delay < 1)
2472             delay = 1000;
2473     }
2474 
2475     return delay;
2476 }
2477 
display_options()2478 void display_options()
2479 {
2480     struct menu* pmenu;
2481     struct menu* pgraphicsmenu;
2482     struct menu* pcoloursmenu;
2483     struct menuentry* pentryscreensize;
2484     struct menuentry* pentryfullscreen;
2485     struct menuentry* pentrygraphics;
2486     struct menuentry* pentrysize;
2487     struct menuentry* pentrylevel;
2488     struct menuentry* pentrycolours;
2489     struct menuentry* pentryspeed;
2490     struct menuentry* pentryfirstspeed;
2491     struct menuentry* pentryreplayspeed;
2492     struct menuentry* pentryundospeed;
2493     int result;
2494     int ok;
2495 
2496     char buffer[4096];
2497 
2498     pmenu = menu_new(gettext("Display Options"));
2499 
2500     menuentry_new(pmenu, gettext("Return to previous menu"), 'Q', 0);
2501     menuentry_new(pmenu, gettext("Save Options"), 'S', 0);
2502 
2503     menuentry_new(pmenu, "", 0, MENU_SPACE);
2504 
2505     pentrygraphics = menuentry_new(pmenu, gettext("Graphics Scheme"), 'G', 0);
2506     pentrysize = menuentry_new(pmenu, gettext("Graphics Size"), 'I', 0);
2507     pentrylevel = menuentry_new(pmenu, gettext("Graphics Level"), 'L', 0);
2508     pentrycolours = menuentry_new(pmenu, gettext("Colour Scheme"), 'C', 0);
2509 
2510     menuentry_new(pmenu, "", 0, MENU_SPACE);
2511 
2512     pentryscreensize = menuentry_new(pmenu, gettext("Screen size"), 'Z', 0);
2513     pentryfullscreen = menuentry_new(pmenu, gettext("Fullscreen"), 'F', 0);
2514 
2515     menuentry_new(pmenu, "", 0, MENU_SPACE);
2516 
2517     pentryfirstspeed = menuentry_new(pmenu, gettext("Player Speed"), 'P', MENU_SCROLLABLE);
2518     pentryspeed = menuentry_new(pmenu, gettext("Move Speed"), 'M', MENU_SCROLLABLE);
2519     pentryreplayspeed = menuentry_new(pmenu, gettext("Replay Speed"), 'R', MENU_SCROLLABLE);
2520     pentryundospeed = menuentry_new(pmenu, gettext("Undo Speed"), 'U', MENU_SCROLLABLE);
2521 
2522     menuentry_new(pmenu, "", 0, MENU_SPACE);
2523 
2524     menuentry_new(pmenu, gettext("Change Keys"), 'K', 0);
2525     menuentry_new(pmenu, gettext("Change Mouse"), 'O', 0);
2526 
2527     /* XOR and Enigma options are only visible once an appropriate level has
2528      * been seen so as not to confuse those simply playing Chroma levels */
2529     if(0
2530 #ifdef XOR_COMPATIBILITY
2531             || options_xor_options
2532 #endif
2533 #ifdef ENIGMA_COMPATIBILITY
2534             || options_enigma_options
2535 #endif
2536       )
2537     {
2538         menuentry_new(pmenu, "", 0, MENU_SPACE);
2539         menuentry_new(pmenu, gettext("Other Games Options"), 'X', 0);
2540     }
2541 
2542     if(options_debug & DEBUG_MENU)
2543     {
2544         menuentry_new(pmenu, "", 0, MENU_SPACE);
2545         menuentry_new(pmenu, gettext("Debug Options"), 'D', 0);
2546     }
2547 
2548     ok = 0;
2549     while(!ok)
2550     {
2551         if(options_sdl_width == 0 && options_sdl_height == 0)
2552             sprintf(buffer, gettext("Auto (%d x %d)"), screen_width, screen_height);
2553         else
2554             sprintf(buffer, "%d x %d", screen_width, screen_height);
2555         menuentry_extratext(pentryscreensize, buffer, NULL, NULL);
2556 
2557         menuentry_extratext(pentryfullscreen, screen_fullscreen ? gettext("Yes") : gettext("No"), NULL, NULL);
2558 
2559         sprintf(buffer, gettext("%d milliseconds"), options_sdl_delay);
2560         menuentry_extratext(pentryspeed, buffer, NULL, NULL);
2561 
2562         sprintf(buffer, gettext("%d milliseconds"), options_sdl_player_delay);
2563         menuentry_extratext(pentryfirstspeed, buffer, NULL, NULL);
2564 
2565         sprintf(buffer, gettext("%d milliseconds"), options_sdl_replay_delay);
2566         menuentry_extratext(pentryreplayspeed, buffer, NULL, NULL);
2567 
2568         sprintf(buffer, gettext("%d milliseconds"), options_sdl_undo_delay);
2569         menuentry_extratext(pentryundospeed, buffer, NULL, NULL);
2570 
2571         if(pdisplaygraphics != NULL)
2572         {
2573             if(options_sdl_size_x != pdisplaygraphics->size_x || options_sdl_size_y != pdisplaygraphics->size_y)
2574                 sprintf(buffer, gettext("Auto (%d x %d)"), pdisplaygraphics->size_x, pdisplaygraphics->size_y);
2575 
2576             else
2577                 sprintf(buffer, "%d x %d", pdisplaygraphics->size_x, pdisplaygraphics->size_y);
2578 
2579             menuentry_extratext(pentrysize, buffer, NULL, NULL);
2580 
2581             menuentry_extratext(pentrygraphics, pdisplaygraphics->title != NULL ? pdisplaygraphics->title : gettext("[untitled graphics]"), NULL, NULL);
2582 
2583             if(pdisplaygraphics->title == NULL)
2584                 menuentry_extratext(pentrygraphics, gettext("[untitled graphics]"), NULL, NULL);
2585             else if(pdisplaygraphics->flags & GRAPHICS_TRANSLATE)
2586                 menuentry_extratext(pentrygraphics, gettext(pdisplaygraphics->title), NULL, NULL);
2587             else
2588                 menuentry_extratext(pentrygraphics, pdisplaygraphics->title, NULL, NULL);
2589 
2590             if(options_graphic_level != 0)
2591                 sprintf(buffer, "%d / %d", options_graphic_level, pdisplaygraphics->levels);
2592             else
2593                 sprintf(buffer, gettext("Auto (%d)"), pdisplaygraphics->levels);
2594 
2595             menuentry_extratext(pentrylevel, buffer, NULL, NULL);
2596         }
2597         else
2598             menuentry_extratext(pentrygraphics, gettext("** NONE **"), NULL, NULL);
2599 
2600         if(pdisplaygraphics != NULL && (pdisplaygraphics->flags & GRAPHICS_CURSES))
2601             pentrycolours->flags = 0;
2602         else
2603             pentrycolours->flags = MENU_INVISIBLE | MENU_GREY;
2604 
2605         if(pdisplaygraphics != NULL && pdisplaygraphics->sizes != NULL)
2606             pentrysize->flags = 0;
2607         else
2608             pentrysize->flags = MENU_INVISIBLE | MENU_GREY;
2609 
2610         if(pdisplaygraphics != NULL && pdisplaygraphics->levels > 0)
2611             pentrylevel->flags = MENU_SCROLLABLE;
2612         else
2613             pentrylevel->flags = MENU_INVISIBLE | MENU_GREY;
2614 
2615         if(pdisplaycolours == NULL)
2616             menuentry_extratext(pentrycolours, gettext("** NONE **"), NULL, NULL);
2617         else if(pdisplaycolours->title == NULL)
2618             menuentry_extratext(pentrycolours, gettext("[untitled colours]"), NULL, NULL);
2619         else if(pdisplaycolours->flags & COLOURS_TRANSLATE)
2620             menuentry_extratext(pentrycolours, gettext(pdisplaycolours->title), NULL, NULL);
2621         else
2622             menuentry_extratext(pentrycolours, pdisplaycolours->title, NULL, NULL);
2623 
2624         result = menu_process(pmenu);
2625         if(result == MENU_QUIT)
2626             ok = 1;
2627 
2628         if(result == MENU_SELECT && pmenu->entry_selected != NULL)
2629         {
2630             switch(pmenu->entry_selected->key)
2631             {
2632                 case 'Q':
2633                     ok = 1;
2634                     break;
2635 
2636                 case 'Z':
2637                     display_screensizemenu();
2638                     break;
2639 
2640                 case 'F':
2641                     screen_fullscreen = 1 - screen_fullscreen;
2642                     screen_resize(screen_width, screen_height, screen_fullscreen);
2643                     options_sdl_fullscreen = screen_fullscreen;
2644                     break;
2645 
2646                 case 'G':
2647                     pgraphicsmenu = graphics_menu();
2648                     if(menu_process(pgraphicsmenu) == MENU_SELECT)
2649                     {
2650                         if(pgraphicsmenu->entry_selected != NULL && pgraphicsmenu->entry_selected->value != NULL)
2651                         {
2652                             strcpy(options_graphics, pgraphicsmenu->entry_selected->value);
2653                             graphics_init();
2654                         }
2655                     }
2656                     menu_delete(pgraphicsmenu);
2657                     break;
2658 
2659                 case 'C':
2660                     pcoloursmenu = colours_menu();
2661                     if(menu_process(pcoloursmenu) == MENU_SELECT)
2662                     {
2663                         if(pcoloursmenu->entry_selected != NULL && pcoloursmenu->entry_selected->value != NULL)
2664                         {
2665                             strcpy(options_colours, pcoloursmenu->entry_selected->value);
2666                             colours_init();
2667                             graphics_init();
2668                         }
2669                     }
2670                     menu_delete(pcoloursmenu);
2671                     break;
2672 
2673                 case 'I':
2674                     display_options_size();
2675                     break;
2676 
2677                 case 'S':
2678                     display_options_save();
2679                     ok = 1;
2680                     break;
2681 
2682                 case 'K':
2683                     display_options_keys();
2684                     break;
2685 
2686                 case 'O':
2687                     display_options_mouse();
2688                     break;
2689 
2690                 case 'X':
2691                     display_options_othergames();
2692                     break;
2693 
2694                 case 'D':
2695                     display_options_debug();
2696                     break;
2697             }
2698         }
2699 
2700         if(result == MENU_SCROLLLEFT && pmenu->entry_selected != NULL)
2701         {
2702             switch(pmenu->entry_selected->key)
2703             {
2704                 case 'M':
2705                     options_sdl_delay = scale_delay(options_sdl_delay, -1);
2706                     break;
2707                 case 'P':
2708                     options_sdl_player_delay = scale_delay(options_sdl_player_delay, -1);
2709                     break;
2710                 case 'R':
2711                     options_sdl_replay_delay = scale_delay(options_sdl_replay_delay, -1);
2712                     break;
2713                 case 'U':
2714                     options_sdl_undo_delay = scale_delay(options_sdl_undo_delay, -1);
2715                     break;
2716                 case 'L':
2717                     options_graphic_level --;
2718                     if(options_graphic_level < 0)
2719                         options_graphic_level = pdisplaygraphics->levels;
2720                     graphics_reload();
2721                     break;
2722             }
2723         }
2724 
2725         if(result == MENU_SCROLLRIGHT && pmenu->entry_selected != NULL)
2726         {
2727             switch(pmenu->entry_selected->key)
2728             {
2729                 case 'M':
2730                     options_sdl_delay = scale_delay(options_sdl_delay, 1);
2731                     break;
2732                 case 'P':
2733                     options_sdl_player_delay = scale_delay(options_sdl_player_delay, 1);
2734                     break;
2735                 case 'R':
2736                     options_sdl_replay_delay = scale_delay(options_sdl_replay_delay, 1);
2737                     break;
2738                 case 'U':
2739                     options_sdl_undo_delay = scale_delay(options_sdl_undo_delay, 1);
2740                     break;
2741                 case 'L':
2742                     options_graphic_level ++;
2743                     if(options_graphic_level > pdisplaygraphics->levels)
2744                         options_graphic_level = 0;
2745                     graphics_reload();
2746                     break;
2747             }
2748         }
2749 
2750 
2751     }
2752 
2753     menu_delete(pmenu);
2754 }
2755 
display_clip(struct level * plevel,int clip)2756 void display_clip(struct level* plevel, int clip)
2757 {
2758     SDL_Rect crect;
2759 
2760     if(clip)
2761     {
2762         crect.x = 0;
2763         crect.y = 0;
2764         crect.w = screen_width;
2765         crect.h = screen_height - display_bar_pixels;
2766 
2767 #ifdef XOR_COMPATIBILITY
2768         if(plevel->mode == MODE_XOR && options_xor_display)
2769         {
2770             crect.w = pdisplaygraphics->size_x * 8;
2771             crect.h = pdisplaygraphics->size_y * 8;
2772             crect.x = (screen_width - crect.w) / 2;
2773             crect.y = (screen_height - display_bar_pixels - crect.h) / 2;
2774 
2775             /* Ensure bar is always visible */
2776             if(crect.y + crect.h > screen_height - display_bar_pixels)
2777                 crect.h = screen_height - display_bar_pixels - crect.y;
2778         }
2779 #endif
2780 
2781         SDL_SetClipRect(screen_surface, &crect);
2782     }
2783     else
2784     {
2785         SDL_SetClipRect(screen_surface, NULL);
2786     }
2787 }
2788 
2789 
display_screensizemenu()2790 void display_screensizemenu()
2791 {
2792     struct menu* pmenu;
2793     struct menuentry *pentry;
2794 
2795     int sizes[6][2] = { {640, 480}, {800, 600}, {1024, 768}, {1280, 1024}, {1600, 1200}, {0, 0} };
2796     int i;
2797     char buffer[256], tmp[256];
2798     int custom;
2799     SDL_Rect **modes;
2800     int w, h;
2801     int ok;
2802 
2803     custom = 1;
2804 
2805     pmenu = menu_new(gettext("Screen Size"));
2806 
2807     menuentry_new(pmenu, gettext("Quit and return to previous menu"), 'Q', 0);
2808     menuentry_new(pmenu, "", 0, MENU_SPACE);
2809 
2810     pentry = menuentry_new(pmenu, gettext("Automatic sizing"), 0, 0);
2811     menuentry_extratext(pentry, NULL, "0", "0");
2812     if(options_sdl_width == 0 && options_sdl_height == 0)
2813     {
2814         pmenu->entry_selected = pentry;
2815         custom = 0;
2816     }
2817 
2818     /* First, add modes that we know the screen can do */
2819     modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
2820     if(modes != (SDL_Rect **)0 && modes != (SDL_Rect **)-1)
2821     {
2822         for(i = 0; modes[i]; i ++)
2823         {
2824             w = modes[i]->w; h = modes[i]->h;
2825             sprintf(buffer, "%d x %d", w, h);
2826 
2827             pentry = pmenu->entry_first; ok = 1;
2828             while(pentry != NULL)
2829             {
2830                 if(pentry->text != NULL && strcmp(pentry->text, buffer) == 0)
2831                 {
2832                     ok = 0;
2833                 }
2834                 pentry = pentry->next;
2835             }
2836 
2837             if(ok)
2838             {
2839                 sprintf(tmp, "%04dx%04d", w, h);
2840                 pentry = menuentry_newwithvalue(pmenu, buffer, 0, MENU_SORT, tmp);
2841                 sprintf(buffer, "%d", w);
2842                 sprintf(tmp, "%d", h);
2843                 menuentry_extratext(pentry, NULL, buffer, tmp);
2844                 if(options_sdl_width == w && options_sdl_height == h)
2845                     pmenu->entry_selected = pentry;
2846                 if(screen_width == w && screen_height == h)
2847                     custom = 0;
2848             }
2849         }
2850     }
2851 
2852     /* Then add any of the default modes that haven't been already added */
2853     i = 0;
2854     while(sizes[i][0] != 0)
2855     {
2856         sprintf(buffer, "%d x %d", sizes[i][0], sizes[i][1]);
2857         pentry = pmenu->entry_first; ok = 1;
2858         while(pentry != NULL)
2859         {
2860             if(pentry->text != NULL && strcmp(pentry->text, buffer) == 0)
2861             {
2862                 ok = 0;
2863             }
2864             pentry = pentry->next;
2865         }
2866 
2867         if(ok)
2868         {
2869             sprintf(tmp, "%04dx%04d", sizes[i][0], sizes[i][1]);
2870             pentry = menuentry_newwithvalue(pmenu, buffer, 0, MENU_SORT, tmp);
2871             sprintf(buffer, "%d", sizes[i][0]);
2872             sprintf(tmp, "%d", sizes[i][1]);
2873             menuentry_extratext(pentry, NULL, buffer, tmp);
2874             if(options_sdl_width == sizes[i][0] && options_sdl_height == sizes[i][1])
2875                 pmenu->entry_selected = pentry;
2876             if(screen_width == sizes[i][0] && screen_height == sizes[i][1])
2877                 custom = 0;
2878         }
2879 
2880         i ++;
2881     }
2882     if(custom)
2883     {
2884         sprintf(buffer, gettext("Custom (%d x %d)"), screen_width, screen_height);
2885         pentry = menuentry_new(pmenu, buffer, 0, 0);
2886         sprintf(buffer, "%d", screen_width);
2887         sprintf(buffer + 16, "%d", screen_height);
2888         menuentry_extratext(pentry, NULL, buffer, buffer + 16);
2889         pmenu->entry_selected = pentry;
2890     }
2891 
2892     pentry = menuentry_new(pmenu, gettext("Current screen size:"), 0, MENU_NOTE);
2893     sprintf(buffer, gettext("%d x %d (%d bits per pixel)"), screen_width, screen_height, screen_surface->format->BitsPerPixel);
2894     pentry = menuentry_new(pmenu, buffer, 0, MENU_NOTE | MENU_RIGHT);
2895 
2896     menu_assignletters(pmenu);
2897 
2898     if(menu_process(pmenu) == MENU_SELECT)
2899     {
2900         if(pmenu->entry_selected->text3 != NULL)
2901         {
2902             options_sdl_width = atoi(pmenu->entry_selected->text3);
2903             options_sdl_height = atoi(pmenu->entry_selected->text4);
2904             screen_resize(options_sdl_width, options_sdl_height, screen_fullscreen);
2905         }
2906     }
2907 
2908     menu_delete(pmenu);
2909 }
2910 
display_keyfixed(SDLKey key)2911 int display_keyfixed(SDLKey key)
2912 {
2913     if(key == SDLK_ESCAPE || key == SDLK_q || key == SDLK_RETURN || key == SDLK_UP || key == SDLK_DOWN || key == SDLK_LEFT || key == SDLK_RIGHT)
2914         return 1;
2915 
2916     return 0;
2917 }
2918 
display_keyname(SDLKey key)2919 char *display_keyname(SDLKey key)
2920 {
2921     return SDL_GetKeyName(key);
2922 }
2923 
display_addkeytomenu(struct menu * pmenu,int action,char * text)2924 void display_addkeytomenu(struct menu* pmenu, int action, char *text)
2925 {
2926     struct menuentry *pentry;
2927     char buffer[256];
2928     SDLKey key;
2929 
2930     sprintf(buffer, "%d", action);
2931     pentry = menuentry_newwithvalue(pmenu, text, 0, MENU_DOUBLE, buffer);
2932 
2933     strcpy(buffer, "");
2934     for(key = SDLK_FIRST; key < SDLK_LAST; key ++)
2935     {
2936         if(actions[key] == action)
2937         {
2938             if(strlen(buffer) != 0)
2939                 strcat(buffer,", ");
2940             strcat(buffer, "[");
2941             strcat(buffer, display_keyname(key));
2942             strcat(buffer, "]");
2943         }
2944     }
2945 
2946     if(strcmp(buffer, "") == 0)
2947         strcpy(buffer, gettext("(none)"));
2948 
2949     menuentry_extratext(pentry, NULL, NULL, buffer);
2950 }
2951 
display_options_keys()2952 void display_options_keys()
2953 {
2954     struct menu *pmenu;
2955     struct menu *psubmenu;
2956     struct menuentry *pentry;
2957     int redraw;
2958     int action;
2959     int result;
2960     int ok;
2961     int subok;
2962     char buffer[256];
2963     SDLKey key;
2964     SDL_Event event;
2965 
2966     ok = 0;
2967     while(!ok)
2968     {
2969         pmenu = menu_new(gettext("Keys"));
2970 
2971         menuentry_new(pmenu, gettext("Quit and return to previous menu"), 'Q', 0);
2972         menuentry_new(pmenu, "", 0, MENU_SPACE);
2973 
2974         display_addkeytomenu(pmenu, ACTION_LEFT, gettext(action_name[ACTION_LEFT]));
2975         display_addkeytomenu(pmenu, ACTION_RIGHT, gettext(action_name[ACTION_RIGHT]));
2976         display_addkeytomenu(pmenu, ACTION_UP, gettext(action_name[ACTION_UP]));
2977         display_addkeytomenu(pmenu, ACTION_DOWN, gettext(action_name[ACTION_DOWN]));
2978         display_addkeytomenu(pmenu, ACTION_SWAP, gettext(action_name[ACTION_SWAP]));
2979         display_addkeytomenu(pmenu, ACTION_UNDO, gettext(action_name[ACTION_UNDO]));
2980         display_addkeytomenu(pmenu, ACTION_REDO, gettext(action_name[ACTION_REDO]));
2981         display_addkeytomenu(pmenu, ACTION_FAST, gettext(action_name[ACTION_FAST]));
2982         display_addkeytomenu(pmenu, ACTION_FASTER, gettext(action_name[ACTION_FASTER]));
2983         display_addkeytomenu(pmenu, ACTION_SLOWER, gettext(action_name[ACTION_SLOWER]));
2984         display_addkeytomenu(pmenu, ACTION_PAUSE, gettext(action_name[ACTION_PAUSE]));
2985         display_addkeytomenu(pmenu, ACTION_QUIT, gettext(action_name[ACTION_QUIT]));
2986         display_addkeytomenu(pmenu, ACTION_REDRAW, gettext(action_name[ACTION_REDRAW]));
2987         display_addkeytomenu(pmenu, ACTION_HIDE, gettext(action_name[ACTION_HIDE]));
2988         display_addkeytomenu(pmenu, ACTION_PIECE_LEFT, gettext(action_name[ACTION_PIECE_LEFT]));
2989         display_addkeytomenu(pmenu, ACTION_PIECE_RIGHT, gettext(action_name[ACTION_PIECE_RIGHT]));
2990 
2991         menu_assignletters(pmenu);
2992 
2993         result = menu_process(pmenu);
2994 
2995         if(result == MENU_QUIT)
2996             ok = 1;
2997 
2998         if(result == MENU_SELECT)
2999         {
3000             if(pmenu->entry_selected->key == 'Q')
3001                 ok = 1;
3002             else if(pmenu->entry_selected->value != NULL)
3003             {
3004                 subok = 0;
3005                 redraw = MENUREDRAW_ALL;
3006                 while(!subok)
3007                 {
3008                     action = atoi(pmenu->entry_selected->value);
3009 
3010                     sprintf(buffer, gettext("Set keys for '%s'"), gettext(action_name[action]));
3011                     psubmenu = menu_new(buffer);
3012 
3013                     menuentry_new(psubmenu, gettext("Quit and return to previous menu"), 'Q', 0);
3014                     menuentry_new(psubmenu, "", 0, MENU_SPACE);
3015 
3016                     for(key = SDLK_FIRST; key < SDLK_LAST; key ++)
3017                     {
3018                         if(actions[key] == action)
3019                         {
3020                             sprintf(buffer, "[%s]", display_keyname(key));
3021                             pentry = menuentry_new(psubmenu, buffer, 0, MENU_GREY);
3022                             if(display_keyfixed(key))
3023                                 menuentry_extratext(pentry, gettext("(fixed)"), NULL, NULL);
3024                         }
3025                     }
3026 
3027                     menuentry_new(psubmenu, gettext("Press a key to add or remove it from this list."), 0, MENU_NOTE | MENU_CENTRE);
3028 
3029                     menu_display(psubmenu, redraw);
3030                     redraw = MENUREDRAW_ENTRIES;
3031 
3032                     menu_delete(psubmenu);
3033 
3034                     subok = 0;
3035                     while(!subok)
3036                     {
3037                         SDL_WaitEvent(&event);
3038 
3039                         switch(event.type)
3040                         {
3041                             case SDL_KEYDOWN:
3042                                 key = event.key.keysym.sym;
3043                                 if(key == SDLK_q || key == SDLK_ESCAPE)
3044                                     subok = 1;
3045                                 else if(!display_keyfixed(key))
3046                                 {
3047                                     if(actions[key] == action)
3048                                         actions[key] = ACTION_NONE;
3049                                     else
3050                                         actions[key] = action;
3051 
3052                                     subok = 2;
3053                                 }
3054                                 break;
3055 
3056                             case SDL_QUIT:
3057                                 exit(0);
3058 
3059                             case SDL_VIDEORESIZE:
3060                                 screen_resizeevent(&event);
3061                                 subok = 2;
3062                                 redraw = MENUREDRAW_ALL;
3063                                 break;
3064 
3065                             case SDL_ACTIVEEVENT:
3066                                 if((event.active.state & SDL_APPACTIVE) && event.active.gain == 1)
3067                                     redraw = MENUREDRAW_ALL;
3068                                 break;
3069                         }
3070                     }
3071                     if(subok == 2)
3072                         subok = 0;
3073                 }
3074             }
3075         }
3076 
3077         menu_delete(pmenu);
3078     }
3079 }
3080 
display_options_mouse()3081 void display_options_mouse()
3082 {
3083     struct menu *pmenu;
3084     struct menu *psubmenu;
3085     struct menuentry *pentry;
3086     int result;
3087     int ok;
3088     int subok;
3089     int i, j, k;
3090     int button, where;
3091     char buffer[256];
3092 
3093     char *locations[] = {"Game", "Editor", "Menu"};
3094 
3095     int actions_game[] = {
3096         ACTION_NONE,
3097         ACTION_MOUSE_CLICK,
3098         ACTION_MOUSE_DRAG,
3099         ACTION_MOUSE_DRAG_OR_CLICK,
3100         ACTION_SWAP,
3101         ACTION_UNDO,
3102         ACTION_REDO,
3103         ACTION_HIDE,
3104         ACTION_QUIT,
3105         ACTION_MAX
3106     };
3107 
3108     int actions_edit[] = {
3109         ACTION_NONE,
3110         ACTION_MOUSE_CLICK,
3111         ACTION_MOUSE_DRAG,
3112         ACTION_MOUSE_DRAG_OR_CLICK,
3113         ACTION_PIECE_LEFT,
3114         ACTION_PIECE_RIGHT,
3115         ACTION_HIDE,
3116         ACTION_QUIT,
3117         ACTION_MAX
3118     };
3119 
3120     int actions_menu[] = {
3121         ACTION_NONE,
3122         ACTION_UP,
3123         ACTION_DOWN,
3124         ACTION_PAGE_UP,
3125         ACTION_PAGE_DOWN,
3126         ACTION_HIDE,
3127         ACTION_MOUSE_CLICK,
3128         ACTION_QUIT,
3129         ACTION_MAX
3130     };
3131 
3132     int *actions_available[] = {
3133         actions_game,
3134         actions_edit,
3135         actions_menu,
3136     };
3137 
3138     char *actions_names_game[] = {
3139         "Do nothing",
3140         "Click to move player",
3141         "Drag to scroll screen",
3142         "Click to move player, drag to scroll screen",
3143         "Click to swap player",
3144         "Undo move",
3145         "Redo move",
3146         "Hide screen",
3147         "Return to previous menu",
3148         ""
3149     };
3150 
3151     char *actions_names_edit[] = {
3152         "Do nothing",
3153         "Click to set piece",
3154         "Drag to scroll screen",
3155         "Click to set piece, drag to scroll screen",
3156         "Piece left",
3157         "Piece right",
3158         "Hide screen",
3159         "Return to previous menu",
3160         ""
3161     };
3162 
3163     char *actions_names_menu[] = {
3164         "Do nothing",
3165         "Move up",
3166         "Move down",
3167         "Page up",
3168         "Page down",
3169         "Hide screen",
3170         "Select entry",
3171         "Return to previous menu",
3172         ""
3173     };
3174 
3175     char **actions_names[] = {
3176         actions_names_game,
3177         actions_names_edit,
3178         actions_names_menu,
3179     };
3180 
3181     ok = 0;
3182     pmenu = menu_new(gettext("Mouse"));
3183 
3184     menuentry_new(pmenu, gettext("Quit and return to previous menu"), 'Q', 0);
3185 
3186     for(i = 0; i < 3; i ++)
3187     {
3188         menuentry_new(pmenu, "", 0, MENU_SPACE);
3189         menuentry_new(pmenu, locations[i], 0, MENU_GREY);
3190         for(j = 1; j < MOUSE_BUTTONS_MAX; j ++)
3191         {
3192             sprintf(buffer, gettext("Button %d"), j);
3193             pentry = menuentry_new(pmenu, buffer, 0, 0);
3194 
3195             sprintf(buffer, "%d%d", i, j);
3196             menuentry_value(pentry, buffer);
3197 
3198             /* Should be overwritten shortly - this is a fallback if not */
3199             sprintf(buffer, "? %s", gettext(action_name[actions_mouse[i][j]]));
3200             menuentry_extratext(pentry, buffer, NULL, NULL);
3201 
3202             /* Perhaps not the neatest way of doing this here, but saves
3203                having to have redundant actions merely to give them different
3204                names. */
3205             k = 0;
3206             while(actions_available[i][k] != ACTION_MAX)
3207             {
3208                 if(actions_available[i][k] == actions_mouse[i][j])
3209                     menuentry_extratext(pentry, gettext(actions_names[i][k]), NULL, NULL);
3210                 k ++;
3211             }
3212         }
3213     }
3214 
3215     menu_assignletters(pmenu);
3216 
3217     ok  = 0;
3218     while(!ok)
3219     {
3220         result = menu_process(pmenu);
3221 
3222         if(result == MENU_QUIT)
3223             ok = 1;
3224 
3225         if(result == MENU_SELECT)
3226         {
3227             if(pmenu->entry_selected->key == 'Q')
3228                 ok = 1;
3229             else if(pmenu->entry_selected->value != NULL)
3230             {
3231                 where = pmenu->entry_selected->value[0] - '0';
3232                 button = pmenu->entry_selected->value[1] - '0';
3233                 sprintf(buffer, gettext("Set action for button %d in %s"), button, locations[where]);
3234                 psubmenu = menu_new(buffer);
3235 
3236                 menuentry_new(psubmenu, gettext("Quit and return to previous menu"), 'Q', 0);
3237                 menuentry_new(psubmenu, "", 0, MENU_SPACE);
3238 
3239                 i = 0;
3240                 while(actions_available[where][i] != ACTION_MAX)
3241                 {
3242                     pentry = menuentry_new(psubmenu, gettext(actions_names[where][i]), 0, 0);
3243                     sprintf(buffer, "%d", i);
3244                     menuentry_value(pentry, buffer);
3245                     if(actions_mouse[where][button] == actions_available[where][i])
3246                     {
3247                         psubmenu->entry_selected = pentry;
3248 
3249                         menuentry_new(psubmenu, gettext("Current action is:"), 0, MENU_NOTE);
3250                         menuentry_new(psubmenu, gettext(actions_names[where][i]), 0, MENU_NOTE | MENU_RIGHT);
3251                     }
3252 
3253                     i ++;
3254                 }
3255 
3256                 menu_assignletters(psubmenu);
3257 
3258                 subok = 0;
3259                 while(!subok)
3260                 {
3261                     result = menu_process(psubmenu);
3262 
3263                     if(result == MENU_QUIT)
3264                         subok = 1;
3265 
3266                     if(result == MENU_SELECT)
3267                     {
3268                         if(psubmenu->entry_selected->key == 'Q')
3269                             subok = 1;
3270                         else if(psubmenu->entry_selected->value != NULL)
3271                         {
3272                             actions_mouse[where][button] = actions_available[where][atoi(psubmenu->entry_selected->value)];
3273                             menuentry_extratext(pmenu->entry_selected, gettext(actions_names[where][atoi(psubmenu->entry_selected->value)]), NULL, NULL);
3274                             subok = 1;
3275                         }
3276                     }
3277 
3278                 }
3279                 menu_delete(psubmenu);
3280             }
3281         }
3282 
3283     }
3284 
3285     menu_delete(pmenu);
3286 }
3287 
display_options_size()3288 void display_options_size()
3289 {
3290     struct menu* pmenu;
3291     struct menuentry* pentry;
3292     struct graphicssize* psize;
3293     char buffer[4096];
3294 
3295     pmenu = menu_new(gettext("Graphics Size"));
3296 
3297     menuentry_new(pmenu, gettext("Quit and return to previous menu"), 'Q', 0);
3298     menuentry_new(pmenu, "", 0, MENU_SPACE);
3299 
3300     menuentry_new(pmenu, gettext("Current graphics size:"), 0, MENU_NOTE);
3301     if(pdisplaygraphics != NULL)
3302     {
3303         if(options_sdl_size_x != pdisplaygraphics->size_x || options_sdl_size_y != pdisplaygraphics->size_y)
3304             sprintf(buffer, gettext("Automatic (%d x %d)"), pdisplaygraphics->size_x, pdisplaygraphics->size_y);
3305         else
3306             sprintf(buffer, "%d x %d", pdisplaygraphics->size_x, pdisplaygraphics->size_y);
3307         menuentry_new(pmenu, buffer, 0, MENU_NOTE | MENU_RIGHT);
3308     }
3309     else
3310         menuentry_new(pmenu, gettext("** NONE **"), 0, MENU_NOTE | MENU_RIGHT);
3311 
3312     pentry = menuentry_new(pmenu, gettext("Automatic sizing"), 0, 0);
3313     menuentry_extratext(pentry, NULL, "0", "0");
3314     if(options_sdl_size_x != pdisplaygraphics->size_x || options_sdl_size_y != pdisplaygraphics->size_y)
3315         pmenu->entry_selected = pentry;
3316 
3317     psize = pdisplaygraphics->sizes;
3318     while(psize != NULL)
3319     {
3320         if(psize->flags & SIZE_PIECES)
3321         {
3322             sprintf(buffer, "%d x %d", psize->x, psize->y);
3323             pentry = menuentry_new(pmenu, buffer, 0, 0);
3324             if(psize->x == options_sdl_size_x && psize->y == options_sdl_size_y)
3325                 pmenu->entry_selected = pentry;
3326             sprintf(buffer, "%d", psize->x);
3327             sprintf(buffer + 16, "%d", psize->y);
3328             menuentry_extratext(pentry, NULL, buffer, buffer + 16);
3329         }
3330         psize = psize->next;
3331     }
3332     menu_assignletters(pmenu);
3333 
3334     if(menu_process(pmenu) == MENU_SELECT)
3335     {
3336         if(pmenu->entry_selected->text3 != NULL)
3337         {
3338             options_sdl_size_x = atoi(pmenu->entry_selected->text3);
3339             options_sdl_size_y = atoi(pmenu->entry_selected->text4);
3340 
3341             graphics_init();
3342         }
3343     }
3344 
3345     menu_delete(pmenu);
3346 }
3347 
display_options_debug()3348 void display_options_debug()
3349 {
3350     struct menu* pmenu;
3351     struct menuentry* pentryorder;
3352     struct menuentry* pentrymovers;
3353     struct menuentry* pentryspeed;
3354     struct menuentry* pentryhidden;
3355 
3356     int ok;
3357     int result;
3358 
3359     pmenu = menu_new(gettext("Debug Options"));
3360 
3361     menuentry_new(pmenu, gettext("Return to previous menu"), 'Q', 0);
3362 
3363     menuentry_new(pmenu, "", 0, MENU_SPACE);
3364 
3365     pentryorder = menuentry_new(pmenu, gettext("Display order of movers"), 'O', 0);
3366     pentrymovers = menuentry_new(pmenu, gettext("List movers on stderr"), 'M', 0);
3367     pentryspeed = menuentry_new(pmenu, gettext("Show frames per second"), 'F', 0);
3368     pentryhidden = menuentry_new(pmenu, gettext("Show hidden items"), 'H', 0);
3369 
3370     ok = 0;
3371     while(!ok)
3372     {
3373         menuentry_extratext(pentryorder, options_debug & DEBUG_ORDER ? gettext("yes") : gettext("no"), NULL, NULL);
3374         menuentry_extratext(pentrymovers, options_debug & DEBUG_MOVERS ? gettext("yes") : gettext("no"), NULL, NULL);
3375         menuentry_extratext(pentryspeed, options_debug & DEBUG_SPEED ? gettext("yes") : gettext("no"), NULL, NULL);
3376         menuentry_extratext(pentryhidden, options_debug & DEBUG_HIDDEN ? gettext("yes") : gettext("no"), NULL, NULL);
3377 
3378         result = menu_process(pmenu);
3379         if(result == MENU_QUIT)
3380             ok = 1;
3381 
3382         if(result == MENU_SELECT && pmenu->entry_selected != NULL)
3383         {
3384             switch(pmenu->entry_selected->key)
3385             {
3386                 case 'Q':
3387                     ok = 1;
3388                     break;
3389 
3390                 case 'O':
3391                     options_debug ^= DEBUG_ORDER;
3392                     break;
3393 
3394                 case 'M':
3395                     options_debug ^= DEBUG_MOVERS;
3396                     break;
3397 
3398                 case 'F':
3399                     options_debug ^= DEBUG_SPEED;
3400                     break;
3401 
3402                 case 'H':
3403                     options_debug ^= DEBUG_HIDDEN;
3404                     break;
3405             }
3406 
3407             pmenu->redraw = MENUREDRAW_CHANGED;
3408             pmenu->entry_selected->redraw = 1;
3409         }
3410 
3411     }
3412 
3413     menu_delete(pmenu);
3414 }
3415 
display_options_othergames()3416 void display_options_othergames()
3417 {
3418     struct menu* pmenu;
3419 #ifdef XOR_COMPATIBILITY
3420     struct menuentry* pentryxormode;
3421     struct menuentry* pentryxordisplay;
3422 #endif
3423 #ifdef ENIGMA_COMPATIBILITY
3424     struct menuentry* pentryenigmamode;
3425 #endif
3426 
3427     int ok;
3428     int result;
3429 
3430     pmenu = menu_new(gettext("Other Games Options"));
3431 
3432     menuentry_new(pmenu, gettext("Return to previous menu"), 'Q', 0);
3433 
3434     menuentry_new(pmenu, "", 0, MENU_SPACE);
3435 
3436 #ifdef XOR_COMPATIBILITY
3437     pentryxormode = menuentry_new(pmenu, gettext("XOR Engine"), 'X', options_xor_options ? 0 : MENU_INVISIBLE | MENU_GREY);
3438     pentryxordisplay = menuentry_new(pmenu, gettext("XOR Display"), 'D', options_xor_options ? 0 : MENU_INVISIBLE | MENU_GREY);
3439     if(options_xor_options)
3440         menuentry_new(pmenu, "", 0, MENU_SPACE);
3441 #endif
3442 
3443 #ifdef ENIGMA_COMPATIBILITY
3444     pentryenigmamode = menuentry_new(pmenu, gettext("Enigma Engine"), 'E', options_enigma_options ? 0 : MENU_INVISIBLE | MENU_GREY);
3445 #endif
3446 
3447     ok = 0;
3448     while(!ok)
3449     {
3450 #ifdef XOR_COMPATIBILITY
3451         menuentry_extratext(pentryxormode, options_xor_mode ? gettext("exact") : gettext("approximate"), NULL, NULL);
3452         menuentry_extratext(pentryxordisplay, options_xor_display ? gettext("partial") : gettext("full"), NULL, NULL);
3453 #endif
3454 #ifdef ENIGMA_COMPATIBILITY
3455         menuentry_extratext(pentryenigmamode, options_enigma_mode ? gettext("exact") : gettext("approximate"), NULL, NULL);
3456 #endif
3457 
3458         result = menu_process(pmenu);
3459         if(result == MENU_QUIT)
3460             ok = 1;
3461 
3462         if(result == MENU_SELECT && pmenu->entry_selected != NULL)
3463         {
3464             switch(pmenu->entry_selected->key)
3465             {
3466                 case 'Q':
3467                     ok = 1;
3468                     break;
3469 
3470 #ifdef XOR_COMPATIBILITY
3471                 case 'X':
3472                     options_xor_mode = 1 - options_xor_mode;
3473                     break;
3474 
3475                 case 'D':
3476                     options_xor_display = 1 - options_xor_display;
3477                     break;
3478 #endif
3479 
3480 #ifdef ENIGMA_COMPATIBILITY
3481                 case 'E':
3482                     options_enigma_mode = 1 - options_enigma_mode;
3483                     break;
3484 #endif
3485             }
3486 
3487             pmenu->redraw = MENUREDRAW_CHANGED;
3488             pmenu->entry_selected->redraw = 1;
3489         }
3490 
3491     }
3492 
3493     menu_delete(pmenu);
3494 }
3495 
display_options_save()3496 void display_options_save()
3497 {
3498     FILE *file;
3499     char filename[FILENAME_MAX];
3500     SDLKey key;
3501     int i, j;
3502     char *locations[] = {"game", "editor", "menu"};
3503 
3504     getfilename("sdl.chroma", filename, 1, LOCATION_LOCAL);
3505 
3506     file = fopen(filename, "w");
3507     if(file == NULL)
3508     {
3509         warning("Unable to save options");
3510         return;
3511     }
3512 
3513     fprintf(file, "<!-- Chroma SDL options \n"
3514                   "     This file is automatically generated. -->\n"
3515                   "\n"
3516                   "<chroma type=\"options\">\n");
3517 
3518     fprintf(file, "    <screen ");
3519     if(options_sdl_width == 0 && options_sdl_height == 0)
3520         fprintf(file, "width=\"auto\" height=\"auto\" ");
3521     else
3522         fprintf(file, "width=\"%d\" height=\"%d\" ", options_sdl_width, options_sdl_height);
3523     fprintf(file, "fullscreen=\"%s\" />\n", options_sdl_fullscreen == 1 ? "yes" : "no");
3524 
3525     fprintf(file, "    <graphics scheme=\"%s\" ", options_graphics);
3526     if(options_graphic_level != 0)
3527         fprintf(file, "level=\"%d\" ", options_graphic_level);
3528     if(options_sdl_size_x == 0)
3529         fprintf(file, "width=\"auto\" height=\"auto\" />\n");
3530     else
3531         fprintf(file, "width=\"%d\" height=\"%d\" />\n", options_sdl_size_x, options_sdl_size_y);
3532 
3533     fprintf(file, "    <colour scheme=\"%s\" />\n", options_colours);
3534 
3535     fprintf(file, "    <move speed=\"%d\" />\n", options_sdl_delay);
3536     fprintf(file, "    <player speed=\"%d\" />\n", options_sdl_player_delay);
3537     fprintf(file, "    <replay speed=\"%d\" />\n", options_sdl_replay_delay);
3538     fprintf(file, "    <undo speed=\"%d\" />\n", options_sdl_undo_delay);
3539 
3540 #ifdef XOR_COMPATIBILITY
3541     if(options_xor_options)
3542         fprintf(file, "    <xor mode=\"%s\" display=\"%s\" />\n", options_xor_mode ? "exact" : "approximate", options_xor_display ? "partial" : "full");
3543 #endif
3544 #ifdef ENIGMA_COMPATIBILITY
3545     if(options_enigma_options)
3546         fprintf(file, "    <enigma mode=\"%s\" />\n", options_enigma_mode ? "exact" : "approximate");
3547 #endif
3548 
3549     fprintf(file, "    <!-- Set <debug menu=\"yes\" /> to change debug options within Chroma -->\n");
3550     fprintf(file, "    <debug ");
3551     fprintf(file, "menu=\"%s\" ", options_debug & DEBUG_MENU ? "yes" : "no");
3552     fprintf(file, "order=\"%s\" ", options_debug & DEBUG_ORDER ? "yes" : "no");
3553     fprintf(file, "speed=\"%s\" ", options_debug & DEBUG_SPEED ? "yes" : "no");
3554     fprintf(file, "movers=\"%s\" ", options_debug & DEBUG_MOVERS ? "yes" : "no");
3555     fprintf(file, "hidden=\"%s\" ", options_debug & DEBUG_HIDDEN ? "yes" : "no");
3556     fprintf(file, "/>\n");
3557 
3558     fprintf(file, "    <keys>\n");
3559 
3560     for(key = SDLK_FIRST; key < SDLK_LAST; key ++)
3561     {
3562         if(actions[key] != ACTION_NONE)
3563             fprintf(file, "        <key name=\"%s\" action=\"%s\" />\n", display_keyname(key), action_shortname[actions[key]]);
3564     }
3565 
3566     fprintf(file, "    </keys>\n");
3567 
3568     for(i = 0; i < 3; i ++)
3569     {
3570         fprintf(file, "    <mouse location=\"%s\">\n", locations[i]);
3571         for(j = 1; j < MOUSE_BUTTONS_MAX; j ++)
3572         {
3573             fprintf(file, "        <button type=\"%d\" action=\"%s\" />\n", j, action_shortname[actions_mouse[i][j]]);
3574         }
3575         fprintf(file, "    </mouse>\n");
3576     }
3577 
3578     fprintf(file, "</chroma>\n");
3579 
3580     fclose(file);
3581 }
3582 
display_options_load()3583 void display_options_load()
3584 {
3585     struct parser* pparser;
3586     char filename[FILENAME_MAX];
3587     int state;
3588     SDLKey k;
3589     int i, key, action, location, button;
3590 
3591     /* Sensible defaults */
3592     options_sdl_fullscreen = 0;
3593     options_sdl_width = 1024;
3594     options_sdl_height = 768;
3595     options_sdl_delay = 100;
3596     options_sdl_player_delay = 200;
3597     options_sdl_replay_delay = 200;
3598     options_sdl_undo_delay = 200;
3599     options_sdl_size_x = 0;
3600     options_sdl_size_y = 0;
3601     options_graphic_level = 0;
3602 #ifdef XOR_COMPATIBILITY
3603     options_xor_options = 0;
3604     options_xor_mode = 1;
3605     options_xor_display = 0;
3606 #endif
3607 #ifdef ENIGMA_COMPATIBILITY
3608     options_enigma_options = 0;
3609     options_enigma_mode = 1;
3610 #endif
3611     options_debug = 0;
3612 
3613     getfilename("colours", filename, 0, LOCATION_SYSTEM);
3614     snprintf(options_colours, sizeof(options_colours), "%s/%s", filename, COLOURS_DEFAULT);
3615     getfilename("graphics", filename, 0, LOCATION_SYSTEM);
3616     snprintf(options_graphics, sizeof(options_graphics), "%s/%s", filename, GRAPHICS_DEFAULT);
3617 
3618     getfilename("sdl.chroma", filename, 0, LOCATION_LOCAL);
3619 
3620     for(k = SDLK_FIRST; k < SDLK_LAST; k ++)
3621     {
3622         actions[k] = ACTION_NONE;
3623     }
3624 
3625     for(action = 0; action < MOUSE_BUTTONS_MAX; action ++)
3626     {
3627         actions_mouse[ACTIONS_GAME][action] = ACTION_NONE;
3628         actions_mouse[ACTIONS_MENU][action] = ACTION_NONE;
3629         actions_mouse[ACTIONS_EDIT][action] = ACTION_NONE;
3630     }
3631 
3632     /* Fixed keys */
3633     actions[SDLK_UP] = ACTION_UP;
3634     actions[SDLK_DOWN] = ACTION_DOWN;
3635     actions[SDLK_LEFT] = ACTION_LEFT;
3636     actions[SDLK_RIGHT] = ACTION_RIGHT;
3637     actions[SDLK_RETURN] = ACTION_SWAP;
3638     actions[SDLK_q] = ACTION_QUIT;
3639     actions[SDLK_ESCAPE] = ACTION_QUIT;
3640 
3641     actions_mouse[ACTIONS_GAME][1] = ACTION_MOUSE_DRAG_OR_CLICK;
3642     actions_mouse[ACTIONS_GAME][2] = ACTION_SWAP;
3643     actions_mouse[ACTIONS_GAME][3] = ACTION_UNDO;
3644     actions_mouse[ACTIONS_GAME][4] = ACTION_UNDO;
3645     actions_mouse[ACTIONS_GAME][5] = ACTION_REDO;
3646 
3647     actions_mouse[ACTIONS_MENU][1] = ACTION_MOUSE_CLICK;
3648     actions_mouse[ACTIONS_MENU][2] = ACTION_MOUSE_CLICK;
3649     actions_mouse[ACTIONS_MENU][3] = ACTION_QUIT;
3650     actions_mouse[ACTIONS_MENU][4] = ACTION_PAGE_UP;
3651     actions_mouse[ACTIONS_MENU][5] = ACTION_PAGE_DOWN;
3652 
3653     actions_mouse[ACTIONS_EDIT][1] = ACTION_MOUSE_CLICK;
3654     actions_mouse[ACTIONS_EDIT][2] = ACTION_MOUSE_DRAG;
3655     actions_mouse[ACTIONS_EDIT][3] = ACTION_QUIT;
3656     actions_mouse[ACTIONS_EDIT][4] = ACTION_PIECE_LEFT;
3657     actions_mouse[ACTIONS_EDIT][5] = ACTION_PIECE_RIGHT;
3658 
3659     /* Sensible default keys */
3660     if(!isfile(filename))
3661     {
3662         actions[SDLK_SPACE] = ACTION_SWAP;
3663         actions[SDLK_f] = ACTION_FAST;
3664         actions[SDLK_BACKSPACE] = ACTION_UNDO;
3665         actions[SDLK_DELETE] = ACTION_UNDO;
3666         actions[SDLK_u] = ACTION_UNDO;
3667         actions[SDLK_INSERT] = ACTION_REDO;
3668         actions[SDLK_y] = ACTION_REDO;
3669         actions[SDLK_p] = ACTION_PAUSE;
3670         actions[SDLK_LSHIFT] = ACTION_FASTER;
3671         actions[SDLK_RSHIFT] = ACTION_FASTER;
3672         actions[SDLK_LCTRL] = ACTION_SLOWER;
3673         actions[SDLK_RCTRL] = ACTION_SLOWER;
3674         actions[SDLK_z] = ACTION_PIECE_LEFT;
3675         actions[SDLK_x] = ACTION_PIECE_RIGHT;
3676         actions[SDLK_PAGEUP] = ACTION_PIECE_LEFT;;
3677         actions[SDLK_PAGEDOWN] = ACTION_PIECE_RIGHT;
3678         actions[SDLK_KP8] = ACTION_UP;
3679         actions[SDLK_KP2] = ACTION_DOWN;
3680         actions[SDLK_KP4] = ACTION_LEFT;
3681         actions[SDLK_KP6] = ACTION_RIGHT;
3682         actions[SDLK_KP_ENTER] = ACTION_SWAP;
3683         actions[SDLK_KP_MINUS] = ACTION_UNDO;
3684         actions[SDLK_KP_PLUS] = ACTION_REDO;
3685         actions[SDLK_KP_DIVIDE] = ACTION_PIECE_LEFT;
3686         actions[SDLK_KP_MULTIPLY] = ACTION_PIECE_RIGHT;
3687 
3688         return;
3689     }
3690 
3691     /* Parse XML file */
3692     /*
3693        <chroma type="options">
3694            <colour scheme="filename" />
3695            <move speed="speed" />
3696            <replay speed="speed" />
3697            <xor mode="mode" />
3698            <debug movers="yes/no" />
3699            <keys>
3700                <key name="name" action="action" />
3701            </keys>
3702        </chroma>
3703     */
3704 
3705     pparser = parser_new(filename);
3706 
3707     enum {
3708         OPTIONSPARSER_END,       /* End of file */
3709         OPTIONSPARSER_OUTSIDE,   /* Outside of <chroma> */
3710         OPTIONSPARSER_CHROMA,    /* Inside <chroma> */
3711         OPTIONSPARSER_KEYS,      /* Inside <keys> */
3712         OPTIONSPARSER_MOUSE      /* Inside <mouse> */
3713     };
3714 
3715     state = OPTIONSPARSER_OUTSIDE;
3716     key = 0;
3717     action = 0;
3718     location = -1;
3719     button = -1;
3720 
3721     while(state != OPTIONSPARSER_END)
3722     {
3723         switch(parser_parse(pparser))
3724         {
3725             case PARSER_END:
3726                 state = OPTIONSPARSER_END;
3727                 break;
3728 
3729             case PARSER_ELEMENT_START:
3730                 switch(state)
3731                 {
3732                     case OPTIONSPARSER_CHROMA:
3733                         if(parser_match(pparser, 0, "keys"))
3734                             state = OPTIONSPARSER_KEYS;
3735                         if(parser_match(pparser, 0, "mouse"))
3736                         {
3737                             location = -1;
3738                             state = OPTIONSPARSER_MOUSE;
3739                         }
3740                         break;
3741 
3742                     case OPTIONSPARSER_KEYS:
3743                         if(parser_match(pparser, 0, "key"))
3744                         {
3745                             key = 0;
3746                             action = ACTION_NONE;
3747                         }
3748                         break;
3749 
3750                     case OPTIONSPARSER_MOUSE:
3751                         if(parser_match(pparser, 0, "button"))
3752                         {
3753                             button = -1;
3754                             action = ACTION_NONE;
3755                         }
3756                         break;
3757                 }
3758                 break;
3759 
3760             case PARSER_ELEMENT_END:
3761                 switch(state)
3762                 {
3763                     case OPTIONSPARSER_KEYS:
3764                         if(parser_match(pparser, 0, "keys"))
3765                             state = OPTIONSPARSER_CHROMA;
3766                         if(parser_match(pparser, 0, "key"))
3767                         {
3768                             if(key != 0 && !display_keyfixed(key))
3769                                 actions[key] = action;
3770                         }
3771                         break;
3772 
3773                     case OPTIONSPARSER_MOUSE:
3774                         if(parser_match(pparser, 0, "mouse"))
3775                             state = OPTIONSPARSER_CHROMA;
3776                         if(parser_match(pparser, 0, "button"))
3777                         {
3778                             if(location != -1 && button != -1)
3779                                 actions_mouse[location][button] = action;
3780                         }
3781                         break;
3782                 }
3783                 break;
3784 
3785             case PARSER_CONTENT:
3786                 break;
3787 
3788             case PARSER_ATTRIBUTE:
3789                 switch(state)
3790                 {
3791                     case OPTIONSPARSER_OUTSIDE:
3792                         if(parser_match(pparser, 2, "chroma") && parser_match(pparser, 1, "type"))
3793                         {
3794                             if(parser_match(pparser, 0, "options"))
3795                                 state = OPTIONSPARSER_CHROMA;
3796                         }
3797                         break;
3798 
3799                     case OPTIONSPARSER_CHROMA:
3800                         if(parser_match(pparser, 2, "screen") && parser_match(pparser, 1, "width"))
3801                         {
3802                             options_sdl_width = atoi(parser_text(pparser, 0));
3803                         }
3804                         if(parser_match(pparser, 2, "screen") && parser_match(pparser, 1, "height"))
3805                         {
3806                             options_sdl_height = atoi(parser_text(pparser, 0));
3807                         }
3808                         if(parser_match(pparser, 2, "screen") && parser_match(pparser, 1, "fullscreen"))
3809                         {
3810                             if(parser_match(pparser, 0, "yes"))
3811                                 options_sdl_fullscreen = 1;
3812                             if(parser_match(pparser, 0, "no"))
3813                                 options_sdl_fullscreen = 0;
3814                         }
3815                         if(parser_match(pparser, 2, "colour") && parser_match(pparser, 1, "scheme"))
3816                         {
3817                             strncpy(options_colours, parser_text(pparser, 0), FILENAME_MAX);
3818                         }
3819                         if(parser_match(pparser, 2, "graphics") && parser_match(pparser, 1, "scheme"))
3820                         {
3821                             strncpy(options_graphics, parser_text(pparser, 0), FILENAME_MAX);
3822                         }
3823                         if(parser_match(pparser, 2, "graphics") && parser_match(pparser, 1, "width"))
3824                         {
3825                             options_sdl_size_x = atoi(parser_text(pparser, 0));
3826                         }
3827                         if(parser_match(pparser, 2, "graphics") && parser_match(pparser, 1, "height"))
3828                         {
3829                             options_sdl_size_y = atoi(parser_text(pparser, 0));
3830                         }
3831                         if(parser_match(pparser, 2, "graphics") && parser_match(pparser, 1, "level"))
3832                         {
3833                             options_graphic_level = atoi(parser_text(pparser, 0));
3834                         }
3835                         if(parser_match(pparser, 2, "move") && parser_match(pparser, 1, "speed"))
3836                         {
3837                             options_sdl_delay = atoi(parser_text(pparser, 0));
3838                         }
3839                         if(parser_match(pparser, 2, "player") && parser_match(pparser, 1, "speed"))
3840                         {
3841                             options_sdl_player_delay = atoi(parser_text(pparser, 0));
3842                         }
3843                         if(parser_match(pparser, 2, "replay") && parser_match(pparser, 1, "speed"))
3844                         {
3845                             options_sdl_replay_delay = atoi(parser_text(pparser, 0));
3846                         }
3847                         if(parser_match(pparser, 2, "undo") && parser_match(pparser, 1, "speed"))
3848                         {
3849                             options_sdl_undo_delay = atoi(parser_text(pparser, 0));
3850                         }
3851 #ifdef XOR_COMPATIBILITY
3852                         if(parser_match(pparser, 2, "xor") && parser_match(pparser, 1, "mode"))
3853                         {
3854                             options_xor_options = 1;
3855 
3856                             if(parser_match(pparser, 0, "approximate"))
3857                                 options_xor_mode = 0;
3858                             if(parser_match(pparser, 0, "exact"))
3859                                 options_xor_mode = 1;
3860                         }
3861                         if(parser_match(pparser, 2, "xor") && parser_match(pparser, 1, "display"))
3862                         {
3863                             options_xor_options = 1;
3864 
3865                             if(parser_match(pparser, 0, "full"))
3866                                 options_xor_display = 0;
3867                             if(parser_match(pparser, 0, "partial"))
3868                                 options_xor_display = 1;
3869                         }
3870 #endif
3871 #ifdef ENIGMA_COMPATIBILITY
3872                         if(parser_match(pparser, 2, "enigma") && parser_match(pparser, 1, "mode"))
3873                         {
3874                             options_enigma_options = 1;
3875 
3876                             if(parser_match(pparser, 0, "approximate"))
3877                                 options_enigma_mode = 0;
3878                             if(parser_match(pparser, 0, "exact"))
3879                                 options_enigma_mode = 1;
3880                         }
3881 #endif
3882                         if(parser_match(pparser, 2, "debug") && parser_match(pparser, 1, "menu"))
3883                         {
3884                             if(parser_match(pparser, 0, "yes"))
3885                                 options_debug |= DEBUG_MENU;
3886                         }
3887                         if(parser_match(pparser, 2, "debug") && parser_match(pparser, 1, "order"))
3888                         {
3889                             if(parser_match(pparser, 0, "yes"))
3890                                 options_debug |= DEBUG_ORDER;
3891                         }
3892                         if(parser_match(pparser, 2, "debug") && parser_match(pparser, 1, "speed"))
3893                         {
3894                             if(parser_match(pparser, 0, "yes"))
3895                                 options_debug |= DEBUG_SPEED;
3896                         }
3897                         if(parser_match(pparser, 2, "debug") && parser_match(pparser, 1, "movers"))
3898                         {
3899                             if(parser_match(pparser, 0, "yes"))
3900                                 options_debug |= DEBUG_MOVERS;
3901                         }
3902                         if(parser_match(pparser, 2, "debug") && parser_match(pparser, 1, "hidden"))
3903                         {
3904                             if(parser_match(pparser, 0, "yes"))
3905                                 options_debug |= DEBUG_HIDDEN;
3906                         }
3907                         break;
3908 
3909                     case OPTIONSPARSER_KEYS:
3910                         if(parser_match(pparser, 2, "key") &&  parser_match(pparser, 1, "name"))
3911                         {
3912                             for(i = SDLK_FIRST; i < SDLK_LAST; i ++)
3913                             {
3914                                 if(parser_match(pparser, 0, display_keyname(i)))
3915                                 {
3916                                     key = i;
3917                                     i = SDLK_LAST;
3918                                 }
3919                             }
3920                         }
3921                         if(parser_match(pparser, 2, "key") &&  parser_match(pparser, 1, "action"))
3922                         {
3923                             for(i = ACTION_KEY_MIN; i < ACTION_KEY_MAX; i ++)
3924                             {
3925                                 if(parser_match(pparser, 0, action_shortname[i]))
3926                                 {
3927                                     action = i;
3928                                     i = ACTION_KEY_MAX;
3929                                 }
3930                             }
3931                         }
3932                         break;
3933 
3934                     case OPTIONSPARSER_MOUSE:
3935                         if(parser_match(pparser, 2, "button") &&  parser_match(pparser, 1, "type"))
3936                         {
3937                             button = atoi(parser_text(pparser, 0));
3938                             if(button < 1 || button >= MOUSE_BUTTONS_MAX)
3939                                 button = -1;
3940                         }
3941                         if(parser_match(pparser, 2, "mouse") &&  parser_match(pparser, 1, "location"))
3942                         {
3943                             if(parser_match(pparser, 0, "game"))
3944                                 location = ACTIONS_GAME;
3945                             if(parser_match(pparser, 0, "menu"))
3946                                 location = ACTIONS_MENU;
3947                             if(parser_match(pparser, 0, "editor"))
3948                                 location = ACTIONS_EDIT;
3949                         }
3950                         if(parser_match(pparser, 2, "button") &&  parser_match(pparser, 1, "action"))
3951                         {
3952                             for(i = 0; i < ACTION_MAX; i ++)
3953                             {
3954                                 if(parser_match(pparser, 0, action_shortname[i]))
3955                                 {
3956                                     action = i;
3957                                     i = ACTION_MAX;
3958                                 }
3959                             }
3960                         }
3961                         break;
3962                 }
3963                 break;
3964 
3965             case PARSER_ERROR:
3966                 state = OPTIONSPARSER_END;
3967                 break;
3968         }
3969     }
3970 
3971     parser_delete(pparser);
3972 }
3973