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