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(" GfxElement: %d\n", GfxElement[x][y]);
89 printf(" GfxAction: %d\n", GfxAction[x][y]);
90 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
94 void SetDrawtoField(int mode)
96 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
107 drawto_field = fieldbuffer;
109 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
115 BX2 = SCR_FIELDX - 1;
116 BY2 = SCR_FIELDY - 1;
120 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
124 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
126 if (game_status == GAME_MODE_PLAYING &&
127 level.game_engine_type == GAME_ENGINE_TYPE_EM)
129 BlitScreenToBitmap_EM(backbuffer);
131 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
137 width = gfx.sxsize + 2 * TILEX;
138 height = gfx.sysize + 2 * TILEY;
141 if (force_redraw || setup.direct_draw)
144 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
145 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
147 if (setup.direct_draw)
148 SetDrawtoField(DRAW_BACKBUFFER);
150 for (xx = BX1; xx <= BX2; xx++)
151 for (yy = BY1; yy <= BY2; yy++)
152 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
153 DrawScreenField(xx, yy);
156 if (setup.direct_draw)
157 SetDrawtoField(DRAW_DIRECT);
160 if (setup.soft_scrolling)
162 int fx = FX, fy = FY;
164 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
165 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
167 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
171 BlitBitmap(drawto, window, x, y, width, height, x, y);
177 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
179 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
180 redraw_mask &= ~REDRAW_MAIN;
182 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
183 redraw_mask |= REDRAW_FIELD;
185 if (redraw_mask & REDRAW_FIELD)
186 redraw_mask &= ~REDRAW_TILES;
188 if (redraw_mask == REDRAW_NONE)
191 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
193 static boolean last_frame_skipped = FALSE;
194 boolean skip_even_when_not_scrolling = TRUE;
195 boolean just_scrolling = (ScreenMovDir != 0);
196 boolean verbose = FALSE;
198 if (global.fps_slowdown_factor > 1 &&
199 (FrameCounter % global.fps_slowdown_factor) &&
200 (just_scrolling || skip_even_when_not_scrolling))
202 redraw_mask &= ~REDRAW_MAIN;
204 last_frame_skipped = TRUE;
207 printf("FRAME SKIPPED\n");
211 if (last_frame_skipped)
212 redraw_mask |= REDRAW_FIELD;
214 last_frame_skipped = FALSE;
217 printf("frame not skipped\n");
221 /* synchronize X11 graphics at this point; if we would synchronize the
222 display immediately after the buffer switching (after the XFlush),
223 this could mean that we have to wait for the graphics to complete,
224 although we could go on doing calculations for the next frame */
228 if (redraw_mask & REDRAW_ALL)
230 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
234 if (redraw_mask & REDRAW_FIELD)
236 if (game_status != GAME_MODE_PLAYING ||
237 redraw_mask & REDRAW_FROM_BACKBUFFER)
239 BlitBitmap(backbuffer, window,
240 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
244 int fx = FX, fy = FY;
246 if (setup.soft_scrolling)
248 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
249 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
252 if (setup.soft_scrolling ||
253 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
254 ABS(ScreenMovPos) == ScrollStepSize ||
255 redraw_tiles > REDRAWTILES_THRESHOLD)
257 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
261 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
263 (setup.soft_scrolling ?
264 "setup.soft_scrolling" :
265 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
266 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
267 ABS(ScreenGfxPos) == ScrollStepSize ?
268 "ABS(ScreenGfxPos) == ScrollStepSize" :
269 "redraw_tiles > REDRAWTILES_THRESHOLD"));
275 redraw_mask &= ~REDRAW_MAIN;
278 if (redraw_mask & REDRAW_DOORS)
280 if (redraw_mask & REDRAW_DOOR_1)
281 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
283 if (redraw_mask & REDRAW_DOOR_2)
286 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
288 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
292 if (redraw_mask & REDRAW_VIDEO_1)
293 BlitBitmap(backbuffer, window,
294 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS,
295 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
296 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS);
297 if (redraw_mask & REDRAW_VIDEO_2)
298 BlitBitmap(backbuffer, window,
299 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS,
300 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
301 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS);
302 if (redraw_mask & REDRAW_VIDEO_3)
303 BlitBitmap(backbuffer, window,
304 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS,
305 VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
306 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS);
311 if (redraw_mask & REDRAW_DOOR_3)
312 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
314 redraw_mask &= ~REDRAW_DOORS;
317 if (redraw_mask & REDRAW_MICROLEVEL)
319 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
320 SX, SY + 10 * TILEY);
322 redraw_mask &= ~REDRAW_MICROLEVEL;
325 if (redraw_mask & REDRAW_TILES)
327 for (x = 0; x < SCR_FIELDX; x++)
328 for (y = 0 ; y < SCR_FIELDY; y++)
329 if (redraw[redraw_x1 + x][redraw_y1 + y])
330 BlitBitmap(buffer, window,
331 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
332 SX + x * TILEX, SY + y * TILEY);
335 if (redraw_mask & REDRAW_FPS) /* display frames per second */
340 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
341 if (!global.fps_slowdown)
344 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
345 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
350 for (x = 0; x < MAX_BUF_XSIZE; x++)
351 for (y = 0; y < MAX_BUF_YSIZE; y++)
354 redraw_mask = REDRAW_NONE;
360 long fading_delay = 300;
362 if (setup.fading && (redraw_mask & REDRAW_FIELD))
369 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
372 for (i = 0; i < 2 * FULL_SYSIZE; i++)
374 for (y = 0; y < FULL_SYSIZE; y++)
376 BlitBitmap(backbuffer, window,
377 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
385 for (i = 1; i < FULL_SYSIZE; i+=2)
386 BlitBitmap(backbuffer, window,
387 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
393 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
394 BlitBitmapMasked(backbuffer, window,
395 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
400 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
401 BlitBitmapMasked(backbuffer, window,
402 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
407 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
408 BlitBitmapMasked(backbuffer, window,
409 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
414 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
415 BlitBitmapMasked(backbuffer, window,
416 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
421 redraw_mask &= ~REDRAW_MAIN;
428 void SetMainBackgroundImage(int graphic)
430 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
431 graphic_info[graphic].bitmap ?
432 graphic_info[graphic].bitmap :
433 graphic_info[IMG_BACKGROUND].bitmap);
436 void SetDoorBackgroundImage(int graphic)
438 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
439 graphic_info[graphic].bitmap ?
440 graphic_info[graphic].bitmap :
441 graphic_info[IMG_BACKGROUND].bitmap);
444 void DrawBackground(int dst_x, int dst_y, int width, int height)
446 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
448 redraw_mask |= REDRAW_FIELD;
453 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
455 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
457 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
458 SetDrawtoField(DRAW_BUFFERED);
461 SetDrawtoField(DRAW_BACKBUFFER);
463 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
465 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
466 SetDrawtoField(DRAW_DIRECT);
470 void MarkTileDirty(int x, int y)
472 int xx = redraw_x1 + x;
473 int yy = redraw_y1 + y;
478 redraw[xx][yy] = TRUE;
479 redraw_mask |= REDRAW_TILES;
482 void SetBorderElement()
486 BorderElement = EL_EMPTY;
488 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
490 for (x = 0; x < lev_fieldx; x++)
492 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
493 BorderElement = EL_STEELWALL;
495 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
501 void SetRandomAnimationValue(int x, int y)
503 gfx.anim_random_frame = GfxRandom[x][y];
506 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
508 /* animation synchronized with global frame counter, not move position */
509 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
510 sync_frame = FrameCounter;
512 return getAnimationFrame(graphic_info[graphic].anim_frames,
513 graphic_info[graphic].anim_delay,
514 graphic_info[graphic].anim_mode,
515 graphic_info[graphic].anim_start_frame,
519 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
520 int *x, int *y, boolean get_backside)
522 struct GraphicInfo *g = &graphic_info[graphic];
523 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
524 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
528 if (g->offset_y == 0) /* frames are ordered horizontally */
530 int max_width = g->anim_frames_per_line * g->width;
532 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
534 *x = pos % max_width;
535 *y = src_y % g->height + pos / max_width * g->height;
537 *x = (src_x + frame * g->offset_x) % max_width;
538 *y = src_y + (src_x + frame * g->offset_x) / max_width * g->height;
541 else if (g->offset_x == 0) /* frames are ordered vertically */
543 int max_height = g->anim_frames_per_line * g->height;
545 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
547 *x = src_x % g->width + pos / max_height * g->width;
548 *y = pos % max_height;
550 *x = src_x + (src_y + frame * g->offset_y) / max_height * g->width;
551 *y = (src_y + frame * g->offset_y) % max_height;
554 else /* frames are ordered diagonally */
556 *x = src_x + frame * g->offset_x;
557 *y = src_y + frame * g->offset_y;
561 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
563 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
566 void DrawGraphic(int x, int y, int graphic, int frame)
569 if (!IN_SCR_FIELD(x, y))
571 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
572 printf("DrawGraphic(): This should never happen!\n");
577 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
581 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
587 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
588 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
591 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
594 if (!IN_SCR_FIELD(x, y))
596 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
597 printf("DrawGraphicThruMask(): This should never happen!\n");
602 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
607 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
613 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
615 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
616 dst_x - src_x, dst_y - src_y);
617 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
620 void DrawMiniGraphic(int x, int y, int graphic)
622 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
623 MarkTileDirty(x / 2, y / 2);
626 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
628 struct GraphicInfo *g = &graphic_info[graphic];
630 int mini_starty = g->bitmap->height * 2 / 3;
633 *x = mini_startx + g->src_x / 2;
634 *y = mini_starty + g->src_y / 2;
637 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
642 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
643 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
646 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
647 int graphic, int frame,
648 int cut_mode, int mask_mode)
653 int width = TILEX, height = TILEY;
656 if (dx || dy) /* shifted graphic */
658 if (x < BX1) /* object enters playfield from the left */
665 else if (x > BX2) /* object enters playfield from the right */
671 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
677 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
679 else if (dx) /* general horizontal movement */
680 MarkTileDirty(x + SIGN(dx), y);
682 if (y < BY1) /* object enters playfield from the top */
684 if (cut_mode==CUT_BELOW) /* object completely above top border */
692 else if (y > BY2) /* object enters playfield from the bottom */
698 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
704 else if (dy > 0 && cut_mode == CUT_ABOVE)
706 if (y == BY2) /* object completely above bottom border */
712 MarkTileDirty(x, y + 1);
713 } /* object leaves playfield to the bottom */
714 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
716 else if (dy) /* general vertical movement */
717 MarkTileDirty(x, y + SIGN(dy));
721 if (!IN_SCR_FIELD(x, y))
723 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
724 printf("DrawGraphicShifted(): This should never happen!\n");
729 if (width > 0 && height > 0)
731 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
736 dst_x = FX + x * TILEX + dx;
737 dst_y = FY + y * TILEY + dy;
739 if (mask_mode == USE_MASKING)
741 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
742 dst_x - src_x, dst_y - src_y);
743 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
747 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
754 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
755 int graphic, int frame,
756 int cut_mode, int mask_mode)
761 int width = TILEX, height = TILEY;
764 int x2 = x + SIGN(dx);
765 int y2 = y + SIGN(dy);
766 int anim_frames = graphic_info[graphic].anim_frames;
767 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
769 /* re-calculate animation frame for two-tile movement animation */
770 frame = getGraphicAnimationFrame(graphic, sync_frame);
772 if (IN_SCR_FIELD(x1, y1)) /* movement start graphic inside screen area */
774 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
776 dst_x = FX + x1 * TILEX;
777 dst_y = FY + y1 * TILEY;
779 if (mask_mode == USE_MASKING)
781 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
782 dst_x - src_x, dst_y - src_y);
783 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
787 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
790 MarkTileDirty(x1, y1);
793 if (IN_SCR_FIELD(x2, y2)) /* movement end graphic inside screen area */
795 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
797 dst_x = FX + x2 * TILEX;
798 dst_y = FY + y2 * TILEY;
800 if (mask_mode == USE_MASKING)
802 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
803 dst_x - src_x, dst_y - src_y);
804 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
808 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
811 MarkTileDirty(x2, y2);
815 printf("::: DONE DrawGraphicShiftedDouble");
821 static void DrawGraphicShifted(int x, int y, int dx, int dy,
822 int graphic, int frame,
823 int cut_mode, int mask_mode)
827 DrawGraphic(x, y, graphic, frame);
832 if (graphic_info[graphic].double_movement) /* EM style movement images */
833 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
835 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
838 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
839 int frame, int cut_mode)
841 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
844 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
845 int cut_mode, int mask_mode)
847 int lx = LEVELX(x), ly = LEVELY(y);
851 if (IN_LEV_FIELD(lx, ly))
853 SetRandomAnimationValue(lx, ly);
855 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
856 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
858 /* do not use double (EM style) movement graphic when not moving */
859 if (graphic_info[graphic].double_movement && !dx && !dy)
861 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
862 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
865 else /* border element */
867 graphic = el2img(element);
868 frame = getGraphicAnimationFrame(graphic, -1);
871 if (element == EL_EXPANDABLE_WALL)
873 boolean left_stopped = FALSE, right_stopped = FALSE;
875 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
877 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
878 right_stopped = TRUE;
880 if (left_stopped && right_stopped)
882 else if (left_stopped)
884 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
885 frame = graphic_info[graphic].anim_frames - 1;
887 else if (right_stopped)
889 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
890 frame = graphic_info[graphic].anim_frames - 1;
895 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
896 else if (mask_mode == USE_MASKING)
897 DrawGraphicThruMask(x, y, graphic, frame);
899 DrawGraphic(x, y, graphic, frame);
902 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
903 int cut_mode, int mask_mode)
905 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
906 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
907 cut_mode, mask_mode);
910 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
913 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
916 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
919 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
922 void DrawLevelElementThruMask(int x, int y, int element)
924 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
927 void DrawLevelFieldThruMask(int x, int y)
929 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
932 #define TILE_GFX_ELEMENT(x, y) \
933 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
934 GfxElement[x][y] : Feld[x][y])
936 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
940 int sx = SCREENX(x), sy = SCREENY(y);
942 int width, height, cx, cy, i;
944 int crumbled_border_size = graphic_info[graphic].border_size;
946 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
948 static int xy[4][2] =
957 if (x == 0 && y == 7)
958 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
959 crumbled_border_size);
962 if (!IN_LEV_FIELD(x, y))
965 element = TILE_GFX_ELEMENT(x, y);
967 /* crumble field itself */
968 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
970 if (!IN_SCR_FIELD(sx, sy))
973 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
975 for (i = 0; i < 4; i++)
977 int xx = x + xy[i][0];
978 int yy = y + xy[i][1];
981 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
984 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
987 /* check if neighbour field is of same type */
988 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
992 if (Feld[x][y] == EL_CUSTOM_START + 123)
993 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
994 i, Feld[x][y], element,
995 GFX_CRUMBLED(element), IS_MOVING(x, y));
998 if (i == 1 || i == 2)
1000 width = crumbled_border_size;
1002 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1008 height = crumbled_border_size;
1010 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1013 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1014 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1017 MarkTileDirty(sx, sy);
1019 else /* crumble neighbour fields */
1022 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1025 for (i = 0; i < 4; i++)
1027 int xx = x + xy[i][0];
1028 int yy = y + xy[i][1];
1029 int sxx = sx + xy[i][0];
1030 int syy = sy + xy[i][1];
1033 if (!IN_LEV_FIELD(xx, yy) ||
1034 !IN_SCR_FIELD(sxx, syy) ||
1038 element = TILE_GFX_ELEMENT(xx, yy);
1040 if (!GFX_CRUMBLED(element))
1043 if (!IN_LEV_FIELD(xx, yy) ||
1044 !IN_SCR_FIELD(sxx, syy) ||
1045 !GFX_CRUMBLED(Feld[xx][yy]) ||
1051 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1052 crumbled_border_size = graphic_info[graphic].border_size;
1054 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1057 if (i == 1 || i == 2)
1059 width = crumbled_border_size;
1061 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1067 height = crumbled_border_size;
1069 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1072 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1073 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1075 MarkTileDirty(sxx, syy);
1080 void DrawLevelFieldCrumbledSand(int x, int y)
1085 if (!IN_LEV_FIELD(x, y))
1088 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1090 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1092 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1096 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1100 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1101 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1103 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1104 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1106 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1107 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1108 int sx = SCREENX(x), sy = SCREENY(y);
1110 DrawGraphic(sx, sy, graphic1, frame1);
1111 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1114 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1116 int sx = SCREENX(x), sy = SCREENY(y);
1117 static int xy[4][2] =
1126 for (i = 0; i < 4; i++)
1128 int xx = x + xy[i][0];
1129 int yy = y + xy[i][1];
1130 int sxx = sx + xy[i][0];
1131 int syy = sy + xy[i][1];
1133 if (!IN_LEV_FIELD(xx, yy) ||
1134 !IN_SCR_FIELD(sxx, syy) ||
1135 !GFX_CRUMBLED(Feld[xx][yy]) ||
1139 DrawLevelField(xx, yy);
1143 static int getBorderElement(int x, int y)
1147 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1148 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1149 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1150 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1151 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1152 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1153 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1155 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1156 int steel_position = (x == -1 && y == -1 ? 0 :
1157 x == lev_fieldx && y == -1 ? 1 :
1158 x == -1 && y == lev_fieldy ? 2 :
1159 x == lev_fieldx && y == lev_fieldy ? 3 :
1160 x == -1 || x == lev_fieldx ? 4 :
1161 y == -1 || y == lev_fieldy ? 5 : 6);
1163 return border[steel_position][steel_type];
1166 void DrawScreenElement(int x, int y, int element)
1168 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1169 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1172 void DrawLevelElement(int x, int y, int element)
1174 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1175 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1178 void DrawScreenField(int x, int y)
1180 int lx = LEVELX(x), ly = LEVELY(y);
1181 int element, content;
1183 if (!IN_LEV_FIELD(lx, ly))
1185 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1188 element = getBorderElement(lx, ly);
1190 DrawScreenElement(x, y, element);
1194 element = Feld[lx][ly];
1195 content = Store[lx][ly];
1197 if (IS_MOVING(lx, ly))
1199 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1200 boolean cut_mode = NO_CUTTING;
1202 if (element == EL_QUICKSAND_EMPTYING ||
1203 element == EL_MAGIC_WALL_EMPTYING ||
1204 element == EL_BD_MAGIC_WALL_EMPTYING ||
1205 element == EL_AMOEBA_DROPPING)
1206 cut_mode = CUT_ABOVE;
1207 else if (element == EL_QUICKSAND_FILLING ||
1208 element == EL_MAGIC_WALL_FILLING ||
1209 element == EL_BD_MAGIC_WALL_FILLING)
1210 cut_mode = CUT_BELOW;
1212 if (cut_mode == CUT_ABOVE)
1213 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1215 DrawScreenElement(x, y, EL_EMPTY);
1218 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1219 else if (cut_mode == NO_CUTTING)
1220 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1222 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1224 if (content == EL_ACID)
1226 int dir = MovDir[lx][ly];
1227 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1228 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1230 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1233 else if (IS_BLOCKED(lx, ly))
1238 boolean cut_mode = NO_CUTTING;
1239 int element_old, content_old;
1241 Blocked2Moving(lx, ly, &oldx, &oldy);
1244 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1245 MovDir[oldx][oldy] == MV_RIGHT);
1247 element_old = Feld[oldx][oldy];
1248 content_old = Store[oldx][oldy];
1250 if (element_old == EL_QUICKSAND_EMPTYING ||
1251 element_old == EL_MAGIC_WALL_EMPTYING ||
1252 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1253 element_old == EL_AMOEBA_DROPPING)
1254 cut_mode = CUT_ABOVE;
1256 DrawScreenElement(x, y, EL_EMPTY);
1259 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1261 else if (cut_mode == NO_CUTTING)
1262 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1265 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1268 else if (IS_DRAWABLE(element))
1269 DrawScreenElement(x, y, element);
1271 DrawScreenElement(x, y, EL_EMPTY);
1274 void DrawLevelField(int x, int y)
1276 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1277 DrawScreenField(SCREENX(x), SCREENY(y));
1278 else if (IS_MOVING(x, y))
1282 Moving2Blocked(x, y, &newx, &newy);
1283 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1284 DrawScreenField(SCREENX(newx), SCREENY(newy));
1286 else if (IS_BLOCKED(x, y))
1290 Blocked2Moving(x, y, &oldx, &oldy);
1291 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1292 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1296 void DrawMiniElement(int x, int y, int element)
1300 graphic = el2edimg(element);
1301 DrawMiniGraphic(x, y, graphic);
1304 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1306 int x = sx + scroll_x, y = sy + scroll_y;
1308 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1309 DrawMiniElement(sx, sy, EL_EMPTY);
1310 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1311 DrawMiniElement(sx, sy, Feld[x][y]);
1313 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1316 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1317 int x, int y, int xsize, int ysize, int font_nr)
1319 int font_width = getFontWidth(font_nr);
1320 int font_height = getFontHeight(font_nr);
1321 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1324 int dst_x = SX + startx + x * font_width;
1325 int dst_y = SY + starty + y * font_height;
1326 int width = graphic_info[graphic].width;
1327 int height = graphic_info[graphic].height;
1328 int inner_width = MAX(width - 2 * font_width, font_width);
1329 int inner_height = MAX(height - 2 * font_height, font_height);
1330 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1331 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1332 boolean draw_masked = graphic_info[graphic].draw_masked;
1334 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1336 if (src_bitmap == NULL || width < font_width || height < font_height)
1338 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1342 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1343 inner_sx + (x - 1) * font_width % inner_width);
1344 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1345 inner_sy + (y - 1) * font_height % inner_height);
1349 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1350 dst_x - src_x, dst_y - src_y);
1351 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1355 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1359 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1361 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1363 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1364 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1366 boolean draw_masked = graphic_info[graphic].draw_masked;
1367 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1369 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1370 boolean no_delay = (tape.warp_forward);
1371 unsigned long anim_delay = 0;
1372 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1373 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1374 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1375 int font_width = getFontWidth(font_nr);
1376 int font_height = getFontHeight(font_nr);
1377 int max_xsize = level.envelope_xsize[envelope_nr];
1378 int max_ysize = level.envelope_ysize[envelope_nr];
1379 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1380 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1381 int xend = max_xsize;
1382 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1383 int xstep = (xstart < xend ? 1 : 0);
1384 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1387 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1389 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1390 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1391 int sx = (SXSIZE - xsize * font_width) / 2;
1392 int sy = (SYSIZE - ysize * font_height) / 2;
1395 SetDrawtoField(DRAW_BUFFERED);
1397 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1399 SetDrawtoField(DRAW_BACKBUFFER);
1401 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1402 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1404 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1405 level.envelope_text[envelope_nr], font_nr, max_xsize,
1406 xsize - 2, ysize - 2, mask_mode);
1408 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1411 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1415 void ShowEnvelope(int envelope_nr)
1417 int element = EL_ENVELOPE_1 + envelope_nr;
1418 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1419 int sound_opening = element_info[element].sound[ACTION_OPENING];
1420 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1421 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1422 boolean no_delay = (tape.warp_forward);
1423 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1424 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1425 int anim_mode = graphic_info[graphic].anim_mode;
1426 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1427 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1429 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1431 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1433 if (anim_mode == ANIM_DEFAULT)
1434 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1436 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1439 Delay(wait_delay_value);
1441 WaitForEventToContinue();
1443 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1445 if (anim_mode != ANIM_NONE)
1446 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1448 if (anim_mode == ANIM_DEFAULT)
1449 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1451 game.envelope_active = FALSE;
1453 SetDrawtoField(DRAW_BUFFERED);
1455 redraw_mask |= REDRAW_FIELD;
1459 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1461 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1462 int mini_startx = src_bitmap->width * 3 / 4;
1463 int mini_starty = src_bitmap->height * 2 / 3;
1464 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1465 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1467 *bitmap = src_bitmap;
1472 void DrawMicroElement(int xpos, int ypos, int element)
1476 int graphic = el2preimg(element);
1478 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1479 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1487 SetDrawBackgroundMask(REDRAW_NONE);
1490 for (x = BX1; x <= BX2; x++)
1491 for (y = BY1; y <= BY2; y++)
1492 DrawScreenField(x, y);
1494 redraw_mask |= REDRAW_FIELD;
1497 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1501 for (x = 0; x < size_x; x++)
1502 for (y = 0; y < size_y; y++)
1503 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1505 redraw_mask |= REDRAW_FIELD;
1508 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1512 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1514 if (lev_fieldx < STD_LEV_FIELDX)
1515 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1516 if (lev_fieldy < STD_LEV_FIELDY)
1517 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1519 xpos += MICRO_TILEX;
1520 ypos += MICRO_TILEY;
1522 for (x = -1; x <= STD_LEV_FIELDX; x++)
1524 for (y = -1; y <= STD_LEV_FIELDY; y++)
1526 int lx = from_x + x, ly = from_y + y;
1528 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1529 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1530 level.field[lx][ly]);
1531 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1532 && BorderElement != EL_EMPTY)
1533 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1534 getBorderElement(lx, ly));
1538 redraw_mask |= REDRAW_MICROLEVEL;
1541 #define MICROLABEL_EMPTY 0
1542 #define MICROLABEL_LEVEL_NAME 1
1543 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1544 #define MICROLABEL_LEVEL_AUTHOR 3
1545 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1546 #define MICROLABEL_IMPORTED_FROM 5
1547 #define MICROLABEL_IMPORTED_BY_HEAD 6
1548 #define MICROLABEL_IMPORTED_BY 7
1550 static void DrawMicroLevelLabelExt(int mode)
1552 char label_text[MAX_OUTPUT_LINESIZE + 1];
1553 int max_len_label_text;
1554 int font_nr = FONT_TEXT_2;
1556 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1557 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1558 mode == MICROLABEL_IMPORTED_BY_HEAD)
1559 font_nr = FONT_TEXT_3;
1561 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1563 DrawBackground(SX, MICROLABEL2_YPOS, SXSIZE, getFontHeight(font_nr));
1566 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1567 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1568 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1569 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1570 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1571 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1572 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1573 max_len_label_text);
1574 label_text[max_len_label_text] = '\0';
1576 if (strlen(label_text) > 0)
1578 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1579 int lypos = MICROLABEL2_YPOS;
1581 DrawText(lxpos, lypos, label_text, font_nr);
1584 redraw_mask |= REDRAW_MICROLEVEL;
1587 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1589 static unsigned long scroll_delay = 0;
1590 static unsigned long label_delay = 0;
1591 static int from_x, from_y, scroll_direction;
1592 static int label_state, label_counter;
1593 int last_game_status = game_status; /* save current game status */
1595 /* force PREVIEW font on preview level */
1596 game_status = GAME_MODE_PSEUDO_PREVIEW;
1600 from_x = from_y = 0;
1601 scroll_direction = MV_RIGHT;
1605 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1606 DrawMicroLevelLabelExt(label_state);
1608 /* initialize delay counters */
1609 DelayReached(&scroll_delay, 0);
1610 DelayReached(&label_delay, 0);
1612 if (leveldir_current->name)
1614 char label_text[MAX_OUTPUT_LINESIZE + 1];
1615 int font_nr = FONT_TEXT_1;
1616 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1619 strncpy(label_text, leveldir_current->name, max_len_label_text);
1620 label_text[max_len_label_text] = '\0';
1622 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1623 lypos = SY + MICROLABEL1_YPOS;
1625 DrawText(lxpos, lypos, label_text, font_nr);
1628 game_status = last_game_status; /* restore current game status */
1633 /* scroll micro level, if needed */
1634 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1635 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1637 switch (scroll_direction)
1643 scroll_direction = MV_UP;
1647 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1650 scroll_direction = MV_DOWN;
1657 scroll_direction = MV_RIGHT;
1661 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1664 scroll_direction = MV_LEFT;
1671 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1674 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1675 /* redraw micro level label, if needed */
1676 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1677 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1678 strcmp(level.author, leveldir_current->name) != 0 &&
1679 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1681 int max_label_counter = 23;
1683 if (leveldir_current->imported_from != NULL)
1684 max_label_counter += 14;
1685 if (leveldir_current->imported_by != NULL)
1686 max_label_counter += 14;
1688 label_counter = (label_counter + 1) % max_label_counter;
1689 label_state = (label_counter >= 0 && label_counter <= 7 ?
1690 MICROLABEL_LEVEL_NAME :
1691 label_counter >= 9 && label_counter <= 12 ?
1692 MICROLABEL_LEVEL_AUTHOR_HEAD :
1693 label_counter >= 14 && label_counter <= 21 ?
1694 MICROLABEL_LEVEL_AUTHOR :
1695 label_counter >= 23 && label_counter <= 26 ?
1696 MICROLABEL_IMPORTED_FROM_HEAD :
1697 label_counter >= 28 && label_counter <= 35 ?
1698 MICROLABEL_IMPORTED_FROM :
1699 label_counter >= 37 && label_counter <= 40 ?
1700 MICROLABEL_IMPORTED_BY_HEAD :
1701 label_counter >= 42 && label_counter <= 49 ?
1702 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1704 if (leveldir_current->imported_from == NULL &&
1705 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1706 label_state == MICROLABEL_IMPORTED_FROM))
1707 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1708 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1710 DrawMicroLevelLabelExt(label_state);
1713 game_status = last_game_status; /* restore current game status */
1716 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1717 int graphic, int sync_frame, int mask_mode)
1719 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1721 if (mask_mode == USE_MASKING)
1722 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1724 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1727 inline void DrawGraphicAnimation(int x, int y, int graphic)
1729 int lx = LEVELX(x), ly = LEVELY(y);
1731 if (!IN_SCR_FIELD(x, y))
1734 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1735 graphic, GfxFrame[lx][ly], NO_MASKING);
1736 MarkTileDirty(x, y);
1739 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1741 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1744 void DrawLevelElementAnimation(int x, int y, int element)
1747 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1749 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1751 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
1755 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1757 int sx = SCREENX(x), sy = SCREENY(y);
1759 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1762 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1765 DrawGraphicAnimation(sx, sy, graphic);
1767 if (GFX_CRUMBLED(Feld[x][y]))
1768 DrawLevelFieldCrumbledSand(x, y);
1771 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1773 int sx = SCREENX(x), sy = SCREENY(y);
1776 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1779 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1781 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1784 DrawGraphicAnimation(sx, sy, graphic);
1786 if (GFX_CRUMBLED(element))
1787 DrawLevelFieldCrumbledSand(x, y);
1790 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1792 if (player->use_murphy_graphic)
1794 /* this works only because currently only one player can be "murphy" ... */
1795 static int last_horizontal_dir = MV_LEFT;
1796 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1798 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1799 last_horizontal_dir = move_dir;
1801 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1803 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1805 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1811 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
1814 static boolean equalGraphics(int graphic1, int graphic2)
1816 struct GraphicInfo *g1 = &graphic_info[graphic1];
1817 struct GraphicInfo *g2 = &graphic_info[graphic2];
1819 return (g1->bitmap == g2->bitmap &&
1820 g1->src_x == g2->src_x &&
1821 g1->src_y == g2->src_y &&
1822 g1->anim_frames == g2->anim_frames &&
1823 g1->anim_delay == g2->anim_delay &&
1824 g1->anim_mode == g2->anim_mode);
1827 void DrawAllPlayers()
1831 for (i = 0; i < MAX_PLAYERS; i++)
1832 if (stored_player[i].active)
1833 DrawPlayer(&stored_player[i]);
1836 void DrawPlayerField(int x, int y)
1838 if (!IS_PLAYER(x, y))
1841 DrawPlayer(PLAYERINFO(x, y));
1844 void DrawPlayer(struct PlayerInfo *player)
1846 int jx = player->jx;
1847 int jy = player->jy;
1848 int move_dir = player->MovDir;
1850 int last_jx = player->last_jx;
1851 int last_jy = player->last_jy;
1852 int next_jx = jx + (jx - last_jx);
1853 int next_jy = jy + (jy - last_jy);
1854 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
1856 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1857 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1858 int last_jx = (player->is_moving ? jx - dx : jx);
1859 int last_jy = (player->is_moving ? jy - dy : jy);
1860 int next_jx = jx + dx;
1861 int next_jy = jy + dy;
1862 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1864 int sx = SCREENX(jx), sy = SCREENY(jy);
1865 int sxx = 0, syy = 0;
1866 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1868 int action = ACTION_DEFAULT;
1869 int last_player_graphic = getPlayerGraphic(player, move_dir);
1870 int last_player_frame = player->Frame;
1873 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1877 if (!IN_LEV_FIELD(jx, jy))
1879 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1880 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1881 printf("DrawPlayerField(): This should never happen!\n");
1886 if (element == EL_EXPLOSION)
1889 action = (player->is_pushing ? ACTION_PUSHING :
1890 player->is_digging ? ACTION_DIGGING :
1891 player->is_collecting ? ACTION_COLLECTING :
1892 player->is_moving ? ACTION_MOVING :
1893 player->is_snapping ? ACTION_SNAPPING :
1894 player->is_dropping ? ACTION_DROPPING :
1895 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1897 InitPlayerGfxAnimation(player, action, move_dir);
1899 /* ----------------------------------------------------------------------- */
1900 /* draw things in the field the player is leaving, if needed */
1901 /* ----------------------------------------------------------------------- */
1904 if (player->is_moving)
1906 if (player_is_moving)
1909 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1911 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1913 if (last_element == EL_DYNAMITE_ACTIVE ||
1914 last_element == EL_SP_DISK_RED_ACTIVE)
1915 DrawDynamite(last_jx, last_jy);
1917 DrawLevelFieldThruMask(last_jx, last_jy);
1919 else if (last_element == EL_DYNAMITE_ACTIVE ||
1920 last_element == EL_SP_DISK_RED_ACTIVE)
1921 DrawDynamite(last_jx, last_jy);
1923 DrawLevelField(last_jx, last_jy);
1925 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1926 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1929 if (!IN_SCR_FIELD(sx, sy))
1932 if (setup.direct_draw)
1933 SetDrawtoField(DRAW_BUFFERED);
1935 /* ----------------------------------------------------------------------- */
1936 /* draw things behind the player, if needed */
1937 /* ----------------------------------------------------------------------- */
1940 DrawLevelElement(jx, jy, Back[jx][jy]);
1941 else if (IS_ACTIVE_BOMB(element))
1942 DrawLevelElement(jx, jy, EL_EMPTY);
1945 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1947 if (GFX_CRUMBLED(GfxElement[jx][jy]))
1948 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1951 int old_element = GfxElement[jx][jy];
1952 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1953 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1955 DrawGraphic(sx, sy, old_graphic, frame);
1960 GfxElement[jx][jy] = EL_UNDEFINED;
1962 DrawLevelField(jx, jy);
1966 /* ----------------------------------------------------------------------- */
1967 /* draw player himself */
1968 /* ----------------------------------------------------------------------- */
1972 graphic = getPlayerGraphic(player, move_dir);
1974 /* in the case of changed player action or direction, prevent the current
1975 animation frame from being restarted for identical animations */
1976 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1977 player->Frame = last_player_frame;
1981 if (player->use_murphy_graphic)
1983 static int last_horizontal_dir = MV_LEFT;
1985 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1986 last_horizontal_dir = move_dir;
1988 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1990 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1992 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1994 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1998 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
2002 frame = getGraphicAnimationFrame(graphic, player->Frame);
2006 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2007 sxx = player->GfxPos;
2009 syy = player->GfxPos;
2012 if (!setup.soft_scrolling && ScreenMovPos)
2015 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2017 if (SHIELD_ON(player))
2019 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2020 IMG_SHIELD_NORMAL_ACTIVE);
2021 int frame = getGraphicAnimationFrame(graphic, -1);
2023 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2026 /* ----------------------------------------------------------------------- */
2027 /* draw things the player is pushing, if needed */
2028 /* ----------------------------------------------------------------------- */
2031 printf("::: %d, %d [%d, %d] [%d]\n",
2032 player->is_pushing, player_is_moving, player->GfxAction,
2033 player->is_moving, player_is_moving);
2037 if (player->is_pushing && player->is_moving)
2039 if (player->is_pushing && player_is_moving)
2043 int px = SCREENX(jx), py = SCREENY(jy);
2044 int pxx = (TILEX - ABS(sxx)) * dx;
2045 int pyy = (TILEY - ABS(syy)) * dy;
2047 int px = SCREENX(next_jx), py = SCREENY(next_jy);
2056 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2057 element = Feld[next_jx][next_jy];
2059 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2060 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2062 /* draw background element under pushed element (like the Sokoban field) */
2063 if (Back[next_jx][next_jy])
2064 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2066 /* masked drawing is needed for EMC style (double) movement graphics */
2067 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2070 if (Back[next_jx][next_jy])
2071 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2073 if ((pxx || pyy) && element == EL_SOKOBAN_OBJECT)
2074 DrawGraphicShiftedThruMask(px, py, pxx, pyy, IMG_SOKOBAN_OBJECT, 0,
2078 int element = MovingOrBlocked2Element(next_jx, next_jy);
2079 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2081 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2083 int frame = getGraphicAnimationFrame(graphic, player->Frame);
2087 /* masked drawing is needed for EMC style (double) movement graphics */
2088 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame,
2091 DrawGraphicShifted(px, py, pxx, pyy, graphic, frame,
2092 NO_CUTTING, NO_MASKING);
2098 /* ----------------------------------------------------------------------- */
2099 /* draw things in front of player (active dynamite or dynabombs) */
2100 /* ----------------------------------------------------------------------- */
2102 if (IS_ACTIVE_BOMB(element))
2104 graphic = el2img(element);
2105 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2107 if (game.emulation == EMU_SUPAPLEX)
2108 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2110 DrawGraphicThruMask(sx, sy, graphic, frame);
2113 if (player_is_moving && last_element == EL_EXPLOSION)
2115 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
2116 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2117 int phase = ExplodePhase[last_jx][last_jy] - 1;
2118 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2121 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2124 /* ----------------------------------------------------------------------- */
2125 /* draw elements the player is just walking/passing through/under */
2126 /* ----------------------------------------------------------------------- */
2128 if (player_is_moving)
2130 /* handle the field the player is leaving ... */
2131 if (IS_ACCESSIBLE_INSIDE(last_element))
2132 DrawLevelField(last_jx, last_jy);
2133 else if (IS_ACCESSIBLE_UNDER(last_element))
2134 DrawLevelFieldThruMask(last_jx, last_jy);
2138 /* do not redraw accessible elements if the player is just pushing them */
2139 if (!player_is_moving || !player->is_pushing)
2141 /* ... and the field the player is entering */
2142 if (IS_ACCESSIBLE_INSIDE(element))
2143 DrawLevelField(jx, jy);
2144 else if (IS_ACCESSIBLE_UNDER(element))
2145 DrawLevelFieldThruMask(jx, jy);
2151 /* !!! I have forgotton what this should be good for !!! */
2152 /* !!! causes player being visible when pushing from within tubes !!! */
2153 if (!player->is_pushing)
2156 /* ... and the field the player is entering */
2157 if (IS_ACCESSIBLE_INSIDE(element))
2158 DrawLevelField(jx, jy);
2159 else if (IS_ACCESSIBLE_UNDER(element))
2160 DrawLevelFieldThruMask(jx, jy);
2164 if (setup.direct_draw)
2166 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2167 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2168 int x_size = TILEX * (1 + ABS(jx - last_jx));
2169 int y_size = TILEY * (1 + ABS(jy - last_jy));
2171 BlitBitmap(drawto_field, window,
2172 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2173 SetDrawtoField(DRAW_DIRECT);
2176 MarkTileDirty(sx, sy);
2179 /* ------------------------------------------------------------------------- */
2181 void WaitForEventToContinue()
2183 boolean still_wait = TRUE;
2185 /* simulate releasing mouse button over last gadget, if still pressed */
2187 HandleGadgets(-1, -1, 0);
2189 button_status = MB_RELEASED;
2201 case EVENT_BUTTONPRESS:
2202 case EVENT_KEYPRESS:
2206 case EVENT_KEYRELEASE:
2207 ClearPlayerAction();
2211 HandleOtherEvents(&event);
2215 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2222 /* don't eat all CPU time */
2227 #define MAX_REQUEST_LINES 13
2228 #define MAX_REQUEST_LINE_FONT1_LEN 7
2229 #define MAX_REQUEST_LINE_FONT2_LEN 10
2231 boolean Request(char *text, unsigned int req_state)
2233 int mx, my, ty, result = -1;
2234 unsigned int old_door_state;
2235 int last_game_status = game_status; /* save current game status */
2236 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2237 int font_nr = FONT_TEXT_2;
2238 int max_word_len = 0;
2241 for (text_ptr = text; *text_ptr; text_ptr++)
2243 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2245 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2247 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2248 font_nr = FONT_LEVEL_NUMBER;
2255 if (game_status == GAME_MODE_PLAYING &&
2256 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2257 BlitScreenToBitmap_EM(backbuffer);
2261 /* disable deactivated drawing when quick-loading level tape recording */
2262 if (tape.playing && tape.deactivate_display)
2263 TapeDeactivateDisplayOff(TRUE);
2267 SetMouseCursor(CURSOR_DEFAULT);
2270 #if defined(NETWORK_AVALIABLE)
2271 /* pause network game while waiting for request to answer */
2272 if (options.network &&
2273 game_status == GAME_MODE_PLAYING &&
2274 req_state & REQUEST_WAIT_FOR_INPUT)
2275 SendToServer_PausePlaying();
2278 old_door_state = GetDoorState();
2280 /* simulate releasing mouse button over last gadget, if still pressed */
2282 HandleGadgets(-1, -1, 0);
2286 if (old_door_state & DOOR_OPEN_1)
2288 CloseDoor(DOOR_CLOSE_1);
2290 /* save old door content */
2291 BlitBitmap(bitmap_db_door, bitmap_db_door,
2292 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2293 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2296 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2298 /* clear door drawing field */
2299 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2301 /* force DOOR font on preview level */
2302 game_status = GAME_MODE_PSEUDO_DOOR;
2304 /* write text for request */
2305 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2307 char text_line[max_request_line_len + 1];
2313 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2316 if (!tc || tc == ' ')
2327 strncpy(text_line, text, tl);
2330 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2331 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2332 text_line, font_nr);
2334 text += tl + (tc == ' ' ? 1 : 0);
2337 game_status = last_game_status; /* restore current game status */
2339 if (req_state & REQ_ASK)
2341 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2342 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2344 else if (req_state & REQ_CONFIRM)
2346 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2348 else if (req_state & REQ_PLAYER)
2350 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2351 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2352 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2353 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2356 /* copy request gadgets to door backbuffer */
2357 BlitBitmap(drawto, bitmap_db_door,
2358 DX, DY, DXSIZE, DYSIZE,
2359 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2361 OpenDoor(DOOR_OPEN_1);
2367 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2369 SetDrawBackgroundMask(REDRAW_FIELD);
2374 if (game_status != GAME_MODE_MAIN)
2377 button_status = MB_RELEASED;
2379 request_gadget_id = -1;
2381 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2384 SetMouseCursor(CURSOR_DEFAULT);
2397 case EVENT_BUTTONPRESS:
2398 case EVENT_BUTTONRELEASE:
2399 case EVENT_MOTIONNOTIFY:
2401 if (event.type == EVENT_MOTIONNOTIFY)
2403 if (!PointerInWindow(window))
2404 continue; /* window and pointer are on different screens */
2409 motion_status = TRUE;
2410 mx = ((MotionEvent *) &event)->x;
2411 my = ((MotionEvent *) &event)->y;
2415 motion_status = FALSE;
2416 mx = ((ButtonEvent *) &event)->x;
2417 my = ((ButtonEvent *) &event)->y;
2418 if (event.type == EVENT_BUTTONPRESS)
2419 button_status = ((ButtonEvent *) &event)->button;
2421 button_status = MB_RELEASED;
2424 /* this sets 'request_gadget_id' */
2425 HandleGadgets(mx, my, button_status);
2427 switch(request_gadget_id)
2429 case TOOL_CTRL_ID_YES:
2432 case TOOL_CTRL_ID_NO:
2435 case TOOL_CTRL_ID_CONFIRM:
2436 result = TRUE | FALSE;
2439 case TOOL_CTRL_ID_PLAYER_1:
2442 case TOOL_CTRL_ID_PLAYER_2:
2445 case TOOL_CTRL_ID_PLAYER_3:
2448 case TOOL_CTRL_ID_PLAYER_4:
2459 case EVENT_KEYPRESS:
2460 switch(GetEventKey((KeyEvent *)&event, TRUE))
2473 if (req_state & REQ_PLAYER)
2477 case EVENT_KEYRELEASE:
2478 ClearPlayerAction();
2482 HandleOtherEvents(&event);
2486 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2488 int joy = AnyJoystick();
2490 if (joy & JOY_BUTTON_1)
2492 else if (joy & JOY_BUTTON_2)
2498 /* don't eat all CPU time */
2502 if (game_status != GAME_MODE_MAIN)
2507 if (!(req_state & REQ_STAY_OPEN))
2509 CloseDoor(DOOR_CLOSE_1);
2511 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2512 (req_state & REQ_REOPEN))
2513 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2518 SetDrawBackgroundMask(REDRAW_FIELD);
2520 #if defined(NETWORK_AVALIABLE)
2521 /* continue network game after request */
2522 if (options.network &&
2523 game_status == GAME_MODE_PLAYING &&
2524 req_state & REQUEST_WAIT_FOR_INPUT)
2525 SendToServer_ContinuePlaying();
2529 /* restore deactivated drawing when quick-loading level tape recording */
2530 if (tape.playing && tape.deactivate_display)
2531 TapeDeactivateDisplayOn();
2537 unsigned int OpenDoor(unsigned int door_state)
2539 if (door_state & DOOR_COPY_BACK)
2541 if (door_state & DOOR_OPEN_1)
2542 BlitBitmap(bitmap_db_door, bitmap_db_door,
2543 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2544 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2546 if (door_state & DOOR_OPEN_2)
2547 BlitBitmap(bitmap_db_door, bitmap_db_door,
2548 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2549 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2551 door_state &= ~DOOR_COPY_BACK;
2554 return MoveDoor(door_state);
2557 unsigned int CloseDoor(unsigned int door_state)
2559 unsigned int old_door_state = GetDoorState();
2561 if (!(door_state & DOOR_NO_COPY_BACK))
2563 if (old_door_state & DOOR_OPEN_1)
2564 BlitBitmap(backbuffer, bitmap_db_door,
2565 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2567 if (old_door_state & DOOR_OPEN_2)
2568 BlitBitmap(backbuffer, bitmap_db_door,
2569 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2571 door_state &= ~DOOR_NO_COPY_BACK;
2574 return MoveDoor(door_state);
2577 unsigned int GetDoorState()
2579 return MoveDoor(DOOR_GET_STATE);
2582 unsigned int SetDoorState(unsigned int door_state)
2584 return MoveDoor(door_state | DOOR_SET_STATE);
2587 unsigned int MoveDoor(unsigned int door_state)
2589 static int door1 = DOOR_OPEN_1;
2590 static int door2 = DOOR_CLOSE_2;
2591 unsigned long door_delay = 0;
2592 unsigned long door_delay_value;
2595 if (door_state == DOOR_GET_STATE)
2596 return(door1 | door2);
2598 if (door_state & DOOR_SET_STATE)
2600 if (door_state & DOOR_ACTION_1)
2601 door1 = door_state & DOOR_ACTION_1;
2602 if (door_state & DOOR_ACTION_2)
2603 door2 = door_state & DOOR_ACTION_2;
2605 return(door1 | door2);
2608 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2609 door_state &= ~DOOR_OPEN_1;
2610 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2611 door_state &= ~DOOR_CLOSE_1;
2612 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2613 door_state &= ~DOOR_OPEN_2;
2614 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2615 door_state &= ~DOOR_CLOSE_2;
2617 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2620 if (setup.quick_doors)
2622 stepsize = 20; /* must be choosen to always draw last frame */
2623 door_delay_value = 0;
2626 StopSound(SND_DOOR_OPENING);
2627 StopSound(SND_DOOR_CLOSING);
2631 if (global.autoplay_leveldir)
2633 door_state |= DOOR_NO_DELAY;
2634 door_state &= ~DOOR_CLOSE_ALL;
2637 if (door_state & DOOR_ACTION)
2639 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2640 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2641 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2642 int end = (door_state & DOOR_ACTION_1 &&
2643 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2646 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2648 /* opening door sound has priority over simultaneously closing door */
2649 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2650 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2651 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2652 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2655 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2657 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2658 GC gc = bitmap->stored_clip_gc;
2660 if (door_state & DOOR_ACTION_1)
2662 int a = MIN(x * door_1.step_offset, end);
2663 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2667 BlitBitmap(bitmap_db_door, drawto,
2668 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2669 DXSIZE, DYSIZE - i / 2, DX, DY);
2671 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2674 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2676 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2677 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2678 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2679 int dst2_x = DX, dst2_y = DY;
2680 int width = i, height = DYSIZE;
2682 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2683 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2686 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2687 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2690 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2692 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2693 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2694 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2695 int dst2_x = DX, dst2_y = DY;
2696 int width = DXSIZE, height = i;
2698 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2699 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2702 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2703 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2706 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2708 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2710 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2711 BlitBitmapMasked(bitmap, drawto,
2712 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2713 DX + DXSIZE - i, DY + j);
2714 BlitBitmapMasked(bitmap, drawto,
2715 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2716 DX + DXSIZE - i, DY + 140 + j);
2717 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2718 DY - (DOOR_GFX_PAGEY1 + j));
2719 BlitBitmapMasked(bitmap, drawto,
2720 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2722 BlitBitmapMasked(bitmap, drawto,
2723 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2726 BlitBitmapMasked(bitmap, drawto,
2727 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2729 BlitBitmapMasked(bitmap, drawto,
2730 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2732 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2733 BlitBitmapMasked(bitmap, drawto,
2734 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2735 DX + DXSIZE - i, DY + 77 + j);
2736 BlitBitmapMasked(bitmap, drawto,
2737 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2738 DX + DXSIZE - i, DY + 203 + j);
2741 redraw_mask |= REDRAW_DOOR_1;
2742 door_1_done = (a == end);
2745 if (door_state & DOOR_ACTION_2)
2747 int a = MIN(x * door_2.step_offset, VXSIZE);
2748 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2752 BlitBitmap(bitmap_db_door, drawto,
2753 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2754 VXSIZE, VYSIZE - i / 2, VX, VY);
2756 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2759 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2761 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2762 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2763 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2764 int dst2_x = VX, dst2_y = VY;
2765 int width = i, height = VYSIZE;
2767 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2768 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2771 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2772 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2775 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2777 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2778 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2779 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2780 int dst2_x = VX, dst2_y = VY;
2781 int width = VXSIZE, height = i;
2783 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2784 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2787 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2788 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2791 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2793 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2795 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2796 BlitBitmapMasked(bitmap, drawto,
2797 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2798 VX + VXSIZE - i, VY + j);
2799 SetClipOrigin(bitmap, gc,
2800 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2801 BlitBitmapMasked(bitmap, drawto,
2802 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2805 BlitBitmapMasked(bitmap, drawto,
2806 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2807 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2808 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2809 BlitBitmapMasked(bitmap, drawto,
2810 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2812 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2815 redraw_mask |= REDRAW_DOOR_2;
2816 door_2_done = (a == VXSIZE);
2821 if (game_status == GAME_MODE_MAIN)
2824 if (!(door_state & DOOR_NO_DELAY))
2825 WaitUntilDelayReached(&door_delay, door_delay_value);
2830 if (setup.quick_doors)
2832 StopSound(SND_DOOR_OPENING);
2833 StopSound(SND_DOOR_CLOSING);
2837 if (door_state & DOOR_ACTION_1)
2838 door1 = door_state & DOOR_ACTION_1;
2839 if (door_state & DOOR_ACTION_2)
2840 door2 = door_state & DOOR_ACTION_2;
2842 return (door1 | door2);
2845 void DrawSpecialEditorDoor()
2847 /* draw bigger toolbox window */
2848 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2849 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2851 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2852 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2855 redraw_mask |= REDRAW_ALL;
2858 void UndrawSpecialEditorDoor()
2860 /* draw normal tape recorder window */
2861 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2862 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2865 redraw_mask |= REDRAW_ALL;
2869 /* ---------- new tool button stuff ---------------------------------------- */
2871 /* graphic position values for tool buttons */
2872 #define TOOL_BUTTON_YES_XPOS 2
2873 #define TOOL_BUTTON_YES_YPOS 250
2874 #define TOOL_BUTTON_YES_GFX_YPOS 0
2875 #define TOOL_BUTTON_YES_XSIZE 46
2876 #define TOOL_BUTTON_YES_YSIZE 28
2877 #define TOOL_BUTTON_NO_XPOS 52
2878 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2879 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2880 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2881 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2882 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2883 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2884 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2885 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2886 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2887 #define TOOL_BUTTON_PLAYER_XSIZE 30
2888 #define TOOL_BUTTON_PLAYER_YSIZE 30
2889 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2890 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2891 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2892 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2893 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2894 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2895 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2896 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2897 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2898 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2899 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2900 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2901 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2902 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2903 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2904 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2905 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2906 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2907 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2908 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2917 } toolbutton_info[NUM_TOOL_BUTTONS] =
2920 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2921 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2922 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2927 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2928 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2929 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2934 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2935 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2936 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2937 TOOL_CTRL_ID_CONFIRM,
2941 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2942 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2943 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2944 TOOL_CTRL_ID_PLAYER_1,
2948 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2949 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2950 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2951 TOOL_CTRL_ID_PLAYER_2,
2955 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2956 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2957 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2958 TOOL_CTRL_ID_PLAYER_3,
2962 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2963 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2964 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2965 TOOL_CTRL_ID_PLAYER_4,
2970 void CreateToolButtons()
2974 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2976 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2977 Bitmap *deco_bitmap = None;
2978 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2979 struct GadgetInfo *gi;
2980 unsigned long event_mask;
2981 int gd_xoffset, gd_yoffset;
2982 int gd_x1, gd_x2, gd_y;
2985 event_mask = GD_EVENT_RELEASED;
2987 gd_xoffset = toolbutton_info[i].xpos;
2988 gd_yoffset = toolbutton_info[i].ypos;
2989 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2990 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2991 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2993 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2995 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2997 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2998 &deco_bitmap, &deco_x, &deco_y);
2999 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3000 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3003 gi = CreateGadget(GDI_CUSTOM_ID, id,
3004 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3005 GDI_X, DX + toolbutton_info[i].x,
3006 GDI_Y, DY + toolbutton_info[i].y,
3007 GDI_WIDTH, toolbutton_info[i].width,
3008 GDI_HEIGHT, toolbutton_info[i].height,
3009 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3010 GDI_STATE, GD_BUTTON_UNPRESSED,
3011 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3012 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3013 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3014 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3015 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3016 GDI_DECORATION_SHIFTING, 1, 1,
3017 GDI_EVENT_MASK, event_mask,
3018 GDI_CALLBACK_ACTION, HandleToolButtons,
3022 Error(ERR_EXIT, "cannot create gadget");
3024 tool_gadget[id] = gi;
3028 void FreeToolButtons()
3032 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3033 FreeGadget(tool_gadget[i]);
3036 static void UnmapToolButtons()
3040 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3041 UnmapGadget(tool_gadget[i]);
3044 static void HandleToolButtons(struct GadgetInfo *gi)
3046 request_gadget_id = gi->custom_id;
3051 static struct Mapping_EM_to_RND_object
3054 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3055 boolean is_backside; /* backside of moving element */
3061 em_object_mapping_list[] =
3064 Xblank, TRUE, FALSE,
3068 Yacid_splash_eB, FALSE, FALSE,
3069 EL_ACID_SPLASH_RIGHT, -1, -1
3072 Yacid_splash_wB, FALSE, FALSE,
3073 EL_ACID_SPLASH_LEFT, -1, -1
3076 #ifdef EM_ENGINE_BAD_ROLL
3078 Xstone_force_e, FALSE, FALSE,
3079 EL_ROCK, -1, MV_BIT_RIGHT
3082 Xstone_force_w, FALSE, FALSE,
3083 EL_ROCK, -1, MV_BIT_LEFT
3086 Xnut_force_e, FALSE, FALSE,
3087 EL_NUT, -1, MV_BIT_RIGHT
3090 Xnut_force_w, FALSE, FALSE,
3091 EL_NUT, -1, MV_BIT_LEFT
3094 Xspring_force_e, FALSE, FALSE,
3095 EL_SPRING, -1, MV_BIT_RIGHT
3098 Xspring_force_w, FALSE, FALSE,
3099 EL_SPRING, -1, MV_BIT_LEFT
3102 Xemerald_force_e, FALSE, FALSE,
3103 EL_EMERALD, -1, MV_BIT_RIGHT
3106 Xemerald_force_w, FALSE, FALSE,
3107 EL_EMERALD, -1, MV_BIT_LEFT
3110 Xdiamond_force_e, FALSE, FALSE,
3111 EL_DIAMOND, -1, MV_BIT_RIGHT
3114 Xdiamond_force_w, FALSE, FALSE,
3115 EL_DIAMOND, -1, MV_BIT_LEFT
3118 Xbomb_force_e, FALSE, FALSE,
3119 EL_BOMB, -1, MV_BIT_RIGHT
3122 Xbomb_force_w, FALSE, FALSE,
3123 EL_BOMB, -1, MV_BIT_LEFT
3125 #endif /* EM_ENGINE_BAD_ROLL */
3128 Xstone, TRUE, FALSE,
3132 Xstone_pause, FALSE, FALSE,
3136 Xstone_fall, FALSE, FALSE,
3140 Ystone_s, FALSE, FALSE,
3141 EL_ROCK, ACTION_FALLING, -1
3144 Ystone_sB, FALSE, TRUE,
3145 EL_ROCK, ACTION_FALLING, -1
3148 Ystone_e, FALSE, FALSE,
3149 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3152 Ystone_eB, FALSE, TRUE,
3153 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3156 Ystone_w, FALSE, FALSE,
3157 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3160 Ystone_wB, FALSE, TRUE,
3161 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3168 Xnut_pause, FALSE, FALSE,
3172 Xnut_fall, FALSE, FALSE,
3176 Ynut_s, FALSE, FALSE,
3177 EL_NUT, ACTION_FALLING, -1
3180 Ynut_sB, FALSE, TRUE,
3181 EL_NUT, ACTION_FALLING, -1
3184 Ynut_e, FALSE, FALSE,
3185 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3188 Ynut_eB, FALSE, TRUE,
3189 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3192 Ynut_w, FALSE, FALSE,
3193 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3196 Ynut_wB, FALSE, TRUE,
3197 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3200 Xbug_n, TRUE, FALSE,
3204 Xbug_e, TRUE, FALSE,
3205 EL_BUG_RIGHT, -1, -1
3208 Xbug_s, TRUE, FALSE,
3212 Xbug_w, TRUE, FALSE,
3216 Xbug_gon, FALSE, FALSE,
3220 Xbug_goe, FALSE, FALSE,
3221 EL_BUG_RIGHT, -1, -1
3224 Xbug_gos, FALSE, FALSE,
3228 Xbug_gow, FALSE, FALSE,
3232 Ybug_n, FALSE, FALSE,
3233 EL_BUG, ACTION_MOVING, MV_BIT_UP
3236 Ybug_nB, FALSE, TRUE,
3237 EL_BUG, ACTION_MOVING, MV_BIT_UP
3240 Ybug_e, FALSE, FALSE,
3241 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3244 Ybug_eB, FALSE, TRUE,
3245 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3248 Ybug_s, FALSE, FALSE,
3249 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3252 Ybug_sB, FALSE, TRUE,
3253 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3256 Ybug_w, FALSE, FALSE,
3257 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3260 Ybug_wB, FALSE, TRUE,
3261 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3264 Ybug_w_n, FALSE, FALSE,
3265 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3268 Ybug_n_e, FALSE, FALSE,
3269 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3272 Ybug_e_s, FALSE, FALSE,
3273 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3276 Ybug_s_w, FALSE, FALSE,
3277 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3280 Ybug_e_n, FALSE, FALSE,
3281 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3284 Ybug_s_e, FALSE, FALSE,
3285 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3288 Ybug_w_s, FALSE, FALSE,
3289 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3292 Ybug_n_w, FALSE, FALSE,
3293 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3296 Ybug_stone, FALSE, FALSE,
3297 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3300 Ybug_spring, FALSE, FALSE,
3301 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3304 Xtank_n, TRUE, FALSE,
3305 EL_SPACESHIP_UP, -1, -1
3308 Xtank_e, TRUE, FALSE,
3309 EL_SPACESHIP_RIGHT, -1, -1
3312 Xtank_s, TRUE, FALSE,
3313 EL_SPACESHIP_DOWN, -1, -1
3316 Xtank_w, TRUE, FALSE,
3317 EL_SPACESHIP_LEFT, -1, -1
3320 Xtank_gon, FALSE, FALSE,
3321 EL_SPACESHIP_UP, -1, -1
3324 Xtank_goe, FALSE, FALSE,
3325 EL_SPACESHIP_RIGHT, -1, -1
3328 Xtank_gos, FALSE, FALSE,
3329 EL_SPACESHIP_DOWN, -1, -1
3332 Xtank_gow, FALSE, FALSE,
3333 EL_SPACESHIP_LEFT, -1, -1
3336 Ytank_n, FALSE, FALSE,
3337 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3340 Ytank_nB, FALSE, TRUE,
3341 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3344 Ytank_e, FALSE, FALSE,
3345 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3348 Ytank_eB, FALSE, TRUE,
3349 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3352 Ytank_s, FALSE, FALSE,
3353 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3356 Ytank_sB, FALSE, TRUE,
3357 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3360 Ytank_w, FALSE, FALSE,
3361 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3364 Ytank_wB, FALSE, TRUE,
3365 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3368 Ytank_w_n, FALSE, FALSE,
3369 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3372 Ytank_n_e, FALSE, FALSE,
3373 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3376 Ytank_e_s, FALSE, FALSE,
3377 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3380 Ytank_s_w, FALSE, FALSE,
3381 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3384 Ytank_e_n, FALSE, FALSE,
3385 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3388 Ytank_s_e, FALSE, FALSE,
3389 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3392 Ytank_w_s, FALSE, FALSE,
3393 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3396 Ytank_n_w, FALSE, FALSE,
3397 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3400 Ytank_stone, FALSE, FALSE,
3401 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3404 Ytank_spring, FALSE, FALSE,
3405 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3408 Xandroid, TRUE, FALSE,
3409 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3412 Xandroid_1_n, FALSE, FALSE,
3413 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3416 Xandroid_2_n, FALSE, FALSE,
3417 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3420 Xandroid_1_e, FALSE, FALSE,
3421 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3424 Xandroid_2_e, FALSE, FALSE,
3425 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3428 Xandroid_1_w, FALSE, FALSE,
3429 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3432 Xandroid_2_w, FALSE, FALSE,
3433 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3436 Xandroid_1_s, FALSE, FALSE,
3437 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3440 Xandroid_2_s, FALSE, FALSE,
3441 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3444 Yandroid_n, FALSE, FALSE,
3445 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3448 Yandroid_nB, FALSE, TRUE,
3449 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3452 Yandroid_ne, FALSE, FALSE,
3453 EL_EMC_ANDROID, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3456 Yandroid_neB, FALSE, TRUE,
3457 EL_EMC_ANDROID, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3460 Yandroid_e, FALSE, FALSE,
3461 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3464 Yandroid_eB, FALSE, TRUE,
3465 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3468 Yandroid_se, FALSE, FALSE,
3469 EL_EMC_ANDROID, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3472 Yandroid_seB, FALSE, TRUE,
3473 EL_EMC_ANDROID, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3476 Yandroid_s, FALSE, FALSE,
3477 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3480 Yandroid_sB, FALSE, TRUE,
3481 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3484 Yandroid_sw, FALSE, FALSE,
3485 EL_EMC_ANDROID, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3488 Yandroid_swB, FALSE, TRUE,
3489 EL_EMC_ANDROID, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3492 Yandroid_w, FALSE, FALSE,
3493 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3496 Yandroid_wB, FALSE, TRUE,
3497 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3500 Yandroid_nw, FALSE, FALSE,
3501 EL_EMC_ANDROID, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3504 Yandroid_nwB, FALSE, TRUE,
3505 EL_EMC_ANDROID, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3508 Xspring, TRUE, FALSE,
3512 Xspring_pause, FALSE, FALSE,
3516 Xspring_e, FALSE, FALSE,
3520 Xspring_w, FALSE, FALSE,
3524 Xspring_fall, FALSE, FALSE,
3528 Yspring_s, FALSE, FALSE,
3529 EL_SPRING, ACTION_FALLING, -1
3532 Yspring_sB, FALSE, TRUE,
3533 EL_SPRING, ACTION_FALLING, -1
3536 Yspring_e, FALSE, FALSE,
3537 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3540 Yspring_eB, FALSE, TRUE,
3541 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3544 Yspring_w, FALSE, FALSE,
3545 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3548 Yspring_wB, FALSE, TRUE,
3549 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3552 Yspring_kill_e, FALSE, FALSE,
3553 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_RIGHT
3556 Yspring_kill_eB, FALSE, TRUE,
3557 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_RIGHT
3560 Yspring_kill_w, FALSE, FALSE,
3561 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_LEFT
3564 Yspring_kill_wB, FALSE, TRUE,
3565 EL_ROBOT, ACTION_SLURPED_BY_SPRING, MV_BIT_LEFT
3568 Xeater_n, TRUE, FALSE,
3572 Xeater_e, FALSE, FALSE,
3576 Xeater_w, FALSE, FALSE,
3580 Xeater_s, FALSE, FALSE,
3584 Yeater_n, FALSE, FALSE,
3585 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3588 Yeater_nB, FALSE, TRUE,
3589 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3592 Yeater_e, FALSE, FALSE,
3593 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3596 Yeater_eB, FALSE, TRUE,
3597 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3600 Yeater_s, FALSE, FALSE,
3601 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3604 Yeater_sB, FALSE, TRUE,
3605 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3608 Yeater_w, FALSE, FALSE,
3609 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3612 Yeater_wB, FALSE, TRUE,
3613 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3616 Yeater_stone, FALSE, FALSE,
3617 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3620 Yeater_spring, FALSE, FALSE,
3621 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3624 Xalien, TRUE, FALSE,
3628 Xalien_pause, FALSE, FALSE,
3632 Yalien_n, FALSE, FALSE,
3633 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3636 Yalien_nB, FALSE, TRUE,
3637 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3640 Yalien_e, FALSE, FALSE,
3641 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3644 Yalien_eB, FALSE, TRUE,
3645 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3648 Yalien_s, FALSE, FALSE,
3649 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3652 Yalien_sB, FALSE, TRUE,
3653 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3656 Yalien_w, FALSE, FALSE,
3657 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3660 Yalien_wB, FALSE, TRUE,
3661 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3664 Yalien_stone, FALSE, FALSE,
3665 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3668 Yalien_spring, FALSE, FALSE,
3669 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3672 Xemerald, TRUE, FALSE,
3676 Xemerald_pause, FALSE, FALSE,
3680 Xemerald_fall, FALSE, FALSE,
3684 Xemerald_shine, FALSE, FALSE,
3685 EL_EMERALD, ACTION_TWINKLING, -1
3688 Yemerald_s, FALSE, FALSE,
3689 EL_EMERALD, ACTION_FALLING, -1
3692 Yemerald_sB, FALSE, TRUE,
3693 EL_EMERALD, ACTION_FALLING, -1
3696 Yemerald_e, FALSE, FALSE,
3697 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3700 Yemerald_eB, FALSE, TRUE,
3701 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3704 Yemerald_w, FALSE, FALSE,
3705 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3708 Yemerald_wB, FALSE, TRUE,
3709 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3712 Yemerald_eat, FALSE, FALSE,
3713 EL_EMERALD, ACTION_COLLECTING, -1
3716 Yemerald_stone, FALSE, FALSE,
3717 EL_NUT, ACTION_BREAKING, -1
3720 Xdiamond, TRUE, FALSE,
3724 Xdiamond_pause, FALSE, FALSE,
3728 Xdiamond_fall, FALSE, FALSE,
3732 Xdiamond_shine, FALSE, FALSE,
3733 EL_DIAMOND, ACTION_TWINKLING, -1
3736 Ydiamond_s, FALSE, FALSE,
3737 EL_DIAMOND, ACTION_FALLING, -1
3740 Ydiamond_sB, FALSE, TRUE,
3741 EL_DIAMOND, ACTION_FALLING, -1
3744 Ydiamond_e, FALSE, FALSE,
3745 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3748 Ydiamond_eB, FALSE, TRUE,
3749 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3752 Ydiamond_w, FALSE, FALSE,
3753 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3756 Ydiamond_wB, FALSE, TRUE,
3757 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3760 Ydiamond_eat, FALSE, FALSE,
3761 EL_DIAMOND, ACTION_COLLECTING, -1
3764 Ydiamond_stone, FALSE, FALSE,
3765 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3768 Xdrip_fall, TRUE, FALSE,
3769 EL_AMOEBA_DROP, -1, -1
3772 Xdrip_stretch, FALSE, FALSE,
3773 EL_AMOEBA_DROP, ACTION_FALLING, -1
3776 Xdrip_stretchB, FALSE, TRUE,
3777 EL_AMOEBA_DROP, ACTION_FALLING, -1
3780 Xdrip_eat, FALSE, FALSE,
3781 EL_AMOEBA_DROP, ACTION_GROWING, -1
3784 Ydrip_s1, FALSE, FALSE,
3785 EL_AMOEBA_DROP, ACTION_FALLING, -1
3788 Ydrip_s1B, FALSE, TRUE,
3789 EL_AMOEBA_DROP, ACTION_FALLING, -1
3792 Ydrip_s2, FALSE, FALSE,
3793 EL_AMOEBA_DROP, ACTION_FALLING, -1
3796 Ydrip_s2B, FALSE, TRUE,
3797 EL_AMOEBA_DROP, ACTION_FALLING, -1
3804 Xbomb_pause, FALSE, FALSE,
3808 Xbomb_fall, FALSE, FALSE,
3812 Ybomb_s, FALSE, FALSE,
3813 EL_BOMB, ACTION_FALLING, -1
3816 Ybomb_sB, FALSE, TRUE,
3817 EL_BOMB, ACTION_FALLING, -1
3820 Ybomb_e, FALSE, FALSE,
3821 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3824 Ybomb_eB, FALSE, TRUE,
3825 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3828 Ybomb_w, FALSE, FALSE,
3829 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3832 Ybomb_wB, FALSE, TRUE,
3833 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3836 Ybomb_eat, FALSE, FALSE,
3837 EL_BOMB, ACTION_SMASHED_BY_ROCK, -1
3840 Xballoon, TRUE, FALSE,
3844 Yballoon_n, FALSE, FALSE,
3845 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3848 Yballoon_nB, FALSE, TRUE,
3849 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3852 Yballoon_e, FALSE, FALSE,
3853 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3856 Yballoon_eB, FALSE, TRUE,
3857 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3860 Yballoon_s, FALSE, FALSE,
3861 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3864 Yballoon_sB, FALSE, TRUE,
3865 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3868 Yballoon_w, FALSE, FALSE,
3869 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3872 Yballoon_wB, FALSE, TRUE,
3873 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3876 Xgrass, TRUE, FALSE,
3877 EL_EMC_GRASS, -1, -1
3880 Ygrass_nB, FALSE, FALSE,
3881 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3884 Ygrass_eB, FALSE, FALSE,
3885 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3888 Ygrass_sB, FALSE, FALSE,
3889 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3892 Ygrass_wB, FALSE, FALSE,
3893 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3900 Ydirt_nB, FALSE, FALSE,
3901 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3904 Ydirt_eB, FALSE, FALSE,
3905 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3908 Ydirt_sB, FALSE, FALSE,
3909 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3912 Ydirt_wB, FALSE, FALSE,
3913 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3916 Xacid_ne, TRUE, FALSE,
3917 EL_ACID_POOL_TOPRIGHT, -1, -1
3920 Xacid_se, TRUE, FALSE,
3921 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3924 Xacid_s, TRUE, FALSE,
3925 EL_ACID_POOL_BOTTOM, -1, -1
3928 Xacid_sw, TRUE, FALSE,
3929 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3932 Xacid_nw, TRUE, FALSE,
3933 EL_ACID_POOL_TOPLEFT, -1, -1
3936 Xacid_1, TRUE, FALSE,
3940 Xacid_2, FALSE, FALSE,
3944 Xacid_3, FALSE, FALSE,
3948 Xacid_4, FALSE, FALSE,
3952 Xacid_5, FALSE, FALSE,
3956 Xacid_6, FALSE, FALSE,
3960 Xacid_7, FALSE, FALSE,
3964 Xacid_8, FALSE, FALSE,
3968 Xball_1, TRUE, FALSE,
3969 EL_EMC_MAGIC_BALL, -1, -1
3972 Xball_1B, FALSE, FALSE,
3973 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3976 Xball_2, FALSE, FALSE,
3977 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3980 Xball_2B, FALSE, FALSE,
3981 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3984 Yball_eat, FALSE, FALSE,
3985 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3988 Ykey_1_eat, FALSE, FALSE,
3989 EL_EM_KEY_1, ACTION_COLLECTING, -1
3992 Ykey_2_eat, FALSE, FALSE,
3993 EL_EM_KEY_2, ACTION_COLLECTING, -1
3996 Ykey_3_eat, FALSE, FALSE,
3997 EL_EM_KEY_3, ACTION_COLLECTING, -1
4000 Ykey_4_eat, FALSE, FALSE,
4001 EL_EM_KEY_4, ACTION_COLLECTING, -1
4004 Ykey_5_eat, FALSE, FALSE,
4005 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4008 Ykey_6_eat, FALSE, FALSE,
4009 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4012 Ykey_7_eat, FALSE, FALSE,
4013 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4016 Ykey_8_eat, FALSE, FALSE,
4017 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4020 Ylenses_eat, FALSE, FALSE,
4021 EL_EMC_LENSES, ACTION_COLLECTING, -1
4024 Ymagnify_eat, FALSE, FALSE,
4025 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4028 Ygrass_eat, FALSE, FALSE,
4029 EL_EMC_GRASS, ACTION_SNAPPING, -1
4032 Ydirt_eat, FALSE, FALSE,
4033 EL_SAND, ACTION_SNAPPING, -1
4036 Xgrow_ns, TRUE, FALSE,
4037 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4040 Ygrow_ns_eat, FALSE, FALSE,
4041 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4044 Xgrow_ew, TRUE, FALSE,
4045 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4048 Ygrow_ew_eat, FALSE, FALSE,
4049 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4052 Xwonderwall, TRUE, FALSE,
4053 EL_MAGIC_WALL, -1, -1
4056 XwonderwallB, FALSE, FALSE,
4057 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4060 Xamoeba_1, TRUE, FALSE,
4061 EL_AMOEBA_DRY, ACTION_OTHER, -1
4064 Xamoeba_2, FALSE, FALSE,
4065 EL_AMOEBA_DRY, ACTION_OTHER, -1
4068 Xamoeba_3, FALSE, FALSE,
4069 EL_AMOEBA_DRY, ACTION_OTHER, -1
4072 Xamoeba_4, FALSE, FALSE,
4073 EL_AMOEBA_DRY, ACTION_OTHER, -1
4076 Xamoeba_5, TRUE, FALSE,
4077 EL_AMOEBA_WET, ACTION_OTHER, -1
4080 Xamoeba_6, FALSE, FALSE,
4081 EL_AMOEBA_WET, ACTION_OTHER, -1
4084 Xamoeba_7, FALSE, FALSE,
4085 EL_AMOEBA_WET, ACTION_OTHER, -1
4088 Xamoeba_8, FALSE, FALSE,
4089 EL_AMOEBA_WET, ACTION_OTHER, -1
4092 Xdoor_1, TRUE, FALSE,
4093 EL_EM_GATE_1, -1, -1
4096 Xdoor_2, TRUE, FALSE,
4097 EL_EM_GATE_2, -1, -1
4100 Xdoor_3, TRUE, FALSE,
4101 EL_EM_GATE_3, -1, -1
4104 Xdoor_4, TRUE, FALSE,
4105 EL_EM_GATE_4, -1, -1
4108 Xdoor_5, TRUE, FALSE,
4109 EL_EMC_GATE_5, -1, -1
4112 Xdoor_6, TRUE, FALSE,
4113 EL_EMC_GATE_6, -1, -1
4116 Xdoor_7, TRUE, FALSE,
4117 EL_EMC_GATE_7, -1, -1
4120 Xdoor_8, TRUE, FALSE,
4121 EL_EMC_GATE_8, -1, -1
4124 Xkey_1, TRUE, FALSE,
4128 Xkey_2, TRUE, FALSE,
4132 Xkey_3, TRUE, FALSE,
4136 Xkey_4, TRUE, FALSE,
4140 Xkey_5, TRUE, FALSE,
4141 EL_EMC_KEY_5, -1, -1
4144 Xkey_6, TRUE, FALSE,
4145 EL_EMC_KEY_6, -1, -1
4148 Xkey_7, TRUE, FALSE,
4149 EL_EMC_KEY_7, -1, -1
4152 Xkey_8, TRUE, FALSE,
4153 EL_EMC_KEY_8, -1, -1
4156 Xwind_n, TRUE, FALSE,
4157 EL_BALLOON_SWITCH_UP, -1, -1
4160 Xwind_e, TRUE, FALSE,
4161 EL_BALLOON_SWITCH_RIGHT, -1, -1
4164 Xwind_s, TRUE, FALSE,
4165 EL_BALLOON_SWITCH_DOWN, -1, -1
4168 Xwind_w, TRUE, FALSE,
4169 EL_BALLOON_SWITCH_LEFT, -1, -1
4172 Xwind_nesw, TRUE, FALSE,
4173 EL_BALLOON_SWITCH_ANY, -1, -1
4176 Xwind_stop, TRUE, FALSE,
4177 EL_BALLOON_SWITCH_NONE, -1, -1
4181 EL_EXIT_CLOSED, -1, -1
4184 Xexit_1, TRUE, FALSE,
4185 EL_EXIT_OPEN, -1, -1
4188 Xexit_2, FALSE, FALSE,
4189 EL_EXIT_OPEN, -1, -1
4192 Xexit_3, FALSE, FALSE,
4193 EL_EXIT_OPEN, -1, -1
4196 Xdynamite, TRUE, FALSE,
4200 Ydynamite_eat, FALSE, FALSE,
4201 EL_DYNAMITE, ACTION_COLLECTING, -1
4204 Xdynamite_1, TRUE, FALSE,
4205 EL_DYNAMITE_ACTIVE, -1, -1
4208 Xdynamite_2, FALSE, FALSE,
4209 EL_DYNAMITE_ACTIVE, -1, -1
4212 Xdynamite_3, FALSE, FALSE,
4213 EL_DYNAMITE_ACTIVE, -1, -1
4216 Xdynamite_4, FALSE, FALSE,
4217 EL_DYNAMITE_ACTIVE, -1, -1
4220 Xbumper, TRUE, FALSE,
4221 EL_EMC_SPRING_BUMPER, -1, -1
4224 XbumperB, FALSE, FALSE,
4225 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4228 Xwheel, TRUE, FALSE,
4229 EL_ROBOT_WHEEL, -1, -1
4232 XwheelB, FALSE, FALSE,
4233 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4236 Xswitch, TRUE, FALSE,
4237 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4240 XswitchB, FALSE, FALSE,
4241 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4245 EL_QUICKSAND_EMPTY, -1, -1
4248 Xsand_stone, TRUE, FALSE,
4249 EL_QUICKSAND_FULL, -1, -1
4252 Xsand_stonein_1, FALSE, FALSE,
4253 EL_ROCK, ACTION_FILLING, -1
4256 Xsand_stonein_2, FALSE, FALSE,
4257 EL_ROCK, ACTION_FILLING, -1
4260 Xsand_stonein_3, FALSE, FALSE,
4261 EL_ROCK, ACTION_FILLING, -1
4264 Xsand_stonein_4, FALSE, FALSE,
4265 EL_ROCK, ACTION_FILLING, -1
4268 Xsand_stonesand_1, FALSE, FALSE,
4269 EL_QUICKSAND_FULL, -1, -1
4272 Xsand_stonesand_2, FALSE, FALSE,
4273 EL_QUICKSAND_FULL, -1, -1
4276 Xsand_stonesand_3, FALSE, FALSE,
4277 EL_QUICKSAND_FULL, -1, -1
4280 Xsand_stonesand_4, FALSE, FALSE,
4281 EL_QUICKSAND_FULL, -1, -1
4284 Xsand_stoneout_1, FALSE, FALSE,
4285 EL_ROCK, ACTION_EMPTYING, -1
4288 Xsand_stoneout_2, FALSE, FALSE,
4289 EL_ROCK, ACTION_EMPTYING, -1
4292 Xsand_sandstone_1, FALSE, FALSE,
4293 EL_QUICKSAND_FULL, -1, -1
4296 Xsand_sandstone_2, FALSE, FALSE,
4297 EL_QUICKSAND_FULL, -1, -1
4300 Xsand_sandstone_3, FALSE, FALSE,
4301 EL_QUICKSAND_FULL, -1, -1
4304 Xsand_sandstone_4, FALSE, FALSE,
4305 EL_QUICKSAND_FULL, -1, -1
4308 Xplant, TRUE, FALSE,
4309 EL_EMC_PLANT, -1, -1
4312 Yplant, FALSE, FALSE,
4313 EL_EMC_PLANT, -1, -1
4316 Xlenses, TRUE, FALSE,
4317 EL_EMC_LENSES, -1, -1
4320 Xmagnify, TRUE, FALSE,
4321 EL_EMC_MAGNIFIER, -1, -1
4324 Xdripper, TRUE, FALSE,
4325 EL_EMC_DRIPPER, -1, -1
4328 XdripperB, FALSE, FALSE,
4329 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4332 Xfake_blank, TRUE, FALSE,
4333 EL_INVISIBLE_WALL, -1, -1
4336 Xfake_blankB, FALSE, FALSE,
4337 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4340 Xfake_grass, TRUE, FALSE,
4341 EL_EMC_FAKE_GRASS, -1, -1
4344 Xfake_grassB, FALSE, FALSE,
4345 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4348 Xfake_door_1, TRUE, FALSE,
4349 EL_EM_GATE_1_GRAY, -1, -1
4352 Xfake_door_2, TRUE, FALSE,
4353 EL_EM_GATE_2_GRAY, -1, -1
4356 Xfake_door_3, TRUE, FALSE,
4357 EL_EM_GATE_3_GRAY, -1, -1
4360 Xfake_door_4, TRUE, FALSE,
4361 EL_EM_GATE_4_GRAY, -1, -1
4364 Xfake_door_5, TRUE, FALSE,
4365 EL_EMC_GATE_5_GRAY, -1, -1
4368 Xfake_door_6, TRUE, FALSE,
4369 EL_EMC_GATE_6_GRAY, -1, -1
4372 Xfake_door_7, TRUE, FALSE,
4373 EL_EMC_GATE_7_GRAY, -1, -1
4376 Xfake_door_8, TRUE, FALSE,
4377 EL_EMC_GATE_8_GRAY, -1, -1
4380 Xfake_acid_1, TRUE, FALSE,
4381 EL_EMC_FAKE_ACID, -1, -1
4384 Xfake_acid_2, FALSE, FALSE,
4385 EL_EMC_FAKE_ACID, -1, -1
4388 Xfake_acid_3, FALSE, FALSE,
4389 EL_EMC_FAKE_ACID, -1, -1
4392 Xfake_acid_4, FALSE, FALSE,
4393 EL_EMC_FAKE_ACID, -1, -1
4396 Xfake_acid_5, FALSE, FALSE,
4397 EL_EMC_FAKE_ACID, -1, -1
4400 Xfake_acid_6, FALSE, FALSE,
4401 EL_EMC_FAKE_ACID, -1, -1
4404 Xfake_acid_7, FALSE, FALSE,
4405 EL_EMC_FAKE_ACID, -1, -1
4408 Xfake_acid_8, FALSE, FALSE,
4409 EL_EMC_FAKE_ACID, -1, -1
4412 Xsteel_1, TRUE, FALSE,
4413 EL_STEELWALL, -1, -1
4416 Xsteel_2, TRUE, FALSE,
4417 EL_EMC_STEELWALL_2, -1, -1
4420 Xsteel_3, TRUE, FALSE,
4421 EL_EMC_STEELWALL_3, -1, -1
4424 Xsteel_4, TRUE, FALSE,
4425 EL_EMC_STEELWALL_4, -1, -1
4428 Xwall_1, TRUE, FALSE,
4432 Xwall_2, TRUE, FALSE,
4433 EL_EMC_WALL_14, -1, -1
4436 Xwall_3, TRUE, FALSE,
4437 EL_EMC_WALL_15, -1, -1
4440 Xwall_4, TRUE, FALSE,
4441 EL_EMC_WALL_16, -1, -1
4444 Xround_wall_1, TRUE, FALSE,
4445 EL_WALL_SLIPPERY, -1, -1
4448 Xround_wall_2, TRUE, FALSE,
4449 EL_EMC_WALL_SLIPPERY_2, -1, -1
4452 Xround_wall_3, TRUE, FALSE,
4453 EL_EMC_WALL_SLIPPERY_3, -1, -1
4456 Xround_wall_4, TRUE, FALSE,
4457 EL_EMC_WALL_SLIPPERY_4, -1, -1
4460 Xdecor_1, TRUE, FALSE,
4461 EL_EMC_WALL_8, -1, -1
4464 Xdecor_2, TRUE, FALSE,
4465 EL_EMC_WALL_6, -1, -1
4468 Xdecor_3, TRUE, FALSE,
4469 EL_EMC_WALL_4, -1, -1
4472 Xdecor_4, TRUE, FALSE,
4473 EL_EMC_WALL_7, -1, -1
4476 Xdecor_5, TRUE, FALSE,
4477 EL_EMC_WALL_5, -1, -1
4480 Xdecor_6, TRUE, FALSE,
4481 EL_EMC_WALL_9, -1, -1
4484 Xdecor_7, TRUE, FALSE,
4485 EL_EMC_WALL_10, -1, -1
4488 Xdecor_8, TRUE, FALSE,
4489 EL_EMC_WALL_1, -1, -1
4492 Xdecor_9, TRUE, FALSE,
4493 EL_EMC_WALL_2, -1, -1
4496 Xdecor_10, TRUE, FALSE,
4497 EL_EMC_WALL_3, -1, -1
4500 Xdecor_11, TRUE, FALSE,
4501 EL_EMC_WALL_11, -1, -1
4504 Xdecor_12, TRUE, FALSE,
4505 EL_EMC_WALL_12, -1, -1
4508 Xalpha_0, TRUE, FALSE,
4509 EL_CHAR('0'), -1, -1
4512 Xalpha_1, TRUE, FALSE,
4513 EL_CHAR('1'), -1, -1
4516 Xalpha_2, TRUE, FALSE,
4517 EL_CHAR('2'), -1, -1
4520 Xalpha_3, TRUE, FALSE,
4521 EL_CHAR('3'), -1, -1
4524 Xalpha_4, TRUE, FALSE,
4525 EL_CHAR('4'), -1, -1
4528 Xalpha_5, TRUE, FALSE,
4529 EL_CHAR('5'), -1, -1
4532 Xalpha_6, TRUE, FALSE,
4533 EL_CHAR('6'), -1, -1
4536 Xalpha_7, TRUE, FALSE,
4537 EL_CHAR('7'), -1, -1
4540 Xalpha_8, TRUE, FALSE,
4541 EL_CHAR('8'), -1, -1
4544 Xalpha_9, TRUE, FALSE,
4545 EL_CHAR('9'), -1, -1
4548 Xalpha_excla, TRUE, FALSE,
4549 EL_CHAR('!'), -1, -1
4552 Xalpha_quote, TRUE, FALSE,
4553 EL_CHAR('"'), -1, -1
4556 Xalpha_comma, TRUE, FALSE,
4557 EL_CHAR(','), -1, -1
4560 Xalpha_minus, TRUE, FALSE,
4561 EL_CHAR('-'), -1, -1
4564 Xalpha_perio, TRUE, FALSE,
4565 EL_CHAR('.'), -1, -1
4568 Xalpha_colon, TRUE, FALSE,
4569 EL_CHAR(':'), -1, -1
4572 Xalpha_quest, TRUE, FALSE,
4573 EL_CHAR('?'), -1, -1
4576 Xalpha_a, TRUE, FALSE,
4577 EL_CHAR('A'), -1, -1
4580 Xalpha_b, TRUE, FALSE,
4581 EL_CHAR('B'), -1, -1
4584 Xalpha_c, TRUE, FALSE,
4585 EL_CHAR('C'), -1, -1
4588 Xalpha_d, TRUE, FALSE,
4589 EL_CHAR('D'), -1, -1
4592 Xalpha_e, TRUE, FALSE,
4593 EL_CHAR('E'), -1, -1
4596 Xalpha_f, TRUE, FALSE,
4597 EL_CHAR('F'), -1, -1
4600 Xalpha_g, TRUE, FALSE,
4601 EL_CHAR('G'), -1, -1
4604 Xalpha_h, TRUE, FALSE,
4605 EL_CHAR('H'), -1, -1
4608 Xalpha_i, TRUE, FALSE,
4609 EL_CHAR('I'), -1, -1
4612 Xalpha_j, TRUE, FALSE,
4613 EL_CHAR('J'), -1, -1
4616 Xalpha_k, TRUE, FALSE,
4617 EL_CHAR('K'), -1, -1
4620 Xalpha_l, TRUE, FALSE,
4621 EL_CHAR('L'), -1, -1
4624 Xalpha_m, TRUE, FALSE,
4625 EL_CHAR('M'), -1, -1
4628 Xalpha_n, TRUE, FALSE,
4629 EL_CHAR('N'), -1, -1
4632 Xalpha_o, TRUE, FALSE,
4633 EL_CHAR('O'), -1, -1
4636 Xalpha_p, TRUE, FALSE,
4637 EL_CHAR('P'), -1, -1
4640 Xalpha_q, TRUE, FALSE,
4641 EL_CHAR('Q'), -1, -1
4644 Xalpha_r, TRUE, FALSE,
4645 EL_CHAR('R'), -1, -1
4648 Xalpha_s, TRUE, FALSE,
4649 EL_CHAR('S'), -1, -1
4652 Xalpha_t, TRUE, FALSE,
4653 EL_CHAR('T'), -1, -1
4656 Xalpha_u, TRUE, FALSE,
4657 EL_CHAR('U'), -1, -1
4660 Xalpha_v, TRUE, FALSE,
4661 EL_CHAR('V'), -1, -1
4664 Xalpha_w, TRUE, FALSE,
4665 EL_CHAR('W'), -1, -1
4668 Xalpha_x, TRUE, FALSE,
4669 EL_CHAR('X'), -1, -1
4672 Xalpha_y, TRUE, FALSE,
4673 EL_CHAR('Y'), -1, -1
4676 Xalpha_z, TRUE, FALSE,
4677 EL_CHAR('Z'), -1, -1
4680 Xalpha_arrow_e, TRUE, FALSE,
4681 EL_CHAR('>'), -1, -1
4684 Xalpha_arrow_w, TRUE, FALSE,
4685 EL_CHAR('<'), -1, -1
4688 Xalpha_copyr, TRUE, FALSE,
4689 EL_CHAR('©'), -1, -1
4692 Xalpha_copyr, TRUE, FALSE,
4693 EL_CHAR('©'), -1, -1
4697 Xboom_bug, FALSE, FALSE,
4698 EL_BUG, ACTION_EXPLODING, -1
4701 Xboom_bomb, FALSE, FALSE,
4702 EL_BOMB, ACTION_EXPLODING, -1
4705 Xboom_android, FALSE, FALSE,
4706 EL_EMC_ANDROID, ACTION_OTHER, -1
4709 Xboom_1, FALSE, FALSE,
4710 EL_DEFAULT, ACTION_EXPLODING, -1
4713 Xboom_2, FALSE, FALSE,
4714 EL_DEFAULT, ACTION_EXPLODING, -1
4717 Znormal, FALSE, FALSE,
4721 Zdynamite, FALSE, FALSE,
4725 Zplayer, FALSE, FALSE,
4729 ZBORDER, FALSE, FALSE,
4739 static struct Mapping_EM_to_RND_player
4748 em_player_mapping_list[] =
4752 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4756 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4760 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4764 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4768 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4772 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4776 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4780 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4784 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4788 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4792 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4796 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4800 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4804 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4808 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4812 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4816 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4820 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4824 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4828 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4832 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4836 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4840 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4844 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4848 EL_PLAYER_1, ACTION_DEFAULT, -1,
4852 EL_PLAYER_2, ACTION_DEFAULT, -1,
4861 int map_element_RND_to_EM(int element_rnd)
4863 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4864 static boolean mapping_initialized = FALSE;
4866 if (!mapping_initialized)
4870 /* return "Xalpha_quest" for all undefined elements in mapping array */
4871 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4872 mapping_RND_to_EM[i] = Xalpha_quest;
4874 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4875 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4876 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4877 em_object_mapping_list[i].element_em;
4879 mapping_initialized = TRUE;
4882 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4883 return mapping_RND_to_EM[element_rnd];
4885 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4890 int map_element_EM_to_RND(int element_em)
4892 static unsigned short mapping_EM_to_RND[TILE_MAX];
4893 static boolean mapping_initialized = FALSE;
4895 if (!mapping_initialized)
4899 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4900 for (i = 0; i < TILE_MAX; i++)
4901 mapping_EM_to_RND[i] = EL_UNKNOWN;
4903 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4904 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4905 em_object_mapping_list[i].element_rnd;
4907 mapping_initialized = TRUE;
4910 if (element_em >= 0 && element_em < TILE_MAX)
4911 return mapping_EM_to_RND[element_em];
4913 Error(ERR_WARN, "invalid EM level element %d", element_em);
4920 int map_element_RND_to_EM(int element_rnd)
4922 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4923 static boolean mapping_initialized = FALSE;
4930 mapping_RND_to_EM_list[] =
4932 { Xblank, EL_EMPTY },
4933 { Xstone, EL_ROCK },
4935 { Xbug_n, EL_BUG_UP },
4936 { Xbug_e, EL_BUG_RIGHT },
4937 { Xbug_s, EL_BUG_DOWN },
4938 { Xbug_w, EL_BUG_LEFT },
4939 { Xtank_n, EL_SPACESHIP_UP },
4940 { Xtank_e, EL_SPACESHIP_RIGHT },
4941 { Xtank_s, EL_SPACESHIP_DOWN },
4942 { Xtank_w, EL_SPACESHIP_LEFT },
4943 { Xandroid, EL_EMC_ANDROID },
4944 { Xandroid_1_n, EL_EMC_ANDROID_UP },
4945 { Xandroid_1_e, EL_EMC_ANDROID_RIGHT },
4946 { Xandroid_1_w, EL_EMC_ANDROID_LEFT },
4947 { Xandroid_1_s, EL_EMC_ANDROID_DOWN },
4948 { Xspring, EL_SPRING },
4949 { Xeater_n, EL_YAMYAM },
4950 { Xalien, EL_ROBOT },
4951 { Xemerald, EL_EMERALD },
4952 { Xdiamond, EL_DIAMOND },
4953 { Xdrip_fall, EL_AMOEBA_DROP },
4955 { Xballoon, EL_BALLOON },
4956 { Xgrass, EL_EMC_GRASS },
4958 { Xacid_ne, EL_ACID_POOL_TOPRIGHT },
4959 { Xacid_se, EL_ACID_POOL_BOTTOMRIGHT },
4960 { Xacid_s, EL_ACID_POOL_BOTTOM },
4961 { Xacid_sw, EL_ACID_POOL_BOTTOMLEFT },
4962 { Xacid_nw, EL_ACID_POOL_TOPLEFT },
4963 { Xacid_1, EL_ACID },
4964 { Xball_1, EL_EMC_MAGIC_BALL },
4965 { Xgrow_ns, EL_EMC_GROW },
4966 { Xwonderwall, EL_MAGIC_WALL },
4967 { Xamoeba_1, EL_AMOEBA_WET },
4968 { Xdoor_1, EL_EM_GATE_1 },
4969 { Xdoor_2, EL_EM_GATE_2 },
4970 { Xdoor_3, EL_EM_GATE_3 },
4971 { Xdoor_4, EL_EM_GATE_4 },
4972 { Xdoor_5, EL_EMC_GATE_5 },
4973 { Xdoor_6, EL_EMC_GATE_6 },
4974 { Xdoor_7, EL_EMC_GATE_7 },
4975 { Xdoor_8, EL_EMC_GATE_8 },
4976 { Xkey_1, EL_EM_KEY_1 },
4977 { Xkey_2, EL_EM_KEY_2 },
4978 { Xkey_3, EL_EM_KEY_3 },
4979 { Xkey_4, EL_EM_KEY_4 },
4980 { Xkey_5, EL_EMC_KEY_5 },
4981 { Xkey_6, EL_EMC_KEY_6 },
4982 { Xkey_7, EL_EMC_KEY_7 },
4983 { Xkey_8, EL_EMC_KEY_8 },
4984 { Xwind_n, EL_BALLOON_SWITCH_UP },
4985 { Xwind_e, EL_BALLOON_SWITCH_RIGHT },
4986 { Xwind_s, EL_BALLOON_SWITCH_DOWN },
4987 { Xwind_w, EL_BALLOON_SWITCH_LEFT },
4988 { Xwind_nesw, EL_BALLOON_SWITCH_ANY },
4989 { Xwind_stop, EL_BALLOON_SWITCH_NONE },
4990 { Xexit, EL_EXIT_CLOSED },
4991 { Xexit_1, EL_EXIT_OPEN },
4992 { Xdynamite, EL_DYNAMITE },
4993 { Xdynamite_1, EL_DYNAMITE_ACTIVE },
4994 { Xbumper, EL_EMC_BUMPER },
4995 { Xwheel, EL_ROBOT_WHEEL },
4996 { Xswitch, EL_UNKNOWN },
4997 { Xsand, EL_QUICKSAND_EMPTY },
4998 { Xsand_stone, EL_QUICKSAND_FULL },
4999 { Xplant, EL_EMC_PLANT },
5000 { Xlenses, EL_EMC_LENSES },
5001 { Xmagnify, EL_EMC_MAGNIFIER },
5002 { Xdripper, EL_UNKNOWN },
5003 { Xfake_blank, EL_INVISIBLE_WALL },
5004 { Xfake_grass, EL_INVISIBLE_SAND },
5005 { Xfake_door_1, EL_EM_GATE_1_GRAY },
5006 { Xfake_door_2, EL_EM_GATE_2_GRAY },
5007 { Xfake_door_3, EL_EM_GATE_3_GRAY },
5008 { Xfake_door_4, EL_EM_GATE_4_GRAY },
5009 { Xfake_door_5, EL_EMC_GATE_5_GRAY },
5010 { Xfake_door_6, EL_EMC_GATE_6_GRAY },
5011 { Xfake_door_7, EL_EMC_GATE_7_GRAY },
5012 { Xfake_door_8, EL_EMC_GATE_8_GRAY },
5013 { Xsteel_1, EL_STEELWALL },
5014 { Xsteel_2, EL_UNKNOWN },
5015 { Xsteel_3, EL_EMC_STEELWALL_1 },
5016 { Xsteel_4, EL_UNKNOWN },
5017 { Xwall_1, EL_WALL },
5018 { Xwall_2, EL_UNKNOWN },
5019 { Xwall_3, EL_UNKNOWN },
5020 { Xwall_4, EL_UNKNOWN },
5021 { Xround_wall_1, EL_WALL_SLIPPERY },
5022 { Xround_wall_2, EL_UNKNOWN },
5023 { Xround_wall_3, EL_UNKNOWN },
5024 { Xround_wall_4, EL_UNKNOWN },
5025 { Xdecor_1, EL_UNKNOWN },
5026 { Xdecor_2, EL_EMC_WALL_6 },
5027 { Xdecor_3, EL_EMC_WALL_4 },
5028 { Xdecor_4, EL_EMC_WALL_5 },
5029 { Xdecor_5, EL_EMC_WALL_7 },
5030 { Xdecor_6, EL_EMC_WALL_8 },
5031 { Xdecor_7, EL_UNKNOWN },
5032 { Xdecor_8, EL_EMC_WALL_1 },
5033 { Xdecor_9, EL_EMC_WALL_2 },
5034 { Xdecor_10, EL_EMC_WALL_3 },
5035 { Xdecor_11, EL_UNKNOWN },
5036 { Xdecor_12, EL_UNKNOWN },
5037 { Xalpha_0, EL_CHAR('0') },
5038 { Xalpha_1, EL_CHAR('1') },
5039 { Xalpha_2, EL_CHAR('2') },
5040 { Xalpha_3, EL_CHAR('3') },
5041 { Xalpha_4, EL_CHAR('4') },
5042 { Xalpha_5, EL_CHAR('5') },
5043 { Xalpha_6, EL_CHAR('6') },
5044 { Xalpha_7, EL_CHAR('7') },
5045 { Xalpha_8, EL_CHAR('8') },
5046 { Xalpha_9, EL_CHAR('9') },
5047 { Xalpha_excla, EL_CHAR('!') },
5048 { Xalpha_quote, EL_CHAR('"') },
5049 { Xalpha_comma, EL_CHAR(',') },
5050 { Xalpha_minus, EL_CHAR('-') },
5051 { Xalpha_perio, EL_CHAR('.') },
5052 { Xalpha_colon, EL_CHAR(':') },
5053 { Xalpha_quest, EL_CHAR('?') },
5054 { Xalpha_a, EL_CHAR('A') },
5055 { Xalpha_b, EL_CHAR('B') },
5056 { Xalpha_c, EL_CHAR('C') },
5057 { Xalpha_d, EL_CHAR('D') },
5058 { Xalpha_e, EL_CHAR('E') },
5059 { Xalpha_f, EL_CHAR('F') },
5060 { Xalpha_g, EL_CHAR('G') },
5061 { Xalpha_h, EL_CHAR('H') },
5062 { Xalpha_i, EL_CHAR('I') },
5063 { Xalpha_j, EL_CHAR('J') },
5064 { Xalpha_k, EL_CHAR('K') },
5065 { Xalpha_l, EL_CHAR('L') },
5066 { Xalpha_m, EL_CHAR('M') },
5067 { Xalpha_n, EL_CHAR('N') },
5068 { Xalpha_o, EL_CHAR('O') },
5069 { Xalpha_p, EL_CHAR('P') },
5070 { Xalpha_q, EL_CHAR('Q') },
5071 { Xalpha_r, EL_CHAR('R') },
5072 { Xalpha_s, EL_CHAR('S') },
5073 { Xalpha_t, EL_CHAR('T') },
5074 { Xalpha_u, EL_CHAR('U') },
5075 { Xalpha_v, EL_CHAR('V') },
5076 { Xalpha_w, EL_CHAR('W') },
5077 { Xalpha_x, EL_CHAR('X') },
5078 { Xalpha_y, EL_CHAR('Y') },
5079 { Xalpha_z, EL_CHAR('Z') },
5080 { Xalpha_arrow_e, EL_CHAR('>') },
5081 { Xalpha_arrow_w, EL_CHAR('<') },
5082 { Xalpha_copyr, EL_CHAR('©') },
5084 { Zplayer, EL_PLAYER_1 },
5085 { Zplayer, EL_PLAYER_2 },
5086 { Zplayer, EL_PLAYER_3 },
5087 { Zplayer, EL_PLAYER_4 },
5089 { ZBORDER, EL_EMC_LEVEL_BORDER },
5094 if (!mapping_initialized)
5098 /* return "Xalpha_quest" for all undefined elements in mapping array */
5099 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5100 mapping_RND_to_EM[i] = Xalpha_quest;
5102 for (i = 0; mapping_RND_to_EM_list[i].element_rnd != -1; i++)
5103 mapping_RND_to_EM[mapping_RND_to_EM_list[i].element_rnd] =
5104 mapping_RND_to_EM_list[i].element_em;
5106 mapping_initialized = TRUE;
5109 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5110 return mapping_RND_to_EM[element_rnd];
5112 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5117 int map_element_EM_to_RND(int element_em)
5119 static unsigned short mapping_EM_to_RND[TILE_MAX];
5120 static boolean mapping_initialized = FALSE;
5127 em_object_mapping_list[] =
5129 { Xblank, EL_EMPTY },
5130 { Yacid_splash_eB, EL_EMPTY },
5131 { Yacid_splash_wB, EL_EMPTY },
5133 #ifdef EM_ENGINE_BAD_ROLL
5134 { Xstone_force_e, EL_ROCK },
5135 { Xstone_force_w, EL_ROCK },
5136 { Xnut_force_e, EL_NUT },
5137 { Xnut_force_w, EL_NUT },
5138 { Xspring_force_e, EL_SPRING },
5139 { Xspring_force_w, EL_SPRING },
5140 { Xemerald_force_e, EL_EMERALD },
5141 { Xemerald_force_w, EL_EMERALD },
5142 { Xdiamond_force_e, EL_DIAMOND },
5143 { Xdiamond_force_w, EL_DIAMOND },
5144 { Xbomb_force_e, EL_BOMB },
5145 { Xbomb_force_w, EL_BOMB },
5148 { Xstone, EL_ROCK },
5149 { Xstone_pause, EL_ROCK },
5150 { Xstone_fall, EL_ROCK },
5151 { Ystone_s, EL_ROCK },
5152 { Ystone_sB, EL_ROCK },
5153 { Ystone_e, EL_ROCK },
5154 { Ystone_eB, EL_ROCK },
5155 { Ystone_w, EL_ROCK },
5156 { Ystone_wB, EL_ROCK },
5158 { Xnut_pause, EL_NUT },
5159 { Xnut_fall, EL_NUT },
5161 { Ynut_sB, EL_NUT },
5163 { Ynut_eB, EL_NUT },
5165 { Ynut_wB, EL_NUT },
5166 { Xbug_n, EL_BUG_UP },
5167 { Xbug_e, EL_BUG_RIGHT },
5168 { Xbug_s, EL_BUG_DOWN },
5169 { Xbug_w, EL_BUG_LEFT },
5170 { Xbug_gon, EL_BUG_UP },
5171 { Xbug_goe, EL_BUG_RIGHT },
5172 { Xbug_gos, EL_BUG_DOWN },
5173 { Xbug_gow, EL_BUG_LEFT },
5174 { Ybug_n, EL_BUG_UP },
5175 { Ybug_nB, EL_BUG_UP },
5176 { Ybug_e, EL_BUG_RIGHT },
5177 { Ybug_eB, EL_BUG_RIGHT },
5178 { Ybug_s, EL_BUG_DOWN },
5179 { Ybug_sB, EL_BUG_DOWN },
5180 { Ybug_w, EL_BUG_LEFT },
5181 { Ybug_wB, EL_BUG_LEFT },
5182 { Ybug_w_n, EL_BUG_UP },
5183 { Ybug_n_e, EL_BUG_RIGHT },
5184 { Ybug_e_s, EL_BUG_DOWN },
5185 { Ybug_s_w, EL_BUG_LEFT },
5186 { Ybug_e_n, EL_BUG_UP },
5187 { Ybug_s_e, EL_BUG_RIGHT },
5188 { Ybug_w_s, EL_BUG_DOWN },
5189 { Ybug_n_w, EL_BUG_LEFT },
5190 { Ybug_stone, EL_ROCK },
5191 { Ybug_spring, EL_SPRING },
5192 { Xtank_n, EL_SPACESHIP_UP },
5193 { Xtank_e, EL_SPACESHIP_RIGHT },
5194 { Xtank_s, EL_SPACESHIP_DOWN },
5195 { Xtank_w, EL_SPACESHIP_LEFT },
5196 { Xtank_gon, EL_SPACESHIP_UP },
5197 { Xtank_goe, EL_SPACESHIP_RIGHT },
5198 { Xtank_gos, EL_SPACESHIP_DOWN },
5199 { Xtank_gow, EL_SPACESHIP_LEFT },
5200 { Ytank_n, EL_SPACESHIP_UP },
5201 { Ytank_nB, EL_SPACESHIP_UP },
5202 { Ytank_e, EL_SPACESHIP_RIGHT },
5203 { Ytank_eB, EL_SPACESHIP_RIGHT },
5204 { Ytank_s, EL_SPACESHIP_DOWN },
5205 { Ytank_sB, EL_SPACESHIP_DOWN },
5206 { Ytank_w, EL_SPACESHIP_LEFT },
5207 { Ytank_wB, EL_SPACESHIP_LEFT },
5208 { Ytank_w_n, EL_SPACESHIP_UP },
5209 { Ytank_n_e, EL_SPACESHIP_RIGHT },
5210 { Ytank_e_s, EL_SPACESHIP_DOWN },
5211 { Ytank_s_w, EL_SPACESHIP_LEFT },
5212 { Ytank_e_n, EL_SPACESHIP_UP },
5213 { Ytank_s_e, EL_SPACESHIP_RIGHT },
5214 { Ytank_w_s, EL_SPACESHIP_DOWN },
5215 { Ytank_n_w, EL_SPACESHIP_LEFT },
5216 { Ytank_stone, EL_ROCK },
5217 { Ytank_spring, EL_SPRING },
5218 { Xandroid, EL_EMC_ANDROID },
5219 { Xandroid_1_n, EL_EMC_ANDROID_UP },
5220 { Xandroid_2_n, EL_EMC_ANDROID_UP },
5221 { Xandroid_1_e, EL_EMC_ANDROID_RIGHT },
5222 { Xandroid_2_e, EL_EMC_ANDROID_RIGHT },
5223 { Xandroid_1_w, EL_EMC_ANDROID_LEFT },
5224 { Xandroid_2_w, EL_EMC_ANDROID_LEFT },
5225 { Xandroid_1_s, EL_EMC_ANDROID_DOWN },
5226 { Xandroid_2_s, EL_EMC_ANDROID_DOWN },
5227 { Yandroid_n, EL_EMC_ANDROID_UP },
5228 { Yandroid_nB, EL_EMC_ANDROID_UP },
5229 { Yandroid_ne, EL_EMC_ANDROID_RIGHT_UP },
5230 { Yandroid_neB, EL_EMC_ANDROID_RIGHT_UP },
5231 { Yandroid_e, EL_EMC_ANDROID_RIGHT },
5232 { Yandroid_eB, EL_EMC_ANDROID_RIGHT },
5233 { Yandroid_se, EL_EMC_ANDROID_RIGHT_DOWN },
5234 { Yandroid_seB, EL_EMC_ANDROID_RIGHT_DOWN },
5235 { Yandroid_s, EL_EMC_ANDROID_DOWN },
5236 { Yandroid_sB, EL_EMC_ANDROID_DOWN },
5237 { Yandroid_sw, EL_EMC_ANDROID_LEFT_DOWN },
5238 { Yandroid_swB, EL_EMC_ANDROID_LEFT_DOWN },
5239 { Yandroid_w, EL_EMC_ANDROID_LEFT },
5240 { Yandroid_wB, EL_EMC_ANDROID_LEFT },
5241 { Yandroid_nw, EL_EMC_ANDROID_LEFT_UP },
5242 { Yandroid_nwB, EL_EMC_ANDROID_LEFT_UP },
5243 { Xspring, EL_SPRING },
5244 { Xspring_pause, EL_SPRING },
5245 { Xspring_e, EL_SPRING },
5246 { Xspring_w, EL_SPRING },
5247 { Xspring_fall, EL_SPRING },
5248 { Yspring_s, EL_SPRING },
5249 { Yspring_sB, EL_SPRING },
5250 { Yspring_e, EL_SPRING },
5251 { Yspring_eB, EL_SPRING },
5252 { Yspring_w, EL_SPRING },
5253 { Yspring_wB, EL_SPRING },
5254 { Yspring_kill_e, EL_SPRING },
5255 { Yspring_kill_eB, EL_SPRING },
5256 { Yspring_kill_w, EL_SPRING },
5257 { Yspring_kill_wB, EL_SPRING },
5258 { Xeater_n, EL_YAMYAM },
5259 { Xeater_e, EL_YAMYAM },
5260 { Xeater_w, EL_YAMYAM },
5261 { Xeater_s, EL_YAMYAM },
5262 { Yeater_n, EL_YAMYAM },
5263 { Yeater_nB, EL_YAMYAM },
5264 { Yeater_e, EL_YAMYAM },
5265 { Yeater_eB, EL_YAMYAM },
5266 { Yeater_s, EL_YAMYAM },
5267 { Yeater_sB, EL_YAMYAM },
5268 { Yeater_w, EL_YAMYAM },
5269 { Yeater_wB, EL_YAMYAM },
5270 { Yeater_stone, EL_ROCK },
5271 { Yeater_spring, EL_SPRING },
5272 { Xalien, EL_ROBOT },
5273 { Xalien_pause, EL_ROBOT },
5274 { Yalien_n, EL_ROBOT },
5275 { Yalien_nB, EL_ROBOT },
5276 { Yalien_e, EL_ROBOT },
5277 { Yalien_eB, EL_ROBOT },
5278 { Yalien_s, EL_ROBOT },
5279 { Yalien_sB, EL_ROBOT },
5280 { Yalien_w, EL_ROBOT },
5281 { Yalien_wB, EL_ROBOT },
5282 { Yalien_stone, EL_ROCK },
5283 { Yalien_spring, EL_SPRING },
5284 { Xemerald, EL_EMERALD },
5285 { Xemerald_pause, EL_EMERALD },
5286 { Xemerald_fall, EL_EMERALD },
5287 { Xemerald_shine, EL_EMERALD },
5288 { Yemerald_s, EL_EMERALD },
5289 { Yemerald_sB, EL_EMERALD },
5290 { Yemerald_e, EL_EMERALD },
5291 { Yemerald_eB, EL_EMERALD },
5292 { Yemerald_w, EL_EMERALD },
5293 { Yemerald_wB, EL_EMERALD },
5294 { Yemerald_eat, EL_EMERALD },
5295 { Yemerald_stone, EL_ROCK },
5296 { Xdiamond, EL_DIAMOND },
5297 { Xdiamond_pause, EL_DIAMOND },
5298 { Xdiamond_fall, EL_DIAMOND },
5299 { Xdiamond_shine, EL_DIAMOND },
5300 { Ydiamond_s, EL_DIAMOND },
5301 { Ydiamond_sB, EL_DIAMOND },
5302 { Ydiamond_e, EL_DIAMOND },
5303 { Ydiamond_eB, EL_DIAMOND },
5304 { Ydiamond_w, EL_DIAMOND },
5305 { Ydiamond_wB, EL_DIAMOND },
5306 { Ydiamond_eat, EL_DIAMOND },
5307 { Ydiamond_stone, EL_ROCK },
5308 { Xdrip_fall, EL_AMOEBA_DROP },
5309 { Xdrip_stretch, EL_AMOEBA_DROP },
5310 { Xdrip_stretchB, EL_AMOEBA_DROP },
5311 { Xdrip_eat, EL_AMOEBA_DROP },
5312 { Ydrip_s1, EL_AMOEBA_DROP },
5313 { Ydrip_s1B, EL_AMOEBA_DROP },
5314 { Ydrip_s2, EL_AMOEBA_DROP },
5315 { Ydrip_s2B, EL_AMOEBA_DROP },
5317 { Xbomb_pause, EL_BOMB },
5318 { Xbomb_fall, EL_BOMB },
5319 { Ybomb_s, EL_BOMB },
5320 { Ybomb_sB, EL_BOMB },
5321 { Ybomb_e, EL_BOMB },
5322 { Ybomb_eB, EL_BOMB },
5323 { Ybomb_w, EL_BOMB },
5324 { Ybomb_wB, EL_BOMB },
5325 { Ybomb_eat, EL_BOMB },
5326 { Xballoon, EL_BALLOON },
5327 { Yballoon_n, EL_BALLOON },
5328 { Yballoon_nB, EL_BALLOON },
5329 { Yballoon_e, EL_BALLOON },
5330 { Yballoon_eB, EL_BALLOON },
5331 { Yballoon_s, EL_BALLOON },
5332 { Yballoon_sB, EL_BALLOON },
5333 { Yballoon_w, EL_BALLOON },
5334 { Yballoon_wB, EL_BALLOON },
5335 { Xgrass, EL_SAND },
5336 { Ygrass_nB, EL_SAND },
5337 { Ygrass_eB, EL_SAND },
5338 { Ygrass_sB, EL_SAND },
5339 { Ygrass_wB, EL_SAND },
5341 { Ydirt_nB, EL_SAND },
5342 { Ydirt_eB, EL_SAND },
5343 { Ydirt_sB, EL_SAND },
5344 { Ydirt_wB, EL_SAND },
5345 { Xacid_ne, EL_ACID_POOL_TOPRIGHT },
5346 { Xacid_se, EL_ACID_POOL_BOTTOMRIGHT },
5347 { Xacid_s, EL_ACID_POOL_BOTTOM },
5348 { Xacid_sw, EL_ACID_POOL_BOTTOMLEFT },
5349 { Xacid_nw, EL_ACID_POOL_TOPLEFT },
5350 { Xacid_1, EL_ACID },
5351 { Xacid_2, EL_ACID },
5352 { Xacid_3, EL_ACID },
5353 { Xacid_4, EL_ACID },
5354 { Xacid_5, EL_ACID },
5355 { Xacid_6, EL_ACID },
5356 { Xacid_7, EL_ACID },
5357 { Xacid_8, EL_ACID },
5358 { Xball_1, EL_EMC_MAGIC_BALL },
5359 { Xball_1B, EL_EMC_MAGIC_BALL },
5360 { Xball_2, EL_EMC_MAGIC_BALL },
5361 { Xball_2B, EL_EMC_MAGIC_BALL },
5362 { Yball_eat, EL_EMC_MAGIC_BALL },
5363 { Xgrow_ns, EL_EMC_GROW },
5364 { Ygrow_ns_eat, EL_EMC_GROW },
5365 { Xgrow_ew, EL_EMC_GROW },
5366 { Ygrow_ew_eat, EL_EMC_GROW },
5367 { Xwonderwall, EL_MAGIC_WALL },
5368 { XwonderwallB, EL_MAGIC_WALL },
5369 { Xamoeba_1, EL_AMOEBA_WET },
5370 { Xamoeba_2, EL_AMOEBA_WET },
5371 { Xamoeba_3, EL_AMOEBA_WET },
5372 { Xamoeba_4, EL_AMOEBA_WET },
5373 { Xamoeba_5, EL_AMOEBA_WET },
5374 { Xamoeba_6, EL_AMOEBA_WET },
5375 { Xamoeba_7, EL_AMOEBA_WET },
5376 { Xamoeba_8, EL_AMOEBA_WET },
5377 { Xdoor_1, EL_EM_GATE_1 },
5378 { Xdoor_2, EL_EM_GATE_2 },
5379 { Xdoor_3, EL_EM_GATE_3 },
5380 { Xdoor_4, EL_EM_GATE_4 },
5381 { Xdoor_5, EL_EMC_GATE_5 },
5382 { Xdoor_6, EL_EMC_GATE_6 },
5383 { Xdoor_7, EL_EMC_GATE_7 },
5384 { Xdoor_8, EL_EMC_GATE_8 },
5385 { Xkey_1, EL_EM_KEY_1 },
5386 { Xkey_2, EL_EM_KEY_2 },
5387 { Xkey_3, EL_EM_KEY_3 },
5388 { Xkey_4, EL_EM_KEY_4 },
5389 { Xkey_5, EL_EMC_KEY_5 },
5390 { Xkey_6, EL_EMC_KEY_6 },
5391 { Xkey_7, EL_EMC_KEY_7 },
5392 { Xkey_8, EL_EMC_KEY_8 },
5393 { Xwind_n, EL_BALLOON_SWITCH_UP },
5394 { Xwind_e, EL_BALLOON_SWITCH_RIGHT },
5395 { Xwind_s, EL_BALLOON_SWITCH_DOWN },
5396 { Xwind_w, EL_BALLOON_SWITCH_LEFT },
5397 { Xwind_nesw, EL_BALLOON_SWITCH_ANY },
5398 { Xwind_stop, EL_BALLOON_SWITCH_NONE },
5399 { Xexit, EL_EXIT_CLOSED },
5400 { Xexit_1, EL_EXIT_OPEN },
5401 { Xexit_2, EL_EXIT_OPEN },
5402 { Xexit_3, EL_EXIT_OPEN },
5403 { Xdynamite, EL_DYNAMITE },
5404 { Ydynamite_eat, EL_DYNAMITE },
5405 { Xdynamite_1, EL_DYNAMITE_ACTIVE },
5406 { Xdynamite_2, EL_DYNAMITE_ACTIVE },
5407 { Xdynamite_3, EL_DYNAMITE_ACTIVE },
5408 { Xdynamite_4, EL_DYNAMITE_ACTIVE },
5409 { Xbumper, EL_EMC_BUMPER },
5410 { XbumperB, EL_EMC_BUMPER },
5411 { Xwheel, EL_ROBOT_WHEEL },
5412 { XwheelB, EL_ROBOT_WHEEL },
5413 { Xswitch, EL_UNKNOWN },
5414 { XswitchB, EL_UNKNOWN },
5415 { Xsand, EL_QUICKSAND_EMPTY },
5416 { Xsand_stone, EL_QUICKSAND_FULL },
5417 { Xsand_stonein_1, EL_QUICKSAND_FULL },
5418 { Xsand_stonein_2, EL_QUICKSAND_FULL },
5419 { Xsand_stonein_3, EL_QUICKSAND_FULL },
5420 { Xsand_stonein_4, EL_QUICKSAND_FULL },
5421 { Xsand_stonesand_1, EL_QUICKSAND_FULL },
5422 { Xsand_stonesand_2, EL_QUICKSAND_FULL },
5423 { Xsand_stonesand_3, EL_QUICKSAND_FULL },
5424 { Xsand_stonesand_4, EL_QUICKSAND_FULL },
5425 { Xsand_stoneout_1, EL_QUICKSAND_FULL },
5426 { Xsand_stoneout_2, EL_QUICKSAND_FULL },
5427 { Xsand_sandstone_1, EL_QUICKSAND_FULL },
5428 { Xsand_sandstone_2, EL_QUICKSAND_FULL },
5429 { Xsand_sandstone_3, EL_QUICKSAND_FULL },
5430 { Xsand_sandstone_4, EL_QUICKSAND_FULL },
5431 { Xplant, EL_EMC_PLANT },
5432 { Yplant, EL_EMC_PLANT },
5433 { Xlenses, EL_EMC_LENSES },
5434 { Xmagnify, EL_EMC_MAGNIFIER },
5435 { Xdripper, EL_UNKNOWN },
5436 { XdripperB, EL_UNKNOWN },
5437 { Xfake_blank, EL_INVISIBLE_WALL },
5438 { Xfake_blankB, EL_INVISIBLE_WALL },
5439 { Xfake_grass, EL_INVISIBLE_SAND },
5440 { Xfake_grassB, EL_INVISIBLE_SAND },
5441 { Xfake_door_1, EL_EM_GATE_1_GRAY },
5442 { Xfake_door_2, EL_EM_GATE_2_GRAY },
5443 { Xfake_door_3, EL_EM_GATE_3_GRAY },
5444 { Xfake_door_4, EL_EM_GATE_4_GRAY },
5445 { Xfake_door_5, EL_EMC_GATE_5_GRAY },
5446 { Xfake_door_6, EL_EMC_GATE_6_GRAY },
5447 { Xfake_door_7, EL_EMC_GATE_7_GRAY },
5448 { Xfake_door_8, EL_EMC_GATE_8_GRAY },
5449 { Xsteel_1, EL_STEELWALL },
5450 { Xsteel_2, EL_UNKNOWN },
5451 { Xsteel_3, EL_EMC_STEELWALL_1 },
5452 { Xsteel_4, EL_UNKNOWN },
5453 { Xwall_1, EL_WALL },
5454 { Xwall_2, EL_UNKNOWN },
5455 { Xwall_3, EL_UNKNOWN },
5456 { Xwall_4, EL_UNKNOWN },
5457 { Xround_wall_1, EL_WALL_SLIPPERY },
5458 { Xround_wall_2, EL_UNKNOWN },
5459 { Xround_wall_3, EL_UNKNOWN },
5460 { Xround_wall_4, EL_UNKNOWN },
5461 { Xdecor_1, EL_UNKNOWN },
5462 { Xdecor_2, EL_EMC_WALL_6 },
5463 { Xdecor_3, EL_EMC_WALL_4 },
5464 { Xdecor_4, EL_EMC_WALL_5 },
5465 { Xdecor_5, EL_EMC_WALL_7 },
5466 { Xdecor_6, EL_EMC_WALL_8 },
5467 { Xdecor_7, EL_UNKNOWN },
5468 { Xdecor_8, EL_EMC_WALL_1 },
5469 { Xdecor_9, EL_EMC_WALL_2 },
5470 { Xdecor_10, EL_EMC_WALL_3 },
5471 { Xdecor_11, EL_UNKNOWN },
5472 { Xdecor_12, EL_UNKNOWN },
5473 { Xalpha_0, EL_CHAR('0') },
5474 { Xalpha_1, EL_CHAR('1') },
5475 { Xalpha_2, EL_CHAR('2') },
5476 { Xalpha_3, EL_CHAR('3') },
5477 { Xalpha_4, EL_CHAR('4') },
5478 { Xalpha_5, EL_CHAR('5') },
5479 { Xalpha_6, EL_CHAR('6') },
5480 { Xalpha_7, EL_CHAR('7') },
5481 { Xalpha_8, EL_CHAR('8') },
5482 { Xalpha_9, EL_CHAR('9') },
5483 { Xalpha_excla, EL_CHAR('!') },
5484 { Xalpha_quote, EL_CHAR('"') },
5485 { Xalpha_comma, EL_CHAR(',') },
5486 { Xalpha_minus, EL_CHAR('-') },
5487 { Xalpha_perio, EL_CHAR('.') },
5488 { Xalpha_colon, EL_CHAR(':') },
5489 { Xalpha_quest, EL_CHAR('?') },
5490 { Xalpha_a, EL_CHAR('A') },
5491 { Xalpha_b, EL_CHAR('B') },
5492 { Xalpha_c, EL_CHAR('C') },
5493 { Xalpha_d, EL_CHAR('D') },
5494 { Xalpha_e, EL_CHAR('E') },
5495 { Xalpha_f, EL_CHAR('F') },
5496 { Xalpha_g, EL_CHAR('G') },
5497 { Xalpha_h, EL_CHAR('H') },
5498 { Xalpha_i, EL_CHAR('I') },
5499 { Xalpha_j, EL_CHAR('J') },
5500 { Xalpha_k, EL_CHAR('K') },
5501 { Xalpha_l, EL_CHAR('L') },
5502 { Xalpha_m, EL_CHAR('M') },
5503 { Xalpha_n, EL_CHAR('N') },
5504 { Xalpha_o, EL_CHAR('O') },
5505 { Xalpha_p, EL_CHAR('P') },
5506 { Xalpha_q, EL_CHAR('Q') },
5507 { Xalpha_r, EL_CHAR('R') },
5508 { Xalpha_s, EL_CHAR('S') },
5509 { Xalpha_t, EL_CHAR('T') },
5510 { Xalpha_u, EL_CHAR('U') },
5511 { Xalpha_v, EL_CHAR('V') },
5512 { Xalpha_w, EL_CHAR('W') },
5513 { Xalpha_x, EL_CHAR('X') },
5514 { Xalpha_y, EL_CHAR('Y') },
5515 { Xalpha_z, EL_CHAR('Z') },
5516 { Xalpha_arrow_e, EL_CHAR('>') },
5517 { Xalpha_arrow_w, EL_CHAR('<') },
5518 { Xalpha_copyr, EL_CHAR('©') },
5520 { Zplayer, EL_PLAYER_1 },
5522 { ZBORDER, EL_EMC_LEVEL_BORDER },
5527 if (!mapping_initialized)
5531 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5532 for (i = 0; i < TILE_MAX; i++)
5533 mapping_EM_to_RND[i] = EL_UNKNOWN;
5535 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5536 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5537 em_object_mapping_list[i].element_rnd;
5539 mapping_initialized = TRUE;
5542 if (element_em >= 0 && element_em < TILE_MAX)
5543 return mapping_EM_to_RND[element_em];
5545 Error(ERR_WARN, "invalid EM level element %d", element_em);
5552 int get_next_element(int element)
5556 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5557 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5558 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5559 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5560 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5561 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5562 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5564 default: return element;
5569 int el_act_dir2img(int element, int action, int direction)
5571 element = GFX_ELEMENT(element);
5573 if (direction == MV_NO_MOVING)
5574 return element_info[element].graphic[action];
5576 direction = MV_DIR_BIT(direction);
5578 return element_info[element].direction_graphic[action][direction];
5581 int el_act_dir2img(int element, int action, int direction)
5583 element = GFX_ELEMENT(element);
5584 direction = MV_DIR_BIT(direction); /* default: MV_NO_MOVING => MV_DOWN */
5586 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5587 return element_info[element].direction_graphic[action][direction];
5592 static int el_act_dir2crm(int element, int action, int direction)
5594 element = GFX_ELEMENT(element);
5596 if (direction == MV_NO_MOVING)
5597 return element_info[element].crumbled[action];
5599 direction = MV_DIR_BIT(direction);
5601 return element_info[element].direction_crumbled[action][direction];
5604 static int el_act_dir2crm(int element, int action, int direction)
5606 element = GFX_ELEMENT(element);
5607 direction = MV_DIR_BIT(direction); /* default: MV_NO_MOVING => MV_DOWN */
5609 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5610 return element_info[element].direction_crumbled[action][direction];
5614 int el_act2img(int element, int action)
5616 element = GFX_ELEMENT(element);
5618 return element_info[element].graphic[action];
5621 int el_act2crm(int element, int action)
5623 element = GFX_ELEMENT(element);
5625 return element_info[element].crumbled[action];
5628 int el_dir2img(int element, int direction)
5630 element = GFX_ELEMENT(element);
5632 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5635 int el2baseimg(int element)
5637 return element_info[element].graphic[ACTION_DEFAULT];
5640 int el2img(int element)
5642 element = GFX_ELEMENT(element);
5644 return element_info[element].graphic[ACTION_DEFAULT];
5647 int el2edimg(int element)
5649 element = GFX_ELEMENT(element);
5651 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5654 int el2preimg(int element)
5656 element = GFX_ELEMENT(element);
5658 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5661 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5663 int game_frame_delay_value;
5665 game_frame_delay_value =
5666 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5667 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5670 if (tape.playing && tape.warp_forward && !tape.pausing)
5671 game_frame_delay_value = 0;
5673 return game_frame_delay_value;
5676 unsigned int InitRND(long seed)
5678 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5679 return InitEngineRND_EM(seed);
5681 return InitEngineRND(seed);
5684 #define DEBUG_EM_GFX 0
5686 void InitGraphicInfo_EM(void)
5688 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5689 struct Mapping_EM_to_RND_player player_mapping[2][SPR_MAX];
5693 if (graphic_info_em_object[0][0].bitmap == NULL)
5695 /* EM graphics not yet initialized in em_open_all() */
5701 /* always start with reliable default values */
5702 for (i = 0; i < TILE_MAX; i++)
5704 object_mapping[i].element_rnd = EL_UNKNOWN;
5705 object_mapping[i].is_backside = FALSE;
5706 object_mapping[i].action = ACTION_DEFAULT;
5707 object_mapping[i].direction = MV_NO_MOVING;
5710 /* always start with reliable default values */
5711 for (p = 0; p < 2; p++)
5713 for (i = 0; i < SPR_MAX; i++)
5715 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5716 player_mapping[p][i].action = ACTION_DEFAULT;
5717 player_mapping[p][i].direction = MV_NO_MOVING;
5721 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5723 int e = em_object_mapping_list[i].element_em;
5725 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5726 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5728 if (em_object_mapping_list[i].action != -1)
5729 object_mapping[e].action = em_object_mapping_list[i].action;
5731 if (em_object_mapping_list[i].direction != -1)
5732 object_mapping[e].direction = (1 << em_object_mapping_list[i].direction);
5735 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5737 int a = em_player_mapping_list[i].action_em;
5738 int p = em_player_mapping_list[i].player_nr;
5740 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5742 if (em_player_mapping_list[i].action != -1)
5743 player_mapping[p][a].action = em_player_mapping_list[i].action;
5745 if (em_player_mapping_list[i].direction != -1)
5746 player_mapping[p][a].direction =
5747 (1 << em_player_mapping_list[i].direction);
5750 for (i = 0; i < TILE_MAX; i++)
5752 int element = object_mapping[i].element_rnd;
5753 int action = object_mapping[i].action;
5754 int direction = object_mapping[i].direction;
5755 boolean is_backside = object_mapping[i].is_backside;
5756 boolean action_removing = (action == ACTION_DIGGING ||
5757 action == ACTION_SNAPPING ||
5758 action == ACTION_COLLECTING);
5759 boolean action_exploding = ((action == ACTION_EXPLODING ||
5760 action == ACTION_SMASHED_BY_ROCK ||
5761 action == ACTION_SMASHED_BY_SPRING) &&
5762 element != EL_DIAMOND);
5763 boolean action_active = (action == ACTION_ACTIVE);
5764 boolean action_other = (action == ACTION_OTHER);
5766 for (j = 0; j < 8; j++)
5768 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5769 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5771 i == Xdrip_stretch ? element :
5772 i == Xdrip_stretchB ? element :
5773 i == Ydrip_s1 ? element :
5774 i == Ydrip_s1B ? element :
5775 i == Xball_1B ? element :
5776 i == Xball_2 ? element :
5777 i == Xball_2B ? element :
5778 i == Yball_eat ? element :
5779 i == Ykey_1_eat ? element :
5780 i == Ykey_2_eat ? element :
5781 i == Ykey_3_eat ? element :
5782 i == Ykey_4_eat ? element :
5783 i == Ykey_5_eat ? element :
5784 i == Ykey_6_eat ? element :
5785 i == Ykey_7_eat ? element :
5786 i == Ykey_8_eat ? element :
5787 i == Ylenses_eat ? element :
5788 i == Ymagnify_eat ? element :
5789 i == Ygrass_eat ? element :
5790 i == Ydirt_eat ? element :
5791 i == Yspring_kill_e ? EL_SPRING :
5792 i == Yspring_kill_w ? EL_SPRING :
5793 i == Yemerald_stone ? EL_EMERALD :
5794 i == Ydiamond_stone ? EL_ROCK :
5795 i == Xsand_stonein_4 ? EL_EMPTY :
5796 i == Xsand_stoneout_2 ? EL_ROCK :
5797 is_backside ? EL_EMPTY :
5798 action_removing ? EL_EMPTY :
5800 int effective_action = (j < 7 ? action :
5801 i == Xdrip_stretch ? action :
5802 i == Xdrip_stretchB ? action :
5803 i == Ydrip_s1 ? action :
5804 i == Ydrip_s1B ? action :
5805 i == Xball_1B ? action :
5806 i == Xball_2 ? action :
5807 i == Xball_2B ? action :
5808 i == Yball_eat ? action :
5809 i == Ykey_1_eat ? action :
5810 i == Ykey_2_eat ? action :
5811 i == Ykey_3_eat ? action :
5812 i == Ykey_4_eat ? action :
5813 i == Ykey_5_eat ? action :
5814 i == Ykey_6_eat ? action :
5815 i == Ykey_7_eat ? action :
5816 i == Ykey_8_eat ? action :
5817 i == Ylenses_eat ? action :
5818 i == Ymagnify_eat ? action :
5819 i == Ygrass_eat ? action :
5820 i == Ydirt_eat ? action :
5821 i == Xsand_stonein_1 ? action :
5822 i == Xsand_stonein_2 ? action :
5823 i == Xsand_stonein_3 ? action :
5824 i == Xsand_stonein_4 ? action :
5825 i == Xsand_stoneout_1 ? action :
5826 i == Xsand_stoneout_2 ? action :
5827 i == Xboom_android ? ACTION_EXPLODING :
5828 action_exploding ? ACTION_EXPLODING :
5829 action_active ? action :
5830 action_other ? action :
5832 int graphic = (el_act_dir2img(effective_element, effective_action,
5834 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5836 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5837 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5838 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5839 struct GraphicInfo *g = &graphic_info[graphic];
5840 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5843 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5844 boolean special_animation = (action != ACTION_DEFAULT &&
5845 g->anim_frames == 3 &&
5846 g->anim_delay == 2 &&
5847 g->anim_mode & ANIM_LINEAR);
5848 int sync_frame = (i == Xdrip_stretch ? 7 :
5849 i == Xdrip_stretchB ? 7 :
5850 i == Ydrip_s2 ? j + 8 :
5851 i == Ydrip_s2B ? j + 8 :
5860 i == Xfake_acid_1 ? 0 :
5861 i == Xfake_acid_2 ? 10 :
5862 i == Xfake_acid_3 ? 20 :
5863 i == Xfake_acid_4 ? 30 :
5864 i == Xfake_acid_5 ? 40 :
5865 i == Xfake_acid_6 ? 50 :
5866 i == Xfake_acid_7 ? 60 :
5867 i == Xfake_acid_8 ? 70 :
5869 i == Xball_2B ? j + 8 :
5870 i == Yball_eat ? j + 1 :
5871 i == Ykey_1_eat ? j + 1 :
5872 i == Ykey_2_eat ? j + 1 :
5873 i == Ykey_3_eat ? j + 1 :
5874 i == Ykey_4_eat ? j + 1 :
5875 i == Ykey_5_eat ? j + 1 :
5876 i == Ykey_6_eat ? j + 1 :
5877 i == Ykey_7_eat ? j + 1 :
5878 i == Ykey_8_eat ? j + 1 :
5879 i == Ylenses_eat ? j + 1 :
5880 i == Ymagnify_eat ? j + 1 :
5881 i == Ygrass_eat ? j + 1 :
5882 i == Ydirt_eat ? j + 1 :
5883 i == Xamoeba_1 ? 0 :
5884 i == Xamoeba_2 ? 1 :
5885 i == Xamoeba_3 ? 2 :
5886 i == Xamoeba_4 ? 3 :
5887 i == Xamoeba_5 ? 0 :
5888 i == Xamoeba_6 ? 1 :
5889 i == Xamoeba_7 ? 2 :
5890 i == Xamoeba_8 ? 3 :
5891 i == Xexit_2 ? j + 8 :
5892 i == Xexit_3 ? j + 16 :
5893 i == Xdynamite_1 ? 0 :
5894 i == Xdynamite_2 ? 20 :
5895 i == Xdynamite_3 ? 40 :
5896 i == Xdynamite_4 ? 60 :
5897 i == Xsand_stonein_1 ? j + 1 :
5898 i == Xsand_stonein_2 ? j + 9 :
5899 i == Xsand_stonein_3 ? j + 17 :
5900 i == Xsand_stonein_4 ? j + 25 :
5901 i == Xsand_stoneout_1 && j == 0 ? 0 :
5902 i == Xsand_stoneout_1 && j == 1 ? 0 :
5903 i == Xsand_stoneout_1 && j == 2 ? 1 :
5904 i == Xsand_stoneout_1 && j == 3 ? 2 :
5905 i == Xsand_stoneout_1 && j == 4 ? 2 :
5906 i == Xsand_stoneout_1 && j == 5 ? 3 :
5907 i == Xsand_stoneout_1 && j == 6 ? 4 :
5908 i == Xsand_stoneout_1 && j == 7 ? 4 :
5909 i == Xsand_stoneout_2 && j == 0 ? 5 :
5910 i == Xsand_stoneout_2 && j == 1 ? 6 :
5911 i == Xsand_stoneout_2 && j == 2 ? 7 :
5912 i == Xsand_stoneout_2 && j == 3 ? 8 :
5913 i == Xsand_stoneout_2 && j == 4 ? 9 :
5914 i == Xsand_stoneout_2 && j == 5 ? 11 :
5915 i == Xsand_stoneout_2 && j == 6 ? 13 :
5916 i == Xsand_stoneout_2 && j == 7 ? 15 :
5917 i == Xboom_bug && j == 1 ? 2 :
5918 i == Xboom_bug && j == 2 ? 2 :
5919 i == Xboom_bug && j == 3 ? 4 :
5920 i == Xboom_bug && j == 4 ? 4 :
5921 i == Xboom_bug && j == 5 ? 2 :
5922 i == Xboom_bug && j == 6 ? 2 :
5923 i == Xboom_bug && j == 7 ? 0 :
5924 i == Xboom_bomb && j == 1 ? 2 :
5925 i == Xboom_bomb && j == 2 ? 2 :
5926 i == Xboom_bomb && j == 3 ? 4 :
5927 i == Xboom_bomb && j == 4 ? 4 :
5928 i == Xboom_bomb && j == 5 ? 2 :
5929 i == Xboom_bomb && j == 6 ? 2 :
5930 i == Xboom_bomb && j == 7 ? 0 :
5931 i == Xboom_android && j == 7 ? 6 :
5932 i == Xboom_1 && j == 1 ? 2 :
5933 i == Xboom_1 && j == 2 ? 2 :
5934 i == Xboom_1 && j == 3 ? 4 :
5935 i == Xboom_1 && j == 4 ? 4 :
5936 i == Xboom_1 && j == 5 ? 6 :
5937 i == Xboom_1 && j == 6 ? 6 :
5938 i == Xboom_1 && j == 7 ? 8 :
5939 i == Xboom_2 && j == 0 ? 8 :
5940 i == Xboom_2 && j == 1 ? 8 :
5941 i == Xboom_2 && j == 2 ? 10 :
5942 i == Xboom_2 && j == 3 ? 10 :
5943 i == Xboom_2 && j == 4 ? 10 :
5944 i == Xboom_2 && j == 5 ? 12 :
5945 i == Xboom_2 && j == 6 ? 12 :
5946 i == Xboom_2 && j == 7 ? 12 :
5947 special_animation && j == 4 ? 3 :
5948 effective_action != action ? 0 :
5952 Bitmap *debug_bitmap = g_em->bitmap;
5953 int debug_src_x = g_em->src_x;
5954 int debug_src_y = g_em->src_y;
5957 int frame = getAnimationFrame(g->anim_frames,
5960 g->anim_start_frame,
5963 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5964 g->double_movement && is_backside);
5967 g_em->bitmap = src_bitmap;
5968 g_em->src_x = src_x;
5969 g_em->src_y = src_y;
5970 g_em->src_offset_x = 0;
5971 g_em->src_offset_y = 0;
5972 g_em->dst_offset_x = 0;
5973 g_em->dst_offset_y = 0;
5974 g_em->width = TILEX;
5975 g_em->height = TILEY;
5977 g_em->crumbled_bitmap = NULL;
5978 g_em->crumbled_src_x = 0;
5979 g_em->crumbled_src_y = 0;
5980 g_em->crumbled_border_size = 0;
5982 g_em->has_crumbled_graphics = FALSE;
5983 g_em->preserve_background = FALSE;
5987 if (effective_element == EL_EMC_GRASS &&
5988 effective_action == ACTION_DIGGING)
5989 printf("::: %d\n", crumbled);
5993 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5994 printf("::: empty crumbled: %d [%s], %d, %d\n",
5995 effective_element, element_info[effective_element].token_name,
5996 effective_action, direction);
5999 /* if element can be crumbled, but certain action graphics are just empty
6000 space (like snapping sand with the original R'n'D graphics), do not
6001 treat these empty space graphics as crumbled graphics in EMC engine */
6002 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6004 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6006 g_em->has_crumbled_graphics = TRUE;
6007 g_em->crumbled_bitmap = src_bitmap;
6008 g_em->crumbled_src_x = src_x;
6009 g_em->crumbled_src_y = src_y;
6010 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6014 if (!g->double_movement && (effective_action == ACTION_FALLING ||
6015 effective_action == ACTION_MOVING ||
6016 effective_action == ACTION_PUSHING))
6019 (effective_action == ACTION_FALLING ? MV_DOWN : direction);
6020 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6021 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6022 int num_steps = (i == Ydrip_s1 ||
6025 i == Ydrip_s2B ? 16 : 8);
6026 int cx = ABS(dx) * (TILEX / num_steps);
6027 int cy = ABS(dy) * (TILEY / num_steps);
6028 int step_frame = (i == Ydrip_s2 ||
6029 i == Ydrip_s2B ? j + 8 : j) + 1;
6030 int step = (is_backside ? step_frame : num_steps - step_frame);
6032 if (is_backside) /* tile where movement starts */
6034 if (dx < 0 || dy < 0)
6036 g_em->src_offset_x = cx * step;
6037 g_em->src_offset_y = cy * step;
6041 g_em->dst_offset_x = cx * step;
6042 g_em->dst_offset_y = cy * step;
6045 else /* tile where movement ends */
6047 if (dx < 0 || dy < 0)
6049 g_em->dst_offset_x = cx * step;
6050 g_em->dst_offset_y = cy * step;
6054 g_em->src_offset_x = cx * step;
6055 g_em->src_offset_y = cy * step;
6059 g_em->width = TILEX - cx * step;
6060 g_em->height = TILEY - cy * step;
6064 if (effective_action == ACTION_SMASHED_BY_ROCK &&
6065 element_info[effective_element].graphic[effective_action] ==
6066 element_info[effective_element].graphic[ACTION_DEFAULT])
6068 int move_dir = MV_DOWN;
6069 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6070 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6072 int cx = ABS(dx) * (TILEX / num_steps);
6073 int cy = ABS(dy) * (TILEY / num_steps);
6074 int step_frame = j + 1;
6075 int step = (is_backside ? step_frame : num_steps - step_frame);
6077 graphic = (el_act_dir2img(EL_ROCK, ACTION_FALLING, MV_DOWN));
6078 g = &graphic_info[graphic];
6080 frame = getAnimationFrame(g->anim_frames,
6083 g->anim_start_frame,
6085 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6086 g->double_movement && is_backside);
6088 g_em->bitmap = src_bitmap;
6089 g_em->src_x = src_x;
6090 g_em->src_y = src_y;
6091 g_em->src_offset_x = 0;
6092 g_em->src_offset_y = 0;
6093 g_em->dst_offset_x = 0;
6094 g_em->dst_offset_y = 0;
6096 if (is_backside) /* tile where movement starts */
6098 if (dx < 0 || dy < 0)
6100 g_em->src_offset_x = cx * step;
6101 g_em->src_offset_y = cy * step;
6105 g_em->dst_offset_x = cx * step;
6106 g_em->dst_offset_y = cy * step;
6109 else /* tile where movement ends */
6111 if (dx < 0 || dy < 0)
6113 g_em->dst_offset_x = cx * step;
6114 g_em->dst_offset_y = cy * step;
6118 g_em->src_offset_x = cx * step;
6119 g_em->src_offset_y = cy * step;
6123 g_em->width = TILEX - cx * step;
6124 g_em->height = TILEY - cy * step;
6127 printf("::: -> '%s'\n", element_info[effective_element].token_name);
6134 /* create unique graphic identifier to decide if tile must be redrawn */
6135 /* bit 31 - 16 (16 bit): EM style element
6136 bit 15 - 12 ( 4 bit): EM style frame
6137 bit 11 - 6 ( 6 bit): graphic width
6138 bit 5 - 0 ( 6 bit): graphic height */
6139 g_em->unique_identifier =
6140 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
6143 if (g_em->bitmap != debug_bitmap ||
6144 g_em->src_x != debug_src_x ||
6145 g_em->src_y != debug_src_y ||
6146 g_em->src_offset_x != 0 ||
6147 g_em->src_offset_y != 0 ||
6148 g_em->dst_offset_x != 0 ||
6149 g_em->dst_offset_y != 0 ||
6150 g_em->width != TILEX ||
6151 g_em->height != TILEY)
6153 static int last_i = -1;
6161 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6162 i, element, element_info[element].token_name,
6163 element_action_info[effective_action].suffix, direction);
6165 if (element != effective_element)
6166 printf(" [%d ('%s')]",
6168 element_info[effective_element].token_name);
6172 if (g_em->bitmap != debug_bitmap)
6173 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6174 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6176 if (g_em->src_x != debug_src_x ||
6177 g_em->src_y != debug_src_y)
6178 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6179 j, (is_backside ? 'B' : 'F'),
6180 g_em->src_x, g_em->src_y,
6181 g_em->src_x / 32, g_em->src_y / 32,
6182 debug_src_x, debug_src_y,
6183 debug_src_x / 32, debug_src_y / 32);
6185 if (g_em->src_offset_x != 0 ||
6186 g_em->src_offset_y != 0 ||
6187 g_em->dst_offset_x != 0 ||
6188 g_em->dst_offset_y != 0)
6189 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6191 g_em->src_offset_x, g_em->src_offset_y,
6192 g_em->dst_offset_x, g_em->dst_offset_y);
6194 if (g_em->width != TILEX ||
6195 g_em->height != TILEY)
6196 printf(" %d (%d): size %d,%d should be %d,%d\n",
6198 g_em->width, g_em->height, TILEX, TILEY);
6206 for (i = 0; i < TILE_MAX; i++)
6208 for (j = 0; j < 8; j++)
6210 int element = object_mapping[i].element_rnd;
6211 int action = object_mapping[i].action;
6213 if (action == ACTION_SMASHED_BY_ROCK &&
6214 element_info[element].graphic[action] ==
6215 element_info[element].graphic[ACTION_DEFAULT])
6217 /* no separate animation for "smashed by rock" -- use rock instead */
6218 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6219 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[Ystone_s][7 - j];
6221 g_em->bitmap = g_xx->bitmap;
6222 g_em->src_x = g_xx->src_x;
6223 g_em->src_y = g_xx->src_y;
6224 g_em->src_offset_x = g_xx->src_offset_x;
6225 g_em->src_offset_y = g_xx->src_offset_y;
6226 g_em->dst_offset_x = g_xx->dst_offset_x;
6227 g_em->dst_offset_y = g_xx->dst_offset_y;
6228 g_em->width = g_xx->width;
6229 g_em->height = g_xx->height;
6231 g_em->preserve_background = TRUE;
6237 for (p = 0; p < 2; p++)
6239 for (i = 0; i < SPR_MAX; i++)
6241 int element = player_mapping[p][i].element_rnd;
6242 int action = player_mapping[p][i].action;
6243 int direction = player_mapping[p][i].direction;
6245 for (j = 0; j < 8; j++)
6247 int effective_element = element;
6248 int effective_action = action;
6249 int graphic = (direction == MV_NO_MOVING ?
6250 el_act2img(effective_element, effective_action) :
6251 el_act_dir2img(effective_element, effective_action,
6253 struct GraphicInfo *g = &graphic_info[graphic];
6254 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6260 Bitmap *debug_bitmap = g_em->bitmap;
6261 int debug_src_x = g_em->src_x;
6262 int debug_src_y = g_em->src_y;
6265 int frame = getAnimationFrame(g->anim_frames,
6268 g->anim_start_frame,
6271 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6274 g_em->bitmap = src_bitmap;
6275 g_em->src_x = src_x;
6276 g_em->src_y = src_y;
6277 g_em->src_offset_x = 0;
6278 g_em->src_offset_y = 0;
6279 g_em->dst_offset_x = 0;
6280 g_em->dst_offset_y = 0;
6281 g_em->width = TILEX;
6282 g_em->height = TILEY;
6286 if (g_em->bitmap != debug_bitmap ||
6287 g_em->src_x != debug_src_x ||
6288 g_em->src_y != debug_src_y)
6290 static int last_i = -1;
6298 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6299 p, i, element, element_info[element].token_name,
6300 element_action_info[effective_action].suffix, direction);
6302 if (element != effective_element)
6303 printf(" [%d ('%s')]",
6305 element_info[effective_element].token_name);
6309 if (g_em->bitmap != debug_bitmap)
6310 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6311 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6313 if (g_em->src_x != debug_src_x ||
6314 g_em->src_y != debug_src_y)
6315 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6317 g_em->src_x, g_em->src_y,
6318 g_em->src_x / 32, g_em->src_y / 32,
6319 debug_src_x, debug_src_y,
6320 debug_src_x / 32, debug_src_y / 32);