rnd-20140307-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include <math.h>
15
16 #include "libgame/libgame.h"
17
18 #include "tools.h"
19 #include "init.h"
20 #include "game.h"
21 #include "events.h"
22 #include "cartoons.h"
23 #include "network.h"
24 #include "tape.h"
25 #include "screens.h"
26
27
28 /* select level set with EMC X11 graphics before activating EM GFX debugging */
29 #define DEBUG_EM_GFX    0
30
31 /* tool button identifiers */
32 #define TOOL_CTRL_ID_YES        0
33 #define TOOL_CTRL_ID_NO         1
34 #define TOOL_CTRL_ID_CONFIRM    2
35 #define TOOL_CTRL_ID_PLAYER_1   3
36 #define TOOL_CTRL_ID_PLAYER_2   4
37 #define TOOL_CTRL_ID_PLAYER_3   5
38 #define TOOL_CTRL_ID_PLAYER_4   6
39
40 #define NUM_TOOL_BUTTONS        7
41
42 /* constants for number of doors and door parts */
43 #define NUM_DOORS               2
44 #define NUM_PANELS              NUM_DOORS
45 // #define NUM_PANELS           0
46 #define MAX_PARTS_PER_DOOR      8
47 #define MAX_DOOR_PARTS          (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
48 #define DOOR_PART_IS_PANEL(i)   ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49
50
51 struct DoorPartOrderInfo
52 {
53   int nr;
54   int sort_priority;
55 };
56
57 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58
59 struct DoorPartControlInfo
60 {
61   int door_token;
62   int graphic;
63   struct DoorPartPosInfo *pos;
64 };
65
66 static struct DoorPartControlInfo door_part_controls[] =
67 {
68   {
69     DOOR_1,
70     IMG_DOOR_1_GFX_PART_1,
71     &door_1.part_1
72   },
73   {
74     DOOR_1,
75     IMG_DOOR_1_GFX_PART_2,
76     &door_1.part_2
77   },
78   {
79     DOOR_1,
80     IMG_DOOR_1_GFX_PART_3,
81     &door_1.part_3
82   },
83   {
84     DOOR_1,
85     IMG_DOOR_1_GFX_PART_4,
86     &door_1.part_4
87   },
88   {
89     DOOR_1,
90     IMG_DOOR_1_GFX_PART_5,
91     &door_1.part_5
92   },
93   {
94     DOOR_1,
95     IMG_DOOR_1_GFX_PART_6,
96     &door_1.part_6
97   },
98   {
99     DOOR_1,
100     IMG_DOOR_1_GFX_PART_7,
101     &door_1.part_7
102   },
103   {
104     DOOR_1,
105     IMG_DOOR_1_GFX_PART_8,
106     &door_1.part_8
107   },
108
109   {
110     DOOR_2,
111     IMG_DOOR_2_GFX_PART_1,
112     &door_2.part_1
113   },
114   {
115     DOOR_2,
116     IMG_DOOR_2_GFX_PART_2,
117     &door_2.part_2
118   },
119   {
120     DOOR_2,
121     IMG_DOOR_2_GFX_PART_3,
122     &door_2.part_3
123   },
124   {
125     DOOR_2,
126     IMG_DOOR_2_GFX_PART_4,
127     &door_2.part_4
128   },
129   {
130     DOOR_2,
131     IMG_DOOR_2_GFX_PART_5,
132     &door_2.part_5
133   },
134   {
135     DOOR_2,
136     IMG_DOOR_2_GFX_PART_6,
137     &door_2.part_6
138   },
139   {
140     DOOR_2,
141     IMG_DOOR_2_GFX_PART_7,
142     &door_2.part_7
143   },
144   {
145     DOOR_2,
146     IMG_DOOR_2_GFX_PART_8,
147     &door_2.part_8
148   },
149
150   {
151     DOOR_1,
152     IMG_BACKGROUND_PANEL,
153     &door_1.panel
154   },
155   {
156     DOOR_2,
157     IMG_BACKGROUND_TAPE,
158     &door_2.panel
159   },
160
161   {
162     -1,
163     -1,
164     NULL
165   }
166 };
167
168
169 /* forward declaration for internal use */
170 static void UnmapToolButtons();
171 static void HandleToolButtons(struct GadgetInfo *);
172 static int el_act_dir2crm(int, int, int);
173 static int el_act2crm(int, int);
174
175 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
176 static int request_gadget_id = -1;
177
178 static char *print_if_not_empty(int element)
179 {
180   static char *s = NULL;
181   char *token_name = element_info[element].token_name;
182
183   if (s != NULL)
184     free(s);
185
186   s = checked_malloc(strlen(token_name) + 10 + 1);
187
188   if (element != EL_EMPTY)
189     sprintf(s, "%d\t['%s']", element, token_name);
190   else
191     sprintf(s, "%d", element);
192
193   return s;
194 }
195
196 void DumpTile(int x, int y)
197 {
198   int sx = SCREENX(x);
199   int sy = SCREENY(y);
200
201   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
202   {
203     x--;
204     y--;
205   }
206
207   printf_line("-", 79);
208   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
209   printf_line("-", 79);
210
211   if (!IN_LEV_FIELD(x, y))
212   {
213     printf("(not in level field)\n");
214     printf("\n");
215
216     return;
217   }
218
219   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
220          element_info[Feld[x][y]].token_name);
221   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
222   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
223   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
224   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
225   printf("  MovPos:      %d\n", MovPos[x][y]);
226   printf("  MovDir:      %d\n", MovDir[x][y]);
227   printf("  MovDelay:    %d\n", MovDelay[x][y]);
228   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
229   printf("  CustomValue: %d\n", CustomValue[x][y]);
230   printf("  GfxElement:  %d\n", GfxElement[x][y]);
231   printf("  GfxAction:   %d\n", GfxAction[x][y]);
232   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
233   printf("\n");
234 }
235
236 void SetDrawtoField(int mode)
237 {
238   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
239   {
240 #if NEW_TILESIZE
241 #if NEW_SCROLL
242     FX = 2 * TILEX_VAR;
243     FY = 2 * TILEY_VAR;
244     BX1 = -2;
245     BY1 = -2;
246     BX2 = SCR_FIELDX + 1;
247     BY2 = SCR_FIELDY + 1;
248     redraw_x1 = 2;
249     redraw_y1 = 2;
250 #else
251     FX = TILEX_VAR;
252     FY = TILEY_VAR;
253     BX1 = -1;
254     BY1 = -1;
255     BX2 = SCR_FIELDX;
256     BY2 = SCR_FIELDY;
257     redraw_x1 = 1;
258     redraw_y1 = 1;
259 #endif
260 #else
261 #if NEW_SCROLL
262     FX = 2 * TILEX;
263     FY = 2 * TILEY;
264     BX1 = -2;
265     BY1 = -2;
266     BX2 = SCR_FIELDX + 1;
267     BY2 = SCR_FIELDY + 1;
268     redraw_x1 = 2;
269     redraw_y1 = 2;
270 #else
271     FX = TILEX;
272     FY = TILEY;
273     BX1 = -1;
274     BY1 = -1;
275     BX2 = SCR_FIELDX;
276     BY2 = SCR_FIELDY;
277     redraw_x1 = 1;
278     redraw_y1 = 1;
279 #endif
280 #endif
281
282     drawto_field = fieldbuffer;
283   }
284   else  /* DRAW_BACKBUFFER */
285   {
286     FX = SX;
287     FY = SY;
288     BX1 = 0;
289     BY1 = 0;
290     BX2 = SCR_FIELDX - 1;
291     BY2 = SCR_FIELDY - 1;
292     redraw_x1 = 0;
293     redraw_y1 = 0;
294
295     drawto_field = backbuffer;
296   }
297 }
298
299 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
300 {
301   if (game_status == GAME_MODE_PLAYING &&
302       level.game_engine_type == GAME_ENGINE_TYPE_EM)
303   {
304     /* currently there is no partial redraw -- always redraw whole playfield */
305     RedrawPlayfield_EM(TRUE);
306
307     /* blit playfield from scroll buffer to normal back buffer for fading in */
308     BlitScreenToBitmap_EM(backbuffer);
309   }
310   else if (game_status == GAME_MODE_PLAYING &&
311            level.game_engine_type == GAME_ENGINE_TYPE_SP)
312   {
313     /* currently there is no partial redraw -- always redraw whole playfield */
314     RedrawPlayfield_SP(TRUE);
315
316     /* blit playfield from scroll buffer to normal back buffer for fading in */
317     BlitScreenToBitmap_SP(backbuffer);
318   }
319   else if (game_status == GAME_MODE_PLAYING &&
320            !game.envelope_active)
321   {
322     if (force_redraw)
323     {
324       x = gfx.sx - TILEX;
325       y = gfx.sy - TILEY;
326       width = gfx.sxsize + 2 * TILEX;
327       height = gfx.sysize + 2 * TILEY;
328     }
329
330     if (force_redraw)
331     {
332       int xx, yy;
333       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
334       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
335
336       for (xx = BX1; xx <= BX2; xx++)
337         for (yy = BY1; yy <= BY2; yy++)
338           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
339             DrawScreenField(xx, yy);
340       DrawAllPlayers();
341     }
342
343     if (setup.soft_scrolling)
344     {
345       int fx = FX, fy = FY;
346
347       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
348       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
349
350       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
351     }
352   }
353
354   if (force_redraw)
355   {
356     x = gfx.sx;
357     y = gfx.sy;
358     width = gfx.sxsize;
359     height = gfx.sysize;
360   }
361
362   BlitBitmap(drawto, window, x, y, width, height, x, y);
363 }
364
365 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
366 {
367   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
368
369   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
370   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
371 }
372
373 void DrawMaskedBorder_FIELD()
374 {
375   if (global.border_status >= GAME_MODE_TITLE &&
376       global.border_status <= GAME_MODE_PLAYING &&
377       border.draw_masked[global.border_status])
378     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
379 }
380
381 void DrawMaskedBorder_DOOR_1()
382 {
383   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
384       (global.border_status != GAME_MODE_EDITOR ||
385        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
386     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
387 }
388
389 void DrawMaskedBorder_DOOR_2()
390 {
391   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
392       global.border_status != GAME_MODE_EDITOR)
393     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
394 }
395
396 void DrawMaskedBorder_DOOR_3()
397 {
398   /* currently not available */
399 }
400
401 void DrawMaskedBorder_ALL()
402 {
403   DrawMaskedBorder_FIELD();
404   DrawMaskedBorder_DOOR_1();
405   DrawMaskedBorder_DOOR_2();
406   DrawMaskedBorder_DOOR_3();
407 }
408
409 void DrawMaskedBorder(int redraw_mask)
410 {
411   /* never draw masked screen borders on borderless screens */
412   if (effectiveGameStatus() == GAME_MODE_LOADING ||
413       effectiveGameStatus() == GAME_MODE_TITLE)
414     return;
415
416   /* never draw masked screen borders when displaying request outside door */
417   if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
418       global.use_envelope_request)
419     return;
420
421   if (redraw_mask & REDRAW_ALL)
422     DrawMaskedBorder_ALL();
423   else
424   {
425     if (redraw_mask & REDRAW_FIELD)
426       DrawMaskedBorder_FIELD();
427     if (redraw_mask & REDRAW_DOOR_1)
428       DrawMaskedBorder_DOOR_1();
429     if (redraw_mask & REDRAW_DOOR_2)
430       DrawMaskedBorder_DOOR_2();
431     if (redraw_mask & REDRAW_DOOR_3)
432       DrawMaskedBorder_DOOR_3();
433   }
434 }
435
436 void BlitScreenToBitmap(Bitmap *target_bitmap)
437 {
438   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
439   int fx = FX, fy = FY;
440
441 #if NEW_TILESIZE
442   int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
443   int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
444   int dx_var = dx * TILESIZE_VAR / TILESIZE;
445   int dy_var = dy * TILESIZE_VAR / TILESIZE;
446   int ffx, ffy;
447
448   // fx += dx * TILESIZE_VAR / TILESIZE;
449   // fy += dy * TILESIZE_VAR / TILESIZE;
450 #else
451   fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
452   fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
453 #endif
454
455   ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
456   ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
457
458   if (EVEN(SCR_FIELDX))
459   {
460     if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
461       fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
462     else
463       fx += (dx_var > 0 ? TILEX_VAR : 0);
464   }
465   else
466   {
467     fx += dx_var;
468   }
469
470   if (EVEN(SCR_FIELDY))
471   {
472     if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
473       fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
474     else
475       fy += (dy_var > 0 ? TILEY_VAR : 0);
476   }
477   else
478   {
479     fy += dy_var;
480   }
481
482 #if 0
483   printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
484          scroll_x, scroll_y,
485          SBX_Left, SBX_Right,
486          SBY_Upper, SBY_Lower,
487          fx, fy);
488 #endif
489
490   if (border.draw_masked[GAME_MODE_PLAYING])
491   {
492     if (buffer != backbuffer)
493     {
494       /* copy playfield buffer to backbuffer to add masked border */
495       BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
496       DrawMaskedBorder(REDRAW_FIELD);
497     }
498
499     BlitBitmap(backbuffer, target_bitmap,
500                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
501                REAL_SX, REAL_SY);
502   }
503   else
504   {
505     BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
506   }
507 }
508
509 void BackToFront()
510 {
511   int x, y;
512   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
513
514 #if 0
515   printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
516   for (x = 0; x < SCR_FIELDX; x++)
517     for (y = 0 ; y < SCR_FIELDY; y++)
518       if (redraw[redraw_x1 + x][redraw_y1 + y])
519         printf("::: - %d, %d [%s]\n",
520                LEVELX(x), LEVELY(y),
521                EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
522 #endif
523
524   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
525     redraw_mask |= REDRAW_FIELD;
526
527 #if 0
528   // never redraw single tiles, always redraw the whole field
529   // (redrawing single tiles up to a certain threshold was faster on old,
530   // now legacy graphics, but slows things down on modern graphics now)
531   // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
532   if (redraw_mask & REDRAW_TILES)
533     redraw_mask |= REDRAW_FIELD;
534 #endif
535
536 #if 0
537   /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
538   /* (force full redraw) */
539   if (game_status == GAME_MODE_PLAYING)
540     redraw_mask |= REDRAW_FIELD;
541 #endif
542
543   if (redraw_mask & REDRAW_FIELD)
544     redraw_mask &= ~REDRAW_TILES;
545
546   if (redraw_mask == REDRAW_NONE)
547     return;
548
549 #if 0
550   printf("::: ");
551   if (redraw_mask & REDRAW_ALL)
552     printf("[REDRAW_ALL]");
553   if (redraw_mask & REDRAW_FIELD)
554     printf("[REDRAW_FIELD]");
555   if (redraw_mask & REDRAW_TILES)
556     printf("[REDRAW_TILES]");
557   if (redraw_mask & REDRAW_DOOR_1)
558     printf("[REDRAW_DOOR_1]");
559   if (redraw_mask & REDRAW_DOOR_2)
560     printf("[REDRAW_DOOR_2]");
561   if (redraw_mask & REDRAW_FROM_BACKBUFFER)
562     printf("[REDRAW_FROM_BACKBUFFER]");
563   printf(" [%d]\n", FrameCounter);
564 #endif
565
566   if (redraw_mask & REDRAW_TILES &&
567       game_status == GAME_MODE_PLAYING &&
568       border.draw_masked[GAME_MODE_PLAYING])
569     redraw_mask |= REDRAW_FIELD;
570
571   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
572   {
573     static boolean last_frame_skipped = FALSE;
574     boolean skip_even_when_not_scrolling = TRUE;
575     boolean just_scrolling = (ScreenMovDir != 0);
576     boolean verbose = FALSE;
577
578     if (global.fps_slowdown_factor > 1 &&
579         (FrameCounter % global.fps_slowdown_factor) &&
580         (just_scrolling || skip_even_when_not_scrolling))
581     {
582       redraw_mask &= ~REDRAW_MAIN;
583
584       last_frame_skipped = TRUE;
585
586       if (verbose)
587         printf("FRAME SKIPPED\n");
588     }
589     else
590     {
591       if (last_frame_skipped)
592         redraw_mask |= REDRAW_FIELD;
593
594       last_frame_skipped = FALSE;
595
596       if (verbose)
597         printf("frame not skipped\n");
598     }
599   }
600
601   /* synchronize X11 graphics at this point; if we would synchronize the
602      display immediately after the buffer switching (after the XFlush),
603      this could mean that we have to wait for the graphics to complete,
604      although we could go on doing calculations for the next frame */
605
606   SyncDisplay();
607
608   /* never draw masked border to backbuffer when using playfield buffer */
609   if (game_status != GAME_MODE_PLAYING ||
610       redraw_mask & REDRAW_FROM_BACKBUFFER ||
611       buffer == backbuffer)
612     DrawMaskedBorder(redraw_mask);
613   else
614     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
615
616   if (redraw_mask & REDRAW_ALL)
617   {
618     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
619
620     redraw_mask = REDRAW_NONE;
621   }
622
623   if (redraw_mask & REDRAW_FIELD)
624   {
625 #if 0
626     printf("::: REDRAW_FIELD\n");
627 #endif
628
629     if (game_status != GAME_MODE_PLAYING ||
630         redraw_mask & REDRAW_FROM_BACKBUFFER)
631     {
632       BlitBitmap(backbuffer, window,
633                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
634     }
635     else
636     {
637 #if 1
638       BlitScreenToBitmap(window);
639 #else
640       int fx = FX, fy = FY;
641
642 #if NEW_TILESIZE
643       int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
644       int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
645       int dx_var = dx * TILESIZE_VAR / TILESIZE;
646       int dy_var = dy * TILESIZE_VAR / TILESIZE;
647       int ffx, ffy;
648
649       // fx += dx * TILESIZE_VAR / TILESIZE;
650       // fy += dy * TILESIZE_VAR / TILESIZE;
651 #else
652       fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
653       fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
654 #endif
655
656       /* !!! THIS WORKS !!! */
657
658       printf("::: %d, %d\n", scroll_x, scroll_y);
659
660       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
661       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
662
663       if (EVEN(SCR_FIELDX))
664       {
665         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
666           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
667         else
668           fx += (dx > 0 ? TILEX_VAR : 0);
669       }
670       else
671       {
672         fx += dx;
673       }
674
675       if (EVEN(SCR_FIELDY))
676       {
677         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
678           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
679         else
680           fy += (dy > 0 ? TILEY_VAR : 0);
681       }
682       else
683       {
684         fy += dy;
685       }
686
687       if (border.draw_masked[GAME_MODE_PLAYING])
688       {
689         if (buffer != backbuffer)
690         {
691           /* copy playfield buffer to backbuffer to add masked border */
692           BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
693           DrawMaskedBorder(REDRAW_FIELD);
694         }
695
696         BlitBitmap(backbuffer, window,
697                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
698                    REAL_SX, REAL_SY);
699       }
700       else
701       {
702         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
703       }
704 #endif
705
706 #if 0
707 #ifdef DEBUG
708       printf("redrawing all (ScreenGfxPos == %d) because %s\n",
709              ScreenGfxPos,
710              (setup.soft_scrolling ?
711               "setup.soft_scrolling" :
712               ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
713               "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
714               ABS(ScreenGfxPos) == ScrollStepSize ?
715               "ABS(ScreenGfxPos) == ScrollStepSize" :
716               "redraw_tiles > REDRAWTILES_THRESHOLD"));
717 #endif
718 #endif
719     }
720
721     redraw_mask &= ~REDRAW_MAIN;
722   }
723
724   if (redraw_mask & REDRAW_DOORS)
725   {
726     if (redraw_mask & REDRAW_DOOR_1)
727       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
728
729     if (redraw_mask & REDRAW_DOOR_2)
730       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
731
732     if (redraw_mask & REDRAW_DOOR_3)
733       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
734
735     redraw_mask &= ~REDRAW_DOORS;
736   }
737
738   if (redraw_mask & REDRAW_MICROLEVEL)
739   {
740     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
741                SX, SY + 10 * TILEY);
742
743     redraw_mask &= ~REDRAW_MICROLEVEL;
744   }
745
746   if (redraw_mask & REDRAW_TILES)
747   {
748 #if 0
749     printf("::: REDRAW_TILES\n");
750 #endif
751
752 #if NEW_TILESIZE
753
754 #if 1
755     InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
756
757     {
758       int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
759       int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
760
761       int dx = 0, dy = 0;
762       int dx_var = dx * TILESIZE_VAR / TILESIZE;
763       int dy_var = dy * TILESIZE_VAR / TILESIZE;
764       int ffx, ffy;
765       int fx = FX, fy = FY;
766
767       int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
768       int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
769
770       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
771       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
772
773       if (EVEN(SCR_FIELDX))
774       {
775         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
776         {
777           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
778
779           if (fx % TILEX_VAR)
780             sx -= TILEX_VAR / 2;
781           else
782             sx -= TILEX_VAR;
783         }
784         else
785         {
786           fx += (dx_var > 0 ? TILEX_VAR : 0);
787         }
788       }
789
790       if (EVEN(SCR_FIELDY))
791       {
792         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
793         {
794           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
795
796           if (fy % TILEY_VAR)
797             sy -= TILEY_VAR / 2;
798           else
799             sy -= TILEY_VAR;
800         }
801         else
802         {
803           fy += (dy_var > 0 ? TILEY_VAR : 0);
804         }
805       }
806
807 #if 0
808       printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
809 #endif
810
811       for (x = 0; x < scr_fieldx; x++)
812         for (y = 0 ; y < scr_fieldy; y++)
813           if (redraw[redraw_x1 + x][redraw_y1 + y])
814             BlitBitmap(buffer, window,
815                        FX + x * TILEX_VAR, FY + y * TILEY_VAR,
816                        TILEX_VAR, TILEY_VAR,
817                        sx + x * TILEX_VAR, sy + y * TILEY_VAR);
818     }
819
820     InitGfxClipRegion(FALSE, -1, -1, -1, -1);
821 #else
822     for (x = 0; x < SCR_FIELDX; x++)
823       for (y = 0 ; y < SCR_FIELDY; y++)
824         if (redraw[redraw_x1 + x][redraw_y1 + y])
825           BlitBitmap(buffer, window,
826                      FX + x * TILEX_VAR, FY + y * TILEY_VAR,
827                      TILEX_VAR, TILEY_VAR,
828                      SX + x * TILEX_VAR, SY + y * TILEY_VAR);
829 #endif
830
831 #else
832     for (x = 0; x < SCR_FIELDX; x++)
833       for (y = 0 ; y < SCR_FIELDY; y++)
834         if (redraw[redraw_x1 + x][redraw_y1 + y])
835           BlitBitmap(buffer, window,
836                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
837                      SX + x * TILEX, SY + y * TILEY);
838 #endif
839   }
840
841   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
842   {
843     char text[100];
844     char info1[100];
845
846     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
847     if (!global.fps_slowdown)
848       info1[0] = '\0';
849
850     sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
851 #if 1
852     DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
853 #else
854     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
855 #endif
856   }
857
858   FlushDisplay();
859
860   for (x = 0; x < MAX_BUF_XSIZE; x++)
861     for (y = 0; y < MAX_BUF_YSIZE; y++)
862       redraw[x][y] = 0;
863   redraw_tiles = 0;
864   redraw_mask = REDRAW_NONE;
865 }
866
867 static void FadeCrossSaveBackbuffer()
868 {
869   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
870 }
871
872 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
873 {
874   static int fade_type_skip = FADE_TYPE_NONE;
875   void (*draw_border_function)(void) = NULL;
876   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
877   int x, y, width, height;
878   int fade_delay, post_delay;
879
880   if (fade_type == FADE_TYPE_FADE_OUT)
881   {
882     if (fade_type_skip != FADE_TYPE_NONE)
883     {
884 #if 0
885       printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
886 #endif
887
888       /* skip all fade operations until specified fade operation */
889       if (fade_type & fade_type_skip)
890         fade_type_skip = FADE_TYPE_NONE;
891
892       return;
893     }
894
895     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
896     {
897       FadeCrossSaveBackbuffer();
898
899       return;
900     }
901   }
902
903   redraw_mask |= fade_mask;
904
905   if (fade_type == FADE_TYPE_SKIP)
906   {
907 #if 0
908     printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
909 #endif
910
911     fade_type_skip = fade_mode;
912
913     return;
914   }
915
916 #if 0
917   printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
918          fade_type_skip);
919 #endif
920
921 #if 1
922   fade_delay = fading.fade_delay;
923   post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
924 #endif
925
926   if (fade_type_skip != FADE_TYPE_NONE)
927   {
928 #if 0
929     printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
930 #endif
931
932     /* skip all fade operations until specified fade operation */
933     if (fade_type & fade_type_skip)
934       fade_type_skip = FADE_TYPE_NONE;
935
936 #if 1
937     fade_delay = 0;
938 #else
939     return;
940 #endif
941   }
942
943 #if 1
944   if (global.autoplay_leveldir)
945   {
946     // fading.fade_mode = FADE_MODE_NONE;
947
948     return;
949   }
950 #endif
951
952 #if 0
953   if (fading.fade_mode == FADE_MODE_NONE)
954   {
955     BackToFront();
956
957     return;
958   }
959 #endif
960
961   /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
962
963 #if 0
964   printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
965 #endif
966
967 #if 0
968   if (fade_mask == REDRAW_NONE)
969     fade_mask = REDRAW_FIELD;
970 #endif
971
972   // if (fade_mask & REDRAW_FIELD)
973   if (fade_mask == REDRAW_FIELD)
974   {
975     x = REAL_SX;
976     y = REAL_SY;
977     width  = FULL_SXSIZE;
978     height = FULL_SYSIZE;
979
980 #if 0
981     fade_delay = fading.fade_delay;
982     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
983 #endif
984
985     if (border.draw_masked_when_fading)
986       draw_border_function = DrawMaskedBorder_FIELD;    /* update when fading */
987     else
988       DrawMaskedBorder_FIELD();                         /* draw once */
989   }
990   else          /* REDRAW_ALL */
991   {
992     x = 0;
993     y = 0;
994     width  = WIN_XSIZE;
995     height = WIN_YSIZE;
996
997 #if 0
998     fade_delay = fading.fade_delay;
999     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1000 #endif
1001   }
1002
1003 #if 1
1004   if (!setup.fade_screens ||
1005       fade_delay == 0 ||
1006       fading.fade_mode == FADE_MODE_NONE)
1007 #else
1008   if (!setup.fade_screens || fade_delay == 0)
1009 #endif
1010   {
1011     if (fade_mode == FADE_MODE_FADE_OUT)
1012       return;
1013
1014 #if 0
1015     if (fade_mode == FADE_MODE_FADE_OUT &&
1016         fading.fade_mode != FADE_MODE_NONE)
1017       ClearRectangle(backbuffer, x, y, width, height);
1018 #endif
1019
1020 #if 1
1021     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1022     redraw_mask = REDRAW_NONE;
1023 #else
1024     BackToFront();
1025 #endif
1026
1027     return;
1028   }
1029
1030   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1031                 draw_border_function);
1032
1033   redraw_mask &= ~fade_mask;
1034 }
1035
1036 void FadeIn(int fade_mask)
1037 {
1038   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1039     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1040   else
1041     FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1042 }
1043
1044 void FadeOut(int fade_mask)
1045 {
1046   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1047     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1048   else
1049     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1050
1051   global.border_status = game_status;
1052 }
1053
1054 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1055 {
1056   static struct TitleFadingInfo fading_leave_stored;
1057
1058   if (set)
1059     fading_leave_stored = fading_leave;
1060   else
1061     fading = fading_leave_stored;
1062 }
1063
1064 void FadeSetEnterMenu()
1065 {
1066   fading = menu.enter_menu;
1067
1068 #if 0
1069   printf("::: storing enter_menu\n");
1070 #endif
1071
1072   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
1073 }
1074
1075 void FadeSetLeaveMenu()
1076 {
1077   fading = menu.leave_menu;
1078
1079 #if 0
1080   printf("::: storing leave_menu\n");
1081 #endif
1082
1083   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
1084 }
1085
1086 void FadeSetEnterScreen()
1087 {
1088   fading = menu.enter_screen[game_status];
1089
1090 #if 0
1091   printf("::: storing leave_screen[%d]\n", game_status);
1092 #endif
1093
1094   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
1095 }
1096
1097 void FadeSetNextScreen()
1098 {
1099   fading = menu.next_screen;
1100
1101 #if 0
1102   printf("::: storing next_screen\n");
1103 #endif
1104
1105   // (do not overwrite fade mode set by FadeSetEnterScreen)
1106   // FadeSetLeaveNext(fading, TRUE);    /* (keep same fade mode) */
1107 }
1108
1109 void FadeSetLeaveScreen()
1110 {
1111 #if 0
1112   printf("::: recalling last stored value\n");
1113 #endif
1114
1115   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
1116 }
1117
1118 void FadeSetFromType(int type)
1119 {
1120   if (type & TYPE_ENTER_SCREEN)
1121     FadeSetEnterScreen();
1122   else if (type & TYPE_ENTER)
1123     FadeSetEnterMenu();
1124   else if (type & TYPE_LEAVE)
1125     FadeSetLeaveMenu();
1126 }
1127
1128 void FadeSetDisabled()
1129 {
1130   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1131
1132   fading = fading_none;
1133 }
1134
1135 void FadeSkipNextFadeIn()
1136 {
1137   FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1138 }
1139
1140 void FadeSkipNextFadeOut()
1141 {
1142   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1143 }
1144
1145 void SetWindowBackgroundImageIfDefined(int graphic)
1146 {
1147   if (graphic_info[graphic].bitmap)
1148     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1149 }
1150
1151 void SetMainBackgroundImageIfDefined(int graphic)
1152 {
1153   if (graphic_info[graphic].bitmap)
1154     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1155 }
1156
1157 void SetDoorBackgroundImageIfDefined(int graphic)
1158 {
1159   if (graphic_info[graphic].bitmap)
1160     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1161 }
1162
1163 void SetWindowBackgroundImage(int graphic)
1164 {
1165   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1166                             graphic_info[graphic].bitmap ?
1167                             graphic_info[graphic].bitmap :
1168                             graphic_info[IMG_BACKGROUND].bitmap);
1169 }
1170
1171 void SetMainBackgroundImage(int graphic)
1172 {
1173   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1174                           graphic_info[graphic].bitmap ?
1175                           graphic_info[graphic].bitmap :
1176                           graphic_info[IMG_BACKGROUND].bitmap);
1177 }
1178
1179 void SetDoorBackgroundImage(int graphic)
1180 {
1181   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1182                           graphic_info[graphic].bitmap ?
1183                           graphic_info[graphic].bitmap :
1184                           graphic_info[IMG_BACKGROUND].bitmap);
1185 }
1186
1187 void SetPanelBackground()
1188 {
1189 #if 1
1190   struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1191
1192 #if 1
1193   BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1194                   gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1195 #else
1196   /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1197   ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1198   BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1199              MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1200 #endif
1201 #else
1202   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1203              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1204 #endif
1205
1206   SetDoorBackgroundBitmap(bitmap_db_panel);
1207 }
1208
1209 void DrawBackground(int x, int y, int width, int height)
1210 {
1211   /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1212   /* (when entering hall of fame after playing) */
1213 #if 0
1214   ClearRectangleOnBackground(drawto, x, y, width, height);
1215 #else
1216   ClearRectangleOnBackground(backbuffer, x, y, width, height);
1217 #endif
1218
1219 #if 1
1220
1221 #if 1
1222   if (IN_GFX_FIELD_FULL(x, y))
1223     redraw_mask |= REDRAW_FIELD;
1224   else if (IN_GFX_DOOR_1(x, y))
1225     redraw_mask |= REDRAW_DOOR_1;
1226   else if (IN_GFX_DOOR_2(x, y))
1227     redraw_mask |= REDRAW_DOOR_2;
1228   else if (IN_GFX_DOOR_3(x, y))
1229     redraw_mask |= REDRAW_DOOR_3;
1230 #else
1231   /* (this only works for the current arrangement of playfield and panels) */
1232   if (x < gfx.dx)
1233     redraw_mask |= REDRAW_FIELD;
1234   else if (y < gfx.vy)
1235     redraw_mask |= REDRAW_DOOR_1;
1236   else
1237     redraw_mask |= REDRAW_DOOR_2;
1238 #endif
1239
1240 #else
1241   /* (this is just wrong (when drawing to one of the two door panel areas)) */
1242   redraw_mask |= REDRAW_FIELD;
1243 #endif
1244 }
1245
1246 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1247 {
1248   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1249
1250   if (font->bitmap == NULL)
1251     return;
1252
1253   DrawBackground(x, y, width, height);
1254 }
1255
1256 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1257 {
1258   struct GraphicInfo *g = &graphic_info[graphic];
1259
1260   if (g->bitmap == NULL)
1261     return;
1262
1263   DrawBackground(x, y, width, height);
1264 }
1265
1266 void ClearField()
1267 {
1268   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1269   /* (when entering hall of fame after playing) */
1270   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1271
1272   /* !!! maybe this should be done before clearing the background !!! */
1273   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1274   {
1275     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1276     SetDrawtoField(DRAW_BUFFERED);
1277   }
1278   else
1279     SetDrawtoField(DRAW_BACKBUFFER);
1280 }
1281
1282 void MarkTileDirty(int x, int y)
1283 {
1284   int xx = redraw_x1 + x;
1285   int yy = redraw_y1 + y;
1286
1287   if (!redraw[xx][yy])
1288     redraw_tiles++;
1289
1290   redraw[xx][yy] = TRUE;
1291   redraw_mask |= REDRAW_TILES;
1292 }
1293
1294 void SetBorderElement()
1295 {
1296   int x, y;
1297
1298   BorderElement = EL_EMPTY;
1299
1300   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1301   {
1302     for (x = 0; x < lev_fieldx; x++)
1303     {
1304       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1305         BorderElement = EL_STEELWALL;
1306
1307       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1308         x = lev_fieldx - 2;
1309     }
1310   }
1311 }
1312
1313 void FloodFillLevel(int from_x, int from_y, int fill_element,
1314                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1315                     int max_fieldx, int max_fieldy)
1316 {
1317   int i,x,y;
1318   int old_element;
1319   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1320   static int safety = 0;
1321
1322   /* check if starting field still has the desired content */
1323   if (field[from_x][from_y] == fill_element)
1324     return;
1325
1326   safety++;
1327
1328   if (safety > max_fieldx * max_fieldy)
1329     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1330
1331   old_element = field[from_x][from_y];
1332   field[from_x][from_y] = fill_element;
1333
1334   for (i = 0; i < 4; i++)
1335   {
1336     x = from_x + check[i][0];
1337     y = from_y + check[i][1];
1338
1339     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1340       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1341   }
1342
1343   safety--;
1344 }
1345
1346 void SetRandomAnimationValue(int x, int y)
1347 {
1348   gfx.anim_random_frame = GfxRandom[x][y];
1349 }
1350
1351 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1352 {
1353   /* animation synchronized with global frame counter, not move position */
1354   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1355     sync_frame = FrameCounter;
1356
1357   return getAnimationFrame(graphic_info[graphic].anim_frames,
1358                            graphic_info[graphic].anim_delay,
1359                            graphic_info[graphic].anim_mode,
1360                            graphic_info[graphic].anim_start_frame,
1361                            sync_frame);
1362 }
1363
1364 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1365                               Bitmap **bitmap, int *x, int *y,
1366                               boolean get_backside)
1367 {
1368   struct
1369   {
1370     int width_mult, width_div;
1371     int height_mult, height_div;
1372   }
1373   offset_calc[6] =
1374   {
1375     { 15, 16,   2, 3    },      /* 1 x 1 */
1376     { 7, 8,     2, 3    },      /* 2 x 2 */
1377     { 3, 4,     2, 3    },      /* 4 x 4 */
1378     { 1, 2,     2, 3    },      /* 8 x 8 */
1379     { 0, 1,     2, 3    },      /* 16 x 16 */
1380     { 0, 1,     0, 1    },      /* 32 x 32 */
1381   };
1382   struct GraphicInfo *g = &graphic_info[graphic];
1383   Bitmap *src_bitmap = g->bitmap;
1384   int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1385   int offset_calc_pos = log_2(tilesize);
1386   int width_mult  = offset_calc[offset_calc_pos].width_mult;
1387   int width_div   = offset_calc[offset_calc_pos].width_div;
1388   int height_mult = offset_calc[offset_calc_pos].height_mult;
1389   int height_div  = offset_calc[offset_calc_pos].height_div;
1390   int startx = src_bitmap->width * width_mult / width_div;
1391   int starty = src_bitmap->height * height_mult / height_div;
1392 #if NEW_TILESIZE
1393   int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1394     tilesize / TILESIZE;
1395   int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1396     tilesize / TILESIZE;
1397 #else
1398   int src_x = g->src_x * tilesize / TILESIZE;
1399   int src_y = g->src_y * tilesize / TILESIZE;
1400 #endif
1401   int width = g->width * tilesize / TILESIZE;
1402   int height = g->height * tilesize / TILESIZE;
1403   int offset_x = g->offset_x * tilesize / TILESIZE;
1404   int offset_y = g->offset_y * tilesize / TILESIZE;
1405
1406   if (g->offset_y == 0)         /* frames are ordered horizontally */
1407   {
1408     int max_width = g->anim_frames_per_line * width;
1409     int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1410
1411     src_x = pos % max_width;
1412     src_y = src_y % height + pos / max_width * height;
1413   }
1414   else if (g->offset_x == 0)    /* frames are ordered vertically */
1415   {
1416     int max_height = g->anim_frames_per_line * height;
1417     int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1418
1419     src_x = src_x % width + pos / max_height * width;
1420     src_y = pos % max_height;
1421   }
1422   else                          /* frames are ordered diagonally */
1423   {
1424     src_x = src_x + frame * offset_x;
1425     src_y = src_y + frame * offset_y;
1426   }
1427
1428   *bitmap = src_bitmap;
1429   *x = startx + src_x;
1430   *y = starty + src_y;
1431 }
1432
1433 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1434                               int *x, int *y, boolean get_backside)
1435 {
1436   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1437                            get_backside);
1438 }
1439
1440 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1441                            Bitmap **bitmap, int *x, int *y)
1442 {
1443   getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1444 }
1445
1446 void getFixedGraphicSource(int graphic, int frame,
1447                            Bitmap **bitmap, int *x, int *y)
1448 {
1449   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1450 }
1451
1452 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1453 {
1454 #if 1
1455   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1456 #else
1457   struct GraphicInfo *g = &graphic_info[graphic];
1458   int mini_startx = 0;
1459   int mini_starty = g->bitmap->height * 2 / 3;
1460
1461   *bitmap = g->bitmap;
1462   *x = mini_startx + g->src_x / 2;
1463   *y = mini_starty + g->src_y / 2;
1464 #endif
1465 }
1466
1467 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1468                                 int *x, int *y, boolean get_backside)
1469 {
1470   struct GraphicInfo *g = &graphic_info[graphic];
1471   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1472   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1473
1474 #if NEW_TILESIZE
1475   if (TILESIZE_VAR != TILESIZE)
1476     return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1477                                     get_backside);
1478 #endif
1479
1480   *bitmap = g->bitmap;
1481
1482   if (g->offset_y == 0)         /* frames are ordered horizontally */
1483   {
1484     int max_width = g->anim_frames_per_line * g->width;
1485     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1486
1487     *x = pos % max_width;
1488     *y = src_y % g->height + pos / max_width * g->height;
1489   }
1490   else if (g->offset_x == 0)    /* frames are ordered vertically */
1491   {
1492     int max_height = g->anim_frames_per_line * g->height;
1493     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1494
1495     *x = src_x % g->width + pos / max_height * g->width;
1496     *y = pos % max_height;
1497   }
1498   else                          /* frames are ordered diagonally */
1499   {
1500     *x = src_x + frame * g->offset_x;
1501     *y = src_y + frame * g->offset_y;
1502   }
1503 }
1504
1505 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1506 {
1507   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1508 }
1509
1510 void DrawGraphic(int x, int y, int graphic, int frame)
1511 {
1512 #if DEBUG
1513   if (!IN_SCR_FIELD(x, y))
1514   {
1515     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1516     printf("DrawGraphic(): This should never happen!\n");
1517     return;
1518   }
1519 #endif
1520
1521 #if NEW_TILESIZE
1522   DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1523                  frame);
1524 #else
1525   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1526 #endif
1527   MarkTileDirty(x, y);
1528 }
1529
1530 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1531 {
1532 #if DEBUG
1533   if (!IN_SCR_FIELD(x, y))
1534   {
1535     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1536     printf("DrawGraphic(): This should never happen!\n");
1537     return;
1538   }
1539 #endif
1540
1541   DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1542                       frame);
1543   MarkTileDirty(x, y);
1544 }
1545
1546 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1547                     int frame)
1548 {
1549   Bitmap *src_bitmap;
1550   int src_x, src_y;
1551
1552   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1553 #if NEW_TILESIZE
1554   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1555 #else
1556   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1557 #endif
1558 }
1559
1560 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1561                          int frame)
1562 {
1563   Bitmap *src_bitmap;
1564   int src_x, src_y;
1565
1566   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1567   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1568 }
1569
1570 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1571 {
1572 #if DEBUG
1573   if (!IN_SCR_FIELD(x, y))
1574   {
1575     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1576     printf("DrawGraphicThruMask(): This should never happen!\n");
1577     return;
1578   }
1579 #endif
1580
1581 #if NEW_TILESIZE
1582   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1583                          graphic, frame);
1584 #else
1585   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1586                          frame);
1587 #endif
1588   MarkTileDirty(x, y);
1589 }
1590
1591 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1592 {
1593 #if DEBUG
1594   if (!IN_SCR_FIELD(x, y))
1595   {
1596     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1597     printf("DrawGraphicThruMask(): This should never happen!\n");
1598     return;
1599   }
1600 #endif
1601
1602   DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1603                               graphic, frame);
1604   MarkTileDirty(x, y);
1605 }
1606
1607 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1608                             int frame)
1609 {
1610   Bitmap *src_bitmap;
1611   int src_x, src_y;
1612
1613   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1614
1615   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1616                 dst_x - src_x, dst_y - src_y);
1617 #if NEW_TILESIZE
1618   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1619                    dst_x, dst_y);
1620 #else
1621   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1622 #endif
1623 }
1624
1625 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1626                                  int graphic, int frame)
1627 {
1628   Bitmap *src_bitmap;
1629   int src_x, src_y;
1630
1631   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1632
1633   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1634                 dst_x - src_x, dst_y - src_y);
1635   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1636 }
1637
1638 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1639 {
1640   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1641                       frame, tilesize);
1642   MarkTileDirty(x / tilesize, y / tilesize);
1643 }
1644
1645 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1646                          int tilesize)
1647 {
1648   Bitmap *src_bitmap;
1649   int src_x, src_y;
1650
1651   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1652   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1653 }
1654
1655 void DrawMiniGraphic(int x, int y, int graphic)
1656 {
1657   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1658   MarkTileDirty(x / 2, y / 2);
1659 }
1660
1661 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1662 {
1663   Bitmap *src_bitmap;
1664   int src_x, src_y;
1665
1666   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1667   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1668 }
1669
1670 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1671                                             int graphic, int frame,
1672                                             int cut_mode, int mask_mode)
1673 {
1674   Bitmap *src_bitmap;
1675   int src_x, src_y;
1676   int dst_x, dst_y;
1677   int width = TILEX, height = TILEY;
1678   int cx = 0, cy = 0;
1679
1680   if (dx || dy)                 /* shifted graphic */
1681   {
1682     if (x < BX1)                /* object enters playfield from the left */
1683     {
1684       x = BX1;
1685       width = dx;
1686       cx = TILEX - dx;
1687       dx = 0;
1688     }
1689     else if (x > BX2)           /* object enters playfield from the right */
1690     {
1691       x = BX2;
1692       width = -dx;
1693       dx = TILEX + dx;
1694     }
1695     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1696     {
1697       width += dx;
1698       cx = -dx;
1699       dx = 0;
1700     }
1701     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1702       width -= dx;
1703     else if (dx)                /* general horizontal movement */
1704       MarkTileDirty(x + SIGN(dx), y);
1705
1706     if (y < BY1)                /* object enters playfield from the top */
1707     {
1708       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1709         return;
1710
1711       y = BY1;
1712       height = dy;
1713       cy = TILEY - dy;
1714       dy = 0;
1715     }
1716     else if (y > BY2)           /* object enters playfield from the bottom */
1717     {
1718       y = BY2;
1719       height = -dy;
1720       dy = TILEY + dy;
1721     }
1722     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1723     {
1724       height += dy;
1725       cy = -dy;
1726       dy = 0;
1727     }
1728     else if (dy > 0 && cut_mode == CUT_ABOVE)
1729     {
1730       if (y == BY2)             /* object completely above bottom border */
1731         return;
1732
1733       height = dy;
1734       cy = TILEY - dy;
1735       dy = TILEY;
1736       MarkTileDirty(x, y + 1);
1737     }                           /* object leaves playfield to the bottom */
1738     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1739       height -= dy;
1740     else if (dy)                /* general vertical movement */
1741       MarkTileDirty(x, y + SIGN(dy));
1742   }
1743
1744 #if DEBUG
1745   if (!IN_SCR_FIELD(x, y))
1746   {
1747     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1748     printf("DrawGraphicShifted(): This should never happen!\n");
1749     return;
1750   }
1751 #endif
1752
1753 #if NEW_TILESIZE
1754   width = width * TILESIZE_VAR / TILESIZE;
1755   height = height * TILESIZE_VAR / TILESIZE;
1756   cx = cx * TILESIZE_VAR / TILESIZE;
1757   cy = cy * TILESIZE_VAR / TILESIZE;
1758   dx = dx * TILESIZE_VAR / TILESIZE;
1759   dy = dy * TILESIZE_VAR / TILESIZE;
1760 #endif
1761
1762   if (width > 0 && height > 0)
1763   {
1764     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1765
1766     src_x += cx;
1767     src_y += cy;
1768
1769 #if NEW_TILESIZE
1770     dst_x = FX + x * TILEX_VAR + dx;
1771     dst_y = FY + y * TILEY_VAR + dy;
1772 #else
1773     dst_x = FX + x * TILEX + dx;
1774     dst_y = FY + y * TILEY + dy;
1775 #endif
1776
1777     if (mask_mode == USE_MASKING)
1778     {
1779       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1780                     dst_x - src_x, dst_y - src_y);
1781       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1782                        dst_x, dst_y);
1783     }
1784     else
1785       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1786                  dst_x, dst_y);
1787
1788     MarkTileDirty(x, y);
1789   }
1790 }
1791
1792 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1793                                             int graphic, int frame,
1794                                             int cut_mode, int mask_mode)
1795 {
1796   Bitmap *src_bitmap;
1797   int src_x, src_y;
1798   int dst_x, dst_y;
1799 #if NEW_TILESIZE
1800   int width = TILEX_VAR, height = TILEY_VAR;
1801 #else
1802   int width = TILEX, height = TILEY;
1803 #endif
1804   int x1 = x;
1805   int y1 = y;
1806   int x2 = x + SIGN(dx);
1807   int y2 = y + SIGN(dy);
1808 #if 0
1809   /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1810   int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1811 #else
1812   /* movement with two-tile animations must be sync'ed with movement position,
1813      not with current GfxFrame (which can be higher when using slow movement) */
1814   int anim_pos = (dx ? ABS(dx) : ABS(dy));
1815   int anim_frames = graphic_info[graphic].anim_frames;
1816 #if 1
1817   /* (we also need anim_delay here for movement animations with less frames) */
1818   int anim_delay = graphic_info[graphic].anim_delay;
1819   int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1820 #else
1821   int sync_frame = anim_pos * anim_frames / TILESIZE;
1822 #endif
1823 #endif
1824   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1825   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1826
1827   /* re-calculate animation frame for two-tile movement animation */
1828   frame = getGraphicAnimationFrame(graphic, sync_frame);
1829
1830 #if 0
1831 #if 0
1832   printf("::: %d, %d, %d => %d [%d]\n",
1833          anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1834 #else
1835   printf("::: %d, %d => %d\n",
1836          anim_pos, anim_frames, sync_frame);
1837 #endif
1838 #endif
1839
1840 #if 0
1841   printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1842          GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1843 #endif
1844
1845   /* check if movement start graphic inside screen area and should be drawn */
1846   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1847   {
1848     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1849
1850 #if NEW_TILESIZE
1851     dst_x = FX + x1 * TILEX_VAR;
1852     dst_y = FY + y1 * TILEY_VAR;
1853 #else
1854     dst_x = FX + x1 * TILEX;
1855     dst_y = FY + y1 * TILEY;
1856 #endif
1857
1858     if (mask_mode == USE_MASKING)
1859     {
1860       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1861                     dst_x - src_x, dst_y - src_y);
1862       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1863                        dst_x, dst_y);
1864     }
1865     else
1866       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1867                  dst_x, dst_y);
1868
1869     MarkTileDirty(x1, y1);
1870   }
1871
1872   /* check if movement end graphic inside screen area and should be drawn */
1873   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1874   {
1875     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1876
1877 #if NEW_TILESIZE
1878     dst_x = FX + x2 * TILEX_VAR;
1879     dst_y = FY + y2 * TILEY_VAR;
1880 #else
1881     dst_x = FX + x2 * TILEX;
1882     dst_y = FY + y2 * TILEY;
1883 #endif
1884
1885     if (mask_mode == USE_MASKING)
1886     {
1887       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1888                     dst_x - src_x, dst_y - src_y);
1889       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1890                        dst_x, dst_y);
1891     }
1892     else
1893       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1894                  dst_x, dst_y);
1895
1896     MarkTileDirty(x2, y2);
1897   }
1898 }
1899
1900 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1901                                int graphic, int frame,
1902                                int cut_mode, int mask_mode)
1903 {
1904   if (graphic < 0)
1905   {
1906     DrawGraphic(x, y, graphic, frame);
1907
1908     return;
1909   }
1910
1911   if (graphic_info[graphic].double_movement)    /* EM style movement images */
1912     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1913   else
1914     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1915 }
1916
1917 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1918                                 int frame, int cut_mode)
1919 {
1920   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1921 }
1922
1923 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1924                           int cut_mode, int mask_mode)
1925 {
1926   int lx = LEVELX(x), ly = LEVELY(y);
1927   int graphic;
1928   int frame;
1929
1930   if (IN_LEV_FIELD(lx, ly))
1931   {
1932     SetRandomAnimationValue(lx, ly);
1933
1934     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1935     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1936
1937     /* do not use double (EM style) movement graphic when not moving */
1938     if (graphic_info[graphic].double_movement && !dx && !dy)
1939     {
1940       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1941       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1942     }
1943   }
1944   else  /* border element */
1945   {
1946     graphic = el2img(element);
1947     frame = getGraphicAnimationFrame(graphic, -1);
1948   }
1949
1950   if (element == EL_EXPANDABLE_WALL)
1951   {
1952     boolean left_stopped = FALSE, right_stopped = FALSE;
1953
1954     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1955       left_stopped = TRUE;
1956     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1957       right_stopped = TRUE;
1958
1959     if (left_stopped && right_stopped)
1960       graphic = IMG_WALL;
1961     else if (left_stopped)
1962     {
1963       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1964       frame = graphic_info[graphic].anim_frames - 1;
1965     }
1966     else if (right_stopped)
1967     {
1968       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1969       frame = graphic_info[graphic].anim_frames - 1;
1970     }
1971   }
1972
1973   if (dx || dy)
1974     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1975   else if (mask_mode == USE_MASKING)
1976     DrawGraphicThruMask(x, y, graphic, frame);
1977   else
1978     DrawGraphic(x, y, graphic, frame);
1979 }
1980
1981 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1982                          int cut_mode, int mask_mode)
1983 {
1984   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1985     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1986                          cut_mode, mask_mode);
1987 }
1988
1989 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1990                               int cut_mode)
1991 {
1992   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1993 }
1994
1995 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1996                              int cut_mode)
1997 {
1998   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1999 }
2000
2001 void DrawLevelElementThruMask(int x, int y, int element)
2002 {
2003   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2004 }
2005
2006 void DrawLevelFieldThruMask(int x, int y)
2007 {
2008   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2009 }
2010
2011 /* !!! implementation of quicksand is totally broken !!! */
2012 #define IS_CRUMBLED_TILE(x, y, e)                                       \
2013         (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) ||                     \
2014                              !IS_MOVING(x, y) ||                        \
2015                              (e) == EL_QUICKSAND_EMPTYING ||            \
2016                              (e) == EL_QUICKSAND_FAST_EMPTYING))
2017
2018 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2019                                                int graphic)
2020 {
2021   Bitmap *src_bitmap;
2022   int src_x, src_y;
2023   int width, height, cx, cy;
2024   int sx = SCREENX(x), sy = SCREENY(y);
2025   int crumbled_border_size = graphic_info[graphic].border_size;
2026   int i;
2027
2028   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2029
2030   for (i = 1; i < 4; i++)
2031   {
2032     int dxx = (i & 1 ? dx : 0);
2033     int dyy = (i & 2 ? dy : 0);
2034     int xx = x + dxx;
2035     int yy = y + dyy;
2036     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2037                    BorderElement);
2038
2039     /* check if neighbour field is of same crumble type */
2040     boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2041                     graphic_info[graphic].class ==
2042                     graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2043
2044     /* return if check prevents inner corner */
2045     if (same == (dxx == dx && dyy == dy))
2046       return;
2047   }
2048
2049   /* if we reach this point, we have an inner corner */
2050
2051   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2052
2053 #if NEW_TILESIZE
2054   width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2055   height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2056   cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2057   cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2058
2059   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2060              width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2061 #else
2062   width  = crumbled_border_size;
2063   height = crumbled_border_size;
2064   cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2065   cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2066
2067   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2068              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2069 #endif
2070 }
2071
2072 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2073                                           int dir)
2074 {
2075   Bitmap *src_bitmap;
2076   int src_x, src_y;
2077   int width, height, bx, by, cx, cy;
2078   int sx = SCREENX(x), sy = SCREENY(y);
2079   int crumbled_border_size = graphic_info[graphic].border_size;
2080   int i;
2081
2082   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2083
2084   /* draw simple, sloppy, non-corner-accurate crumbled border */
2085
2086 #if 1
2087   width  = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2088   height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2089   cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2090   cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2091 #else
2092   if (dir == 1 || dir == 2)             /* left or right crumbled border */
2093   {
2094     width = crumbled_border_size;
2095     height = TILEY;
2096     cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2097     cy = 0;
2098   }
2099   else                                  /* top or bottom crumbled border */
2100   {
2101     width = TILEX;
2102     height = crumbled_border_size;
2103     cx = 0;
2104     cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2105   }
2106 #endif
2107
2108 #if NEW_TILESIZE
2109   BlitBitmap(src_bitmap, drawto_field,
2110              src_x + cx * TILESIZE_VAR / TILESIZE,
2111              src_y + cy * TILESIZE_VAR / TILESIZE,
2112              width * TILESIZE_VAR / TILESIZE,
2113              height * TILESIZE_VAR / TILESIZE,
2114              FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2115              FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2116 #else
2117   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2118              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2119 #endif
2120
2121   /* (remaining middle border part must be at least as big as corner part) */
2122   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2123       crumbled_border_size >= TILESIZE / 3)
2124     return;
2125
2126   /* correct corners of crumbled border, if needed */
2127
2128 #if 1
2129   for (i = -1; i <= 1; i+=2)
2130   {
2131     int xx = x + (dir == 0 || dir == 3 ? i : 0);
2132     int yy = y + (dir == 1 || dir == 2 ? i : 0);
2133     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2134                    BorderElement);
2135
2136     /* check if neighbour field is of same crumble type */
2137     if (IS_CRUMBLED_TILE(xx, yy, element) &&
2138         graphic_info[graphic].class ==
2139         graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2140     {
2141       /* no crumbled corner, but continued crumbled border */
2142
2143       int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2144       int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2145       int b1 = (i == 1 ? crumbled_border_size :
2146                 TILESIZE - 2 * crumbled_border_size);
2147
2148       width  = crumbled_border_size;
2149       height = crumbled_border_size;
2150
2151       if (dir == 1 || dir == 2)
2152       {
2153         cx = c1;
2154         cy = c2;
2155         bx = cx;
2156         by = b1;
2157       }
2158       else
2159       {
2160         cx = c2;
2161         cy = c1;
2162         bx = b1;
2163         by = cy;
2164       }
2165
2166 #if NEW_TILESIZE
2167       BlitBitmap(src_bitmap, drawto_field,
2168                  src_x + bx * TILESIZE_VAR / TILESIZE,
2169                  src_y + by * TILESIZE_VAR / TILESIZE,
2170                  width * TILESIZE_VAR / TILESIZE,
2171                  height * TILESIZE_VAR / TILESIZE,
2172                  FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2173                  FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2174 #else
2175       BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2176                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2177 #endif
2178     }
2179   }
2180 #else
2181   if (dir == 1 || dir == 2)             /* left or right crumbled border */
2182   {
2183     for (i = -1; i <= 1; i+=2)
2184     {
2185       int xx = x;
2186       int yy = y + i;
2187       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2188                      BorderElement);
2189
2190       /* check if neighbour field is of same crumble type */
2191       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2192           graphic_info[graphic].class ==
2193           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2194       {
2195         /* no crumbled corner, but continued crumbled border */
2196
2197         width  = crumbled_border_size;
2198         height = crumbled_border_size;
2199         cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2200         cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2201         bx = cx;
2202         by = (i == 1 ? crumbled_border_size :
2203               TILEY - 2 * crumbled_border_size);
2204
2205         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2206                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2207       }
2208     }
2209   }
2210   else                          /* top or bottom crumbled border */
2211   {
2212     for (i = -1; i <= 1; i+=2)
2213     {
2214       int xx = x + i;
2215       int yy = y;
2216       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2217                      BorderElement);
2218
2219       /* check if neighbour field is of same crumble type */
2220       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2221           graphic_info[graphic].class ==
2222           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2223       {
2224         /* no crumbled corner, but continued crumbled border */
2225
2226         width  = crumbled_border_size;
2227         height = crumbled_border_size;
2228         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2229         cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2230         bx = (i == 1 ? crumbled_border_size :
2231               TILEX - 2 * crumbled_border_size);
2232         by = cy;
2233
2234         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2235                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2236       }
2237     }
2238   }
2239 #endif
2240 }
2241
2242 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2243 {
2244   int sx = SCREENX(x), sy = SCREENY(y);
2245   int element;
2246   int i;
2247   static int xy[4][2] =
2248   {
2249     { 0, -1 },
2250     { -1, 0 },
2251     { +1, 0 },
2252     { 0, +1 }
2253   };
2254
2255   if (!IN_LEV_FIELD(x, y))
2256     return;
2257
2258   element = TILE_GFX_ELEMENT(x, y);
2259
2260   /* crumble field itself */
2261   if (IS_CRUMBLED_TILE(x, y, element))
2262   {
2263     if (!IN_SCR_FIELD(sx, sy))
2264       return;
2265
2266     for (i = 0; i < 4; i++)
2267     {
2268       int xx = x + xy[i][0];
2269       int yy = y + xy[i][1];
2270
2271       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2272                  BorderElement);
2273
2274       /* check if neighbour field is of same crumble type */
2275 #if 1
2276       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2277           graphic_info[graphic].class ==
2278           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2279         continue;
2280 #else
2281       if (IS_CRUMBLED_TILE(xx, yy, element))
2282         continue;
2283 #endif
2284
2285       DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2286     }
2287
2288     if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2289         graphic_info[graphic].anim_frames == 2)
2290     {
2291       for (i = 0; i < 4; i++)
2292       {
2293         int dx = (i & 1 ? +1 : -1);
2294         int dy = (i & 2 ? +1 : -1);
2295
2296         DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2297       }
2298     }
2299
2300     MarkTileDirty(sx, sy);
2301   }
2302   else          /* center field not crumbled -- crumble neighbour fields */
2303   {
2304     for (i = 0; i < 4; i++)
2305     {
2306       int xx = x + xy[i][0];
2307       int yy = y + xy[i][1];
2308       int sxx = sx + xy[i][0];
2309       int syy = sy + xy[i][1];
2310
2311       if (!IN_LEV_FIELD(xx, yy) ||
2312           !IN_SCR_FIELD(sxx, syy))
2313         continue;
2314
2315       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2316         continue;
2317
2318       element = TILE_GFX_ELEMENT(xx, yy);
2319
2320       if (!IS_CRUMBLED_TILE(xx, yy, element))
2321         continue;
2322
2323       graphic = el_act2crm(element, ACTION_DEFAULT);
2324
2325       DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2326
2327       MarkTileDirty(sxx, syy);
2328     }
2329   }
2330 }
2331
2332 void DrawLevelFieldCrumbled(int x, int y)
2333 {
2334   int graphic;
2335
2336   if (!IN_LEV_FIELD(x, y))
2337     return;
2338
2339 #if 1
2340   /* !!! CHECK THIS !!! */
2341
2342   /*
2343   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2344       GFX_CRUMBLED(GfxElement[x][y]))
2345   */
2346
2347   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2348       GfxElement[x][y] != EL_UNDEFINED &&
2349       GFX_CRUMBLED(GfxElement[x][y]))
2350   {
2351     DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2352
2353     return;
2354   }
2355 #endif
2356
2357 #if 1
2358   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2359 #else
2360   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2361 #endif
2362
2363   DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2364 }
2365
2366 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2367                                    int step_frame)
2368 {
2369   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2370   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2371   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2372   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2373   int sx = SCREENX(x), sy = SCREENY(y);
2374
2375   DrawGraphic(sx, sy, graphic1, frame1);
2376   DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2377 }
2378
2379 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2380 {
2381   int sx = SCREENX(x), sy = SCREENY(y);
2382   static int xy[4][2] =
2383   {
2384     { 0, -1 },
2385     { -1, 0 },
2386     { +1, 0 },
2387     { 0, +1 }
2388   };
2389   int i;
2390
2391   for (i = 0; i < 4; i++)
2392   {
2393     int xx = x + xy[i][0];
2394     int yy = y + xy[i][1];
2395     int sxx = sx + xy[i][0];
2396     int syy = sy + xy[i][1];
2397
2398     if (!IN_LEV_FIELD(xx, yy) ||
2399         !IN_SCR_FIELD(sxx, syy) ||
2400         !GFX_CRUMBLED(Feld[xx][yy]) ||
2401         IS_MOVING(xx, yy))
2402       continue;
2403
2404     DrawLevelField(xx, yy);
2405   }
2406 }
2407
2408 static int getBorderElement(int x, int y)
2409 {
2410   int border[7][2] =
2411   {
2412     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
2413     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
2414     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
2415     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2416     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
2417     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
2418     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
2419   };
2420   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2421   int steel_position = (x == -1         && y == -1              ? 0 :
2422                         x == lev_fieldx && y == -1              ? 1 :
2423                         x == -1         && y == lev_fieldy      ? 2 :
2424                         x == lev_fieldx && y == lev_fieldy      ? 3 :
2425                         x == -1         || x == lev_fieldx      ? 4 :
2426                         y == -1         || y == lev_fieldy      ? 5 : 6);
2427
2428   return border[steel_position][steel_type];
2429 }
2430
2431 void DrawScreenElement(int x, int y, int element)
2432 {
2433   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2434   DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2435 }
2436
2437 void DrawLevelElement(int x, int y, int element)
2438 {
2439   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2440     DrawScreenElement(SCREENX(x), SCREENY(y), element);
2441 }
2442
2443 void DrawScreenField(int x, int y)
2444 {
2445   int lx = LEVELX(x), ly = LEVELY(y);
2446   int element, content;
2447
2448   if (!IN_LEV_FIELD(lx, ly))
2449   {
2450     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2451       element = EL_EMPTY;
2452     else
2453       element = getBorderElement(lx, ly);
2454
2455     DrawScreenElement(x, y, element);
2456
2457     return;
2458   }
2459
2460   element = Feld[lx][ly];
2461   content = Store[lx][ly];
2462
2463   if (IS_MOVING(lx, ly))
2464   {
2465     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2466     boolean cut_mode = NO_CUTTING;
2467
2468     if (element == EL_QUICKSAND_EMPTYING ||
2469         element == EL_QUICKSAND_FAST_EMPTYING ||
2470         element == EL_MAGIC_WALL_EMPTYING ||
2471         element == EL_BD_MAGIC_WALL_EMPTYING ||
2472         element == EL_DC_MAGIC_WALL_EMPTYING ||
2473         element == EL_AMOEBA_DROPPING)
2474       cut_mode = CUT_ABOVE;
2475     else if (element == EL_QUICKSAND_FILLING ||
2476              element == EL_QUICKSAND_FAST_FILLING ||
2477              element == EL_MAGIC_WALL_FILLING ||
2478              element == EL_BD_MAGIC_WALL_FILLING ||
2479              element == EL_DC_MAGIC_WALL_FILLING)
2480       cut_mode = CUT_BELOW;
2481
2482 #if 0
2483     if (lx == 9 && ly == 1)
2484       printf("::: %s [%d] [%d, %d] [%d]\n",
2485              EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2486              el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2487              element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2488              element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2489              GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2490 #endif
2491
2492     if (cut_mode == CUT_ABOVE)
2493 #if 1
2494       DrawScreenElement(x, y, element);
2495 #else
2496       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2497 #endif
2498     else
2499       DrawScreenElement(x, y, EL_EMPTY);
2500
2501     if (horiz_move)
2502       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2503     else if (cut_mode == NO_CUTTING)
2504       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2505     else
2506     {
2507       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2508
2509 #if 1
2510       if (cut_mode == CUT_BELOW &&
2511           IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2512         DrawLevelElement(lx, ly + 1, element);
2513 #endif
2514     }
2515
2516     if (content == EL_ACID)
2517     {
2518       int dir = MovDir[lx][ly];
2519       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2520       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2521
2522       DrawLevelElementThruMask(newlx, newly, EL_ACID);
2523     }
2524   }
2525   else if (IS_BLOCKED(lx, ly))
2526   {
2527     int oldx, oldy;
2528     int sx, sy;
2529     int horiz_move;
2530     boolean cut_mode = NO_CUTTING;
2531     int element_old, content_old;
2532
2533     Blocked2Moving(lx, ly, &oldx, &oldy);
2534     sx = SCREENX(oldx);
2535     sy = SCREENY(oldy);
2536     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2537                   MovDir[oldx][oldy] == MV_RIGHT);
2538
2539     element_old = Feld[oldx][oldy];
2540     content_old = Store[oldx][oldy];
2541
2542     if (element_old == EL_QUICKSAND_EMPTYING ||
2543         element_old == EL_QUICKSAND_FAST_EMPTYING ||
2544         element_old == EL_MAGIC_WALL_EMPTYING ||
2545         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2546         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2547         element_old == EL_AMOEBA_DROPPING)
2548       cut_mode = CUT_ABOVE;
2549
2550     DrawScreenElement(x, y, EL_EMPTY);
2551
2552     if (horiz_move)
2553       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2554                                NO_CUTTING);
2555     else if (cut_mode == NO_CUTTING)
2556       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2557                                cut_mode);
2558     else
2559       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2560                                cut_mode);
2561   }
2562   else if (IS_DRAWABLE(element))
2563     DrawScreenElement(x, y, element);
2564   else
2565     DrawScreenElement(x, y, EL_EMPTY);
2566 }
2567
2568 void DrawLevelField(int x, int y)
2569 {
2570   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2571     DrawScreenField(SCREENX(x), SCREENY(y));
2572   else if (IS_MOVING(x, y))
2573   {
2574     int newx,newy;
2575
2576     Moving2Blocked(x, y, &newx, &newy);
2577     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2578       DrawScreenField(SCREENX(newx), SCREENY(newy));
2579   }
2580   else if (IS_BLOCKED(x, y))
2581   {
2582     int oldx, oldy;
2583
2584     Blocked2Moving(x, y, &oldx, &oldy);
2585     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2586       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2587   }
2588 }
2589
2590 void DrawMiniElement(int x, int y, int element)
2591 {
2592   int graphic;
2593
2594   graphic = el2edimg(element);
2595   DrawMiniGraphic(x, y, graphic);
2596 }
2597
2598 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2599 {
2600   int x = sx + scroll_x, y = sy + scroll_y;
2601
2602   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2603     DrawMiniElement(sx, sy, EL_EMPTY);
2604   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2605     DrawMiniElement(sx, sy, Feld[x][y]);
2606   else
2607     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2608 }
2609
2610 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2611                                  int x, int y, int xsize, int ysize,
2612                                  int tile_width, int tile_height)
2613 {
2614   Bitmap *src_bitmap;
2615   int src_x, src_y;
2616   int dst_x = startx + x * tile_width;
2617   int dst_y = starty + y * tile_height;
2618   int width  = graphic_info[graphic].width;
2619   int height = graphic_info[graphic].height;
2620   int inner_width_raw  = MAX(width  - 2 * tile_width,  tile_width);
2621   int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2622   int inner_width  = inner_width_raw  - (inner_width_raw  % tile_width);
2623   int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2624   int inner_sx = (width  >= 3 * tile_width  ? tile_width  : 0);
2625   int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2626   boolean draw_masked = graphic_info[graphic].draw_masked;
2627
2628   getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2629
2630   if (src_bitmap == NULL || width < tile_width || height < tile_height)
2631   {
2632     ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2633     return;
2634   }
2635
2636   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - tile_width  :
2637             inner_sx + (x - 1) * tile_width  % inner_width);
2638   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2639             inner_sy + (y - 1) * tile_height % inner_height);
2640
2641   if (draw_masked)
2642   {
2643     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2644                   dst_x - src_x, dst_y - src_y);
2645     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2646                      dst_x, dst_y);
2647   }
2648   else
2649     BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2650                dst_x, dst_y);
2651 }
2652
2653 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2654                             int x, int y, int xsize, int ysize, int font_nr)
2655 {
2656   int font_width  = getFontWidth(font_nr);
2657   int font_height = getFontHeight(font_nr);
2658
2659   DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2660                               font_width, font_height);
2661 }
2662
2663 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2664 {
2665   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2666   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2667   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2668   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2669   boolean no_delay = (tape.warp_forward);
2670   unsigned int anim_delay = 0;
2671   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2672   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2673   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2674   int font_width = getFontWidth(font_nr);
2675   int font_height = getFontHeight(font_nr);
2676   int max_xsize = level.envelope[envelope_nr].xsize;
2677   int max_ysize = level.envelope[envelope_nr].ysize;
2678   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2679   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2680   int xend = max_xsize;
2681   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2682   int xstep = (xstart < xend ? 1 : 0);
2683   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2684   int x, y;
2685
2686   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2687   {
2688     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2689     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2690     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
2691     int sy = SY + (SYSIZE - ysize * font_height) / 2;
2692     int xx, yy;
2693
2694     SetDrawtoField(DRAW_BUFFERED);
2695
2696 #if 1
2697     BlitScreenToBitmap(backbuffer);
2698 #else
2699     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2700 #endif
2701
2702     SetDrawtoField(DRAW_BACKBUFFER);
2703
2704     for (yy = 0; yy < ysize; yy++)
2705       for (xx = 0; xx < xsize; xx++)
2706         DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2707
2708 #if 1
2709     DrawTextBuffer(sx + font_width, sy + font_height,
2710                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2711                    xsize - 2, ysize - 2, 0, mask_mode,
2712                    level.envelope[envelope_nr].autowrap,
2713                    level.envelope[envelope_nr].centered, FALSE);
2714 #else
2715     DrawTextToTextArea(sx + font_width, sy + font_height,
2716                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2717                        xsize - 2, ysize - 2, mask_mode);
2718 #endif
2719
2720     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2721     BackToFront();
2722
2723     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2724   }
2725 }
2726
2727 void ShowEnvelope(int envelope_nr)
2728 {
2729   int element = EL_ENVELOPE_1 + envelope_nr;
2730   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2731   int sound_opening = element_info[element].sound[ACTION_OPENING];
2732   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2733   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2734   boolean no_delay = (tape.warp_forward);
2735   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2736   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2737   int anim_mode = graphic_info[graphic].anim_mode;
2738   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2739                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2740
2741   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2742
2743   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2744
2745   if (anim_mode == ANIM_DEFAULT)
2746     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2747
2748   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2749
2750   if (tape.playing)
2751     Delay(wait_delay_value);
2752   else
2753     WaitForEventToContinue();
2754
2755   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2756
2757   if (anim_mode != ANIM_NONE)
2758     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2759
2760   if (anim_mode == ANIM_DEFAULT)
2761     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2762
2763   game.envelope_active = FALSE;
2764
2765   SetDrawtoField(DRAW_BUFFERED);
2766
2767   redraw_mask |= REDRAW_FIELD;
2768   BackToFront();
2769 }
2770
2771 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2772 {
2773   int border_size = request.border_size;
2774   int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2775   int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2776   int sx = sx_center - request.width  / 2;
2777   int sy = sy_center - request.height / 2;
2778
2779   if (add_border_size)
2780   {
2781     sx += border_size;
2782     sy += border_size;
2783   }
2784
2785   *x = sx;
2786   *y = sy;
2787 }
2788
2789 void DrawEnvelopeRequest(char *text)
2790 {
2791   char *text_final = text;
2792   char *text_door_style = NULL;
2793   int graphic = IMG_BACKGROUND_REQUEST;
2794   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2795   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2796   int font_nr = FONT_REQUEST;
2797   int font_width = getFontWidth(font_nr);
2798   int font_height = getFontHeight(font_nr);
2799   int border_size = request.border_size;
2800   int line_spacing = request.line_spacing;
2801   int line_height = font_height + line_spacing;
2802   int text_width = request.width - 2 * border_size;
2803   int text_height = request.height - 2 * border_size;
2804   int line_length = text_width / font_width;
2805   int max_lines = text_height / line_height;
2806   int width = request.width;
2807   int height = request.height;
2808   int tile_size = request.step_offset;
2809   int x_steps = width  / tile_size;
2810   int y_steps = height / tile_size;
2811   int sx, sy;
2812   int i, x, y;
2813
2814   if (request.wrap_single_words)
2815   {
2816     char *src_text_ptr, *dst_text_ptr;
2817
2818     text_door_style = checked_malloc(2 * strlen(text) + 1);
2819
2820     src_text_ptr = text;
2821     dst_text_ptr = text_door_style;
2822
2823     while (*src_text_ptr)
2824     {
2825       if (*src_text_ptr == ' ' ||
2826           *src_text_ptr == '?' ||
2827           *src_text_ptr == '!')
2828         *dst_text_ptr++ = '\n';
2829
2830       if (*src_text_ptr != ' ')
2831         *dst_text_ptr++ = *src_text_ptr;
2832
2833       src_text_ptr++;
2834     }
2835
2836     *dst_text_ptr = '\0';
2837
2838     text_final = text_door_style;
2839   }
2840
2841   setRequestPosition(&sx, &sy, FALSE);
2842
2843   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2844
2845   for (y = 0; y < y_steps; y++)
2846     for (x = 0; x < x_steps; x++)
2847       DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2848                                   x, y, x_steps, y_steps,
2849                                   tile_size, tile_size);
2850
2851   DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2852                  line_length, -1, max_lines, line_spacing, mask_mode,
2853                  request.autowrap, request.centered, FALSE);
2854
2855   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2856     RedrawGadget(tool_gadget[i]);
2857
2858   // store readily prepared envelope request for later use when animating
2859   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2860
2861 #if 0
2862   // !!! TEST !!!
2863   BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2864   BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2865
2866   redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2867   BackToFront();
2868
2869   Delay(3000);
2870
2871   BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2872
2873   redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2874   BackToFront();
2875
2876   Delay(1000);
2877 #endif
2878
2879   if (text_door_style)
2880     free(text_door_style);
2881 }
2882
2883 #if 1
2884
2885 void AnimateEnvelopeRequest(int anim_mode, int action)
2886 {
2887   int graphic = IMG_BACKGROUND_REQUEST;
2888   boolean draw_masked = graphic_info[graphic].draw_masked;
2889 #if 1
2890   int delay_value_normal = request.step_delay;
2891   int delay_value_fast = delay_value_normal / 2;
2892 #else
2893   int delay_value_normal = GameFrameDelay;
2894   int delay_value_fast = FfwdFrameDelay;
2895 #endif
2896   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2897   boolean no_delay = (tape.warp_forward);
2898   int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2899   int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2900   unsigned int anim_delay = 0;
2901
2902   int width = request.width;
2903   int height = request.height;
2904   int tile_size = request.step_offset;
2905   int max_xsize = width  / tile_size;
2906   int max_ysize = height / tile_size;
2907   int max_xsize_inner = max_xsize - 2;
2908   int max_ysize_inner = max_ysize - 2;
2909
2910   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2911   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2912   int xend = max_xsize_inner;
2913   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2914   int xstep = (xstart < xend ? 1 : 0);
2915   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2916   int x, y;
2917
2918   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2919   {
2920     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2921     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2922     int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2923     int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2924     int src_x = sx_center - width  / 2;
2925     int src_y = sy_center - height / 2;
2926     int dst_x = sx_center - xsize * tile_size / 2;
2927     int dst_y = sy_center - ysize * tile_size / 2;
2928     int xsize_size_left = (xsize - 1) * tile_size;
2929     int ysize_size_top  = (ysize - 1) * tile_size;
2930     int max_xsize_pos = (max_xsize - 1) * tile_size;
2931     int max_ysize_pos = (max_ysize - 1) * tile_size;
2932     int xx, yy;
2933
2934     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2935
2936 #if 1
2937     for (yy = 0; yy < 2; yy++)
2938     {
2939       for (xx = 0; xx < 2; xx++)
2940       {
2941         int src_xx = src_x + xx * max_xsize_pos;
2942         int src_yy = src_y + yy * max_ysize_pos;
2943         int dst_xx = dst_x + xx * xsize_size_left;
2944         int dst_yy = dst_y + yy * ysize_size_top;
2945         int xx_size = (xx ? tile_size : xsize_size_left);
2946         int yy_size = (yy ? tile_size : ysize_size_top);
2947
2948         if (draw_masked)
2949           BlitBitmapMasked(bitmap_db_cross, backbuffer,
2950                            src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2951         else
2952           BlitBitmap(bitmap_db_cross, backbuffer,
2953                      src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2954       }
2955     }
2956 #else
2957     BlitBitmap(bitmap_db_cross, backbuffer,
2958                src_x, src_y,
2959                xsize_size_left, ysize_size_top,
2960                dst_x, dst_y);
2961     BlitBitmap(bitmap_db_cross, backbuffer,
2962                src_x + max_xsize_pos, src_y,
2963                tile_size, ysize_size_top,
2964                dst_x + xsize_size_left, dst_y);
2965     BlitBitmap(bitmap_db_cross, backbuffer,
2966                src_x, src_y + max_ysize_pos,
2967                xsize_size_left, tile_size,
2968                dst_x, dst_y + ysize_size_top);
2969     BlitBitmap(bitmap_db_cross, backbuffer,
2970                src_x + max_xsize_pos, src_y + max_ysize_pos,
2971                tile_size, tile_size,
2972                dst_x + xsize_size_left, dst_y + ysize_size_top);
2973 #endif
2974
2975 #if 1
2976     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2977     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2978 #else
2979     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2980 #endif
2981
2982 #if 1
2983     DoAnimation();
2984     BackToFront();
2985 #else
2986     BackToFront();
2987 #endif
2988
2989     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2990   }
2991 }
2992
2993 #else
2994
2995 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2996 {
2997 #if 0
2998   int envelope_nr = 0;
2999 #endif
3000 #if 1
3001   int graphic = IMG_BACKGROUND_REQUEST;
3002 #else
3003   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3004 #endif
3005   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3006   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3007   boolean ffwd_delay = (tape.playing && tape.fast_forward);
3008   boolean no_delay = (tape.warp_forward);
3009   unsigned int anim_delay = 0;
3010   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3011   int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3012 #if 1
3013   int max_word_len = maxWordLengthInString(text);
3014   int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3015 #else
3016   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3017 #endif
3018   int font_width = getFontWidth(font_nr);
3019   int font_height = getFontHeight(font_nr);
3020   int line_spacing = 2 * 1;
3021 #if 1
3022
3023 #if 1
3024   int max_xsize = DXSIZE / font_width;
3025   // int max_ysize = DYSIZE / font_height;
3026   int max_ysize = DYSIZE / (font_height + line_spacing);
3027 #else
3028   int max_xsize = 7;    /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3029   int max_ysize = 13;   /* tools.c: MAX_REQUEST_LINES == 13 */
3030 #endif
3031
3032 #else
3033   int max_xsize = level.envelope[envelope_nr].xsize;
3034   int max_ysize = level.envelope[envelope_nr].ysize;
3035 #endif
3036   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3037   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3038   int xend = max_xsize;
3039   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3040   int xstep = (xstart < xend ? 1 : 0);
3041   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3042   int x, y;
3043
3044 #if 1
3045   char *text_ptr;
3046   char *text_copy = getStringCopy(text);
3047 #else
3048 #if 1
3049   font_nr = FONT_TEXT_2;
3050
3051   if (maxWordLengthInString(text) > 7)  /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3052   {
3053     max_xsize = 10;     /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3054     font_nr = FONT_TEXT_1;
3055   }
3056 #else
3057   int max_word_len = 0;
3058   char *text_ptr;
3059   char *text_copy = getStringCopy(text);
3060
3061   font_nr = FONT_TEXT_2;
3062
3063   for (text_ptr = text; *text_ptr; text_ptr++)
3064   {
3065     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3066
3067     if (max_word_len > 7)       /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3068     {
3069       max_xsize = 10;   /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3070       font_nr = FONT_TEXT_1;
3071
3072       break;
3073     }
3074   }
3075 #endif
3076 #endif
3077
3078 #if 1
3079   for (text_ptr = text_copy; *text_ptr; text_ptr++)
3080     if (*text_ptr == ' ')
3081       *text_ptr = '\n';
3082 #endif
3083
3084 #if 1
3085   dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3086   dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3087 #else
3088   dDX = SX + SXSIZE / 2 - max_xsize * font_width  / 2 - DX;
3089   dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3090 #endif
3091
3092   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3093   {
3094     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3095     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3096     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
3097     // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3098     int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3099     int xx, yy;
3100
3101 #if 1
3102     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3103 #else
3104     SetDrawtoField(DRAW_BUFFERED);
3105
3106 #if 1
3107     BlitScreenToBitmap(backbuffer);
3108 #else
3109     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3110 #endif
3111
3112     SetDrawtoField(DRAW_BACKBUFFER);
3113 #endif
3114
3115     for (yy = 0; yy < ysize; yy++)
3116       for (xx = 0; xx < xsize; xx++)
3117         DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3118                                     getFontWidth(font_nr),
3119                                     getFontHeight(font_nr) + line_spacing);
3120
3121 #if 1
3122
3123 #if 1
3124     DrawTextBuffer(sx + font_width, sy + font_height + 8,
3125                    text_copy, font_nr, max_xsize,
3126                    xsize - 2, ysize - 2, line_spacing, mask_mode,
3127                    FALSE, TRUE, FALSE);
3128 #else
3129     DrawTextBuffer(sx + font_width, sy + font_height,
3130                    level.envelope[envelope_nr].text, font_nr, max_xsize,
3131                    xsize - 2, ysize - 2, 0, mask_mode,
3132                    level.envelope[envelope_nr].autowrap,
3133                    level.envelope[envelope_nr].centered, FALSE);
3134 #endif
3135
3136 #else
3137     DrawTextToTextArea(sx + font_width, sy + font_height,
3138                        level.envelope[envelope_nr].text, font_nr, max_xsize,
3139                        xsize - 2, ysize - 2, mask_mode);
3140 #endif
3141
3142     /* copy request gadgets to door backbuffer */
3143 #if 1
3144     /*
3145     if ((ysize - 2) > 13)
3146       BlitBitmap(bitmap_db_door, drawto,
3147                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3148                  DOOR_GFX_PAGEY1 + 13 * font_height,
3149                  (xsize - 2) * font_width,
3150                  (ysize - 2 - 13) * font_height,
3151                  sx + font_width,
3152                  sy + font_height * (1 + 13));
3153     */
3154     if ((ysize - 2) > 13)
3155       BlitBitmap(bitmap_db_door, drawto,
3156                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3157                  DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3158                  (xsize - 2) * font_width,
3159                  (ysize - 2 - 13) * (font_height + line_spacing),
3160                  sx + font_width,
3161                  sy + (font_height + line_spacing) * (1 + 13));
3162 #else
3163     if ((ysize - 2) > 13)
3164       BlitBitmap(bitmap_db_door, drawto,
3165                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3166                  DOOR_GFX_PAGEY1 + 13 * font_height,
3167                  (xsize - 2) * font_width,
3168                  (ysize - 2 - 13) * font_height,
3169                  sx + font_width,
3170                  sy + font_height * (1 + 13));
3171 #endif
3172
3173 #if 1
3174     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3175     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3176 #else
3177     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3178 #endif
3179
3180 #if 1
3181     DoAnimation();
3182     BackToFront();
3183 #else
3184     BackToFront();
3185 #endif
3186
3187     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3188   }
3189
3190 #if 1
3191   free(text_copy);
3192 #endif
3193 }
3194
3195 #endif
3196
3197 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3198 {
3199 #if 1
3200   int last_game_status = game_status;   /* save current game status */
3201   // int last_draw_background_mask = gfx.draw_background_mask;
3202 #endif
3203 #if 1
3204   int graphic = IMG_BACKGROUND_REQUEST;
3205   int sound_opening = SND_REQUEST_OPENING;
3206   int sound_closing = SND_REQUEST_CLOSING;
3207 #else
3208   int envelope_nr = 0;
3209   int element = EL_ENVELOPE_1 + envelope_nr;
3210   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3211   int sound_opening = element_info[element].sound[ACTION_OPENING];
3212   int sound_closing = element_info[element].sound[ACTION_CLOSING];
3213 #endif
3214 #if 0
3215   boolean ffwd_delay = (tape.playing && tape.fast_forward);
3216   boolean no_delay = (tape.warp_forward);
3217   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3218   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3219 #endif
3220   int anim_mode = graphic_info[graphic].anim_mode;
3221   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3222                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3223 #if 0
3224   char *text_copy = getStringCopy(text);
3225   char *text_ptr;
3226
3227   for (text_ptr = text_copy; *text_ptr; text_ptr++)
3228     if (*text_ptr == ' ')
3229       *text_ptr = '\n';
3230 #endif
3231
3232 #if 1
3233   if (game_status == GAME_MODE_PLAYING)
3234   {
3235     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3236       BlitScreenToBitmap_EM(backbuffer);
3237     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3238       BlitScreenToBitmap_SP(backbuffer);
3239     else
3240     {
3241       BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3242     }
3243   }
3244
3245   SetDrawtoField(DRAW_BACKBUFFER);
3246
3247   // SetDrawBackgroundMask(REDRAW_NONE);
3248
3249   if (action == ACTION_OPENING)
3250   {
3251     BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3252
3253 #if 1
3254   if (req_state & REQ_ASK)
3255   {
3256     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3257     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3258   }
3259   else if (req_state & REQ_CONFIRM)
3260   {
3261     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3262   }
3263   else if (req_state & REQ_PLAYER)
3264   {
3265     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3266     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3267     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3268     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3269   }
3270 #endif
3271
3272 #if 1
3273     DrawEnvelopeRequest(text);
3274 #else
3275     DrawEnvelopeRequest(text_copy);
3276 #endif
3277
3278     if (game_status != GAME_MODE_MAIN)
3279       InitAnimation();
3280   }
3281
3282   /* force DOOR font inside door area */
3283   game_status = GAME_MODE_PSEUDO_DOOR;
3284 #endif
3285
3286   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
3287
3288   if (action == ACTION_OPENING)
3289   {
3290     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3291
3292     if (anim_mode == ANIM_DEFAULT)
3293       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3294
3295     AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3296
3297 #if 0
3298     if (tape.playing)
3299       Delay(wait_delay_value);
3300     else
3301       WaitForEventToContinue();
3302 #endif
3303   }
3304   else
3305   {
3306     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3307
3308     if (anim_mode != ANIM_NONE)
3309       AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3310
3311     if (anim_mode == ANIM_DEFAULT)
3312       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3313   }
3314
3315   game.envelope_active = FALSE;
3316
3317 #if 1
3318   // game_status = last_game_status;    /* restore current game status */
3319
3320   if (action == ACTION_CLOSING)
3321   {
3322     if (game_status != GAME_MODE_MAIN)
3323       StopAnimation();
3324
3325     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3326   }
3327 #else
3328   SetDrawtoField(DRAW_BUFFERED);
3329 #endif
3330
3331   // SetDrawBackgroundMask(last_draw_background_mask);
3332
3333 #if 1
3334   redraw_mask = REDRAW_FIELD;
3335   // redraw_mask |= REDRAW_ALL;
3336 #else
3337   redraw_mask |= REDRAW_FIELD;
3338 #endif
3339
3340 #if 1
3341   if (game_status == GAME_MODE_MAIN)
3342     DoAnimation();
3343
3344   BackToFront();
3345
3346   /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3347   game_status = last_game_status;       /* restore current game status */
3348
3349 #if 1
3350   if (action == ACTION_CLOSING &&
3351       game_status == GAME_MODE_PLAYING &&
3352       level.game_engine_type == GAME_ENGINE_TYPE_RND)
3353     SetDrawtoField(DRAW_BUFFERED);
3354 #else
3355   if (game_status == GAME_MODE_PLAYING &&
3356       level.game_engine_type == GAME_ENGINE_TYPE_RND)
3357     SetDrawtoField(DRAW_BUFFERED);
3358 #endif
3359
3360 #else
3361   BackToFront();
3362 #endif
3363
3364 #if 0
3365   free(text_copy);
3366 #endif
3367 }
3368
3369 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3370 {
3371   Bitmap *src_bitmap;
3372   int src_x, src_y;
3373   int graphic = el2preimg(element);
3374
3375   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3376   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3377 }
3378
3379 void DrawLevel()
3380 {
3381   int x,y;
3382
3383 #if 1
3384   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3385   SetDrawBackgroundMask(REDRAW_FIELD);
3386 #else
3387   SetDrawBackgroundMask(REDRAW_NONE);
3388 #endif
3389
3390   ClearField();
3391
3392   for (x = BX1; x <= BX2; x++)
3393     for (y = BY1; y <= BY2; y++)
3394       DrawScreenField(x, y);
3395
3396   redraw_mask |= REDRAW_FIELD;
3397 }
3398
3399 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3400 {
3401   int x,y;
3402
3403   for (x = 0; x < size_x; x++)
3404     for (y = 0; y < size_y; y++)
3405       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3406
3407   redraw_mask |= REDRAW_FIELD;
3408 }
3409
3410 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3411 {
3412   boolean show_level_border = (BorderElement != EL_EMPTY);
3413   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3414   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3415   int tile_size = preview.tile_size;
3416   int preview_width  = preview.xsize * tile_size;
3417   int preview_height = preview.ysize * tile_size;
3418   int real_preview_xsize = MIN(level_xsize, preview.xsize);
3419   int real_preview_ysize = MIN(level_ysize, preview.ysize);
3420   int real_preview_width  = real_preview_xsize * tile_size;
3421   int real_preview_height = real_preview_ysize * tile_size;
3422   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3423   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3424   int x, y;
3425
3426 #if 1
3427   if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3428     return;
3429 #endif
3430
3431 #if 0
3432   dst_x += (preview_width  - real_preview_width)  / 2;
3433   dst_y += (preview_height - real_preview_height) / 2;
3434
3435   DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3436 #else
3437   DrawBackground(dst_x, dst_y, preview_width, preview_height);
3438
3439   dst_x += (preview_width  - real_preview_width)  / 2;
3440   dst_y += (preview_height - real_preview_height) / 2;
3441 #endif
3442
3443   for (x = 0; x < real_preview_xsize; x++)
3444   {
3445     for (y = 0; y < real_preview_ysize; y++)
3446     {
3447       int lx = from_x + x + (show_level_border ? -1 : 0);
3448       int ly = from_y + y + (show_level_border ? -1 : 0);
3449       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3450                      getBorderElement(lx, ly));
3451
3452       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3453                          element, tile_size);
3454     }
3455   }
3456
3457   redraw_mask |= REDRAW_MICROLEVEL;
3458 }
3459
3460 #define MICROLABEL_EMPTY                0
3461 #define MICROLABEL_LEVEL_NAME           1
3462 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
3463 #define MICROLABEL_LEVEL_AUTHOR         3
3464 #define MICROLABEL_IMPORTED_FROM_HEAD   4
3465 #define MICROLABEL_IMPORTED_FROM        5
3466 #define MICROLABEL_IMPORTED_BY_HEAD     6
3467 #define MICROLABEL_IMPORTED_BY          7
3468
3469 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3470 {
3471   int max_text_width = SXSIZE;
3472   int font_width = getFontWidth(font_nr);
3473
3474   if (pos->align == ALIGN_CENTER)
3475     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3476   else if (pos->align == ALIGN_RIGHT)
3477     max_text_width = pos->x;
3478   else
3479     max_text_width = SXSIZE - pos->x;
3480
3481   return max_text_width / font_width;
3482 }
3483
3484 static void DrawPreviewLevelLabelExt(int mode)
3485 {
3486   struct TextPosInfo *pos = &menu.main.text.level_info_2;
3487   char label_text[MAX_OUTPUT_LINESIZE + 1];
3488   int max_len_label_text;
3489 #if 1
3490   int font_nr = pos->font;
3491   int i;
3492
3493   if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3494     return;
3495
3496   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3497       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3498       mode == MICROLABEL_IMPORTED_BY_HEAD)
3499     font_nr = pos->font_alt;
3500 #else
3501   int font_nr = FONT_TEXT_2;
3502   int i;
3503
3504   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3505       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3506       mode == MICROLABEL_IMPORTED_BY_HEAD)
3507     font_nr = FONT_TEXT_3;
3508 #endif
3509
3510 #if 1
3511   max_len_label_text = getMaxTextLength(pos, font_nr);
3512 #else
3513   max_len_label_text = SXSIZE / getFontWidth(font_nr);
3514 #endif
3515
3516 #if 1
3517   if (pos->size != -1)
3518     max_len_label_text = pos->size;
3519 #endif
3520
3521   for (i = 0; i < max_len_label_text; i++)
3522     label_text[i] = ' ';
3523   label_text[max_len_label_text] = '\0';
3524
3525   if (strlen(label_text) > 0)
3526   {
3527 #if 1
3528     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3529 #else
3530     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3531     int lypos = MICROLABEL2_YPOS;
3532
3533     DrawText(lxpos, lypos, label_text, font_nr);
3534 #endif
3535   }
3536
3537   strncpy(label_text,
3538           (mode == MICROLABEL_LEVEL_NAME ? level.name :
3539            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3540            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3541            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3542            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3543            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3544            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3545           max_len_label_text);
3546   label_text[max_len_label_text] = '\0';
3547
3548   if (strlen(label_text) > 0)
3549   {
3550 #if 1
3551     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3552 #else
3553     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3554     int lypos = MICROLABEL2_YPOS;
3555
3556     DrawText(lxpos, lypos, label_text, font_nr);
3557 #endif
3558   }
3559
3560   redraw_mask |= REDRAW_MICROLEVEL;
3561 }
3562
3563 static void DrawPreviewLevelExt(boolean restart)
3564 {
3565   static unsigned int scroll_delay = 0;
3566   static unsigned int label_delay = 0;
3567   static int from_x, from_y, scroll_direction;
3568   static int label_state, label_counter;
3569   unsigned int scroll_delay_value = preview.step_delay;
3570   boolean show_level_border = (BorderElement != EL_EMPTY);
3571   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3572   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3573   int last_game_status = game_status;           /* save current game status */
3574
3575 #if 0
3576   /* force PREVIEW font on preview level */
3577   game_status = GAME_MODE_PSEUDO_PREVIEW;
3578 #endif
3579
3580   if (restart)
3581   {
3582     from_x = 0;
3583     from_y = 0;
3584
3585     if (preview.anim_mode == ANIM_CENTERED)
3586     {
3587       if (level_xsize > preview.xsize)
3588         from_x = (level_xsize - preview.xsize) / 2;
3589       if (level_ysize > preview.ysize)
3590         from_y = (level_ysize - preview.ysize) / 2;
3591     }
3592
3593     from_x += preview.xoffset;
3594     from_y += preview.yoffset;
3595
3596     scroll_direction = MV_RIGHT;
3597     label_state = 1;
3598     label_counter = 0;
3599
3600     DrawPreviewLevelPlayfieldExt(from_x, from_y);
3601     DrawPreviewLevelLabelExt(label_state);
3602
3603     /* initialize delay counters */
3604     DelayReached(&scroll_delay, 0);
3605     DelayReached(&label_delay, 0);
3606
3607     if (leveldir_current->name)
3608     {
3609       struct TextPosInfo *pos = &menu.main.text.level_info_1;
3610       char label_text[MAX_OUTPUT_LINESIZE + 1];
3611 #if 1
3612       int font_nr = pos->font;
3613 #else
3614       int font_nr = FONT_TEXT_1;
3615 #endif
3616 #if 1
3617       int max_len_label_text = getMaxTextLength(pos, font_nr);
3618 #else
3619       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3620 #endif
3621 #if 0
3622       int text_width;
3623       int lxpos, lypos;
3624 #endif
3625
3626 #if 1
3627       if (pos->size != -1)
3628         max_len_label_text = pos->size;
3629 #endif
3630
3631       strncpy(label_text, leveldir_current->name, max_len_label_text);
3632       label_text[max_len_label_text] = '\0';
3633
3634 #if 1
3635       if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3636         DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3637 #else
3638       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3639       lypos = SY + MICROLABEL1_YPOS;
3640
3641       DrawText(lxpos, lypos, label_text, font_nr);
3642 #endif
3643     }
3644
3645     game_status = last_game_status;     /* restore current game status */
3646
3647     return;
3648   }
3649
3650   /* scroll preview level, if needed */
3651   if (preview.anim_mode != ANIM_NONE &&
3652       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3653       DelayReached(&scroll_delay, scroll_delay_value))
3654   {
3655     switch (scroll_direction)
3656     {
3657       case MV_LEFT:
3658         if (from_x > 0)
3659         {
3660           from_x -= preview.step_offset;
3661           from_x = (from_x < 0 ? 0 : from_x);
3662         }
3663         else
3664           scroll_direction = MV_UP;
3665         break;
3666
3667       case MV_RIGHT:
3668         if (from_x < level_xsize - preview.xsize)
3669         {
3670           from_x += preview.step_offset;
3671           from_x = (from_x > level_xsize - preview.xsize ?
3672                     level_xsize - preview.xsize : from_x);
3673         }
3674         else
3675           scroll_direction = MV_DOWN;
3676         break;
3677
3678       case MV_UP:
3679         if (from_y > 0)
3680         {
3681           from_y -= preview.step_offset;
3682           from_y = (from_y < 0 ? 0 : from_y);
3683         }
3684         else
3685           scroll_direction = MV_RIGHT;
3686         break;
3687
3688       case MV_DOWN:
3689         if (from_y < level_ysize - preview.ysize)
3690         {
3691           from_y += preview.step_offset;
3692           from_y = (from_y > level_ysize - preview.ysize ?
3693                     level_ysize - preview.ysize : from_y);
3694         }
3695         else
3696           scroll_direction = MV_LEFT;
3697         break;
3698
3699       default:
3700         break;
3701     }
3702
3703     DrawPreviewLevelPlayfieldExt(from_x, from_y);
3704   }
3705
3706   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3707   /* redraw micro level label, if needed */
3708   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3709       !strEqual(level.author, ANONYMOUS_NAME) &&
3710       !strEqual(level.author, leveldir_current->name) &&
3711       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3712   {
3713     int max_label_counter = 23;
3714
3715     if (leveldir_current->imported_from != NULL &&
3716         strlen(leveldir_current->imported_from) > 0)
3717       max_label_counter += 14;
3718     if (leveldir_current->imported_by != NULL &&
3719         strlen(leveldir_current->imported_by) > 0)
3720       max_label_counter += 14;
3721
3722     label_counter = (label_counter + 1) % max_label_counter;
3723     label_state = (label_counter >= 0 && label_counter <= 7 ?
3724                    MICROLABEL_LEVEL_NAME :
3725                    label_counter >= 9 && label_counter <= 12 ?
3726                    MICROLABEL_LEVEL_AUTHOR_HEAD :
3727                    label_counter >= 14 && label_counter <= 21 ?
3728                    MICROLABEL_LEVEL_AUTHOR :
3729                    label_counter >= 23 && label_counter <= 26 ?
3730                    MICROLABEL_IMPORTED_FROM_HEAD :
3731                    label_counter >= 28 && label_counter <= 35 ?
3732                    MICROLABEL_IMPORTED_FROM :
3733                    label_counter >= 37 && label_counter <= 40 ?
3734                    MICROLABEL_IMPORTED_BY_HEAD :
3735                    label_counter >= 42 && label_counter <= 49 ?
3736                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3737
3738     if (leveldir_current->imported_from == NULL &&
3739         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3740          label_state == MICROLABEL_IMPORTED_FROM))
3741       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3742                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3743
3744     DrawPreviewLevelLabelExt(label_state);
3745   }
3746
3747   game_status = last_game_status;       /* restore current game status */
3748 }
3749
3750 void DrawPreviewLevelInitial()
3751 {
3752   DrawPreviewLevelExt(TRUE);
3753 }
3754
3755 void DrawPreviewLevelAnimation()
3756 {
3757   DrawPreviewLevelExt(FALSE);
3758 }
3759
3760 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3761                                     int graphic, int sync_frame, int mask_mode)
3762 {
3763   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3764
3765   if (mask_mode == USE_MASKING)
3766     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3767   else
3768     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3769 }
3770
3771 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3772                                          int graphic, int sync_frame,
3773                                          int mask_mode)
3774 {
3775   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3776
3777   if (mask_mode == USE_MASKING)
3778     DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3779   else
3780     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3781 }
3782
3783 inline void DrawGraphicAnimation(int x, int y, int graphic)
3784 {
3785   int lx = LEVELX(x), ly = LEVELY(y);
3786
3787   if (!IN_SCR_FIELD(x, y))
3788     return;
3789
3790 #if NEW_TILESIZE
3791   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3792                           graphic, GfxFrame[lx][ly], NO_MASKING);
3793 #else
3794   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3795                           graphic, GfxFrame[lx][ly], NO_MASKING);
3796 #endif
3797   MarkTileDirty(x, y);
3798 }
3799
3800 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3801 {
3802   int lx = LEVELX(x), ly = LEVELY(y);
3803
3804   if (!IN_SCR_FIELD(x, y))
3805     return;
3806
3807   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3808                           graphic, GfxFrame[lx][ly], NO_MASKING);
3809   MarkTileDirty(x, y);
3810 }
3811
3812 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3813 {
3814   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3815 }
3816
3817 void DrawLevelElementAnimation(int x, int y, int element)
3818 {
3819   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3820
3821   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3822 }
3823
3824 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3825 {
3826   int sx = SCREENX(x), sy = SCREENY(y);
3827
3828   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3829     return;
3830
3831   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3832     return;
3833
3834   DrawGraphicAnimation(sx, sy, graphic);
3835
3836 #if 1
3837   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3838     DrawLevelFieldCrumbled(x, y);
3839 #else
3840   if (GFX_CRUMBLED(Feld[x][y]))
3841     DrawLevelFieldCrumbled(x, y);
3842 #endif
3843 }
3844
3845 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3846 {
3847   int sx = SCREENX(x), sy = SCREENY(y);
3848   int graphic;
3849
3850   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3851     return;
3852
3853   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3854
3855   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3856     return;
3857
3858   DrawGraphicAnimation(sx, sy, graphic);
3859
3860   if (GFX_CRUMBLED(element))
3861     DrawLevelFieldCrumbled(x, y);
3862 }
3863
3864 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3865 {
3866   if (player->use_murphy)
3867   {
3868     /* this works only because currently only one player can be "murphy" ... */
3869     static int last_horizontal_dir = MV_LEFT;
3870     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3871
3872     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3873       last_horizontal_dir = move_dir;
3874
3875     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
3876     {
3877       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3878
3879       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3880     }
3881
3882     return graphic;
3883   }
3884   else
3885     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3886 }
3887
3888 static boolean equalGraphics(int graphic1, int graphic2)
3889 {
3890   struct GraphicInfo *g1 = &graphic_info[graphic1];
3891   struct GraphicInfo *g2 = &graphic_info[graphic2];
3892
3893   return (g1->bitmap      == g2->bitmap &&
3894           g1->src_x       == g2->src_x &&
3895           g1->src_y       == g2->src_y &&
3896           g1->anim_frames == g2->anim_frames &&
3897           g1->anim_delay  == g2->anim_delay &&
3898           g1->anim_mode   == g2->anim_mode);
3899 }
3900
3901 void DrawAllPlayers()
3902 {
3903   int i;
3904
3905   for (i = 0; i < MAX_PLAYERS; i++)
3906     if (stored_player[i].active)
3907       DrawPlayer(&stored_player[i]);
3908 }
3909
3910 void DrawPlayerField(int x, int y)
3911 {
3912   if (!IS_PLAYER(x, y))
3913     return;
3914
3915   DrawPlayer(PLAYERINFO(x, y));
3916 }
3917
3918 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3919
3920 void DrawPlayer(struct PlayerInfo *player)
3921 {
3922   int jx = player->jx;
3923   int jy = player->jy;
3924   int move_dir = player->MovDir;
3925   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3926   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
3927   int last_jx = (player->is_moving ? jx - dx : jx);
3928   int last_jy = (player->is_moving ? jy - dy : jy);
3929   int next_jx = jx + dx;
3930   int next_jy = jy + dy;
3931   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3932   boolean player_is_opaque = FALSE;
3933   int sx = SCREENX(jx), sy = SCREENY(jy);
3934   int sxx = 0, syy = 0;
3935   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3936   int graphic;
3937   int action = ACTION_DEFAULT;
3938   int last_player_graphic = getPlayerGraphic(player, move_dir);
3939   int last_player_frame = player->Frame;
3940   int frame = 0;
3941
3942   /* GfxElement[][] is set to the element the player is digging or collecting;
3943      remove also for off-screen player if the player is not moving anymore */
3944   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3945     GfxElement[jx][jy] = EL_UNDEFINED;
3946
3947   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3948     return;
3949
3950 #if DEBUG
3951   if (!IN_LEV_FIELD(jx, jy))
3952   {
3953     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3954     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3955     printf("DrawPlayerField(): This should never happen!\n");
3956     return;
3957   }
3958 #endif
3959
3960   if (element == EL_EXPLOSION)
3961     return;
3962
3963   action = (player->is_pushing    ? ACTION_PUSHING         :
3964             player->is_digging    ? ACTION_DIGGING         :
3965             player->is_collecting ? ACTION_COLLECTING      :
3966             player->is_moving     ? ACTION_MOVING          :
3967             player->is_snapping   ? ACTION_SNAPPING        :
3968             player->is_dropping   ? ACTION_DROPPING        :
3969             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
3970
3971   if (player->is_waiting)
3972     move_dir = player->dir_waiting;
3973
3974   InitPlayerGfxAnimation(player, action, move_dir);
3975
3976   /* ----------------------------------------------------------------------- */
3977   /* draw things in the field the player is leaving, if needed               */
3978   /* ----------------------------------------------------------------------- */
3979
3980   if (player->is_moving)
3981   {
3982     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3983     {
3984       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3985
3986       if (last_element == EL_DYNAMITE_ACTIVE ||
3987           last_element == EL_EM_DYNAMITE_ACTIVE ||
3988           last_element == EL_SP_DISK_RED_ACTIVE)
3989         DrawDynamite(last_jx, last_jy);
3990       else
3991         DrawLevelFieldThruMask(last_jx, last_jy);
3992     }
3993     else if (last_element == EL_DYNAMITE_ACTIVE ||
3994              last_element == EL_EM_DYNAMITE_ACTIVE ||
3995              last_element == EL_SP_DISK_RED_ACTIVE)
3996       DrawDynamite(last_jx, last_jy);
3997 #if 0
3998     /* !!! this is not enough to prevent flickering of players which are
3999        moving next to each others without a free tile between them -- this
4000        can only be solved by drawing all players layer by layer (first the
4001        background, then the foreground etc.) !!! => TODO */
4002     else if (!IS_PLAYER(last_jx, last_jy))
4003       DrawLevelField(last_jx, last_jy);
4004 #else
4005     else
4006       DrawLevelField(last_jx, last_jy);
4007 #endif
4008
4009     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4010       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4011   }
4012
4013   if (!IN_SCR_FIELD(sx, sy))
4014     return;
4015
4016   /* ----------------------------------------------------------------------- */
4017   /* draw things behind the player, if needed                                */
4018   /* ----------------------------------------------------------------------- */
4019
4020   if (Back[jx][jy])
4021     DrawLevelElement(jx, jy, Back[jx][jy]);
4022   else if (IS_ACTIVE_BOMB(element))
4023     DrawLevelElement(jx, jy, EL_EMPTY);
4024   else
4025   {
4026     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4027     {
4028       int old_element = GfxElement[jx][jy];
4029       int old_graphic = el_act_dir2img(old_element, action, move_dir);
4030       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4031
4032       if (GFX_CRUMBLED(old_element))
4033         DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4034       else
4035         DrawGraphic(sx, sy, old_graphic, frame);
4036
4037       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4038         player_is_opaque = TRUE;
4039     }
4040     else
4041     {
4042       GfxElement[jx][jy] = EL_UNDEFINED;
4043
4044       /* make sure that pushed elements are drawn with correct frame rate */
4045 #if 1
4046       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4047
4048       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4049         GfxFrame[jx][jy] = player->StepFrame;
4050 #else
4051       if (player->is_pushing && player->is_moving)
4052         GfxFrame[jx][jy] = player->StepFrame;
4053 #endif
4054
4055       DrawLevelField(jx, jy);
4056     }
4057   }
4058
4059 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4060   /* ----------------------------------------------------------------------- */
4061   /* draw player himself                                                     */
4062   /* ----------------------------------------------------------------------- */
4063
4064   graphic = getPlayerGraphic(player, move_dir);
4065
4066   /* in the case of changed player action or direction, prevent the current
4067      animation frame from being restarted for identical animations */
4068   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4069     player->Frame = last_player_frame;
4070
4071   frame = getGraphicAnimationFrame(graphic, player->Frame);
4072
4073   if (player->GfxPos)
4074   {
4075     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4076       sxx = player->GfxPos;
4077     else
4078       syy = player->GfxPos;
4079   }
4080
4081   if (!setup.soft_scrolling && ScreenMovPos)
4082     sxx = syy = 0;
4083
4084   if (player_is_opaque)
4085     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4086   else
4087     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4088
4089   if (SHIELD_ON(player))
4090   {
4091     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4092                    IMG_SHIELD_NORMAL_ACTIVE);
4093     int frame = getGraphicAnimationFrame(graphic, -1);
4094
4095     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4096   }
4097 #endif
4098
4099 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4100   if (player->GfxPos)
4101   {
4102     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4103       sxx = player->GfxPos;
4104     else
4105       syy = player->GfxPos;
4106   }
4107 #endif
4108
4109   /* ----------------------------------------------------------------------- */
4110   /* draw things the player is pushing, if needed                            */
4111   /* ----------------------------------------------------------------------- */
4112
4113 #if 0
4114   printf("::: %d, %d [%d, %d] [%d]\n",
4115          player->is_pushing, player_is_moving, player->GfxAction,
4116          player->is_moving, player_is_moving);
4117 #endif
4118
4119 #if 1
4120   if (player->is_pushing && player->is_moving)
4121   {
4122     int px = SCREENX(jx), py = SCREENY(jy);
4123     int pxx = (TILEX - ABS(sxx)) * dx;
4124     int pyy = (TILEY - ABS(syy)) * dy;
4125     int gfx_frame = GfxFrame[jx][jy];
4126
4127     int graphic;
4128     int sync_frame;
4129     int frame;
4130
4131     if (!IS_MOVING(jx, jy))             /* push movement already finished */
4132     {
4133       element = Feld[next_jx][next_jy];
4134       gfx_frame = GfxFrame[next_jx][next_jy];
4135     }
4136
4137     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4138
4139 #if 1
4140     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4141     frame = getGraphicAnimationFrame(graphic, sync_frame);
4142 #else
4143     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4144 #endif
4145
4146     /* draw background element under pushed element (like the Sokoban field) */
4147 #if 1
4148     if (game.use_masked_pushing && IS_MOVING(jx, jy))
4149     {
4150       /* this allows transparent pushing animation over non-black background */
4151
4152       if (Back[jx][jy])
4153         DrawLevelElement(jx, jy, Back[jx][jy]);
4154       else
4155         DrawLevelElement(jx, jy, EL_EMPTY);
4156
4157       if (Back[next_jx][next_jy])
4158         DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4159       else
4160         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4161     }
4162     else if (Back[next_jx][next_jy])
4163       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4164 #else
4165     if (Back[next_jx][next_jy])
4166       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4167 #endif
4168
4169 #if 0
4170     printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4171            jx, px, player->GfxPos, player->StepFrame,
4172            player->is_pushing,
4173            dx, sxx, pxx,
4174            IS_MOVING(jx, jy),
4175            graphic, frame,
4176            GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4177 #endif
4178
4179 #if 1
4180     /* do not draw (EM style) pushing animation when pushing is finished */
4181     /* (two-tile animations usually do not contain start and end frame) */
4182     if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4183       DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4184     else
4185       DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4186 #else
4187     /* masked drawing is needed for EMC style (double) movement graphics */
4188     /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4189     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4190 #endif
4191   }
4192 #endif
4193
4194 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4195   /* ----------------------------------------------------------------------- */
4196   /* draw player himself                                                     */
4197   /* ----------------------------------------------------------------------- */
4198
4199   graphic = getPlayerGraphic(player, move_dir);
4200
4201   /* in the case of changed player action or direction, prevent the current
4202      animation frame from being restarted for identical animations */
4203   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4204     player->Frame = last_player_frame;
4205
4206   frame = getGraphicAnimationFrame(graphic, player->Frame);
4207
4208   if (player->GfxPos)
4209   {
4210     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4211       sxx = player->GfxPos;
4212     else
4213       syy = player->GfxPos;
4214   }
4215
4216   if (!setup.soft_scrolling && ScreenMovPos)
4217     sxx = syy = 0;
4218
4219   if (player_is_opaque)
4220     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4221   else
4222     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4223
4224   if (SHIELD_ON(player))
4225   {
4226     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4227                    IMG_SHIELD_NORMAL_ACTIVE);
4228     int frame = getGraphicAnimationFrame(graphic, -1);
4229
4230     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4231   }
4232 #endif
4233
4234   /* ----------------------------------------------------------------------- */
4235   /* draw things in front of player (active dynamite or dynabombs)           */
4236   /* ----------------------------------------------------------------------- */
4237
4238   if (IS_ACTIVE_BOMB(element))
4239   {
4240     graphic = el2img(element);
4241     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4242
4243     if (game.emulation == EMU_SUPAPLEX)
4244       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4245     else
4246       DrawGraphicThruMask(sx, sy, graphic, frame);
4247   }
4248
4249   if (player_is_moving && last_element == EL_EXPLOSION)
4250   {
4251     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4252                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
4253     int graphic = el_act2img(element, ACTION_EXPLODING);
4254     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4255     int phase = ExplodePhase[last_jx][last_jy] - 1;
4256     int frame = getGraphicAnimationFrame(graphic, phase - delay);
4257
4258     if (phase >= delay)
4259       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4260   }
4261
4262   /* ----------------------------------------------------------------------- */
4263   /* draw elements the player is just walking/passing through/under          */
4264   /* ----------------------------------------------------------------------- */
4265
4266   if (player_is_moving)
4267   {
4268     /* handle the field the player is leaving ... */
4269     if (IS_ACCESSIBLE_INSIDE(last_element))
4270       DrawLevelField(last_jx, last_jy);
4271     else if (IS_ACCESSIBLE_UNDER(last_element))
4272       DrawLevelFieldThruMask(last_jx, last_jy);
4273   }
4274
4275   /* do not redraw accessible elements if the player is just pushing them */
4276   if (!player_is_moving || !player->is_pushing)
4277   {
4278     /* ... and the field the player is entering */
4279     if (IS_ACCESSIBLE_INSIDE(element))
4280       DrawLevelField(jx, jy);
4281     else if (IS_ACCESSIBLE_UNDER(element))
4282       DrawLevelFieldThruMask(jx, jy);
4283   }
4284
4285   MarkTileDirty(sx, sy);
4286 }
4287
4288 /* ------------------------------------------------------------------------- */
4289
4290 void WaitForEventToContinue()
4291 {
4292   boolean still_wait = TRUE;
4293
4294   /* simulate releasing mouse button over last gadget, if still pressed */
4295   if (button_status)
4296     HandleGadgets(-1, -1, 0);
4297
4298   button_status = MB_RELEASED;
4299
4300 #if 1
4301   ClearEventQueue();
4302 #endif
4303
4304   while (still_wait)
4305   {
4306     if (PendingEvent())
4307     {
4308       Event event;
4309
4310       NextEvent(&event);
4311
4312       switch (event.type)
4313       {
4314         case EVENT_BUTTONPRESS:
4315         case EVENT_KEYPRESS:
4316           still_wait = FALSE;
4317           break;
4318
4319         case EVENT_KEYRELEASE:
4320           ClearPlayerAction();
4321           break;
4322
4323         default:
4324           HandleOtherEvents(&event);
4325           break;
4326       }
4327     }
4328     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4329     {
4330       still_wait = FALSE;
4331     }
4332
4333     DoAnimation();
4334
4335     /* don't eat all CPU time */
4336     Delay(10);
4337   }
4338 }
4339
4340 #define MAX_REQUEST_LINES               13
4341 #define MAX_REQUEST_LINE_FONT1_LEN      7
4342 #define MAX_REQUEST_LINE_FONT2_LEN      10
4343
4344 #if 1
4345
4346 static int RequestHandleEvents(unsigned int req_state)
4347 {
4348   int last_game_status = game_status;   /* save current game status */
4349   int result;
4350   int mx, my;
4351
4352   button_status = MB_RELEASED;
4353
4354   request_gadget_id = -1;
4355   result = -1;
4356
4357   while (result < 0)
4358   {
4359     if (PendingEvent())
4360     {
4361       Event event;
4362
4363       NextEvent(&event);
4364
4365       switch (event.type)
4366       {
4367         case EVENT_BUTTONPRESS:
4368         case EVENT_BUTTONRELEASE:
4369         case EVENT_MOTIONNOTIFY:
4370         {
4371           if (event.type == EVENT_MOTIONNOTIFY)
4372           {
4373             if (!PointerInWindow(window))
4374               continue; /* window and pointer are on different screens */
4375
4376             if (!button_status)
4377               continue;
4378
4379             motion_status = TRUE;
4380             mx = ((MotionEvent *) &event)->x;
4381             my = ((MotionEvent *) &event)->y;
4382           }
4383           else
4384           {
4385             motion_status = FALSE;
4386             mx = ((ButtonEvent *) &event)->x;
4387             my = ((ButtonEvent *) &event)->y;
4388             if (event.type == EVENT_BUTTONPRESS)
4389               button_status = ((ButtonEvent *) &event)->button;
4390             else
4391               button_status = MB_RELEASED;
4392           }
4393
4394           /* this sets 'request_gadget_id' */
4395           HandleGadgets(mx, my, button_status);
4396
4397           switch (request_gadget_id)
4398           {
4399             case TOOL_CTRL_ID_YES:
4400               result = TRUE;
4401               break;
4402             case TOOL_CTRL_ID_NO:
4403               result = FALSE;
4404               break;
4405             case TOOL_CTRL_ID_CONFIRM:
4406               result = TRUE | FALSE;
4407               break;
4408
4409             case TOOL_CTRL_ID_PLAYER_1:
4410               result = 1;
4411               break;
4412             case TOOL_CTRL_ID_PLAYER_2:
4413               result = 2;
4414               break;
4415             case TOOL_CTRL_ID_PLAYER_3:
4416               result = 3;
4417               break;
4418             case TOOL_CTRL_ID_PLAYER_4:
4419               result = 4;
4420               break;
4421
4422             default:
4423               break;
4424           }
4425
4426           break;
4427         }
4428
4429         case EVENT_KEYPRESS:
4430           switch (GetEventKey((KeyEvent *)&event, TRUE))
4431           {
4432             case KSYM_space:
4433               if (req_state & REQ_CONFIRM)
4434                 result = 1;
4435               break;
4436
4437             case KSYM_Return:
4438               result = 1;
4439               break;
4440
4441             case KSYM_Escape:
4442 #if defined(TARGET_SDL2)
4443             case KSYM_Back:
4444 #endif
4445               result = 0;
4446               break;
4447
4448             default:
4449               break;
4450           }
4451
4452           if (req_state & REQ_PLAYER)
4453             result = 0;
4454           break;
4455
4456         case EVENT_KEYRELEASE:
4457           ClearPlayerAction();
4458           break;
4459
4460         default:
4461           HandleOtherEvents(&event);
4462           break;
4463       }
4464     }
4465     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4466     {
4467       int joy = AnyJoystick();
4468
4469       if (joy & JOY_BUTTON_1)
4470         result = 1;
4471       else if (joy & JOY_BUTTON_2)
4472         result = 0;
4473     }
4474
4475 #if 1
4476
4477     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4478     {
4479       HandleGameActions();
4480     }
4481     else
4482     {
4483       DoAnimation();
4484
4485       if (!PendingEvent())      /* delay only if no pending events */
4486         Delay(10);
4487     }
4488
4489 #if 1
4490     game_status = GAME_MODE_PSEUDO_DOOR;
4491 #endif
4492
4493     BackToFront();
4494
4495 #if 1
4496     game_status = last_game_status;     /* restore current game status */
4497 #endif
4498
4499 #else
4500
4501     DoAnimation();
4502
4503 #if 1
4504     if (!PendingEvent())        /* delay only if no pending events */
4505       Delay(10);
4506 #else
4507     /* don't eat all CPU time */
4508     Delay(10);
4509 #endif
4510
4511 #endif
4512   }
4513
4514   return result;
4515 }
4516
4517 static boolean RequestDoor(char *text, unsigned int req_state)
4518 {
4519   unsigned int old_door_state;
4520   int last_game_status = game_status;   /* save current game status */
4521   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4522   int font_nr = FONT_TEXT_2;
4523   char *text_ptr;
4524   int result;
4525   int ty;
4526
4527   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4528   {
4529     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4530     font_nr = FONT_TEXT_1;
4531   }
4532
4533   if (game_status == GAME_MODE_PLAYING)
4534   {
4535     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4536       BlitScreenToBitmap_EM(backbuffer);
4537     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4538       BlitScreenToBitmap_SP(backbuffer);
4539   }
4540
4541   /* disable deactivated drawing when quick-loading level tape recording */
4542   if (tape.playing && tape.deactivate_display)
4543     TapeDeactivateDisplayOff(TRUE);
4544
4545   SetMouseCursor(CURSOR_DEFAULT);
4546
4547 #if defined(NETWORK_AVALIABLE)
4548   /* pause network game while waiting for request to answer */
4549   if (options.network &&
4550       game_status == GAME_MODE_PLAYING &&
4551       req_state & REQUEST_WAIT_FOR_INPUT)
4552     SendToServer_PausePlaying();
4553 #endif
4554
4555   old_door_state = GetDoorState();
4556
4557   /* simulate releasing mouse button over last gadget, if still pressed */
4558   if (button_status)
4559     HandleGadgets(-1, -1, 0);
4560
4561   UnmapAllGadgets();
4562
4563   /* draw released gadget before proceeding */
4564   // BackToFront();
4565
4566   if (old_door_state & DOOR_OPEN_1)
4567   {
4568     CloseDoor(DOOR_CLOSE_1);
4569
4570     /* save old door content */
4571 #if 1
4572     BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4573                0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4574 #else
4575     BlitBitmap(bitmap_db_door, bitmap_db_door,
4576                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4577                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4578 #endif
4579   }
4580
4581   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4582   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4583
4584   /* clear door drawing field */
4585   DrawBackground(DX, DY, DXSIZE, DYSIZE);
4586
4587   /* force DOOR font inside door area */
4588   game_status = GAME_MODE_PSEUDO_DOOR;
4589
4590   /* write text for request */
4591   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4592   {
4593     char text_line[max_request_line_len + 1];
4594     int tx, tl, tc = 0;
4595
4596     if (!*text_ptr)
4597       break;
4598
4599     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4600     {
4601       tc = *(text_ptr + tx);
4602       // if (!tc || tc == ' ')
4603       if (!tc || tc == ' ' || tc == '?' || tc == '!')
4604         break;
4605     }
4606
4607     if ((tc == '?' || tc == '!') && tl == 0)
4608       tl = 1;
4609
4610     if (!tl)
4611     { 
4612       text_ptr++; 
4613       ty--; 
4614       continue; 
4615     }
4616
4617     strncpy(text_line, text_ptr, tl);
4618     text_line[tl] = 0;
4619
4620     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4621              DY + 8 + ty * (getFontHeight(font_nr) + 2),
4622              text_line, font_nr);
4623
4624     text_ptr += tl + (tc == ' ' ? 1 : 0);
4625     // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4626   }
4627
4628   game_status = last_game_status;       /* restore current game status */
4629
4630   if (req_state & REQ_ASK)
4631   {
4632     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4633     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4634   }
4635   else if (req_state & REQ_CONFIRM)
4636   {
4637     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4638   }
4639   else if (req_state & REQ_PLAYER)
4640   {
4641     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4642     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4643     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4644     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4645   }
4646
4647   /* copy request gadgets to door backbuffer */
4648 #if 1
4649   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4650 #else
4651   BlitBitmap(drawto, bitmap_db_door,
4652              DX, DY, DXSIZE, DYSIZE,
4653              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4654 #endif
4655
4656   OpenDoor(DOOR_OPEN_1);
4657
4658   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4659   {
4660     if (game_status == GAME_MODE_PLAYING)
4661     {
4662       SetPanelBackground();
4663       SetDrawBackgroundMask(REDRAW_DOOR_1);
4664     }
4665     else
4666     {
4667       SetDrawBackgroundMask(REDRAW_FIELD);
4668     }
4669
4670     return FALSE;
4671   }
4672
4673   if (game_status != GAME_MODE_MAIN)
4674     InitAnimation();
4675
4676   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4677
4678   // ---------- handle request buttons ----------
4679   result = RequestHandleEvents(req_state);
4680
4681   if (game_status != GAME_MODE_MAIN)
4682     StopAnimation();
4683
4684   UnmapToolButtons();
4685
4686   if (!(req_state & REQ_STAY_OPEN))
4687   {
4688     CloseDoor(DOOR_CLOSE_1);
4689
4690     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4691         (req_state & REQ_REOPEN))
4692       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4693   }
4694
4695   RemapAllGadgets();
4696
4697   if (game_status == GAME_MODE_PLAYING)
4698   {
4699     SetPanelBackground();
4700     SetDrawBackgroundMask(REDRAW_DOOR_1);
4701   }
4702   else
4703   {
4704     SetDrawBackgroundMask(REDRAW_FIELD);
4705   }
4706
4707 #if defined(NETWORK_AVALIABLE)
4708   /* continue network game after request */
4709   if (options.network &&
4710       game_status == GAME_MODE_PLAYING &&
4711       req_state & REQUEST_WAIT_FOR_INPUT)
4712     SendToServer_ContinuePlaying();
4713 #endif
4714
4715   /* restore deactivated drawing when quick-loading level tape recording */
4716   if (tape.playing && tape.deactivate_display)
4717     TapeDeactivateDisplayOn();
4718
4719   return result;
4720 }
4721
4722 static boolean RequestEnvelope(char *text, unsigned int req_state)
4723 {
4724   int result;
4725 #if 0
4726   int i;
4727 #endif
4728
4729   if (game_status == GAME_MODE_PLAYING)
4730   {
4731     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4732       BlitScreenToBitmap_EM(backbuffer);
4733     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4734       BlitScreenToBitmap_SP(backbuffer);
4735   }
4736
4737   /* disable deactivated drawing when quick-loading level tape recording */
4738   if (tape.playing && tape.deactivate_display)
4739     TapeDeactivateDisplayOff(TRUE);
4740
4741   SetMouseCursor(CURSOR_DEFAULT);
4742
4743 #if defined(NETWORK_AVALIABLE)
4744   /* pause network game while waiting for request to answer */
4745   if (options.network &&
4746       game_status == GAME_MODE_PLAYING &&
4747       req_state & REQUEST_WAIT_FOR_INPUT)
4748     SendToServer_PausePlaying();
4749 #endif
4750
4751   /* simulate releasing mouse button over last gadget, if still pressed */
4752   if (button_status)
4753     HandleGadgets(-1, -1, 0);
4754
4755   UnmapAllGadgets();
4756
4757   // (replace with setting corresponding request background)
4758   // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4759   // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4760
4761   /* clear door drawing field */
4762   // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4763
4764 #if 0
4765   if (global.use_envelope_request)
4766   {
4767     /* !!! TMP !!! */
4768     FreeToolButtons();
4769     CreateToolButtons();
4770   }
4771 #endif
4772
4773 #if 0
4774 #if 0
4775   if (req_state & REQ_ASK)
4776   {
4777     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4778     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4779   }
4780   else if (req_state & REQ_CONFIRM)
4781   {
4782     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4783   }
4784   else if (req_state & REQ_PLAYER)
4785   {
4786     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4787     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4788     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4789     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4790   }
4791 #else
4792   if (req_state & REQ_ASK)
4793   {
4794     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4795     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4796   }
4797   else if (req_state & REQ_CONFIRM)
4798   {
4799     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4800   }
4801   else if (req_state & REQ_PLAYER)
4802   {
4803     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4804     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4805     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4806     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4807   }
4808 #endif
4809 #endif
4810
4811   ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4812
4813 #if 0
4814   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4815   {
4816     if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4817                                  i == TOOL_CTRL_ID_NO)) ||
4818         (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4819         (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4820                                     i == TOOL_CTRL_ID_PLAYER_2 &&
4821                                     i == TOOL_CTRL_ID_PLAYER_3 &&
4822                                     i == TOOL_CTRL_ID_PLAYER_4)))
4823     {
4824       int x = tool_gadget[i]->x + dDX;
4825       int y = tool_gadget[i]->y + dDY;
4826
4827       ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4828     }
4829   }
4830 #endif
4831
4832   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4833   {
4834     if (game_status == GAME_MODE_PLAYING)
4835     {
4836       SetPanelBackground();
4837       SetDrawBackgroundMask(REDRAW_DOOR_1);
4838     }
4839     else
4840     {
4841       SetDrawBackgroundMask(REDRAW_FIELD);
4842     }
4843
4844     return FALSE;
4845   }
4846
4847 #if 0
4848   if (game_status != GAME_MODE_MAIN)
4849     InitAnimation();
4850 #endif
4851
4852   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4853
4854   // ---------- handle request buttons ----------
4855   result = RequestHandleEvents(req_state);
4856
4857   if (game_status != GAME_MODE_MAIN)
4858     StopAnimation();
4859
4860   UnmapToolButtons();
4861
4862   ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4863
4864   RemapAllGadgets();
4865
4866   if (game_status == GAME_MODE_PLAYING)
4867   {
4868     SetPanelBackground();
4869     SetDrawBackgroundMask(REDRAW_DOOR_1);
4870   }
4871   else
4872   {
4873     SetDrawBackgroundMask(REDRAW_FIELD);
4874   }
4875
4876 #if defined(NETWORK_AVALIABLE)
4877   /* continue network game after request */
4878   if (options.network &&
4879       game_status == GAME_MODE_PLAYING &&
4880       req_state & REQUEST_WAIT_FOR_INPUT)
4881     SendToServer_ContinuePlaying();
4882 #endif
4883
4884   /* restore deactivated drawing when quick-loading level tape recording */
4885   if (tape.playing && tape.deactivate_display)
4886     TapeDeactivateDisplayOn();
4887
4888   return result;
4889 }
4890
4891 boolean Request(char *text, unsigned int req_state)
4892 {
4893   if (global.use_envelope_request)
4894     return RequestEnvelope(text, req_state);
4895   else
4896     return RequestDoor(text, req_state);
4897 }
4898
4899 #else   // =====================================================================
4900
4901 boolean Request(char *text, unsigned int req_state)
4902 {
4903   int mx, my, ty, result = -1;
4904   unsigned int old_door_state;
4905   int last_game_status = game_status;   /* save current game status */
4906   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4907   int font_nr = FONT_TEXT_2;
4908 #if 0
4909   int max_word_len = 0;
4910 #endif
4911   char *text_ptr;
4912   int i;
4913
4914 #if 0
4915   global.use_envelope_request = 1;
4916 #endif
4917
4918 #if 1
4919   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4920   {
4921     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4922     font_nr = FONT_TEXT_1;
4923   }
4924 #else
4925   for (text_ptr = text; *text_ptr; text_ptr++)
4926   {
4927     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
4928
4929     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
4930     {
4931       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4932 #if 1
4933       font_nr = FONT_TEXT_1;
4934 #else
4935       font_nr = FONT_LEVEL_NUMBER;
4936 #endif
4937
4938       break;
4939     }
4940   }
4941 #endif
4942
4943   if (game_status == GAME_MODE_PLAYING)
4944   {
4945     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4946       BlitScreenToBitmap_EM(backbuffer);
4947     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4948       BlitScreenToBitmap_SP(backbuffer);
4949   }
4950
4951   /* disable deactivated drawing when quick-loading level tape recording */
4952   if (tape.playing && tape.deactivate_display)
4953     TapeDeactivateDisplayOff(TRUE);
4954
4955   SetMouseCursor(CURSOR_DEFAULT);
4956
4957 #if defined(NETWORK_AVALIABLE)
4958   /* pause network game while waiting for request to answer */
4959   if (options.network &&
4960       game_status == GAME_MODE_PLAYING &&
4961       req_state & REQUEST_WAIT_FOR_INPUT)
4962     SendToServer_PausePlaying();
4963 #endif
4964
4965   old_door_state = GetDoorState();
4966
4967   /* simulate releasing mouse button over last gadget, if still pressed */
4968   if (button_status)
4969     HandleGadgets(-1, -1, 0);
4970
4971   UnmapAllGadgets();
4972
4973   /* draw released gadget before proceeding */
4974   // BackToFront();
4975
4976 #if 0
4977   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
4978 #else
4979   if (old_door_state & DOOR_OPEN_1)
4980 #endif
4981   {
4982 #if 1
4983     if (!global.use_envelope_request)
4984       CloseDoor(DOOR_CLOSE_1);
4985 #else
4986     CloseDoor(DOOR_CLOSE_1);
4987 #endif
4988
4989     /* save old door content */
4990     BlitBitmap(bitmap_db_door, bitmap_db_door,
4991                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4992                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4993   }
4994
4995 #if 1
4996   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4997 #endif
4998
4999   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5000
5001   /* clear door drawing field */
5002   DrawBackground(DX, DY, DXSIZE, DYSIZE);
5003
5004   /* force DOOR font inside door area */
5005   game_status = GAME_MODE_PSEUDO_DOOR;
5006
5007   /* write text for request */
5008   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5009   {
5010     char text_line[max_request_line_len + 1];
5011     int tx, tl, tc = 0;
5012
5013     if (!*text_ptr)
5014       break;
5015
5016     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5017     {
5018       tc = *(text_ptr + tx);
5019       if (!tc || tc == ' ')
5020         break;
5021     }
5022
5023     if (!tl)
5024     { 
5025       text_ptr++; 
5026       ty--; 
5027       continue; 
5028     }
5029
5030     strncpy(text_line, text_ptr, tl);
5031     text_line[tl] = 0;
5032
5033     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5034              DY + 8 + ty * (getFontHeight(font_nr) + 2),
5035              text_line, font_nr);
5036
5037     text_ptr += tl + (tc == ' ' ? 1 : 0);
5038   }
5039
5040   game_status = last_game_status;       /* restore current game status */
5041
5042 #if 1
5043   if (global.use_envelope_request)
5044   {
5045     /* !!! TMP !!! */
5046     FreeToolButtons();
5047     CreateToolButtons();
5048   }
5049 #endif
5050
5051   if (req_state & REQ_ASK)
5052   {
5053     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5054     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5055   }
5056   else if (req_state & REQ_CONFIRM)
5057   {
5058     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5059   }
5060   else if (req_state & REQ_PLAYER)
5061   {
5062     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5063     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5064     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5065     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5066   }
5067
5068   /* copy request gadgets to door backbuffer */
5069   BlitBitmap(drawto, bitmap_db_door,
5070              DX, DY, DXSIZE, DYSIZE,
5071              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5072
5073 #if 1
5074   if (global.use_envelope_request)
5075   {
5076     ShowEnvelopeRequest(text, ACTION_OPENING);
5077
5078     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5079     {
5080       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5081                                    i == TOOL_CTRL_ID_NO)) ||
5082           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5083           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5084                                       i == TOOL_CTRL_ID_PLAYER_2 &&
5085                                       i == TOOL_CTRL_ID_PLAYER_3 &&
5086                                       i == TOOL_CTRL_ID_PLAYER_4)))
5087       {
5088         int x = tool_gadget[i]->x + dDX;
5089         int y = tool_gadget[i]->y + dDY;
5090
5091         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5092       }
5093     }
5094   }
5095 #endif
5096
5097 #if 1
5098   if (!global.use_envelope_request)
5099     OpenDoor(DOOR_OPEN_1);
5100 #else
5101   OpenDoor(DOOR_OPEN_1);
5102 #endif
5103
5104   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5105   {
5106     if (game_status == GAME_MODE_PLAYING)
5107     {
5108       SetPanelBackground();
5109       SetDrawBackgroundMask(REDRAW_DOOR_1);
5110     }
5111     else
5112     {
5113       SetDrawBackgroundMask(REDRAW_FIELD);
5114     }
5115
5116     return FALSE;
5117   }
5118
5119 #if 1
5120   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5121     InitAnimation();
5122 #else
5123   if (game_status != GAME_MODE_MAIN)
5124     InitAnimation();
5125 #endif
5126
5127   button_status = MB_RELEASED;
5128
5129   request_gadget_id = -1;
5130
5131   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5132
5133   while (result < 0)
5134   {
5135     if (PendingEvent())
5136     {
5137       Event event;
5138
5139       NextEvent(&event);
5140
5141       switch (event.type)
5142       {
5143         case EVENT_BUTTONPRESS:
5144         case EVENT_BUTTONRELEASE:
5145         case EVENT_MOTIONNOTIFY:
5146         {
5147           if (event.type == EVENT_MOTIONNOTIFY)
5148           {
5149             if (!PointerInWindow(window))
5150               continue; /* window and pointer are on different screens */
5151
5152             if (!button_status)
5153               continue;
5154
5155             motion_status = TRUE;
5156             mx = ((MotionEvent *) &event)->x;
5157             my = ((MotionEvent *) &event)->y;
5158           }
5159           else
5160           {
5161             motion_status = FALSE;
5162             mx = ((ButtonEvent *) &event)->x;
5163             my = ((ButtonEvent *) &event)->y;
5164             if (event.type == EVENT_BUTTONPRESS)
5165               button_status = ((ButtonEvent *) &event)->button;
5166             else
5167               button_status = MB_RELEASED;
5168           }
5169
5170           /* this sets 'request_gadget_id' */
5171           HandleGadgets(mx, my, button_status);
5172
5173           switch (request_gadget_id)
5174           {
5175             case TOOL_CTRL_ID_YES:
5176               result = TRUE;
5177               break;
5178             case TOOL_CTRL_ID_NO:
5179               result = FALSE;
5180               break;
5181             case TOOL_CTRL_ID_CONFIRM:
5182               result = TRUE | FALSE;
5183               break;
5184
5185             case TOOL_CTRL_ID_PLAYER_1:
5186               result = 1;
5187               break;
5188             case TOOL_CTRL_ID_PLAYER_2:
5189               result = 2;
5190               break;
5191             case TOOL_CTRL_ID_PLAYER_3:
5192               result = 3;
5193               break;
5194             case TOOL_CTRL_ID_PLAYER_4:
5195               result = 4;
5196               break;
5197
5198             default:
5199               break;
5200           }
5201
5202           break;
5203         }
5204
5205         case EVENT_KEYPRESS:
5206           switch (GetEventKey((KeyEvent *)&event, TRUE))
5207           {
5208             case KSYM_space:
5209               if (req_state & REQ_CONFIRM)
5210                 result = 1;
5211               break;
5212
5213             case KSYM_Return:
5214               result = 1;
5215               break;
5216
5217             case KSYM_Escape:
5218 #if defined(TARGET_SDL2)
5219             case KSYM_Back:
5220 #endif
5221               result = 0;
5222               break;
5223
5224             default:
5225               break;
5226           }
5227
5228           if (req_state & REQ_PLAYER)
5229             result = 0;
5230           break;
5231
5232         case EVENT_KEYRELEASE:
5233           ClearPlayerAction();
5234           break;
5235
5236         default:
5237           HandleOtherEvents(&event);
5238           break;
5239       }
5240     }
5241     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5242     {
5243       int joy = AnyJoystick();
5244
5245       if (joy & JOY_BUTTON_1)
5246         result = 1;
5247       else if (joy & JOY_BUTTON_2)
5248         result = 0;
5249     }
5250
5251 #if 1
5252
5253     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5254     {
5255       HandleGameActions();
5256     }
5257     else
5258     {
5259       DoAnimation();
5260
5261       if (!PendingEvent())      /* delay only if no pending events */
5262         Delay(10);
5263     }
5264
5265 #if 1
5266     game_status = GAME_MODE_PSEUDO_DOOR;
5267 #endif
5268
5269     BackToFront();
5270
5271 #if 1
5272     game_status = last_game_status;     /* restore current game status */
5273 #endif
5274
5275 #else
5276
5277     DoAnimation();
5278
5279 #if 1
5280     if (!PendingEvent())        /* delay only if no pending events */
5281       Delay(10);
5282 #else
5283     /* don't eat all CPU time */
5284     Delay(10);
5285 #endif
5286
5287 #endif
5288   }
5289
5290   if (game_status != GAME_MODE_MAIN)
5291     StopAnimation();
5292
5293   UnmapToolButtons();
5294
5295 #if 1
5296   if (global.use_envelope_request)
5297     ShowEnvelopeRequest(text, ACTION_CLOSING);
5298 #endif
5299
5300 #if 1
5301   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5302 #else
5303   if (!(req_state & REQ_STAY_OPEN))
5304 #endif
5305   {
5306     CloseDoor(DOOR_CLOSE_1);
5307
5308     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5309         (req_state & REQ_REOPEN))
5310       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5311   }
5312
5313   RemapAllGadgets();
5314
5315   if (game_status == GAME_MODE_PLAYING)
5316   {
5317     SetPanelBackground();
5318     SetDrawBackgroundMask(REDRAW_DOOR_1);
5319   }
5320   else
5321   {
5322     SetDrawBackgroundMask(REDRAW_FIELD);
5323   }
5324
5325 #if defined(NETWORK_AVALIABLE)
5326   /* continue network game after request */
5327   if (options.network &&
5328       game_status == GAME_MODE_PLAYING &&
5329       req_state & REQUEST_WAIT_FOR_INPUT)
5330     SendToServer_ContinuePlaying();
5331 #endif
5332
5333   /* restore deactivated drawing when quick-loading level tape recording */
5334   if (tape.playing && tape.deactivate_display)
5335     TapeDeactivateDisplayOn();
5336
5337   return result;
5338 }
5339
5340 #endif
5341
5342 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5343 {
5344   const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5345   const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5346   int compare_result;
5347
5348   if (dpo1->sort_priority != dpo2->sort_priority)
5349     compare_result = dpo1->sort_priority - dpo2->sort_priority;
5350   else
5351     compare_result = dpo1->nr - dpo2->nr;
5352
5353   return compare_result;
5354 }
5355
5356 void InitGraphicCompatibilityInfo_Doors()
5357 {
5358   struct
5359   {
5360     int door_token;
5361     int part_1, part_8;
5362     struct DoorInfo *door;
5363   }
5364   doors[] =
5365   {
5366     { DOOR_1,   IMG_DOOR_1_GFX_PART_1,  IMG_DOOR_1_GFX_PART_8,  &door_1 },
5367     { DOOR_2,   IMG_DOOR_2_GFX_PART_1,  IMG_DOOR_2_GFX_PART_8,  &door_2 },
5368
5369     { -1,       -1,                     -1,                     NULL    }
5370   };
5371   struct Rect door_rect_list[] =
5372   {
5373     { DX, DY, DXSIZE, DYSIZE },
5374     { VX, VY, VXSIZE, VYSIZE }
5375   };
5376   int i, j;
5377
5378   for (i = 0; doors[i].door_token != -1; i++)
5379   {
5380     int door_token = doors[i].door_token;
5381     int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5382     int part_1 = doors[i].part_1;
5383     int part_8 = doors[i].part_8;
5384     int part_2 = part_1 + 1;
5385     int part_3 = part_1 + 2;
5386     struct DoorInfo *door = doors[i].door;
5387     struct Rect *door_rect = &door_rect_list[door_index];
5388     boolean door_gfx_redefined = FALSE;
5389
5390     /* check if any door part graphic definitions have been redefined */
5391
5392     for (j = 0; door_part_controls[j].door_token != -1; j++)
5393     {
5394       struct DoorPartControlInfo *dpc = &door_part_controls[j];
5395       struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5396
5397       if (dpc->door_token == door_token && fi->redefined)
5398         door_gfx_redefined = TRUE;
5399     }
5400
5401     /* check for old-style door graphic/animation modifications */
5402
5403     if (!door_gfx_redefined)
5404     {
5405       if (door->anim_mode & ANIM_STATIC_PANEL)
5406       {
5407         door->panel.step_xoffset = 0;
5408         door->panel.step_yoffset = 0;
5409       }
5410
5411       if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5412       {
5413         struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5414         struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5415         int num_door_steps, num_panel_steps;
5416
5417         /* remove door part graphics other than the two default wings */
5418
5419         for (j = 0; door_part_controls[j].door_token != -1; j++)
5420         {
5421           struct DoorPartControlInfo *dpc = &door_part_controls[j];
5422           struct GraphicInfo *g = &graphic_info[dpc->graphic];
5423
5424           if (dpc->graphic >= part_3 &&
5425               dpc->graphic <= part_8)
5426             g->bitmap = NULL;
5427         }
5428
5429         /* set graphics and screen positions of the default wings */
5430
5431         g_part_1->width  = door_rect->width;
5432         g_part_1->height = door_rect->height;
5433         g_part_2->width  = door_rect->width;
5434         g_part_2->height = door_rect->height;
5435         g_part_2->src_x = door_rect->width;
5436         g_part_2->src_y = g_part_1->src_y;
5437
5438         door->part_2.x = door->part_1.x;
5439         door->part_2.y = door->part_1.y;
5440
5441         if (door->width != -1)
5442         {
5443           g_part_1->width = door->width;
5444           g_part_2->width = door->width;
5445
5446           // special treatment for graphics and screen position of right wing
5447           g_part_2->src_x += door_rect->width - door->width;
5448           door->part_2.x  += door_rect->width - door->width;
5449         }
5450
5451         if (door->height != -1)
5452         {
5453           g_part_1->height = door->height;
5454           g_part_2->height = door->height;
5455
5456           // special treatment for graphics and screen position of bottom wing
5457           g_part_2->src_y += door_rect->height - door->height;
5458           door->part_2.y  += door_rect->height - door->height;
5459         }
5460
5461         /* set animation delays for the default wings and panels */
5462
5463         door->part_1.step_delay = door->step_delay;
5464         door->part_2.step_delay = door->step_delay;
5465         door->panel.step_delay  = door->step_delay;
5466
5467         /* set animation draw order for the default wings */
5468
5469         door->part_1.sort_priority = 2; /* draw left wing over ... */
5470         door->part_2.sort_priority = 1; /*          ... right wing */
5471
5472         /* set animation draw offset for the default wings */
5473
5474         if (door->anim_mode & ANIM_HORIZONTAL)
5475         {
5476           door->part_1.step_xoffset = door->step_offset;
5477           door->part_1.step_yoffset = 0;
5478           door->part_2.step_xoffset = door->step_offset * -1;
5479           door->part_2.step_yoffset = 0;
5480
5481           num_door_steps = g_part_1->width / door->step_offset;
5482         }
5483         else    // ANIM_VERTICAL
5484         {
5485           door->part_1.step_xoffset = 0;
5486           door->part_1.step_yoffset = door->step_offset;
5487           door->part_2.step_xoffset = 0;
5488           door->part_2.step_yoffset = door->step_offset * -1;
5489
5490           num_door_steps = g_part_1->height / door->step_offset;
5491         }
5492
5493         /* set animation draw offset for the default panels */
5494
5495         if (door->step_offset > 1)
5496         {
5497           num_panel_steps = 2 * door_rect->height / door->step_offset;
5498           door->panel.start_step = num_panel_steps - num_door_steps;
5499         }
5500         else
5501         {
5502           num_panel_steps = door_rect->height / door->step_offset;
5503           door->panel.start_step = num_panel_steps - num_door_steps / 2;
5504           door->panel.step_delay *= 2;
5505         }
5506       }
5507     }
5508   }
5509 }
5510
5511 void InitDoors()
5512 {
5513   int i;
5514
5515   for (i = 0; door_part_controls[i].door_token != -1; i++)
5516   {
5517     struct DoorPartControlInfo *dpc = &door_part_controls[i];
5518     struct DoorPartOrderInfo *dpo = &door_part_order[i];
5519
5520     /* initialize "start_step_opening" and "start_step_closing", if needed */
5521     if (dpc->pos->start_step_opening == 0 &&
5522         dpc->pos->start_step_closing == 0)
5523     {
5524       // dpc->pos->start_step_opening = dpc->pos->start_step;
5525       dpc->pos->start_step_closing = dpc->pos->start_step;
5526     }
5527
5528     /* fill structure for door part draw order (sorted below) */
5529     dpo->nr = i;
5530     dpo->sort_priority = dpc->pos->sort_priority;
5531
5532 #if 0
5533     struct DoorPartPosInfo *pos = dpc->pos;
5534
5535     printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5536            pos->step_xoffset, pos->step_yoffset);
5537 #endif
5538   }
5539
5540   /* sort door part controls according to sort_priority and graphic number */
5541   qsort(door_part_order, MAX_DOOR_PARTS,
5542         sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5543 }
5544
5545 unsigned int OpenDoor(unsigned int door_state)
5546 {
5547   if (door_state & DOOR_COPY_BACK)
5548   {
5549 #if 1
5550     if (door_state & DOOR_OPEN_1)
5551       BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5552                  1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5553
5554     if (door_state & DOOR_OPEN_2)
5555       BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5556                  1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5557 #else
5558     if (door_state & DOOR_OPEN_1)
5559       BlitBitmap(bitmap_db_door, bitmap_db_door,
5560                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5561                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5562
5563     if (door_state & DOOR_OPEN_2)
5564       BlitBitmap(bitmap_db_door, bitmap_db_door,
5565                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5566                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5567 #endif
5568
5569     door_state &= ~DOOR_COPY_BACK;
5570   }
5571
5572   return MoveDoor(door_state);
5573 }
5574
5575 unsigned int CloseDoor(unsigned int door_state)
5576 {
5577   unsigned int old_door_state = GetDoorState();
5578
5579   if (!(door_state & DOOR_NO_COPY_BACK))
5580   {
5581 #if 1
5582     if (old_door_state & DOOR_OPEN_1)
5583       BlitBitmap(backbuffer, bitmap_db_door_1,
5584                  DX, DY, DXSIZE, DYSIZE, 0, 0);
5585
5586     if (old_door_state & DOOR_OPEN_2)
5587       BlitBitmap(backbuffer, bitmap_db_door_2,
5588                  VX, VY, VXSIZE, VYSIZE, 0, 0);
5589 #else
5590     if (old_door_state & DOOR_OPEN_1)
5591       BlitBitmap(backbuffer, bitmap_db_door,
5592                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5593
5594     if (old_door_state & DOOR_OPEN_2)
5595       BlitBitmap(backbuffer, bitmap_db_door,
5596                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5597 #endif
5598
5599     door_state &= ~DOOR_NO_COPY_BACK;
5600   }
5601
5602   return MoveDoor(door_state);
5603 }
5604
5605 unsigned int GetDoorState()
5606 {
5607   return MoveDoor(DOOR_GET_STATE);
5608 }
5609
5610 unsigned int SetDoorState(unsigned int door_state)
5611 {
5612   return MoveDoor(door_state | DOOR_SET_STATE);
5613 }
5614
5615 #if 1
5616
5617 // ========== TEST 1 ===========================================================
5618
5619 int euclid(int a, int b)
5620 {
5621   return (b ? euclid(b, a % b) : a);
5622 }
5623
5624 unsigned int MoveDoor(unsigned int door_state)
5625 {
5626 #if 0
5627   struct XY panel_pos_list[] =
5628   {
5629     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5630     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5631   };
5632 #endif
5633   struct Rect door_rect_list[] =
5634   {
5635     { DX, DY, DXSIZE, DYSIZE },
5636     { VX, VY, VXSIZE, VYSIZE }
5637   };
5638   static int door1 = DOOR_OPEN_1;
5639   static int door2 = DOOR_CLOSE_2;
5640   unsigned int door_delay = 0;
5641   unsigned int door_delay_value;
5642   int i;
5643
5644 #if 1
5645   if (door_1.width < 0 || door_1.width > DXSIZE)
5646     door_1.width = DXSIZE;
5647   if (door_1.height < 0 || door_1.height > DYSIZE)
5648     door_1.height = DYSIZE;
5649   if (door_2.width < 0 || door_2.width > VXSIZE)
5650     door_2.width = VXSIZE;
5651   if (door_2.height < 0 || door_2.height > VYSIZE)
5652     door_2.height = VYSIZE;
5653 #endif
5654
5655   if (door_state == DOOR_GET_STATE)
5656     return (door1 | door2);
5657
5658   if (door_state & DOOR_SET_STATE)
5659   {
5660     if (door_state & DOOR_ACTION_1)
5661       door1 = door_state & DOOR_ACTION_1;
5662     if (door_state & DOOR_ACTION_2)
5663       door2 = door_state & DOOR_ACTION_2;
5664
5665     return (door1 | door2);
5666   }
5667
5668   if (!(door_state & DOOR_FORCE_REDRAW))
5669   {
5670     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5671       door_state &= ~DOOR_OPEN_1;
5672     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5673       door_state &= ~DOOR_CLOSE_1;
5674     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5675       door_state &= ~DOOR_OPEN_2;
5676     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5677       door_state &= ~DOOR_CLOSE_2;
5678   }
5679
5680 #if 0
5681   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5682                       door_2.step_delay);
5683
5684   if (setup.quick_doors)
5685   {
5686     stepsize = 20;              /* must be chosen to always draw last frame */
5687     door_delay_value = 0;
5688   }
5689 #endif
5690
5691   if (global.autoplay_leveldir)
5692   {
5693     door_state |= DOOR_NO_DELAY;
5694     door_state &= ~DOOR_CLOSE_ALL;
5695   }
5696
5697 #if 1
5698   if (game_status == GAME_MODE_EDITOR)
5699     door_state |= DOOR_NO_DELAY;
5700 #endif
5701
5702   if (door_state & DOOR_ACTION)
5703   {
5704     boolean door_panel_drawn[NUM_DOORS];
5705     boolean door_part_skip[MAX_DOOR_PARTS];
5706     boolean door_part_done[MAX_DOOR_PARTS];
5707     boolean door_part_done_all;
5708     int num_steps[MAX_DOOR_PARTS];
5709     int max_move_delay = 0;     // delay for complete animations of all doors
5710     int max_step_delay = 0;     // delay (ms) between two animation frames
5711     int num_move_steps = 0;     // number of animation steps for all doors
5712     int current_move_delay = 0;
5713     int k;
5714
5715     for (i = 0; i < MAX_DOOR_PARTS; i++)
5716     {
5717       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5718       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5719       int door_token = dpc->door_token;
5720
5721       door_part_done[i] = FALSE;
5722       door_part_skip[i] = (!(door_state & door_token) ||
5723                            !g->bitmap);
5724     }
5725
5726 #if 0
5727     for (i = 0; i < MAX_DOOR_PARTS; i++)
5728     {
5729       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5730       struct DoorPartPosInfo *pos = dpc->pos;
5731       int start_step = pos->start_step;
5732
5733       printf("::: ---> %d: start_step == %d [%d]\n",
5734              i, start_step, door_part_done[i]);
5735     }
5736 #endif
5737
5738     for (i = 0; i < MAX_DOOR_PARTS; i++)
5739     {
5740       int nr = door_part_order[i].nr;
5741       struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5742       struct DoorPartPosInfo *pos = dpc->pos;
5743       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5744       int door_token = dpc->door_token;
5745       boolean is_panel = DOOR_PART_IS_PANEL(nr);
5746       int step_xoffset = ABS(pos->step_xoffset);
5747       int step_yoffset = ABS(pos->step_yoffset);
5748       int step_delay = pos->step_delay;
5749       int current_door_state = door_state & door_token;
5750       boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
5751       boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5752       boolean part_opening = (is_panel ? door_closing : door_opening);
5753       int start_step = (part_opening ? pos->start_step_opening :
5754                         pos->start_step_closing);
5755       float move_xsize = (step_xoffset ? g->width  : 0);
5756       float move_ysize = (step_yoffset ? g->height : 0);
5757       int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5758       int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5759       int move_steps = (move_xsteps && move_ysteps ?
5760                         MIN(move_xsteps, move_ysteps) :
5761                         move_xsteps ? move_xsteps : move_ysteps) - start_step;
5762       int move_delay = move_steps * step_delay;
5763
5764       if (door_part_skip[nr])
5765         continue;
5766
5767       max_move_delay = MAX(max_move_delay, move_delay);
5768       max_step_delay = (max_step_delay == 0 ? step_delay :
5769                         euclid(max_step_delay, step_delay));
5770       num_steps[nr] = move_steps;
5771
5772 #if 0
5773 #if 0
5774       printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5775              i, move_delay, start_step, door_part_order[i].nr);
5776 #else
5777       if (DOOR_PART_IS_PANEL(i))
5778         printf("::: %d: move_delay == %d, start_step == %d\n",
5779                i, move_delay, start_step);
5780 #endif
5781 #endif
5782     }
5783
5784     num_move_steps = max_move_delay / max_step_delay;
5785
5786     door_delay_value = max_step_delay;
5787
5788 #if 0
5789     door_delay_value *= 10;
5790 #endif
5791
5792 #if 0
5793     printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5794 #endif
5795
5796     for (k = 0; k < num_move_steps; k++)
5797     {
5798       door_part_done_all = TRUE;
5799
5800       for (i = 0; i < NUM_DOORS; i++)
5801         door_panel_drawn[i] = FALSE;
5802
5803       for (i = 0; i < MAX_DOOR_PARTS; i++)
5804       {
5805         int nr = door_part_order[i].nr;
5806         struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5807         struct DoorPartPosInfo *pos = dpc->pos;
5808         struct GraphicInfo *g = &graphic_info[dpc->graphic];
5809         int door_token = dpc->door_token;
5810         int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5811         boolean is_panel = DOOR_PART_IS_PANEL(nr);
5812 #if 0
5813         struct XY *panel_pos = &panel_pos_list[door_index];
5814 #endif
5815         struct Rect *door_rect = &door_rect_list[door_index];
5816         Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5817                                   bitmap_db_door_2);
5818         Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5819         int current_door_state = door_state & door_token;
5820         boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
5821         boolean door_closing = !door_opening;
5822         boolean part_opening = (is_panel ? door_closing : door_opening);
5823         boolean part_closing = !part_opening;
5824         int start_step = (part_opening ? pos->start_step_opening :
5825                           pos->start_step_closing);
5826         int step_delay = pos->step_delay;
5827         int step_factor = step_delay / max_step_delay;
5828         int k1 = (step_factor ? k / step_factor + 1 : k);
5829         int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5830         int kk = (k2 < 0 ? 0 : k2);
5831         int src_x, src_y, src_xx, src_yy;
5832         int dst_x, dst_y, dst_xx, dst_yy;
5833         int width, height;
5834
5835 #if 0
5836         if (k == 0 && is_panel && door_token == DOOR_2)
5837           printf("::: %d, %d\n", g->width, g->height);
5838 #endif
5839
5840 #if 0
5841         if (DOOR_PART_IS_PANEL(nr))
5842         {
5843           int start_step = pos->start_step;
5844
5845           k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
5846           kk = (k2 < 0 ? 0 : k2);
5847         }
5848 #endif
5849
5850 #if 0
5851         // !!! TEST !!! 
5852         if (nr != 16 && nr != 0)
5853           continue;
5854 #endif
5855
5856 #if 0
5857         // !!! TEST !!! 
5858         if (!is_panel)
5859           continue;
5860 #endif
5861
5862 #if 1
5863         if (door_part_skip[nr])
5864           continue;
5865 #endif
5866
5867         if (!(door_state & door_token))
5868           continue;
5869
5870         if (!g->bitmap)
5871           continue;
5872
5873 #if 0
5874         if (current_move_delay % step_delay)
5875           continue;
5876 #endif
5877
5878         // draw door panel
5879
5880         if (!door_panel_drawn[door_index])
5881         {
5882 #if 1
5883           ClearRectangle(drawto, door_rect->x, door_rect->y,
5884                          door_rect->width, door_rect->height);
5885 #else
5886           BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
5887                      door_rect->width, door_rect->height,
5888                      door_rect->x, door_rect->y);
5889 #endif
5890
5891           door_panel_drawn[door_index] = TRUE;
5892         }
5893
5894         // draw opening or closing door parts
5895
5896         if (pos->step_xoffset < 0)      // door part on right side
5897         {
5898           src_xx = 0;
5899           dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5900           width = g->width;
5901
5902           if (dst_xx + width > door_rect->width)
5903             width = door_rect->width - dst_xx;
5904         }
5905         else                            // door part on left side
5906         {
5907           src_xx = 0;
5908           dst_xx = pos->x - kk * pos->step_xoffset;
5909
5910           if (dst_xx < 0)
5911           {
5912             src_xx = ABS(dst_xx);
5913             dst_xx = 0;
5914           }
5915
5916           width = g->width - src_xx;
5917
5918           // printf("::: k == %d [%d] \n", k, start_step);
5919         }
5920
5921         if (pos->step_yoffset < 0)      // door part on bottom side
5922         {
5923           src_yy = 0;
5924           dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5925           height = g->height;
5926
5927           if (dst_yy + height > door_rect->height)
5928             height = door_rect->height - dst_yy;
5929         }
5930         else                            // door part on top side
5931         {
5932           src_yy = 0;
5933           dst_yy = pos->y - kk * pos->step_yoffset;
5934
5935           if (dst_yy < 0)
5936           {
5937             src_yy = ABS(dst_yy);
5938             dst_yy = 0;
5939           }
5940
5941           height = g->height - src_yy;
5942         }
5943
5944         if (is_panel)
5945         {
5946 #if 1
5947           src_x = src_xx;
5948           src_y = src_yy;
5949 #else
5950           src_x = panel_pos->x + src_xx;
5951           src_y = panel_pos->y + src_yy;
5952 #endif
5953         }
5954         else
5955         {
5956           src_x = g->src_x + src_xx;
5957           src_y = g->src_y + src_yy;
5958         }
5959
5960         dst_x = door_rect->x + dst_xx;
5961         dst_y = door_rect->y + dst_yy;
5962
5963 #if 0
5964         if (DOOR_PART_IS_PANEL(nr))
5965         {
5966           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
5967                  width, height, g->width, g->height, src_x, src_y);
5968         }
5969 #endif
5970
5971         if (width  >= 0 && width  <= g->width &&
5972             height >= 0 && height <= g->height)
5973         {
5974           if (is_panel || !pos->draw_masked)
5975             BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5976                        dst_x, dst_y);
5977           else
5978             BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5979                              dst_x, dst_y);
5980         }
5981
5982 #if 0
5983         if (DOOR_PART_IS_PANEL(nr))
5984         {
5985           bitmap = bitmap_db_door;
5986           src_x = panel_pos->x + src_xx;
5987           src_y = panel_pos->y + src_yy;
5988
5989           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
5990                  width, height, g->width, g->height, src_x, src_y);
5991
5992           if (width  >= 0 && width  <= g->width &&
5993               height >= 0 && height <= g->height)
5994             BlitBitmap(bitmap, drawto, src_x, src_y,
5995                              width, height,
5996                              dst_x, dst_y);
5997         }
5998 #endif
5999
6000         redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6001
6002 #if 1
6003         if ((part_opening && (width < 0         || height < 0)) ||
6004             (part_closing && (width >= g->width && height >= g->height)))
6005           door_part_done[nr] = TRUE;
6006 #else
6007         if ((door_opening && (width < 0         || height < 0)) ||
6008             (door_closing && (width >= g->width && height >= g->height)))
6009           door_part_done[nr] = TRUE;
6010 #endif
6011
6012         // continue door part animations, but not panel after door has closed
6013         if (!door_part_done[nr] && !(is_panel && door_closing))
6014           door_part_done_all = FALSE;
6015
6016 #if 0
6017         if (!door_part_done[nr])
6018           printf("::: k == %d, nr == %d\n", k, nr);
6019 #endif
6020       }
6021
6022       if (!(door_state & DOOR_NO_DELAY))
6023       {
6024         BackToFront();
6025
6026         if (game_status == GAME_MODE_MAIN)
6027           DoAnimation();
6028
6029         WaitUntilDelayReached(&door_delay, door_delay_value);
6030
6031         current_move_delay += max_step_delay;
6032       }
6033
6034 #if 0
6035       door_part_done_all = TRUE;
6036
6037       for (i = 0; i < MAX_DOOR_PARTS; i++)
6038         if (!door_part_done[i] &&
6039             !(DOOR_PART_IS_PANEL(i) && door_closing))
6040           door_part_done_all = FALSE;
6041 #endif
6042 #if 1
6043       if (door_part_done_all)
6044         break;
6045 #endif
6046     }
6047   }
6048
6049   if (door_state & DOOR_ACTION_1)
6050     door1 = door_state & DOOR_ACTION_1;
6051   if (door_state & DOOR_ACTION_2)
6052     door2 = door_state & DOOR_ACTION_2;
6053
6054 #if 0
6055   printf("::: DOORS DONE %08x\n", door_state);
6056   Delay(3000);
6057   printf("::: GO!\n");
6058 #endif
6059
6060   return (door1 | door2);
6061 }
6062
6063 #else
6064
6065 // ========== OLD ==============================================================
6066
6067 unsigned int MoveDoor(unsigned int door_state)
6068 {
6069   static int door1 = DOOR_OPEN_1;
6070   static int door2 = DOOR_CLOSE_2;
6071   unsigned int door_delay = 0;
6072   unsigned int door_delay_value;
6073   int stepsize = 1;
6074
6075 #if 1
6076   if (door_1.width < 0 || door_1.width > DXSIZE)
6077     door_1.width = DXSIZE;
6078   if (door_1.height < 0 || door_1.height > DYSIZE)
6079     door_1.height = DYSIZE;
6080   if (door_2.width < 0 || door_2.width > VXSIZE)
6081     door_2.width = VXSIZE;
6082   if (door_2.height < 0 || door_2.height > VYSIZE)
6083     door_2.height = VYSIZE;
6084 #endif
6085
6086   if (door_state == DOOR_GET_STATE)
6087     return (door1 | door2);
6088
6089   if (door_state & DOOR_SET_STATE)
6090   {
6091     if (door_state & DOOR_ACTION_1)
6092       door1 = door_state & DOOR_ACTION_1;
6093     if (door_state & DOOR_ACTION_2)
6094       door2 = door_state & DOOR_ACTION_2;
6095
6096     return (door1 | door2);
6097   }
6098
6099   if (!(door_state & DOOR_FORCE_REDRAW))
6100   {
6101     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6102       door_state &= ~DOOR_OPEN_1;
6103     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6104       door_state &= ~DOOR_CLOSE_1;
6105     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6106       door_state &= ~DOOR_OPEN_2;
6107     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6108       door_state &= ~DOOR_CLOSE_2;
6109   }
6110
6111   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6112                       door_2.step_delay);
6113
6114   // door_delay_value *= 4;     // !!! TEST ONLY !!!
6115
6116   if (setup.quick_doors)
6117   {
6118     stepsize = 20;              /* must be chosen to always draw last frame */
6119     door_delay_value = 0;
6120   }
6121
6122   if (global.autoplay_leveldir)
6123   {
6124     door_state |= DOOR_NO_DELAY;
6125     door_state &= ~DOOR_CLOSE_ALL;
6126   }
6127
6128 #if 1
6129   if (game_status == GAME_MODE_EDITOR)
6130     door_state |= DOOR_NO_DELAY;
6131 #endif
6132
6133   if (door_state & DOOR_ACTION)
6134   {
6135 #if 1
6136     struct GraphicInfo *g1_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6137     struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6138     struct GraphicInfo *g2_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6139     struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6140     int door_1_left_width   = g1_left->width;
6141     int door_1_left_height  = g1_left->height;
6142     int door_1_right_width  = g1_right->width;
6143     int door_1_right_height = g1_right->height;
6144     int door_2_left_width   = g2_left->width;
6145     int door_2_left_height  = g2_left->height;
6146     int door_2_right_width  = g2_right->width;
6147     int door_2_right_height = g2_right->height;
6148     int door_1_width  = MAX(door_1_left_width,  door_1_right_width);
6149     int door_1_height = MAX(door_1_left_height, door_1_right_height);
6150     int door_2_width  = MAX(door_2_left_width,  door_2_right_width);
6151     int door_2_height = MAX(door_2_left_height, door_2_right_height);
6152 #endif
6153     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6154     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6155     boolean door_1_done = (!handle_door_1);
6156     boolean door_2_done = (!handle_door_2);
6157     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6158     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6159 #if 1
6160 #if 1
6161     int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6162     int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6163 #else
6164     int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6165     int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6166 #endif
6167 #else
6168     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6169     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6170 #endif
6171     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6172     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6173     // int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
6174     int door_size     = (handle_door_2 ? door_size_2     : door_size_1);
6175     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6176     int door_skip = max_door_size - door_size;
6177     int end = door_size;
6178     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6179     int k;
6180
6181     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6182     {
6183       /* opening door sound has priority over simultaneously closing door */
6184       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6185         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6186       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6187         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6188     }
6189
6190     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6191     {
6192       int x = k;
6193 #if 0
6194       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6195       GC gc = bitmap->stored_clip_gc;
6196 #endif
6197
6198       if (door_state & DOOR_ACTION_1 &&
6199           x * door_1.step_offset <= door_size_1)
6200       {
6201         int a = MIN(x * door_1.step_offset, end);
6202         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6203 #if 1
6204         int i = p;
6205 #else
6206         int i = p + door_skip;
6207 #endif
6208
6209 #if 1
6210         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6211         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6212         Bitmap *bm_left  = g_left->bitmap;
6213         Bitmap *bm_right = g_right->bitmap;
6214         GC gc_left  = bm_left->stored_clip_gc;
6215         GC gc_right = bm_right->stored_clip_gc;
6216 #endif
6217
6218         int classic_dxsize = 100;
6219         int classic_dysize = 280;
6220         boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6221                                        DYSIZE == classic_dysize);
6222
6223         if (door_1.anim_mode & ANIM_STATIC_PANEL)
6224         {
6225           BlitBitmap(bitmap_db_door, drawto,
6226                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6227                      DXSIZE, DYSIZE, DX, DY);
6228         }
6229         else if (x <= a)
6230         {
6231           BlitBitmap(bitmap_db_door, drawto,
6232                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6233                      DXSIZE, DYSIZE - p / 2, DX, DY);
6234
6235 #if 1
6236           // printf("::: p == %d\n", p);
6237           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6238 #endif
6239         }
6240
6241         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6242         {
6243 #if 1
6244           int src1_x = g_right->src_x;
6245           int src1_y = g_right->src_y;
6246           int src2_x = g_left->src_x + g_left->width - i;
6247           int src2_y = g_left->src_y;
6248           int dst1_x = DX + DXSIZE - i;
6249           int dst1_y = DY;
6250           int dst2_x = DX;
6251           int dst2_y = DY;
6252           int width = i;
6253           int height = DYSIZE;
6254
6255           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6256           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6257                            dst1_x, dst1_y);
6258
6259           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6260           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6261                            dst2_x, dst2_y);
6262 #else
6263           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6264           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6265           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6266           int dst2_x = DX,              dst2_y = DY;
6267           int width = i, height = DYSIZE;
6268
6269           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6270           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6271                            dst1_x, dst1_y);
6272
6273           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6274           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6275                            dst2_x, dst2_y);
6276 #endif
6277         }
6278         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6279         {
6280 #if 1
6281           int src1_x = g_right->src_x;
6282           int src1_y = g_right->src_y;
6283           int src2_x = g_left->src_x;
6284           int src2_y = g_left->src_y + g_left->height - i;
6285           int dst1_x = DX;
6286           int dst1_y = DY + DYSIZE - i;
6287           int dst2_x = DX;
6288           int dst2_y = DY;
6289           int width = DXSIZE;
6290           int height = i;
6291
6292           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6293           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6294                            dst1_x, dst1_y);
6295
6296           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6297           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6298                            dst2_x, dst2_y);
6299 #else
6300           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6301           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6302           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
6303           int dst2_x = DX,              dst2_y = DY;
6304           int width = DXSIZE, height = i;
6305
6306           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6307           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6308                            dst1_x, dst1_y);
6309
6310           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6311           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6312                            dst2_x, dst2_y);
6313 #endif
6314         }
6315         else if (classic_door_1_size && x <= DXSIZE)    /* ANIM_DEFAULT */
6316         {
6317           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6318
6319 #if 1
6320           int src1_x = g_right->src_x;
6321           int src1_y = g_right->src_y;
6322           int src2_x = g_left->src_x + g_left->width - i;
6323           int src2_y = g_left->src_y;
6324           int dst1_x = DX + DXSIZE - i;
6325           int dst1_y = DY;
6326           int dst2_x = DX;
6327           int dst2_y = DY;
6328           int width = i;
6329           int height1 = 63, height2 = DYSIZE / 2 - height1;
6330           int ypos1 = 0, ypos2 = height2;
6331           int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6332
6333           SetClipOrigin(bm_right, gc_right,
6334                         dst1_x - src1_x, dst1_y - src1_y + j);
6335           BlitBitmapMasked(bm_right, drawto,
6336                            src1_x, src1_y + ypos1, width, height2,
6337                            dst1_x, dst1_y + ypos1 + j);
6338           BlitBitmapMasked(bm_right, drawto,
6339                            src1_x, src1_y + ypos3, width, height1,
6340                            dst1_x, dst1_y + ypos3 + j);
6341           SetClipOrigin(bm_left, gc_left,
6342                         dst2_x - src2_x, dst2_y - src2_y - j);
6343           BlitBitmapMasked(bm_left, drawto,
6344                            src2_x, src2_y + ypos1 + j, width, height2 - j,
6345                            dst2_x, dst2_y + ypos1);
6346           BlitBitmapMasked(bm_left, drawto,
6347                            src2_x, src2_y + ypos3, width, height1,
6348                            dst2_x, dst2_y + ypos3 - j);
6349
6350           SetClipOrigin(bm_left, gc_left,
6351                         dst2_x - src2_x, dst2_y - src2_y - j);
6352           BlitBitmapMasked(bm_left, drawto,
6353                            src2_x, src2_y + ypos2, width, height1,
6354                            dst2_x, dst2_y + ypos2 - j);
6355           BlitBitmapMasked(bm_left, drawto,
6356                            src2_x, src2_y + ypos4, width, height2,
6357                            dst2_x, dst2_y + ypos4 - j);
6358           SetClipOrigin(bm_right, gc_right,
6359                         dst1_x - src1_x, dst1_y - src1_y + j);
6360           BlitBitmapMasked(bm_right, drawto,
6361                            src1_x, src1_y + ypos2, width, height1,
6362                            dst1_x, dst1_y + ypos2 + j);
6363           BlitBitmapMasked(bm_right, drawto,
6364                            src1_x, src1_y + ypos4, width, height2 - j,
6365                            dst1_x, dst1_y + ypos4 + j);
6366
6367 #else
6368           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6369           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6370           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6371           int dst2_x = DX,              dst2_y = DY;
6372           int width = i, height = DYSIZE;
6373           int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6374
6375           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6376           BlitBitmapMasked(bitmap, drawto,
6377                            src1_x, src1_y, width, ypos2,
6378                            dst1_x, dst1_y + j);
6379           BlitBitmapMasked(bitmap, drawto,
6380                            src1_x, src1_y + ypos3, width, ypos1,
6381                            dst1_x, dst1_y + ypos3 + j);
6382           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6383           BlitBitmapMasked(bitmap, drawto,
6384                            src2_x, src2_y + j, width, ypos2 - j,
6385                            dst2_x, dst2_y);
6386           BlitBitmapMasked(bitmap, drawto,
6387                            src2_x, src2_y + ypos3, width, ypos1,
6388                            dst2_x, dst2_y + ypos3 - j);
6389
6390           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6391           BlitBitmapMasked(bitmap, drawto,
6392                            src2_x, src2_y + ypos2, width, ypos1,
6393                            dst2_x, dst2_y + ypos2 - j);
6394           BlitBitmapMasked(bitmap, drawto,
6395                            src2_x, src2_y + ypos4, width, ypos2,
6396                            dst2_x, dst2_y + ypos4 - j);
6397           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6398           BlitBitmapMasked(bitmap, drawto,
6399                            src1_x, src1_y + ypos2, width, ypos1,
6400                            dst1_x, dst1_y + ypos2 + j);
6401           BlitBitmapMasked(bitmap, drawto,
6402                            src1_x, src1_y + ypos4, width, ypos2 - j,
6403                            dst1_x, dst1_y + ypos4 + j);
6404
6405           /*
6406           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6407           BlitBitmapMasked(bitmap, drawto,
6408                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6409                            DX + DXSIZE - i, DY + j);
6410           BlitBitmapMasked(bitmap, drawto,
6411                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6412                            DX + DXSIZE - i, DY + 140 + j);
6413           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6414                         DY - (DOOR_GFX_PAGEY1 + j));
6415           BlitBitmapMasked(bitmap, drawto,
6416                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6417                            DX, DY);
6418           BlitBitmapMasked(bitmap, drawto,
6419                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6420                            DX, DY + 140 - j);
6421
6422           BlitBitmapMasked(bitmap, drawto,
6423                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6424                            DX, DY + 77 - j);
6425           BlitBitmapMasked(bitmap, drawto,
6426                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6427                            DX, DY + 203 - j);
6428           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6429           BlitBitmapMasked(bitmap, drawto,
6430                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6431                            DX + DXSIZE - i, DY + 77 + j);
6432           BlitBitmapMasked(bitmap, drawto,
6433                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6434                            DX + DXSIZE - i, DY + 203 + j);
6435           */
6436 #endif
6437         }
6438
6439         redraw_mask |= REDRAW_DOOR_1;
6440         door_1_done = (a == end);
6441       }
6442
6443       if (door_state & DOOR_ACTION_2 &&
6444           x * door_2.step_offset <= door_size_2)
6445       {
6446         int a = MIN(x * door_2.step_offset, door_size);
6447         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6448         int i = p + door_skip;
6449
6450 #if 1
6451         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6452         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6453         Bitmap *bm_left  = g_left->bitmap;
6454         Bitmap *bm_right = g_right->bitmap;
6455         GC gc_left  = bm_left->stored_clip_gc;
6456         GC gc_right = bm_right->stored_clip_gc;
6457 #endif
6458
6459         int classic_vxsize = 100;
6460         int classic_vysize = 100;
6461         boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6462                                        VYSIZE == classic_vysize);
6463
6464         if (door_2.anim_mode & ANIM_STATIC_PANEL)
6465         {
6466           BlitBitmap(bitmap_db_door, drawto,
6467                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6468                      VXSIZE, VYSIZE, VX, VY);
6469         }
6470         else if (x <= VYSIZE)
6471         {
6472           BlitBitmap(bitmap_db_door, drawto,
6473                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6474                      VXSIZE, VYSIZE - p / 2, VX, VY);
6475
6476           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6477         }
6478
6479         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6480         {
6481 #if 1
6482           int src1_x = g_right->src_x;
6483           int src1_y = g_right->src_y;
6484           int src2_x = g_left->src_x + g_left->width - i;
6485           int src2_y = g_left->src_y;
6486           int dst1_x = VX + VXSIZE - i;
6487           int dst1_y = VY;
6488           int dst2_x = VX;
6489           int dst2_y = VY;
6490           int width = i;
6491           int height = VYSIZE;
6492
6493           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6494           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6495                            dst1_x, dst1_y);
6496
6497           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6498           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6499                            dst2_x, dst2_y);
6500 #else
6501           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6502           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6503           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6504           int dst2_x = VX,              dst2_y = VY;
6505           int width = i, height = VYSIZE;
6506
6507           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6508           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6509                            dst1_x, dst1_y);
6510
6511           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6512           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6513                            dst2_x, dst2_y);
6514 #endif
6515         }
6516         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6517         {
6518 #if 1
6519           int src1_x = g_right->src_x;
6520           int src1_y = g_right->src_y;
6521           int src2_x = g_left->src_x;
6522           int src2_y = g_left->src_y + g_left->height - i;
6523           int dst1_x = VX;
6524           int dst1_y = VY + VYSIZE - i;
6525           int dst2_x = VX;
6526           int dst2_y = VY;
6527           int width = VXSIZE;
6528           int height = i;
6529
6530           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6531           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6532                            dst1_x, dst1_y);
6533
6534           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6535           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6536                            dst2_x, dst2_y);
6537 #else
6538           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6539           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6540           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
6541           int dst2_x = VX,              dst2_y = VY;
6542           int width = VXSIZE, height = i;
6543
6544           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6545           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6546                            dst1_x, dst1_y);
6547
6548           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6549           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6550                            dst2_x, dst2_y);
6551 #endif
6552         }
6553         else if (classic_door_2_size && x <= VXSIZE)    /* ANIM_DEFAULT */
6554         {
6555           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6556
6557 #if 1
6558           int src1_x = g_right->src_x;
6559           int src1_y = g_right->src_y;
6560           int src2_x = g_left->src_x + g_left->width - i;
6561           int src2_y = g_left->src_y;
6562           int dst1_x = VX + VXSIZE - i;
6563           int dst1_y = VY;
6564           int dst2_x = VX;
6565           int dst2_y = VY;
6566           int width = i;
6567           int height = VYSIZE / 2;
6568           int ypos1 = 0, ypos2 = VYSIZE / 2;
6569
6570           SetClipOrigin(bm_right, gc_right,
6571                         dst1_x - src1_x, dst1_y - src1_y + j);
6572           BlitBitmapMasked(bm_right, drawto,
6573                            src1_x, src1_y + ypos1, width, height,
6574                            dst1_x, dst1_y + ypos1 + j);
6575           SetClipOrigin(bm_left, gc_left,
6576                         dst2_x - src2_x, dst2_y - src2_y - j);
6577           BlitBitmapMasked(bm_left, drawto,
6578                            src2_x, src2_y + ypos1 + j, width, height - j,
6579                            dst2_x, dst2_y + ypos1);
6580
6581           SetClipOrigin(bm_left, gc_left,
6582                         dst2_x - src2_x, dst2_y - src2_y - j);
6583           BlitBitmapMasked(bm_left, drawto,
6584                            src2_x, src2_y + ypos2, width, height,
6585                            dst2_x, dst2_y + ypos2 - j);
6586           SetClipOrigin(bm_right, gc_right,
6587                         dst1_x - src1_x, dst1_y - src1_y + j);
6588           BlitBitmapMasked(bm_right, drawto,
6589                            src1_x, src1_y + ypos2, width, height - j,
6590                            dst1_x, dst1_y + ypos2 + j);
6591 #else
6592           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6593           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6594           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6595           int dst2_x = VX,              dst2_y = VY;
6596           int width = i, height = VYSIZE;
6597           int ypos = VYSIZE / 2;
6598
6599           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6600           BlitBitmapMasked(bitmap, drawto,
6601                            src1_x, src1_y, width, ypos,
6602                            dst1_x, dst1_y + j);
6603           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6604           BlitBitmapMasked(bitmap, drawto,
6605                            src2_x, src2_y + j, width, ypos - j,
6606                            dst2_x, dst2_y);
6607
6608           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6609           BlitBitmapMasked(bitmap, drawto,
6610                            src2_x, src2_y + ypos, width, ypos,
6611                            dst2_x, dst2_y + ypos - j);
6612           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6613           BlitBitmapMasked(bitmap, drawto,
6614                            src1_x, src1_y + ypos, width, ypos - j,
6615                            dst1_x, dst1_y + ypos + j);
6616
6617           /*
6618           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6619           BlitBitmapMasked(bitmap, drawto,
6620                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6621                            VX + VXSIZE - i, VY + j);
6622           SetClipOrigin(bitmap, gc,
6623                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6624           BlitBitmapMasked(bitmap, drawto,
6625                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6626                            VX, VY);
6627
6628           BlitBitmapMasked(bitmap, drawto,
6629                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6630                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6631           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6632           BlitBitmapMasked(bitmap, drawto,
6633                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6634                            i, VYSIZE / 2 - j,
6635                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6636           */
6637 #endif
6638         }
6639
6640         redraw_mask |= REDRAW_DOOR_2;
6641         door_2_done = (a == VXSIZE);
6642       }
6643
6644       if (!(door_state & DOOR_NO_DELAY))
6645       {
6646         BackToFront();
6647
6648         if (game_status == GAME_MODE_MAIN)
6649           DoAnimation();
6650
6651         WaitUntilDelayReached(&door_delay, door_delay_value);
6652       }
6653     }
6654   }
6655
6656   if (door_state & DOOR_ACTION_1)
6657     door1 = door_state & DOOR_ACTION_1;
6658   if (door_state & DOOR_ACTION_2)
6659     door2 = door_state & DOOR_ACTION_2;
6660
6661   return (door1 | door2);
6662 }
6663
6664 #endif
6665
6666 void DrawSpecialEditorDoor()
6667 {
6668 #if 1
6669   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6670   int top_border_width = gfx1->width;
6671   int top_border_height = gfx1->height;
6672   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6673   int ex = EX - outer_border;
6674   int ey = EY - outer_border;
6675   int vy = VY - outer_border;
6676   int exsize = EXSIZE + 2 * outer_border;
6677
6678   CloseDoor(DOOR_CLOSE_2);
6679
6680   /* draw bigger level editor toolbox window */
6681   BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6682              top_border_width, top_border_height, ex, ey - top_border_height);
6683   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6684              exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6685 #else
6686   /* draw bigger level editor toolbox window */
6687   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6688              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6689              EX - 4, EY - 12);
6690   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6691              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6692              EX - 6, EY - 4);
6693 #endif
6694
6695   redraw_mask |= REDRAW_ALL;
6696 }
6697
6698 void UndrawSpecialEditorDoor()
6699 {
6700 #if 1
6701   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6702   int top_border_width = gfx1->width;
6703   int top_border_height = gfx1->height;
6704   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6705   int ex = EX - outer_border;
6706   int ey = EY - outer_border;
6707   int ey_top = ey - top_border_height;
6708   int exsize = EXSIZE + 2 * outer_border;
6709   int eysize = EYSIZE + 2 * outer_border;
6710
6711   /* draw normal tape recorder window */
6712   if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6713   {
6714     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6715                ex, ey_top, top_border_width, top_border_height,
6716                ex, ey_top);
6717     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6718                ex, ey, exsize, eysize, ex, ey);
6719   }
6720   else
6721   {
6722     // if screen background is set to "[NONE]", clear editor toolbox window
6723     ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6724     ClearRectangle(drawto, ex, ey, exsize, eysize);
6725   }
6726 #else
6727   /* draw normal tape recorder window */
6728   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6729              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6730              EX - 6, EY - 12);
6731 #endif
6732
6733   redraw_mask |= REDRAW_ALL;
6734 }
6735
6736
6737 /* ---------- new tool button stuff ---------------------------------------- */
6738
6739 #if 1
6740
6741 static struct
6742 {
6743   int graphic;
6744   struct TextPosInfo *pos;
6745   int gadget_id;
6746   char *infotext;
6747 } toolbutton_info[NUM_TOOL_BUTTONS] =
6748 {
6749   {
6750     IMG_REQUEST_BUTTON_GFX_YES,         &request.button.yes,
6751     TOOL_CTRL_ID_YES,                   "yes"
6752   },
6753   {
6754     IMG_REQUEST_BUTTON_GFX_NO,          &request.button.no,
6755     TOOL_CTRL_ID_NO,                    "no"
6756   },
6757   {
6758     IMG_REQUEST_BUTTON_GFX_CONFIRM,     &request.button.confirm,
6759     TOOL_CTRL_ID_CONFIRM,               "confirm"
6760   },
6761   {
6762     IMG_REQUEST_BUTTON_GFX_PLAYER_1,    &request.button.player_1,
6763     TOOL_CTRL_ID_PLAYER_1,              "player 1"
6764   },
6765   {
6766     IMG_REQUEST_BUTTON_GFX_PLAYER_2,    &request.button.player_2,
6767     TOOL_CTRL_ID_PLAYER_2,              "player 2"
6768   },
6769   {
6770     IMG_REQUEST_BUTTON_GFX_PLAYER_3,    &request.button.player_3,
6771     TOOL_CTRL_ID_PLAYER_3,              "player 3"
6772   },
6773   {
6774     IMG_REQUEST_BUTTON_GFX_PLAYER_4,    &request.button.player_4,
6775     TOOL_CTRL_ID_PLAYER_4,              "player 4"
6776   }
6777 };
6778
6779 void CreateToolButtons()
6780 {
6781   int i;
6782
6783   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6784   {
6785     struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6786     struct TextPosInfo *pos = toolbutton_info[i].pos;
6787     struct GadgetInfo *gi;
6788     Bitmap *deco_bitmap = None;
6789     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6790     unsigned int event_mask = GD_EVENT_RELEASED;
6791     int dx = DX;
6792     int dy = DY;
6793     int gd_x = gfx->src_x;
6794     int gd_y = gfx->src_y;
6795     int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6796     int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6797     int id = i;
6798
6799     if (global.use_envelope_request)
6800       setRequestPosition(&dx, &dy, TRUE);
6801
6802     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6803     {
6804       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6805
6806       getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6807                             pos->size, &deco_bitmap, &deco_x, &deco_y);
6808       deco_xpos = (gfx->width  - pos->size) / 2;
6809       deco_ypos = (gfx->height - pos->size) / 2;
6810     }
6811
6812     gi = CreateGadget(GDI_CUSTOM_ID, id,
6813                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
6814                       GDI_X, dx + GDI_ACTIVE_POS(pos->x),
6815                       GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
6816                       GDI_WIDTH, gfx->width,
6817                       GDI_HEIGHT, gfx->height,
6818                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6819                       GDI_STATE, GD_BUTTON_UNPRESSED,
6820                       GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6821                       GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6822                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6823                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6824                       GDI_DECORATION_SIZE, pos->size, pos->size,
6825                       GDI_DECORATION_SHIFTING, 1, 1,
6826                       GDI_DIRECT_DRAW, FALSE,
6827                       GDI_EVENT_MASK, event_mask,
6828                       GDI_CALLBACK_ACTION, HandleToolButtons,
6829                       GDI_END);
6830
6831     if (gi == NULL)
6832       Error(ERR_EXIT, "cannot create gadget");
6833
6834     tool_gadget[id] = gi;
6835   }
6836 }
6837
6838 #else
6839
6840 /* graphic position values for tool buttons */
6841 #define TOOL_BUTTON_YES_XPOS            2
6842 #define TOOL_BUTTON_YES_YPOS            250
6843 #define TOOL_BUTTON_YES_GFX_YPOS        0
6844 #define TOOL_BUTTON_YES_XSIZE           46
6845 #define TOOL_BUTTON_YES_YSIZE           28
6846 #define TOOL_BUTTON_NO_XPOS             52
6847 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
6848 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
6849 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
6850 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
6851 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
6852 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
6853 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
6854 #define TOOL_BUTTON_CONFIRM_XSIZE       96
6855 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
6856 #define TOOL_BUTTON_PLAYER_XSIZE        30
6857 #define TOOL_BUTTON_PLAYER_YSIZE        30
6858 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
6859 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
6860 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
6861 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
6862 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6863                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6864 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6865                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6866 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6867                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6868 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6869                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6870 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6871                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6872 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6873                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6874 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6875                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6876 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6877                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6878
6879 static struct
6880 {
6881   int xpos, ypos;
6882   int x, y;
6883   int width, height;
6884   int gadget_id;
6885   char *infotext;
6886 } toolbutton_info[NUM_TOOL_BUTTONS] =
6887 {
6888   {
6889     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
6890     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
6891     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
6892     TOOL_CTRL_ID_YES,
6893     "yes"
6894   },
6895   {
6896     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
6897     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
6898     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
6899     TOOL_CTRL_ID_NO,
6900     "no"
6901   },
6902   {
6903     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
6904     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
6905     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
6906     TOOL_CTRL_ID_CONFIRM,
6907     "confirm"
6908   },
6909   {
6910     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6911     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
6912     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6913     TOOL_CTRL_ID_PLAYER_1,
6914     "player 1"
6915   },
6916   {
6917     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6918     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
6919     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6920     TOOL_CTRL_ID_PLAYER_2,
6921     "player 2"
6922   },
6923   {
6924     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6925     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
6926     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6927     TOOL_CTRL_ID_PLAYER_3,
6928     "player 3"
6929   },
6930   {
6931     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6932     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
6933     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6934     TOOL_CTRL_ID_PLAYER_4,
6935     "player 4"
6936   }
6937 };
6938
6939 void CreateToolButtons()
6940 {
6941   int i;
6942
6943   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6944   {
6945     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6946     Bitmap *deco_bitmap = None;
6947     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6948     struct GadgetInfo *gi;
6949     unsigned int event_mask;
6950     int gd_xoffset, gd_yoffset;
6951     int gd_x1, gd_x2, gd_y;
6952     int id = i;
6953
6954     event_mask = GD_EVENT_RELEASED;
6955
6956     gd_xoffset = toolbutton_info[i].xpos;
6957     gd_yoffset = toolbutton_info[i].ypos;
6958     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6959     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6960     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
6961
6962     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6963     {
6964       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6965
6966       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
6967                            &deco_bitmap, &deco_x, &deco_y);
6968       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
6969       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
6970     }
6971
6972     gi = CreateGadget(GDI_CUSTOM_ID, id,
6973                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
6974                       GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
6975                       GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
6976                       GDI_WIDTH, toolbutton_info[i].width,
6977                       GDI_HEIGHT, toolbutton_info[i].height,
6978                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6979                       GDI_STATE, GD_BUTTON_UNPRESSED,
6980                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6981                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6982                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6983                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6984                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
6985                       GDI_DECORATION_SHIFTING, 1, 1,
6986                       GDI_DIRECT_DRAW, FALSE,
6987                       GDI_EVENT_MASK, event_mask,
6988                       GDI_CALLBACK_ACTION, HandleToolButtons,
6989                       GDI_END);
6990
6991     if (gi == NULL)
6992       Error(ERR_EXIT, "cannot create gadget");
6993
6994     tool_gadget[id] = gi;
6995   }
6996 }
6997
6998 #endif
6999
7000 void FreeToolButtons()
7001 {
7002   int i;
7003
7004   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7005     FreeGadget(tool_gadget[i]);
7006 }
7007
7008 static void UnmapToolButtons()
7009 {
7010   int i;
7011
7012   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7013     UnmapGadget(tool_gadget[i]);
7014 }
7015
7016 static void HandleToolButtons(struct GadgetInfo *gi)
7017 {
7018   request_gadget_id = gi->custom_id;
7019 }
7020
7021 static struct Mapping_EM_to_RND_object
7022 {
7023   int element_em;
7024   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
7025   boolean is_backside;                  /* backside of moving element */
7026
7027   int element_rnd;
7028   int action;
7029   int direction;
7030 }
7031 em_object_mapping_list[] =
7032 {
7033   {
7034     Xblank,                             TRUE,   FALSE,
7035     EL_EMPTY,                           -1, -1
7036   },
7037   {
7038     Yacid_splash_eB,                    FALSE,  FALSE,
7039     EL_ACID_SPLASH_RIGHT,               -1, -1
7040   },
7041   {
7042     Yacid_splash_wB,                    FALSE,  FALSE,
7043     EL_ACID_SPLASH_LEFT,                -1, -1
7044   },
7045
7046 #ifdef EM_ENGINE_BAD_ROLL
7047   {
7048     Xstone_force_e,                     FALSE,  FALSE,
7049     EL_ROCK,                            -1, MV_BIT_RIGHT
7050   },
7051   {
7052     Xstone_force_w,                     FALSE,  FALSE,
7053     EL_ROCK,                            -1, MV_BIT_LEFT
7054   },
7055   {
7056     Xnut_force_e,                       FALSE,  FALSE,
7057     EL_NUT,                             -1, MV_BIT_RIGHT
7058   },
7059   {
7060     Xnut_force_w,                       FALSE,  FALSE,
7061     EL_NUT,                             -1, MV_BIT_LEFT
7062   },
7063   {
7064     Xspring_force_e,                    FALSE,  FALSE,
7065     EL_SPRING,                          -1, MV_BIT_RIGHT
7066   },
7067   {
7068     Xspring_force_w,                    FALSE,  FALSE,
7069     EL_SPRING,                          -1, MV_BIT_LEFT
7070   },
7071   {
7072     Xemerald_force_e,                   FALSE,  FALSE,
7073     EL_EMERALD,                         -1, MV_BIT_RIGHT
7074   },
7075   {
7076     Xemerald_force_w,                   FALSE,  FALSE,
7077     EL_EMERALD,                         -1, MV_BIT_LEFT
7078   },
7079   {
7080     Xdiamond_force_e,                   FALSE,  FALSE,
7081     EL_DIAMOND,                         -1, MV_BIT_RIGHT
7082   },
7083   {
7084     Xdiamond_force_w,                   FALSE,  FALSE,
7085     EL_DIAMOND,                         -1, MV_BIT_LEFT
7086   },
7087   {
7088     Xbomb_force_e,                      FALSE,  FALSE,
7089     EL_BOMB,                            -1, MV_BIT_RIGHT
7090   },
7091   {
7092     Xbomb_force_w,                      FALSE,  FALSE,
7093     EL_BOMB,                            -1, MV_BIT_LEFT
7094   },
7095 #endif  /* EM_ENGINE_BAD_ROLL */
7096
7097   {
7098     Xstone,                             TRUE,   FALSE,
7099     EL_ROCK,                            -1, -1
7100   },
7101   {
7102     Xstone_pause,                       FALSE,  FALSE,
7103     EL_ROCK,                            -1, -1
7104   },
7105   {
7106     Xstone_fall,                        FALSE,  FALSE,
7107     EL_ROCK,                            -1, -1
7108   },
7109   {
7110     Ystone_s,                           FALSE,  FALSE,
7111     EL_ROCK,                            ACTION_FALLING, -1
7112   },
7113   {
7114     Ystone_sB,                          FALSE,  TRUE,
7115     EL_ROCK,                            ACTION_FALLING, -1
7116   },
7117   {
7118     Ystone_e,                           FALSE,  FALSE,
7119     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7120   },
7121   {
7122     Ystone_eB,                          FALSE,  TRUE,
7123     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7124   },
7125   {
7126     Ystone_w,                           FALSE,  FALSE,
7127     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7128   },
7129   {
7130     Ystone_wB,                          FALSE,  TRUE,
7131     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7132   },
7133   {
7134     Xnut,                               TRUE,   FALSE,
7135     EL_NUT,                             -1, -1
7136   },
7137   {
7138     Xnut_pause,                         FALSE,  FALSE,
7139     EL_NUT,                             -1, -1
7140   },
7141   {
7142     Xnut_fall,                          FALSE,  FALSE,
7143     EL_NUT,                             -1, -1
7144   },
7145   {
7146     Ynut_s,                             FALSE,  FALSE,
7147     EL_NUT,                             ACTION_FALLING, -1
7148   },
7149   {
7150     Ynut_sB,                            FALSE,  TRUE,
7151     EL_NUT,                             ACTION_FALLING, -1
7152   },
7153   {
7154     Ynut_e,                             FALSE,  FALSE,
7155     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7156   },
7157   {
7158     Ynut_eB,                            FALSE,  TRUE,
7159     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7160   },
7161   {
7162     Ynut_w,                             FALSE,  FALSE,
7163     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7164   },
7165   {
7166     Ynut_wB,                            FALSE,  TRUE,
7167     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7168   },
7169   {
7170     Xbug_n,                             TRUE,   FALSE,
7171     EL_BUG_UP,                          -1, -1
7172   },
7173   {
7174     Xbug_e,                             TRUE,   FALSE,
7175     EL_BUG_RIGHT,                       -1, -1
7176   },
7177   {
7178     Xbug_s,                             TRUE,   FALSE,
7179     EL_BUG_DOWN,                        -1, -1
7180   },
7181   {
7182     Xbug_w,                             TRUE,   FALSE,
7183     EL_BUG_LEFT,                        -1, -1
7184   },
7185   {
7186     Xbug_gon,                           FALSE,  FALSE,
7187     EL_BUG_UP,                          -1, -1
7188   },
7189   {
7190     Xbug_goe,                           FALSE,  FALSE,
7191     EL_BUG_RIGHT,                       -1, -1
7192   },
7193   {
7194     Xbug_gos,                           FALSE,  FALSE,
7195     EL_BUG_DOWN,                        -1, -1
7196   },
7197   {
7198     Xbug_gow,                           FALSE,  FALSE,
7199     EL_BUG_LEFT,                        -1, -1
7200   },
7201   {
7202     Ybug_n,                             FALSE,  FALSE,
7203     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7204   },
7205   {
7206     Ybug_nB,                            FALSE,  TRUE,
7207     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7208   },
7209   {
7210     Ybug_e,                             FALSE,  FALSE,
7211     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7212   },
7213   {
7214     Ybug_eB,                            FALSE,  TRUE,
7215     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7216   },
7217   {
7218     Ybug_s,                             FALSE,  FALSE,
7219     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7220   },
7221   {
7222     Ybug_sB,                            FALSE,  TRUE,
7223     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7224   },
7225   {
7226     Ybug_w,                             FALSE,  FALSE,
7227     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7228   },
7229   {
7230     Ybug_wB,                            FALSE,  TRUE,
7231     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7232   },
7233   {
7234     Ybug_w_n,                           FALSE,  FALSE,
7235     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7236   },
7237   {
7238     Ybug_n_e,                           FALSE,  FALSE,
7239     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7240   },
7241   {
7242     Ybug_e_s,                           FALSE,  FALSE,
7243     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7244   },
7245   {
7246     Ybug_s_w,                           FALSE,  FALSE,
7247     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7248   },
7249   {
7250     Ybug_e_n,                           FALSE,  FALSE,
7251     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7252   },
7253   {
7254     Ybug_s_e,                           FALSE,  FALSE,
7255     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7256   },
7257   {
7258     Ybug_w_s,                           FALSE,  FALSE,
7259     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7260   },
7261   {
7262     Ybug_n_w,                           FALSE,  FALSE,
7263     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7264   },
7265   {
7266     Ybug_stone,                         FALSE,  FALSE,
7267     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
7268   },
7269   {
7270     Ybug_spring,                        FALSE,  FALSE,
7271     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
7272   },
7273   {
7274     Xtank_n,                            TRUE,   FALSE,
7275     EL_SPACESHIP_UP,                    -1, -1
7276   },
7277   {
7278     Xtank_e,                            TRUE,   FALSE,
7279     EL_SPACESHIP_RIGHT,                 -1, -1
7280   },
7281   {
7282     Xtank_s,                            TRUE,   FALSE,
7283     EL_SPACESHIP_DOWN,                  -1, -1
7284   },
7285   {
7286     Xtank_w,                            TRUE,   FALSE,
7287     EL_SPACESHIP_LEFT,                  -1, -1
7288   },
7289   {
7290     Xtank_gon,                          FALSE,  FALSE,
7291     EL_SPACESHIP_UP,                    -1, -1
7292   },
7293   {
7294     Xtank_goe,                          FALSE,  FALSE,
7295     EL_SPACESHIP_RIGHT,                 -1, -1
7296   },
7297   {
7298     Xtank_gos,                          FALSE,  FALSE,
7299     EL_SPACESHIP_DOWN,                  -1, -1
7300   },
7301   {
7302     Xtank_gow,                          FALSE,  FALSE,
7303     EL_SPACESHIP_LEFT,                  -1, -1
7304   },
7305   {
7306     Ytank_n,                            FALSE,  FALSE,
7307     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7308   },
7309   {
7310     Ytank_nB,                           FALSE,  TRUE,
7311     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7312   },
7313   {
7314     Ytank_e,                            FALSE,  FALSE,
7315     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7316   },
7317   {
7318     Ytank_eB,                           FALSE,  TRUE,
7319     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7320   },
7321   {
7322     Ytank_s,                            FALSE,  FALSE,
7323     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7324   },
7325   {
7326     Ytank_sB,                           FALSE,  TRUE,
7327     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7328   },
7329   {
7330     Ytank_w,                            FALSE,  FALSE,
7331     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7332   },
7333   {
7334     Ytank_wB,                           FALSE,  TRUE,
7335     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7336   },
7337   {
7338     Ytank_w_n,                          FALSE,  FALSE,
7339     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7340   },
7341   {
7342     Ytank_n_e,                          FALSE,  FALSE,
7343     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7344   },
7345   {
7346     Ytank_e_s,                          FALSE,  FALSE,
7347     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7348   },
7349   {
7350     Ytank_s_w,                          FALSE,  FALSE,
7351     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7352   },
7353   {
7354     Ytank_e_n,                          FALSE,  FALSE,
7355     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7356   },
7357   {
7358     Ytank_s_e,                          FALSE,  FALSE,
7359     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7360   },
7361   {
7362     Ytank_w_s,                          FALSE,  FALSE,
7363     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7364   },
7365   {
7366     Ytank_n_w,                          FALSE,  FALSE,
7367     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7368   },
7369   {
7370     Ytank_stone,                        FALSE,  FALSE,
7371     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
7372   },
7373   {
7374     Ytank_spring,                       FALSE,  FALSE,
7375     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
7376   },
7377   {
7378     Xandroid,                           TRUE,   FALSE,
7379     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
7380   },
7381   {
7382     Xandroid_1_n,                       FALSE,  FALSE,
7383     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7384   },
7385   {
7386     Xandroid_2_n,                       FALSE,  FALSE,
7387     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7388   },
7389   {
7390     Xandroid_1_e,                       FALSE,  FALSE,
7391     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7392   },
7393   {
7394     Xandroid_2_e,                       FALSE,  FALSE,
7395     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7396   },
7397   {
7398     Xandroid_1_w,                       FALSE,  FALSE,
7399     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7400   },
7401   {
7402     Xandroid_2_w,                       FALSE,  FALSE,
7403     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7404   },
7405   {
7406     Xandroid_1_s,                       FALSE,  FALSE,
7407     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7408   },
7409   {
7410     Xandroid_2_s,                       FALSE,  FALSE,
7411     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7412   },
7413   {
7414     Yandroid_n,                         FALSE,  FALSE,
7415     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7416   },
7417   {
7418     Yandroid_nB,                        FALSE,  TRUE,
7419     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7420   },
7421   {
7422     Yandroid_ne,                        FALSE,  FALSE,
7423     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
7424   },
7425   {
7426     Yandroid_neB,                       FALSE,  TRUE,
7427     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
7428   },
7429   {
7430     Yandroid_e,                         FALSE,  FALSE,
7431     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7432   },
7433   {
7434     Yandroid_eB,                        FALSE,  TRUE,
7435     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7436   },
7437   {
7438     Yandroid_se,                        FALSE,  FALSE,
7439     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
7440   },
7441   {
7442     Yandroid_seB,                       FALSE,  TRUE,
7443     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7444   },
7445   {
7446     Yandroid_s,                         FALSE,  FALSE,
7447     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7448   },
7449   {
7450     Yandroid_sB,                        FALSE,  TRUE,
7451     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7452   },
7453   {
7454     Yandroid_sw,                        FALSE,  FALSE,
7455     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
7456   },
7457   {
7458     Yandroid_swB,                       FALSE,  TRUE,
7459     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
7460   },
7461   {
7462     Yandroid_w,                         FALSE,  FALSE,
7463     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7464   },
7465   {
7466     Yandroid_wB,                        FALSE,  TRUE,
7467     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7468   },
7469   {
7470     Yandroid_nw,                        FALSE,  FALSE,
7471     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
7472   },
7473   {
7474     Yandroid_nwB,                       FALSE,  TRUE,
7475     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
7476   },
7477   {
7478     Xspring,                            TRUE,   FALSE,
7479     EL_SPRING,                          -1, -1
7480   },
7481   {
7482     Xspring_pause,                      FALSE,  FALSE,
7483     EL_SPRING,                          -1, -1
7484   },
7485   {
7486     Xspring_e,                          FALSE,  FALSE,
7487     EL_SPRING,                          -1, -1
7488   },
7489   {
7490     Xspring_w,                          FALSE,  FALSE,
7491     EL_SPRING,                          -1, -1
7492   },
7493   {
7494     Xspring_fall,                       FALSE,  FALSE,
7495     EL_SPRING,                          -1, -1
7496   },
7497   {
7498     Yspring_s,                          FALSE,  FALSE,
7499     EL_SPRING,                          ACTION_FALLING, -1
7500   },
7501   {
7502     Yspring_sB,                         FALSE,  TRUE,
7503     EL_SPRING,                          ACTION_FALLING, -1
7504   },
7505   {
7506     Yspring_e,                          FALSE,  FALSE,
7507     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7508   },
7509   {
7510     Yspring_eB,                         FALSE,  TRUE,
7511     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7512   },
7513   {
7514     Yspring_w,                          FALSE,  FALSE,
7515     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7516   },
7517   {
7518     Yspring_wB,                         FALSE,  TRUE,
7519     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7520   },
7521   {
7522     Yspring_kill_e,                     FALSE,  FALSE,
7523     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7524   },
7525   {
7526     Yspring_kill_eB,                    FALSE,  TRUE,
7527     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7528   },
7529   {
7530     Yspring_kill_w,                     FALSE,  FALSE,
7531     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7532   },
7533   {
7534     Yspring_kill_wB,                    FALSE,  TRUE,
7535     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7536   },
7537   {
7538     Xeater_n,                           TRUE,   FALSE,
7539     EL_YAMYAM_UP,                       -1, -1
7540   },
7541   {
7542     Xeater_e,                           TRUE,   FALSE,
7543     EL_YAMYAM_RIGHT,                    -1, -1
7544   },
7545   {
7546     Xeater_w,                           TRUE,   FALSE,
7547     EL_YAMYAM_LEFT,                     -1, -1
7548   },
7549   {
7550     Xeater_s,                           TRUE,   FALSE,
7551     EL_YAMYAM_DOWN,                     -1, -1
7552   },
7553   {
7554     Yeater_n,                           FALSE,  FALSE,
7555     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7556   },
7557   {
7558     Yeater_nB,                          FALSE,  TRUE,
7559     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7560   },
7561   {
7562     Yeater_e,                           FALSE,  FALSE,
7563     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7564   },
7565   {
7566     Yeater_eB,                          FALSE,  TRUE,
7567     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7568   },
7569   {
7570     Yeater_s,                           FALSE,  FALSE,
7571     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7572   },
7573   {
7574     Yeater_sB,                          FALSE,  TRUE,
7575     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7576   },
7577   {
7578     Yeater_w,                           FALSE,  FALSE,
7579     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7580   },
7581   {
7582     Yeater_wB,                          FALSE,  TRUE,
7583     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7584   },
7585   {
7586     Yeater_stone,                       FALSE,  FALSE,
7587     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
7588   },
7589   {
7590     Yeater_spring,                      FALSE,  FALSE,
7591     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
7592   },
7593   {
7594     Xalien,                             TRUE,   FALSE,
7595     EL_ROBOT,                           -1, -1
7596   },
7597   {
7598     Xalien_pause,                       FALSE,  FALSE,
7599     EL_ROBOT,                           -1, -1
7600   },
7601   {
7602     Yalien_n,                           FALSE,  FALSE,
7603     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7604   },
7605   {
7606     Yalien_nB,                          FALSE,  TRUE,
7607     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7608   },
7609   {
7610     Yalien_e,                           FALSE,  FALSE,
7611     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7612   },
7613   {
7614     Yalien_eB,                          FALSE,  TRUE,
7615     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7616   },
7617   {
7618     Yalien_s,                           FALSE,  FALSE,
7619     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7620   },
7621   {
7622     Yalien_sB,                          FALSE,  TRUE,
7623     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7624   },
7625   {
7626     Yalien_w,                           FALSE,  FALSE,
7627     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7628   },
7629   {
7630     Yalien_wB,                          FALSE,  TRUE,
7631     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7632   },
7633   {
7634     Yalien_stone,                       FALSE,  FALSE,
7635     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
7636   },
7637   {
7638     Yalien_spring,                      FALSE,  FALSE,
7639     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
7640   },
7641   {
7642     Xemerald,                           TRUE,   FALSE,
7643     EL_EMERALD,                         -1, -1
7644   },
7645   {
7646     Xemerald_pause,                     FALSE,  FALSE,
7647     EL_EMERALD,                         -1, -1
7648   },
7649   {
7650     Xemerald_fall,                      FALSE,  FALSE,
7651     EL_EMERALD,                         -1, -1
7652   },
7653   {
7654     Xemerald_shine,                     FALSE,  FALSE,
7655     EL_EMERALD,                         ACTION_TWINKLING, -1
7656   },
7657   {
7658     Yemerald_s,                         FALSE,  FALSE,
7659     EL_EMERALD,                         ACTION_FALLING, -1
7660   },
7661   {
7662     Yemerald_sB,                        FALSE,  TRUE,
7663     EL_EMERALD,                         ACTION_FALLING, -1
7664   },
7665   {
7666     Yemerald_e,                         FALSE,  FALSE,
7667     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7668   },
7669   {
7670     Yemerald_eB,                        FALSE,  TRUE,
7671     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7672   },
7673   {
7674     Yemerald_w,                         FALSE,  FALSE,
7675     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7676   },
7677   {
7678     Yemerald_wB,                        FALSE,  TRUE,
7679     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7680   },
7681   {
7682     Yemerald_eat,                       FALSE,  FALSE,
7683     EL_EMERALD,                         ACTION_COLLECTING, -1
7684   },
7685   {
7686     Yemerald_stone,                     FALSE,  FALSE,
7687     EL_NUT,                             ACTION_BREAKING, -1
7688   },
7689   {
7690     Xdiamond,                           TRUE,   FALSE,
7691     EL_DIAMOND,                         -1, -1
7692   },
7693   {
7694     Xdiamond_pause,                     FALSE,  FALSE,
7695     EL_DIAMOND,                         -1, -1
7696   },
7697   {
7698     Xdiamond_fall,                      FALSE,  FALSE,
7699     EL_DIAMOND,                         -1, -1
7700   },
7701   {
7702     Xdiamond_shine,                     FALSE,  FALSE,
7703     EL_DIAMOND,                         ACTION_TWINKLING, -1
7704   },
7705   {
7706     Ydiamond_s,                         FALSE,  FALSE,
7707     EL_DIAMOND,                         ACTION_FALLING, -1
7708   },
7709   {
7710     Ydiamond_sB,                        FALSE,  TRUE,
7711     EL_DIAMOND,                         ACTION_FALLING, -1
7712   },
7713   {
7714     Ydiamond_e,                         FALSE,  FALSE,
7715     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7716   },
7717   {
7718     Ydiamond_eB,                        FALSE,  TRUE,
7719     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7720   },
7721   {
7722     Ydiamond_w,                         FALSE,  FALSE,
7723     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7724   },
7725   {
7726     Ydiamond_wB,                        FALSE,  TRUE,
7727     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7728   },
7729   {
7730     Ydiamond_eat,                       FALSE,  FALSE,
7731     EL_DIAMOND,                         ACTION_COLLECTING, -1
7732   },
7733   {
7734     Ydiamond_stone,                     FALSE,  FALSE,
7735     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
7736   },
7737   {
7738     Xdrip_fall,                         TRUE,   FALSE,
7739     EL_AMOEBA_DROP,                     -1, -1
7740   },
7741   {
7742     Xdrip_stretch,                      FALSE,  FALSE,
7743     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7744   },
7745   {
7746     Xdrip_stretchB,                     FALSE,  TRUE,
7747     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7748   },
7749   {
7750     Xdrip_eat,                          FALSE,  FALSE,
7751     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
7752   },
7753   {
7754     Ydrip_s1,                           FALSE,  FALSE,
7755     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7756   },
7757   {
7758     Ydrip_s1B,                          FALSE,  TRUE,
7759     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7760   },
7761   {
7762     Ydrip_s2,                           FALSE,  FALSE,
7763     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7764   },
7765   {
7766     Ydrip_s2B,                          FALSE,  TRUE,
7767     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7768   },
7769   {
7770     Xbomb,                              TRUE,   FALSE,
7771     EL_BOMB,                            -1, -1
7772   },
7773   {
7774     Xbomb_pause,                        FALSE,  FALSE,
7775     EL_BOMB,                            -1, -1
7776   },
7777   {
7778     Xbomb_fall,                         FALSE,  FALSE,
7779     EL_BOMB,                            -1, -1
7780   },
7781   {
7782     Ybomb_s,                            FALSE,  FALSE,
7783     EL_BOMB,                            ACTION_FALLING, -1
7784   },
7785   {
7786     Ybomb_sB,                           FALSE,  TRUE,
7787     EL_BOMB,                            ACTION_FALLING, -1
7788   },
7789   {
7790     Ybomb_e,                            FALSE,  FALSE,
7791     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
7792   },
7793   {
7794     Ybomb_eB,                           FALSE,  TRUE,
7795     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
7796   },
7797   {
7798     Ybomb_w,                            FALSE,  FALSE,
7799     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
7800   },
7801   {
7802     Ybomb_wB,                           FALSE,  TRUE,
7803     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
7804   },
7805   {
7806     Ybomb_eat,                          FALSE,  FALSE,
7807     EL_BOMB,                            ACTION_ACTIVATING, -1
7808   },
7809   {
7810     Xballoon,                           TRUE,   FALSE,
7811     EL_BALLOON,                         -1, -1
7812   },
7813   {
7814     Yballoon_n,                         FALSE,  FALSE,
7815     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
7816   },
7817   {
7818     Yballoon_nB,                        FALSE,  TRUE,
7819     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
7820   },
7821   {
7822     Yballoon_e,                         FALSE,  FALSE,
7823     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
7824   },
7825   {
7826     Yballoon_eB,                        FALSE,  TRUE,
7827     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
7828   },
7829   {
7830     Yballoon_s,                         FALSE,  FALSE,
7831     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
7832   },
7833   {
7834     Yballoon_sB,                        FALSE,  TRUE,
7835     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
7836   },
7837   {
7838     Yballoon_w,                         FALSE,  FALSE,
7839     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
7840   },
7841   {
7842     Yballoon_wB,                        FALSE,  TRUE,
7843     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
7844   },
7845   {
7846     Xgrass,                             TRUE,   FALSE,
7847     EL_EMC_GRASS,                       -1, -1
7848   },
7849   {
7850     Ygrass_nB,                          FALSE,  FALSE,
7851     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
7852   },
7853   {
7854     Ygrass_eB,                          FALSE,  FALSE,
7855     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
7856   },
7857   {
7858     Ygrass_sB,                          FALSE,  FALSE,
7859     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
7860   },
7861   {
7862     Ygrass_wB,                          FALSE,  FALSE,
7863     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
7864   },
7865   {
7866     Xdirt,                              TRUE,   FALSE,
7867     EL_SAND,                            -1, -1
7868   },
7869   {
7870     Ydirt_nB,                           FALSE,  FALSE,
7871     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
7872   },
7873   {
7874     Ydirt_eB,                           FALSE,  FALSE,
7875     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
7876   },
7877   {
7878     Ydirt_sB,                           FALSE,  FALSE,
7879     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
7880   },
7881   {
7882     Ydirt_wB,                           FALSE,  FALSE,
7883     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
7884   },
7885   {
7886     Xacid_ne,                           TRUE,   FALSE,
7887     EL_ACID_POOL_TOPRIGHT,              -1, -1
7888   },
7889   {
7890     Xacid_se,                           TRUE,   FALSE,
7891     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
7892   },
7893   {
7894     Xacid_s,                            TRUE,   FALSE,
7895     EL_ACID_POOL_BOTTOM,                -1, -1
7896   },
7897   {
7898     Xacid_sw,                           TRUE,   FALSE,
7899     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
7900   },
7901   {
7902     Xacid_nw,                           TRUE,   FALSE,
7903     EL_ACID_POOL_TOPLEFT,               -1, -1
7904   },
7905   {
7906     Xacid_1,                            TRUE,   FALSE,
7907     EL_ACID,                            -1, -1
7908   },
7909   {
7910     Xacid_2,                            FALSE,  FALSE,
7911     EL_ACID,                            -1, -1
7912   },
7913   {
7914     Xacid_3,                            FALSE,  FALSE,
7915     EL_ACID,                            -1, -1
7916   },
7917   {
7918     Xacid_4,                            FALSE,  FALSE,
7919     EL_ACID,                            -1, -1
7920   },
7921   {
7922     Xacid_5,                            FALSE,  FALSE,
7923     EL_ACID,                            -1, -1
7924   },
7925   {
7926     Xacid_6,                            FALSE,  FALSE,
7927     EL_ACID,                            -1, -1
7928   },
7929   {
7930     Xacid_7,                            FALSE,  FALSE,
7931     EL_ACID,                            -1, -1
7932   },
7933   {
7934     Xacid_8,                            FALSE,  FALSE,
7935     EL_ACID,                            -1, -1
7936   },
7937   {
7938     Xball_1,                            TRUE,   FALSE,
7939     EL_EMC_MAGIC_BALL,                  -1, -1
7940   },
7941   {
7942     Xball_1B,                           FALSE,  FALSE,
7943     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
7944   },
7945   {
7946     Xball_2,                            FALSE,  FALSE,
7947     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
7948   },
7949   {
7950     Xball_2B,                           FALSE,  FALSE,
7951     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
7952   },
7953   {
7954     Yball_eat,                          FALSE,  FALSE,
7955     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
7956   },
7957   {
7958     Ykey_1_eat,                         FALSE,  FALSE,
7959     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
7960   },
7961   {
7962     Ykey_2_eat,                         FALSE,  FALSE,
7963     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
7964   },
7965   {
7966     Ykey_3_eat,                         FALSE,  FALSE,
7967     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
7968   },
7969   {
7970     Ykey_4_eat,                         FALSE,  FALSE,
7971     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
7972   },
7973   {
7974     Ykey_5_eat,                         FALSE,  FALSE,
7975     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
7976   },
7977   {
7978     Ykey_6_eat,                         FALSE,  FALSE,
7979     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
7980   },
7981   {
7982     Ykey_7_eat,                         FALSE,  FALSE,
7983     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
7984   },
7985   {
7986     Ykey_8_eat,                         FALSE,  FALSE,
7987     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
7988   },
7989   {
7990     Ylenses_eat,                        FALSE,  FALSE,
7991     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
7992   },
7993   {
7994     Ymagnify_eat,                       FALSE,  FALSE,
7995     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
7996   },
7997   {
7998     Ygrass_eat,                         FALSE,  FALSE,
7999     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
8000   },
8001   {
8002     Ydirt_eat,                          FALSE,  FALSE,
8003     EL_SAND,                            ACTION_SNAPPING, -1
8004   },
8005   {
8006     Xgrow_ns,                           TRUE,   FALSE,
8007     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
8008   },
8009   {
8010     Ygrow_ns_eat,                       FALSE,  FALSE,
8011     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
8012   },
8013   {
8014     Xgrow_ew,                           TRUE,   FALSE,
8015     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
8016   },
8017   {
8018     Ygrow_ew_eat,                       FALSE,  FALSE,
8019     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
8020   },
8021   {
8022     Xwonderwall,                        TRUE,   FALSE,
8023     EL_MAGIC_WALL,                      -1, -1
8024   },
8025   {
8026     XwonderwallB,                       FALSE,  FALSE,
8027     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
8028   },
8029   {
8030     Xamoeba_1,                          TRUE,   FALSE,
8031     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8032   },
8033   {
8034     Xamoeba_2,                          FALSE,  FALSE,
8035     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8036   },
8037   {
8038     Xamoeba_3,                          FALSE,  FALSE,
8039     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8040   },
8041   {
8042     Xamoeba_4,                          FALSE,  FALSE,
8043     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8044   },
8045   {
8046     Xamoeba_5,                          TRUE,   FALSE,
8047     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8048   },
8049   {
8050     Xamoeba_6,                          FALSE,  FALSE,
8051     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8052   },
8053   {
8054     Xamoeba_7,                          FALSE,  FALSE,
8055     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8056   },
8057   {
8058     Xamoeba_8,                          FALSE,  FALSE,
8059     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8060   },
8061   {
8062     Xdoor_1,                            TRUE,   FALSE,
8063     EL_EM_GATE_1,                       -1, -1
8064   },
8065   {
8066     Xdoor_2,                            TRUE,   FALSE,
8067     EL_EM_GATE_2,                       -1, -1
8068   },
8069   {
8070     Xdoor_3,                            TRUE,   FALSE,
8071     EL_EM_GATE_3,                       -1, -1
8072   },
8073   {
8074     Xdoor_4,                            TRUE,   FALSE,
8075     EL_EM_GATE_4,                       -1, -1
8076   },
8077   {
8078     Xdoor_5,                            TRUE,   FALSE,
8079     EL_EMC_GATE_5,                      -1, -1
8080   },
8081   {
8082     Xdoor_6,                            TRUE,   FALSE,
8083     EL_EMC_GATE_6,                      -1, -1
8084   },
8085   {
8086     Xdoor_7,                            TRUE,   FALSE,
8087     EL_EMC_GATE_7,                      -1, -1
8088   },
8089   {
8090     Xdoor_8,                            TRUE,   FALSE,
8091     EL_EMC_GATE_8,                      -1, -1
8092   },
8093   {
8094     Xkey_1,                             TRUE,   FALSE,
8095     EL_EM_KEY_1,                        -1, -1
8096   },
8097   {
8098     Xkey_2,                             TRUE,   FALSE,
8099     EL_EM_KEY_2,                        -1, -1
8100   },
8101   {
8102     Xkey_3,                             TRUE,   FALSE,
8103     EL_EM_KEY_3,                        -1, -1
8104   },
8105   {
8106     Xkey_4,                             TRUE,   FALSE,
8107     EL_EM_KEY_4,                        -1, -1
8108   },
8109   {
8110     Xkey_5,                             TRUE,   FALSE,
8111     EL_EMC_KEY_5,                       -1, -1
8112   },
8113   {
8114     Xkey_6,                             TRUE,   FALSE,
8115     EL_EMC_KEY_6,                       -1, -1
8116   },
8117   {
8118     Xkey_7,                             TRUE,   FALSE,
8119     EL_EMC_KEY_7,                       -1, -1
8120   },
8121   {
8122     Xkey_8,                             TRUE,   FALSE,
8123     EL_EMC_KEY_8,                       -1, -1
8124   },
8125   {
8126     Xwind_n,                            TRUE,   FALSE,
8127     EL_BALLOON_SWITCH_UP,               -1, -1
8128   },
8129   {
8130     Xwind_e,                            TRUE,   FALSE,
8131     EL_BALLOON_SWITCH_RIGHT,            -1, -1
8132   },
8133   {
8134     Xwind_s,                            TRUE,   FALSE,
8135     EL_BALLOON_SWITCH_DOWN,             -1, -1
8136   },
8137   {
8138     Xwind_w,                            TRUE,   FALSE,
8139     EL_BALLOON_SWITCH_LEFT,             -1, -1
8140   },
8141   {
8142     Xwind_nesw,                         TRUE,   FALSE,
8143     EL_BALLOON_SWITCH_ANY,              -1, -1
8144   },
8145   {
8146     Xwind_stop,                         TRUE,   FALSE,
8147     EL_BALLOON_SWITCH_NONE,             -1, -1
8148   },
8149   {
8150     Xexit,                              TRUE,   FALSE,
8151     EL_EM_EXIT_CLOSED,                  -1, -1
8152   },
8153   {
8154     Xexit_1,                            TRUE,   FALSE,
8155     EL_EM_EXIT_OPEN,                    -1, -1
8156   },
8157   {
8158     Xexit_2,                            FALSE,  FALSE,
8159     EL_EM_EXIT_OPEN,                    -1, -1
8160   },
8161   {
8162     Xexit_3,                            FALSE,  FALSE,
8163     EL_EM_EXIT_OPEN,                    -1, -1
8164   },
8165   {
8166     Xdynamite,                          TRUE,   FALSE,
8167     EL_EM_DYNAMITE,                     -1, -1
8168   },
8169   {
8170     Ydynamite_eat,                      FALSE,  FALSE,
8171     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
8172   },
8173   {
8174     Xdynamite_1,                        TRUE,   FALSE,
8175     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8176   },
8177   {
8178     Xdynamite_2,                        FALSE,  FALSE,
8179     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8180   },
8181   {
8182     Xdynamite_3,                        FALSE,  FALSE,
8183     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8184   },
8185   {
8186     Xdynamite_4,                        FALSE,  FALSE,
8187     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8188   },
8189   {
8190     Xbumper,                            TRUE,   FALSE,
8191     EL_EMC_SPRING_BUMPER,               -1, -1
8192   },
8193   {
8194     XbumperB,                           FALSE,  FALSE,
8195     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
8196   },
8197   {
8198     Xwheel,                             TRUE,   FALSE,
8199     EL_ROBOT_WHEEL,                     -1, -1
8200   },
8201   {
8202     XwheelB,                            FALSE,  FALSE,
8203     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
8204   },
8205   {
8206     Xswitch,                            TRUE,   FALSE,
8207     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
8208   },
8209   {
8210     XswitchB,                           FALSE,  FALSE,
8211     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
8212   },
8213   {
8214     Xsand,                              TRUE,   FALSE,
8215     EL_QUICKSAND_EMPTY,                 -1, -1
8216   },
8217   {
8218     Xsand_stone,                        TRUE,   FALSE,
8219     EL_QUICKSAND_FULL,                  -1, -1
8220   },
8221   {
8222     Xsand_stonein_1,                    FALSE,  TRUE,
8223     EL_ROCK,                            ACTION_FILLING, -1
8224   },
8225   {
8226     Xsand_stonein_2,                    FALSE,  TRUE,
8227     EL_ROCK,                            ACTION_FILLING, -1
8228   },
8229   {
8230     Xsand_stonein_3,                    FALSE,  TRUE,
8231     EL_ROCK,                            ACTION_FILLING, -1
8232   },
8233   {
8234     Xsand_stonein_4,                    FALSE,  TRUE,
8235     EL_ROCK,                            ACTION_FILLING, -1
8236   },
8237 #if 1
8238   {
8239     Xsand_stonesand_1,                  FALSE,  FALSE,
8240     EL_QUICKSAND_EMPTYING,              -1, -1
8241   },
8242   {
8243     Xsand_stonesand_2,                  FALSE,  FALSE,
8244     EL_QUICKSAND_EMPTYING,              -1, -1
8245   },
8246   {
8247     Xsand_stonesand_3,                  FALSE,  FALSE,
8248     EL_QUICKSAND_EMPTYING,              -1, -1
8249   },
8250   {
8251     Xsand_stonesand_4,                  FALSE,  FALSE,
8252     EL_QUICKSAND_EMPTYING,              -1, -1
8253   },
8254   {
8255     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
8256     EL_QUICKSAND_EMPTYING,              -1, -1
8257   },
8258   {
8259     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
8260     EL_QUICKSAND_EMPTYING,              -1, -1
8261   },
8262 #else
8263   {
8264     Xsand_stonesand_1,                  FALSE,  FALSE,
8265     EL_QUICKSAND_FULL,                  -1, -1
8266   },
8267   {
8268     Xsand_stonesand_2,                  FALSE,  FALSE,
8269     EL_QUICKSAND_FULL,                  -1, -1
8270   },
8271   {
8272     Xsand_stonesand_3,                  FALSE,  FALSE,
8273     EL_QUICKSAND_FULL,                  -1, -1
8274   },
8275   {
8276     Xsand_stonesand_4,                  FALSE,  FALSE,
8277     EL_QUICKSAND_FULL,                  -1, -1
8278   },
8279 #endif
8280   {
8281     Xsand_stoneout_1,                   FALSE,  FALSE,
8282     EL_ROCK,                            ACTION_EMPTYING, -1
8283   },
8284   {
8285     Xsand_stoneout_2,                   FALSE,  FALSE,
8286     EL_ROCK,                            ACTION_EMPTYING, -1
8287   },
8288 #if 1
8289   {
8290     Xsand_sandstone_1,                  FALSE,  FALSE,
8291     EL_QUICKSAND_FILLING,               -1, -1
8292   },
8293   {
8294     Xsand_sandstone_2,                  FALSE,  FALSE,
8295     EL_QUICKSAND_FILLING,               -1, -1
8296   },
8297   {
8298     Xsand_sandstone_3,                  FALSE,  FALSE,
8299     EL_QUICKSAND_FILLING,               -1, -1
8300   },
8301   {
8302     Xsand_sandstone_4,                  FALSE,  FALSE,
8303     EL_QUICKSAND_FILLING,               -1, -1
8304   },
8305 #else
8306   {
8307     Xsand_sandstone_1,                  FALSE,  FALSE,
8308     EL_QUICKSAND_FULL,                  -1, -1
8309   },
8310   {
8311     Xsand_sandstone_2,                  FALSE,  FALSE,
8312     EL_QUICKSAND_FULL,                  -1, -1
8313   },
8314   {
8315     Xsand_sandstone_3,                  FALSE,  FALSE,
8316     EL_QUICKSAND_FULL,                  -1, -1
8317   },
8318   {
8319     Xsand_sandstone_4,                  FALSE,  FALSE,
8320     EL_QUICKSAND_FULL,                  -1, -1
8321   },
8322 #endif
8323   {
8324     Xplant,                             TRUE,   FALSE,
8325     EL_EMC_PLANT,                       -1, -1
8326   },
8327   {
8328     Yplant,                             FALSE,  FALSE,
8329     EL_EMC_PLANT,                       -1, -1
8330   },
8331   {
8332     Xlenses,                            TRUE,   FALSE,
8333     EL_EMC_LENSES,                      -1, -1
8334   },
8335   {
8336     Xmagnify,                           TRUE,   FALSE,
8337     EL_EMC_MAGNIFIER,                   -1, -1
8338   },
8339   {
8340     Xdripper,                           TRUE,   FALSE,
8341     EL_EMC_DRIPPER,                     -1, -1
8342   },
8343   {
8344     XdripperB,                          FALSE,  FALSE,
8345     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
8346   },
8347   {
8348     Xfake_blank,                        TRUE,   FALSE,
8349     EL_INVISIBLE_WALL,                  -1, -1
8350   },
8351   {
8352     Xfake_blankB,                       FALSE,  FALSE,
8353     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
8354   },
8355   {
8356     Xfake_grass,                        TRUE,   FALSE,
8357     EL_EMC_FAKE_GRASS,                  -1, -1
8358   },
8359   {
8360     Xfake_grassB,                       FALSE,  FALSE,
8361     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
8362   },
8363   {
8364     Xfake_door_1,                       TRUE,   FALSE,
8365     EL_EM_GATE_1_GRAY,                  -1, -1
8366   },
8367   {
8368     Xfake_door_2,                       TRUE,   FALSE,
8369     EL_EM_GATE_2_GRAY,                  -1, -1
8370   },
8371   {
8372     Xfake_door_3,                       TRUE,   FALSE,
8373     EL_EM_GATE_3_GRAY,                  -1, -1
8374   },
8375   {
8376     Xfake_door_4,                       TRUE,   FALSE,
8377     EL_EM_GATE_4_GRAY,                  -1, -1
8378   },
8379   {
8380     Xfake_door_5,                       TRUE,   FALSE,
8381     EL_EMC_GATE_5_GRAY,                 -1, -1
8382   },
8383   {
8384     Xfake_door_6,                       TRUE,   FALSE,
8385     EL_EMC_GATE_6_GRAY,                 -1, -1
8386   },
8387   {
8388     Xfake_door_7,                       TRUE,   FALSE,
8389     EL_EMC_GATE_7_GRAY,                 -1, -1
8390   },
8391   {
8392     Xfake_door_8,                       TRUE,   FALSE,
8393     EL_EMC_GATE_8_GRAY,                 -1, -1
8394   },
8395   {
8396     Xfake_acid_1,                       TRUE,   FALSE,
8397     EL_EMC_FAKE_ACID,                   -1, -1
8398   },
8399   {
8400     Xfake_acid_2,                       FALSE,  FALSE,
8401     EL_EMC_FAKE_ACID,                   -1, -1
8402   },
8403   {
8404     Xfake_acid_3,                       FALSE,  FALSE,
8405     EL_EMC_FAKE_ACID,                   -1, -1
8406   },
8407   {
8408     Xfake_acid_4,                       FALSE,  FALSE,
8409     EL_EMC_FAKE_ACID,                   -1, -1
8410   },
8411   {
8412     Xfake_acid_5,                       FALSE,  FALSE,
8413     EL_EMC_FAKE_ACID,                   -1, -1
8414   },
8415   {
8416     Xfake_acid_6,                       FALSE,  FALSE,
8417     EL_EMC_FAKE_ACID,                   -1, -1
8418   },
8419   {
8420     Xfake_acid_7,                       FALSE,  FALSE,
8421     EL_EMC_FAKE_ACID,                   -1, -1
8422   },
8423   {
8424     Xfake_acid_8,                       FALSE,  FALSE,
8425     EL_EMC_FAKE_ACID,                   -1, -1
8426   },
8427   {
8428     Xsteel_1,                           TRUE,   FALSE,
8429     EL_STEELWALL,                       -1, -1
8430   },
8431   {
8432     Xsteel_2,                           TRUE,   FALSE,
8433     EL_EMC_STEELWALL_2,                 -1, -1
8434   },
8435   {
8436     Xsteel_3,                           TRUE,   FALSE,
8437     EL_EMC_STEELWALL_3,                 -1, -1
8438   },
8439   {
8440     Xsteel_4,                           TRUE,   FALSE,
8441     EL_EMC_STEELWALL_4,                 -1, -1
8442   },
8443   {
8444     Xwall_1,                            TRUE,   FALSE,
8445     EL_WALL,                            -1, -1
8446   },
8447   {
8448     Xwall_2,                            TRUE,   FALSE,
8449     EL_EMC_WALL_14,                     -1, -1
8450   },
8451   {
8452     Xwall_3,                            TRUE,   FALSE,
8453     EL_EMC_WALL_15,                     -1, -1
8454   },
8455   {
8456     Xwall_4,                            TRUE,   FALSE,
8457     EL_EMC_WALL_16,                     -1, -1
8458   },
8459   {
8460     Xround_wall_1,                      TRUE,   FALSE,
8461     EL_WALL_SLIPPERY,                   -1, -1
8462   },
8463   {
8464     Xround_wall_2,                      TRUE,   FALSE,
8465     EL_EMC_WALL_SLIPPERY_2,             -1, -1
8466   },
8467   {
8468     Xround_wall_3,                      TRUE,   FALSE,
8469     EL_EMC_WALL_SLIPPERY_3,             -1, -1
8470   },
8471   {
8472     Xround_wall_4,                      TRUE,   FALSE,
8473     EL_EMC_WALL_SLIPPERY_4,             -1, -1
8474   },
8475   {
8476     Xdecor_1,                           TRUE,   FALSE,
8477     EL_EMC_WALL_8,                      -1, -1
8478   },
8479   {
8480     Xdecor_2,                           TRUE,   FALSE,
8481     EL_EMC_WALL_6,                      -1, -1
8482   },
8483   {
8484     Xdecor_3,                           TRUE,   FALSE,
8485     EL_EMC_WALL_4,                      -1, -1
8486   },
8487   {
8488     Xdecor_4,                           TRUE,   FALSE,
8489     EL_EMC_WALL_7,                      -1, -1
8490   },
8491   {
8492     Xdecor_5,                           TRUE,   FALSE,
8493     EL_EMC_WALL_5,                      -1, -1
8494   },
8495   {
8496     Xdecor_6,                           TRUE,   FALSE,
8497     EL_EMC_WALL_9,                      -1, -1
8498   },
8499   {
8500     Xdecor_7,                           TRUE,   FALSE,
8501     EL_EMC_WALL_10,                     -1, -1
8502   },
8503   {
8504     Xdecor_8,                           TRUE,   FALSE,
8505     EL_EMC_WALL_1,                      -1, -1
8506   },
8507   {
8508     Xdecor_9,                           TRUE,   FALSE,
8509     EL_EMC_WALL_2,                      -1, -1
8510   },
8511   {
8512     Xdecor_10,                          TRUE,   FALSE,
8513     EL_EMC_WALL_3,                      -1, -1
8514   },
8515   {
8516     Xdecor_11,                          TRUE,   FALSE,
8517     EL_EMC_WALL_11,                     -1, -1
8518   },
8519   {
8520     Xdecor_12,                          TRUE,   FALSE,
8521     EL_EMC_WALL_12,                     -1, -1
8522   },
8523   {
8524     Xalpha_0,                           TRUE,   FALSE,
8525     EL_CHAR('0'),                       -1, -1
8526   },
8527   {
8528     Xalpha_1,                           TRUE,   FALSE,
8529     EL_CHAR('1'),                       -1, -1
8530   },
8531   {
8532     Xalpha_2,                           TRUE,   FALSE,
8533     EL_CHAR('2'),                       -1, -1
8534   },
8535   {
8536     Xalpha_3,                           TRUE,   FALSE,
8537     EL_CHAR('3'),                       -1, -1
8538   },
8539   {
8540     Xalpha_4,                           TRUE,   FALSE,
8541     EL_CHAR('4'),                       -1, -1
8542   },
8543   {
8544     Xalpha_5,                           TRUE,   FALSE,
8545     EL_CHAR('5'),                       -1, -1
8546   },
8547   {
8548     Xalpha_6,                           TRUE,   FALSE,
8549     EL_CHAR('6'),                       -1, -1
8550   },
8551   {
8552     Xalpha_7,                           TRUE,   FALSE,
8553     EL_CHAR('7'),                       -1, -1
8554   },
8555   {
8556     Xalpha_8,                           TRUE,   FALSE,
8557     EL_CHAR('8'),                       -1, -1
8558   },
8559   {
8560     Xalpha_9,                           TRUE,   FALSE,
8561     EL_CHAR('9'),                       -1, -1
8562   },
8563   {
8564     Xalpha_excla,                       TRUE,   FALSE,
8565     EL_CHAR('!'),                       -1, -1
8566   },
8567   {
8568     Xalpha_quote,                       TRUE,   FALSE,
8569     EL_CHAR('"'),                       -1, -1
8570   },
8571   {
8572     Xalpha_comma,                       TRUE,   FALSE,
8573     EL_CHAR(','),                       -1, -1
8574   },
8575   {
8576     Xalpha_minus,                       TRUE,   FALSE,
8577     EL_CHAR('-'),                       -1, -1
8578   },
8579   {
8580     Xalpha_perio,                       TRUE,   FALSE,
8581     EL_CHAR('.'),                       -1, -1
8582   },
8583   {
8584     Xalpha_colon,                       TRUE,   FALSE,
8585     EL_CHAR(':'),                       -1, -1
8586   },
8587   {
8588     Xalpha_quest,                       TRUE,   FALSE,
8589     EL_CHAR('?'),                       -1, -1
8590   },
8591   {
8592     Xalpha_a,                           TRUE,   FALSE,
8593     EL_CHAR('A'),                       -1, -1
8594   },
8595   {
8596     Xalpha_b,                           TRUE,   FALSE,
8597     EL_CHAR('B'),                       -1, -1
8598   },
8599   {
8600     Xalpha_c,                           TRUE,   FALSE,
8601     EL_CHAR('C'),                       -1, -1
8602   },
8603   {
8604     Xalpha_d,                           TRUE,   FALSE,
8605     EL_CHAR('D'),                       -1, -1
8606   },
8607   {
8608     Xalpha_e,                           TRUE,   FALSE,
8609     EL_CHAR('E'),                       -1, -1
8610   },
8611   {
8612     Xalpha_f,                           TRUE,   FALSE,
8613     EL_CHAR('F'),                       -1, -1
8614   },
8615   {
8616     Xalpha_g,                           TRUE,   FALSE,
8617     EL_CHAR('G'),                       -1, -1
8618   },
8619   {
8620     Xalpha_h,                           TRUE,   FALSE,
8621     EL_CHAR('H'),                       -1, -1
8622   },
8623   {
8624     Xalpha_i,                           TRUE,   FALSE,
8625     EL_CHAR('I'),                       -1, -1
8626   },
8627   {
8628     Xalpha_j,                           TRUE,   FALSE,
8629     EL_CHAR('J'),                       -1, -1
8630   },
8631   {
8632     Xalpha_k,                           TRUE,   FALSE,
8633     EL_CHAR('K'),                       -1, -1
8634   },
8635   {
8636     Xalpha_l,                           TRUE,   FALSE,
8637     EL_CHAR('L'),                       -1, -1
8638   },
8639   {
8640     Xalpha_m,                           TRUE,   FALSE,
8641     EL_CHAR('M'),                       -1, -1
8642   },
8643   {
8644     Xalpha_n,                           TRUE,   FALSE,
8645     EL_CHAR('N'),                       -1, -1
8646   },
8647   {
8648     Xalpha_o,                           TRUE,   FALSE,
8649     EL_CHAR('O'),                       -1, -1
8650   },
8651   {
8652     Xalpha_p,                           TRUE,   FALSE,
8653     EL_CHAR('P'),                       -1, -1
8654   },
8655   {
8656     Xalpha_q,                           TRUE,   FALSE,
8657     EL_CHAR('Q'),                       -1, -1
8658   },
8659   {
8660     Xalpha_r,                           TRUE,   FALSE,
8661     EL_CHAR('R'),                       -1, -1
8662   },
8663   {
8664     Xalpha_s,                           TRUE,   FALSE,
8665     EL_CHAR('S'),                       -1, -1
8666   },
8667   {
8668     Xalpha_t,                           TRUE,   FALSE,
8669     EL_CHAR('T'),                       -1, -1
8670   },
8671   {
8672     Xalpha_u,                           TRUE,   FALSE,
8673     EL_CHAR('U'),                       -1, -1
8674   },
8675   {
8676     Xalpha_v,                           TRUE,   FALSE,
8677     EL_CHAR('V'),                       -1, -1
8678   },
8679   {
8680     Xalpha_w,                           TRUE,   FALSE,
8681     EL_CHAR('W'),                       -1, -1
8682   },
8683   {
8684     Xalpha_x,                           TRUE,   FALSE,
8685     EL_CHAR('X'),                       -1, -1
8686   },
8687   {
8688     Xalpha_y,                           TRUE,   FALSE,
8689     EL_CHAR('Y'),                       -1, -1
8690   },
8691   {
8692     Xalpha_z,                           TRUE,   FALSE,
8693     EL_CHAR('Z'),                       -1, -1
8694   },
8695   {
8696     Xalpha_arrow_e,                     TRUE,   FALSE,
8697     EL_CHAR('>'),                       -1, -1
8698   },
8699   {
8700     Xalpha_arrow_w,                     TRUE,   FALSE,
8701     EL_CHAR('<'),                       -1, -1
8702   },
8703   {
8704     Xalpha_copyr,                       TRUE,   FALSE,
8705     EL_CHAR('©'),                       -1, -1
8706   },
8707
8708   {
8709     Xboom_bug,                          FALSE,  FALSE,
8710     EL_BUG,                             ACTION_EXPLODING, -1
8711   },
8712   {
8713     Xboom_bomb,                         FALSE,  FALSE,
8714     EL_BOMB,                            ACTION_EXPLODING, -1
8715   },
8716   {
8717     Xboom_android,                      FALSE,  FALSE,
8718     EL_EMC_ANDROID,                     ACTION_OTHER, -1
8719   },
8720   {
8721     Xboom_1,                            FALSE,  FALSE,
8722     EL_DEFAULT,                         ACTION_EXPLODING, -1
8723   },
8724   {
8725     Xboom_2,                            FALSE,  FALSE,
8726     EL_DEFAULT,                         ACTION_EXPLODING, -1
8727   },
8728   {
8729     Znormal,                            FALSE,  FALSE,
8730     EL_EMPTY,                           -1, -1
8731   },
8732   {
8733     Zdynamite,                          FALSE,  FALSE,
8734     EL_EMPTY,                           -1, -1
8735   },
8736   {
8737     Zplayer,                            FALSE,  FALSE,
8738     EL_EMPTY,                           -1, -1
8739   },
8740   {
8741     ZBORDER,                            FALSE,  FALSE,
8742     EL_EMPTY,                           -1, -1
8743   },
8744
8745   {
8746     -1,                                 FALSE,  FALSE,
8747     -1,                                 -1, -1
8748   }
8749 };
8750
8751 static struct Mapping_EM_to_RND_player
8752 {
8753   int action_em;
8754   int player_nr;
8755
8756   int element_rnd;
8757   int action;
8758   int direction;
8759 }
8760 em_player_mapping_list[] =
8761 {
8762   {
8763     SPR_walk + 0,                       0,
8764     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
8765   },
8766   {
8767     SPR_walk + 1,                       0,
8768     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
8769   },
8770   {
8771     SPR_walk + 2,                       0,
8772     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
8773   },
8774   {
8775     SPR_walk + 3,                       0,
8776     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
8777   },
8778   {
8779     SPR_push + 0,                       0,
8780     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
8781   },
8782   {
8783     SPR_push + 1,                       0,
8784     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
8785   },
8786   {
8787     SPR_push + 2,                       0,
8788     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
8789   },
8790   {
8791     SPR_push + 3,                       0,
8792     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
8793   },
8794   {
8795     SPR_spray + 0,                      0,
8796     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
8797   },
8798   {
8799     SPR_spray + 1,                      0,
8800     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8801   },
8802   {
8803     SPR_spray + 2,                      0,
8804     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
8805   },
8806   {
8807     SPR_spray + 3,                      0,
8808     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
8809   },
8810   {
8811     SPR_walk + 0,                       1,
8812     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
8813   },
8814   {
8815     SPR_walk + 1,                       1,
8816     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
8817   },
8818   {
8819     SPR_walk + 2,                       1,
8820     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
8821   },
8822   {
8823     SPR_walk + 3,                       1,
8824     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
8825   },
8826   {
8827     SPR_push + 0,                       1,
8828     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
8829   },
8830   {
8831     SPR_push + 1,                       1,
8832     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
8833   },
8834   {
8835     SPR_push + 2,                       1,
8836     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
8837   },
8838   {
8839     SPR_push + 3,                       1,
8840     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
8841   },
8842   {
8843     SPR_spray + 0,                      1,
8844     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
8845   },
8846   {
8847     SPR_spray + 1,                      1,
8848     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8849   },
8850   {
8851     SPR_spray + 2,                      1,
8852     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
8853   },
8854   {
8855     SPR_spray + 3,                      1,
8856     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
8857   },
8858   {
8859     SPR_still,                          0,
8860     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
8861   },
8862   {
8863     SPR_still,                          1,
8864     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
8865   },
8866   {
8867     SPR_walk + 0,                       2,
8868     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
8869   },
8870   {
8871     SPR_walk + 1,                       2,
8872     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
8873   },
8874   {
8875     SPR_walk + 2,                       2,
8876     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
8877   },
8878   {
8879     SPR_walk + 3,                       2,
8880     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
8881   },
8882   {
8883     SPR_push + 0,                       2,
8884     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
8885   },
8886   {
8887     SPR_push + 1,                       2,
8888     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
8889   },
8890   {
8891     SPR_push + 2,                       2,
8892     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
8893   },
8894   {
8895     SPR_push + 3,                       2,
8896     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
8897   },
8898   {
8899     SPR_spray + 0,                      2,
8900     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
8901   },
8902   {
8903     SPR_spray + 1,                      2,
8904     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8905   },
8906   {
8907     SPR_spray + 2,                      2,
8908     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
8909   },
8910   {
8911     SPR_spray + 3,                      2,
8912     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
8913   },
8914   {
8915     SPR_walk + 0,                       3,
8916     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
8917   },
8918   {
8919     SPR_walk + 1,                       3,
8920     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
8921   },
8922   {
8923     SPR_walk + 2,                       3,
8924     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
8925   },
8926   {
8927     SPR_walk + 3,                       3,
8928     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
8929   },
8930   {
8931     SPR_push + 0,                       3,
8932     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
8933   },
8934   {
8935     SPR_push + 1,                       3,
8936     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
8937   },
8938   {
8939     SPR_push + 2,                       3,
8940     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
8941   },
8942   {
8943     SPR_push + 3,                       3,
8944     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
8945   },
8946   {
8947     SPR_spray + 0,                      3,
8948     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
8949   },
8950   {
8951     SPR_spray + 1,                      3,
8952     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8953   },
8954   {
8955     SPR_spray + 2,                      3,
8956     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
8957   },
8958   {
8959     SPR_spray + 3,                      3,
8960     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
8961   },
8962   {
8963     SPR_still,                          2,
8964     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
8965   },
8966   {
8967     SPR_still,                          3,
8968     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
8969   },
8970
8971   {
8972     -1,                                 -1,
8973     -1,                                 -1, -1
8974   }
8975 };
8976
8977 int map_element_RND_to_EM(int element_rnd)
8978 {
8979   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
8980   static boolean mapping_initialized = FALSE;
8981
8982   if (!mapping_initialized)
8983   {
8984     int i;
8985
8986     /* return "Xalpha_quest" for all undefined elements in mapping array */
8987     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8988       mapping_RND_to_EM[i] = Xalpha_quest;
8989
8990     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8991       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
8992         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
8993           em_object_mapping_list[i].element_em;
8994
8995     mapping_initialized = TRUE;
8996   }
8997
8998   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
8999     return mapping_RND_to_EM[element_rnd];
9000
9001   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9002
9003   return EL_UNKNOWN;
9004 }
9005
9006 int map_element_EM_to_RND(int element_em)
9007 {
9008   static unsigned short mapping_EM_to_RND[TILE_MAX];
9009   static boolean mapping_initialized = FALSE;
9010
9011   if (!mapping_initialized)
9012   {
9013     int i;
9014
9015     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9016     for (i = 0; i < TILE_MAX; i++)
9017       mapping_EM_to_RND[i] = EL_UNKNOWN;
9018
9019     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9020       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9021         em_object_mapping_list[i].element_rnd;
9022
9023     mapping_initialized = TRUE;
9024   }
9025
9026   if (element_em >= 0 && element_em < TILE_MAX)
9027     return mapping_EM_to_RND[element_em];
9028
9029   Error(ERR_WARN, "invalid EM level element %d", element_em);
9030
9031   return EL_UNKNOWN;
9032 }
9033
9034 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9035 {
9036   struct LevelInfo_EM *level_em = level->native_em_level;
9037   struct LEVEL *lev = level_em->lev;
9038   int i, j;
9039
9040   for (i = 0; i < TILE_MAX; i++)
9041     lev->android_array[i] = Xblank;
9042
9043   for (i = 0; i < level->num_android_clone_elements; i++)
9044   {
9045     int element_rnd = level->android_clone_element[i];
9046     int element_em = map_element_RND_to_EM(element_rnd);
9047
9048     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9049       if (em_object_mapping_list[j].element_rnd == element_rnd)
9050         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9051   }
9052 }
9053
9054 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9055 {
9056   struct LevelInfo_EM *level_em = level->native_em_level;
9057   struct LEVEL *lev = level_em->lev;
9058   int i, j;
9059
9060   level->num_android_clone_elements = 0;
9061
9062   for (i = 0; i < TILE_MAX; i++)
9063   {
9064     int element_em = lev->android_array[i];
9065     int element_rnd;
9066     boolean element_found = FALSE;
9067
9068     if (element_em == Xblank)
9069       continue;
9070
9071     element_rnd = map_element_EM_to_RND(element_em);
9072
9073     for (j = 0; j < level->num_android_clone_elements; j++)
9074       if (level->android_clone_element[j] == element_rnd)
9075         element_found = TRUE;
9076
9077     if (!element_found)
9078     {
9079       level->android_clone_element[level->num_android_clone_elements++] =
9080         element_rnd;
9081
9082       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9083         break;
9084     }
9085   }
9086
9087   if (level->num_android_clone_elements == 0)
9088   {
9089     level->num_android_clone_elements = 1;
9090     level->android_clone_element[0] = EL_EMPTY;
9091   }
9092 }
9093
9094 int map_direction_RND_to_EM(int direction)
9095 {
9096   return (direction == MV_UP    ? 0 :
9097           direction == MV_RIGHT ? 1 :
9098           direction == MV_DOWN  ? 2 :
9099           direction == MV_LEFT  ? 3 :
9100           -1);
9101 }
9102
9103 int map_direction_EM_to_RND(int direction)
9104 {
9105   return (direction == 0 ? MV_UP    :
9106           direction == 1 ? MV_RIGHT :
9107           direction == 2 ? MV_DOWN  :
9108           direction == 3 ? MV_LEFT  :
9109           MV_NONE);
9110 }
9111
9112 int map_element_RND_to_SP(int element_rnd)
9113 {
9114   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
9115
9116   if (element_rnd >= EL_SP_START &&
9117       element_rnd <= EL_SP_END)
9118     element_sp = element_rnd - EL_SP_START;
9119   else if (element_rnd == EL_EMPTY_SPACE)
9120     element_sp = 0x00;
9121   else if (element_rnd == EL_INVISIBLE_WALL)
9122     element_sp = 0x28;
9123
9124   return element_sp;
9125 }
9126
9127 int map_element_SP_to_RND(int element_sp)
9128 {
9129   int element_rnd = EL_UNKNOWN;
9130
9131   if (element_sp >= 0x00 &&
9132       element_sp <= 0x27)
9133     element_rnd = EL_SP_START + element_sp;
9134   else if (element_sp == 0x28)
9135     element_rnd = EL_INVISIBLE_WALL;
9136
9137   return element_rnd;
9138 }
9139
9140 int map_action_SP_to_RND(int action_sp)
9141 {
9142   switch (action_sp)
9143   {
9144     case actActive:             return ACTION_ACTIVE;
9145     case actImpact:             return ACTION_IMPACT;
9146     case actExploding:          return ACTION_EXPLODING;
9147     case actDigging:            return ACTION_DIGGING;
9148     case actSnapping:           return ACTION_SNAPPING;
9149     case actCollecting:         return ACTION_COLLECTING;
9150     case actPassing:            return ACTION_PASSING;
9151     case actPushing:            return ACTION_PUSHING;
9152     case actDropping:           return ACTION_DROPPING;
9153
9154     default:                    return ACTION_DEFAULT;
9155   }
9156 }
9157
9158 int get_next_element(int element)
9159 {
9160   switch (element)
9161   {
9162     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
9163     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
9164     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
9165     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
9166     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
9167     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
9168     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
9169     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
9170     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
9171     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
9172     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
9173
9174     default:                            return element;
9175   }
9176 }
9177
9178 #if 0
9179 int el_act_dir2img(int element, int action, int direction)
9180 {
9181   element = GFX_ELEMENT(element);
9182
9183   if (direction == MV_NONE)
9184     return element_info[element].graphic[action];
9185
9186   direction = MV_DIR_TO_BIT(direction);
9187
9188   return element_info[element].direction_graphic[action][direction];
9189 }
9190 #else
9191 int el_act_dir2img(int element, int action, int direction)
9192 {
9193   element = GFX_ELEMENT(element);
9194   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9195
9196   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9197   return element_info[element].direction_graphic[action][direction];
9198 }
9199 #endif
9200
9201 #if 0
9202 static int el_act_dir2crm(int element, int action, int direction)
9203 {
9204   element = GFX_ELEMENT(element);
9205
9206   if (direction == MV_NONE)
9207     return element_info[element].crumbled[action];
9208
9209   direction = MV_DIR_TO_BIT(direction);
9210
9211   return element_info[element].direction_crumbled[action][direction];
9212 }
9213 #else
9214 static int el_act_dir2crm(int element, int action, int direction)
9215 {
9216   element = GFX_ELEMENT(element);
9217   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9218
9219   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9220   return element_info[element].direction_crumbled[action][direction];
9221 }
9222 #endif
9223
9224 int el_act2img(int element, int action)
9225 {
9226   element = GFX_ELEMENT(element);
9227
9228   return element_info[element].graphic[action];
9229 }
9230
9231 int el_act2crm(int element, int action)
9232 {
9233   element = GFX_ELEMENT(element);
9234
9235   return element_info[element].crumbled[action];
9236 }
9237
9238 int el_dir2img(int element, int direction)
9239 {
9240   element = GFX_ELEMENT(element);
9241
9242   return el_act_dir2img(element, ACTION_DEFAULT, direction);
9243 }
9244
9245 int el2baseimg(int element)
9246 {
9247   return element_info[element].graphic[ACTION_DEFAULT];
9248 }
9249
9250 int el2img(int element)
9251 {
9252   element = GFX_ELEMENT(element);
9253
9254   return element_info[element].graphic[ACTION_DEFAULT];
9255 }
9256
9257 int el2edimg(int element)
9258 {
9259   element = GFX_ELEMENT(element);
9260
9261   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9262 }
9263
9264 int el2preimg(int element)
9265 {
9266   element = GFX_ELEMENT(element);
9267
9268   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9269 }
9270
9271 int el2panelimg(int element)
9272 {
9273   element = GFX_ELEMENT(element);
9274
9275   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9276 }
9277
9278 int font2baseimg(int font_nr)
9279 {
9280   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9281 }
9282
9283 int getBeltNrFromBeltElement(int element)
9284 {
9285   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9286           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9287           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9288 }
9289
9290 int getBeltNrFromBeltActiveElement(int element)
9291 {
9292   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9293           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9294           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9295 }
9296
9297 int getBeltNrFromBeltSwitchElement(int element)
9298 {
9299   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9300           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9301           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9302 }
9303
9304 int getBeltDirNrFromBeltElement(int element)
9305 {
9306   static int belt_base_element[4] =
9307   {
9308     EL_CONVEYOR_BELT_1_LEFT,
9309     EL_CONVEYOR_BELT_2_LEFT,
9310     EL_CONVEYOR_BELT_3_LEFT,
9311     EL_CONVEYOR_BELT_4_LEFT
9312   };
9313
9314   int belt_nr = getBeltNrFromBeltElement(element);
9315   int belt_dir_nr = element - belt_base_element[belt_nr];
9316
9317   return (belt_dir_nr % 3);
9318 }
9319
9320 int getBeltDirNrFromBeltSwitchElement(int element)
9321 {
9322   static int belt_base_element[4] =
9323   {
9324     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9325     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9326     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9327     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9328   };
9329
9330   int belt_nr = getBeltNrFromBeltSwitchElement(element);
9331   int belt_dir_nr = element - belt_base_element[belt_nr];
9332
9333   return (belt_dir_nr % 3);
9334 }
9335
9336 int getBeltDirFromBeltElement(int element)
9337 {
9338   static int belt_move_dir[3] =
9339   {
9340     MV_LEFT,
9341     MV_NONE,
9342     MV_RIGHT
9343   };
9344
9345   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9346
9347   return belt_move_dir[belt_dir_nr];
9348 }
9349
9350 int getBeltDirFromBeltSwitchElement(int element)
9351 {
9352   static int belt_move_dir[3] =
9353   {
9354     MV_LEFT,
9355     MV_NONE,
9356     MV_RIGHT
9357   };
9358
9359   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9360
9361   return belt_move_dir[belt_dir_nr];
9362 }
9363
9364 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9365 {
9366   static int belt_base_element[4] =
9367   {
9368     EL_CONVEYOR_BELT_1_LEFT,
9369     EL_CONVEYOR_BELT_2_LEFT,
9370     EL_CONVEYOR_BELT_3_LEFT,
9371     EL_CONVEYOR_BELT_4_LEFT
9372   };
9373
9374   return belt_base_element[belt_nr] + belt_dir_nr;
9375 }
9376
9377 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9378 {
9379   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9380
9381   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9382 }
9383
9384 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9385 {
9386   static int belt_base_element[4] =
9387   {
9388     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9389     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9390     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9391     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9392   };
9393
9394   return belt_base_element[belt_nr] + belt_dir_nr;
9395 }
9396
9397 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9398 {
9399   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9400
9401   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9402 }
9403
9404 #if 1
9405 boolean getTeamMode_EM()
9406 {
9407   return game.team_mode;
9408 }
9409 #else
9410 int getNumActivePlayers_EM()
9411 {
9412 #if 1
9413   int num_players = 0;
9414   int i;
9415
9416   if (!tape.playing)
9417     return (setup.team_mode ? MAX_PLAYERS : 1);
9418
9419   for (i = 0; i < MAX_PLAYERS; i++)
9420     if (tape.player_participates[i])
9421       num_players++;
9422
9423   return (num_players > 1 ? MAX_PLAYERS : 1);
9424
9425 #else
9426
9427   int num_players = 0;
9428   int i;
9429
9430   /* when recording game, activate all connected players */
9431   if (!tape.playing)
9432     return -1;
9433
9434   for (i = 0; i < MAX_PLAYERS; i++)
9435     if (tape.player_participates[i])
9436       num_players++;
9437
9438   return num_players;
9439 #endif
9440 }
9441 #endif
9442
9443 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9444 {
9445   int game_frame_delay_value;
9446
9447   game_frame_delay_value =
9448     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9449      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9450      GameFrameDelay);
9451
9452   if (tape.playing && tape.warp_forward && !tape.pausing)
9453     game_frame_delay_value = 0;
9454
9455   return game_frame_delay_value;
9456 }
9457
9458 unsigned int InitRND(int seed)
9459 {
9460   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9461     return InitEngineRandom_EM(seed);
9462   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9463     return InitEngineRandom_SP(seed);
9464   else
9465     return InitEngineRandom_RND(seed);
9466 }
9467
9468 #if 1
9469 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9470 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9471 #endif
9472
9473 inline static int get_effective_element_EM(int tile, int frame_em)
9474 {
9475   int element             = object_mapping[tile].element_rnd;
9476   int action              = object_mapping[tile].action;
9477   boolean is_backside     = object_mapping[tile].is_backside;
9478   boolean action_removing = (action == ACTION_DIGGING ||
9479                              action == ACTION_SNAPPING ||
9480                              action == ACTION_COLLECTING);
9481
9482   if (frame_em < 7)
9483   {
9484     switch (tile)
9485     {
9486       case Yacid_splash_eB:
9487       case Yacid_splash_wB:
9488         return (frame_em > 5 ? EL_EMPTY : element);
9489
9490 #if 0
9491         /* !!! FIX !!! */
9492       case Ydiamond_stone:
9493         //  if (!game.use_native_emc_graphics_engine)
9494         return EL_ROCK;
9495 #endif
9496
9497       default:
9498         return element;
9499     }
9500   }
9501   else  /* frame_em == 7 */
9502   {
9503     switch (tile)
9504     {
9505       case Yacid_splash_eB:
9506       case Yacid_splash_wB:
9507         return EL_EMPTY;
9508
9509       case Yemerald_stone:
9510         return EL_EMERALD;
9511
9512       case Ydiamond_stone:
9513         return EL_ROCK;
9514
9515       case Xdrip_stretch:
9516       case Xdrip_stretchB:
9517       case Ydrip_s1:
9518       case Ydrip_s1B:
9519       case Xball_1B:
9520       case Xball_2:
9521       case Xball_2B:
9522       case Yball_eat:
9523       case Ykey_1_eat:
9524       case Ykey_2_eat:
9525       case Ykey_3_eat:
9526       case Ykey_4_eat:
9527       case Ykey_5_eat:
9528       case Ykey_6_eat:
9529       case Ykey_7_eat:
9530       case Ykey_8_eat:
9531       case Ylenses_eat:
9532       case Ymagnify_eat:
9533       case Ygrass_eat:
9534       case Ydirt_eat:
9535       case Xsand_stonein_1:
9536       case Xsand_stonein_2:
9537       case Xsand_stonein_3:
9538       case Xsand_stonein_4:
9539         return element;
9540
9541       default:
9542         return (is_backside || action_removing ? EL_EMPTY : element);
9543     }
9544   }
9545 }
9546
9547 inline static boolean check_linear_animation_EM(int tile)
9548 {
9549   switch (tile)
9550   {
9551     case Xsand_stonesand_1:
9552     case Xsand_stonesand_quickout_1:
9553     case Xsand_sandstone_1:
9554     case Xsand_stonein_1:
9555     case Xsand_stoneout_1:
9556     case Xboom_1:
9557     case Xdynamite_1:
9558     case Ybug_w_n:
9559     case Ybug_n_e:
9560     case Ybug_e_s:
9561     case Ybug_s_w:
9562     case Ybug_e_n:
9563     case Ybug_s_e:
9564     case Ybug_w_s:
9565     case Ybug_n_w:
9566     case Ytank_w_n:
9567     case Ytank_n_e:
9568     case Ytank_e_s:
9569     case Ytank_s_w:
9570     case Ytank_e_n:
9571     case Ytank_s_e:
9572     case Ytank_w_s:
9573     case Ytank_n_w:
9574 #if 1
9575     case Yacid_splash_eB:
9576     case Yacid_splash_wB:
9577     case Yemerald_stone:
9578 #endif
9579       return TRUE;
9580   }
9581
9582   return FALSE;
9583 }
9584
9585 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9586                                             boolean has_crumbled_graphics,
9587                                             int crumbled, int sync_frame)
9588 {
9589   /* if element can be crumbled, but certain action graphics are just empty
9590      space (like instantly snapping sand to empty space in 1 frame), do not
9591      treat these empty space graphics as crumbled graphics in EMC engine */
9592   if (crumbled == IMG_EMPTY_SPACE)
9593     has_crumbled_graphics = FALSE;
9594
9595   if (has_crumbled_graphics)
9596   {
9597     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9598     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9599                                            g_crumbled->anim_delay,
9600                                            g_crumbled->anim_mode,
9601                                            g_crumbled->anim_start_frame,
9602                                            sync_frame);
9603
9604     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9605                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9606
9607     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9608
9609     g_em->has_crumbled_graphics = TRUE;
9610   }
9611   else
9612   {
9613     g_em->crumbled_bitmap = NULL;
9614     g_em->crumbled_src_x = 0;
9615     g_em->crumbled_src_y = 0;
9616     g_em->crumbled_border_size = 0;
9617
9618     g_em->has_crumbled_graphics = FALSE;
9619   }
9620 }
9621
9622 void ResetGfxAnimation_EM(int x, int y, int tile)
9623 {
9624   GfxFrame[x][y] = 0;
9625 }
9626
9627 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9628                         int tile, int frame_em, int x, int y)
9629 {
9630   int action = object_mapping[tile].action;
9631 #if 1
9632   int direction = object_mapping[tile].direction;
9633   int effective_element = get_effective_element_EM(tile, frame_em);
9634   int graphic = (direction == MV_NONE ?
9635                  el_act2img(effective_element, action) :
9636                  el_act_dir2img(effective_element, action, direction));
9637   struct GraphicInfo *g = &graphic_info[graphic];
9638   int sync_frame;
9639 #endif
9640   boolean action_removing = (action == ACTION_DIGGING ||
9641                              action == ACTION_SNAPPING ||
9642                              action == ACTION_COLLECTING);
9643   boolean action_moving   = (action == ACTION_FALLING ||
9644                              action == ACTION_MOVING ||
9645                              action == ACTION_PUSHING ||
9646                              action == ACTION_EATING ||
9647                              action == ACTION_FILLING ||
9648                              action == ACTION_EMPTYING);
9649   boolean action_falling  = (action == ACTION_FALLING ||
9650                              action == ACTION_FILLING ||
9651                              action == ACTION_EMPTYING);
9652
9653   /* special case: graphic uses "2nd movement tile" and has defined
9654      7 frames for movement animation (or less) => use default graphic
9655      for last (8th) frame which ends the movement animation */
9656   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9657   {
9658     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
9659     graphic = (direction == MV_NONE ?
9660                el_act2img(effective_element, action) :
9661                el_act_dir2img(effective_element, action, direction));
9662
9663     g = &graphic_info[graphic];
9664   }
9665
9666 #if 0
9667   if (tile == Xsand_stonesand_1 ||
9668       tile == Xsand_stonesand_2 ||
9669       tile == Xsand_stonesand_3 ||
9670       tile == Xsand_stonesand_4)
9671     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9672 #endif
9673
9674 #if 1
9675   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9676   {
9677     GfxFrame[x][y] = 0;
9678
9679     // printf("::: resetting... [%d]\n", tile);
9680   }
9681 #else
9682   if (action_removing || check_linear_animation_EM(tile))
9683   {
9684     GfxFrame[x][y] = frame_em;
9685
9686     // printf("::: resetting... [%d]\n", tile);
9687   }
9688 #endif
9689   else if (action_moving)
9690   {
9691     boolean is_backside = object_mapping[tile].is_backside;
9692
9693     if (is_backside)
9694     {
9695       int direction = object_mapping[tile].direction;
9696       int move_dir = (action_falling ? MV_DOWN : direction);
9697
9698       GfxFrame[x][y]++;
9699
9700 #if 1
9701       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9702       if (g->double_movement && frame_em == 0)
9703       {
9704         GfxFrame[x][y] = 0;
9705
9706         // printf("::: resetting... [%d]\n", tile);
9707       }
9708 #endif
9709
9710       if (move_dir == MV_LEFT)
9711         GfxFrame[x - 1][y] = GfxFrame[x][y];
9712       else if (move_dir == MV_RIGHT)
9713         GfxFrame[x + 1][y] = GfxFrame[x][y];
9714       else if (move_dir == MV_UP)
9715         GfxFrame[x][y - 1] = GfxFrame[x][y];
9716       else if (move_dir == MV_DOWN)
9717         GfxFrame[x][y + 1] = GfxFrame[x][y];
9718     }
9719   }
9720   else
9721   {
9722     GfxFrame[x][y]++;
9723
9724     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9725     if (tile == Xsand_stonesand_quickout_1 ||
9726         tile == Xsand_stonesand_quickout_2)
9727       GfxFrame[x][y]++;
9728   }
9729
9730 #if 0
9731   if (tile == Xsand_stonesand_1 ||
9732       tile == Xsand_stonesand_2 ||
9733       tile == Xsand_stonesand_3 ||
9734       tile == Xsand_stonesand_4)
9735     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9736 #endif
9737
9738 #if 1
9739   if (graphic_info[graphic].anim_global_sync)
9740     sync_frame = FrameCounter;
9741   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9742     sync_frame = GfxFrame[x][y];
9743   else
9744     sync_frame = 0;     /* playfield border (pseudo steel) */
9745
9746   SetRandomAnimationValue(x, y);
9747
9748   int frame = getAnimationFrame(g->anim_frames,
9749                                 g->anim_delay,
9750                                 g->anim_mode,
9751                                 g->anim_start_frame,
9752                                 sync_frame);
9753
9754   g_em->unique_identifier =
9755     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9756 #endif
9757 }
9758
9759 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9760                                   int tile, int frame_em, int x, int y)
9761 {
9762   int action = object_mapping[tile].action;
9763   int direction = object_mapping[tile].direction;
9764   boolean is_backside = object_mapping[tile].is_backside;
9765   int effective_element = get_effective_element_EM(tile, frame_em);
9766 #if 1
9767   int effective_action = action;
9768 #else
9769   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9770 #endif
9771   int graphic = (direction == MV_NONE ?
9772                  el_act2img(effective_element, effective_action) :
9773                  el_act_dir2img(effective_element, effective_action,
9774                                 direction));
9775   int crumbled = (direction == MV_NONE ?
9776                   el_act2crm(effective_element, effective_action) :
9777                   el_act_dir2crm(effective_element, effective_action,
9778                                  direction));
9779   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9780   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9781   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9782   struct GraphicInfo *g = &graphic_info[graphic];
9783 #if 0
9784   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9785 #endif
9786   int sync_frame;
9787
9788   /* special case: graphic uses "2nd movement tile" and has defined
9789      7 frames for movement animation (or less) => use default graphic
9790      for last (8th) frame which ends the movement animation */
9791   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9792   {
9793     effective_action = ACTION_DEFAULT;
9794     graphic = (direction == MV_NONE ?
9795                el_act2img(effective_element, effective_action) :
9796                el_act_dir2img(effective_element, effective_action,
9797                               direction));
9798     crumbled = (direction == MV_NONE ?
9799                 el_act2crm(effective_element, effective_action) :
9800                 el_act_dir2crm(effective_element, effective_action,
9801                                direction));
9802
9803     g = &graphic_info[graphic];
9804   }
9805
9806 #if 0
9807   if (frame_em == 7)
9808     return;
9809 #endif
9810
9811
9812 #if 0
9813   if (frame_em == 0)    /* reset animation frame for certain elements */
9814   {
9815     if (check_linear_animation_EM(tile))
9816       GfxFrame[x][y] = 0;
9817   }
9818 #endif
9819
9820   if (graphic_info[graphic].anim_global_sync)
9821     sync_frame = FrameCounter;
9822   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9823     sync_frame = GfxFrame[x][y];
9824   else
9825     sync_frame = 0;     /* playfield border (pseudo steel) */
9826
9827   SetRandomAnimationValue(x, y);
9828
9829 #if 0
9830   int i = tile;
9831   int j = frame_em;
9832   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9833                         i == Xdrip_stretchB ? 7 :
9834                         i == Ydrip_s2 ? j + 8 :
9835                         i == Ydrip_s2B ? j + 8 :
9836                         i == Xacid_1 ? 0 :
9837                         i == Xacid_2 ? 10 :
9838                         i == Xacid_3 ? 20 :
9839                         i == Xacid_4 ? 30 :
9840                         i == Xacid_5 ? 40 :
9841                         i == Xacid_6 ? 50 :
9842                         i == Xacid_7 ? 60 :
9843                         i == Xacid_8 ? 70 :
9844                         i == Xfake_acid_1 ? 0 :
9845                         i == Xfake_acid_2 ? 10 :
9846                         i == Xfake_acid_3 ? 20 :
9847                         i == Xfake_acid_4 ? 30 :
9848                         i == Xfake_acid_5 ? 40 :
9849                         i == Xfake_acid_6 ? 50 :
9850                         i == Xfake_acid_7 ? 60 :
9851                         i == Xfake_acid_8 ? 70 :
9852                         i == Xball_2 ? 7 :
9853                         i == Xball_2B ? j + 8 :
9854                         i == Yball_eat ? j + 1 :
9855                         i == Ykey_1_eat ? j + 1 :
9856                         i == Ykey_2_eat ? j + 1 :
9857                         i == Ykey_3_eat ? j + 1 :
9858                         i == Ykey_4_eat ? j + 1 :
9859                         i == Ykey_5_eat ? j + 1 :
9860                         i == Ykey_6_eat ? j + 1 :
9861                         i == Ykey_7_eat ? j + 1 :
9862                         i == Ykey_8_eat ? j + 1 :
9863                         i == Ylenses_eat ? j + 1 :
9864                         i == Ymagnify_eat ? j + 1 :
9865                         i == Ygrass_eat ? j + 1 :
9866                         i == Ydirt_eat ? j + 1 :
9867                         i == Xamoeba_1 ? 0 :
9868                         i == Xamoeba_2 ? 1 :
9869                         i == Xamoeba_3 ? 2 :
9870                         i == Xamoeba_4 ? 3 :
9871                         i == Xamoeba_5 ? 0 :
9872                         i == Xamoeba_6 ? 1 :
9873                         i == Xamoeba_7 ? 2 :
9874                         i == Xamoeba_8 ? 3 :
9875                         i == Xexit_2 ? j + 8 :
9876                         i == Xexit_3 ? j + 16 :
9877                         i == Xdynamite_1 ? 0 :
9878                         i == Xdynamite_2 ? 8 :
9879                         i == Xdynamite_3 ? 16 :
9880                         i == Xdynamite_4 ? 24 :
9881                         i == Xsand_stonein_1 ? j + 1 :
9882                         i == Xsand_stonein_2 ? j + 9 :
9883                         i == Xsand_stonein_3 ? j + 17 :
9884                         i == Xsand_stonein_4 ? j + 25 :
9885                         i == Xsand_stoneout_1 && j == 0 ? 0 :
9886                         i == Xsand_stoneout_1 && j == 1 ? 0 :
9887                         i == Xsand_stoneout_1 && j == 2 ? 1 :
9888                         i == Xsand_stoneout_1 && j == 3 ? 2 :
9889                         i == Xsand_stoneout_1 && j == 4 ? 2 :
9890                         i == Xsand_stoneout_1 && j == 5 ? 3 :
9891                         i == Xsand_stoneout_1 && j == 6 ? 4 :
9892                         i == Xsand_stoneout_1 && j == 7 ? 4 :
9893                         i == Xsand_stoneout_2 && j == 0 ? 5 :
9894                         i == Xsand_stoneout_2 && j == 1 ? 6 :
9895                         i == Xsand_stoneout_2 && j == 2 ? 7 :
9896                         i == Xsand_stoneout_2 && j == 3 ? 8 :
9897                         i == Xsand_stoneout_2 && j == 4 ? 9 :
9898                         i == Xsand_stoneout_2 && j == 5 ? 11 :
9899                         i == Xsand_stoneout_2 && j == 6 ? 13 :
9900                         i == Xsand_stoneout_2 && j == 7 ? 15 :
9901                         i == Xboom_bug && j == 1 ? 2 :
9902                         i == Xboom_bug && j == 2 ? 2 :
9903                         i == Xboom_bug && j == 3 ? 4 :
9904                         i == Xboom_bug && j == 4 ? 4 :
9905                         i == Xboom_bug && j == 5 ? 2 :
9906                         i == Xboom_bug && j == 6 ? 2 :
9907                         i == Xboom_bug && j == 7 ? 0 :
9908                         i == Xboom_bomb && j == 1 ? 2 :
9909                         i == Xboom_bomb && j == 2 ? 2 :
9910                         i == Xboom_bomb && j == 3 ? 4 :
9911                         i == Xboom_bomb && j == 4 ? 4 :
9912                         i == Xboom_bomb && j == 5 ? 2 :
9913                         i == Xboom_bomb && j == 6 ? 2 :
9914                         i == Xboom_bomb && j == 7 ? 0 :
9915                         i == Xboom_android && j == 7 ? 6 :
9916                         i == Xboom_1 && j == 1 ? 2 :
9917                         i == Xboom_1 && j == 2 ? 2 :
9918                         i == Xboom_1 && j == 3 ? 4 :
9919                         i == Xboom_1 && j == 4 ? 4 :
9920                         i == Xboom_1 && j == 5 ? 6 :
9921                         i == Xboom_1 && j == 6 ? 6 :
9922                         i == Xboom_1 && j == 7 ? 8 :
9923                         i == Xboom_2 && j == 0 ? 8 :
9924                         i == Xboom_2 && j == 1 ? 8 :
9925                         i == Xboom_2 && j == 2 ? 10 :
9926                         i == Xboom_2 && j == 3 ? 10 :
9927                         i == Xboom_2 && j == 4 ? 10 :
9928                         i == Xboom_2 && j == 5 ? 12 :
9929                         i == Xboom_2 && j == 6 ? 12 :
9930                         i == Xboom_2 && j == 7 ? 12 :
9931 #if 0
9932                         special_animation && j == 4 ? 3 :
9933                         effective_action != action ? 0 :
9934 #endif
9935                         j);
9936 #endif
9937
9938 #if 0
9939   int xxx_effective_action;
9940   int xxx_has_action_graphics;
9941
9942   {
9943     int element = object_mapping[i].element_rnd;
9944     int action = object_mapping[i].action;
9945     int direction = object_mapping[i].direction;
9946     boolean is_backside = object_mapping[i].is_backside;
9947 #if 0
9948     boolean action_removing = (action == ACTION_DIGGING ||
9949                                action == ACTION_SNAPPING ||
9950                                action == ACTION_COLLECTING);
9951 #endif
9952     boolean action_exploding = ((action == ACTION_EXPLODING ||
9953                                  action == ACTION_SMASHED_BY_ROCK ||
9954                                  action == ACTION_SMASHED_BY_SPRING) &&
9955                                 element != EL_DIAMOND);
9956     boolean action_active = (action == ACTION_ACTIVE);
9957     boolean action_other = (action == ACTION_OTHER);
9958
9959     {
9960 #if 1
9961       int effective_element = get_effective_element_EM(i, j);
9962 #else
9963       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9964                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9965                                j < 7 ? element :
9966                                i == Xdrip_stretch ? element :
9967                                i == Xdrip_stretchB ? element :
9968                                i == Ydrip_s1 ? element :
9969                                i == Ydrip_s1B ? element :
9970                                i == Xball_1B ? element :
9971                                i == Xball_2 ? element :
9972                                i == Xball_2B ? element :
9973                                i == Yball_eat ? element :
9974                                i == Ykey_1_eat ? element :
9975                                i == Ykey_2_eat ? element :
9976                                i == Ykey_3_eat ? element :
9977                                i == Ykey_4_eat ? element :
9978                                i == Ykey_5_eat ? element :
9979                                i == Ykey_6_eat ? element :
9980                                i == Ykey_7_eat ? element :
9981                                i == Ykey_8_eat ? element :
9982                                i == Ylenses_eat ? element :
9983                                i == Ymagnify_eat ? element :
9984                                i == Ygrass_eat ? element :
9985                                i == Ydirt_eat ? element :
9986                                i == Yemerald_stone ? EL_EMERALD :
9987                                i == Ydiamond_stone ? EL_ROCK :
9988                                i == Xsand_stonein_1 ? element :
9989                                i == Xsand_stonein_2 ? element :
9990                                i == Xsand_stonein_3 ? element :
9991                                i == Xsand_stonein_4 ? element :
9992                                is_backside ? EL_EMPTY :
9993                                action_removing ? EL_EMPTY :
9994                                element);
9995 #endif
9996       int effective_action = (j < 7 ? action :
9997                               i == Xdrip_stretch ? action :
9998                               i == Xdrip_stretchB ? action :
9999                               i == Ydrip_s1 ? action :
10000                               i == Ydrip_s1B ? action :
10001                               i == Xball_1B ? action :
10002                               i == Xball_2 ? action :
10003                               i == Xball_2B ? action :
10004                               i == Yball_eat ? action :
10005                               i == Ykey_1_eat ? action :
10006                               i == Ykey_2_eat ? action :
10007                               i == Ykey_3_eat ? action :
10008                               i == Ykey_4_eat ? action :
10009                               i == Ykey_5_eat ? action :
10010                               i == Ykey_6_eat ? action :
10011                               i == Ykey_7_eat ? action :
10012                               i == Ykey_8_eat ? action :
10013                               i == Ylenses_eat ? action :
10014                               i == Ymagnify_eat ? action :
10015                               i == Ygrass_eat ? action :
10016                               i == Ydirt_eat ? action :
10017                               i == Xsand_stonein_1 ? action :
10018                               i == Xsand_stonein_2 ? action :
10019                               i == Xsand_stonein_3 ? action :
10020                               i == Xsand_stonein_4 ? action :
10021                               i == Xsand_stoneout_1 ? action :
10022                               i == Xsand_stoneout_2 ? action :
10023                               i == Xboom_android ? ACTION_EXPLODING :
10024                               action_exploding ? ACTION_EXPLODING :
10025                               action_active ? action :
10026                               action_other ? action :
10027                               ACTION_DEFAULT);
10028       int graphic = (el_act_dir2img(effective_element, effective_action,
10029                                     direction));
10030       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10031                                      direction));
10032       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10033       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10034       boolean has_action_graphics = (graphic != base_graphic);
10035       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10036       struct GraphicInfo *g = &graphic_info[graphic];
10037 #if 0
10038       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10039 #endif
10040       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10041       Bitmap *src_bitmap;
10042       int src_x, src_y;
10043       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10044       boolean special_animation = (action != ACTION_DEFAULT &&
10045                                    g->anim_frames == 3 &&
10046                                    g->anim_delay == 2 &&
10047                                    g->anim_mode & ANIM_LINEAR);
10048       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10049                         i == Xdrip_stretchB ? 7 :
10050                         i == Ydrip_s2 ? j + 8 :
10051                         i == Ydrip_s2B ? j + 8 :
10052                         i == Xacid_1 ? 0 :
10053                         i == Xacid_2 ? 10 :
10054                         i == Xacid_3 ? 20 :
10055                         i == Xacid_4 ? 30 :
10056                         i == Xacid_5 ? 40 :
10057                         i == Xacid_6 ? 50 :
10058                         i == Xacid_7 ? 60 :
10059                         i == Xacid_8 ? 70 :
10060                         i == Xfake_acid_1 ? 0 :
10061                         i == Xfake_acid_2 ? 10 :
10062                         i == Xfake_acid_3 ? 20 :
10063                         i == Xfake_acid_4 ? 30 :
10064                         i == Xfake_acid_5 ? 40 :
10065                         i == Xfake_acid_6 ? 50 :
10066                         i == Xfake_acid_7 ? 60 :
10067                         i == Xfake_acid_8 ? 70 :
10068                         i == Xball_2 ? 7 :
10069                         i == Xball_2B ? j + 8 :
10070                         i == Yball_eat ? j + 1 :
10071                         i == Ykey_1_eat ? j + 1 :
10072                         i == Ykey_2_eat ? j + 1 :
10073                         i == Ykey_3_eat ? j + 1 :
10074                         i == Ykey_4_eat ? j + 1 :
10075                         i == Ykey_5_eat ? j + 1 :
10076                         i == Ykey_6_eat ? j + 1 :
10077                         i == Ykey_7_eat ? j + 1 :
10078                         i == Ykey_8_eat ? j + 1 :
10079                         i == Ylenses_eat ? j + 1 :
10080                         i == Ymagnify_eat ? j + 1 :
10081                         i == Ygrass_eat ? j + 1 :
10082                         i == Ydirt_eat ? j + 1 :
10083                         i == Xamoeba_1 ? 0 :
10084                         i == Xamoeba_2 ? 1 :
10085                         i == Xamoeba_3 ? 2 :
10086                         i == Xamoeba_4 ? 3 :
10087                         i == Xamoeba_5 ? 0 :
10088                         i == Xamoeba_6 ? 1 :
10089                         i == Xamoeba_7 ? 2 :
10090                         i == Xamoeba_8 ? 3 :
10091                         i == Xexit_2 ? j + 8 :
10092                         i == Xexit_3 ? j + 16 :
10093                         i == Xdynamite_1 ? 0 :
10094                         i == Xdynamite_2 ? 8 :
10095                         i == Xdynamite_3 ? 16 :
10096                         i == Xdynamite_4 ? 24 :
10097                         i == Xsand_stonein_1 ? j + 1 :
10098                         i == Xsand_stonein_2 ? j + 9 :
10099                         i == Xsand_stonein_3 ? j + 17 :
10100                         i == Xsand_stonein_4 ? j + 25 :
10101                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10102                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10103                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10104                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10105                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10106                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10107                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10108                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10109                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10110                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10111                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10112                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10113                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10114                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10115                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10116                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10117                         i == Xboom_bug && j == 1 ? 2 :
10118                         i == Xboom_bug && j == 2 ? 2 :
10119                         i == Xboom_bug && j == 3 ? 4 :
10120                         i == Xboom_bug && j == 4 ? 4 :
10121                         i == Xboom_bug && j == 5 ? 2 :
10122                         i == Xboom_bug && j == 6 ? 2 :
10123                         i == Xboom_bug && j == 7 ? 0 :
10124                         i == Xboom_bomb && j == 1 ? 2 :
10125                         i == Xboom_bomb && j == 2 ? 2 :
10126                         i == Xboom_bomb && j == 3 ? 4 :
10127                         i == Xboom_bomb && j == 4 ? 4 :
10128                         i == Xboom_bomb && j == 5 ? 2 :
10129                         i == Xboom_bomb && j == 6 ? 2 :
10130                         i == Xboom_bomb && j == 7 ? 0 :
10131                         i == Xboom_android && j == 7 ? 6 :
10132                         i == Xboom_1 && j == 1 ? 2 :
10133                         i == Xboom_1 && j == 2 ? 2 :
10134                         i == Xboom_1 && j == 3 ? 4 :
10135                         i == Xboom_1 && j == 4 ? 4 :
10136                         i == Xboom_1 && j == 5 ? 6 :
10137                         i == Xboom_1 && j == 6 ? 6 :
10138                         i == Xboom_1 && j == 7 ? 8 :
10139                         i == Xboom_2 && j == 0 ? 8 :
10140                         i == Xboom_2 && j == 1 ? 8 :
10141                         i == Xboom_2 && j == 2 ? 10 :
10142                         i == Xboom_2 && j == 3 ? 10 :
10143                         i == Xboom_2 && j == 4 ? 10 :
10144                         i == Xboom_2 && j == 5 ? 12 :
10145                         i == Xboom_2 && j == 6 ? 12 :
10146                         i == Xboom_2 && j == 7 ? 12 :
10147                         special_animation && j == 4 ? 3 :
10148                         effective_action != action ? 0 :
10149                         j);
10150
10151       xxx_effective_action = effective_action;
10152       xxx_has_action_graphics = has_action_graphics;
10153     }
10154   }
10155 #endif
10156
10157   int frame = getAnimationFrame(g->anim_frames,
10158                                 g->anim_delay,
10159                                 g->anim_mode,
10160                                 g->anim_start_frame,
10161                                 sync_frame);
10162
10163
10164 #if 0
10165   return;
10166 #endif
10167
10168 #if 0
10169   if (frame_em == 7)
10170     return;
10171 #endif
10172
10173 #if 0
10174   int old_src_x = g_em->src_x;
10175   int old_src_y = g_em->src_y;
10176 #endif
10177
10178 #if 1
10179   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10180                       g->double_movement && is_backside);
10181 #else
10182   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10183                       &g_em->src_x, &g_em->src_y, FALSE);
10184 #endif
10185
10186
10187 #if 0
10188   if (tile == Ydiamond_stone)
10189     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10190            frame_em,
10191            g->anim_frames,
10192            g->anim_delay,
10193            g->anim_mode,
10194            g->anim_start_frame,
10195            sync_frame,
10196            frame,
10197            g_em->src_x, g_em->src_y,
10198            g_em->src_offset_x, g_em->src_offset_y,
10199            g_em->dst_offset_x, g_em->dst_offset_y,
10200            graphic);
10201 #endif
10202
10203
10204 #if 0
10205   return;
10206 #endif
10207
10208 #if 0
10209   if (frame_em == 7)
10210   {
10211     if (graphic == IMG_BUG_MOVING_RIGHT)
10212       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10213              g->double_movement, is_backside,
10214              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10215
10216     return;
10217   }
10218 #endif
10219
10220
10221 #if 0
10222   g_em->src_offset_x = 0;
10223   g_em->src_offset_y = 0;
10224   g_em->dst_offset_x = 0;
10225   g_em->dst_offset_y = 0;
10226   g_em->width  = TILEX;
10227   g_em->height = TILEY;
10228
10229   g_em->preserve_background = FALSE;
10230 #endif
10231
10232   /* (updating the "crumbled" graphic definitions is probably not really needed,
10233      as animations for crumbled graphics can't be longer than one EMC cycle) */
10234 #if 1
10235   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10236                            sync_frame);
10237
10238 #else
10239
10240   g_em->crumbled_bitmap = NULL;
10241   g_em->crumbled_src_x = 0;
10242   g_em->crumbled_src_y = 0;
10243
10244   g_em->has_crumbled_graphics = FALSE;
10245
10246   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10247   {
10248     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10249                                            g_crumbled->anim_delay,
10250                                            g_crumbled->anim_mode,
10251                                            g_crumbled->anim_start_frame,
10252                                            sync_frame);
10253
10254     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10255                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10256
10257     g_em->has_crumbled_graphics = TRUE;
10258   }
10259 #endif
10260
10261 #if 0
10262  {
10263    int effective_action = xxx_effective_action;
10264    int has_action_graphics = xxx_has_action_graphics;
10265
10266       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10267                                    effective_action == ACTION_MOVING  ||
10268                                    effective_action == ACTION_PUSHING ||
10269                                    effective_action == ACTION_EATING)) ||
10270           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10271                                     effective_action == ACTION_EMPTYING)))
10272       {
10273         int move_dir =
10274           (effective_action == ACTION_FALLING ||
10275            effective_action == ACTION_FILLING ||
10276            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10277         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10278         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10279         int num_steps = (i == Ydrip_s1  ? 16 :
10280                          i == Ydrip_s1B ? 16 :
10281                          i == Ydrip_s2  ? 16 :
10282                          i == Ydrip_s2B ? 16 :
10283                          i == Xsand_stonein_1 ? 32 :
10284                          i == Xsand_stonein_2 ? 32 :
10285                          i == Xsand_stonein_3 ? 32 :
10286                          i == Xsand_stonein_4 ? 32 :
10287                          i == Xsand_stoneout_1 ? 16 :
10288                          i == Xsand_stoneout_2 ? 16 : 8);
10289         int cx = ABS(dx) * (TILEX / num_steps);
10290         int cy = ABS(dy) * (TILEY / num_steps);
10291         int step_frame = (i == Ydrip_s2         ? j + 8 :
10292                           i == Ydrip_s2B        ? j + 8 :
10293                           i == Xsand_stonein_2  ? j + 8 :
10294                           i == Xsand_stonein_3  ? j + 16 :
10295                           i == Xsand_stonein_4  ? j + 24 :
10296                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10297         int step = (is_backside ? step_frame : num_steps - step_frame);
10298
10299         if (is_backside)        /* tile where movement starts */
10300         {
10301           if (dx < 0 || dy < 0)
10302           {
10303             g_em->src_offset_x = cx * step;
10304             g_em->src_offset_y = cy * step;
10305           }
10306           else
10307           {
10308             g_em->dst_offset_x = cx * step;
10309             g_em->dst_offset_y = cy * step;
10310           }
10311         }
10312         else                    /* tile where movement ends */
10313         {
10314           if (dx < 0 || dy < 0)
10315           {
10316             g_em->dst_offset_x = cx * step;
10317             g_em->dst_offset_y = cy * step;
10318           }
10319           else
10320           {
10321             g_em->src_offset_x = cx * step;
10322             g_em->src_offset_y = cy * step;
10323           }
10324         }
10325
10326         g_em->width  = TILEX - cx * step;
10327         g_em->height = TILEY - cy * step;
10328       }
10329
10330       /* create unique graphic identifier to decide if tile must be redrawn */
10331       /* bit 31 - 16 (16 bit): EM style graphic
10332          bit 15 - 12 ( 4 bit): EM style frame
10333          bit 11 -  6 ( 6 bit): graphic width
10334          bit  5 -  0 ( 6 bit): graphic height */
10335       g_em->unique_identifier =
10336         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10337  }
10338 #endif
10339
10340 }
10341
10342 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10343                                   int player_nr, int anim, int frame_em)
10344 {
10345   int element   = player_mapping[player_nr][anim].element_rnd;
10346   int action    = player_mapping[player_nr][anim].action;
10347   int direction = player_mapping[player_nr][anim].direction;
10348   int graphic = (direction == MV_NONE ?
10349                  el_act2img(element, action) :
10350                  el_act_dir2img(element, action, direction));
10351   struct GraphicInfo *g = &graphic_info[graphic];
10352   int sync_frame;
10353
10354   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10355
10356   stored_player[player_nr].StepFrame = frame_em;
10357
10358   sync_frame = stored_player[player_nr].Frame;
10359
10360   int frame = getAnimationFrame(g->anim_frames,
10361                                 g->anim_delay,
10362                                 g->anim_mode,
10363                                 g->anim_start_frame,
10364                                 sync_frame);
10365
10366   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10367                       &g_em->src_x, &g_em->src_y, FALSE);
10368
10369 #if 0
10370   printf("::: %d: %d, %d [%d]\n",
10371          player_nr,
10372          stored_player[player_nr].Frame,
10373          stored_player[player_nr].StepFrame,
10374          FrameCounter);
10375 #endif
10376 }
10377
10378 void InitGraphicInfo_EM(void)
10379 {
10380 #if 0
10381   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10382   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10383 #endif
10384   int i, j, p;
10385
10386 #if DEBUG_EM_GFX
10387   int num_em_gfx_errors = 0;
10388
10389   if (graphic_info_em_object[0][0].bitmap == NULL)
10390   {
10391     /* EM graphics not yet initialized in em_open_all() */
10392
10393     return;
10394   }
10395
10396   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10397 #endif
10398
10399   /* always start with reliable default values */
10400   for (i = 0; i < TILE_MAX; i++)
10401   {
10402     object_mapping[i].element_rnd = EL_UNKNOWN;
10403     object_mapping[i].is_backside = FALSE;
10404     object_mapping[i].action = ACTION_DEFAULT;
10405     object_mapping[i].direction = MV_NONE;
10406   }
10407
10408   /* always start with reliable default values */
10409   for (p = 0; p < MAX_PLAYERS; p++)
10410   {
10411     for (i = 0; i < SPR_MAX; i++)
10412     {
10413       player_mapping[p][i].element_rnd = EL_UNKNOWN;
10414       player_mapping[p][i].action = ACTION_DEFAULT;
10415       player_mapping[p][i].direction = MV_NONE;
10416     }
10417   }
10418
10419   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10420   {
10421     int e = em_object_mapping_list[i].element_em;
10422
10423     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10424     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10425
10426     if (em_object_mapping_list[i].action != -1)
10427       object_mapping[e].action = em_object_mapping_list[i].action;
10428
10429     if (em_object_mapping_list[i].direction != -1)
10430       object_mapping[e].direction =
10431         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10432   }
10433
10434   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10435   {
10436     int a = em_player_mapping_list[i].action_em;
10437     int p = em_player_mapping_list[i].player_nr;
10438
10439     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10440
10441     if (em_player_mapping_list[i].action != -1)
10442       player_mapping[p][a].action = em_player_mapping_list[i].action;
10443
10444     if (em_player_mapping_list[i].direction != -1)
10445       player_mapping[p][a].direction =
10446         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10447   }
10448
10449   for (i = 0; i < TILE_MAX; i++)
10450   {
10451     int element = object_mapping[i].element_rnd;
10452     int action = object_mapping[i].action;
10453     int direction = object_mapping[i].direction;
10454     boolean is_backside = object_mapping[i].is_backside;
10455 #if 0
10456     boolean action_removing = (action == ACTION_DIGGING ||
10457                                action == ACTION_SNAPPING ||
10458                                action == ACTION_COLLECTING);
10459 #endif
10460     boolean action_exploding = ((action == ACTION_EXPLODING ||
10461                                  action == ACTION_SMASHED_BY_ROCK ||
10462                                  action == ACTION_SMASHED_BY_SPRING) &&
10463                                 element != EL_DIAMOND);
10464     boolean action_active = (action == ACTION_ACTIVE);
10465     boolean action_other = (action == ACTION_OTHER);
10466
10467     for (j = 0; j < 8; j++)
10468     {
10469 #if 1
10470       int effective_element = get_effective_element_EM(i, j);
10471 #else
10472       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10473                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10474                                j < 7 ? element :
10475                                i == Xdrip_stretch ? element :
10476                                i == Xdrip_stretchB ? element :
10477                                i == Ydrip_s1 ? element :
10478                                i == Ydrip_s1B ? element :
10479                                i == Xball_1B ? element :
10480                                i == Xball_2 ? element :
10481                                i == Xball_2B ? element :
10482                                i == Yball_eat ? element :
10483                                i == Ykey_1_eat ? element :
10484                                i == Ykey_2_eat ? element :
10485                                i == Ykey_3_eat ? element :
10486                                i == Ykey_4_eat ? element :
10487                                i == Ykey_5_eat ? element :
10488                                i == Ykey_6_eat ? element :
10489                                i == Ykey_7_eat ? element :
10490                                i == Ykey_8_eat ? element :
10491                                i == Ylenses_eat ? element :
10492                                i == Ymagnify_eat ? element :
10493                                i == Ygrass_eat ? element :
10494                                i == Ydirt_eat ? element :
10495                                i == Yemerald_stone ? EL_EMERALD :
10496                                i == Ydiamond_stone ? EL_ROCK :
10497                                i == Xsand_stonein_1 ? element :
10498                                i == Xsand_stonein_2 ? element :
10499                                i == Xsand_stonein_3 ? element :
10500                                i == Xsand_stonein_4 ? element :
10501                                is_backside ? EL_EMPTY :
10502                                action_removing ? EL_EMPTY :
10503                                element);
10504 #endif
10505       int effective_action = (j < 7 ? action :
10506                               i == Xdrip_stretch ? action :
10507                               i == Xdrip_stretchB ? action :
10508                               i == Ydrip_s1 ? action :
10509                               i == Ydrip_s1B ? action :
10510                               i == Xball_1B ? action :
10511                               i == Xball_2 ? action :
10512                               i == Xball_2B ? action :
10513                               i == Yball_eat ? action :
10514                               i == Ykey_1_eat ? action :
10515                               i == Ykey_2_eat ? action :
10516                               i == Ykey_3_eat ? action :
10517                               i == Ykey_4_eat ? action :
10518                               i == Ykey_5_eat ? action :
10519                               i == Ykey_6_eat ? action :
10520                               i == Ykey_7_eat ? action :
10521                               i == Ykey_8_eat ? action :
10522                               i == Ylenses_eat ? action :
10523                               i == Ymagnify_eat ? action :
10524                               i == Ygrass_eat ? action :
10525                               i == Ydirt_eat ? action :
10526                               i == Xsand_stonein_1 ? action :
10527                               i == Xsand_stonein_2 ? action :
10528                               i == Xsand_stonein_3 ? action :
10529                               i == Xsand_stonein_4 ? action :
10530                               i == Xsand_stoneout_1 ? action :
10531                               i == Xsand_stoneout_2 ? action :
10532                               i == Xboom_android ? ACTION_EXPLODING :
10533                               action_exploding ? ACTION_EXPLODING :
10534                               action_active ? action :
10535                               action_other ? action :
10536                               ACTION_DEFAULT);
10537       int graphic = (el_act_dir2img(effective_element, effective_action,
10538                                     direction));
10539       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10540                                      direction));
10541       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10542       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10543       boolean has_action_graphics = (graphic != base_graphic);
10544       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10545       struct GraphicInfo *g = &graphic_info[graphic];
10546 #if 0
10547       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10548 #endif
10549       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10550       Bitmap *src_bitmap;
10551       int src_x, src_y;
10552       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10553       boolean special_animation = (action != ACTION_DEFAULT &&
10554                                    g->anim_frames == 3 &&
10555                                    g->anim_delay == 2 &&
10556                                    g->anim_mode & ANIM_LINEAR);
10557       int sync_frame = (i == Xdrip_stretch ? 7 :
10558                         i == Xdrip_stretchB ? 7 :
10559                         i == Ydrip_s2 ? j + 8 :
10560                         i == Ydrip_s2B ? j + 8 :
10561                         i == Xacid_1 ? 0 :
10562                         i == Xacid_2 ? 10 :
10563                         i == Xacid_3 ? 20 :
10564                         i == Xacid_4 ? 30 :
10565                         i == Xacid_5 ? 40 :
10566                         i == Xacid_6 ? 50 :
10567                         i == Xacid_7 ? 60 :
10568                         i == Xacid_8 ? 70 :
10569                         i == Xfake_acid_1 ? 0 :
10570                         i == Xfake_acid_2 ? 10 :
10571                         i == Xfake_acid_3 ? 20 :
10572                         i == Xfake_acid_4 ? 30 :
10573                         i == Xfake_acid_5 ? 40 :
10574                         i == Xfake_acid_6 ? 50 :
10575                         i == Xfake_acid_7 ? 60 :
10576                         i == Xfake_acid_8 ? 70 :
10577                         i == Xball_2 ? 7 :
10578                         i == Xball_2B ? j + 8 :
10579                         i == Yball_eat ? j + 1 :
10580                         i == Ykey_1_eat ? j + 1 :
10581                         i == Ykey_2_eat ? j + 1 :
10582                         i == Ykey_3_eat ? j + 1 :
10583                         i == Ykey_4_eat ? j + 1 :
10584                         i == Ykey_5_eat ? j + 1 :
10585                         i == Ykey_6_eat ? j + 1 :
10586                         i == Ykey_7_eat ? j + 1 :
10587                         i == Ykey_8_eat ? j + 1 :
10588                         i == Ylenses_eat ? j + 1 :
10589                         i == Ymagnify_eat ? j + 1 :
10590                         i == Ygrass_eat ? j + 1 :
10591                         i == Ydirt_eat ? j + 1 :
10592                         i == Xamoeba_1 ? 0 :
10593                         i == Xamoeba_2 ? 1 :
10594                         i == Xamoeba_3 ? 2 :
10595                         i == Xamoeba_4 ? 3 :
10596                         i == Xamoeba_5 ? 0 :
10597                         i == Xamoeba_6 ? 1 :
10598                         i == Xamoeba_7 ? 2 :
10599                         i == Xamoeba_8 ? 3 :
10600                         i == Xexit_2 ? j + 8 :
10601                         i == Xexit_3 ? j + 16 :
10602                         i == Xdynamite_1 ? 0 :
10603                         i == Xdynamite_2 ? 8 :
10604                         i == Xdynamite_3 ? 16 :
10605                         i == Xdynamite_4 ? 24 :
10606                         i == Xsand_stonein_1 ? j + 1 :
10607                         i == Xsand_stonein_2 ? j + 9 :
10608                         i == Xsand_stonein_3 ? j + 17 :
10609                         i == Xsand_stonein_4 ? j + 25 :
10610                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10611                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10612                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10613                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10614                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10615                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10616                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10617                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10618                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10619                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10620                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10621                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10622                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10623                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10624                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10625                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10626                         i == Xboom_bug && j == 1 ? 2 :
10627                         i == Xboom_bug && j == 2 ? 2 :
10628                         i == Xboom_bug && j == 3 ? 4 :
10629                         i == Xboom_bug && j == 4 ? 4 :
10630                         i == Xboom_bug && j == 5 ? 2 :
10631                         i == Xboom_bug && j == 6 ? 2 :
10632                         i == Xboom_bug && j == 7 ? 0 :
10633                         i == Xboom_bomb && j == 1 ? 2 :
10634                         i == Xboom_bomb && j == 2 ? 2 :
10635                         i == Xboom_bomb && j == 3 ? 4 :
10636                         i == Xboom_bomb && j == 4 ? 4 :
10637                         i == Xboom_bomb && j == 5 ? 2 :
10638                         i == Xboom_bomb && j == 6 ? 2 :
10639                         i == Xboom_bomb && j == 7 ? 0 :
10640                         i == Xboom_android && j == 7 ? 6 :
10641                         i == Xboom_1 && j == 1 ? 2 :
10642                         i == Xboom_1 && j == 2 ? 2 :
10643                         i == Xboom_1 && j == 3 ? 4 :
10644                         i == Xboom_1 && j == 4 ? 4 :
10645                         i == Xboom_1 && j == 5 ? 6 :
10646                         i == Xboom_1 && j == 6 ? 6 :
10647                         i == Xboom_1 && j == 7 ? 8 :
10648                         i == Xboom_2 && j == 0 ? 8 :
10649                         i == Xboom_2 && j == 1 ? 8 :
10650                         i == Xboom_2 && j == 2 ? 10 :
10651                         i == Xboom_2 && j == 3 ? 10 :
10652                         i == Xboom_2 && j == 4 ? 10 :
10653                         i == Xboom_2 && j == 5 ? 12 :
10654                         i == Xboom_2 && j == 6 ? 12 :
10655                         i == Xboom_2 && j == 7 ? 12 :
10656                         special_animation && j == 4 ? 3 :
10657                         effective_action != action ? 0 :
10658                         j);
10659
10660 #if DEBUG_EM_GFX
10661       Bitmap *debug_bitmap = g_em->bitmap;
10662       int debug_src_x = g_em->src_x;
10663       int debug_src_y = g_em->src_y;
10664 #endif
10665
10666       int frame = getAnimationFrame(g->anim_frames,
10667                                     g->anim_delay,
10668                                     g->anim_mode,
10669                                     g->anim_start_frame,
10670                                     sync_frame);
10671
10672       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10673                           g->double_movement && is_backside);
10674
10675       g_em->bitmap = src_bitmap;
10676       g_em->src_x = src_x;
10677       g_em->src_y = src_y;
10678       g_em->src_offset_x = 0;
10679       g_em->src_offset_y = 0;
10680       g_em->dst_offset_x = 0;
10681       g_em->dst_offset_y = 0;
10682       g_em->width  = TILEX;
10683       g_em->height = TILEY;
10684
10685       g_em->preserve_background = FALSE;
10686
10687 #if 1
10688       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10689                                sync_frame);
10690
10691 #else
10692
10693       g_em->crumbled_bitmap = NULL;
10694       g_em->crumbled_src_x = 0;
10695       g_em->crumbled_src_y = 0;
10696       g_em->crumbled_border_size = 0;
10697
10698       g_em->has_crumbled_graphics = FALSE;
10699
10700 #if 0
10701       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10702         printf("::: empty crumbled: %d [%s], %d, %d\n",
10703                effective_element, element_info[effective_element].token_name,
10704                effective_action, direction);
10705 #endif
10706
10707       /* if element can be crumbled, but certain action graphics are just empty
10708          space (like instantly snapping sand to empty space in 1 frame), do not
10709          treat these empty space graphics as crumbled graphics in EMC engine */
10710       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10711       {
10712         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10713                                                g_crumbled->anim_delay,
10714                                                g_crumbled->anim_mode,
10715                                                g_crumbled->anim_start_frame,
10716                                                sync_frame);
10717
10718         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10719
10720         g_em->has_crumbled_graphics = TRUE;
10721         g_em->crumbled_bitmap = src_bitmap;
10722         g_em->crumbled_src_x = src_x;
10723         g_em->crumbled_src_y = src_y;
10724         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10725
10726
10727 #if 0
10728         if (g_em == &graphic_info_em_object[207][0])
10729           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10730                  graphic_info_em_object[207][0].crumbled_src_x,
10731                  graphic_info_em_object[207][0].crumbled_src_y,
10732
10733                  crumbled, frame, src_x, src_y,
10734
10735                  g->anim_frames,
10736                  g->anim_delay,
10737                  g->anim_mode,
10738                  g->anim_start_frame,
10739                  sync_frame,
10740                  gfx.anim_random_frame,
10741                  frame);
10742 #endif
10743
10744 #if 0
10745         printf("::: EMC tile %d is crumbled\n", i);
10746 #endif
10747       }
10748 #endif
10749
10750 #if 0
10751       if (element == EL_ROCK &&
10752           effective_action == ACTION_FILLING)
10753         printf("::: has_action_graphics == %d\n", has_action_graphics);
10754 #endif
10755
10756       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10757                                    effective_action == ACTION_MOVING  ||
10758                                    effective_action == ACTION_PUSHING ||
10759                                    effective_action == ACTION_EATING)) ||
10760           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10761                                     effective_action == ACTION_EMPTYING)))
10762       {
10763         int move_dir =
10764           (effective_action == ACTION_FALLING ||
10765            effective_action == ACTION_FILLING ||
10766            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10767         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10768         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10769         int num_steps = (i == Ydrip_s1  ? 16 :
10770                          i == Ydrip_s1B ? 16 :
10771                          i == Ydrip_s2  ? 16 :
10772                          i == Ydrip_s2B ? 16 :
10773                          i == Xsand_stonein_1 ? 32 :
10774                          i == Xsand_stonein_2 ? 32 :
10775                          i == Xsand_stonein_3 ? 32 :
10776                          i == Xsand_stonein_4 ? 32 :
10777                          i == Xsand_stoneout_1 ? 16 :
10778                          i == Xsand_stoneout_2 ? 16 : 8);
10779         int cx = ABS(dx) * (TILEX / num_steps);
10780         int cy = ABS(dy) * (TILEY / num_steps);
10781         int step_frame = (i == Ydrip_s2         ? j + 8 :
10782                           i == Ydrip_s2B        ? j + 8 :
10783                           i == Xsand_stonein_2  ? j + 8 :
10784                           i == Xsand_stonein_3  ? j + 16 :
10785                           i == Xsand_stonein_4  ? j + 24 :
10786                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10787         int step = (is_backside ? step_frame : num_steps - step_frame);
10788
10789         if (is_backside)        /* tile where movement starts */
10790         {
10791           if (dx < 0 || dy < 0)
10792           {
10793             g_em->src_offset_x = cx * step;
10794             g_em->src_offset_y = cy * step;
10795           }
10796           else
10797           {
10798             g_em->dst_offset_x = cx * step;
10799             g_em->dst_offset_y = cy * step;
10800           }
10801         }
10802         else                    /* tile where movement ends */
10803         {
10804           if (dx < 0 || dy < 0)
10805           {
10806             g_em->dst_offset_x = cx * step;
10807             g_em->dst_offset_y = cy * step;
10808           }
10809           else
10810           {
10811             g_em->src_offset_x = cx * step;
10812             g_em->src_offset_y = cy * step;
10813           }
10814         }
10815
10816         g_em->width  = TILEX - cx * step;
10817         g_em->height = TILEY - cy * step;
10818       }
10819
10820       /* create unique graphic identifier to decide if tile must be redrawn */
10821       /* bit 31 - 16 (16 bit): EM style graphic
10822          bit 15 - 12 ( 4 bit): EM style frame
10823          bit 11 -  6 ( 6 bit): graphic width
10824          bit  5 -  0 ( 6 bit): graphic height */
10825       g_em->unique_identifier =
10826         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10827
10828 #if DEBUG_EM_GFX
10829
10830       /* skip check for EMC elements not contained in original EMC artwork */
10831       if (element == EL_EMC_FAKE_ACID)
10832         continue;
10833
10834       if (g_em->bitmap != debug_bitmap ||
10835           g_em->src_x != debug_src_x ||
10836           g_em->src_y != debug_src_y ||
10837           g_em->src_offset_x != 0 ||
10838           g_em->src_offset_y != 0 ||
10839           g_em->dst_offset_x != 0 ||
10840           g_em->dst_offset_y != 0 ||
10841           g_em->width != TILEX ||
10842           g_em->height != TILEY)
10843       {
10844         static int last_i = -1;
10845
10846         if (i != last_i)
10847         {
10848           printf("\n");
10849           last_i = i;
10850         }
10851
10852         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
10853                i, element, element_info[element].token_name,
10854                element_action_info[effective_action].suffix, direction);
10855
10856         if (element != effective_element)
10857           printf(" [%d ('%s')]",
10858                  effective_element,
10859                  element_info[effective_element].token_name);
10860
10861         printf("\n");
10862
10863         if (g_em->bitmap != debug_bitmap)
10864           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
10865                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
10866
10867         if (g_em->src_x != debug_src_x ||
10868             g_em->src_y != debug_src_y)
10869           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10870                  j, (is_backside ? 'B' : 'F'),
10871                  g_em->src_x, g_em->src_y,
10872                  g_em->src_x / 32, g_em->src_y / 32,
10873                  debug_src_x, debug_src_y,
10874                  debug_src_x / 32, debug_src_y / 32);
10875
10876         if (g_em->src_offset_x != 0 ||
10877             g_em->src_offset_y != 0 ||
10878             g_em->dst_offset_x != 0 ||
10879             g_em->dst_offset_y != 0)
10880           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
10881                  j, is_backside,
10882                  g_em->src_offset_x, g_em->src_offset_y,
10883                  g_em->dst_offset_x, g_em->dst_offset_y);
10884
10885         if (g_em->width != TILEX ||
10886             g_em->height != TILEY)
10887           printf("    %d (%d): size %d,%d should be %d,%d\n",
10888                  j, is_backside,
10889                  g_em->width, g_em->height, TILEX, TILEY);
10890
10891         num_em_gfx_errors++;
10892       }
10893 #endif
10894
10895     }
10896   }
10897
10898   for (i = 0; i < TILE_MAX; i++)
10899   {
10900     for (j = 0; j < 8; j++)
10901     {
10902       int element = object_mapping[i].element_rnd;
10903       int action = object_mapping[i].action;
10904       int direction = object_mapping[i].direction;
10905       boolean is_backside = object_mapping[i].is_backside;
10906       int graphic_action  = el_act_dir2img(element, action, direction);
10907       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
10908
10909       if ((action == ACTION_SMASHED_BY_ROCK ||
10910            action == ACTION_SMASHED_BY_SPRING ||
10911            action == ACTION_EATING) &&
10912           graphic_action == graphic_default)
10913       {
10914         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
10915                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
10916                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
10917                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
10918                  Xspring);
10919
10920         /* no separate animation for "smashed by rock" -- use rock instead */
10921         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10922         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
10923
10924         g_em->bitmap            = g_xx->bitmap;
10925         g_em->src_x             = g_xx->src_x;
10926         g_em->src_y             = g_xx->src_y;
10927         g_em->src_offset_x      = g_xx->src_offset_x;
10928         g_em->src_offset_y      = g_xx->src_offset_y;
10929         g_em->dst_offset_x      = g_xx->dst_offset_x;
10930         g_em->dst_offset_y      = g_xx->dst_offset_y;
10931         g_em->width             = g_xx->width;
10932         g_em->height            = g_xx->height;
10933         g_em->unique_identifier = g_xx->unique_identifier;
10934
10935         if (!is_backside)
10936           g_em->preserve_background = TRUE;
10937       }
10938     }
10939   }
10940
10941   for (p = 0; p < MAX_PLAYERS; p++)
10942   {
10943     for (i = 0; i < SPR_MAX; i++)
10944     {
10945       int element = player_mapping[p][i].element_rnd;
10946       int action = player_mapping[p][i].action;
10947       int direction = player_mapping[p][i].direction;
10948
10949       for (j = 0; j < 8; j++)
10950       {
10951         int effective_element = element;
10952         int effective_action = action;
10953         int graphic = (direction == MV_NONE ?
10954                        el_act2img(effective_element, effective_action) :
10955                        el_act_dir2img(effective_element, effective_action,
10956                                       direction));
10957         struct GraphicInfo *g = &graphic_info[graphic];
10958         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
10959         Bitmap *src_bitmap;
10960         int src_x, src_y;
10961         int sync_frame = j;
10962
10963 #if DEBUG_EM_GFX
10964         Bitmap *debug_bitmap = g_em->bitmap;
10965         int debug_src_x = g_em->src_x;
10966         int debug_src_y = g_em->src_y;
10967 #endif
10968
10969         int frame = getAnimationFrame(g->anim_frames,
10970                                       g->anim_delay,
10971                                       g->anim_mode,
10972                                       g->anim_start_frame,
10973                                       sync_frame);
10974
10975         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
10976
10977         g_em->bitmap = src_bitmap;
10978         g_em->src_x = src_x;
10979         g_em->src_y = src_y;
10980         g_em->src_offset_x = 0;
10981         g_em->src_offset_y = 0;
10982         g_em->dst_offset_x = 0;
10983         g_em->dst_offset_y = 0;
10984         g_em->width  = TILEX;
10985         g_em->height = TILEY;
10986
10987 #if DEBUG_EM_GFX
10988
10989         /* skip check for EMC elements not contained in original EMC artwork */
10990         if (element == EL_PLAYER_3 ||
10991             element == EL_PLAYER_4)
10992           continue;
10993
10994         if (g_em->bitmap != debug_bitmap ||
10995             g_em->src_x != debug_src_x ||
10996             g_em->src_y != debug_src_y)
10997         {
10998           static int last_i = -1;
10999
11000           if (i != last_i)
11001           {
11002             printf("\n");
11003             last_i = i;
11004           }
11005
11006           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11007                  p, i, element, element_info[element].token_name,
11008                  element_action_info[effective_action].suffix, direction);
11009
11010           if (element != effective_element)
11011             printf(" [%d ('%s')]",
11012                    effective_element,
11013                    element_info[effective_element].token_name);
11014
11015           printf("\n");
11016
11017           if (g_em->bitmap != debug_bitmap)
11018             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
11019                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
11020
11021           if (g_em->src_x != debug_src_x ||
11022               g_em->src_y != debug_src_y)
11023             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11024                    j,
11025                    g_em->src_x, g_em->src_y,
11026                    g_em->src_x / 32, g_em->src_y / 32,
11027                    debug_src_x, debug_src_y,
11028                    debug_src_x / 32, debug_src_y / 32);
11029
11030           num_em_gfx_errors++;
11031         }
11032 #endif
11033
11034       }
11035     }
11036   }
11037
11038 #if DEBUG_EM_GFX
11039   printf("\n");
11040   printf("::: [%d errors found]\n", num_em_gfx_errors);
11041
11042   exit(0);
11043 #endif
11044 }
11045
11046 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11047                             boolean any_player_moving,
11048                             boolean player_is_dropping)
11049 {
11050   if (tape.single_step && tape.recording && !tape.pausing)
11051   {
11052 #if 0
11053     boolean active_players = FALSE;
11054     int i;
11055
11056     for (i = 0; i < MAX_PLAYERS; i++)
11057       if (action[i] != JOY_NO_ACTION)
11058         active_players = TRUE;
11059 #endif
11060
11061     // if (frame == 0)
11062     if (frame == 0 && !player_is_dropping)
11063       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11064   }
11065 }
11066
11067 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11068                             boolean murphy_is_dropping)
11069 {
11070 #if 0
11071   printf("::: waiting: %d, dropping: %d\n",
11072          murphy_is_waiting, murphy_is_dropping);
11073 #endif
11074
11075   if (tape.single_step && tape.recording && !tape.pausing)
11076   {
11077     // if (murphy_is_waiting || murphy_is_dropping)
11078     if (murphy_is_waiting)
11079     {
11080 #if 0
11081       printf("::: murphy is waiting -> pause mode\n");
11082 #endif
11083
11084       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11085     }
11086   }
11087 }
11088
11089 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11090                          int graphic, int sync_frame, int x, int y)
11091 {
11092   int frame = getGraphicAnimationFrame(graphic, sync_frame);
11093
11094   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11095 }
11096
11097 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11098 {
11099   return (IS_NEXT_FRAME(sync_frame, graphic));
11100 }
11101
11102 int getGraphicInfo_Delay(int graphic)
11103 {
11104   return graphic_info[graphic].anim_delay;
11105 }
11106
11107 void PlayMenuSoundExt(int sound)
11108 {
11109   if (sound == SND_UNDEFINED)
11110     return;
11111
11112   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11113       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11114     return;
11115
11116   if (IS_LOOP_SOUND(sound))
11117     PlaySoundLoop(sound);
11118   else
11119     PlaySound(sound);
11120 }
11121
11122 void PlayMenuSound()
11123 {
11124   PlayMenuSoundExt(menu.sound[game_status]);
11125 }
11126
11127 void PlayMenuSoundStereo(int sound, int stereo_position)
11128 {
11129   if (sound == SND_UNDEFINED)
11130     return;
11131
11132   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11133       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11134     return;
11135
11136   if (IS_LOOP_SOUND(sound))
11137     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11138   else
11139     PlaySoundStereo(sound, stereo_position);
11140 }
11141
11142 void PlayMenuSoundIfLoopExt(int sound)
11143 {
11144   if (sound == SND_UNDEFINED)
11145     return;
11146
11147   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11148       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11149     return;
11150
11151   if (IS_LOOP_SOUND(sound))
11152     PlaySoundLoop(sound);
11153 }
11154
11155 void PlayMenuSoundIfLoop()
11156 {
11157   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11158 }
11159
11160 void PlayMenuMusicExt(int music)
11161 {
11162   if (music == MUS_UNDEFINED)
11163     return;
11164
11165   if (!setup.sound_music)
11166     return;
11167
11168   PlayMusic(music);
11169 }
11170
11171 void PlayMenuMusic()
11172 {
11173   PlayMenuMusicExt(menu.music[game_status]);
11174 }
11175
11176 void PlaySoundActivating()
11177 {
11178 #if 0
11179   PlaySound(SND_MENU_ITEM_ACTIVATING);
11180 #endif
11181 }
11182
11183 void PlaySoundSelecting()
11184 {
11185 #if 0
11186   PlaySound(SND_MENU_ITEM_SELECTING);
11187 #endif
11188 }
11189
11190 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11191 {
11192   boolean change_fullscreen = (setup.fullscreen !=
11193                                video.fullscreen_enabled);
11194   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11195                                     !strEqual(setup.fullscreen_mode,
11196                                               video.fullscreen_mode_current));
11197   boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11198                                            setup.window_scaling_percent !=
11199                                            video.window_scaling_percent);
11200
11201   if (change_window_scaling_percent && video.fullscreen_enabled)
11202     return;
11203
11204   if (!change_window_scaling_percent && !video.fullscreen_available)
11205     return;
11206
11207 #if defined(TARGET_SDL2)
11208   if (change_window_scaling_percent)
11209   {
11210     SDLSetWindowScaling(setup.window_scaling_percent);
11211
11212     return;
11213   }
11214   else if (change_fullscreen)
11215   {
11216     SDLSetWindowFullscreen(setup.fullscreen);
11217
11218     /* set setup value according to successfully changed fullscreen mode */
11219     setup.fullscreen = video.fullscreen_enabled;
11220
11221     return;
11222   }
11223 #endif
11224
11225   if (change_fullscreen ||
11226       change_fullscreen_mode ||
11227       change_window_scaling_percent)
11228   {
11229     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11230
11231     /* save backbuffer content which gets lost when toggling fullscreen mode */
11232     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11233
11234     if (change_fullscreen_mode)
11235     {
11236       /* keep fullscreen, but change fullscreen mode (screen resolution) */
11237       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
11238     }
11239
11240     if (change_window_scaling_percent)
11241     {
11242       /* keep window mode, but change window scaling */
11243       video.fullscreen_enabled = TRUE;          /* force new window scaling */
11244     }
11245
11246     /* toggle fullscreen */
11247     ChangeVideoModeIfNeeded(setup.fullscreen);
11248
11249     /* set setup value according to successfully changed fullscreen mode */
11250     setup.fullscreen = video.fullscreen_enabled;
11251
11252     /* restore backbuffer content from temporary backbuffer backup bitmap */
11253     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11254
11255     FreeBitmap(tmp_backbuffer);
11256
11257 #if 1
11258     /* update visible window/screen */
11259     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11260 #else
11261     redraw_mask = REDRAW_ALL;
11262 #endif
11263   }
11264 }
11265
11266 void ChangeViewportPropertiesIfNeeded()
11267 {
11268 #if 0
11269   int *door_1_x = &DX;
11270   int *door_1_y = &DY;
11271   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11272   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11273 #endif
11274   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11275                        game_status == GAME_MODE_EDITOR ? game_status :
11276                        GAME_MODE_MAIN);
11277   int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11278                         game_status);
11279   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11280   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11281   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11282   struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11283   int border_size       = vp_playfield->border_size;
11284   int new_sx            = vp_playfield->x + border_size;
11285   int new_sy            = vp_playfield->y + border_size;
11286   int new_sxsize        = vp_playfield->width  - 2 * border_size;
11287   int new_sysize        = vp_playfield->height - 2 * border_size;
11288   int new_real_sx       = vp_playfield->x;
11289   int new_real_sy       = vp_playfield->y;
11290   int new_full_sxsize   = vp_playfield->width;
11291   int new_full_sysize   = vp_playfield->height;
11292   int new_dx            = vp_door_1->x;
11293   int new_dy            = vp_door_1->y;
11294   int new_dxsize        = vp_door_1->width;
11295   int new_dysize        = vp_door_1->height;
11296   int new_vx            = vp_door_2->x;
11297   int new_vy            = vp_door_2->y;
11298   int new_vxsize        = vp_door_2->width;
11299   int new_vysize        = vp_door_2->height;
11300   int new_ex            = vp_door_3->x;
11301   int new_ey            = vp_door_3->y;
11302   int new_exsize        = vp_door_3->width;
11303   int new_eysize        = vp_door_3->height;
11304 #if NEW_TILESIZE
11305   int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11306   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11307                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11308   int new_scr_fieldx = new_sxsize / tilesize;
11309   int new_scr_fieldy = new_sysize / tilesize;
11310   int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11311   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11312 #else
11313   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
11314   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11315 #endif
11316   boolean init_gfx_buffers = FALSE;
11317   boolean init_video_buffer = FALSE;
11318   boolean init_gadgets_and_toons = FALSE;
11319
11320 #if 0
11321   /* !!! TEST ONLY !!! */
11322   // InitGfxBuffers();
11323   return;
11324 #endif
11325
11326   if (viewport.window.width  != WIN_XSIZE ||
11327       viewport.window.height != WIN_YSIZE)
11328   {
11329     WIN_XSIZE = viewport.window.width;
11330     WIN_YSIZE = viewport.window.height;
11331
11332 #if 1
11333     init_video_buffer = TRUE;
11334     init_gfx_buffers = TRUE;
11335 #else
11336     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11337     InitGfxBuffers();
11338
11339 #if 1
11340     SetDrawDeactivationMask(REDRAW_NONE);
11341     SetDrawBackgroundMask(REDRAW_FIELD);
11342
11343     // RedrawBackground();
11344 #endif
11345 #endif
11346
11347     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11348   }
11349
11350   if (new_scr_fieldx != SCR_FIELDX ||
11351       new_scr_fieldy != SCR_FIELDY)
11352   {
11353     /* this always toggles between MAIN and GAME when using small tile size */
11354
11355     SCR_FIELDX = new_scr_fieldx;
11356     SCR_FIELDY = new_scr_fieldy;
11357
11358     // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11359   }
11360
11361 #if 0
11362   if (new_tilesize_var != TILESIZE_VAR &&
11363       gfx_game_mode == GAME_MODE_PLAYING)
11364   {
11365     /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11366
11367     TILESIZE_VAR = new_tilesize_var;
11368
11369     init_gfx_buffers = TRUE;
11370
11371     // printf("::: tilesize: init_gfx_buffers\n");
11372   }
11373 #endif
11374
11375   if (new_sx != SX ||
11376       new_sy != SY ||
11377       new_dx != DX ||
11378       new_dy != DY ||
11379       new_vx != VX ||
11380       new_vy != VY ||
11381       new_ex != EX ||
11382       new_ey != EY ||
11383       new_sxsize != SXSIZE ||
11384       new_sysize != SYSIZE ||
11385       new_dxsize != DXSIZE ||
11386       new_dysize != DYSIZE ||
11387       new_vxsize != VXSIZE ||
11388       new_vysize != VYSIZE ||
11389       new_exsize != EXSIZE ||
11390       new_eysize != EYSIZE ||
11391       new_real_sx != REAL_SX ||
11392       new_real_sy != REAL_SY ||
11393       new_full_sxsize != FULL_SXSIZE ||
11394       new_full_sysize != FULL_SYSIZE ||
11395       new_tilesize_var != TILESIZE_VAR
11396 #if 0
11397       ||
11398       vp_door_1->x != *door_1_x ||
11399       vp_door_1->y != *door_1_y ||
11400       vp_door_2->x != *door_2_x ||
11401       vp_door_2->y != *door_2_y
11402 #endif
11403       )
11404   {
11405     SX = new_sx;
11406     SY = new_sy;
11407     DX = new_dx;
11408     DY = new_dy;
11409     VX = new_vx;
11410     VY = new_vy;
11411     EX = new_ex;
11412     EY = new_ey;
11413     SXSIZE = new_sxsize;
11414     SYSIZE = new_sysize;
11415     DXSIZE = new_dxsize;
11416     DYSIZE = new_dysize;
11417     VXSIZE = new_vxsize;
11418     VYSIZE = new_vysize;
11419     EXSIZE = new_exsize;
11420     EYSIZE = new_eysize;
11421     REAL_SX = new_real_sx;
11422     REAL_SY = new_real_sy;
11423     FULL_SXSIZE = new_full_sxsize;
11424     FULL_SYSIZE = new_full_sysize;
11425     TILESIZE_VAR = new_tilesize_var;
11426
11427 #if 0
11428     printf("::: %d, %d, %d [%d]\n",
11429            SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11430            setup.small_game_graphics);
11431 #endif
11432
11433 #if 0
11434     *door_1_x = vp_door_1->x;
11435     *door_1_y = vp_door_1->y;
11436     *door_2_x = vp_door_2->x;
11437     *door_2_y = vp_door_2->y;
11438 #endif
11439
11440 #if 1
11441     init_gfx_buffers = TRUE;
11442
11443     // printf("::: viewports: init_gfx_buffers\n");
11444 #else
11445     InitGfxBuffers();
11446 #endif
11447
11448 #if 0
11449     if (gfx_game_mode == GAME_MODE_MAIN)
11450 #endif
11451     {
11452 #if 1
11453       init_gadgets_and_toons = TRUE;
11454
11455       // printf("::: viewports: init_gadgets_and_toons\n");
11456 #else
11457       InitGadgets();
11458       InitToons();
11459 #endif
11460     }
11461   }
11462
11463   if (init_gfx_buffers)
11464   {
11465     // printf("::: init_gfx_buffers\n");
11466
11467     SCR_FIELDX = new_scr_fieldx_buffers;
11468     SCR_FIELDY = new_scr_fieldy_buffers;
11469
11470     InitGfxBuffers();
11471
11472     SCR_FIELDX = new_scr_fieldx;
11473     SCR_FIELDY = new_scr_fieldy;
11474   }
11475
11476   if (init_video_buffer)
11477   {
11478     // printf("::: init_video_buffer\n");
11479
11480     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11481
11482     SetDrawDeactivationMask(REDRAW_NONE);
11483     SetDrawBackgroundMask(REDRAW_FIELD);
11484   }
11485
11486   if (init_gadgets_and_toons)
11487   {
11488     // printf("::: init_gadgets_and_toons\n");
11489
11490     InitGadgets();
11491     InitToons();
11492   }
11493
11494 #if 0
11495   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
11496 #endif
11497 }