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