1 /*
2 sdlshadowdisplay.c
3
4 Copyright (C) 2010-2021 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
27 #include "chroma.h"
28 #include "menu.h"
29 #include "level.h"
30 #include "display.h"
31 #include "graphics.h"
32 #include "colours.h"
33 #include "sdlfont.h"
34 #include "sdlscreen.h"
35 #include "util.h"
36
37 extern SDL_Surface *screen_surface;
38
39 extern int screen_width;
40 extern int screen_height;
41 extern int screen_fullscreen;
42
43 extern int options_sdl_width;
44 extern int options_sdl_height;
45 extern int options_sdl_fullscreen;
46 extern int options_sdl_size_x;
47 extern int options_sdl_size_y;
48 extern int options_sdl_delay;
49 extern int options_sdl_player_delay;
50 extern int options_sdl_replay_delay;
51 extern int options_sdl_undo_delay;
52 extern int options_sdl_mouse;
53 extern int options_graphic_level;
54 extern int options_debug;
55 extern char options_graphics[];
56 extern char options_colours[];
57
58 extern char *piece_name[];
59
60 extern int move_x[];
61 extern int move_y[];
62
63 extern int display_offset_x;
64 extern int display_offset_y;
65 extern int display_offset_pixels_x;
66 extern int display_offset_pixels_y;
67 extern int display_start_x;
68 extern int display_start_y;
69 extern int display_end_x;
70 extern int display_end_y;
71 extern int display_pieces_x;
72 extern int display_pieces_y;
73 extern int display_focus_x;
74 extern int display_focus_y;
75 extern int display_bar_pixels;
76 extern int display_border_x;
77 extern int display_border_y;
78
79 extern float display_animation;
80 extern int display_animation_x;
81 extern int display_animation_y;
82
83 extern struct graphics* pdisplaygraphics;
84
85 void display_clip(struct level* plevel, int clip);
86 int display_bevelsquare(struct level* plevel, int x, int y);
87
88 void displayshadowed_level(struct level* plevel);
89 void displayshadowed_movers(struct level* plevel, int redraw);
90
displayshadowed_piece(struct level * plevel,int p,int x,int y,int d)91 static inline void displayshadowed_piece(struct level* plevel, int p, int x, int y, int d)
92 {
93 SDL_Surface *pimage;
94
95 SDL_Rect srect;
96 SDL_Rect drect;
97 int px, py;
98 int alpha = 0;
99 int bimage[4];
100 int b;
101 int bsizex, bsizey;
102 int boffset = 0;
103 int i;
104 int xend;
105
106 #ifdef XOR_COMPATIBILITY
107 if(p == PIECE_WALL && plevel->switched)
108 return;
109 #endif
110
111 px = x * pdisplaygraphics->size_x + display_offset_pixels_x;
112 py = y * pdisplaygraphics->size_y + display_offset_pixels_y;
113
114 if(d != MOVE_NONE)
115 {
116 px += move_x[d] * display_animation_x;
117 py += move_y[d] * display_animation_y;
118 }
119
120 if(isexplosion(p))
121 alpha = 255 * (1 - display_animation);
122 if(isnewexplosion(p))
123 {
124 alpha = 255 * display_animation;
125 p += PIECE_EXPLOSION_FIRST - PIECE_EXPLOSION_NEW_FIRST;
126 }
127
128 pimage = pdisplaygraphics->image[p][IMAGE_PIECE];
129
130 if(isexplosion(p))
131 SDL_SetAlpha(pimage, SDL_SRCALPHA, alpha);
132
133 srect.x = 0;
134 srect.y = 0;
135 srect.w = pdisplaygraphics->size_x;
136 srect.h = pdisplaygraphics->size_y;
137
138 drect.x = px;
139 drect.y = py;
140 drect.w = pdisplaygraphics->size_x;
141 drect.h = pdisplaygraphics->size_y;
142
143 if(pimage->w > pdisplaygraphics->size_x)
144 {
145 if(p == PIECE_PLAYER_ONE || p == PIECE_PLAYER_TWO)
146 {
147 if(plevel->player != (p & 1) && plevel->player != 2)
148 srect.x = pdisplaygraphics->size_x;
149 }
150 /* Is the piece tiled? */
151 if(pdisplaygraphics->image_flags[p] & GRAPHICS_TILE)
152 {
153 xend = pimage->w / pdisplaygraphics->size_x;
154 if(pdisplaygraphics->image_flags[p] & GRAPHICS_BEVEL)
155 xend -= 4;
156
157 b = x % xend;
158 if(b < 0)
159 b += xend;
160 srect.x += pdisplaygraphics->size_x * b;
161
162 b = y % (pimage->h / pdisplaygraphics->size_y);
163 if(b < 0)
164 b += pimage->h / pdisplaygraphics->size_y;
165 srect.y += pdisplaygraphics->size_y * b;
166 }
167 }
168
169 /* Plot piece */
170 SDL_BlitSurface(pimage, &srect, screen_surface, &drect);
171
172 /* Plot bevelling */
173 if(pdisplaygraphics->image_flags[p] & GRAPHICS_BEVEL)
174 {
175 xend = pimage->w / pdisplaygraphics->size_x;
176 xend -=4;
177
178 b = level_data(plevel, x, y) & BEVEL_ALL;
179 if(b != 0)
180 {
181 bsizex = pdisplaygraphics->size_x / 2;
182 bsizey = pdisplaygraphics->size_y / 2;
183 boffset = (xend - 1) * pdisplaygraphics->size_x;
184
185 for(i = 0; i < 4; i ++)
186 bimage[i] = 0;
187
188 if(b & BEVEL_L)
189 {
190 if(b & BEVEL_U)
191 bimage[0] = 3 * pdisplaygraphics->size_x;
192 else
193 bimage[0] = 1 * pdisplaygraphics->size_x;
194
195 if(b & BEVEL_D)
196 bimage[2] = 3 * pdisplaygraphics->size_x;
197 else
198 bimage[2] = 1 * pdisplaygraphics->size_x;
199 }
200 else
201 {
202 if(b & BEVEL_U)
203 bimage[0] = 2 * pdisplaygraphics->size_x;
204 if(b & BEVEL_D)
205 bimage[2] = 2 * pdisplaygraphics->size_x;
206 }
207
208 if(b & BEVEL_R)
209 {
210 if(b & BEVEL_U)
211 bimage[1] = 3 * pdisplaygraphics->size_x;
212 else
213 bimage[1] = 1 * pdisplaygraphics->size_x;
214
215 if(b & BEVEL_D)
216 bimage[3] = 3 * pdisplaygraphics->size_x;
217 else
218 bimage[3] = 1 * pdisplaygraphics->size_x;
219 }
220 else
221 {
222 if(b & BEVEL_U)
223 bimage[1] = 2 * pdisplaygraphics->size_x;
224 if(b & BEVEL_D)
225 bimage[3] = 2 * pdisplaygraphics->size_x;
226 }
227
228 if(b & BEVEL_TL)
229 bimage[0] = 4 * pdisplaygraphics->size_x;
230 if(b & BEVEL_TR)
231 bimage[1] = 4 * pdisplaygraphics->size_x;
232 if(b & BEVEL_BL)
233 bimage[2] = 4 * pdisplaygraphics->size_x;
234 if(b & BEVEL_BR)
235 bimage[3] = 4 * pdisplaygraphics->size_x;
236
237 for(i = 0; i < 4; i ++)
238 {
239 if(bimage[i] != 0)
240 {
241 srect.x = boffset + bimage[i] + ((i & 1) ? bsizex : 0);
242 srect.y = (i & 2) ? bsizey : 0;
243 srect.w = bsizex;
244 srect.h = bsizey;
245
246 drect.x = px + ((i & 1) ? bsizex : 0);
247 drect.y = py + ((i & 2) ? bsizey : 0);
248 drect.w = bsizex;
249 drect.h = bsizey;
250
251 SDL_BlitSurface(pimage, &srect, screen_surface, &drect);
252 }
253 }
254 }
255 }
256 }
257
displayshadowed_pieceshadow(struct level * plevel,int p,int x,int y,int d)258 static inline void displayshadowed_pieceshadow(struct level* plevel, int p, int x, int y, int d)
259 {
260 SDL_Surface *pimage;
261
262 SDL_Rect srect;
263 SDL_Rect drect;
264 int px, py;
265 int alpha = 0;
266
267 if(isexplosion(p))
268 alpha = 255 * (1 - display_animation);
269 if(isnewexplosion(p))
270 {
271 alpha = 255 * display_animation;
272 p += PIECE_EXPLOSION_FIRST - PIECE_EXPLOSION_NEW_FIRST;
273 }
274
275 pimage = pdisplaygraphics->image[p][IMAGE_SHADOW];
276 if(pimage == NULL)
277 return;
278
279 if(isexplosion(p))
280 SDL_SetAlpha(pimage, SDL_SRCALPHA, alpha);
281
282 px = x * pdisplaygraphics->size_x + display_offset_pixels_x;
283 py = y * pdisplaygraphics->size_y + display_offset_pixels_y;
284 if(d != MOVE_NONE)
285 {
286 px += move_x[d] * display_animation_x;
287 py += move_y[d] * display_animation_y;
288 }
289
290 srect.x = 0;
291 srect.y = 0;
292 srect.w = pdisplaygraphics->shadow_width[p][9];
293 srect.h = pdisplaygraphics->shadow_height[p][9];
294
295 drect.x = px + pdisplaygraphics->shadow_offset_x[p][9];
296 drect.y = py + pdisplaygraphics->shadow_offset_y[p][9];
297 drect.w = srect.w ;
298 drect.h = srect.h;
299
300 if(pimage->w > pdisplaygraphics->shadow_width[p][9])
301 {
302 if(p == PIECE_PLAYER_ONE || p == PIECE_PLAYER_TWO)
303 {
304 if(plevel->player != (p & 1) && plevel->player != 2)
305 srect.x = pdisplaygraphics->shadow_width[p][9];
306 }
307 }
308
309 /* Plot piece */
310 SDL_BlitSurface(pimage, &srect, screen_surface, &drect);
311 }
312
displayshadowed_piecebase(struct level * plevel,int x,int y)313 static inline void displayshadowed_piecebase(struct level* plevel, int x, int y)
314 {
315 int p;
316 SDL_Surface *pimage;
317 struct shadow *pshadow;
318 struct shadow *pshadowstart;
319 struct shadow *pshadowtmp;
320 struct shadow *pshadowlast;
321 int px, py;
322 int z;
323 int ok;
324 int b, bp;
325 int xend;
326
327 SDL_Rect srect;
328 SDL_Rect drect;
329 SDL_Rect bsrect, bdrect;
330 int alpha;
331
332 p = level_piece(plevel, x, y);
333
334 if(level_moving(plevel, x, y) != MOVE_NONE)
335 {
336 if(display_animation >= 1)
337 p = PIECE_SPACE;
338 else
339 p = level_previous(plevel, x, y);
340 }
341
342 #ifdef XOR_COMPATIBILITY
343 if(plevel->switched && (p == PIECE_WALL || p == PIECE_SPACE))
344 p = PIECE_DARKNESS;
345 #endif
346
347 /* If the piece isn't transparent, nothing needs to be plotted */
348 if(p != PIECE_SPACE
349 #ifdef XOR_COMPATIBILITY
350 && p != PIECE_DARKNESS
351 #endif
352 && !(pdisplaygraphics->image[p][IMAGE_PIECE]->flags & SDL_SRCALPHA))
353 return;
354
355 #ifdef XOR_COMPATIBILITY
356 if(plevel->switched)
357 bp = PIECE_DARKNESS;
358 else
359 #endif
360 bp = PIECE_SPACE;
361
362 pimage = pdisplaygraphics->image[bp][IMAGE_PIECE];
363
364 px = x * pdisplaygraphics->size_x + display_offset_pixels_x;
365 py = y * pdisplaygraphics->size_y + display_offset_pixels_y;
366
367 srect.x = 0;
368 srect.y = 0;
369 srect.w = pdisplaygraphics->size_x;
370 srect.h = pdisplaygraphics->size_y;
371
372 drect.x = px;
373 drect.y = py;
374 drect.w = pdisplaygraphics->size_x;
375 drect.h = pdisplaygraphics->size_y;
376
377 /* Is the base tiled? */
378 if(pdisplaygraphics->image_flags[bp] & GRAPHICS_TILE)
379 {
380 xend = pimage->w / pdisplaygraphics->size_x;
381 if(pdisplaygraphics->image_flags[bp] & GRAPHICS_BEVEL)
382 xend -= 4;
383 srect.x += pdisplaygraphics->size_x * (x % xend);
384 srect.y += pdisplaygraphics->size_y * (y % (pimage->h / pdisplaygraphics->size_y));
385 }
386
387 /* Plot the base */
388 SDL_BlitSurface(pimage, &srect, screen_surface, &drect);
389
390 /* Do we need to order the shadows prior to plotting? */
391 if(pdisplaygraphics->flags & GRAPHICS_ZORDER)
392 {
393 pshadowstart = NULL;
394 pshadowlast = NULL;
395
396 pshadow = pdisplaygraphics->shadows;
397 while(pshadow != NULL)
398 {
399 /* Determine which piece to consider the shadow of */
400 p = level_piece(plevel, x - pshadow->x, y - pshadow->y);
401 if(level_moving(plevel, x - pshadow->x, y - pshadow->y) != MOVE_NONE)
402 {
403 if(display_animation >= 1)
404 p = PIECE_SPACE;
405 else
406 {
407 if(level_previousmoving(plevel, x - pshadow->x, y - pshadow->y) == MOVE_NONE)
408 p = level_previous(plevel, x - pshadow->x, y - pshadow->y);
409 else
410 p = PIECE_SPACE;
411 }
412 }
413 #ifdef XOR_COMPATIBILITY
414 if(p == PIECE_WALL && plevel->switched)
415 p = PIECE_DARKNESS;
416 #endif
417 /* Does it have a shadow? */
418 if(pdisplaygraphics->image[p][IMAGE_SHADOW] != NULL && (pdisplaygraphics->shadow_flags[p] & pshadow->flag))
419 {
420 z = pdisplaygraphics->shadow_z[p];
421 pshadow->z = pdisplaygraphics->shadow_z[p];
422 pshadow->p = p;
423
424 /* Put it in the ordered list */
425 pshadowtmp = pshadowstart;
426 while(pshadowtmp != NULL)
427 {
428 if(pshadowtmp->z > z)
429 break;
430
431 pshadowtmp = pshadowtmp->nextordered;
432 }
433 if(pshadowstart == NULL)
434 pshadowstart = pshadow;
435
436 /* It goes on the end of the list */
437 if(pshadowtmp == NULL)
438 {
439 pshadow->nextordered = NULL;
440 pshadow->previousordered = pshadowlast;
441 if(pshadowlast != NULL)
442 pshadowlast->nextordered = pshadow;
443 pshadowlast = pshadow;
444 }
445 /* It goes before pshadowtmp */
446 else
447 {
448 pshadow->nextordered = pshadowtmp;
449 pshadow->previousordered = pshadowtmp->previousordered;
450 if(pshadowtmp->previousordered != NULL)
451 pshadowtmp->previousordered->nextordered = pshadow;
452 else
453 pshadowstart = pshadow;
454 pshadowtmp->previousordered = pshadow;
455 }
456 }
457 pshadow = pshadow->next;
458 }
459 }
460
461 /* Plot shadows in order */
462 if(pdisplaygraphics->flags & GRAPHICS_ZORDER)
463 pshadow = pshadowstart;
464 else
465 pshadow = pdisplaygraphics->shadows;
466
467 while(pshadow != NULL)
468 {
469 /* Determine which piece to consider the shadow of */
470 p = level_piece(plevel, x - pshadow->x, y - pshadow->y);
471 if(level_moving(plevel, x - pshadow->x, y - pshadow->y) != MOVE_NONE)
472 {
473 if(display_animation >= 1)
474 p = PIECE_SPACE;
475 else
476 {
477 if(level_previousmoving(plevel, x - pshadow->x, y - pshadow->y) == MOVE_NONE)
478 p = level_previous(plevel, x - pshadow->x, y - pshadow->y);
479 else
480 p = PIECE_SPACE;
481 }
482 }
483 /* Does it have a shadow? */
484 if(pdisplaygraphics->image[p][IMAGE_SHADOW] != NULL && (pdisplaygraphics->shadow_flags[p] & pshadow->flag))
485 {
486 pimage = pdisplaygraphics->image[p][IMAGE_SHADOW];
487
488 if(isexplosion(p))
489 {
490 alpha = 255 * (1 - display_animation);
491 SDL_SetAlpha(pdisplaygraphics->image[p][IMAGE_SHADOW], SDL_SRCALPHA, alpha);
492 }
493 if(isnewexplosion(p))
494 {
495 p += PIECE_EXPLOSION_FIRST - PIECE_EXPLOSION_NEW_FIRST;
496 alpha = 255 * display_animation;
497 SDL_SetAlpha(pdisplaygraphics->image[p][IMAGE_SHADOW], SDL_SRCALPHA, alpha);
498 }
499
500 srect.x = pdisplaygraphics->shadow_start_x[p][pshadow->shadow];
501 srect.y = pdisplaygraphics->shadow_start_y[p][pshadow->shadow];
502 srect.w = pdisplaygraphics->shadow_width[p][pshadow->shadow];
503 srect.h = pdisplaygraphics->shadow_height[p][pshadow->shadow];
504
505 drect.x = px + pdisplaygraphics->shadow_offset_x[p][pshadow->shadow];
506 drect.y = py + pdisplaygraphics->shadow_offset_y[p][pshadow->shadow];
507 drect.w = pdisplaygraphics->shadow_width[p][pshadow->shadow];
508 drect.h = pdisplaygraphics->shadow_height[p][pshadow->shadow];
509
510 /* Are there multiple images? */
511 if(pimage->w > pdisplaygraphics->shadow_width[p][9])
512 {
513 /* Choose swapped player if necessary */
514 if(p == PIECE_PLAYER_ONE || p == PIECE_PLAYER_TWO)
515 {
516 if(plevel->player != (p & 1) && plevel->player != 2)
517 srect.x += pdisplaygraphics->shadow_width[p][9];
518 }
519 }
520
521 /* Plot shadow */
522 SDL_BlitSurface(pimage, &srect, screen_surface, &drect);
523
524 /* Bevel shadow */
525 if(pdisplaygraphics->image_flags[p] & GRAPHICS_BEVEL_SHADOW)
526 {
527 b = level_data(plevel, x - pshadow->x, y - pshadow->y) & BEVEL_ALL;
528 /* Top left quadrant */
529 if(b & (BEVEL_L | BEVEL_U | BEVEL_TL))
530 {
531 bsrect.x = 0;
532 bsrect.y = 0;
533 bsrect.w = pdisplaygraphics->shadow_width[p][9] / 2;
534 bsrect.h = pdisplaygraphics->shadow_height[p][9] / 2;
535 bdrect.x = drect.x;
536 bdrect.y = drect.y;
537
538 ok = 1;
539 if(bsrect.x < srect.x)
540 {
541 if(bsrect.w > (srect.x - bsrect.x))
542 {
543 bsrect.w -= (srect.x - bsrect.x);
544 bdrect.x -= bsrect.x;
545 bsrect.x = srect.x;
546 }
547 else
548 ok = 0;
549 }
550 if(bsrect.y < srect.y)
551 {
552 if(bsrect.h > (srect.y - bsrect.y))
553 {
554 bsrect.h -= (srect.y - bsrect.y);
555 bdrect.y -= bsrect.y;
556 bsrect.y = srect.y;
557 }
558 else
559 ok = 0;
560 }
561 if(bdrect.x + bsrect.w > drect.x + drect.w)
562 {
563 if(bsrect.w > ((bdrect.x + bsrect.w) - (drect.x + drect.w)))
564 bsrect.w -= ((bdrect.x + bsrect.w) - (drect.x + drect.w));
565 else
566 ok = 0;
567 }
568 if(bdrect.y + bsrect.h > drect.y + drect.h)
569 {
570 if(bsrect.h > ((bdrect.y + bsrect.h) - (drect.y + drect.h)))
571 bsrect.h -= ((bdrect.y + bsrect.h) - (drect.y + drect.h));
572 else
573 ok = 0;
574 }
575 if(b & BEVEL_TL)
576 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 4;
577 else
578 {
579 if(b & BEVEL_U)
580 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 2;
581 if(b & BEVEL_L)
582 bsrect.x += pdisplaygraphics->shadow_width[p][9];
583 }
584
585 if(ok)
586 SDL_BlitSurface(pimage, &bsrect, screen_surface, &bdrect);
587 }
588
589 /* Top right quadrant */
590 if(b & (BEVEL_R | BEVEL_U | BEVEL_TR))
591 {
592 bsrect.x = pdisplaygraphics->shadow_width[p][9] / 2;
593 bsrect.y = 0;
594 bsrect.w = pdisplaygraphics->shadow_width[p][9] / 2;
595 bsrect.h = pdisplaygraphics->shadow_height[p][9] / 2;
596 bdrect.x = drect.x + pdisplaygraphics->size_x / 2;
597 bdrect.y = drect.y;
598
599 ok = 1;
600 if(bsrect.x < srect.x)
601 {
602 if(bsrect.w > (srect.x - bsrect.x))
603 {
604 bsrect.w -= (srect.x - bsrect.x);
605 bdrect.x -= bsrect.x;
606 bsrect.x = srect.x;
607 }
608 else
609 ok = 0;
610 }
611 if(bsrect.y < srect.y)
612 {
613 if(bsrect.h > (srect.y - bsrect.y))
614 {
615 bsrect.h -= (srect.y - bsrect.y);
616 bdrect.y -= bsrect.y;
617 bsrect.y = srect.y;
618 }
619 else
620 ok = 0;
621 }
622 if(bdrect.x + bsrect.w > drect.x + drect.w)
623 {
624 if(bsrect.w > ((bdrect.x + bsrect.w) - (drect.x + drect.w)))
625 bsrect.w -= ((bdrect.x + bsrect.w) - (drect.x + drect.w));
626 else
627 ok = 0;
628 }
629 if(bdrect.y + bsrect.h > drect.y + drect.h)
630 {
631 if(bsrect.h > ((bdrect.y + bsrect.h) - (drect.y + drect.h)))
632 bsrect.h -= ((bdrect.y + bsrect.h) - (drect.y + drect.h));
633 else
634 ok = 0;
635 }
636 if(b & BEVEL_TR)
637 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 4;
638 else
639 {
640 if(b & BEVEL_U)
641 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 2;
642 if(b & BEVEL_R)
643 bsrect.x += pdisplaygraphics->shadow_width[p][9];
644 }
645 if(ok)
646 SDL_BlitSurface(pimage, &bsrect, screen_surface, &bdrect);
647 }
648
649 /* Bottom left quadrant */
650 if(b & (BEVEL_L | BEVEL_D | BEVEL_BL))
651 {
652 bsrect.x = 0;
653 bsrect.y = pdisplaygraphics->shadow_height[p][9] / 2;;
654 bsrect.w = pdisplaygraphics->shadow_width[p][9] / 2;
655 bsrect.h = pdisplaygraphics->shadow_height[p][9] / 2;
656 bdrect.x = drect.x;
657 bdrect.y = drect.y + pdisplaygraphics->size_y / 2;
658
659 ok = 1;
660 if(bsrect.x < srect.x)
661 {
662 if(bsrect.w > (srect.x - bsrect.x))
663 {
664 bsrect.w -= (srect.x - bsrect.x);
665 bdrect.x -= bsrect.x;
666 bsrect.x = srect.x;
667 }
668 else
669 ok = 0;
670 }
671 if(bsrect.y < srect.y)
672 {
673 if(bsrect.h > (srect.y - bsrect.y))
674 {
675 bsrect.h -= (srect.y - bsrect.y);
676 bdrect.y -= bsrect.y;
677 bsrect.y = srect.y;
678 }
679 else
680 ok = 0;
681 }
682 if(bdrect.x + bsrect.w > drect.x + drect.w)
683 {
684 if(bsrect.w > ((bdrect.x + bsrect.w) - (drect.x + drect.w)))
685 bsrect.w -= ((bdrect.x + bsrect.w) - (drect.x + drect.w));
686 else
687 ok = 0;
688 }
689 if(bdrect.y + bsrect.h > drect.y + drect.h)
690 {
691 if(bsrect.h > ((bdrect.y + bsrect.h) - (drect.y + drect.h)))
692 bsrect.h -= ((bdrect.y + bsrect.h) - (drect.y + drect.h));
693 else
694 ok = 0;
695 }
696 if(b & BEVEL_BL)
697 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 4;
698 else
699 {
700 if(b & BEVEL_D)
701 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 2;
702 if(b & BEVEL_L)
703 bsrect.x += pdisplaygraphics->shadow_width[p][9];
704 }
705 if(ok)
706 SDL_BlitSurface(pimage, &bsrect, screen_surface, &bdrect);
707 }
708
709 /* Bottom right quadrant */
710 if(b & (BEVEL_R | BEVEL_D | BEVEL_BR))
711 {
712 bsrect.x = pdisplaygraphics->shadow_width[p][9] / 2;
713 bsrect.y = pdisplaygraphics->shadow_height[p][9] / 2;
714 bsrect.w = pdisplaygraphics->shadow_width[p][9] / 2;
715 bsrect.h = pdisplaygraphics->shadow_height[p][9] / 2;
716 bdrect.x = drect.x + pdisplaygraphics->size_x / 2;
717 bdrect.y = drect.y + pdisplaygraphics->size_y / 2;
718
719 ok = 1;
720 if(bsrect.x < srect.x)
721 {
722 if(bsrect.w > (srect.x - bsrect.x))
723 {
724 bsrect.w -= (srect.x - bsrect.x);
725 bdrect.x -= bsrect.x;
726 bsrect.x = srect.x;
727 }
728 else
729 ok = 0;
730 }
731 if(bsrect.y < srect.y)
732 {
733 if(bsrect.h > (srect.y - bsrect.y))
734 {
735 bsrect.h -= (srect.y - bsrect.y);
736 bdrect.y -= bsrect.y;
737 bsrect.y = srect.y;
738 }
739 else
740 ok = 0;
741 }
742 if(bdrect.x + bsrect.w > drect.x + drect.w)
743 {
744 if(bsrect.w > ((bdrect.x + bsrect.w) - (drect.x + drect.w)))
745 bsrect.w -= ((bdrect.x + bsrect.w) - (drect.x + drect.w));
746 else
747 ok = 0;
748 }
749 if(bdrect.y + bsrect.h > drect.y + drect.h)
750 {
751 if(bsrect.h > ((bdrect.y + bsrect.h) - (drect.y + drect.h)))
752 bsrect.h -= ((bdrect.y + bsrect.h) - (drect.y + drect.h));
753 else
754 ok = 0;
755 }
756 if(b & BEVEL_BR)
757 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 4;
758 else
759 {
760 if(b & BEVEL_D)
761 bsrect.x += pdisplaygraphics->shadow_width[p][9] * 2;
762 if(b & BEVEL_R)
763 bsrect.x += pdisplaygraphics->shadow_width[p][9];
764 }
765 if(ok)
766 SDL_BlitSurface(pimage, &bsrect, screen_surface, &bdrect);
767 }
768 }
769
770 }
771
772 if(pdisplaygraphics->flags & GRAPHICS_ZORDER)
773 pshadow = pshadow->nextordered;
774 else
775 pshadow = pshadow->next;
776 }
777 }
778
displayshadowed_redrawpiece(int p,int x,int y,int d)779 static inline void displayshadowed_redrawpiece(int p, int x, int y, int d)
780 {
781 int dx, dy;
782
783 dx = x * pdisplaygraphics->size_x + display_offset_pixels_x;
784 dy = y * pdisplaygraphics->size_y + display_offset_pixels_y;
785
786 if(d != MOVE_NONE && p != PIECE_SPACE && !isexplosion(p))
787 {
788 if(d == MOVE_LEFT) { dx = dx - display_animation_x; }
789 if(d == MOVE_RIGHT) { dx = dx + display_animation_x; }
790 if(d == MOVE_UP) { dy = dy - display_animation_y; }
791 if(d == MOVE_DOWN) { dy = dy + display_animation_y; }
792 }
793
794 screen_redraw(dx, dy, pdisplaygraphics->size_x, pdisplaygraphics->size_y);
795 }
796
displayshadowed_level(struct level * plevel)797 void displayshadowed_level(struct level* plevel)
798 {
799 int x, y;
800 int p;
801
802 display_clip(plevel, 1);
803
804 /* Plot base */
805 for(y = display_start_y; y < display_end_y; y ++)
806 {
807 for(x = display_start_x; x < display_end_x; x ++)
808 {
809 displayshadowed_piecebase(plevel, x, y);
810
811 p = level_piece(plevel, x, y);
812
813 /* Plot the piece itself */
814 if(p != PIECE_SPACE)
815 displayshadowed_piece(plevel, p, x, y, MOVE_NONE);
816 }
817 }
818
819 if(plevel->mover_first != NULL)
820 displayshadowed_movers(plevel, 0);
821
822 display_clip(plevel, 0);
823
824 screen_redraw(0, 0, screen_width, screen_height);
825 }
826
displayshadowed_count(struct level * plevel,int x,int y,int delta)827 static inline int displayshadowed_count(struct level* plevel, int x, int y, int delta)
828 {
829 unsigned int d;
830
831 d = level_data(plevel, x, y);
832 level_setdata(plevel, x, y, d + (delta * SHADOW_BASE));
833
834 return d & (0x7f * SHADOW_BASE);
835 }
836
837
displayshadowed_movers(struct level * plevel,int redraw)838 void displayshadowed_movers(struct level* plevel, int redraw)
839 {
840 struct shadow* pshadow;
841 struct mover* pmover;
842 int x, y, p, pm;
843 int i, j;
844 char buffer[16];
845 int d;
846 int bevel;
847 int bevelold;
848 SDL_Surface *psurface;
849 SDL_Rect srect, drect;
850
851 p = PIECE_SPACE;
852
853 display_animation_x = - pdisplaygraphics->size_x + (int)((float) pdisplaygraphics->size_x * display_animation);
854 display_animation_y = - pdisplaygraphics->size_y + (int)((float) pdisplaygraphics->size_y * display_animation);
855
856 display_clip(plevel, 1);
857
858 /* Stage one: plot base for pieces that need rebevelling */
859 if(display_animation == 0 || display_animation == 1)
860 {
861 /* When undoing, we have to create the wall prior to rebevelling, as it
862 wouldn't otherwise exist until after the end of the animation. */
863 pmover = plevel->mover_first;
864 while(pmover != NULL)
865 {
866 if(pmover->piece == PIECE_WALL)
867 level_setpiece(plevel, pmover->x, pmover->y, pmover->piece);
868 pmover = pmover->next;
869 }
870
871 pmover = plevel->mover_first;
872 while(pmover != NULL)
873 {
874 x = pmover->x;
875 y = pmover->y;
876 if(pmover->piece == PIECE_WALL ||
877 (isexplosion(pmover->piece) && display_animation == 1))
878 {
879 pshadow = pdisplaygraphics->shadows;
880 while(pshadow != NULL)
881 {
882 bevel = display_bevelsquare(plevel, x + pshadow->x, y + pshadow->y);
883 bevelold = (level_data(plevel, x + pshadow->x, y + pshadow->y) & BEVEL_ALL);
884 /* Because this happens only once per move cycle, we
885 are lazy and don't bother to count whether this base
886 has already been plotted */
887 if(bevel != bevelold);
888 displayshadowed_piecebase(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y);
889 pshadow = pshadow->next;
890 }
891 }
892 pmover = pmover->next;
893 }
894 }
895
896 /* Stage two: plot shadows for stationary squares affected by movers */
897 pmover = plevel->mover_first;
898 while(pmover != NULL)
899 {
900 if(pmover->piece != PIECE_GONE)
901 {
902 /* This is overkill, but it's easier just to plot everything that
903 could be affected than to calculate what is actually affected.
904 */
905 pshadow = pdisplaygraphics->shadows;
906 while(pshadow != NULL)
907 {
908 if(displayshadowed_count(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y, 1) == 0)
909 displayshadowed_piecebase(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y);
910 pshadow = pshadow->next;
911 }
912 if(displayshadowed_count(plevel, pmover->x, pmover->y, 1) == 0)
913 displayshadowed_piecebase(plevel, pmover->x, pmover->y);
914 }
915
916 pmover = pmover->next;
917 }
918 /* then reset the counts */
919 pmover = plevel->mover_first;
920 while(pmover != NULL)
921 {
922 if(pmover->piece != PIECE_GONE)
923 {
924 pshadow = pdisplaygraphics->shadows;
925 while(pshadow != NULL)
926 {
927 displayshadowed_count(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y, -1);
928 pshadow = pshadow->next;
929 }
930 displayshadowed_count(plevel, pmover->x, pmover->y, -1);
931 }
932
933 pmover = pmover->next;
934 }
935
936 /* Stage three: plot shadows for movers */
937 pmover = plevel->mover_first;
938 while(pmover != NULL)
939 {
940 d = pmover->direction;
941 x = pmover->x;
942 y = pmover->y;
943
944 if(isexplosion(pmover->piece))
945 {
946 /* If the previous piece, that is, the piece destroyed in the
947 explosion, is stationary, we don't need to plot a shadow for it,
948 as that is handled in stage one. If it is moving, however, it
949 needs a moving shadow, which we do have to plot here. */
950 p = level_previous(plevel, x, y);
951 pm = level_previousmoving(plevel, x, y);
952 if(p != PIECE_SPACE && pm != MOVE_NONE)
953 displayshadowed_pieceshadow(plevel, p, x, y, pm);
954
955 /* Plot shadow for the detonator */
956 p = level_detonator(plevel, x, y);
957 pm = level_detonatormoving(plevel, x, y);
958 if(p != PIECE_SPACE)
959 displayshadowed_pieceshadow(plevel, p, x, y, pm);
960
961 }
962 /* Spaces and walls were handled in stage one */
963 else if(pmover->piece != PIECE_SPACE && pmover->piece != PIECE_WALL && pmover->piece != PIECE_GONE)
964 {
965 /* We don't need to plot the shadow for the previous piece
966 as that is handled in stage one */
967
968 /* Plot shadow for mover */
969 #ifdef XOR_COMPATIBILITY
970 if(pmover->piece == PIECE_TELEPORT)
971 d = MOVE_NONE;
972 #endif
973 displayshadowed_pieceshadow(plevel, pmover->piece, pmover->x, pmover->y, d);
974 }
975 pmover = pmover->next;
976 }
977
978 /* Stage four: plot shadows for explosions */
979 pmover = plevel->mover_first;
980 while(pmover != NULL)
981 {
982 x = pmover->x;
983 y = pmover->y;
984 /* Plot growing explosion */
985 if(isexplosion(pmover->piece))
986 displayshadowed_pieceshadow(plevel, pmover->piece + PIECE_EXPLOSION_NEW_FIRST - PIECE_EXPLOSION_FIRST, x, y, MOVE_NONE);
987
988 /* Plot dying explosion */
989 p = level_previous(plevel, x, y);
990 if(isexplosion(p) && display_animation < 1)
991 displayshadowed_pieceshadow(plevel, p, x, y, MOVE_NONE);
992
993 pmover = pmover->next;
994 }
995
996 /* Stage five: plot pieces for stationary squares affected by movers.
997 We need to be careful not to plot the same piece twice, so we keep
998 count and only plot on the first occurrence. */
999 pmover = plevel->mover_first;
1000 while(pmover != NULL)
1001 {
1002 pshadow = pdisplaygraphics->shadows;
1003 while(pshadow != NULL)
1004 {
1005 if(displayshadowed_count(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y, 1) == 0)
1006 {
1007 p = level_piece(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y);
1008 pm = level_moving(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y);
1009 if(p != PIECE_SPACE && p != PIECE_GONE && pm == MOVE_NONE)
1010 displayshadowed_piece(plevel, p, pmover->x + pshadow->x, pmover->y + pshadow->y, MOVE_NONE);
1011 }
1012 pshadow = pshadow->next;
1013 }
1014 pmover = pmover->next;
1015 }
1016 /* then reset the counts */
1017 pmover = plevel->mover_first;
1018 while(pmover != NULL)
1019 {
1020 pshadow = pdisplaygraphics->shadows;
1021 while(pshadow != NULL)
1022 {
1023 displayshadowed_count(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y, -1);
1024 pshadow = pshadow->next;
1025 }
1026 pmover = pmover->next;
1027 }
1028
1029 /* Stage six: plot pieces for movers */
1030 pmover = plevel->mover_first;
1031 while(pmover != NULL)
1032 {
1033 d = pmover->direction;
1034 x = pmover->x;
1035 y = pmover->y;
1036
1037 if(isexplosion(pmover->piece))
1038 {
1039 /* Plot any piece destroyed by the explosion, or the bomb itself */
1040 p = level_previous(plevel, x, y);
1041 pm = level_previousmoving(plevel, x, y);
1042 if(p != PIECE_SPACE)
1043 displayshadowed_piece(plevel, p, x, y, pm);
1044
1045 /* Plot the detonator */
1046 p = level_detonator(plevel, x, y);
1047 pm = level_detonatormoving(plevel, x, y);
1048 if(p != PIECE_SPACE)
1049 displayshadowed_piece(plevel, p, x, y, pm);
1050
1051 }
1052 /* Spaces were handled in stage one */
1053 else if(pmover->piece != PIECE_SPACE && pmover->piece != PIECE_GONE)
1054 {
1055 if(display_animation < 1)
1056 {
1057 /* Pieces being collected, earth being eaten */
1058 p = level_previous(plevel, x, y);
1059 pm = level_previousmoving(plevel, x, y);
1060 if((p != PIECE_SPACE && !isexplosion(p) && pm == MOVE_NONE)
1061 #ifdef XOR_COMPATIBILITY
1062 || pmover->piece == PIECE_TELEPORT
1063 #endif
1064 )
1065 displayshadowed_piece(plevel, p, x, y, pm);
1066 }
1067
1068 /* Plot the piece itself */
1069 #ifdef XOR_COMPATIBILITY
1070 if(pmover->piece == PIECE_TELEPORT)
1071 d = MOVE_NONE;
1072 #endif
1073 displayshadowed_piece(plevel, pmover->piece, pmover->x, pmover->y, d);
1074 }
1075 pmover = pmover->next;
1076 }
1077
1078 /* Stage seven: plot pieces that need rebevelling */
1079 if(display_animation == 0 || display_animation == 1)
1080 {
1081 pmover = plevel->mover_first;
1082 while(pmover != NULL)
1083 {
1084 x = pmover->x;
1085 y = pmover->y;
1086 if(pmover->piece == PIECE_WALL ||
1087 (isexplosion(pmover->piece) && display_animation == 1))
1088 {
1089 for(i = -1; i < 2; i ++)
1090 {
1091 for(j = - 1; j < 2; j ++)
1092 {
1093 bevel = display_bevelsquare(plevel, x + i, y + j);
1094 bevelold = (level_data(plevel, x + i, y + j) & BEVEL_ALL);
1095 if(bevel != bevelold);
1096 {
1097 /* Here we are not lazy, to avoid issues with
1098 transparent graphics being plotted twice */
1099 if(displayshadowed_count(plevel, pmover->x + i, pmover->y + j, 1) == 0)
1100 {
1101 level_setdata(plevel, x + i, y + j, bevel | (level_data(plevel, x + i, y + j) & ~BEVEL_ALL));
1102 p = level_piece(plevel, x + i, y + j);
1103 if(p == PIECE_WALL)
1104 displayshadowed_piece(plevel, p, pmover->x + i, pmover->y + j, MOVE_NONE);
1105 level_setdata(plevel, x + i, y + j, bevelold | (level_data(plevel, x + i, y + j) & ~BEVEL_ALL));
1106 }
1107 }
1108 }
1109 }
1110 }
1111 pmover = pmover->next;
1112 }
1113 /* and reset counts */
1114 pmover = plevel->mover_first;
1115 while(pmover != NULL)
1116 {
1117 x = pmover->x;
1118 y = pmover->y;
1119 if(pmover->piece == PIECE_WALL ||
1120 (isexplosion(pmover->piece) && display_animation == 1))
1121 {
1122 for(i = -1; i < 2; i ++)
1123 {
1124 for(j = - 1; j < 2; j ++)
1125 {
1126 bevel = display_bevelsquare(plevel, x + i, y + j);
1127 bevelold = (level_data(plevel, x + i, y + j) & BEVEL_ALL);
1128 if(bevel != bevelold);
1129 displayshadowed_count(plevel, pmover->x + i, pmover->y + j, -1);
1130 }
1131 }
1132 }
1133 pmover = pmover->next;
1134 }
1135 }
1136
1137 /* Stage eight: plot pieces for explosions */
1138 pmover = plevel->mover_first;
1139 while(pmover != NULL)
1140 {
1141 x = pmover->x;
1142 y = pmover->y;
1143 /* Plot growing explosion */
1144 if(isexplosion(pmover->piece))
1145 displayshadowed_piece(plevel, pmover->piece + PIECE_EXPLOSION_NEW_FIRST - PIECE_EXPLOSION_FIRST, x, y, MOVE_NONE);
1146
1147 /* Plot dying explosion */
1148 p = level_previous(plevel, x, y);
1149 if(isexplosion(p) && display_animation < 1)
1150 displayshadowed_piece(plevel, p, x, y, MOVE_NONE);
1151
1152 pmover = pmover->next;
1153 }
1154
1155 /* Stage nine: plot order of movers if debugging (but not in editor) */
1156 if(options_debug & DEBUG_ORDER && display_animation < 1 && plevel->player != 2)
1157 {
1158 pmover = plevel->mover_first;
1159 i = 0;
1160 while(pmover != NULL)
1161 {
1162 if(pmover->piece != PIECE_SPACE && pmover->piece != PIECE_GONE)
1163 {
1164 pm = pmover->direction;
1165 if(isexplosion(pmover->piece) || isnewexplosion(pmover->piece))
1166 pm = MOVE_NONE;
1167
1168 x = pmover->x * pdisplaygraphics->size_x + display_offset_pixels_x + ((-1 + display_animation) * move_x[pm] * pdisplaygraphics->size_x);
1169 y = pmover->y * pdisplaygraphics->size_y + display_offset_pixels_y + ((-1 + display_animation) * move_y[pm] * pdisplaygraphics->size_y);
1170
1171 sprintf(buffer, "%X", i++);
1172 switch(pmover->direction)
1173 {
1174 case MOVE_UP:
1175 strcat(buffer, ARROW_UP);
1176 break;
1177 case MOVE_DOWN:
1178 strcat(buffer, ARROW_DOWN);
1179 break;
1180 case MOVE_LEFT:
1181 strcat(buffer, ARROW_LEFT);
1182 break;
1183 case MOVE_RIGHT:
1184 strcat(buffer, ARROW_RIGHT);
1185 break;
1186 default:
1187 break;
1188 }
1189 psurface = font_render(buffer, COLOUR_WHITE | COLOUR_BOLD);
1190 srect.w = psurface->w > pdisplaygraphics->size_x ? pdisplaygraphics->size_x : psurface->w;
1191 srect.h = psurface->h > pdisplaygraphics->size_y ? pdisplaygraphics->size_y : psurface->h;
1192 srect.x = psurface->w - srect.w;
1193 srect.y = 0;
1194 drect.x = x + pdisplaygraphics->size_x - srect.w;
1195 drect.y = y;
1196 SDL_BlitSurface(psurface, &srect, screen_surface, &drect);
1197 SDL_FreeSurface(psurface);
1198 }
1199 pmover = pmover->next;
1200 }
1201 }
1202
1203 display_clip(plevel, 0);
1204
1205 if(redraw == 0)
1206 return;
1207
1208 display_clip(plevel, 1);
1209
1210 /* Stage ten: redraw modified squares */
1211 pmover = plevel->mover_first;
1212 while(pmover != NULL)
1213 {
1214 if(pmover->piece != PIECE_GONE)
1215 {
1216 pshadow = pdisplaygraphics->shadows;
1217 while(pshadow != NULL)
1218 {
1219 if(displayshadowed_count(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y, 1) == 0)
1220 displayshadowed_redrawpiece(level_piece(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y), pmover->x + pshadow->x, pmover->y + pshadow->y, MOVE_NONE);
1221 pshadow = pshadow->next;
1222 }
1223 if(displayshadowed_count(plevel, pmover->x, pmover->y, 1) == 0)
1224 displayshadowed_redrawpiece(level_piece(plevel, pmover->x, pmover->y), pmover->x, pmover->y, MOVE_NONE);
1225 }
1226 pmover = pmover->next;
1227 }
1228 /* then reset the counts */
1229 pmover = plevel->mover_first;
1230 while(pmover != NULL)
1231 {
1232 if(pmover->piece != PIECE_GONE)
1233 {
1234 pshadow = pdisplaygraphics->shadows;
1235 while(pshadow != NULL)
1236 {
1237 displayshadowed_count(plevel, pmover->x + pshadow->x, pmover->y + pshadow->y, -1);
1238 pshadow = pshadow->next;
1239 }
1240 displayshadowed_count(plevel, pmover->x, pmover->y, -1);
1241 }
1242 pmover = pmover->next;
1243 }
1244
1245 /* Stage eleven: redraw pieces that need rebevelling */
1246 if(display_animation == 0 || display_animation == 1)
1247 {
1248 pmover = plevel->mover_first;
1249 while(pmover != NULL)
1250 {
1251 x = pmover->x;
1252 y = pmover->y;
1253 if(pmover->piece == PIECE_WALL ||
1254 (isexplosion(pmover->piece) && display_animation == 1))
1255 {
1256 for(i = -1; i < 2; i ++)
1257 {
1258 for(j = - 1; j < 2; j ++)
1259 {
1260 bevel = display_bevelsquare(plevel, x + i, y + j);
1261 bevelold = (level_data(plevel, x + i, y + j) & BEVEL_ALL);
1262 if(bevel != bevelold);
1263 {
1264 /* Again, we are lazy and do not keep count of
1265 whether this square has already been redrawn. */
1266 level_setdata(plevel, x + i, y + j, bevel | (level_data(plevel, x + i, y + j) & ~BEVEL_ALL));
1267 displayshadowed_redrawpiece(level_piece(plevel, pmover->x + i, pmover->y + j), pmover->x + i, pmover->y + j, MOVE_NONE);
1268 }
1269 }
1270 }
1271 }
1272 pmover = pmover->next;
1273 }
1274 }
1275
1276 display_clip(plevel, 0);
1277 }
1278