1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
37 static int el_act_dir2crm(int, int, int);
38 static int el_act2crm(int, int);
40 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
41 static int request_gadget_id = -1;
43 static char *print_if_not_empty(int element)
45 static char *s = NULL;
46 char *token_name = element_info[element].token_name;
51 s = checked_malloc(strlen(token_name) + 10 + 1);
53 if (element != EL_EMPTY)
54 sprintf(s, "%d\t['%s']", element, token_name);
56 sprintf(s, "%d", element);
61 void DumpTile(int x, int y)
67 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
70 if (!IN_LEV_FIELD(x, y))
72 printf("(not in level field)\n");
78 printf(" Feld: %d\t['%s']\n", Feld[x][y],
79 element_info[Feld[x][y]].token_name);
80 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
81 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
82 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
83 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
84 printf(" MovPos: %d\n", MovPos[x][y]);
85 printf(" MovDir: %d\n", MovDir[x][y]);
86 printf(" MovDelay: %d\n", MovDelay[x][y]);
87 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
88 printf(" CustomValue: %d\n", CustomValue[x][y]);
89 printf(" GfxElement: %d\n", GfxElement[x][y]);
90 printf(" GfxAction: %d\n", GfxAction[x][y]);
91 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
95 void SetDrawtoField(int mode)
97 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
108 drawto_field = fieldbuffer;
110 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
116 BX2 = SCR_FIELDX - 1;
117 BY2 = SCR_FIELDY - 1;
121 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
125 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
127 if (game_status == GAME_MODE_PLAYING &&
128 level.game_engine_type == GAME_ENGINE_TYPE_EM)
130 BlitScreenToBitmap_EM(backbuffer);
132 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
138 width = gfx.sxsize + 2 * TILEX;
139 height = gfx.sysize + 2 * TILEY;
142 if (force_redraw || setup.direct_draw)
145 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
146 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
148 if (setup.direct_draw)
149 SetDrawtoField(DRAW_BACKBUFFER);
151 for (xx = BX1; xx <= BX2; xx++)
152 for (yy = BY1; yy <= BY2; yy++)
153 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
154 DrawScreenField(xx, yy);
157 if (setup.direct_draw)
158 SetDrawtoField(DRAW_DIRECT);
161 if (setup.soft_scrolling)
163 int fx = FX, fy = FY;
165 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
166 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
168 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
172 BlitBitmap(drawto, window, x, y, width, height, x, y);
178 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
180 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
181 redraw_mask &= ~REDRAW_MAIN;
183 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
184 redraw_mask |= REDRAW_FIELD;
186 if (redraw_mask & REDRAW_FIELD)
187 redraw_mask &= ~REDRAW_TILES;
189 if (redraw_mask == REDRAW_NONE)
192 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
194 static boolean last_frame_skipped = FALSE;
195 boolean skip_even_when_not_scrolling = TRUE;
196 boolean just_scrolling = (ScreenMovDir != 0);
197 boolean verbose = FALSE;
199 if (global.fps_slowdown_factor > 1 &&
200 (FrameCounter % global.fps_slowdown_factor) &&
201 (just_scrolling || skip_even_when_not_scrolling))
203 redraw_mask &= ~REDRAW_MAIN;
205 last_frame_skipped = TRUE;
208 printf("FRAME SKIPPED\n");
212 if (last_frame_skipped)
213 redraw_mask |= REDRAW_FIELD;
215 last_frame_skipped = FALSE;
218 printf("frame not skipped\n");
222 /* synchronize X11 graphics at this point; if we would synchronize the
223 display immediately after the buffer switching (after the XFlush),
224 this could mean that we have to wait for the graphics to complete,
225 although we could go on doing calculations for the next frame */
229 if (redraw_mask & REDRAW_ALL)
231 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
235 if (redraw_mask & REDRAW_FIELD)
237 if (game_status != GAME_MODE_PLAYING ||
238 redraw_mask & REDRAW_FROM_BACKBUFFER)
240 BlitBitmap(backbuffer, window,
241 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
245 int fx = FX, fy = FY;
247 if (setup.soft_scrolling)
249 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
250 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
253 if (setup.soft_scrolling ||
254 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
255 ABS(ScreenMovPos) == ScrollStepSize ||
256 redraw_tiles > REDRAWTILES_THRESHOLD)
258 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
262 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
264 (setup.soft_scrolling ?
265 "setup.soft_scrolling" :
266 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
267 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
268 ABS(ScreenGfxPos) == ScrollStepSize ?
269 "ABS(ScreenGfxPos) == ScrollStepSize" :
270 "redraw_tiles > REDRAWTILES_THRESHOLD"));
276 redraw_mask &= ~REDRAW_MAIN;
279 if (redraw_mask & REDRAW_DOORS)
281 if (redraw_mask & REDRAW_DOOR_1)
282 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
284 if (redraw_mask & REDRAW_DOOR_2)
285 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
287 if (redraw_mask & REDRAW_DOOR_3)
288 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
290 redraw_mask &= ~REDRAW_DOORS;
293 if (redraw_mask & REDRAW_MICROLEVEL)
295 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
296 SX, SY + 10 * TILEY);
298 redraw_mask &= ~REDRAW_MICROLEVEL;
301 if (redraw_mask & REDRAW_TILES)
303 for (x = 0; x < SCR_FIELDX; x++)
304 for (y = 0 ; y < SCR_FIELDY; y++)
305 if (redraw[redraw_x1 + x][redraw_y1 + y])
306 BlitBitmap(buffer, window,
307 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
308 SX + x * TILEX, SY + y * TILEY);
311 if (redraw_mask & REDRAW_FPS) /* display frames per second */
316 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
317 if (!global.fps_slowdown)
320 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
321 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
326 for (x = 0; x < MAX_BUF_XSIZE; x++)
327 for (y = 0; y < MAX_BUF_YSIZE; y++)
330 redraw_mask = REDRAW_NONE;
336 long fading_delay = 300;
338 if (setup.fading && (redraw_mask & REDRAW_FIELD))
345 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
348 for (i = 0; i < 2 * FULL_SYSIZE; i++)
350 for (y = 0; y < FULL_SYSIZE; y++)
352 BlitBitmap(backbuffer, window,
353 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
361 for (i = 1; i < FULL_SYSIZE; i+=2)
362 BlitBitmap(backbuffer, window,
363 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
369 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
370 BlitBitmapMasked(backbuffer, window,
371 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
376 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
377 BlitBitmapMasked(backbuffer, window,
378 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
383 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
384 BlitBitmapMasked(backbuffer, window,
385 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
390 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
391 BlitBitmapMasked(backbuffer, window,
392 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
397 redraw_mask &= ~REDRAW_MAIN;
404 void SetMainBackgroundImageIfDefined(int graphic)
406 if (graphic_info[graphic].bitmap)
407 SetMainBackgroundImage(graphic);
410 void SetMainBackgroundImage(int graphic)
412 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
413 graphic_info[graphic].bitmap ?
414 graphic_info[graphic].bitmap :
415 graphic_info[IMG_BACKGROUND].bitmap);
418 void SetDoorBackgroundImage(int graphic)
420 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
421 graphic_info[graphic].bitmap ?
422 graphic_info[graphic].bitmap :
423 graphic_info[IMG_BACKGROUND].bitmap);
426 void DrawBackground(int dst_x, int dst_y, int width, int height)
428 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
430 redraw_mask |= REDRAW_FIELD;
435 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
437 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
439 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
440 SetDrawtoField(DRAW_BUFFERED);
443 SetDrawtoField(DRAW_BACKBUFFER);
445 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
447 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
448 SetDrawtoField(DRAW_DIRECT);
452 void MarkTileDirty(int x, int y)
454 int xx = redraw_x1 + x;
455 int yy = redraw_y1 + y;
460 redraw[xx][yy] = TRUE;
461 redraw_mask |= REDRAW_TILES;
464 void SetBorderElement()
468 BorderElement = EL_EMPTY;
470 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
472 for (x = 0; x < lev_fieldx; x++)
474 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
475 BorderElement = EL_STEELWALL;
477 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
483 void SetRandomAnimationValue(int x, int y)
485 gfx.anim_random_frame = GfxRandom[x][y];
488 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
490 /* animation synchronized with global frame counter, not move position */
491 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
492 sync_frame = FrameCounter;
494 return getAnimationFrame(graphic_info[graphic].anim_frames,
495 graphic_info[graphic].anim_delay,
496 graphic_info[graphic].anim_mode,
497 graphic_info[graphic].anim_start_frame,
501 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
502 int *x, int *y, boolean get_backside)
504 struct GraphicInfo *g = &graphic_info[graphic];
505 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
506 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
510 if (g->offset_y == 0) /* frames are ordered horizontally */
512 int max_width = g->anim_frames_per_line * g->width;
513 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
515 *x = pos % max_width;
516 *y = src_y % g->height + pos / max_width * g->height;
518 else if (g->offset_x == 0) /* frames are ordered vertically */
520 int max_height = g->anim_frames_per_line * g->height;
521 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
523 *x = src_x % g->width + pos / max_height * g->width;
524 *y = pos % max_height;
526 else /* frames are ordered diagonally */
528 *x = src_x + frame * g->offset_x;
529 *y = src_y + frame * g->offset_y;
533 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
535 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
538 void DrawGraphic(int x, int y, int graphic, int frame)
541 if (!IN_SCR_FIELD(x, y))
543 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
544 printf("DrawGraphic(): This should never happen!\n");
549 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
553 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
559 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
560 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
563 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
566 if (!IN_SCR_FIELD(x, y))
568 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
569 printf("DrawGraphicThruMask(): This should never happen!\n");
574 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
579 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
585 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
587 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
588 dst_x - src_x, dst_y - src_y);
589 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
592 void DrawMiniGraphic(int x, int y, int graphic)
594 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
595 MarkTileDirty(x / 2, y / 2);
598 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
600 struct GraphicInfo *g = &graphic_info[graphic];
602 int mini_starty = g->bitmap->height * 2 / 3;
605 *x = mini_startx + g->src_x / 2;
606 *y = mini_starty + g->src_y / 2;
609 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
614 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
615 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
618 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
619 int graphic, int frame,
620 int cut_mode, int mask_mode)
625 int width = TILEX, height = TILEY;
628 if (dx || dy) /* shifted graphic */
630 if (x < BX1) /* object enters playfield from the left */
637 else if (x > BX2) /* object enters playfield from the right */
643 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
649 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
651 else if (dx) /* general horizontal movement */
652 MarkTileDirty(x + SIGN(dx), y);
654 if (y < BY1) /* object enters playfield from the top */
656 if (cut_mode==CUT_BELOW) /* object completely above top border */
664 else if (y > BY2) /* object enters playfield from the bottom */
670 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
676 else if (dy > 0 && cut_mode == CUT_ABOVE)
678 if (y == BY2) /* object completely above bottom border */
684 MarkTileDirty(x, y + 1);
685 } /* object leaves playfield to the bottom */
686 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
688 else if (dy) /* general vertical movement */
689 MarkTileDirty(x, y + SIGN(dy));
693 if (!IN_SCR_FIELD(x, y))
695 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
696 printf("DrawGraphicShifted(): This should never happen!\n");
701 if (width > 0 && height > 0)
703 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
708 dst_x = FX + x * TILEX + dx;
709 dst_y = FY + y * TILEY + dy;
711 if (mask_mode == USE_MASKING)
713 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
714 dst_x - src_x, dst_y - src_y);
715 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
719 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
726 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
727 int graphic, int frame,
728 int cut_mode, int mask_mode)
733 int width = TILEX, height = TILEY;
736 int x2 = x + SIGN(dx);
737 int y2 = y + SIGN(dy);
738 int anim_frames = graphic_info[graphic].anim_frames;
739 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
740 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
741 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
743 /* re-calculate animation frame for two-tile movement animation */
744 frame = getGraphicAnimationFrame(graphic, sync_frame);
746 /* check if movement start graphic inside screen area and should be drawn */
747 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
749 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
751 dst_x = FX + x1 * TILEX;
752 dst_y = FY + y1 * TILEY;
754 if (mask_mode == USE_MASKING)
756 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
757 dst_x - src_x, dst_y - src_y);
758 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
762 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
765 MarkTileDirty(x1, y1);
768 /* check if movement end graphic inside screen area and should be drawn */
769 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
771 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
773 dst_x = FX + x2 * TILEX;
774 dst_y = FY + y2 * TILEY;
776 if (mask_mode == USE_MASKING)
778 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
779 dst_x - src_x, dst_y - src_y);
780 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
784 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
787 MarkTileDirty(x2, y2);
791 static void DrawGraphicShifted(int x, int y, int dx, int dy,
792 int graphic, int frame,
793 int cut_mode, int mask_mode)
797 DrawGraphic(x, y, graphic, frame);
802 if (graphic_info[graphic].double_movement) /* EM style movement images */
803 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
805 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
808 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
809 int frame, int cut_mode)
811 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
814 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
815 int cut_mode, int mask_mode)
817 int lx = LEVELX(x), ly = LEVELY(y);
821 if (IN_LEV_FIELD(lx, ly))
823 SetRandomAnimationValue(lx, ly);
825 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
826 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
828 /* do not use double (EM style) movement graphic when not moving */
829 if (graphic_info[graphic].double_movement && !dx && !dy)
831 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
832 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
835 else /* border element */
837 graphic = el2img(element);
838 frame = getGraphicAnimationFrame(graphic, -1);
841 if (element == EL_EXPANDABLE_WALL)
843 boolean left_stopped = FALSE, right_stopped = FALSE;
845 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
847 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
848 right_stopped = TRUE;
850 if (left_stopped && right_stopped)
852 else if (left_stopped)
854 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
855 frame = graphic_info[graphic].anim_frames - 1;
857 else if (right_stopped)
859 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
860 frame = graphic_info[graphic].anim_frames - 1;
865 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
866 else if (mask_mode == USE_MASKING)
867 DrawGraphicThruMask(x, y, graphic, frame);
869 DrawGraphic(x, y, graphic, frame);
872 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
873 int cut_mode, int mask_mode)
875 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
876 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
877 cut_mode, mask_mode);
880 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
883 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
886 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
889 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
892 void DrawLevelElementThruMask(int x, int y, int element)
894 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
897 void DrawLevelFieldThruMask(int x, int y)
899 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
902 #define TILE_GFX_ELEMENT(x, y) \
903 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
904 GfxElement[x][y] : Feld[x][y])
906 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
910 int sx = SCREENX(x), sy = SCREENY(y);
912 int width, height, cx, cy, i;
913 int crumbled_border_size = graphic_info[graphic].border_size;
914 static int xy[4][2] =
922 if (!IN_LEV_FIELD(x, y))
925 element = TILE_GFX_ELEMENT(x, y);
927 /* crumble field itself */
928 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
930 if (!IN_SCR_FIELD(sx, sy))
933 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
935 for (i = 0; i < 4; i++)
937 int xx = x + xy[i][0];
938 int yy = y + xy[i][1];
940 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
943 /* check if neighbour field is of same type */
944 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
947 if (i == 1 || i == 2)
949 width = crumbled_border_size;
951 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
957 height = crumbled_border_size;
959 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
962 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
963 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
966 MarkTileDirty(sx, sy);
968 else /* crumble neighbour fields */
970 for (i = 0; i < 4; i++)
972 int xx = x + xy[i][0];
973 int yy = y + xy[i][1];
974 int sxx = sx + xy[i][0];
975 int syy = sy + xy[i][1];
978 if (!IN_LEV_FIELD(xx, yy) ||
979 !IN_SCR_FIELD(sxx, syy) ||
984 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
988 element = TILE_GFX_ELEMENT(xx, yy);
990 if (!GFX_CRUMBLED(element))
993 if (!IN_LEV_FIELD(xx, yy) ||
994 !IN_SCR_FIELD(sxx, syy) ||
995 !GFX_CRUMBLED(Feld[xx][yy]) ||
1001 graphic = el_act2crm(element, ACTION_DEFAULT);
1003 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1005 crumbled_border_size = graphic_info[graphic].border_size;
1007 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1009 if (i == 1 || i == 2)
1011 width = crumbled_border_size;
1013 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1019 height = crumbled_border_size;
1021 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1024 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1025 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1027 MarkTileDirty(sxx, syy);
1032 void DrawLevelFieldCrumbledSand(int x, int y)
1036 if (!IN_LEV_FIELD(x, y))
1040 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1041 GFX_CRUMBLED(GfxElement[x][y]))
1043 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1049 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1051 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1054 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1057 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1060 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1061 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1062 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1063 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1064 int sx = SCREENX(x), sy = SCREENY(y);
1066 DrawGraphic(sx, sy, graphic1, frame1);
1067 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1070 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1072 int sx = SCREENX(x), sy = SCREENY(y);
1073 static int xy[4][2] =
1082 for (i = 0; i < 4; i++)
1084 int xx = x + xy[i][0];
1085 int yy = y + xy[i][1];
1086 int sxx = sx + xy[i][0];
1087 int syy = sy + xy[i][1];
1089 if (!IN_LEV_FIELD(xx, yy) ||
1090 !IN_SCR_FIELD(sxx, syy) ||
1091 !GFX_CRUMBLED(Feld[xx][yy]) ||
1095 DrawLevelField(xx, yy);
1099 static int getBorderElement(int x, int y)
1103 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1104 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1105 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1106 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1107 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1108 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1109 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1111 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1112 int steel_position = (x == -1 && y == -1 ? 0 :
1113 x == lev_fieldx && y == -1 ? 1 :
1114 x == -1 && y == lev_fieldy ? 2 :
1115 x == lev_fieldx && y == lev_fieldy ? 3 :
1116 x == -1 || x == lev_fieldx ? 4 :
1117 y == -1 || y == lev_fieldy ? 5 : 6);
1119 return border[steel_position][steel_type];
1122 void DrawScreenElement(int x, int y, int element)
1124 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1125 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1128 void DrawLevelElement(int x, int y, int element)
1130 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1131 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1134 void DrawScreenField(int x, int y)
1136 int lx = LEVELX(x), ly = LEVELY(y);
1137 int element, content;
1139 if (!IN_LEV_FIELD(lx, ly))
1141 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1144 element = getBorderElement(lx, ly);
1146 DrawScreenElement(x, y, element);
1150 element = Feld[lx][ly];
1151 content = Store[lx][ly];
1153 if (IS_MOVING(lx, ly))
1155 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1156 boolean cut_mode = NO_CUTTING;
1158 if (element == EL_QUICKSAND_EMPTYING ||
1159 element == EL_MAGIC_WALL_EMPTYING ||
1160 element == EL_BD_MAGIC_WALL_EMPTYING ||
1161 element == EL_AMOEBA_DROPPING)
1162 cut_mode = CUT_ABOVE;
1163 else if (element == EL_QUICKSAND_FILLING ||
1164 element == EL_MAGIC_WALL_FILLING ||
1165 element == EL_BD_MAGIC_WALL_FILLING)
1166 cut_mode = CUT_BELOW;
1168 if (cut_mode == CUT_ABOVE)
1169 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1171 DrawScreenElement(x, y, EL_EMPTY);
1174 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1175 else if (cut_mode == NO_CUTTING)
1176 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1178 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1180 if (content == EL_ACID)
1182 int dir = MovDir[lx][ly];
1183 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1184 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1186 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1189 else if (IS_BLOCKED(lx, ly))
1194 boolean cut_mode = NO_CUTTING;
1195 int element_old, content_old;
1197 Blocked2Moving(lx, ly, &oldx, &oldy);
1200 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1201 MovDir[oldx][oldy] == MV_RIGHT);
1203 element_old = Feld[oldx][oldy];
1204 content_old = Store[oldx][oldy];
1206 if (element_old == EL_QUICKSAND_EMPTYING ||
1207 element_old == EL_MAGIC_WALL_EMPTYING ||
1208 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1209 element_old == EL_AMOEBA_DROPPING)
1210 cut_mode = CUT_ABOVE;
1212 DrawScreenElement(x, y, EL_EMPTY);
1215 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1217 else if (cut_mode == NO_CUTTING)
1218 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1221 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1224 else if (IS_DRAWABLE(element))
1225 DrawScreenElement(x, y, element);
1227 DrawScreenElement(x, y, EL_EMPTY);
1230 void DrawLevelField(int x, int y)
1232 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1233 DrawScreenField(SCREENX(x), SCREENY(y));
1234 else if (IS_MOVING(x, y))
1238 Moving2Blocked(x, y, &newx, &newy);
1239 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1240 DrawScreenField(SCREENX(newx), SCREENY(newy));
1242 else if (IS_BLOCKED(x, y))
1246 Blocked2Moving(x, y, &oldx, &oldy);
1247 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1248 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1252 void DrawMiniElement(int x, int y, int element)
1256 graphic = el2edimg(element);
1257 DrawMiniGraphic(x, y, graphic);
1260 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1262 int x = sx + scroll_x, y = sy + scroll_y;
1264 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1265 DrawMiniElement(sx, sy, EL_EMPTY);
1266 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1267 DrawMiniElement(sx, sy, Feld[x][y]);
1269 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1272 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1273 int x, int y, int xsize, int ysize, int font_nr)
1275 int font_width = getFontWidth(font_nr);
1276 int font_height = getFontHeight(font_nr);
1277 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1280 int dst_x = SX + startx + x * font_width;
1281 int dst_y = SY + starty + y * font_height;
1282 int width = graphic_info[graphic].width;
1283 int height = graphic_info[graphic].height;
1284 int inner_width = MAX(width - 2 * font_width, font_width);
1285 int inner_height = MAX(height - 2 * font_height, font_height);
1286 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1287 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1288 boolean draw_masked = graphic_info[graphic].draw_masked;
1290 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1292 if (src_bitmap == NULL || width < font_width || height < font_height)
1294 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1298 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1299 inner_sx + (x - 1) * font_width % inner_width);
1300 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1301 inner_sy + (y - 1) * font_height % inner_height);
1305 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1306 dst_x - src_x, dst_y - src_y);
1307 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1311 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1315 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1317 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1318 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1319 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1320 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1321 boolean no_delay = (tape.warp_forward);
1322 unsigned long anim_delay = 0;
1323 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1324 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1325 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1326 int font_width = getFontWidth(font_nr);
1327 int font_height = getFontHeight(font_nr);
1328 int max_xsize = level.envelope_xsize[envelope_nr];
1329 int max_ysize = level.envelope_ysize[envelope_nr];
1330 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1331 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1332 int xend = max_xsize;
1333 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1334 int xstep = (xstart < xend ? 1 : 0);
1335 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1338 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1340 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1341 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1342 int sx = (SXSIZE - xsize * font_width) / 2;
1343 int sy = (SYSIZE - ysize * font_height) / 2;
1346 SetDrawtoField(DRAW_BUFFERED);
1348 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1350 SetDrawtoField(DRAW_BACKBUFFER);
1352 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1353 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1355 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1356 level.envelope_text[envelope_nr], font_nr, max_xsize,
1357 xsize - 2, ysize - 2, mask_mode);
1359 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1362 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1366 void ShowEnvelope(int envelope_nr)
1368 int element = EL_ENVELOPE_1 + envelope_nr;
1369 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1370 int sound_opening = element_info[element].sound[ACTION_OPENING];
1371 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1372 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1373 boolean no_delay = (tape.warp_forward);
1374 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1375 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1376 int anim_mode = graphic_info[graphic].anim_mode;
1377 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1378 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1380 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1382 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1384 if (anim_mode == ANIM_DEFAULT)
1385 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1387 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1390 Delay(wait_delay_value);
1392 WaitForEventToContinue();
1394 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1396 if (anim_mode != ANIM_NONE)
1397 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1399 if (anim_mode == ANIM_DEFAULT)
1400 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1402 game.envelope_active = FALSE;
1404 SetDrawtoField(DRAW_BUFFERED);
1406 redraw_mask |= REDRAW_FIELD;
1410 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1412 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1413 int mini_startx = src_bitmap->width * 3 / 4;
1414 int mini_starty = src_bitmap->height * 2 / 3;
1415 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1416 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1418 *bitmap = src_bitmap;
1423 void DrawMicroElement(int xpos, int ypos, int element)
1427 int graphic = el2preimg(element);
1429 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1430 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1438 SetDrawBackgroundMask(REDRAW_NONE);
1441 for (x = BX1; x <= BX2; x++)
1442 for (y = BY1; y <= BY2; y++)
1443 DrawScreenField(x, y);
1445 redraw_mask |= REDRAW_FIELD;
1448 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1452 for (x = 0; x < size_x; x++)
1453 for (y = 0; y < size_y; y++)
1454 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1456 redraw_mask |= REDRAW_FIELD;
1459 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1463 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1465 if (lev_fieldx < STD_LEV_FIELDX)
1466 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1467 if (lev_fieldy < STD_LEV_FIELDY)
1468 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1470 xpos += MICRO_TILEX;
1471 ypos += MICRO_TILEY;
1473 for (x = -1; x <= STD_LEV_FIELDX; x++)
1475 for (y = -1; y <= STD_LEV_FIELDY; y++)
1477 int lx = from_x + x, ly = from_y + y;
1479 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1480 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1481 level.field[lx][ly]);
1482 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1483 && BorderElement != EL_EMPTY)
1484 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1485 getBorderElement(lx, ly));
1489 redraw_mask |= REDRAW_MICROLEVEL;
1492 #define MICROLABEL_EMPTY 0
1493 #define MICROLABEL_LEVEL_NAME 1
1494 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1495 #define MICROLABEL_LEVEL_AUTHOR 3
1496 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1497 #define MICROLABEL_IMPORTED_FROM 5
1498 #define MICROLABEL_IMPORTED_BY_HEAD 6
1499 #define MICROLABEL_IMPORTED_BY 7
1501 static void DrawMicroLevelLabelExt(int mode)
1503 char label_text[MAX_OUTPUT_LINESIZE + 1];
1504 int max_len_label_text;
1505 int font_nr = FONT_TEXT_2;
1508 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1509 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1510 mode == MICROLABEL_IMPORTED_BY_HEAD)
1511 font_nr = FONT_TEXT_3;
1513 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1515 for (i = 0; i < max_len_label_text; i++)
1516 label_text[i] = ' ';
1517 label_text[max_len_label_text] = '\0';
1519 if (strlen(label_text) > 0)
1521 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1522 int lypos = MICROLABEL2_YPOS;
1524 DrawText(lxpos, lypos, label_text, font_nr);
1528 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1529 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1530 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1531 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1532 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1533 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1534 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1535 max_len_label_text);
1536 label_text[max_len_label_text] = '\0';
1538 if (strlen(label_text) > 0)
1540 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1541 int lypos = MICROLABEL2_YPOS;
1543 DrawText(lxpos, lypos, label_text, font_nr);
1546 redraw_mask |= REDRAW_MICROLEVEL;
1549 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1551 static unsigned long scroll_delay = 0;
1552 static unsigned long label_delay = 0;
1553 static int from_x, from_y, scroll_direction;
1554 static int label_state, label_counter;
1555 int last_game_status = game_status; /* save current game status */
1557 /* force PREVIEW font on preview level */
1558 game_status = GAME_MODE_PSEUDO_PREVIEW;
1562 from_x = from_y = 0;
1563 scroll_direction = MV_RIGHT;
1567 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1568 DrawMicroLevelLabelExt(label_state);
1570 /* initialize delay counters */
1571 DelayReached(&scroll_delay, 0);
1572 DelayReached(&label_delay, 0);
1574 if (leveldir_current->name)
1576 char label_text[MAX_OUTPUT_LINESIZE + 1];
1577 int font_nr = FONT_TEXT_1;
1578 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1581 strncpy(label_text, leveldir_current->name, max_len_label_text);
1582 label_text[max_len_label_text] = '\0';
1584 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1585 lypos = SY + MICROLABEL1_YPOS;
1587 DrawText(lxpos, lypos, label_text, font_nr);
1590 game_status = last_game_status; /* restore current game status */
1595 /* scroll micro level, if needed */
1596 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1597 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1599 switch (scroll_direction)
1605 scroll_direction = MV_UP;
1609 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1612 scroll_direction = MV_DOWN;
1619 scroll_direction = MV_RIGHT;
1623 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1626 scroll_direction = MV_LEFT;
1633 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1636 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1637 /* redraw micro level label, if needed */
1638 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1639 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1640 strcmp(level.author, leveldir_current->name) != 0 &&
1641 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1643 int max_label_counter = 23;
1645 if (leveldir_current->imported_from != NULL &&
1646 strlen(leveldir_current->imported_from) > 0)
1647 max_label_counter += 14;
1648 if (leveldir_current->imported_by != NULL &&
1649 strlen(leveldir_current->imported_by) > 0)
1650 max_label_counter += 14;
1652 label_counter = (label_counter + 1) % max_label_counter;
1653 label_state = (label_counter >= 0 && label_counter <= 7 ?
1654 MICROLABEL_LEVEL_NAME :
1655 label_counter >= 9 && label_counter <= 12 ?
1656 MICROLABEL_LEVEL_AUTHOR_HEAD :
1657 label_counter >= 14 && label_counter <= 21 ?
1658 MICROLABEL_LEVEL_AUTHOR :
1659 label_counter >= 23 && label_counter <= 26 ?
1660 MICROLABEL_IMPORTED_FROM_HEAD :
1661 label_counter >= 28 && label_counter <= 35 ?
1662 MICROLABEL_IMPORTED_FROM :
1663 label_counter >= 37 && label_counter <= 40 ?
1664 MICROLABEL_IMPORTED_BY_HEAD :
1665 label_counter >= 42 && label_counter <= 49 ?
1666 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1668 if (leveldir_current->imported_from == NULL &&
1669 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1670 label_state == MICROLABEL_IMPORTED_FROM))
1671 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1672 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1674 DrawMicroLevelLabelExt(label_state);
1677 game_status = last_game_status; /* restore current game status */
1680 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1681 int graphic, int sync_frame, int mask_mode)
1683 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1685 if (mask_mode == USE_MASKING)
1686 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1688 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1691 inline void DrawGraphicAnimation(int x, int y, int graphic)
1693 int lx = LEVELX(x), ly = LEVELY(y);
1695 if (!IN_SCR_FIELD(x, y))
1698 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1699 graphic, GfxFrame[lx][ly], NO_MASKING);
1700 MarkTileDirty(x, y);
1703 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1705 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1708 void DrawLevelElementAnimation(int x, int y, int element)
1710 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1712 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1715 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1717 int sx = SCREENX(x), sy = SCREENY(y);
1719 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1722 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1725 DrawGraphicAnimation(sx, sy, graphic);
1728 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1729 DrawLevelFieldCrumbledSand(x, y);
1731 if (GFX_CRUMBLED(Feld[x][y]))
1732 DrawLevelFieldCrumbledSand(x, y);
1736 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1738 int sx = SCREENX(x), sy = SCREENY(y);
1741 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1744 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1746 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1749 DrawGraphicAnimation(sx, sy, graphic);
1751 if (GFX_CRUMBLED(element))
1752 DrawLevelFieldCrumbledSand(x, y);
1755 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1757 if (player->use_murphy)
1759 /* this works only because currently only one player can be "murphy" ... */
1760 static int last_horizontal_dir = MV_LEFT;
1761 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1763 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1764 last_horizontal_dir = move_dir;
1766 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1768 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1770 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1776 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1779 static boolean equalGraphics(int graphic1, int graphic2)
1781 struct GraphicInfo *g1 = &graphic_info[graphic1];
1782 struct GraphicInfo *g2 = &graphic_info[graphic2];
1784 return (g1->bitmap == g2->bitmap &&
1785 g1->src_x == g2->src_x &&
1786 g1->src_y == g2->src_y &&
1787 g1->anim_frames == g2->anim_frames &&
1788 g1->anim_delay == g2->anim_delay &&
1789 g1->anim_mode == g2->anim_mode);
1792 void DrawAllPlayers()
1796 for (i = 0; i < MAX_PLAYERS; i++)
1797 if (stored_player[i].active)
1798 DrawPlayer(&stored_player[i]);
1801 void DrawPlayerField(int x, int y)
1803 if (!IS_PLAYER(x, y))
1806 DrawPlayer(PLAYERINFO(x, y));
1809 void DrawPlayer(struct PlayerInfo *player)
1811 int jx = player->jx;
1812 int jy = player->jy;
1813 int move_dir = player->MovDir;
1814 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1815 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1816 int last_jx = (player->is_moving ? jx - dx : jx);
1817 int last_jy = (player->is_moving ? jy - dy : jy);
1818 int next_jx = jx + dx;
1819 int next_jy = jy + dy;
1820 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1821 int sx = SCREENX(jx), sy = SCREENY(jy);
1822 int sxx = 0, syy = 0;
1823 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1825 int action = ACTION_DEFAULT;
1826 int last_player_graphic = getPlayerGraphic(player, move_dir);
1827 int last_player_frame = player->Frame;
1830 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1834 if (!IN_LEV_FIELD(jx, jy))
1836 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1837 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1838 printf("DrawPlayerField(): This should never happen!\n");
1843 if (element == EL_EXPLOSION)
1846 action = (player->is_pushing ? ACTION_PUSHING :
1847 player->is_digging ? ACTION_DIGGING :
1848 player->is_collecting ? ACTION_COLLECTING :
1849 player->is_moving ? ACTION_MOVING :
1850 player->is_snapping ? ACTION_SNAPPING :
1851 player->is_dropping ? ACTION_DROPPING :
1852 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1854 InitPlayerGfxAnimation(player, action, move_dir);
1856 /* ----------------------------------------------------------------------- */
1857 /* draw things in the field the player is leaving, if needed */
1858 /* ----------------------------------------------------------------------- */
1860 if (player->is_moving)
1862 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1864 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1866 if (last_element == EL_DYNAMITE_ACTIVE ||
1867 last_element == EL_SP_DISK_RED_ACTIVE)
1868 DrawDynamite(last_jx, last_jy);
1870 DrawLevelFieldThruMask(last_jx, last_jy);
1872 else if (last_element == EL_DYNAMITE_ACTIVE ||
1873 last_element == EL_SP_DISK_RED_ACTIVE)
1874 DrawDynamite(last_jx, last_jy);
1876 DrawLevelField(last_jx, last_jy);
1878 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1879 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1882 if (!IN_SCR_FIELD(sx, sy))
1885 if (setup.direct_draw)
1886 SetDrawtoField(DRAW_BUFFERED);
1888 /* ----------------------------------------------------------------------- */
1889 /* draw things behind the player, if needed */
1890 /* ----------------------------------------------------------------------- */
1893 DrawLevelElement(jx, jy, Back[jx][jy]);
1894 else if (IS_ACTIVE_BOMB(element))
1895 DrawLevelElement(jx, jy, EL_EMPTY);
1898 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1900 if (GFX_CRUMBLED(GfxElement[jx][jy]))
1901 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1904 int old_element = GfxElement[jx][jy];
1905 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1906 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1908 DrawGraphic(sx, sy, old_graphic, frame);
1913 GfxElement[jx][jy] = EL_UNDEFINED;
1915 /* make sure that pushed elements are drawn with correct frame rate */
1916 if (player->is_pushing && player->is_moving)
1917 GfxFrame[jx][jy] = player->StepFrame;
1919 DrawLevelField(jx, jy);
1923 /* ----------------------------------------------------------------------- */
1924 /* draw player himself */
1925 /* ----------------------------------------------------------------------- */
1927 graphic = getPlayerGraphic(player, move_dir);
1929 /* in the case of changed player action or direction, prevent the current
1930 animation frame from being restarted for identical animations */
1931 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1932 player->Frame = last_player_frame;
1934 frame = getGraphicAnimationFrame(graphic, player->Frame);
1938 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1939 sxx = player->GfxPos;
1941 syy = player->GfxPos;
1944 if (!setup.soft_scrolling && ScreenMovPos)
1947 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1949 if (SHIELD_ON(player))
1951 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1952 IMG_SHIELD_NORMAL_ACTIVE);
1953 int frame = getGraphicAnimationFrame(graphic, -1);
1955 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1958 /* ----------------------------------------------------------------------- */
1959 /* draw things the player is pushing, if needed */
1960 /* ----------------------------------------------------------------------- */
1963 printf("::: %d, %d [%d, %d] [%d]\n",
1964 player->is_pushing, player_is_moving, player->GfxAction,
1965 player->is_moving, player_is_moving);
1969 if (player->is_pushing && player->is_moving)
1971 int px = SCREENX(jx), py = SCREENY(jy);
1972 int pxx = (TILEX - ABS(sxx)) * dx;
1973 int pyy = (TILEY - ABS(syy)) * dy;
1978 if (!IS_MOVING(jx, jy)) /* push movement already finished */
1979 element = Feld[next_jx][next_jy];
1981 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
1982 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
1984 /* draw background element under pushed element (like the Sokoban field) */
1985 if (Back[next_jx][next_jy])
1986 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
1988 /* masked drawing is needed for EMC style (double) movement graphics */
1989 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
1993 /* ----------------------------------------------------------------------- */
1994 /* draw things in front of player (active dynamite or dynabombs) */
1995 /* ----------------------------------------------------------------------- */
1997 if (IS_ACTIVE_BOMB(element))
1999 graphic = el2img(element);
2000 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2002 if (game.emulation == EMU_SUPAPLEX)
2003 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2005 DrawGraphicThruMask(sx, sy, graphic, frame);
2008 if (player_is_moving && last_element == EL_EXPLOSION)
2010 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
2011 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2012 int phase = ExplodePhase[last_jx][last_jy] - 1;
2013 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2016 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2019 /* ----------------------------------------------------------------------- */
2020 /* draw elements the player is just walking/passing through/under */
2021 /* ----------------------------------------------------------------------- */
2023 if (player_is_moving)
2025 /* handle the field the player is leaving ... */
2026 if (IS_ACCESSIBLE_INSIDE(last_element))
2027 DrawLevelField(last_jx, last_jy);
2028 else if (IS_ACCESSIBLE_UNDER(last_element))
2029 DrawLevelFieldThruMask(last_jx, last_jy);
2032 /* do not redraw accessible elements if the player is just pushing them */
2033 if (!player_is_moving || !player->is_pushing)
2035 /* ... and the field the player is entering */
2036 if (IS_ACCESSIBLE_INSIDE(element))
2037 DrawLevelField(jx, jy);
2038 else if (IS_ACCESSIBLE_UNDER(element))
2039 DrawLevelFieldThruMask(jx, jy);
2042 if (setup.direct_draw)
2044 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2045 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2046 int x_size = TILEX * (1 + ABS(jx - last_jx));
2047 int y_size = TILEY * (1 + ABS(jy - last_jy));
2049 BlitBitmap(drawto_field, window,
2050 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2051 SetDrawtoField(DRAW_DIRECT);
2054 MarkTileDirty(sx, sy);
2057 /* ------------------------------------------------------------------------- */
2059 void WaitForEventToContinue()
2061 boolean still_wait = TRUE;
2063 /* simulate releasing mouse button over last gadget, if still pressed */
2065 HandleGadgets(-1, -1, 0);
2067 button_status = MB_RELEASED;
2079 case EVENT_BUTTONPRESS:
2080 case EVENT_KEYPRESS:
2084 case EVENT_KEYRELEASE:
2085 ClearPlayerAction();
2089 HandleOtherEvents(&event);
2093 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2100 /* don't eat all CPU time */
2105 #define MAX_REQUEST_LINES 13
2106 #define MAX_REQUEST_LINE_FONT1_LEN 7
2107 #define MAX_REQUEST_LINE_FONT2_LEN 10
2109 boolean Request(char *text, unsigned int req_state)
2111 int mx, my, ty, result = -1;
2112 unsigned int old_door_state;
2113 int last_game_status = game_status; /* save current game status */
2114 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2115 int font_nr = FONT_TEXT_2;
2116 int max_word_len = 0;
2119 for (text_ptr = text; *text_ptr; text_ptr++)
2121 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2123 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2125 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2126 font_nr = FONT_LEVEL_NUMBER;
2132 if (game_status == GAME_MODE_PLAYING &&
2133 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2134 BlitScreenToBitmap_EM(backbuffer);
2136 /* disable deactivated drawing when quick-loading level tape recording */
2137 if (tape.playing && tape.deactivate_display)
2138 TapeDeactivateDisplayOff(TRUE);
2140 SetMouseCursor(CURSOR_DEFAULT);
2142 #if defined(NETWORK_AVALIABLE)
2143 /* pause network game while waiting for request to answer */
2144 if (options.network &&
2145 game_status == GAME_MODE_PLAYING &&
2146 req_state & REQUEST_WAIT_FOR_INPUT)
2147 SendToServer_PausePlaying();
2150 old_door_state = GetDoorState();
2152 /* simulate releasing mouse button over last gadget, if still pressed */
2154 HandleGadgets(-1, -1, 0);
2158 if (old_door_state & DOOR_OPEN_1)
2160 CloseDoor(DOOR_CLOSE_1);
2162 /* save old door content */
2163 BlitBitmap(bitmap_db_door, bitmap_db_door,
2164 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2165 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2168 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2170 /* clear door drawing field */
2171 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2173 /* force DOOR font on preview level */
2174 game_status = GAME_MODE_PSEUDO_DOOR;
2176 /* write text for request */
2177 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2179 char text_line[max_request_line_len + 1];
2185 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2188 if (!tc || tc == ' ')
2199 strncpy(text_line, text, tl);
2202 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2203 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2204 text_line, font_nr);
2206 text += tl + (tc == ' ' ? 1 : 0);
2209 game_status = last_game_status; /* restore current game status */
2211 if (req_state & REQ_ASK)
2213 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2214 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2216 else if (req_state & REQ_CONFIRM)
2218 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2220 else if (req_state & REQ_PLAYER)
2222 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2223 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2224 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2225 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2228 /* copy request gadgets to door backbuffer */
2229 BlitBitmap(drawto, bitmap_db_door,
2230 DX, DY, DXSIZE, DYSIZE,
2231 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2233 OpenDoor(DOOR_OPEN_1);
2235 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2237 SetDrawBackgroundMask(REDRAW_FIELD);
2242 if (game_status != GAME_MODE_MAIN)
2245 button_status = MB_RELEASED;
2247 request_gadget_id = -1;
2249 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2261 case EVENT_BUTTONPRESS:
2262 case EVENT_BUTTONRELEASE:
2263 case EVENT_MOTIONNOTIFY:
2265 if (event.type == EVENT_MOTIONNOTIFY)
2267 if (!PointerInWindow(window))
2268 continue; /* window and pointer are on different screens */
2273 motion_status = TRUE;
2274 mx = ((MotionEvent *) &event)->x;
2275 my = ((MotionEvent *) &event)->y;
2279 motion_status = FALSE;
2280 mx = ((ButtonEvent *) &event)->x;
2281 my = ((ButtonEvent *) &event)->y;
2282 if (event.type == EVENT_BUTTONPRESS)
2283 button_status = ((ButtonEvent *) &event)->button;
2285 button_status = MB_RELEASED;
2288 /* this sets 'request_gadget_id' */
2289 HandleGadgets(mx, my, button_status);
2291 switch(request_gadget_id)
2293 case TOOL_CTRL_ID_YES:
2296 case TOOL_CTRL_ID_NO:
2299 case TOOL_CTRL_ID_CONFIRM:
2300 result = TRUE | FALSE;
2303 case TOOL_CTRL_ID_PLAYER_1:
2306 case TOOL_CTRL_ID_PLAYER_2:
2309 case TOOL_CTRL_ID_PLAYER_3:
2312 case TOOL_CTRL_ID_PLAYER_4:
2323 case EVENT_KEYPRESS:
2324 switch(GetEventKey((KeyEvent *)&event, TRUE))
2337 if (req_state & REQ_PLAYER)
2341 case EVENT_KEYRELEASE:
2342 ClearPlayerAction();
2346 HandleOtherEvents(&event);
2350 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2352 int joy = AnyJoystick();
2354 if (joy & JOY_BUTTON_1)
2356 else if (joy & JOY_BUTTON_2)
2362 /* don't eat all CPU time */
2366 if (game_status != GAME_MODE_MAIN)
2371 if (!(req_state & REQ_STAY_OPEN))
2373 CloseDoor(DOOR_CLOSE_1);
2375 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2376 (req_state & REQ_REOPEN))
2377 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2382 SetDrawBackgroundMask(REDRAW_FIELD);
2384 #if defined(NETWORK_AVALIABLE)
2385 /* continue network game after request */
2386 if (options.network &&
2387 game_status == GAME_MODE_PLAYING &&
2388 req_state & REQUEST_WAIT_FOR_INPUT)
2389 SendToServer_ContinuePlaying();
2392 /* restore deactivated drawing when quick-loading level tape recording */
2393 if (tape.playing && tape.deactivate_display)
2394 TapeDeactivateDisplayOn();
2399 unsigned int OpenDoor(unsigned int door_state)
2401 if (door_state & DOOR_COPY_BACK)
2403 if (door_state & DOOR_OPEN_1)
2404 BlitBitmap(bitmap_db_door, bitmap_db_door,
2405 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2406 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2408 if (door_state & DOOR_OPEN_2)
2409 BlitBitmap(bitmap_db_door, bitmap_db_door,
2410 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2411 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2413 door_state &= ~DOOR_COPY_BACK;
2416 return MoveDoor(door_state);
2419 unsigned int CloseDoor(unsigned int door_state)
2421 unsigned int old_door_state = GetDoorState();
2423 if (!(door_state & DOOR_NO_COPY_BACK))
2425 if (old_door_state & DOOR_OPEN_1)
2426 BlitBitmap(backbuffer, bitmap_db_door,
2427 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2429 if (old_door_state & DOOR_OPEN_2)
2430 BlitBitmap(backbuffer, bitmap_db_door,
2431 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2433 door_state &= ~DOOR_NO_COPY_BACK;
2436 return MoveDoor(door_state);
2439 unsigned int GetDoorState()
2441 return MoveDoor(DOOR_GET_STATE);
2444 unsigned int SetDoorState(unsigned int door_state)
2446 return MoveDoor(door_state | DOOR_SET_STATE);
2449 unsigned int MoveDoor(unsigned int door_state)
2451 static int door1 = DOOR_OPEN_1;
2452 static int door2 = DOOR_CLOSE_2;
2453 unsigned long door_delay = 0;
2454 unsigned long door_delay_value;
2457 if (door_1.width < 0 || door_1.width > DXSIZE)
2458 door_1.width = DXSIZE;
2459 if (door_1.height < 0 || door_1.height > DYSIZE)
2460 door_1.height = DYSIZE;
2461 if (door_2.width < 0 || door_2.width > VXSIZE)
2462 door_2.width = VXSIZE;
2463 if (door_2.height < 0 || door_2.height > VYSIZE)
2464 door_2.height = VYSIZE;
2466 if (door_state == DOOR_GET_STATE)
2467 return(door1 | door2);
2469 if (door_state & DOOR_SET_STATE)
2471 if (door_state & DOOR_ACTION_1)
2472 door1 = door_state & DOOR_ACTION_1;
2473 if (door_state & DOOR_ACTION_2)
2474 door2 = door_state & DOOR_ACTION_2;
2476 return(door1 | door2);
2479 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2480 door_state &= ~DOOR_OPEN_1;
2481 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2482 door_state &= ~DOOR_CLOSE_1;
2483 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2484 door_state &= ~DOOR_OPEN_2;
2485 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2486 door_state &= ~DOOR_CLOSE_2;
2488 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2491 if (setup.quick_doors)
2493 stepsize = 20; /* must be choosen to always draw last frame */
2494 door_delay_value = 0;
2497 if (global.autoplay_leveldir)
2499 door_state |= DOOR_NO_DELAY;
2500 door_state &= ~DOOR_CLOSE_ALL;
2503 if (door_state & DOOR_ACTION)
2505 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2506 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2507 boolean door_1_done = (!handle_door_1);
2508 boolean door_2_done = (!handle_door_2);
2509 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2510 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2511 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2512 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2513 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2514 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2515 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2516 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2517 int door_skip = max_door_size - door_size;
2519 int end = door_size;
2521 int end = (door_state & DOOR_ACTION_1 &&
2522 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2525 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2527 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2531 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2533 /* opening door sound has priority over simultaneously closing door */
2534 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2535 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2536 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2537 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2540 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2543 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2544 GC gc = bitmap->stored_clip_gc;
2546 if (door_state & DOOR_ACTION_1)
2548 int a = MIN(x * door_1.step_offset, end);
2549 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2550 int i = p + door_skip;
2552 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2554 BlitBitmap(bitmap_db_door, drawto,
2555 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2556 DXSIZE, DYSIZE, DX, DY);
2560 BlitBitmap(bitmap_db_door, drawto,
2561 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2562 DXSIZE, DYSIZE - p / 2, DX, DY);
2564 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2567 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2569 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2570 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2571 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2572 int dst2_x = DX, dst2_y = DY;
2573 int width = i, height = DYSIZE;
2575 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2576 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2579 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2580 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2583 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2585 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2586 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2587 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2588 int dst2_x = DX, dst2_y = DY;
2589 int width = DXSIZE, height = i;
2591 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2592 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2595 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2596 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2599 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2601 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2603 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2604 BlitBitmapMasked(bitmap, drawto,
2605 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2606 DX + DXSIZE - i, DY + j);
2607 BlitBitmapMasked(bitmap, drawto,
2608 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2609 DX + DXSIZE - i, DY + 140 + j);
2610 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2611 DY - (DOOR_GFX_PAGEY1 + j));
2612 BlitBitmapMasked(bitmap, drawto,
2613 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2615 BlitBitmapMasked(bitmap, drawto,
2616 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2619 BlitBitmapMasked(bitmap, drawto,
2620 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2622 BlitBitmapMasked(bitmap, drawto,
2623 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2625 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2626 BlitBitmapMasked(bitmap, drawto,
2627 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2628 DX + DXSIZE - i, DY + 77 + j);
2629 BlitBitmapMasked(bitmap, drawto,
2630 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2631 DX + DXSIZE - i, DY + 203 + j);
2634 redraw_mask |= REDRAW_DOOR_1;
2635 door_1_done = (a == end);
2638 if (door_state & DOOR_ACTION_2)
2640 int a = MIN(x * door_2.step_offset, door_size_2);
2641 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2642 int i = p + door_skip;
2644 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2646 BlitBitmap(bitmap_db_door, drawto,
2647 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2648 VXSIZE, VYSIZE, VX, VY);
2650 else if (x <= VYSIZE)
2652 BlitBitmap(bitmap_db_door, drawto,
2653 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2654 VXSIZE, VYSIZE - p / 2, VX, VY);
2656 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2659 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2661 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2662 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2663 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2664 int dst2_x = VX, dst2_y = VY;
2665 int width = i, height = VYSIZE;
2667 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2668 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2671 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2672 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2675 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2677 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2678 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2679 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2680 int dst2_x = VX, dst2_y = VY;
2681 int width = VXSIZE, height = i;
2683 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2684 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2687 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2688 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2691 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2693 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2695 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2696 BlitBitmapMasked(bitmap, drawto,
2697 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2698 VX + VXSIZE - i, VY + j);
2699 SetClipOrigin(bitmap, gc,
2700 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2701 BlitBitmapMasked(bitmap, drawto,
2702 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2705 BlitBitmapMasked(bitmap, drawto,
2706 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2707 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2708 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2709 BlitBitmapMasked(bitmap, drawto,
2710 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2712 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2715 redraw_mask |= REDRAW_DOOR_2;
2716 door_2_done = (a == VXSIZE);
2721 if (game_status == GAME_MODE_MAIN)
2724 if (!(door_state & DOOR_NO_DELAY))
2725 WaitUntilDelayReached(&door_delay, door_delay_value);
2729 if (door_state & DOOR_ACTION_1)
2730 door1 = door_state & DOOR_ACTION_1;
2731 if (door_state & DOOR_ACTION_2)
2732 door2 = door_state & DOOR_ACTION_2;
2734 return (door1 | door2);
2737 void DrawSpecialEditorDoor()
2739 /* draw bigger toolbox window */
2740 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2741 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2743 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2744 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2747 redraw_mask |= REDRAW_ALL;
2750 void UndrawSpecialEditorDoor()
2752 /* draw normal tape recorder window */
2753 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2754 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2757 redraw_mask |= REDRAW_ALL;
2761 /* ---------- new tool button stuff ---------------------------------------- */
2763 /* graphic position values for tool buttons */
2764 #define TOOL_BUTTON_YES_XPOS 2
2765 #define TOOL_BUTTON_YES_YPOS 250
2766 #define TOOL_BUTTON_YES_GFX_YPOS 0
2767 #define TOOL_BUTTON_YES_XSIZE 46
2768 #define TOOL_BUTTON_YES_YSIZE 28
2769 #define TOOL_BUTTON_NO_XPOS 52
2770 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2771 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2772 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2773 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2774 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2775 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2776 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2777 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2778 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2779 #define TOOL_BUTTON_PLAYER_XSIZE 30
2780 #define TOOL_BUTTON_PLAYER_YSIZE 30
2781 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2782 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2783 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2784 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2785 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2786 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2787 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2788 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2789 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2790 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2791 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2792 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2793 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2794 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2795 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2796 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2797 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2798 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2799 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2800 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2809 } toolbutton_info[NUM_TOOL_BUTTONS] =
2812 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2813 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2814 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2819 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2820 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2821 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2826 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2827 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2828 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2829 TOOL_CTRL_ID_CONFIRM,
2833 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2834 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2835 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2836 TOOL_CTRL_ID_PLAYER_1,
2840 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2841 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2842 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2843 TOOL_CTRL_ID_PLAYER_2,
2847 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2848 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2849 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2850 TOOL_CTRL_ID_PLAYER_3,
2854 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2855 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2856 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2857 TOOL_CTRL_ID_PLAYER_4,
2862 void CreateToolButtons()
2866 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2868 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2869 Bitmap *deco_bitmap = None;
2870 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2871 struct GadgetInfo *gi;
2872 unsigned long event_mask;
2873 int gd_xoffset, gd_yoffset;
2874 int gd_x1, gd_x2, gd_y;
2877 event_mask = GD_EVENT_RELEASED;
2879 gd_xoffset = toolbutton_info[i].xpos;
2880 gd_yoffset = toolbutton_info[i].ypos;
2881 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2882 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2883 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2885 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2887 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2889 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2890 &deco_bitmap, &deco_x, &deco_y);
2891 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2892 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2895 gi = CreateGadget(GDI_CUSTOM_ID, id,
2896 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2897 GDI_X, DX + toolbutton_info[i].x,
2898 GDI_Y, DY + toolbutton_info[i].y,
2899 GDI_WIDTH, toolbutton_info[i].width,
2900 GDI_HEIGHT, toolbutton_info[i].height,
2901 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2902 GDI_STATE, GD_BUTTON_UNPRESSED,
2903 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2904 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2905 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2906 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2907 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2908 GDI_DECORATION_SHIFTING, 1, 1,
2909 GDI_EVENT_MASK, event_mask,
2910 GDI_CALLBACK_ACTION, HandleToolButtons,
2914 Error(ERR_EXIT, "cannot create gadget");
2916 tool_gadget[id] = gi;
2920 void FreeToolButtons()
2924 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2925 FreeGadget(tool_gadget[i]);
2928 static void UnmapToolButtons()
2932 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2933 UnmapGadget(tool_gadget[i]);
2936 static void HandleToolButtons(struct GadgetInfo *gi)
2938 request_gadget_id = gi->custom_id;
2941 static struct Mapping_EM_to_RND_object
2944 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2945 boolean is_backside; /* backside of moving element */
2951 em_object_mapping_list[] =
2954 Xblank, TRUE, FALSE,
2958 Yacid_splash_eB, FALSE, FALSE,
2959 EL_ACID_SPLASH_RIGHT, -1, -1
2962 Yacid_splash_wB, FALSE, FALSE,
2963 EL_ACID_SPLASH_LEFT, -1, -1
2966 #ifdef EM_ENGINE_BAD_ROLL
2968 Xstone_force_e, FALSE, FALSE,
2969 EL_ROCK, -1, MV_BIT_RIGHT
2972 Xstone_force_w, FALSE, FALSE,
2973 EL_ROCK, -1, MV_BIT_LEFT
2976 Xnut_force_e, FALSE, FALSE,
2977 EL_NUT, -1, MV_BIT_RIGHT
2980 Xnut_force_w, FALSE, FALSE,
2981 EL_NUT, -1, MV_BIT_LEFT
2984 Xspring_force_e, FALSE, FALSE,
2985 EL_SPRING, -1, MV_BIT_RIGHT
2988 Xspring_force_w, FALSE, FALSE,
2989 EL_SPRING, -1, MV_BIT_LEFT
2992 Xemerald_force_e, FALSE, FALSE,
2993 EL_EMERALD, -1, MV_BIT_RIGHT
2996 Xemerald_force_w, FALSE, FALSE,
2997 EL_EMERALD, -1, MV_BIT_LEFT
3000 Xdiamond_force_e, FALSE, FALSE,
3001 EL_DIAMOND, -1, MV_BIT_RIGHT
3004 Xdiamond_force_w, FALSE, FALSE,
3005 EL_DIAMOND, -1, MV_BIT_LEFT
3008 Xbomb_force_e, FALSE, FALSE,
3009 EL_BOMB, -1, MV_BIT_RIGHT
3012 Xbomb_force_w, FALSE, FALSE,
3013 EL_BOMB, -1, MV_BIT_LEFT
3015 #endif /* EM_ENGINE_BAD_ROLL */
3018 Xstone, TRUE, FALSE,
3022 Xstone_pause, FALSE, FALSE,
3026 Xstone_fall, FALSE, FALSE,
3030 Ystone_s, FALSE, FALSE,
3031 EL_ROCK, ACTION_FALLING, -1
3034 Ystone_sB, FALSE, TRUE,
3035 EL_ROCK, ACTION_FALLING, -1
3038 Ystone_e, FALSE, FALSE,
3039 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3042 Ystone_eB, FALSE, TRUE,
3043 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3046 Ystone_w, FALSE, FALSE,
3047 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3050 Ystone_wB, FALSE, TRUE,
3051 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3058 Xnut_pause, FALSE, FALSE,
3062 Xnut_fall, FALSE, FALSE,
3066 Ynut_s, FALSE, FALSE,
3067 EL_NUT, ACTION_FALLING, -1
3070 Ynut_sB, FALSE, TRUE,
3071 EL_NUT, ACTION_FALLING, -1
3074 Ynut_e, FALSE, FALSE,
3075 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3078 Ynut_eB, FALSE, TRUE,
3079 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3082 Ynut_w, FALSE, FALSE,
3083 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3086 Ynut_wB, FALSE, TRUE,
3087 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3090 Xbug_n, TRUE, FALSE,
3094 Xbug_e, TRUE, FALSE,
3095 EL_BUG_RIGHT, -1, -1
3098 Xbug_s, TRUE, FALSE,
3102 Xbug_w, TRUE, FALSE,
3106 Xbug_gon, FALSE, FALSE,
3110 Xbug_goe, FALSE, FALSE,
3111 EL_BUG_RIGHT, -1, -1
3114 Xbug_gos, FALSE, FALSE,
3118 Xbug_gow, FALSE, FALSE,
3122 Ybug_n, FALSE, FALSE,
3123 EL_BUG, ACTION_MOVING, MV_BIT_UP
3126 Ybug_nB, FALSE, TRUE,
3127 EL_BUG, ACTION_MOVING, MV_BIT_UP
3130 Ybug_e, FALSE, FALSE,
3131 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3134 Ybug_eB, FALSE, TRUE,
3135 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3138 Ybug_s, FALSE, FALSE,
3139 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3142 Ybug_sB, FALSE, TRUE,
3143 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3146 Ybug_w, FALSE, FALSE,
3147 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3150 Ybug_wB, FALSE, TRUE,
3151 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3154 Ybug_w_n, FALSE, FALSE,
3155 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3158 Ybug_n_e, FALSE, FALSE,
3159 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3162 Ybug_e_s, FALSE, FALSE,
3163 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3166 Ybug_s_w, FALSE, FALSE,
3167 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3170 Ybug_e_n, FALSE, FALSE,
3171 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3174 Ybug_s_e, FALSE, FALSE,
3175 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3178 Ybug_w_s, FALSE, FALSE,
3179 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3182 Ybug_n_w, FALSE, FALSE,
3183 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3186 Ybug_stone, FALSE, FALSE,
3187 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3190 Ybug_spring, FALSE, FALSE,
3191 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3194 Xtank_n, TRUE, FALSE,
3195 EL_SPACESHIP_UP, -1, -1
3198 Xtank_e, TRUE, FALSE,
3199 EL_SPACESHIP_RIGHT, -1, -1
3202 Xtank_s, TRUE, FALSE,
3203 EL_SPACESHIP_DOWN, -1, -1
3206 Xtank_w, TRUE, FALSE,
3207 EL_SPACESHIP_LEFT, -1, -1
3210 Xtank_gon, FALSE, FALSE,
3211 EL_SPACESHIP_UP, -1, -1
3214 Xtank_goe, FALSE, FALSE,
3215 EL_SPACESHIP_RIGHT, -1, -1
3218 Xtank_gos, FALSE, FALSE,
3219 EL_SPACESHIP_DOWN, -1, -1
3222 Xtank_gow, FALSE, FALSE,
3223 EL_SPACESHIP_LEFT, -1, -1
3226 Ytank_n, FALSE, FALSE,
3227 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3230 Ytank_nB, FALSE, TRUE,
3231 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3234 Ytank_e, FALSE, FALSE,
3235 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3238 Ytank_eB, FALSE, TRUE,
3239 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3242 Ytank_s, FALSE, FALSE,
3243 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3246 Ytank_sB, FALSE, TRUE,
3247 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3250 Ytank_w, FALSE, FALSE,
3251 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3254 Ytank_wB, FALSE, TRUE,
3255 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3258 Ytank_w_n, FALSE, FALSE,
3259 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3262 Ytank_n_e, FALSE, FALSE,
3263 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3266 Ytank_e_s, FALSE, FALSE,
3267 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3270 Ytank_s_w, FALSE, FALSE,
3271 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3274 Ytank_e_n, FALSE, FALSE,
3275 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3278 Ytank_s_e, FALSE, FALSE,
3279 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3282 Ytank_w_s, FALSE, FALSE,
3283 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3286 Ytank_n_w, FALSE, FALSE,
3287 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3290 Ytank_stone, FALSE, FALSE,
3291 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3294 Ytank_spring, FALSE, FALSE,
3295 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3298 Xandroid, TRUE, FALSE,
3299 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3302 Xandroid_1_n, FALSE, FALSE,
3303 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3306 Xandroid_2_n, FALSE, FALSE,
3307 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3310 Xandroid_1_e, FALSE, FALSE,
3311 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3314 Xandroid_2_e, FALSE, FALSE,
3315 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3318 Xandroid_1_w, FALSE, FALSE,
3319 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3322 Xandroid_2_w, FALSE, FALSE,
3323 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3326 Xandroid_1_s, FALSE, FALSE,
3327 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3330 Xandroid_2_s, FALSE, FALSE,
3331 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3334 Yandroid_n, FALSE, FALSE,
3335 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3338 Yandroid_nB, FALSE, TRUE,
3339 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3342 Yandroid_ne, FALSE, FALSE,
3343 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3346 Yandroid_neB, FALSE, TRUE,
3347 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3350 Yandroid_e, FALSE, FALSE,
3351 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3354 Yandroid_eB, FALSE, TRUE,
3355 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3358 Yandroid_se, FALSE, FALSE,
3359 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3362 Yandroid_seB, FALSE, TRUE,
3363 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3366 Yandroid_s, FALSE, FALSE,
3367 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3370 Yandroid_sB, FALSE, TRUE,
3371 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3374 Yandroid_sw, FALSE, FALSE,
3375 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3378 Yandroid_swB, FALSE, TRUE,
3379 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3382 Yandroid_w, FALSE, FALSE,
3383 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3386 Yandroid_wB, FALSE, TRUE,
3387 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3390 Yandroid_nw, FALSE, FALSE,
3391 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3394 Yandroid_nwB, FALSE, TRUE,
3395 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3398 Xspring, TRUE, FALSE,
3402 Xspring_pause, FALSE, FALSE,
3406 Xspring_e, FALSE, FALSE,
3410 Xspring_w, FALSE, FALSE,
3414 Xspring_fall, FALSE, FALSE,
3418 Yspring_s, FALSE, FALSE,
3419 EL_SPRING, ACTION_FALLING, -1
3422 Yspring_sB, FALSE, TRUE,
3423 EL_SPRING, ACTION_FALLING, -1
3426 Yspring_e, FALSE, FALSE,
3427 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3430 Yspring_eB, FALSE, TRUE,
3431 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3434 Yspring_w, FALSE, FALSE,
3435 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3438 Yspring_wB, FALSE, TRUE,
3439 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3442 Yspring_kill_e, FALSE, FALSE,
3443 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_RIGHT
3446 Yspring_kill_eB, FALSE, TRUE,
3447 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_RIGHT
3450 Yspring_kill_w, FALSE, FALSE,
3451 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_LEFT
3454 Yspring_kill_wB, FALSE, TRUE,
3455 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_LEFT
3458 Xeater_n, TRUE, FALSE,
3462 Xeater_e, FALSE, FALSE,
3466 Xeater_w, FALSE, FALSE,
3470 Xeater_s, FALSE, FALSE,
3474 Yeater_n, FALSE, FALSE,
3475 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3478 Yeater_nB, FALSE, TRUE,
3479 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3482 Yeater_e, FALSE, FALSE,
3483 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3486 Yeater_eB, FALSE, TRUE,
3487 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3490 Yeater_s, FALSE, FALSE,
3491 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3494 Yeater_sB, FALSE, TRUE,
3495 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3498 Yeater_w, FALSE, FALSE,
3499 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3502 Yeater_wB, FALSE, TRUE,
3503 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3506 Yeater_stone, FALSE, FALSE,
3507 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3510 Yeater_spring, FALSE, FALSE,
3511 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3514 Xalien, TRUE, FALSE,
3518 Xalien_pause, FALSE, FALSE,
3522 Yalien_n, FALSE, FALSE,
3523 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3526 Yalien_nB, FALSE, TRUE,
3527 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3530 Yalien_e, FALSE, FALSE,
3531 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3534 Yalien_eB, FALSE, TRUE,
3535 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3538 Yalien_s, FALSE, FALSE,
3539 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3542 Yalien_sB, FALSE, TRUE,
3543 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3546 Yalien_w, FALSE, FALSE,
3547 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3550 Yalien_wB, FALSE, TRUE,
3551 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3554 Yalien_stone, FALSE, FALSE,
3555 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3558 Yalien_spring, FALSE, FALSE,
3559 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3562 Xemerald, TRUE, FALSE,
3566 Xemerald_pause, FALSE, FALSE,
3570 Xemerald_fall, FALSE, FALSE,
3574 Xemerald_shine, FALSE, FALSE,
3575 EL_EMERALD, ACTION_TWINKLING, -1
3578 Yemerald_s, FALSE, FALSE,
3579 EL_EMERALD, ACTION_FALLING, -1
3582 Yemerald_sB, FALSE, TRUE,
3583 EL_EMERALD, ACTION_FALLING, -1
3586 Yemerald_e, FALSE, FALSE,
3587 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3590 Yemerald_eB, FALSE, TRUE,
3591 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3594 Yemerald_w, FALSE, FALSE,
3595 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3598 Yemerald_wB, FALSE, TRUE,
3599 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3602 Yemerald_eat, FALSE, FALSE,
3603 EL_EMERALD, ACTION_COLLECTING, -1
3606 Yemerald_stone, FALSE, FALSE,
3607 EL_NUT, ACTION_BREAKING, -1
3610 Xdiamond, TRUE, FALSE,
3614 Xdiamond_pause, FALSE, FALSE,
3618 Xdiamond_fall, FALSE, FALSE,
3622 Xdiamond_shine, FALSE, FALSE,
3623 EL_DIAMOND, ACTION_TWINKLING, -1
3626 Ydiamond_s, FALSE, FALSE,
3627 EL_DIAMOND, ACTION_FALLING, -1
3630 Ydiamond_sB, FALSE, TRUE,
3631 EL_DIAMOND, ACTION_FALLING, -1
3634 Ydiamond_e, FALSE, FALSE,
3635 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3638 Ydiamond_eB, FALSE, TRUE,
3639 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3642 Ydiamond_w, FALSE, FALSE,
3643 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3646 Ydiamond_wB, FALSE, TRUE,
3647 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3650 Ydiamond_eat, FALSE, FALSE,
3651 EL_DIAMOND, ACTION_COLLECTING, -1
3654 Ydiamond_stone, FALSE, FALSE,
3655 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3658 Xdrip_fall, TRUE, FALSE,
3659 EL_AMOEBA_DROP, -1, -1
3662 Xdrip_stretch, FALSE, FALSE,
3663 EL_AMOEBA_DROP, ACTION_FALLING, -1
3666 Xdrip_stretchB, FALSE, TRUE,
3667 EL_AMOEBA_DROP, ACTION_FALLING, -1
3670 Xdrip_eat, FALSE, FALSE,
3671 EL_AMOEBA_DROP, ACTION_GROWING, -1
3674 Ydrip_s1, FALSE, FALSE,
3675 EL_AMOEBA_DROP, ACTION_FALLING, -1
3678 Ydrip_s1B, FALSE, TRUE,
3679 EL_AMOEBA_DROP, ACTION_FALLING, -1
3682 Ydrip_s2, FALSE, FALSE,
3683 EL_AMOEBA_DROP, ACTION_FALLING, -1
3686 Ydrip_s2B, FALSE, TRUE,
3687 EL_AMOEBA_DROP, ACTION_FALLING, -1
3694 Xbomb_pause, FALSE, FALSE,
3698 Xbomb_fall, FALSE, FALSE,
3702 Ybomb_s, FALSE, FALSE,
3703 EL_BOMB, ACTION_FALLING, -1
3706 Ybomb_sB, FALSE, TRUE,
3707 EL_BOMB, ACTION_FALLING, -1
3710 Ybomb_e, FALSE, FALSE,
3711 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3714 Ybomb_eB, FALSE, TRUE,
3715 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3718 Ybomb_w, FALSE, FALSE,
3719 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3722 Ybomb_wB, FALSE, TRUE,
3723 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3726 Ybomb_eat, FALSE, FALSE,
3727 EL_BOMB, ACTION_ACTIVATING, -1
3730 Xballoon, TRUE, FALSE,
3734 Yballoon_n, FALSE, FALSE,
3735 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3738 Yballoon_nB, FALSE, TRUE,
3739 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3742 Yballoon_e, FALSE, FALSE,
3743 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3746 Yballoon_eB, FALSE, TRUE,
3747 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3750 Yballoon_s, FALSE, FALSE,
3751 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3754 Yballoon_sB, FALSE, TRUE,
3755 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3758 Yballoon_w, FALSE, FALSE,
3759 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3762 Yballoon_wB, FALSE, TRUE,
3763 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3766 Xgrass, TRUE, FALSE,
3767 EL_EMC_GRASS, -1, -1
3770 Ygrass_nB, FALSE, FALSE,
3771 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3774 Ygrass_eB, FALSE, FALSE,
3775 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3778 Ygrass_sB, FALSE, FALSE,
3779 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3782 Ygrass_wB, FALSE, FALSE,
3783 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3790 Ydirt_nB, FALSE, FALSE,
3791 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3794 Ydirt_eB, FALSE, FALSE,
3795 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3798 Ydirt_sB, FALSE, FALSE,
3799 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3802 Ydirt_wB, FALSE, FALSE,
3803 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3806 Xacid_ne, TRUE, FALSE,
3807 EL_ACID_POOL_TOPRIGHT, -1, -1
3810 Xacid_se, TRUE, FALSE,
3811 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3814 Xacid_s, TRUE, FALSE,
3815 EL_ACID_POOL_BOTTOM, -1, -1
3818 Xacid_sw, TRUE, FALSE,
3819 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3822 Xacid_nw, TRUE, FALSE,
3823 EL_ACID_POOL_TOPLEFT, -1, -1
3826 Xacid_1, TRUE, FALSE,
3830 Xacid_2, FALSE, FALSE,
3834 Xacid_3, FALSE, FALSE,
3838 Xacid_4, FALSE, FALSE,
3842 Xacid_5, FALSE, FALSE,
3846 Xacid_6, FALSE, FALSE,
3850 Xacid_7, FALSE, FALSE,
3854 Xacid_8, FALSE, FALSE,
3858 Xball_1, TRUE, FALSE,
3859 EL_EMC_MAGIC_BALL, -1, -1
3862 Xball_1B, FALSE, FALSE,
3863 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3866 Xball_2, FALSE, FALSE,
3867 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3870 Xball_2B, FALSE, FALSE,
3871 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3874 Yball_eat, FALSE, FALSE,
3875 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3878 Ykey_1_eat, FALSE, FALSE,
3879 EL_EM_KEY_1, ACTION_COLLECTING, -1
3882 Ykey_2_eat, FALSE, FALSE,
3883 EL_EM_KEY_2, ACTION_COLLECTING, -1
3886 Ykey_3_eat, FALSE, FALSE,
3887 EL_EM_KEY_3, ACTION_COLLECTING, -1
3890 Ykey_4_eat, FALSE, FALSE,
3891 EL_EM_KEY_4, ACTION_COLLECTING, -1
3894 Ykey_5_eat, FALSE, FALSE,
3895 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3898 Ykey_6_eat, FALSE, FALSE,
3899 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3902 Ykey_7_eat, FALSE, FALSE,
3903 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3906 Ykey_8_eat, FALSE, FALSE,
3907 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3910 Ylenses_eat, FALSE, FALSE,
3911 EL_EMC_LENSES, ACTION_COLLECTING, -1
3914 Ymagnify_eat, FALSE, FALSE,
3915 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3918 Ygrass_eat, FALSE, FALSE,
3919 EL_EMC_GRASS, ACTION_SNAPPING, -1
3922 Ydirt_eat, FALSE, FALSE,
3923 EL_SAND, ACTION_SNAPPING, -1
3926 Xgrow_ns, TRUE, FALSE,
3927 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3930 Ygrow_ns_eat, FALSE, FALSE,
3931 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3934 Xgrow_ew, TRUE, FALSE,
3935 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3938 Ygrow_ew_eat, FALSE, FALSE,
3939 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3942 Xwonderwall, TRUE, FALSE,
3943 EL_MAGIC_WALL, -1, -1
3946 XwonderwallB, FALSE, FALSE,
3947 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3950 Xamoeba_1, TRUE, FALSE,
3951 EL_AMOEBA_DRY, ACTION_OTHER, -1
3954 Xamoeba_2, FALSE, FALSE,
3955 EL_AMOEBA_DRY, ACTION_OTHER, -1
3958 Xamoeba_3, FALSE, FALSE,
3959 EL_AMOEBA_DRY, ACTION_OTHER, -1
3962 Xamoeba_4, FALSE, FALSE,
3963 EL_AMOEBA_DRY, ACTION_OTHER, -1
3966 Xamoeba_5, TRUE, FALSE,
3967 EL_AMOEBA_WET, ACTION_OTHER, -1
3970 Xamoeba_6, FALSE, FALSE,
3971 EL_AMOEBA_WET, ACTION_OTHER, -1
3974 Xamoeba_7, FALSE, FALSE,
3975 EL_AMOEBA_WET, ACTION_OTHER, -1
3978 Xamoeba_8, FALSE, FALSE,
3979 EL_AMOEBA_WET, ACTION_OTHER, -1
3982 Xdoor_1, TRUE, FALSE,
3983 EL_EM_GATE_1, -1, -1
3986 Xdoor_2, TRUE, FALSE,
3987 EL_EM_GATE_2, -1, -1
3990 Xdoor_3, TRUE, FALSE,
3991 EL_EM_GATE_3, -1, -1
3994 Xdoor_4, TRUE, FALSE,
3995 EL_EM_GATE_4, -1, -1
3998 Xdoor_5, TRUE, FALSE,
3999 EL_EMC_GATE_5, -1, -1
4002 Xdoor_6, TRUE, FALSE,
4003 EL_EMC_GATE_6, -1, -1
4006 Xdoor_7, TRUE, FALSE,
4007 EL_EMC_GATE_7, -1, -1
4010 Xdoor_8, TRUE, FALSE,
4011 EL_EMC_GATE_8, -1, -1
4014 Xkey_1, TRUE, FALSE,
4018 Xkey_2, TRUE, FALSE,
4022 Xkey_3, TRUE, FALSE,
4026 Xkey_4, TRUE, FALSE,
4030 Xkey_5, TRUE, FALSE,
4031 EL_EMC_KEY_5, -1, -1
4034 Xkey_6, TRUE, FALSE,
4035 EL_EMC_KEY_6, -1, -1
4038 Xkey_7, TRUE, FALSE,
4039 EL_EMC_KEY_7, -1, -1
4042 Xkey_8, TRUE, FALSE,
4043 EL_EMC_KEY_8, -1, -1
4046 Xwind_n, TRUE, FALSE,
4047 EL_BALLOON_SWITCH_UP, -1, -1
4050 Xwind_e, TRUE, FALSE,
4051 EL_BALLOON_SWITCH_RIGHT, -1, -1
4054 Xwind_s, TRUE, FALSE,
4055 EL_BALLOON_SWITCH_DOWN, -1, -1
4058 Xwind_w, TRUE, FALSE,
4059 EL_BALLOON_SWITCH_LEFT, -1, -1
4062 Xwind_nesw, TRUE, FALSE,
4063 EL_BALLOON_SWITCH_ANY, -1, -1
4066 Xwind_stop, TRUE, FALSE,
4067 EL_BALLOON_SWITCH_NONE, -1, -1
4071 EL_EXIT_CLOSED, -1, -1
4074 Xexit_1, TRUE, FALSE,
4075 EL_EXIT_OPEN, -1, -1
4078 Xexit_2, FALSE, FALSE,
4079 EL_EXIT_OPEN, -1, -1
4082 Xexit_3, FALSE, FALSE,
4083 EL_EXIT_OPEN, -1, -1
4086 Xdynamite, TRUE, FALSE,
4090 Ydynamite_eat, FALSE, FALSE,
4091 EL_DYNAMITE, ACTION_COLLECTING, -1
4094 Xdynamite_1, TRUE, FALSE,
4095 EL_DYNAMITE_ACTIVE, -1, -1
4098 Xdynamite_2, FALSE, FALSE,
4099 EL_DYNAMITE_ACTIVE, -1, -1
4102 Xdynamite_3, FALSE, FALSE,
4103 EL_DYNAMITE_ACTIVE, -1, -1
4106 Xdynamite_4, FALSE, FALSE,
4107 EL_DYNAMITE_ACTIVE, -1, -1
4110 Xbumper, TRUE, FALSE,
4111 EL_EMC_SPRING_BUMPER, -1, -1
4114 XbumperB, FALSE, FALSE,
4115 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4118 Xwheel, TRUE, FALSE,
4119 EL_ROBOT_WHEEL, -1, -1
4122 XwheelB, FALSE, FALSE,
4123 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4126 Xswitch, TRUE, FALSE,
4127 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4130 XswitchB, FALSE, FALSE,
4131 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4135 EL_QUICKSAND_EMPTY, -1, -1
4138 Xsand_stone, TRUE, FALSE,
4139 EL_QUICKSAND_FULL, -1, -1
4142 Xsand_stonein_1, FALSE, FALSE,
4143 EL_ROCK, ACTION_FILLING, -1
4146 Xsand_stonein_2, FALSE, FALSE,
4147 EL_ROCK, ACTION_FILLING, -1
4150 Xsand_stonein_3, FALSE, FALSE,
4151 EL_ROCK, ACTION_FILLING, -1
4154 Xsand_stonein_4, FALSE, FALSE,
4155 EL_ROCK, ACTION_FILLING, -1
4158 Xsand_stonesand_1, FALSE, FALSE,
4159 EL_QUICKSAND_FULL, -1, -1
4162 Xsand_stonesand_2, FALSE, FALSE,
4163 EL_QUICKSAND_FULL, -1, -1
4166 Xsand_stonesand_3, FALSE, FALSE,
4167 EL_QUICKSAND_FULL, -1, -1
4170 Xsand_stonesand_4, FALSE, FALSE,
4171 EL_QUICKSAND_FULL, -1, -1
4174 Xsand_stoneout_1, FALSE, FALSE,
4175 EL_ROCK, ACTION_EMPTYING, -1
4178 Xsand_stoneout_2, FALSE, FALSE,
4179 EL_ROCK, ACTION_EMPTYING, -1
4182 Xsand_sandstone_1, FALSE, FALSE,
4183 EL_QUICKSAND_FULL, -1, -1
4186 Xsand_sandstone_2, FALSE, FALSE,
4187 EL_QUICKSAND_FULL, -1, -1
4190 Xsand_sandstone_3, FALSE, FALSE,
4191 EL_QUICKSAND_FULL, -1, -1
4194 Xsand_sandstone_4, FALSE, FALSE,
4195 EL_QUICKSAND_FULL, -1, -1
4198 Xplant, TRUE, FALSE,
4199 EL_EMC_PLANT, -1, -1
4202 Yplant, FALSE, FALSE,
4203 EL_EMC_PLANT, -1, -1
4206 Xlenses, TRUE, FALSE,
4207 EL_EMC_LENSES, -1, -1
4210 Xmagnify, TRUE, FALSE,
4211 EL_EMC_MAGNIFIER, -1, -1
4214 Xdripper, TRUE, FALSE,
4215 EL_EMC_DRIPPER, -1, -1
4218 XdripperB, FALSE, FALSE,
4219 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4222 Xfake_blank, TRUE, FALSE,
4223 EL_INVISIBLE_WALL, -1, -1
4226 Xfake_blankB, FALSE, FALSE,
4227 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4230 Xfake_grass, TRUE, FALSE,
4231 EL_EMC_FAKE_GRASS, -1, -1
4234 Xfake_grassB, FALSE, FALSE,
4235 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4238 Xfake_door_1, TRUE, FALSE,
4239 EL_EM_GATE_1_GRAY, -1, -1
4242 Xfake_door_2, TRUE, FALSE,
4243 EL_EM_GATE_2_GRAY, -1, -1
4246 Xfake_door_3, TRUE, FALSE,
4247 EL_EM_GATE_3_GRAY, -1, -1
4250 Xfake_door_4, TRUE, FALSE,
4251 EL_EM_GATE_4_GRAY, -1, -1
4254 Xfake_door_5, TRUE, FALSE,
4255 EL_EMC_GATE_5_GRAY, -1, -1
4258 Xfake_door_6, TRUE, FALSE,
4259 EL_EMC_GATE_6_GRAY, -1, -1
4262 Xfake_door_7, TRUE, FALSE,
4263 EL_EMC_GATE_7_GRAY, -1, -1
4266 Xfake_door_8, TRUE, FALSE,
4267 EL_EMC_GATE_8_GRAY, -1, -1
4270 Xfake_acid_1, TRUE, FALSE,
4271 EL_EMC_FAKE_ACID, -1, -1
4274 Xfake_acid_2, FALSE, FALSE,
4275 EL_EMC_FAKE_ACID, -1, -1
4278 Xfake_acid_3, FALSE, FALSE,
4279 EL_EMC_FAKE_ACID, -1, -1
4282 Xfake_acid_4, FALSE, FALSE,
4283 EL_EMC_FAKE_ACID, -1, -1
4286 Xfake_acid_5, FALSE, FALSE,
4287 EL_EMC_FAKE_ACID, -1, -1
4290 Xfake_acid_6, FALSE, FALSE,
4291 EL_EMC_FAKE_ACID, -1, -1
4294 Xfake_acid_7, FALSE, FALSE,
4295 EL_EMC_FAKE_ACID, -1, -1
4298 Xfake_acid_8, FALSE, FALSE,
4299 EL_EMC_FAKE_ACID, -1, -1
4302 Xsteel_1, TRUE, FALSE,
4303 EL_STEELWALL, -1, -1
4306 Xsteel_2, TRUE, FALSE,
4307 EL_EMC_STEELWALL_2, -1, -1
4310 Xsteel_3, TRUE, FALSE,
4311 EL_EMC_STEELWALL_3, -1, -1
4314 Xsteel_4, TRUE, FALSE,
4315 EL_EMC_STEELWALL_4, -1, -1
4318 Xwall_1, TRUE, FALSE,
4322 Xwall_2, TRUE, FALSE,
4323 EL_EMC_WALL_14, -1, -1
4326 Xwall_3, TRUE, FALSE,
4327 EL_EMC_WALL_15, -1, -1
4330 Xwall_4, TRUE, FALSE,
4331 EL_EMC_WALL_16, -1, -1
4334 Xround_wall_1, TRUE, FALSE,
4335 EL_WALL_SLIPPERY, -1, -1
4338 Xround_wall_2, TRUE, FALSE,
4339 EL_EMC_WALL_SLIPPERY_2, -1, -1
4342 Xround_wall_3, TRUE, FALSE,
4343 EL_EMC_WALL_SLIPPERY_3, -1, -1
4346 Xround_wall_4, TRUE, FALSE,
4347 EL_EMC_WALL_SLIPPERY_4, -1, -1
4350 Xdecor_1, TRUE, FALSE,
4351 EL_EMC_WALL_8, -1, -1
4354 Xdecor_2, TRUE, FALSE,
4355 EL_EMC_WALL_6, -1, -1
4358 Xdecor_3, TRUE, FALSE,
4359 EL_EMC_WALL_4, -1, -1
4362 Xdecor_4, TRUE, FALSE,
4363 EL_EMC_WALL_7, -1, -1
4366 Xdecor_5, TRUE, FALSE,
4367 EL_EMC_WALL_5, -1, -1
4370 Xdecor_6, TRUE, FALSE,
4371 EL_EMC_WALL_9, -1, -1
4374 Xdecor_7, TRUE, FALSE,
4375 EL_EMC_WALL_10, -1, -1
4378 Xdecor_8, TRUE, FALSE,
4379 EL_EMC_WALL_1, -1, -1
4382 Xdecor_9, TRUE, FALSE,
4383 EL_EMC_WALL_2, -1, -1
4386 Xdecor_10, TRUE, FALSE,
4387 EL_EMC_WALL_3, -1, -1
4390 Xdecor_11, TRUE, FALSE,
4391 EL_EMC_WALL_11, -1, -1
4394 Xdecor_12, TRUE, FALSE,
4395 EL_EMC_WALL_12, -1, -1
4398 Xalpha_0, TRUE, FALSE,
4399 EL_CHAR('0'), -1, -1
4402 Xalpha_1, TRUE, FALSE,
4403 EL_CHAR('1'), -1, -1
4406 Xalpha_2, TRUE, FALSE,
4407 EL_CHAR('2'), -1, -1
4410 Xalpha_3, TRUE, FALSE,
4411 EL_CHAR('3'), -1, -1
4414 Xalpha_4, TRUE, FALSE,
4415 EL_CHAR('4'), -1, -1
4418 Xalpha_5, TRUE, FALSE,
4419 EL_CHAR('5'), -1, -1
4422 Xalpha_6, TRUE, FALSE,
4423 EL_CHAR('6'), -1, -1
4426 Xalpha_7, TRUE, FALSE,
4427 EL_CHAR('7'), -1, -1
4430 Xalpha_8, TRUE, FALSE,
4431 EL_CHAR('8'), -1, -1
4434 Xalpha_9, TRUE, FALSE,
4435 EL_CHAR('9'), -1, -1
4438 Xalpha_excla, TRUE, FALSE,
4439 EL_CHAR('!'), -1, -1
4442 Xalpha_quote, TRUE, FALSE,
4443 EL_CHAR('"'), -1, -1
4446 Xalpha_comma, TRUE, FALSE,
4447 EL_CHAR(','), -1, -1
4450 Xalpha_minus, TRUE, FALSE,
4451 EL_CHAR('-'), -1, -1
4454 Xalpha_perio, TRUE, FALSE,
4455 EL_CHAR('.'), -1, -1
4458 Xalpha_colon, TRUE, FALSE,
4459 EL_CHAR(':'), -1, -1
4462 Xalpha_quest, TRUE, FALSE,
4463 EL_CHAR('?'), -1, -1
4466 Xalpha_a, TRUE, FALSE,
4467 EL_CHAR('A'), -1, -1
4470 Xalpha_b, TRUE, FALSE,
4471 EL_CHAR('B'), -1, -1
4474 Xalpha_c, TRUE, FALSE,
4475 EL_CHAR('C'), -1, -1
4478 Xalpha_d, TRUE, FALSE,
4479 EL_CHAR('D'), -1, -1
4482 Xalpha_e, TRUE, FALSE,
4483 EL_CHAR('E'), -1, -1
4486 Xalpha_f, TRUE, FALSE,
4487 EL_CHAR('F'), -1, -1
4490 Xalpha_g, TRUE, FALSE,
4491 EL_CHAR('G'), -1, -1
4494 Xalpha_h, TRUE, FALSE,
4495 EL_CHAR('H'), -1, -1
4498 Xalpha_i, TRUE, FALSE,
4499 EL_CHAR('I'), -1, -1
4502 Xalpha_j, TRUE, FALSE,
4503 EL_CHAR('J'), -1, -1
4506 Xalpha_k, TRUE, FALSE,
4507 EL_CHAR('K'), -1, -1
4510 Xalpha_l, TRUE, FALSE,
4511 EL_CHAR('L'), -1, -1
4514 Xalpha_m, TRUE, FALSE,
4515 EL_CHAR('M'), -1, -1
4518 Xalpha_n, TRUE, FALSE,
4519 EL_CHAR('N'), -1, -1
4522 Xalpha_o, TRUE, FALSE,
4523 EL_CHAR('O'), -1, -1
4526 Xalpha_p, TRUE, FALSE,
4527 EL_CHAR('P'), -1, -1
4530 Xalpha_q, TRUE, FALSE,
4531 EL_CHAR('Q'), -1, -1
4534 Xalpha_r, TRUE, FALSE,
4535 EL_CHAR('R'), -1, -1
4538 Xalpha_s, TRUE, FALSE,
4539 EL_CHAR('S'), -1, -1
4542 Xalpha_t, TRUE, FALSE,
4543 EL_CHAR('T'), -1, -1
4546 Xalpha_u, TRUE, FALSE,
4547 EL_CHAR('U'), -1, -1
4550 Xalpha_v, TRUE, FALSE,
4551 EL_CHAR('V'), -1, -1
4554 Xalpha_w, TRUE, FALSE,
4555 EL_CHAR('W'), -1, -1
4558 Xalpha_x, TRUE, FALSE,
4559 EL_CHAR('X'), -1, -1
4562 Xalpha_y, TRUE, FALSE,
4563 EL_CHAR('Y'), -1, -1
4566 Xalpha_z, TRUE, FALSE,
4567 EL_CHAR('Z'), -1, -1
4570 Xalpha_arrow_e, TRUE, FALSE,
4571 EL_CHAR('>'), -1, -1
4574 Xalpha_arrow_w, TRUE, FALSE,
4575 EL_CHAR('<'), -1, -1
4578 Xalpha_copyr, TRUE, FALSE,
4579 EL_CHAR('©'), -1, -1
4582 Xalpha_copyr, TRUE, FALSE,
4583 EL_CHAR('©'), -1, -1
4587 Xboom_bug, FALSE, FALSE,
4588 EL_BUG, ACTION_EXPLODING, -1
4591 Xboom_bomb, FALSE, FALSE,
4592 EL_BOMB, ACTION_EXPLODING, -1
4595 Xboom_android, FALSE, FALSE,
4596 EL_EMC_ANDROID, ACTION_OTHER, -1
4599 Xboom_1, FALSE, FALSE,
4600 EL_DEFAULT, ACTION_EXPLODING, -1
4603 Xboom_2, FALSE, FALSE,
4604 EL_DEFAULT, ACTION_EXPLODING, -1
4607 Znormal, FALSE, FALSE,
4611 Zdynamite, FALSE, FALSE,
4615 Zplayer, FALSE, FALSE,
4619 ZBORDER, FALSE, FALSE,
4629 static struct Mapping_EM_to_RND_player
4638 em_player_mapping_list[] =
4642 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4646 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4650 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4654 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4658 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4662 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4666 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4670 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4674 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4678 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4682 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4686 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4690 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4694 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4698 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4702 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4706 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4710 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4714 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4718 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4722 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4726 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4730 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4734 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4738 EL_PLAYER_1, ACTION_DEFAULT, -1,
4742 EL_PLAYER_2, ACTION_DEFAULT, -1,
4746 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4750 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4754 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4758 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4762 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4766 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4770 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4774 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4778 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4782 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4786 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4790 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4794 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4798 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4802 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4806 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4810 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4814 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4818 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4822 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4826 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4830 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4834 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4838 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4842 EL_PLAYER_3, ACTION_DEFAULT, -1,
4846 EL_PLAYER_4, ACTION_DEFAULT, -1,
4855 int map_element_RND_to_EM(int element_rnd)
4857 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4858 static boolean mapping_initialized = FALSE;
4860 if (!mapping_initialized)
4864 /* return "Xalpha_quest" for all undefined elements in mapping array */
4865 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4866 mapping_RND_to_EM[i] = Xalpha_quest;
4868 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4869 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4870 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4871 em_object_mapping_list[i].element_em;
4873 mapping_initialized = TRUE;
4876 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4877 return mapping_RND_to_EM[element_rnd];
4879 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4884 int map_element_EM_to_RND(int element_em)
4886 static unsigned short mapping_EM_to_RND[TILE_MAX];
4887 static boolean mapping_initialized = FALSE;
4889 if (!mapping_initialized)
4893 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4894 for (i = 0; i < TILE_MAX; i++)
4895 mapping_EM_to_RND[i] = EL_UNKNOWN;
4897 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4898 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4899 em_object_mapping_list[i].element_rnd;
4901 mapping_initialized = TRUE;
4904 if (element_em >= 0 && element_em < TILE_MAX)
4905 return mapping_EM_to_RND[element_em];
4907 Error(ERR_WARN, "invalid EM level element %d", element_em);
4912 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4914 struct LevelInfo_EM *level_em = level->native_em_level;
4915 struct LEVEL *lev = level_em->lev;
4918 for (i = 0; i < TILE_MAX; i++)
4919 lev->android_array[i] = Xblank;
4921 for (i = 0; i < level->num_android_clone_elements; i++)
4923 int element_rnd = level->android_clone_element[i];
4924 int element_em = map_element_RND_to_EM(element_rnd);
4926 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4927 if (em_object_mapping_list[j].element_rnd == element_rnd)
4928 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4932 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4934 struct LevelInfo_EM *level_em = level->native_em_level;
4935 struct LEVEL *lev = level_em->lev;
4938 level->num_android_clone_elements = 0;
4940 for (i = 0; i < TILE_MAX; i++)
4942 int element_em = lev->android_array[i];
4944 boolean element_found = FALSE;
4946 if (element_em == Xblank)
4949 element_rnd = map_element_EM_to_RND(element_em);
4951 for (j = 0; j < level->num_android_clone_elements; j++)
4952 if (level->android_clone_element[j] == element_rnd)
4953 element_found = TRUE;
4957 level->android_clone_element[level->num_android_clone_elements++] =
4960 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
4965 if (level->num_android_clone_elements == 0)
4967 level->num_android_clone_elements = 1;
4968 level->android_clone_element[0] = EL_EMPTY;
4974 int map_element_RND_to_EM(int element_rnd)
4976 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4977 static boolean mapping_initialized = FALSE;
4984 mapping_RND_to_EM_list[] =
4986 { Xblank, EL_EMPTY },
4987 { Xstone, EL_ROCK },
4989 { Xbug_n, EL_BUG_UP },
4990 { Xbug_e, EL_BUG_RIGHT },
4991 { Xbug_s, EL_BUG_DOWN },
4992 { Xbug_w, EL_BUG_LEFT },
4993 { Xtank_n, EL_SPACESHIP_UP },
4994 { Xtank_e, EL_SPACESHIP_RIGHT },
4995 { Xtank_s, EL_SPACESHIP_DOWN },
4996 { Xtank_w, EL_SPACESHIP_LEFT },
4997 { Xandroid, EL_EMC_ANDROID },
4998 { Xandroid_1_n, EL_EMC_ANDROID_UP },
4999 { Xandroid_1_e, EL_EMC_ANDROID_RIGHT },
5000 { Xandroid_1_w, EL_EMC_ANDROID_LEFT },
5001 { Xandroid_1_s, EL_EMC_ANDROID_DOWN },
5002 { Xspring, EL_SPRING },
5003 { Xeater_n, EL_YAMYAM },
5004 { Xalien, EL_ROBOT },
5005 { Xemerald, EL_EMERALD },
5006 { Xdiamond, EL_DIAMOND },
5007 { Xdrip_fall, EL_AMOEBA_DROP },
5009 { Xballoon, EL_BALLOON },
5010 { Xgrass, EL_EMC_GRASS },
5012 { Xacid_ne, EL_ACID_POOL_TOPRIGHT },
5013 { Xacid_se, EL_ACID_POOL_BOTTOMRIGHT },
5014 { Xacid_s, EL_ACID_POOL_BOTTOM },
5015 { Xacid_sw, EL_ACID_POOL_BOTTOMLEFT },
5016 { Xacid_nw, EL_ACID_POOL_TOPLEFT },
5017 { Xacid_1, EL_ACID },
5018 { Xball_1, EL_EMC_MAGIC_BALL },
5019 { Xgrow_ns, EL_EMC_GROW },
5020 { Xwonderwall, EL_MAGIC_WALL },
5021 { Xamoeba_1, EL_AMOEBA_WET },
5022 { Xdoor_1, EL_EM_GATE_1 },
5023 { Xdoor_2, EL_EM_GATE_2 },
5024 { Xdoor_3, EL_EM_GATE_3 },
5025 { Xdoor_4, EL_EM_GATE_4 },
5026 { Xdoor_5, EL_EMC_GATE_5 },
5027 { Xdoor_6, EL_EMC_GATE_6 },
5028 { Xdoor_7, EL_EMC_GATE_7 },
5029 { Xdoor_8, EL_EMC_GATE_8 },
5030 { Xkey_1, EL_EM_KEY_1 },
5031 { Xkey_2, EL_EM_KEY_2 },
5032 { Xkey_3, EL_EM_KEY_3 },
5033 { Xkey_4, EL_EM_KEY_4 },
5034 { Xkey_5, EL_EMC_KEY_5 },
5035 { Xkey_6, EL_EMC_KEY_6 },
5036 { Xkey_7, EL_EMC_KEY_7 },
5037 { Xkey_8, EL_EMC_KEY_8 },
5038 { Xwind_n, EL_BALLOON_SWITCH_UP },
5039 { Xwind_e, EL_BALLOON_SWITCH_RIGHT },
5040 { Xwind_s, EL_BALLOON_SWITCH_DOWN },
5041 { Xwind_w, EL_BALLOON_SWITCH_LEFT },
5042 { Xwind_nesw, EL_BALLOON_SWITCH_ANY },
5043 { Xwind_stop, EL_BALLOON_SWITCH_NONE },
5044 { Xexit, EL_EXIT_CLOSED },
5045 { Xexit_1, EL_EXIT_OPEN },
5046 { Xdynamite, EL_DYNAMITE },
5047 { Xdynamite_1, EL_DYNAMITE_ACTIVE },
5048 { Xbumper, EL_EMC_BUMPER },
5049 { Xwheel, EL_ROBOT_WHEEL },
5050 { Xswitch, EL_UNKNOWN },
5051 { Xsand, EL_QUICKSAND_EMPTY },
5052 { Xsand_stone, EL_QUICKSAND_FULL },
5053 { Xplant, EL_EMC_PLANT },
5054 { Xlenses, EL_EMC_LENSES },
5055 { Xmagnify, EL_EMC_MAGNIFIER },
5056 { Xdripper, EL_UNKNOWN },
5057 { Xfake_blank, EL_INVISIBLE_WALL },
5058 { Xfake_grass, EL_INVISIBLE_SAND },
5059 { Xfake_door_1, EL_EM_GATE_1_GRAY },
5060 { Xfake_door_2, EL_EM_GATE_2_GRAY },
5061 { Xfake_door_3, EL_EM_GATE_3_GRAY },
5062 { Xfake_door_4, EL_EM_GATE_4_GRAY },
5063 { Xfake_door_5, EL_EMC_GATE_5_GRAY },
5064 { Xfake_door_6, EL_EMC_GATE_6_GRAY },
5065 { Xfake_door_7, EL_EMC_GATE_7_GRAY },
5066 { Xfake_door_8, EL_EMC_GATE_8_GRAY },
5067 { Xsteel_1, EL_STEELWALL },
5068 { Xsteel_2, EL_UNKNOWN },
5069 { Xsteel_3, EL_EMC_STEELWALL_1 },
5070 { Xsteel_4, EL_UNKNOWN },
5071 { Xwall_1, EL_WALL },
5072 { Xwall_2, EL_UNKNOWN },
5073 { Xwall_3, EL_UNKNOWN },
5074 { Xwall_4, EL_UNKNOWN },
5075 { Xround_wall_1, EL_WALL_SLIPPERY },
5076 { Xround_wall_2, EL_UNKNOWN },
5077 { Xround_wall_3, EL_UNKNOWN },
5078 { Xround_wall_4, EL_UNKNOWN },
5079 { Xdecor_1, EL_UNKNOWN },
5080 { Xdecor_2, EL_EMC_WALL_6 },
5081 { Xdecor_3, EL_EMC_WALL_4 },
5082 { Xdecor_4, EL_EMC_WALL_5 },
5083 { Xdecor_5, EL_EMC_WALL_7 },
5084 { Xdecor_6, EL_EMC_WALL_8 },
5085 { Xdecor_7, EL_UNKNOWN },
5086 { Xdecor_8, EL_EMC_WALL_1 },
5087 { Xdecor_9, EL_EMC_WALL_2 },
5088 { Xdecor_10, EL_EMC_WALL_3 },
5089 { Xdecor_11, EL_UNKNOWN },
5090 { Xdecor_12, EL_UNKNOWN },
5091 { Xalpha_0, EL_CHAR('0') },
5092 { Xalpha_1, EL_CHAR('1') },
5093 { Xalpha_2, EL_CHAR('2') },
5094 { Xalpha_3, EL_CHAR('3') },
5095 { Xalpha_4, EL_CHAR('4') },
5096 { Xalpha_5, EL_CHAR('5') },
5097 { Xalpha_6, EL_CHAR('6') },
5098 { Xalpha_7, EL_CHAR('7') },
5099 { Xalpha_8, EL_CHAR('8') },
5100 { Xalpha_9, EL_CHAR('9') },
5101 { Xalpha_excla, EL_CHAR('!') },
5102 { Xalpha_quote, EL_CHAR('"') },
5103 { Xalpha_comma, EL_CHAR(',') },
5104 { Xalpha_minus, EL_CHAR('-') },
5105 { Xalpha_perio, EL_CHAR('.') },
5106 { Xalpha_colon, EL_CHAR(':') },
5107 { Xalpha_quest, EL_CHAR('?') },
5108 { Xalpha_a, EL_CHAR('A') },
5109 { Xalpha_b, EL_CHAR('B') },
5110 { Xalpha_c, EL_CHAR('C') },
5111 { Xalpha_d, EL_CHAR('D') },
5112 { Xalpha_e, EL_CHAR('E') },
5113 { Xalpha_f, EL_CHAR('F') },
5114 { Xalpha_g, EL_CHAR('G') },
5115 { Xalpha_h, EL_CHAR('H') },
5116 { Xalpha_i, EL_CHAR('I') },
5117 { Xalpha_j, EL_CHAR('J') },
5118 { Xalpha_k, EL_CHAR('K') },
5119 { Xalpha_l, EL_CHAR('L') },
5120 { Xalpha_m, EL_CHAR('M') },
5121 { Xalpha_n, EL_CHAR('N') },
5122 { Xalpha_o, EL_CHAR('O') },
5123 { Xalpha_p, EL_CHAR('P') },
5124 { Xalpha_q, EL_CHAR('Q') },
5125 { Xalpha_r, EL_CHAR('R') },
5126 { Xalpha_s, EL_CHAR('S') },
5127 { Xalpha_t, EL_CHAR('T') },
5128 { Xalpha_u, EL_CHAR('U') },
5129 { Xalpha_v, EL_CHAR('V') },
5130 { Xalpha_w, EL_CHAR('W') },
5131 { Xalpha_x, EL_CHAR('X') },
5132 { Xalpha_y, EL_CHAR('Y') },
5133 { Xalpha_z, EL_CHAR('Z') },
5134 { Xalpha_arrow_e, EL_CHAR('>') },
5135 { Xalpha_arrow_w, EL_CHAR('<') },
5136 { Xalpha_copyr, EL_CHAR('©') },
5138 { Zplayer, EL_PLAYER_1 },
5139 { Zplayer, EL_PLAYER_2 },
5140 { Zplayer, EL_PLAYER_3 },
5141 { Zplayer, EL_PLAYER_4 },
5143 { ZBORDER, EL_EMC_LEVEL_BORDER },
5148 if (!mapping_initialized)
5152 /* return "Xalpha_quest" for all undefined elements in mapping array */
5153 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5154 mapping_RND_to_EM[i] = Xalpha_quest;
5156 for (i = 0; mapping_RND_to_EM_list[i].element_rnd != -1; i++)
5157 mapping_RND_to_EM[mapping_RND_to_EM_list[i].element_rnd] =
5158 mapping_RND_to_EM_list[i].element_em;
5160 mapping_initialized = TRUE;
5163 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5164 return mapping_RND_to_EM[element_rnd];
5166 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5171 int map_element_EM_to_RND(int element_em)
5173 static unsigned short mapping_EM_to_RND[TILE_MAX];
5174 static boolean mapping_initialized = FALSE;
5181 em_object_mapping_list[] =
5183 { Xblank, EL_EMPTY },
5184 { Yacid_splash_eB, EL_EMPTY },
5185 { Yacid_splash_wB, EL_EMPTY },
5187 #ifdef EM_ENGINE_BAD_ROLL
5188 { Xstone_force_e, EL_ROCK },
5189 { Xstone_force_w, EL_ROCK },
5190 { Xnut_force_e, EL_NUT },
5191 { Xnut_force_w, EL_NUT },
5192 { Xspring_force_e, EL_SPRING },
5193 { Xspring_force_w, EL_SPRING },
5194 { Xemerald_force_e, EL_EMERALD },
5195 { Xemerald_force_w, EL_EMERALD },
5196 { Xdiamond_force_e, EL_DIAMOND },
5197 { Xdiamond_force_w, EL_DIAMOND },
5198 { Xbomb_force_e, EL_BOMB },
5199 { Xbomb_force_w, EL_BOMB },
5202 { Xstone, EL_ROCK },
5203 { Xstone_pause, EL_ROCK },
5204 { Xstone_fall, EL_ROCK },
5205 { Ystone_s, EL_ROCK },
5206 { Ystone_sB, EL_ROCK },
5207 { Ystone_e, EL_ROCK },
5208 { Ystone_eB, EL_ROCK },
5209 { Ystone_w, EL_ROCK },
5210 { Ystone_wB, EL_ROCK },
5212 { Xnut_pause, EL_NUT },
5213 { Xnut_fall, EL_NUT },
5215 { Ynut_sB, EL_NUT },
5217 { Ynut_eB, EL_NUT },
5219 { Ynut_wB, EL_NUT },
5220 { Xbug_n, EL_BUG_UP },
5221 { Xbug_e, EL_BUG_RIGHT },
5222 { Xbug_s, EL_BUG_DOWN },
5223 { Xbug_w, EL_BUG_LEFT },
5224 { Xbug_gon, EL_BUG_UP },
5225 { Xbug_goe, EL_BUG_RIGHT },
5226 { Xbug_gos, EL_BUG_DOWN },
5227 { Xbug_gow, EL_BUG_LEFT },
5228 { Ybug_n, EL_BUG_UP },
5229 { Ybug_nB, EL_BUG_UP },
5230 { Ybug_e, EL_BUG_RIGHT },
5231 { Ybug_eB, EL_BUG_RIGHT },
5232 { Ybug_s, EL_BUG_DOWN },
5233 { Ybug_sB, EL_BUG_DOWN },
5234 { Ybug_w, EL_BUG_LEFT },
5235 { Ybug_wB, EL_BUG_LEFT },
5236 { Ybug_w_n, EL_BUG_UP },
5237 { Ybug_n_e, EL_BUG_RIGHT },
5238 { Ybug_e_s, EL_BUG_DOWN },
5239 { Ybug_s_w, EL_BUG_LEFT },
5240 { Ybug_e_n, EL_BUG_UP },
5241 { Ybug_s_e, EL_BUG_RIGHT },
5242 { Ybug_w_s, EL_BUG_DOWN },
5243 { Ybug_n_w, EL_BUG_LEFT },
5244 { Ybug_stone, EL_ROCK },
5245 { Ybug_spring, EL_SPRING },
5246 { Xtank_n, EL_SPACESHIP_UP },
5247 { Xtank_e, EL_SPACESHIP_RIGHT },
5248 { Xtank_s, EL_SPACESHIP_DOWN },
5249 { Xtank_w, EL_SPACESHIP_LEFT },
5250 { Xtank_gon, EL_SPACESHIP_UP },
5251 { Xtank_goe, EL_SPACESHIP_RIGHT },
5252 { Xtank_gos, EL_SPACESHIP_DOWN },
5253 { Xtank_gow, EL_SPACESHIP_LEFT },
5254 { Ytank_n, EL_SPACESHIP_UP },
5255 { Ytank_nB, EL_SPACESHIP_UP },
5256 { Ytank_e, EL_SPACESHIP_RIGHT },
5257 { Ytank_eB, EL_SPACESHIP_RIGHT },
5258 { Ytank_s, EL_SPACESHIP_DOWN },
5259 { Ytank_sB, EL_SPACESHIP_DOWN },
5260 { Ytank_w, EL_SPACESHIP_LEFT },
5261 { Ytank_wB, EL_SPACESHIP_LEFT },
5262 { Ytank_w_n, EL_SPACESHIP_UP },
5263 { Ytank_n_e, EL_SPACESHIP_RIGHT },
5264 { Ytank_e_s, EL_SPACESHIP_DOWN },
5265 { Ytank_s_w, EL_SPACESHIP_LEFT },
5266 { Ytank_e_n, EL_SPACESHIP_UP },
5267 { Ytank_s_e, EL_SPACESHIP_RIGHT },
5268 { Ytank_w_s, EL_SPACESHIP_DOWN },
5269 { Ytank_n_w, EL_SPACESHIP_LEFT },
5270 { Ytank_stone, EL_ROCK },
5271 { Ytank_spring, EL_SPRING },
5272 { Xandroid, EL_EMC_ANDROID },
5273 { Xandroid_1_n, EL_EMC_ANDROID_UP },
5274 { Xandroid_2_n, EL_EMC_ANDROID_UP },
5275 { Xandroid_1_e, EL_EMC_ANDROID_RIGHT },
5276 { Xandroid_2_e, EL_EMC_ANDROID_RIGHT },
5277 { Xandroid_1_w, EL_EMC_ANDROID_LEFT },
5278 { Xandroid_2_w, EL_EMC_ANDROID_LEFT },
5279 { Xandroid_1_s, EL_EMC_ANDROID_DOWN },
5280 { Xandroid_2_s, EL_EMC_ANDROID_DOWN },
5281 { Yandroid_n, EL_EMC_ANDROID_UP },
5282 { Yandroid_nB, EL_EMC_ANDROID_UP },
5283 { Yandroid_ne, EL_EMC_ANDROID_RIGHT_UP },
5284 { Yandroid_neB, EL_EMC_ANDROID_RIGHT_UP },
5285 { Yandroid_e, EL_EMC_ANDROID_RIGHT },
5286 { Yandroid_eB, EL_EMC_ANDROID_RIGHT },
5287 { Yandroid_se, EL_EMC_ANDROID_RIGHT_DOWN },
5288 { Yandroid_seB, EL_EMC_ANDROID_RIGHT_DOWN },
5289 { Yandroid_s, EL_EMC_ANDROID_DOWN },
5290 { Yandroid_sB, EL_EMC_ANDROID_DOWN },
5291 { Yandroid_sw, EL_EMC_ANDROID_LEFT_DOWN },
5292 { Yandroid_swB, EL_EMC_ANDROID_LEFT_DOWN },
5293 { Yandroid_w, EL_EMC_ANDROID_LEFT },
5294 { Yandroid_wB, EL_EMC_ANDROID_LEFT },
5295 { Yandroid_nw, EL_EMC_ANDROID_LEFT_UP },
5296 { Yandroid_nwB, EL_EMC_ANDROID_LEFT_UP },
5297 { Xspring, EL_SPRING },
5298 { Xspring_pause, EL_SPRING },
5299 { Xspring_e, EL_SPRING },
5300 { Xspring_w, EL_SPRING },
5301 { Xspring_fall, EL_SPRING },
5302 { Yspring_s, EL_SPRING },
5303 { Yspring_sB, EL_SPRING },
5304 { Yspring_e, EL_SPRING },
5305 { Yspring_eB, EL_SPRING },
5306 { Yspring_w, EL_SPRING },
5307 { Yspring_wB, EL_SPRING },
5308 { Yspring_kill_e, EL_SPRING },
5309 { Yspring_kill_eB, EL_SPRING },
5310 { Yspring_kill_w, EL_SPRING },
5311 { Yspring_kill_wB, EL_SPRING },
5312 { Xeater_n, EL_YAMYAM },
5313 { Xeater_e, EL_YAMYAM },
5314 { Xeater_w, EL_YAMYAM },
5315 { Xeater_s, EL_YAMYAM },
5316 { Yeater_n, EL_YAMYAM },
5317 { Yeater_nB, EL_YAMYAM },
5318 { Yeater_e, EL_YAMYAM },
5319 { Yeater_eB, EL_YAMYAM },
5320 { Yeater_s, EL_YAMYAM },
5321 { Yeater_sB, EL_YAMYAM },
5322 { Yeater_w, EL_YAMYAM },
5323 { Yeater_wB, EL_YAMYAM },
5324 { Yeater_stone, EL_ROCK },
5325 { Yeater_spring, EL_SPRING },
5326 { Xalien, EL_ROBOT },
5327 { Xalien_pause, EL_ROBOT },
5328 { Yalien_n, EL_ROBOT },
5329 { Yalien_nB, EL_ROBOT },
5330 { Yalien_e, EL_ROBOT },
5331 { Yalien_eB, EL_ROBOT },
5332 { Yalien_s, EL_ROBOT },
5333 { Yalien_sB, EL_ROBOT },
5334 { Yalien_w, EL_ROBOT },
5335 { Yalien_wB, EL_ROBOT },
5336 { Yalien_stone, EL_ROCK },
5337 { Yalien_spring, EL_SPRING },
5338 { Xemerald, EL_EMERALD },
5339 { Xemerald_pause, EL_EMERALD },
5340 { Xemerald_fall, EL_EMERALD },
5341 { Xemerald_shine, EL_EMERALD },
5342 { Yemerald_s, EL_EMERALD },
5343 { Yemerald_sB, EL_EMERALD },
5344 { Yemerald_e, EL_EMERALD },
5345 { Yemerald_eB, EL_EMERALD },
5346 { Yemerald_w, EL_EMERALD },
5347 { Yemerald_wB, EL_EMERALD },
5348 { Yemerald_eat, EL_EMERALD },
5349 { Yemerald_stone, EL_ROCK },
5350 { Xdiamond, EL_DIAMOND },
5351 { Xdiamond_pause, EL_DIAMOND },
5352 { Xdiamond_fall, EL_DIAMOND },
5353 { Xdiamond_shine, EL_DIAMOND },
5354 { Ydiamond_s, EL_DIAMOND },
5355 { Ydiamond_sB, EL_DIAMOND },
5356 { Ydiamond_e, EL_DIAMOND },
5357 { Ydiamond_eB, EL_DIAMOND },
5358 { Ydiamond_w, EL_DIAMOND },
5359 { Ydiamond_wB, EL_DIAMOND },
5360 { Ydiamond_eat, EL_DIAMOND },
5361 { Ydiamond_stone, EL_ROCK },
5362 { Xdrip_fall, EL_AMOEBA_DROP },
5363 { Xdrip_stretch, EL_AMOEBA_DROP },
5364 { Xdrip_stretchB, EL_AMOEBA_DROP },
5365 { Xdrip_eat, EL_AMOEBA_DROP },
5366 { Ydrip_s1, EL_AMOEBA_DROP },
5367 { Ydrip_s1B, EL_AMOEBA_DROP },
5368 { Ydrip_s2, EL_AMOEBA_DROP },
5369 { Ydrip_s2B, EL_AMOEBA_DROP },
5371 { Xbomb_pause, EL_BOMB },
5372 { Xbomb_fall, EL_BOMB },
5373 { Ybomb_s, EL_BOMB },
5374 { Ybomb_sB, EL_BOMB },
5375 { Ybomb_e, EL_BOMB },
5376 { Ybomb_eB, EL_BOMB },
5377 { Ybomb_w, EL_BOMB },
5378 { Ybomb_wB, EL_BOMB },
5379 { Ybomb_eat, EL_BOMB },
5380 { Xballoon, EL_BALLOON },
5381 { Yballoon_n, EL_BALLOON },
5382 { Yballoon_nB, EL_BALLOON },
5383 { Yballoon_e, EL_BALLOON },
5384 { Yballoon_eB, EL_BALLOON },
5385 { Yballoon_s, EL_BALLOON },
5386 { Yballoon_sB, EL_BALLOON },
5387 { Yballoon_w, EL_BALLOON },
5388 { Yballoon_wB, EL_BALLOON },
5389 { Xgrass, EL_SAND },
5390 { Ygrass_nB, EL_SAND },
5391 { Ygrass_eB, EL_SAND },
5392 { Ygrass_sB, EL_SAND },
5393 { Ygrass_wB, EL_SAND },
5395 { Ydirt_nB, EL_SAND },
5396 { Ydirt_eB, EL_SAND },
5397 { Ydirt_sB, EL_SAND },
5398 { Ydirt_wB, EL_SAND },
5399 { Xacid_ne, EL_ACID_POOL_TOPRIGHT },
5400 { Xacid_se, EL_ACID_POOL_BOTTOMRIGHT },
5401 { Xacid_s, EL_ACID_POOL_BOTTOM },
5402 { Xacid_sw, EL_ACID_POOL_BOTTOMLEFT },
5403 { Xacid_nw, EL_ACID_POOL_TOPLEFT },
5404 { Xacid_1, EL_ACID },
5405 { Xacid_2, EL_ACID },
5406 { Xacid_3, EL_ACID },
5407 { Xacid_4, EL_ACID },
5408 { Xacid_5, EL_ACID },
5409 { Xacid_6, EL_ACID },
5410 { Xacid_7, EL_ACID },
5411 { Xacid_8, EL_ACID },
5412 { Xball_1, EL_EMC_MAGIC_BALL },
5413 { Xball_1B, EL_EMC_MAGIC_BALL },
5414 { Xball_2, EL_EMC_MAGIC_BALL },
5415 { Xball_2B, EL_EMC_MAGIC_BALL },
5416 { Yball_eat, EL_EMC_MAGIC_BALL },
5417 { Xgrow_ns, EL_EMC_GROW },
5418 { Ygrow_ns_eat, EL_EMC_GROW },
5419 { Xgrow_ew, EL_EMC_GROW },
5420 { Ygrow_ew_eat, EL_EMC_GROW },
5421 { Xwonderwall, EL_MAGIC_WALL },
5422 { XwonderwallB, EL_MAGIC_WALL },
5423 { Xamoeba_1, EL_AMOEBA_WET },
5424 { Xamoeba_2, EL_AMOEBA_WET },
5425 { Xamoeba_3, EL_AMOEBA_WET },
5426 { Xamoeba_4, EL_AMOEBA_WET },
5427 { Xamoeba_5, EL_AMOEBA_WET },
5428 { Xamoeba_6, EL_AMOEBA_WET },
5429 { Xamoeba_7, EL_AMOEBA_WET },
5430 { Xamoeba_8, EL_AMOEBA_WET },
5431 { Xdoor_1, EL_EM_GATE_1 },
5432 { Xdoor_2, EL_EM_GATE_2 },
5433 { Xdoor_3, EL_EM_GATE_3 },
5434 { Xdoor_4, EL_EM_GATE_4 },
5435 { Xdoor_5, EL_EMC_GATE_5 },
5436 { Xdoor_6, EL_EMC_GATE_6 },
5437 { Xdoor_7, EL_EMC_GATE_7 },
5438 { Xdoor_8, EL_EMC_GATE_8 },
5439 { Xkey_1, EL_EM_KEY_1 },
5440 { Xkey_2, EL_EM_KEY_2 },
5441 { Xkey_3, EL_EM_KEY_3 },
5442 { Xkey_4, EL_EM_KEY_4 },
5443 { Xkey_5, EL_EMC_KEY_5 },
5444 { Xkey_6, EL_EMC_KEY_6 },
5445 { Xkey_7, EL_EMC_KEY_7 },
5446 { Xkey_8, EL_EMC_KEY_8 },
5447 { Xwind_n, EL_BALLOON_SWITCH_UP },
5448 { Xwind_e, EL_BALLOON_SWITCH_RIGHT },
5449 { Xwind_s, EL_BALLOON_SWITCH_DOWN },
5450 { Xwind_w, EL_BALLOON_SWITCH_LEFT },
5451 { Xwind_nesw, EL_BALLOON_SWITCH_ANY },
5452 { Xwind_stop, EL_BALLOON_SWITCH_NONE },
5453 { Xexit, EL_EXIT_CLOSED },
5454 { Xexit_1, EL_EXIT_OPEN },
5455 { Xexit_2, EL_EXIT_OPEN },
5456 { Xexit_3, EL_EXIT_OPEN },
5457 { Xdynamite, EL_DYNAMITE },
5458 { Ydynamite_eat, EL_DYNAMITE },
5459 { Xdynamite_1, EL_DYNAMITE_ACTIVE },
5460 { Xdynamite_2, EL_DYNAMITE_ACTIVE },
5461 { Xdynamite_3, EL_DYNAMITE_ACTIVE },
5462 { Xdynamite_4, EL_DYNAMITE_ACTIVE },
5463 { Xbumper, EL_EMC_BUMPER },
5464 { XbumperB, EL_EMC_BUMPER },
5465 { Xwheel, EL_ROBOT_WHEEL },
5466 { XwheelB, EL_ROBOT_WHEEL },
5467 { Xswitch, EL_UNKNOWN },
5468 { XswitchB, EL_UNKNOWN },
5469 { Xsand, EL_QUICKSAND_EMPTY },
5470 { Xsand_stone, EL_QUICKSAND_FULL },
5471 { Xsand_stonein_1, EL_QUICKSAND_FULL },
5472 { Xsand_stonein_2, EL_QUICKSAND_FULL },
5473 { Xsand_stonein_3, EL_QUICKSAND_FULL },
5474 { Xsand_stonein_4, EL_QUICKSAND_FULL },
5475 { Xsand_stonesand_1, EL_QUICKSAND_FULL },
5476 { Xsand_stonesand_2, EL_QUICKSAND_FULL },
5477 { Xsand_stonesand_3, EL_QUICKSAND_FULL },
5478 { Xsand_stonesand_4, EL_QUICKSAND_FULL },
5479 { Xsand_stoneout_1, EL_QUICKSAND_FULL },
5480 { Xsand_stoneout_2, EL_QUICKSAND_FULL },
5481 { Xsand_sandstone_1, EL_QUICKSAND_FULL },
5482 { Xsand_sandstone_2, EL_QUICKSAND_FULL },
5483 { Xsand_sandstone_3, EL_QUICKSAND_FULL },
5484 { Xsand_sandstone_4, EL_QUICKSAND_FULL },
5485 { Xplant, EL_EMC_PLANT },
5486 { Yplant, EL_EMC_PLANT },
5487 { Xlenses, EL_EMC_LENSES },
5488 { Xmagnify, EL_EMC_MAGNIFIER },
5489 { Xdripper, EL_UNKNOWN },
5490 { XdripperB, EL_UNKNOWN },
5491 { Xfake_blank, EL_INVISIBLE_WALL },
5492 { Xfake_blankB, EL_INVISIBLE_WALL },
5493 { Xfake_grass, EL_INVISIBLE_SAND },
5494 { Xfake_grassB, EL_INVISIBLE_SAND },
5495 { Xfake_door_1, EL_EM_GATE_1_GRAY },
5496 { Xfake_door_2, EL_EM_GATE_2_GRAY },
5497 { Xfake_door_3, EL_EM_GATE_3_GRAY },
5498 { Xfake_door_4, EL_EM_GATE_4_GRAY },
5499 { Xfake_door_5, EL_EMC_GATE_5_GRAY },
5500 { Xfake_door_6, EL_EMC_GATE_6_GRAY },
5501 { Xfake_door_7, EL_EMC_GATE_7_GRAY },
5502 { Xfake_door_8, EL_EMC_GATE_8_GRAY },
5503 { Xsteel_1, EL_STEELWALL },
5504 { Xsteel_2, EL_UNKNOWN },
5505 { Xsteel_3, EL_EMC_STEELWALL_1 },
5506 { Xsteel_4, EL_UNKNOWN },
5507 { Xwall_1, EL_WALL },
5508 { Xwall_2, EL_UNKNOWN },
5509 { Xwall_3, EL_UNKNOWN },
5510 { Xwall_4, EL_UNKNOWN },
5511 { Xround_wall_1, EL_WALL_SLIPPERY },
5512 { Xround_wall_2, EL_UNKNOWN },
5513 { Xround_wall_3, EL_UNKNOWN },
5514 { Xround_wall_4, EL_UNKNOWN },
5515 { Xdecor_1, EL_UNKNOWN },
5516 { Xdecor_2, EL_EMC_WALL_6 },
5517 { Xdecor_3, EL_EMC_WALL_4 },
5518 { Xdecor_4, EL_EMC_WALL_5 },
5519 { Xdecor_5, EL_EMC_WALL_7 },
5520 { Xdecor_6, EL_EMC_WALL_8 },
5521 { Xdecor_7, EL_UNKNOWN },
5522 { Xdecor_8, EL_EMC_WALL_1 },
5523 { Xdecor_9, EL_EMC_WALL_2 },
5524 { Xdecor_10, EL_EMC_WALL_3 },
5525 { Xdecor_11, EL_UNKNOWN },
5526 { Xdecor_12, EL_UNKNOWN },
5527 { Xalpha_0, EL_CHAR('0') },
5528 { Xalpha_1, EL_CHAR('1') },
5529 { Xalpha_2, EL_CHAR('2') },
5530 { Xalpha_3, EL_CHAR('3') },
5531 { Xalpha_4, EL_CHAR('4') },
5532 { Xalpha_5, EL_CHAR('5') },
5533 { Xalpha_6, EL_CHAR('6') },
5534 { Xalpha_7, EL_CHAR('7') },
5535 { Xalpha_8, EL_CHAR('8') },
5536 { Xalpha_9, EL_CHAR('9') },
5537 { Xalpha_excla, EL_CHAR('!') },
5538 { Xalpha_quote, EL_CHAR('"') },
5539 { Xalpha_comma, EL_CHAR(',') },
5540 { Xalpha_minus, EL_CHAR('-') },
5541 { Xalpha_perio, EL_CHAR('.') },
5542 { Xalpha_colon, EL_CHAR(':') },
5543 { Xalpha_quest, EL_CHAR('?') },
5544 { Xalpha_a, EL_CHAR('A') },
5545 { Xalpha_b, EL_CHAR('B') },
5546 { Xalpha_c, EL_CHAR('C') },
5547 { Xalpha_d, EL_CHAR('D') },
5548 { Xalpha_e, EL_CHAR('E') },
5549 { Xalpha_f, EL_CHAR('F') },
5550 { Xalpha_g, EL_CHAR('G') },
5551 { Xalpha_h, EL_CHAR('H') },
5552 { Xalpha_i, EL_CHAR('I') },
5553 { Xalpha_j, EL_CHAR('J') },
5554 { Xalpha_k, EL_CHAR('K') },
5555 { Xalpha_l, EL_CHAR('L') },
5556 { Xalpha_m, EL_CHAR('M') },
5557 { Xalpha_n, EL_CHAR('N') },
5558 { Xalpha_o, EL_CHAR('O') },
5559 { Xalpha_p, EL_CHAR('P') },
5560 { Xalpha_q, EL_CHAR('Q') },
5561 { Xalpha_r, EL_CHAR('R') },
5562 { Xalpha_s, EL_CHAR('S') },
5563 { Xalpha_t, EL_CHAR('T') },
5564 { Xalpha_u, EL_CHAR('U') },
5565 { Xalpha_v, EL_CHAR('V') },
5566 { Xalpha_w, EL_CHAR('W') },
5567 { Xalpha_x, EL_CHAR('X') },
5568 { Xalpha_y, EL_CHAR('Y') },
5569 { Xalpha_z, EL_CHAR('Z') },
5570 { Xalpha_arrow_e, EL_CHAR('>') },
5571 { Xalpha_arrow_w, EL_CHAR('<') },
5572 { Xalpha_copyr, EL_CHAR('©') },
5574 { Zplayer, EL_PLAYER_1 },
5576 { ZBORDER, EL_EMC_LEVEL_BORDER },
5581 if (!mapping_initialized)
5585 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5586 for (i = 0; i < TILE_MAX; i++)
5587 mapping_EM_to_RND[i] = EL_UNKNOWN;
5589 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5590 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5591 em_object_mapping_list[i].element_rnd;
5593 mapping_initialized = TRUE;
5596 if (element_em >= 0 && element_em < TILE_MAX)
5597 return mapping_EM_to_RND[element_em];
5599 Error(ERR_WARN, "invalid EM level element %d", element_em);
5606 int map_direction_RND_to_EM(int direction)
5608 return (direction == MV_UP ? 0 :
5609 direction == MV_RIGHT ? 1 :
5610 direction == MV_DOWN ? 2 :
5611 direction == MV_LEFT ? 3 :
5615 int map_direction_EM_to_RND(int direction)
5617 return (direction == 0 ? MV_UP :
5618 direction == 1 ? MV_RIGHT :
5619 direction == 2 ? MV_DOWN :
5620 direction == 3 ? MV_LEFT :
5624 int get_next_element(int element)
5628 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5629 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5630 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5631 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5632 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5633 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5634 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5636 default: return element;
5641 int el_act_dir2img(int element, int action, int direction)
5643 element = GFX_ELEMENT(element);
5645 if (direction == MV_NONE)
5646 return element_info[element].graphic[action];
5648 direction = MV_DIR_TO_BIT(direction);
5650 return element_info[element].direction_graphic[action][direction];
5653 int el_act_dir2img(int element, int action, int direction)
5655 element = GFX_ELEMENT(element);
5656 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5658 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5659 return element_info[element].direction_graphic[action][direction];
5664 static int el_act_dir2crm(int element, int action, int direction)
5666 element = GFX_ELEMENT(element);
5668 if (direction == MV_NONE)
5669 return element_info[element].crumbled[action];
5671 direction = MV_DIR_TO_BIT(direction);
5673 return element_info[element].direction_crumbled[action][direction];
5676 static int el_act_dir2crm(int element, int action, int direction)
5678 element = GFX_ELEMENT(element);
5679 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5681 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5682 return element_info[element].direction_crumbled[action][direction];
5686 int el_act2img(int element, int action)
5688 element = GFX_ELEMENT(element);
5690 return element_info[element].graphic[action];
5693 int el_act2crm(int element, int action)
5695 element = GFX_ELEMENT(element);
5697 return element_info[element].crumbled[action];
5700 int el_dir2img(int element, int direction)
5702 element = GFX_ELEMENT(element);
5704 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5707 int el2baseimg(int element)
5709 return element_info[element].graphic[ACTION_DEFAULT];
5712 int el2img(int element)
5714 element = GFX_ELEMENT(element);
5716 return element_info[element].graphic[ACTION_DEFAULT];
5719 int el2edimg(int element)
5721 element = GFX_ELEMENT(element);
5723 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5726 int el2preimg(int element)
5728 element = GFX_ELEMENT(element);
5730 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5733 int font2baseimg(int font_nr)
5735 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5738 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5740 int game_frame_delay_value;
5742 game_frame_delay_value =
5743 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5744 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5747 if (tape.playing && tape.warp_forward && !tape.pausing)
5748 game_frame_delay_value = 0;
5750 return game_frame_delay_value;
5753 unsigned int InitRND(long seed)
5755 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5756 return InitEngineRND_EM(seed);
5758 return InitEngineRND(seed);
5761 #define DEBUG_EM_GFX 0
5763 void InitGraphicInfo_EM(void)
5765 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5766 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5770 if (graphic_info_em_object[0][0].bitmap == NULL)
5772 /* EM graphics not yet initialized in em_open_all() */
5778 /* always start with reliable default values */
5779 for (i = 0; i < TILE_MAX; i++)
5781 object_mapping[i].element_rnd = EL_UNKNOWN;
5782 object_mapping[i].is_backside = FALSE;
5783 object_mapping[i].action = ACTION_DEFAULT;
5784 object_mapping[i].direction = MV_NONE;
5787 /* always start with reliable default values */
5788 for (p = 0; p < MAX_PLAYERS; p++)
5790 for (i = 0; i < SPR_MAX; i++)
5792 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5793 player_mapping[p][i].action = ACTION_DEFAULT;
5794 player_mapping[p][i].direction = MV_NONE;
5798 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5800 int e = em_object_mapping_list[i].element_em;
5802 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5803 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5805 if (em_object_mapping_list[i].action != -1)
5806 object_mapping[e].action = em_object_mapping_list[i].action;
5808 if (em_object_mapping_list[i].direction != -1)
5809 object_mapping[e].direction =
5810 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5813 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5815 int a = em_player_mapping_list[i].action_em;
5816 int p = em_player_mapping_list[i].player_nr;
5818 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5820 if (em_player_mapping_list[i].action != -1)
5821 player_mapping[p][a].action = em_player_mapping_list[i].action;
5823 if (em_player_mapping_list[i].direction != -1)
5824 player_mapping[p][a].direction =
5825 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5828 for (i = 0; i < TILE_MAX; i++)
5830 int element = object_mapping[i].element_rnd;
5831 int action = object_mapping[i].action;
5832 int direction = object_mapping[i].direction;
5833 boolean is_backside = object_mapping[i].is_backside;
5834 boolean action_removing = (action == ACTION_DIGGING ||
5835 action == ACTION_SNAPPING ||
5836 action == ACTION_COLLECTING);
5837 boolean action_exploding = ((action == ACTION_EXPLODING ||
5838 action == ACTION_SMASHED_BY_ROCK ||
5839 action == ACTION_SMASHED_BY_SPRING) &&
5840 element != EL_DIAMOND);
5841 boolean action_active = (action == ACTION_ACTIVE);
5842 boolean action_other = (action == ACTION_OTHER);
5844 for (j = 0; j < 8; j++)
5846 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5847 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5849 i == Xdrip_stretch ? element :
5850 i == Xdrip_stretchB ? element :
5851 i == Ydrip_s1 ? element :
5852 i == Ydrip_s1B ? element :
5853 i == Xball_1B ? element :
5854 i == Xball_2 ? element :
5855 i == Xball_2B ? element :
5856 i == Yball_eat ? element :
5857 i == Ykey_1_eat ? element :
5858 i == Ykey_2_eat ? element :
5859 i == Ykey_3_eat ? element :
5860 i == Ykey_4_eat ? element :
5861 i == Ykey_5_eat ? element :
5862 i == Ykey_6_eat ? element :
5863 i == Ykey_7_eat ? element :
5864 i == Ykey_8_eat ? element :
5865 i == Ylenses_eat ? element :
5866 i == Ymagnify_eat ? element :
5867 i == Ygrass_eat ? element :
5868 i == Ydirt_eat ? element :
5869 i == Yspring_kill_e ? EL_SPRING :
5870 i == Yspring_kill_w ? EL_SPRING :
5871 i == Yemerald_stone ? EL_EMERALD :
5872 i == Ydiamond_stone ? EL_ROCK :
5873 i == Xsand_stonein_4 ? EL_EMPTY :
5874 i == Xsand_stoneout_2 ? EL_ROCK :
5875 is_backside ? EL_EMPTY :
5876 action_removing ? EL_EMPTY :
5878 int effective_action = (j < 7 ? action :
5879 i == Xdrip_stretch ? action :
5880 i == Xdrip_stretchB ? action :
5881 i == Ydrip_s1 ? action :
5882 i == Ydrip_s1B ? action :
5883 i == Xball_1B ? action :
5884 i == Xball_2 ? action :
5885 i == Xball_2B ? action :
5886 i == Yball_eat ? action :
5887 i == Ykey_1_eat ? action :
5888 i == Ykey_2_eat ? action :
5889 i == Ykey_3_eat ? action :
5890 i == Ykey_4_eat ? action :
5891 i == Ykey_5_eat ? action :
5892 i == Ykey_6_eat ? action :
5893 i == Ykey_7_eat ? action :
5894 i == Ykey_8_eat ? action :
5895 i == Ylenses_eat ? action :
5896 i == Ymagnify_eat ? action :
5897 i == Ygrass_eat ? action :
5898 i == Ydirt_eat ? action :
5899 i == Xsand_stonein_1 ? action :
5900 i == Xsand_stonein_2 ? action :
5901 i == Xsand_stonein_3 ? action :
5902 i == Xsand_stonein_4 ? action :
5903 i == Xsand_stoneout_1 ? action :
5904 i == Xsand_stoneout_2 ? action :
5905 i == Xboom_android ? ACTION_EXPLODING :
5906 action_exploding ? ACTION_EXPLODING :
5907 action_active ? action :
5908 action_other ? action :
5910 int graphic = (el_act_dir2img(effective_element, effective_action,
5912 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5914 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5915 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5916 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5917 struct GraphicInfo *g = &graphic_info[graphic];
5918 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5921 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5922 boolean special_animation = (action != ACTION_DEFAULT &&
5923 g->anim_frames == 3 &&
5924 g->anim_delay == 2 &&
5925 g->anim_mode & ANIM_LINEAR);
5926 int sync_frame = (i == Xdrip_stretch ? 7 :
5927 i == Xdrip_stretchB ? 7 :
5928 i == Ydrip_s2 ? j + 8 :
5929 i == Ydrip_s2B ? j + 8 :
5938 i == Xfake_acid_1 ? 0 :
5939 i == Xfake_acid_2 ? 10 :
5940 i == Xfake_acid_3 ? 20 :
5941 i == Xfake_acid_4 ? 30 :
5942 i == Xfake_acid_5 ? 40 :
5943 i == Xfake_acid_6 ? 50 :
5944 i == Xfake_acid_7 ? 60 :
5945 i == Xfake_acid_8 ? 70 :
5947 i == Xball_2B ? j + 8 :
5948 i == Yball_eat ? j + 1 :
5949 i == Ykey_1_eat ? j + 1 :
5950 i == Ykey_2_eat ? j + 1 :
5951 i == Ykey_3_eat ? j + 1 :
5952 i == Ykey_4_eat ? j + 1 :
5953 i == Ykey_5_eat ? j + 1 :
5954 i == Ykey_6_eat ? j + 1 :
5955 i == Ykey_7_eat ? j + 1 :
5956 i == Ykey_8_eat ? j + 1 :
5957 i == Ylenses_eat ? j + 1 :
5958 i == Ymagnify_eat ? j + 1 :
5959 i == Ygrass_eat ? j + 1 :
5960 i == Ydirt_eat ? j + 1 :
5961 i == Xamoeba_1 ? 0 :
5962 i == Xamoeba_2 ? 1 :
5963 i == Xamoeba_3 ? 2 :
5964 i == Xamoeba_4 ? 3 :
5965 i == Xamoeba_5 ? 0 :
5966 i == Xamoeba_6 ? 1 :
5967 i == Xamoeba_7 ? 2 :
5968 i == Xamoeba_8 ? 3 :
5969 i == Xexit_2 ? j + 8 :
5970 i == Xexit_3 ? j + 16 :
5971 i == Xdynamite_1 ? 0 :
5972 i == Xdynamite_2 ? 20 :
5973 i == Xdynamite_3 ? 40 :
5974 i == Xdynamite_4 ? 60 :
5975 i == Xsand_stonein_1 ? j + 1 :
5976 i == Xsand_stonein_2 ? j + 9 :
5977 i == Xsand_stonein_3 ? j + 17 :
5978 i == Xsand_stonein_4 ? j + 25 :
5979 i == Xsand_stoneout_1 && j == 0 ? 0 :
5980 i == Xsand_stoneout_1 && j == 1 ? 0 :
5981 i == Xsand_stoneout_1 && j == 2 ? 1 :
5982 i == Xsand_stoneout_1 && j == 3 ? 2 :
5983 i == Xsand_stoneout_1 && j == 4 ? 2 :
5984 i == Xsand_stoneout_1 && j == 5 ? 3 :
5985 i == Xsand_stoneout_1 && j == 6 ? 4 :
5986 i == Xsand_stoneout_1 && j == 7 ? 4 :
5987 i == Xsand_stoneout_2 && j == 0 ? 5 :
5988 i == Xsand_stoneout_2 && j == 1 ? 6 :
5989 i == Xsand_stoneout_2 && j == 2 ? 7 :
5990 i == Xsand_stoneout_2 && j == 3 ? 8 :
5991 i == Xsand_stoneout_2 && j == 4 ? 9 :
5992 i == Xsand_stoneout_2 && j == 5 ? 11 :
5993 i == Xsand_stoneout_2 && j == 6 ? 13 :
5994 i == Xsand_stoneout_2 && j == 7 ? 15 :
5995 i == Xboom_bug && j == 1 ? 2 :
5996 i == Xboom_bug && j == 2 ? 2 :
5997 i == Xboom_bug && j == 3 ? 4 :
5998 i == Xboom_bug && j == 4 ? 4 :
5999 i == Xboom_bug && j == 5 ? 2 :
6000 i == Xboom_bug && j == 6 ? 2 :
6001 i == Xboom_bug && j == 7 ? 0 :
6002 i == Xboom_bomb && j == 1 ? 2 :
6003 i == Xboom_bomb && j == 2 ? 2 :
6004 i == Xboom_bomb && j == 3 ? 4 :
6005 i == Xboom_bomb && j == 4 ? 4 :
6006 i == Xboom_bomb && j == 5 ? 2 :
6007 i == Xboom_bomb && j == 6 ? 2 :
6008 i == Xboom_bomb && j == 7 ? 0 :
6009 i == Xboom_android && j == 7 ? 6 :
6010 i == Xboom_1 && j == 1 ? 2 :
6011 i == Xboom_1 && j == 2 ? 2 :
6012 i == Xboom_1 && j == 3 ? 4 :
6013 i == Xboom_1 && j == 4 ? 4 :
6014 i == Xboom_1 && j == 5 ? 6 :
6015 i == Xboom_1 && j == 6 ? 6 :
6016 i == Xboom_1 && j == 7 ? 8 :
6017 i == Xboom_2 && j == 0 ? 8 :
6018 i == Xboom_2 && j == 1 ? 8 :
6019 i == Xboom_2 && j == 2 ? 10 :
6020 i == Xboom_2 && j == 3 ? 10 :
6021 i == Xboom_2 && j == 4 ? 10 :
6022 i == Xboom_2 && j == 5 ? 12 :
6023 i == Xboom_2 && j == 6 ? 12 :
6024 i == Xboom_2 && j == 7 ? 12 :
6025 special_animation && j == 4 ? 3 :
6026 effective_action != action ? 0 :
6030 Bitmap *debug_bitmap = g_em->bitmap;
6031 int debug_src_x = g_em->src_x;
6032 int debug_src_y = g_em->src_y;
6035 int frame = getAnimationFrame(g->anim_frames,
6038 g->anim_start_frame,
6041 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6042 g->double_movement && is_backside);
6044 g_em->bitmap = src_bitmap;
6045 g_em->src_x = src_x;
6046 g_em->src_y = src_y;
6047 g_em->src_offset_x = 0;
6048 g_em->src_offset_y = 0;
6049 g_em->dst_offset_x = 0;
6050 g_em->dst_offset_y = 0;
6051 g_em->width = TILEX;
6052 g_em->height = TILEY;
6054 g_em->crumbled_bitmap = NULL;
6055 g_em->crumbled_src_x = 0;
6056 g_em->crumbled_src_y = 0;
6057 g_em->crumbled_border_size = 0;
6059 g_em->has_crumbled_graphics = FALSE;
6060 g_em->preserve_background = FALSE;
6063 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6064 printf("::: empty crumbled: %d [%s], %d, %d\n",
6065 effective_element, element_info[effective_element].token_name,
6066 effective_action, direction);
6069 /* if element can be crumbled, but certain action graphics are just empty
6070 space (like snapping sand with the original R'n'D graphics), do not
6071 treat these empty space graphics as crumbled graphics in EMC engine */
6072 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6074 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6076 g_em->has_crumbled_graphics = TRUE;
6077 g_em->crumbled_bitmap = src_bitmap;
6078 g_em->crumbled_src_x = src_x;
6079 g_em->crumbled_src_y = src_y;
6080 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6083 if (!g->double_movement && (effective_action == ACTION_FALLING ||
6084 effective_action == ACTION_MOVING ||
6085 effective_action == ACTION_PUSHING))
6088 (effective_action == ACTION_FALLING ? MV_DOWN : direction);
6089 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6090 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6091 int num_steps = (i == Ydrip_s1 ||
6094 i == Ydrip_s2B ? 16 : 8);
6095 int cx = ABS(dx) * (TILEX / num_steps);
6096 int cy = ABS(dy) * (TILEY / num_steps);
6097 int step_frame = (i == Ydrip_s2 ||
6098 i == Ydrip_s2B ? j + 8 : j) + 1;
6099 int step = (is_backside ? step_frame : num_steps - step_frame);
6101 if (is_backside) /* tile where movement starts */
6103 if (dx < 0 || dy < 0)
6105 g_em->src_offset_x = cx * step;
6106 g_em->src_offset_y = cy * step;
6110 g_em->dst_offset_x = cx * step;
6111 g_em->dst_offset_y = cy * step;
6114 else /* tile where movement ends */
6116 if (dx < 0 || dy < 0)
6118 g_em->dst_offset_x = cx * step;
6119 g_em->dst_offset_y = cy * step;
6123 g_em->src_offset_x = cx * step;
6124 g_em->src_offset_y = cy * step;
6128 g_em->width = TILEX - cx * step;
6129 g_em->height = TILEY - cy * step;
6133 /* create unique graphic identifier to decide if tile must be redrawn */
6134 /* bit 31 - 16 (16 bit): EM style graphic
6135 bit 15 - 12 ( 4 bit): EM style frame
6136 bit 11 - 6 ( 6 bit): graphic width
6137 bit 5 - 0 ( 6 bit): graphic height */
6138 g_em->unique_identifier =
6139 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6141 /* create unique graphic identifier to decide if tile must be redrawn */
6142 /* bit 31 - 16 (16 bit): EM style element
6143 bit 15 - 12 ( 4 bit): EM style frame
6144 bit 11 - 6 ( 6 bit): graphic width
6145 bit 5 - 0 ( 6 bit): graphic height */
6146 g_em->unique_identifier =
6147 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
6151 if (effective_element == EL_ROCK)
6152 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
6153 effective_action, j, graphic, frame, g_em->unique_identifier);
6159 /* skip check for EMC elements not contained in original EMC artwork */
6160 if (element == EL_EMC_FAKE_ACID)
6164 if (g_em->bitmap != debug_bitmap ||
6165 g_em->src_x != debug_src_x ||
6166 g_em->src_y != debug_src_y ||
6167 g_em->src_offset_x != 0 ||
6168 g_em->src_offset_y != 0 ||
6169 g_em->dst_offset_x != 0 ||
6170 g_em->dst_offset_y != 0 ||
6171 g_em->width != TILEX ||
6172 g_em->height != TILEY)
6174 static int last_i = -1;
6182 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6183 i, element, element_info[element].token_name,
6184 element_action_info[effective_action].suffix, direction);
6186 if (element != effective_element)
6187 printf(" [%d ('%s')]",
6189 element_info[effective_element].token_name);
6193 if (g_em->bitmap != debug_bitmap)
6194 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6195 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6197 if (g_em->src_x != debug_src_x ||
6198 g_em->src_y != debug_src_y)
6199 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6200 j, (is_backside ? 'B' : 'F'),
6201 g_em->src_x, g_em->src_y,
6202 g_em->src_x / 32, g_em->src_y / 32,
6203 debug_src_x, debug_src_y,
6204 debug_src_x / 32, debug_src_y / 32);
6206 if (g_em->src_offset_x != 0 ||
6207 g_em->src_offset_y != 0 ||
6208 g_em->dst_offset_x != 0 ||
6209 g_em->dst_offset_y != 0)
6210 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6212 g_em->src_offset_x, g_em->src_offset_y,
6213 g_em->dst_offset_x, g_em->dst_offset_y);
6215 if (g_em->width != TILEX ||
6216 g_em->height != TILEY)
6217 printf(" %d (%d): size %d,%d should be %d,%d\n",
6219 g_em->width, g_em->height, TILEX, TILEY);
6226 for (i = 0; i < TILE_MAX; i++)
6228 for (j = 0; j < 8; j++)
6230 int element = object_mapping[i].element_rnd;
6231 int action = object_mapping[i].action;
6233 if (action == ACTION_SMASHED_BY_ROCK &&
6234 element_info[element].graphic[action] ==
6235 element_info[element].graphic[ACTION_DEFAULT])
6237 /* no separate animation for "smashed by rock" -- use rock instead */
6238 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6239 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[Ystone_s][7 - j];
6241 g_em->bitmap = g_xx->bitmap;
6242 g_em->src_x = g_xx->src_x;
6243 g_em->src_y = g_xx->src_y;
6244 g_em->src_offset_x = g_xx->src_offset_x;
6245 g_em->src_offset_y = g_xx->src_offset_y;
6246 g_em->dst_offset_x = g_xx->dst_offset_x;
6247 g_em->dst_offset_y = g_xx->dst_offset_y;
6248 g_em->width = g_xx->width;
6249 g_em->height = g_xx->height;
6251 g_em->preserve_background = TRUE;
6256 for (p = 0; p < MAX_PLAYERS; p++)
6258 for (i = 0; i < SPR_MAX; i++)
6260 int element = player_mapping[p][i].element_rnd;
6261 int action = player_mapping[p][i].action;
6262 int direction = player_mapping[p][i].direction;
6264 for (j = 0; j < 8; j++)
6266 int effective_element = element;
6267 int effective_action = action;
6268 int graphic = (direction == MV_NONE ?
6269 el_act2img(effective_element, effective_action) :
6270 el_act_dir2img(effective_element, effective_action,
6272 struct GraphicInfo *g = &graphic_info[graphic];
6273 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6279 Bitmap *debug_bitmap = g_em->bitmap;
6280 int debug_src_x = g_em->src_x;
6281 int debug_src_y = g_em->src_y;
6284 int frame = getAnimationFrame(g->anim_frames,
6287 g->anim_start_frame,
6290 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6292 g_em->bitmap = src_bitmap;
6293 g_em->src_x = src_x;
6294 g_em->src_y = src_y;
6295 g_em->src_offset_x = 0;
6296 g_em->src_offset_y = 0;
6297 g_em->dst_offset_x = 0;
6298 g_em->dst_offset_y = 0;
6299 g_em->width = TILEX;
6300 g_em->height = TILEY;
6303 if (g_em->bitmap != debug_bitmap ||
6304 g_em->src_x != debug_src_x ||
6305 g_em->src_y != debug_src_y)
6307 static int last_i = -1;
6315 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6316 p, i, element, element_info[element].token_name,
6317 element_action_info[effective_action].suffix, direction);
6319 if (element != effective_element)
6320 printf(" [%d ('%s')]",
6322 element_info[effective_element].token_name);
6326 if (g_em->bitmap != debug_bitmap)
6327 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6328 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6330 if (g_em->src_x != debug_src_x ||
6331 g_em->src_y != debug_src_y)
6332 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6334 g_em->src_x, g_em->src_y,
6335 g_em->src_x / 32, g_em->src_y / 32,
6336 debug_src_x, debug_src_y,
6337 debug_src_x / 32, debug_src_y / 32);