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