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