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