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