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