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)
66 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
73 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
76 if (!IN_LEV_FIELD(x, y))
78 printf("(not in level field)\n");
84 printf(" Feld: %d\t['%s']\n", Feld[x][y],
85 element_info[Feld[x][y]].token_name);
86 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
87 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
88 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
89 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
90 printf(" MovPos: %d\n", MovPos[x][y]);
91 printf(" MovDir: %d\n", MovDir[x][y]);
92 printf(" MovDelay: %d\n", MovDelay[x][y]);
93 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
94 printf(" CustomValue: %d\n", CustomValue[x][y]);
95 printf(" GfxElement: %d\n", GfxElement[x][y]);
96 printf(" GfxAction: %d\n", GfxAction[x][y]);
97 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
101 void SetDrawtoField(int mode)
103 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
114 drawto_field = fieldbuffer;
116 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
122 BX2 = SCR_FIELDX - 1;
123 BY2 = SCR_FIELDY - 1;
127 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
131 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
133 if (game_status == GAME_MODE_PLAYING &&
134 level.game_engine_type == GAME_ENGINE_TYPE_EM)
137 RedrawPlayfield_EM(force_redraw);
139 BlitScreenToBitmap_EM(backbuffer);
142 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
148 width = gfx.sxsize + 2 * TILEX;
149 height = gfx.sysize + 2 * TILEY;
152 if (force_redraw || setup.direct_draw)
155 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
156 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
158 if (setup.direct_draw)
159 SetDrawtoField(DRAW_BACKBUFFER);
161 for (xx = BX1; xx <= BX2; xx++)
162 for (yy = BY1; yy <= BY2; yy++)
163 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
164 DrawScreenField(xx, yy);
167 if (setup.direct_draw)
168 SetDrawtoField(DRAW_DIRECT);
171 if (setup.soft_scrolling)
173 int fx = FX, fy = FY;
175 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
176 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
178 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
182 BlitBitmap(drawto, window, x, y, width, height, x, y);
188 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
190 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
191 redraw_mask &= ~REDRAW_MAIN;
193 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
194 redraw_mask |= REDRAW_FIELD;
196 if (redraw_mask & REDRAW_FIELD)
197 redraw_mask &= ~REDRAW_TILES;
199 if (redraw_mask == REDRAW_NONE)
202 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
204 static boolean last_frame_skipped = FALSE;
205 boolean skip_even_when_not_scrolling = TRUE;
206 boolean just_scrolling = (ScreenMovDir != 0);
207 boolean verbose = FALSE;
209 if (global.fps_slowdown_factor > 1 &&
210 (FrameCounter % global.fps_slowdown_factor) &&
211 (just_scrolling || skip_even_when_not_scrolling))
213 redraw_mask &= ~REDRAW_MAIN;
215 last_frame_skipped = TRUE;
218 printf("FRAME SKIPPED\n");
222 if (last_frame_skipped)
223 redraw_mask |= REDRAW_FIELD;
225 last_frame_skipped = FALSE;
228 printf("frame not skipped\n");
232 /* synchronize X11 graphics at this point; if we would synchronize the
233 display immediately after the buffer switching (after the XFlush),
234 this could mean that we have to wait for the graphics to complete,
235 although we could go on doing calculations for the next frame */
239 if (redraw_mask & REDRAW_ALL)
241 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
245 if (redraw_mask & REDRAW_FIELD)
247 if (game_status != GAME_MODE_PLAYING ||
248 redraw_mask & REDRAW_FROM_BACKBUFFER)
250 BlitBitmap(backbuffer, window,
251 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
255 int fx = FX, fy = FY;
257 if (setup.soft_scrolling)
259 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
260 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
263 if (setup.soft_scrolling ||
264 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
265 ABS(ScreenMovPos) == ScrollStepSize ||
266 redraw_tiles > REDRAWTILES_THRESHOLD)
268 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
272 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
274 (setup.soft_scrolling ?
275 "setup.soft_scrolling" :
276 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
277 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
278 ABS(ScreenGfxPos) == ScrollStepSize ?
279 "ABS(ScreenGfxPos) == ScrollStepSize" :
280 "redraw_tiles > REDRAWTILES_THRESHOLD"));
286 redraw_mask &= ~REDRAW_MAIN;
289 if (redraw_mask & REDRAW_DOORS)
291 if (redraw_mask & REDRAW_DOOR_1)
292 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
294 if (redraw_mask & REDRAW_DOOR_2)
295 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
297 if (redraw_mask & REDRAW_DOOR_3)
298 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
300 redraw_mask &= ~REDRAW_DOORS;
303 if (redraw_mask & REDRAW_MICROLEVEL)
305 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
306 SX, SY + 10 * TILEY);
308 redraw_mask &= ~REDRAW_MICROLEVEL;
311 if (redraw_mask & REDRAW_TILES)
313 for (x = 0; x < SCR_FIELDX; x++)
314 for (y = 0 ; y < SCR_FIELDY; y++)
315 if (redraw[redraw_x1 + x][redraw_y1 + y])
316 BlitBitmap(buffer, window,
317 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
318 SX + x * TILEX, SY + y * TILEY);
321 if (redraw_mask & REDRAW_FPS) /* display frames per second */
326 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
327 if (!global.fps_slowdown)
330 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
331 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
336 for (x = 0; x < MAX_BUF_XSIZE; x++)
337 for (y = 0; y < MAX_BUF_YSIZE; y++)
340 redraw_mask = REDRAW_NONE;
346 long fading_delay = 300;
348 if (setup.fading && (redraw_mask & REDRAW_FIELD))
355 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
358 for (i = 0; i < 2 * FULL_SYSIZE; i++)
360 for (y = 0; y < FULL_SYSIZE; y++)
362 BlitBitmap(backbuffer, window,
363 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
371 for (i = 1; i < FULL_SYSIZE; i+=2)
372 BlitBitmap(backbuffer, window,
373 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
379 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
380 BlitBitmapMasked(backbuffer, window,
381 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
386 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
387 BlitBitmapMasked(backbuffer, window,
388 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
393 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
394 BlitBitmapMasked(backbuffer, window,
395 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
400 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
401 BlitBitmapMasked(backbuffer, window,
402 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
407 redraw_mask &= ~REDRAW_MAIN;
414 void SetMainBackgroundImageIfDefined(int graphic)
416 if (graphic_info[graphic].bitmap)
417 SetMainBackgroundImage(graphic);
420 void SetMainBackgroundImage(int graphic)
422 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
423 graphic_info[graphic].bitmap ?
424 graphic_info[graphic].bitmap :
425 graphic_info[IMG_BACKGROUND].bitmap);
428 void SetDoorBackgroundImage(int graphic)
430 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
431 graphic_info[graphic].bitmap ?
432 graphic_info[graphic].bitmap :
433 graphic_info[IMG_BACKGROUND].bitmap);
436 void DrawBackground(int dst_x, int dst_y, int width, int height)
438 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
440 redraw_mask |= REDRAW_FIELD;
445 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
447 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
449 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
450 SetDrawtoField(DRAW_BUFFERED);
453 SetDrawtoField(DRAW_BACKBUFFER);
455 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
457 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
458 SetDrawtoField(DRAW_DIRECT);
462 void MarkTileDirty(int x, int y)
464 int xx = redraw_x1 + x;
465 int yy = redraw_y1 + y;
470 redraw[xx][yy] = TRUE;
471 redraw_mask |= REDRAW_TILES;
474 void SetBorderElement()
478 BorderElement = EL_EMPTY;
480 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
482 for (x = 0; x < lev_fieldx; x++)
484 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
485 BorderElement = EL_STEELWALL;
487 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
493 void SetRandomAnimationValue(int x, int y)
495 gfx.anim_random_frame = GfxRandom[x][y];
498 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
500 /* animation synchronized with global frame counter, not move position */
501 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
502 sync_frame = FrameCounter;
504 return getAnimationFrame(graphic_info[graphic].anim_frames,
505 graphic_info[graphic].anim_delay,
506 graphic_info[graphic].anim_mode,
507 graphic_info[graphic].anim_start_frame,
511 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
512 int *x, int *y, boolean get_backside)
514 struct GraphicInfo *g = &graphic_info[graphic];
515 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
516 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
520 if (g->offset_y == 0) /* frames are ordered horizontally */
522 int max_width = g->anim_frames_per_line * g->width;
523 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
525 *x = pos % max_width;
526 *y = src_y % g->height + pos / max_width * g->height;
528 else if (g->offset_x == 0) /* frames are ordered vertically */
530 int max_height = g->anim_frames_per_line * g->height;
531 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
533 *x = src_x % g->width + pos / max_height * g->width;
534 *y = pos % max_height;
536 else /* frames are ordered diagonally */
538 *x = src_x + frame * g->offset_x;
539 *y = src_y + frame * g->offset_y;
543 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
545 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
548 void DrawGraphic(int x, int y, int graphic, int frame)
551 if (!IN_SCR_FIELD(x, y))
553 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
554 printf("DrawGraphic(): This should never happen!\n");
559 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
563 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
569 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
570 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
573 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
576 if (!IN_SCR_FIELD(x, y))
578 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
579 printf("DrawGraphicThruMask(): This should never happen!\n");
584 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
589 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
595 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
597 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
598 dst_x - src_x, dst_y - src_y);
599 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
602 void DrawMiniGraphic(int x, int y, int graphic)
604 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
605 MarkTileDirty(x / 2, y / 2);
608 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
610 struct GraphicInfo *g = &graphic_info[graphic];
612 int mini_starty = g->bitmap->height * 2 / 3;
615 *x = mini_startx + g->src_x / 2;
616 *y = mini_starty + g->src_y / 2;
619 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
624 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
625 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
628 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
629 int graphic, int frame,
630 int cut_mode, int mask_mode)
635 int width = TILEX, height = TILEY;
638 if (dx || dy) /* shifted graphic */
640 if (x < BX1) /* object enters playfield from the left */
647 else if (x > BX2) /* object enters playfield from the right */
653 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
659 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
661 else if (dx) /* general horizontal movement */
662 MarkTileDirty(x + SIGN(dx), y);
664 if (y < BY1) /* object enters playfield from the top */
666 if (cut_mode==CUT_BELOW) /* object completely above top border */
674 else if (y > BY2) /* object enters playfield from the bottom */
680 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
686 else if (dy > 0 && cut_mode == CUT_ABOVE)
688 if (y == BY2) /* object completely above bottom border */
694 MarkTileDirty(x, y + 1);
695 } /* object leaves playfield to the bottom */
696 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
698 else if (dy) /* general vertical movement */
699 MarkTileDirty(x, y + SIGN(dy));
703 if (!IN_SCR_FIELD(x, y))
705 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
706 printf("DrawGraphicShifted(): This should never happen!\n");
711 if (width > 0 && height > 0)
713 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
718 dst_x = FX + x * TILEX + dx;
719 dst_y = FY + y * TILEY + dy;
721 if (mask_mode == USE_MASKING)
723 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
724 dst_x - src_x, dst_y - src_y);
725 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
729 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
736 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
737 int graphic, int frame,
738 int cut_mode, int mask_mode)
743 int width = TILEX, height = TILEY;
746 int x2 = x + SIGN(dx);
747 int y2 = y + SIGN(dy);
748 int anim_frames = graphic_info[graphic].anim_frames;
749 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
750 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
751 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
753 /* re-calculate animation frame for two-tile movement animation */
754 frame = getGraphicAnimationFrame(graphic, sync_frame);
756 /* check if movement start graphic inside screen area and should be drawn */
757 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
759 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
761 dst_x = FX + x1 * TILEX;
762 dst_y = FY + y1 * TILEY;
764 if (mask_mode == USE_MASKING)
766 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
767 dst_x - src_x, dst_y - src_y);
768 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
772 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
775 MarkTileDirty(x1, y1);
778 /* check if movement end graphic inside screen area and should be drawn */
779 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
781 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
783 dst_x = FX + x2 * TILEX;
784 dst_y = FY + y2 * TILEY;
786 if (mask_mode == USE_MASKING)
788 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
789 dst_x - src_x, dst_y - src_y);
790 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
794 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
797 MarkTileDirty(x2, y2);
801 static void DrawGraphicShifted(int x, int y, int dx, int dy,
802 int graphic, int frame,
803 int cut_mode, int mask_mode)
807 DrawGraphic(x, y, graphic, frame);
812 if (graphic_info[graphic].double_movement) /* EM style movement images */
813 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
815 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
818 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
819 int frame, int cut_mode)
821 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
824 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
825 int cut_mode, int mask_mode)
827 int lx = LEVELX(x), ly = LEVELY(y);
831 if (IN_LEV_FIELD(lx, ly))
833 SetRandomAnimationValue(lx, ly);
835 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
836 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
838 /* do not use double (EM style) movement graphic when not moving */
839 if (graphic_info[graphic].double_movement && !dx && !dy)
841 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
842 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
845 else /* border element */
847 graphic = el2img(element);
848 frame = getGraphicAnimationFrame(graphic, -1);
851 if (element == EL_EXPANDABLE_WALL)
853 boolean left_stopped = FALSE, right_stopped = FALSE;
855 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
857 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
858 right_stopped = TRUE;
860 if (left_stopped && right_stopped)
862 else if (left_stopped)
864 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
865 frame = graphic_info[graphic].anim_frames - 1;
867 else if (right_stopped)
869 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
870 frame = graphic_info[graphic].anim_frames - 1;
875 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
876 else if (mask_mode == USE_MASKING)
877 DrawGraphicThruMask(x, y, graphic, frame);
879 DrawGraphic(x, y, graphic, frame);
882 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
883 int cut_mode, int mask_mode)
885 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
886 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
887 cut_mode, mask_mode);
890 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
893 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
896 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
899 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
902 void DrawLevelElementThruMask(int x, int y, int element)
904 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
907 void DrawLevelFieldThruMask(int x, int y)
909 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
912 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
916 int sx = SCREENX(x), sy = SCREENY(y);
918 int width, height, cx, cy, i;
919 int crumbled_border_size = graphic_info[graphic].border_size;
920 static int xy[4][2] =
928 if (!IN_LEV_FIELD(x, y))
931 element = TILE_GFX_ELEMENT(x, y);
933 /* crumble field itself */
934 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
936 if (!IN_SCR_FIELD(sx, sy))
939 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
941 for (i = 0; i < 4; i++)
943 int xx = x + xy[i][0];
944 int yy = y + xy[i][1];
946 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
949 /* check if neighbour field is of same type */
950 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
953 if (i == 1 || i == 2)
955 width = crumbled_border_size;
957 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
963 height = crumbled_border_size;
965 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
968 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
969 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
972 MarkTileDirty(sx, sy);
974 else /* crumble neighbour fields */
976 for (i = 0; i < 4; i++)
978 int xx = x + xy[i][0];
979 int yy = y + xy[i][1];
980 int sxx = sx + xy[i][0];
981 int syy = sy + xy[i][1];
984 if (!IN_LEV_FIELD(xx, yy) ||
985 !IN_SCR_FIELD(sxx, syy) ||
990 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
994 element = TILE_GFX_ELEMENT(xx, yy);
996 if (!GFX_CRUMBLED(element))
999 if (!IN_LEV_FIELD(xx, yy) ||
1000 !IN_SCR_FIELD(sxx, syy) ||
1001 !GFX_CRUMBLED(Feld[xx][yy]) ||
1007 graphic = el_act2crm(element, ACTION_DEFAULT);
1009 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1011 crumbled_border_size = graphic_info[graphic].border_size;
1013 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1015 if (i == 1 || i == 2)
1017 width = crumbled_border_size;
1019 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1025 height = crumbled_border_size;
1027 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1030 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1031 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1033 MarkTileDirty(sxx, syy);
1038 void DrawLevelFieldCrumbledSand(int x, int y)
1042 if (!IN_LEV_FIELD(x, y))
1047 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1048 GFX_CRUMBLED(GfxElement[x][y]))
1051 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1052 GfxElement[x][y] != EL_UNDEFINED &&
1053 GFX_CRUMBLED(GfxElement[x][y]))
1055 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1062 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1064 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1067 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1070 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1073 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1074 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1075 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1076 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1077 int sx = SCREENX(x), sy = SCREENY(y);
1079 DrawGraphic(sx, sy, graphic1, frame1);
1080 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1083 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1085 int sx = SCREENX(x), sy = SCREENY(y);
1086 static int xy[4][2] =
1095 for (i = 0; i < 4; i++)
1097 int xx = x + xy[i][0];
1098 int yy = y + xy[i][1];
1099 int sxx = sx + xy[i][0];
1100 int syy = sy + xy[i][1];
1102 if (!IN_LEV_FIELD(xx, yy) ||
1103 !IN_SCR_FIELD(sxx, syy) ||
1104 !GFX_CRUMBLED(Feld[xx][yy]) ||
1108 DrawLevelField(xx, yy);
1112 static int getBorderElement(int x, int y)
1116 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1117 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1118 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1119 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1120 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1121 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1122 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1124 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1125 int steel_position = (x == -1 && y == -1 ? 0 :
1126 x == lev_fieldx && y == -1 ? 1 :
1127 x == -1 && y == lev_fieldy ? 2 :
1128 x == lev_fieldx && y == lev_fieldy ? 3 :
1129 x == -1 || x == lev_fieldx ? 4 :
1130 y == -1 || y == lev_fieldy ? 5 : 6);
1132 return border[steel_position][steel_type];
1135 void DrawScreenElement(int x, int y, int element)
1137 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1138 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1141 void DrawLevelElement(int x, int y, int element)
1143 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1144 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1147 void DrawScreenField(int x, int y)
1149 int lx = LEVELX(x), ly = LEVELY(y);
1150 int element, content;
1152 if (!IN_LEV_FIELD(lx, ly))
1154 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1157 element = getBorderElement(lx, ly);
1159 DrawScreenElement(x, y, element);
1163 element = Feld[lx][ly];
1164 content = Store[lx][ly];
1166 if (IS_MOVING(lx, ly))
1168 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1169 boolean cut_mode = NO_CUTTING;
1171 if (element == EL_QUICKSAND_EMPTYING ||
1172 element == EL_MAGIC_WALL_EMPTYING ||
1173 element == EL_BD_MAGIC_WALL_EMPTYING ||
1174 element == EL_AMOEBA_DROPPING)
1175 cut_mode = CUT_ABOVE;
1176 else if (element == EL_QUICKSAND_FILLING ||
1177 element == EL_MAGIC_WALL_FILLING ||
1178 element == EL_BD_MAGIC_WALL_FILLING)
1179 cut_mode = CUT_BELOW;
1181 if (cut_mode == CUT_ABOVE)
1182 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1184 DrawScreenElement(x, y, EL_EMPTY);
1187 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1188 else if (cut_mode == NO_CUTTING)
1189 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1191 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1193 if (content == EL_ACID)
1195 int dir = MovDir[lx][ly];
1196 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1197 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1199 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1202 else if (IS_BLOCKED(lx, ly))
1207 boolean cut_mode = NO_CUTTING;
1208 int element_old, content_old;
1210 Blocked2Moving(lx, ly, &oldx, &oldy);
1213 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1214 MovDir[oldx][oldy] == MV_RIGHT);
1216 element_old = Feld[oldx][oldy];
1217 content_old = Store[oldx][oldy];
1219 if (element_old == EL_QUICKSAND_EMPTYING ||
1220 element_old == EL_MAGIC_WALL_EMPTYING ||
1221 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1222 element_old == EL_AMOEBA_DROPPING)
1223 cut_mode = CUT_ABOVE;
1225 DrawScreenElement(x, y, EL_EMPTY);
1228 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1230 else if (cut_mode == NO_CUTTING)
1231 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1234 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1237 else if (IS_DRAWABLE(element))
1238 DrawScreenElement(x, y, element);
1240 DrawScreenElement(x, y, EL_EMPTY);
1243 void DrawLevelField(int x, int y)
1245 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1246 DrawScreenField(SCREENX(x), SCREENY(y));
1247 else if (IS_MOVING(x, y))
1251 Moving2Blocked(x, y, &newx, &newy);
1252 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1253 DrawScreenField(SCREENX(newx), SCREENY(newy));
1255 else if (IS_BLOCKED(x, y))
1259 Blocked2Moving(x, y, &oldx, &oldy);
1260 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1261 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1265 void DrawMiniElement(int x, int y, int element)
1269 graphic = el2edimg(element);
1270 DrawMiniGraphic(x, y, graphic);
1273 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1275 int x = sx + scroll_x, y = sy + scroll_y;
1277 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1278 DrawMiniElement(sx, sy, EL_EMPTY);
1279 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1280 DrawMiniElement(sx, sy, Feld[x][y]);
1282 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1285 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1286 int x, int y, int xsize, int ysize, int font_nr)
1288 int font_width = getFontWidth(font_nr);
1289 int font_height = getFontHeight(font_nr);
1290 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1293 int dst_x = SX + startx + x * font_width;
1294 int dst_y = SY + starty + y * font_height;
1295 int width = graphic_info[graphic].width;
1296 int height = graphic_info[graphic].height;
1297 int inner_width = MAX(width - 2 * font_width, font_width);
1298 int inner_height = MAX(height - 2 * font_height, font_height);
1299 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1300 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1301 boolean draw_masked = graphic_info[graphic].draw_masked;
1303 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1305 if (src_bitmap == NULL || width < font_width || height < font_height)
1307 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1311 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1312 inner_sx + (x - 1) * font_width % inner_width);
1313 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1314 inner_sy + (y - 1) * font_height % inner_height);
1318 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1319 dst_x - src_x, dst_y - src_y);
1320 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1324 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1328 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1330 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1331 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1332 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1333 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1334 boolean no_delay = (tape.warp_forward);
1335 unsigned long anim_delay = 0;
1336 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1337 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1338 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1339 int font_width = getFontWidth(font_nr);
1340 int font_height = getFontHeight(font_nr);
1341 int max_xsize = level.envelope_xsize[envelope_nr];
1342 int max_ysize = level.envelope_ysize[envelope_nr];
1343 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1344 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1345 int xend = max_xsize;
1346 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1347 int xstep = (xstart < xend ? 1 : 0);
1348 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1351 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1353 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1354 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1355 int sx = (SXSIZE - xsize * font_width) / 2;
1356 int sy = (SYSIZE - ysize * font_height) / 2;
1359 SetDrawtoField(DRAW_BUFFERED);
1361 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1363 SetDrawtoField(DRAW_BACKBUFFER);
1365 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1366 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1368 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1369 level.envelope_text[envelope_nr], font_nr, max_xsize,
1370 xsize - 2, ysize - 2, mask_mode);
1372 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1375 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1379 void ShowEnvelope(int envelope_nr)
1381 int element = EL_ENVELOPE_1 + envelope_nr;
1382 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1383 int sound_opening = element_info[element].sound[ACTION_OPENING];
1384 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1385 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1386 boolean no_delay = (tape.warp_forward);
1387 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1388 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1389 int anim_mode = graphic_info[graphic].anim_mode;
1390 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1391 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1393 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1395 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1397 if (anim_mode == ANIM_DEFAULT)
1398 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1400 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1403 Delay(wait_delay_value);
1405 WaitForEventToContinue();
1407 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1409 if (anim_mode != ANIM_NONE)
1410 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1412 if (anim_mode == ANIM_DEFAULT)
1413 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1415 game.envelope_active = FALSE;
1417 SetDrawtoField(DRAW_BUFFERED);
1419 redraw_mask |= REDRAW_FIELD;
1423 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1425 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1426 int mini_startx = src_bitmap->width * 3 / 4;
1427 int mini_starty = src_bitmap->height * 2 / 3;
1428 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1429 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1431 *bitmap = src_bitmap;
1436 void DrawMicroElement(int xpos, int ypos, int element)
1440 int graphic = el2preimg(element);
1442 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1443 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1451 SetDrawBackgroundMask(REDRAW_NONE);
1454 for (x = BX1; x <= BX2; x++)
1455 for (y = BY1; y <= BY2; y++)
1456 DrawScreenField(x, y);
1458 redraw_mask |= REDRAW_FIELD;
1461 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1465 for (x = 0; x < size_x; x++)
1466 for (y = 0; y < size_y; y++)
1467 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1469 redraw_mask |= REDRAW_FIELD;
1472 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1476 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1478 if (lev_fieldx < STD_LEV_FIELDX)
1479 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1480 if (lev_fieldy < STD_LEV_FIELDY)
1481 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1483 xpos += MICRO_TILEX;
1484 ypos += MICRO_TILEY;
1486 for (x = -1; x <= STD_LEV_FIELDX; x++)
1488 for (y = -1; y <= STD_LEV_FIELDY; y++)
1490 int lx = from_x + x, ly = from_y + y;
1492 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1493 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1494 level.field[lx][ly]);
1495 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1496 && BorderElement != EL_EMPTY)
1497 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1498 getBorderElement(lx, ly));
1502 redraw_mask |= REDRAW_MICROLEVEL;
1505 #define MICROLABEL_EMPTY 0
1506 #define MICROLABEL_LEVEL_NAME 1
1507 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1508 #define MICROLABEL_LEVEL_AUTHOR 3
1509 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1510 #define MICROLABEL_IMPORTED_FROM 5
1511 #define MICROLABEL_IMPORTED_BY_HEAD 6
1512 #define MICROLABEL_IMPORTED_BY 7
1514 static void DrawMicroLevelLabelExt(int mode)
1516 char label_text[MAX_OUTPUT_LINESIZE + 1];
1517 int max_len_label_text;
1518 int font_nr = FONT_TEXT_2;
1521 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1522 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1523 mode == MICROLABEL_IMPORTED_BY_HEAD)
1524 font_nr = FONT_TEXT_3;
1526 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1528 for (i = 0; i < max_len_label_text; i++)
1529 label_text[i] = ' ';
1530 label_text[max_len_label_text] = '\0';
1532 if (strlen(label_text) > 0)
1534 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1535 int lypos = MICROLABEL2_YPOS;
1537 DrawText(lxpos, lypos, label_text, font_nr);
1541 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1542 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1543 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1544 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1545 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1546 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1547 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1548 max_len_label_text);
1549 label_text[max_len_label_text] = '\0';
1551 if (strlen(label_text) > 0)
1553 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1554 int lypos = MICROLABEL2_YPOS;
1556 DrawText(lxpos, lypos, label_text, font_nr);
1559 redraw_mask |= REDRAW_MICROLEVEL;
1562 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1564 static unsigned long scroll_delay = 0;
1565 static unsigned long label_delay = 0;
1566 static int from_x, from_y, scroll_direction;
1567 static int label_state, label_counter;
1568 int last_game_status = game_status; /* save current game status */
1570 /* force PREVIEW font on preview level */
1571 game_status = GAME_MODE_PSEUDO_PREVIEW;
1575 from_x = from_y = 0;
1576 scroll_direction = MV_RIGHT;
1580 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1581 DrawMicroLevelLabelExt(label_state);
1583 /* initialize delay counters */
1584 DelayReached(&scroll_delay, 0);
1585 DelayReached(&label_delay, 0);
1587 if (leveldir_current->name)
1589 char label_text[MAX_OUTPUT_LINESIZE + 1];
1590 int font_nr = FONT_TEXT_1;
1591 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1594 strncpy(label_text, leveldir_current->name, max_len_label_text);
1595 label_text[max_len_label_text] = '\0';
1597 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1598 lypos = SY + MICROLABEL1_YPOS;
1600 DrawText(lxpos, lypos, label_text, font_nr);
1603 game_status = last_game_status; /* restore current game status */
1608 /* scroll micro level, if needed */
1609 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1610 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1612 switch (scroll_direction)
1618 scroll_direction = MV_UP;
1622 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1625 scroll_direction = MV_DOWN;
1632 scroll_direction = MV_RIGHT;
1636 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1639 scroll_direction = MV_LEFT;
1646 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1649 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1650 /* redraw micro level label, if needed */
1651 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1652 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1653 strcmp(level.author, leveldir_current->name) != 0 &&
1654 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1656 int max_label_counter = 23;
1658 if (leveldir_current->imported_from != NULL &&
1659 strlen(leveldir_current->imported_from) > 0)
1660 max_label_counter += 14;
1661 if (leveldir_current->imported_by != NULL &&
1662 strlen(leveldir_current->imported_by) > 0)
1663 max_label_counter += 14;
1665 label_counter = (label_counter + 1) % max_label_counter;
1666 label_state = (label_counter >= 0 && label_counter <= 7 ?
1667 MICROLABEL_LEVEL_NAME :
1668 label_counter >= 9 && label_counter <= 12 ?
1669 MICROLABEL_LEVEL_AUTHOR_HEAD :
1670 label_counter >= 14 && label_counter <= 21 ?
1671 MICROLABEL_LEVEL_AUTHOR :
1672 label_counter >= 23 && label_counter <= 26 ?
1673 MICROLABEL_IMPORTED_FROM_HEAD :
1674 label_counter >= 28 && label_counter <= 35 ?
1675 MICROLABEL_IMPORTED_FROM :
1676 label_counter >= 37 && label_counter <= 40 ?
1677 MICROLABEL_IMPORTED_BY_HEAD :
1678 label_counter >= 42 && label_counter <= 49 ?
1679 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1681 if (leveldir_current->imported_from == NULL &&
1682 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1683 label_state == MICROLABEL_IMPORTED_FROM))
1684 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1685 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1687 DrawMicroLevelLabelExt(label_state);
1690 game_status = last_game_status; /* restore current game status */
1693 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1694 int graphic, int sync_frame, int mask_mode)
1696 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1698 if (mask_mode == USE_MASKING)
1699 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1701 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1704 inline void DrawGraphicAnimation(int x, int y, int graphic)
1706 int lx = LEVELX(x), ly = LEVELY(y);
1708 if (!IN_SCR_FIELD(x, y))
1711 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1712 graphic, GfxFrame[lx][ly], NO_MASKING);
1713 MarkTileDirty(x, y);
1716 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1718 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1721 void DrawLevelElementAnimation(int x, int y, int element)
1723 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1725 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1728 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1730 int sx = SCREENX(x), sy = SCREENY(y);
1732 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1735 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1738 DrawGraphicAnimation(sx, sy, graphic);
1741 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1742 DrawLevelFieldCrumbledSand(x, y);
1744 if (GFX_CRUMBLED(Feld[x][y]))
1745 DrawLevelFieldCrumbledSand(x, y);
1749 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1751 int sx = SCREENX(x), sy = SCREENY(y);
1754 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1757 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1759 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1762 DrawGraphicAnimation(sx, sy, graphic);
1764 if (GFX_CRUMBLED(element))
1765 DrawLevelFieldCrumbledSand(x, y);
1768 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1770 if (player->use_murphy)
1772 /* this works only because currently only one player can be "murphy" ... */
1773 static int last_horizontal_dir = MV_LEFT;
1774 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1776 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1777 last_horizontal_dir = move_dir;
1779 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1781 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1783 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1789 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1792 static boolean equalGraphics(int graphic1, int graphic2)
1794 struct GraphicInfo *g1 = &graphic_info[graphic1];
1795 struct GraphicInfo *g2 = &graphic_info[graphic2];
1797 return (g1->bitmap == g2->bitmap &&
1798 g1->src_x == g2->src_x &&
1799 g1->src_y == g2->src_y &&
1800 g1->anim_frames == g2->anim_frames &&
1801 g1->anim_delay == g2->anim_delay &&
1802 g1->anim_mode == g2->anim_mode);
1805 void DrawAllPlayers()
1809 for (i = 0; i < MAX_PLAYERS; i++)
1810 if (stored_player[i].active)
1811 DrawPlayer(&stored_player[i]);
1814 void DrawPlayerField(int x, int y)
1816 if (!IS_PLAYER(x, y))
1819 DrawPlayer(PLAYERINFO(x, y));
1822 void DrawPlayer(struct PlayerInfo *player)
1824 int jx = player->jx;
1825 int jy = player->jy;
1826 int move_dir = player->MovDir;
1827 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1828 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1829 int last_jx = (player->is_moving ? jx - dx : jx);
1830 int last_jy = (player->is_moving ? jy - dy : jy);
1831 int next_jx = jx + dx;
1832 int next_jy = jy + dy;
1833 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1834 boolean player_is_opaque = FALSE;
1835 int sx = SCREENX(jx), sy = SCREENY(jy);
1836 int sxx = 0, syy = 0;
1837 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1839 int action = ACTION_DEFAULT;
1840 int last_player_graphic = getPlayerGraphic(player, move_dir);
1841 int last_player_frame = player->Frame;
1845 /* GfxElement[][] is set to the element the player is digging or collecting;
1846 remove also for off-screen player if the player is not moving anymore */
1847 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1848 GfxElement[jx][jy] = EL_UNDEFINED;
1851 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1855 if (!IN_LEV_FIELD(jx, jy))
1857 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1858 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1859 printf("DrawPlayerField(): This should never happen!\n");
1864 if (element == EL_EXPLOSION)
1867 action = (player->is_pushing ? ACTION_PUSHING :
1868 player->is_digging ? ACTION_DIGGING :
1869 player->is_collecting ? ACTION_COLLECTING :
1870 player->is_moving ? ACTION_MOVING :
1871 player->is_snapping ? ACTION_SNAPPING :
1872 player->is_dropping ? ACTION_DROPPING :
1873 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1876 if (player->is_waiting)
1877 move_dir = player->dir_waiting;
1880 InitPlayerGfxAnimation(player, action, move_dir);
1882 /* ----------------------------------------------------------------------- */
1883 /* draw things in the field the player is leaving, if needed */
1884 /* ----------------------------------------------------------------------- */
1886 if (player->is_moving)
1888 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1890 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1892 if (last_element == EL_DYNAMITE_ACTIVE ||
1893 last_element == EL_EM_DYNAMITE_ACTIVE ||
1894 last_element == EL_SP_DISK_RED_ACTIVE)
1895 DrawDynamite(last_jx, last_jy);
1897 DrawLevelFieldThruMask(last_jx, last_jy);
1899 else if (last_element == EL_DYNAMITE_ACTIVE ||
1900 last_element == EL_EM_DYNAMITE_ACTIVE ||
1901 last_element == EL_SP_DISK_RED_ACTIVE)
1902 DrawDynamite(last_jx, last_jy);
1904 DrawLevelField(last_jx, last_jy);
1906 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1907 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1910 if (!IN_SCR_FIELD(sx, sy))
1913 if (setup.direct_draw)
1914 SetDrawtoField(DRAW_BUFFERED);
1916 /* ----------------------------------------------------------------------- */
1917 /* draw things behind the player, if needed */
1918 /* ----------------------------------------------------------------------- */
1921 DrawLevelElement(jx, jy, Back[jx][jy]);
1922 else if (IS_ACTIVE_BOMB(element))
1923 DrawLevelElement(jx, jy, EL_EMPTY);
1926 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1928 int old_element = GfxElement[jx][jy];
1929 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1930 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1932 if (GFX_CRUMBLED(old_element))
1933 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1935 DrawGraphic(sx, sy, old_graphic, frame);
1937 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
1938 player_is_opaque = TRUE;
1942 GfxElement[jx][jy] = EL_UNDEFINED;
1944 /* make sure that pushed elements are drawn with correct frame rate */
1945 if (player->is_pushing && player->is_moving)
1946 GfxFrame[jx][jy] = player->StepFrame;
1948 DrawLevelField(jx, jy);
1952 /* ----------------------------------------------------------------------- */
1953 /* draw player himself */
1954 /* ----------------------------------------------------------------------- */
1956 graphic = getPlayerGraphic(player, move_dir);
1958 /* in the case of changed player action or direction, prevent the current
1959 animation frame from being restarted for identical animations */
1960 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1961 player->Frame = last_player_frame;
1963 frame = getGraphicAnimationFrame(graphic, player->Frame);
1967 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1968 sxx = player->GfxPos;
1970 syy = player->GfxPos;
1973 if (!setup.soft_scrolling && ScreenMovPos)
1976 if (player_is_opaque)
1977 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
1979 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1981 if (SHIELD_ON(player))
1983 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1984 IMG_SHIELD_NORMAL_ACTIVE);
1985 int frame = getGraphicAnimationFrame(graphic, -1);
1987 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1990 /* ----------------------------------------------------------------------- */
1991 /* draw things the player is pushing, if needed */
1992 /* ----------------------------------------------------------------------- */
1995 printf("::: %d, %d [%d, %d] [%d]\n",
1996 player->is_pushing, player_is_moving, player->GfxAction,
1997 player->is_moving, player_is_moving);
2001 if (player->is_pushing && player->is_moving)
2003 int px = SCREENX(jx), py = SCREENY(jy);
2004 int pxx = (TILEX - ABS(sxx)) * dx;
2005 int pyy = (TILEY - ABS(syy)) * dy;
2010 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2011 element = Feld[next_jx][next_jy];
2013 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2014 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2016 /* draw background element under pushed element (like the Sokoban field) */
2017 if (Back[next_jx][next_jy])
2018 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2020 /* masked drawing is needed for EMC style (double) movement graphics */
2021 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2025 /* ----------------------------------------------------------------------- */
2026 /* draw things in front of player (active dynamite or dynabombs) */
2027 /* ----------------------------------------------------------------------- */
2029 if (IS_ACTIVE_BOMB(element))
2031 graphic = el2img(element);
2032 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2034 if (game.emulation == EMU_SUPAPLEX)
2035 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2037 DrawGraphicThruMask(sx, sy, graphic, frame);
2040 if (player_is_moving && last_element == EL_EXPLOSION)
2042 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2043 GfxElement[last_jx][last_jy] : EL_EMPTY);
2044 int graphic = el_act2img(element, ACTION_EXPLODING);
2045 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2046 int phase = ExplodePhase[last_jx][last_jy] - 1;
2047 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2050 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2053 /* ----------------------------------------------------------------------- */
2054 /* draw elements the player is just walking/passing through/under */
2055 /* ----------------------------------------------------------------------- */
2057 if (player_is_moving)
2059 /* handle the field the player is leaving ... */
2060 if (IS_ACCESSIBLE_INSIDE(last_element))
2061 DrawLevelField(last_jx, last_jy);
2062 else if (IS_ACCESSIBLE_UNDER(last_element))
2063 DrawLevelFieldThruMask(last_jx, last_jy);
2066 /* do not redraw accessible elements if the player is just pushing them */
2067 if (!player_is_moving || !player->is_pushing)
2069 /* ... and the field the player is entering */
2070 if (IS_ACCESSIBLE_INSIDE(element))
2071 DrawLevelField(jx, jy);
2072 else if (IS_ACCESSIBLE_UNDER(element))
2073 DrawLevelFieldThruMask(jx, jy);
2076 if (setup.direct_draw)
2078 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2079 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2080 int x_size = TILEX * (1 + ABS(jx - last_jx));
2081 int y_size = TILEY * (1 + ABS(jy - last_jy));
2083 BlitBitmap(drawto_field, window,
2084 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2085 SetDrawtoField(DRAW_DIRECT);
2088 MarkTileDirty(sx, sy);
2091 /* ------------------------------------------------------------------------- */
2093 void WaitForEventToContinue()
2095 boolean still_wait = TRUE;
2097 /* simulate releasing mouse button over last gadget, if still pressed */
2099 HandleGadgets(-1, -1, 0);
2101 button_status = MB_RELEASED;
2113 case EVENT_BUTTONPRESS:
2114 case EVENT_KEYPRESS:
2118 case EVENT_KEYRELEASE:
2119 ClearPlayerAction();
2123 HandleOtherEvents(&event);
2127 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2134 /* don't eat all CPU time */
2139 #define MAX_REQUEST_LINES 13
2140 #define MAX_REQUEST_LINE_FONT1_LEN 7
2141 #define MAX_REQUEST_LINE_FONT2_LEN 10
2143 boolean Request(char *text, unsigned int req_state)
2145 int mx, my, ty, result = -1;
2146 unsigned int old_door_state;
2147 int last_game_status = game_status; /* save current game status */
2148 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2149 int font_nr = FONT_TEXT_2;
2150 int max_word_len = 0;
2153 for (text_ptr = text; *text_ptr; text_ptr++)
2155 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2157 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2159 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2160 font_nr = FONT_LEVEL_NUMBER;
2166 if (game_status == GAME_MODE_PLAYING &&
2167 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2168 BlitScreenToBitmap_EM(backbuffer);
2170 /* disable deactivated drawing when quick-loading level tape recording */
2171 if (tape.playing && tape.deactivate_display)
2172 TapeDeactivateDisplayOff(TRUE);
2174 SetMouseCursor(CURSOR_DEFAULT);
2176 #if defined(NETWORK_AVALIABLE)
2177 /* pause network game while waiting for request to answer */
2178 if (options.network &&
2179 game_status == GAME_MODE_PLAYING &&
2180 req_state & REQUEST_WAIT_FOR_INPUT)
2181 SendToServer_PausePlaying();
2184 old_door_state = GetDoorState();
2186 /* simulate releasing mouse button over last gadget, if still pressed */
2188 HandleGadgets(-1, -1, 0);
2192 if (old_door_state & DOOR_OPEN_1)
2194 CloseDoor(DOOR_CLOSE_1);
2196 /* save old door content */
2197 BlitBitmap(bitmap_db_door, bitmap_db_door,
2198 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2199 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2202 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2204 /* clear door drawing field */
2205 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2207 /* force DOOR font on preview level */
2208 game_status = GAME_MODE_PSEUDO_DOOR;
2210 /* write text for request */
2211 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2213 char text_line[max_request_line_len + 1];
2219 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2222 if (!tc || tc == ' ')
2233 strncpy(text_line, text, tl);
2236 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2237 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2238 text_line, font_nr);
2240 text += tl + (tc == ' ' ? 1 : 0);
2243 game_status = last_game_status; /* restore current game status */
2245 if (req_state & REQ_ASK)
2247 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2248 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2250 else if (req_state & REQ_CONFIRM)
2252 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2254 else if (req_state & REQ_PLAYER)
2256 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2257 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2258 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2259 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2262 /* copy request gadgets to door backbuffer */
2263 BlitBitmap(drawto, bitmap_db_door,
2264 DX, DY, DXSIZE, DYSIZE,
2265 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2267 OpenDoor(DOOR_OPEN_1);
2269 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2271 SetDrawBackgroundMask(REDRAW_FIELD);
2276 if (game_status != GAME_MODE_MAIN)
2279 button_status = MB_RELEASED;
2281 request_gadget_id = -1;
2283 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2295 case EVENT_BUTTONPRESS:
2296 case EVENT_BUTTONRELEASE:
2297 case EVENT_MOTIONNOTIFY:
2299 if (event.type == EVENT_MOTIONNOTIFY)
2301 if (!PointerInWindow(window))
2302 continue; /* window and pointer are on different screens */
2307 motion_status = TRUE;
2308 mx = ((MotionEvent *) &event)->x;
2309 my = ((MotionEvent *) &event)->y;
2313 motion_status = FALSE;
2314 mx = ((ButtonEvent *) &event)->x;
2315 my = ((ButtonEvent *) &event)->y;
2316 if (event.type == EVENT_BUTTONPRESS)
2317 button_status = ((ButtonEvent *) &event)->button;
2319 button_status = MB_RELEASED;
2322 /* this sets 'request_gadget_id' */
2323 HandleGadgets(mx, my, button_status);
2325 switch(request_gadget_id)
2327 case TOOL_CTRL_ID_YES:
2330 case TOOL_CTRL_ID_NO:
2333 case TOOL_CTRL_ID_CONFIRM:
2334 result = TRUE | FALSE;
2337 case TOOL_CTRL_ID_PLAYER_1:
2340 case TOOL_CTRL_ID_PLAYER_2:
2343 case TOOL_CTRL_ID_PLAYER_3:
2346 case TOOL_CTRL_ID_PLAYER_4:
2357 case EVENT_KEYPRESS:
2358 switch(GetEventKey((KeyEvent *)&event, TRUE))
2371 if (req_state & REQ_PLAYER)
2375 case EVENT_KEYRELEASE:
2376 ClearPlayerAction();
2380 HandleOtherEvents(&event);
2384 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2386 int joy = AnyJoystick();
2388 if (joy & JOY_BUTTON_1)
2390 else if (joy & JOY_BUTTON_2)
2396 /* don't eat all CPU time */
2400 if (game_status != GAME_MODE_MAIN)
2405 if (!(req_state & REQ_STAY_OPEN))
2407 CloseDoor(DOOR_CLOSE_1);
2409 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2410 (req_state & REQ_REOPEN))
2411 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2416 SetDrawBackgroundMask(REDRAW_FIELD);
2418 #if defined(NETWORK_AVALIABLE)
2419 /* continue network game after request */
2420 if (options.network &&
2421 game_status == GAME_MODE_PLAYING &&
2422 req_state & REQUEST_WAIT_FOR_INPUT)
2423 SendToServer_ContinuePlaying();
2426 /* restore deactivated drawing when quick-loading level tape recording */
2427 if (tape.playing && tape.deactivate_display)
2428 TapeDeactivateDisplayOn();
2433 unsigned int OpenDoor(unsigned int door_state)
2435 if (door_state & DOOR_COPY_BACK)
2437 if (door_state & DOOR_OPEN_1)
2438 BlitBitmap(bitmap_db_door, bitmap_db_door,
2439 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2440 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2442 if (door_state & DOOR_OPEN_2)
2443 BlitBitmap(bitmap_db_door, bitmap_db_door,
2444 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2445 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2447 door_state &= ~DOOR_COPY_BACK;
2450 return MoveDoor(door_state);
2453 unsigned int CloseDoor(unsigned int door_state)
2455 unsigned int old_door_state = GetDoorState();
2457 if (!(door_state & DOOR_NO_COPY_BACK))
2459 if (old_door_state & DOOR_OPEN_1)
2460 BlitBitmap(backbuffer, bitmap_db_door,
2461 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2463 if (old_door_state & DOOR_OPEN_2)
2464 BlitBitmap(backbuffer, bitmap_db_door,
2465 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2467 door_state &= ~DOOR_NO_COPY_BACK;
2470 return MoveDoor(door_state);
2473 unsigned int GetDoorState()
2475 return MoveDoor(DOOR_GET_STATE);
2478 unsigned int SetDoorState(unsigned int door_state)
2480 return MoveDoor(door_state | DOOR_SET_STATE);
2483 unsigned int MoveDoor(unsigned int door_state)
2485 static int door1 = DOOR_OPEN_1;
2486 static int door2 = DOOR_CLOSE_2;
2487 unsigned long door_delay = 0;
2488 unsigned long door_delay_value;
2491 if (door_1.width < 0 || door_1.width > DXSIZE)
2492 door_1.width = DXSIZE;
2493 if (door_1.height < 0 || door_1.height > DYSIZE)
2494 door_1.height = DYSIZE;
2495 if (door_2.width < 0 || door_2.width > VXSIZE)
2496 door_2.width = VXSIZE;
2497 if (door_2.height < 0 || door_2.height > VYSIZE)
2498 door_2.height = VYSIZE;
2500 if (door_state == DOOR_GET_STATE)
2501 return(door1 | door2);
2503 if (door_state & DOOR_SET_STATE)
2505 if (door_state & DOOR_ACTION_1)
2506 door1 = door_state & DOOR_ACTION_1;
2507 if (door_state & DOOR_ACTION_2)
2508 door2 = door_state & DOOR_ACTION_2;
2510 return(door1 | door2);
2513 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2514 door_state &= ~DOOR_OPEN_1;
2515 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2516 door_state &= ~DOOR_CLOSE_1;
2517 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2518 door_state &= ~DOOR_OPEN_2;
2519 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2520 door_state &= ~DOOR_CLOSE_2;
2522 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2525 if (setup.quick_doors)
2527 stepsize = 20; /* must be choosen to always draw last frame */
2528 door_delay_value = 0;
2531 if (global.autoplay_leveldir)
2533 door_state |= DOOR_NO_DELAY;
2534 door_state &= ~DOOR_CLOSE_ALL;
2537 if (door_state & DOOR_ACTION)
2539 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2540 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2541 boolean door_1_done = (!handle_door_1);
2542 boolean door_2_done = (!handle_door_2);
2543 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2544 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2545 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2546 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2547 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2548 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2549 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2550 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2551 int door_skip = max_door_size - door_size;
2553 int end = door_size;
2555 int end = (door_state & DOOR_ACTION_1 &&
2556 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2559 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2561 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2565 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2567 /* opening door sound has priority over simultaneously closing door */
2568 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2569 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2570 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2571 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2574 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2577 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2578 GC gc = bitmap->stored_clip_gc;
2580 if (door_state & DOOR_ACTION_1)
2582 int a = MIN(x * door_1.step_offset, end);
2583 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2584 int i = p + door_skip;
2586 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2588 BlitBitmap(bitmap_db_door, drawto,
2589 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2590 DXSIZE, DYSIZE, DX, DY);
2594 BlitBitmap(bitmap_db_door, drawto,
2595 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2596 DXSIZE, DYSIZE - p / 2, DX, DY);
2598 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2601 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2603 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2604 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2605 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2606 int dst2_x = DX, dst2_y = DY;
2607 int width = i, height = DYSIZE;
2609 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2610 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2613 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2614 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2617 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2619 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2620 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2621 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2622 int dst2_x = DX, dst2_y = DY;
2623 int width = DXSIZE, height = i;
2625 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2626 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2629 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2630 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2633 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2635 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2637 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2638 BlitBitmapMasked(bitmap, drawto,
2639 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2640 DX + DXSIZE - i, DY + j);
2641 BlitBitmapMasked(bitmap, drawto,
2642 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2643 DX + DXSIZE - i, DY + 140 + j);
2644 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2645 DY - (DOOR_GFX_PAGEY1 + j));
2646 BlitBitmapMasked(bitmap, drawto,
2647 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2649 BlitBitmapMasked(bitmap, drawto,
2650 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2653 BlitBitmapMasked(bitmap, drawto,
2654 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2656 BlitBitmapMasked(bitmap, drawto,
2657 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2659 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2660 BlitBitmapMasked(bitmap, drawto,
2661 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2662 DX + DXSIZE - i, DY + 77 + j);
2663 BlitBitmapMasked(bitmap, drawto,
2664 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2665 DX + DXSIZE - i, DY + 203 + j);
2668 redraw_mask |= REDRAW_DOOR_1;
2669 door_1_done = (a == end);
2672 if (door_state & DOOR_ACTION_2)
2674 int a = MIN(x * door_2.step_offset, door_size_2);
2675 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2676 int i = p + door_skip;
2678 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2680 BlitBitmap(bitmap_db_door, drawto,
2681 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2682 VXSIZE, VYSIZE, VX, VY);
2684 else if (x <= VYSIZE)
2686 BlitBitmap(bitmap_db_door, drawto,
2687 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2688 VXSIZE, VYSIZE - p / 2, VX, VY);
2690 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2693 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2695 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2696 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2697 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2698 int dst2_x = VX, dst2_y = VY;
2699 int width = i, height = VYSIZE;
2701 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2702 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2705 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2706 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2709 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2711 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2712 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2713 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2714 int dst2_x = VX, dst2_y = VY;
2715 int width = VXSIZE, height = i;
2717 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2718 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2721 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2722 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2725 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2727 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2729 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2730 BlitBitmapMasked(bitmap, drawto,
2731 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2732 VX + VXSIZE - i, VY + j);
2733 SetClipOrigin(bitmap, gc,
2734 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2735 BlitBitmapMasked(bitmap, drawto,
2736 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2739 BlitBitmapMasked(bitmap, drawto,
2740 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2741 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2742 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2743 BlitBitmapMasked(bitmap, drawto,
2744 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2746 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2749 redraw_mask |= REDRAW_DOOR_2;
2750 door_2_done = (a == VXSIZE);
2755 if (game_status == GAME_MODE_MAIN)
2758 if (!(door_state & DOOR_NO_DELAY))
2759 WaitUntilDelayReached(&door_delay, door_delay_value);
2763 if (door_state & DOOR_ACTION_1)
2764 door1 = door_state & DOOR_ACTION_1;
2765 if (door_state & DOOR_ACTION_2)
2766 door2 = door_state & DOOR_ACTION_2;
2768 return (door1 | door2);
2771 void DrawSpecialEditorDoor()
2773 /* draw bigger toolbox window */
2774 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2775 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2777 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2778 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2781 redraw_mask |= REDRAW_ALL;
2784 void UndrawSpecialEditorDoor()
2786 /* draw normal tape recorder window */
2787 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2788 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2791 redraw_mask |= REDRAW_ALL;
2795 /* ---------- new tool button stuff ---------------------------------------- */
2797 /* graphic position values for tool buttons */
2798 #define TOOL_BUTTON_YES_XPOS 2
2799 #define TOOL_BUTTON_YES_YPOS 250
2800 #define TOOL_BUTTON_YES_GFX_YPOS 0
2801 #define TOOL_BUTTON_YES_XSIZE 46
2802 #define TOOL_BUTTON_YES_YSIZE 28
2803 #define TOOL_BUTTON_NO_XPOS 52
2804 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2805 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2806 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2807 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2808 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2809 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2810 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2811 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2812 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2813 #define TOOL_BUTTON_PLAYER_XSIZE 30
2814 #define TOOL_BUTTON_PLAYER_YSIZE 30
2815 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2816 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2817 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2818 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2819 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2820 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2821 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2822 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2823 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2824 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2825 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2826 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2827 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2828 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2829 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2830 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2831 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2832 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2833 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2834 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2843 } toolbutton_info[NUM_TOOL_BUTTONS] =
2846 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2847 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2848 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2853 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2854 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2855 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2860 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2861 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2862 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2863 TOOL_CTRL_ID_CONFIRM,
2867 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2868 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2869 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2870 TOOL_CTRL_ID_PLAYER_1,
2874 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2875 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2876 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2877 TOOL_CTRL_ID_PLAYER_2,
2881 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2882 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2883 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2884 TOOL_CTRL_ID_PLAYER_3,
2888 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2889 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2890 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2891 TOOL_CTRL_ID_PLAYER_4,
2896 void CreateToolButtons()
2900 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2902 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2903 Bitmap *deco_bitmap = None;
2904 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2905 struct GadgetInfo *gi;
2906 unsigned long event_mask;
2907 int gd_xoffset, gd_yoffset;
2908 int gd_x1, gd_x2, gd_y;
2911 event_mask = GD_EVENT_RELEASED;
2913 gd_xoffset = toolbutton_info[i].xpos;
2914 gd_yoffset = toolbutton_info[i].ypos;
2915 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2916 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2917 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2919 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2921 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2923 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2924 &deco_bitmap, &deco_x, &deco_y);
2925 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2926 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2929 gi = CreateGadget(GDI_CUSTOM_ID, id,
2930 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2931 GDI_X, DX + toolbutton_info[i].x,
2932 GDI_Y, DY + toolbutton_info[i].y,
2933 GDI_WIDTH, toolbutton_info[i].width,
2934 GDI_HEIGHT, toolbutton_info[i].height,
2935 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2936 GDI_STATE, GD_BUTTON_UNPRESSED,
2937 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2938 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2939 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2940 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2941 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2942 GDI_DECORATION_SHIFTING, 1, 1,
2943 GDI_EVENT_MASK, event_mask,
2944 GDI_CALLBACK_ACTION, HandleToolButtons,
2948 Error(ERR_EXIT, "cannot create gadget");
2950 tool_gadget[id] = gi;
2954 void FreeToolButtons()
2958 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2959 FreeGadget(tool_gadget[i]);
2962 static void UnmapToolButtons()
2966 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2967 UnmapGadget(tool_gadget[i]);
2970 static void HandleToolButtons(struct GadgetInfo *gi)
2972 request_gadget_id = gi->custom_id;
2975 static struct Mapping_EM_to_RND_object
2978 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2979 boolean is_backside; /* backside of moving element */
2985 em_object_mapping_list[] =
2988 Xblank, TRUE, FALSE,
2992 Yacid_splash_eB, FALSE, FALSE,
2993 EL_ACID_SPLASH_RIGHT, -1, -1
2996 Yacid_splash_wB, FALSE, FALSE,
2997 EL_ACID_SPLASH_LEFT, -1, -1
3000 #ifdef EM_ENGINE_BAD_ROLL
3002 Xstone_force_e, FALSE, FALSE,
3003 EL_ROCK, -1, MV_BIT_RIGHT
3006 Xstone_force_w, FALSE, FALSE,
3007 EL_ROCK, -1, MV_BIT_LEFT
3010 Xnut_force_e, FALSE, FALSE,
3011 EL_NUT, -1, MV_BIT_RIGHT
3014 Xnut_force_w, FALSE, FALSE,
3015 EL_NUT, -1, MV_BIT_LEFT
3018 Xspring_force_e, FALSE, FALSE,
3019 EL_SPRING, -1, MV_BIT_RIGHT
3022 Xspring_force_w, FALSE, FALSE,
3023 EL_SPRING, -1, MV_BIT_LEFT
3026 Xemerald_force_e, FALSE, FALSE,
3027 EL_EMERALD, -1, MV_BIT_RIGHT
3030 Xemerald_force_w, FALSE, FALSE,
3031 EL_EMERALD, -1, MV_BIT_LEFT
3034 Xdiamond_force_e, FALSE, FALSE,
3035 EL_DIAMOND, -1, MV_BIT_RIGHT
3038 Xdiamond_force_w, FALSE, FALSE,
3039 EL_DIAMOND, -1, MV_BIT_LEFT
3042 Xbomb_force_e, FALSE, FALSE,
3043 EL_BOMB, -1, MV_BIT_RIGHT
3046 Xbomb_force_w, FALSE, FALSE,
3047 EL_BOMB, -1, MV_BIT_LEFT
3049 #endif /* EM_ENGINE_BAD_ROLL */
3052 Xstone, TRUE, FALSE,
3056 Xstone_pause, FALSE, FALSE,
3060 Xstone_fall, FALSE, FALSE,
3064 Ystone_s, FALSE, FALSE,
3065 EL_ROCK, ACTION_FALLING, -1
3068 Ystone_sB, FALSE, TRUE,
3069 EL_ROCK, ACTION_FALLING, -1
3072 Ystone_e, FALSE, FALSE,
3073 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3076 Ystone_eB, FALSE, TRUE,
3077 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3080 Ystone_w, FALSE, FALSE,
3081 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3084 Ystone_wB, FALSE, TRUE,
3085 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3092 Xnut_pause, FALSE, FALSE,
3096 Xnut_fall, FALSE, FALSE,
3100 Ynut_s, FALSE, FALSE,
3101 EL_NUT, ACTION_FALLING, -1
3104 Ynut_sB, FALSE, TRUE,
3105 EL_NUT, ACTION_FALLING, -1
3108 Ynut_e, FALSE, FALSE,
3109 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3112 Ynut_eB, FALSE, TRUE,
3113 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3116 Ynut_w, FALSE, FALSE,
3117 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3120 Ynut_wB, FALSE, TRUE,
3121 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3124 Xbug_n, TRUE, FALSE,
3128 Xbug_e, TRUE, FALSE,
3129 EL_BUG_RIGHT, -1, -1
3132 Xbug_s, TRUE, FALSE,
3136 Xbug_w, TRUE, FALSE,
3140 Xbug_gon, FALSE, FALSE,
3144 Xbug_goe, FALSE, FALSE,
3145 EL_BUG_RIGHT, -1, -1
3148 Xbug_gos, FALSE, FALSE,
3152 Xbug_gow, FALSE, FALSE,
3156 Ybug_n, FALSE, FALSE,
3157 EL_BUG, ACTION_MOVING, MV_BIT_UP
3160 Ybug_nB, FALSE, TRUE,
3161 EL_BUG, ACTION_MOVING, MV_BIT_UP
3164 Ybug_e, FALSE, FALSE,
3165 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3168 Ybug_eB, FALSE, TRUE,
3169 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3172 Ybug_s, FALSE, FALSE,
3173 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3176 Ybug_sB, FALSE, TRUE,
3177 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3180 Ybug_w, FALSE, FALSE,
3181 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3184 Ybug_wB, FALSE, TRUE,
3185 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3188 Ybug_w_n, FALSE, FALSE,
3189 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3192 Ybug_n_e, FALSE, FALSE,
3193 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3196 Ybug_e_s, FALSE, FALSE,
3197 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3200 Ybug_s_w, FALSE, FALSE,
3201 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3204 Ybug_e_n, FALSE, FALSE,
3205 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3208 Ybug_s_e, FALSE, FALSE,
3209 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3212 Ybug_w_s, FALSE, FALSE,
3213 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3216 Ybug_n_w, FALSE, FALSE,
3217 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3220 Ybug_stone, FALSE, FALSE,
3221 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3224 Ybug_spring, FALSE, FALSE,
3225 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3228 Xtank_n, TRUE, FALSE,
3229 EL_SPACESHIP_UP, -1, -1
3232 Xtank_e, TRUE, FALSE,
3233 EL_SPACESHIP_RIGHT, -1, -1
3236 Xtank_s, TRUE, FALSE,
3237 EL_SPACESHIP_DOWN, -1, -1
3240 Xtank_w, TRUE, FALSE,
3241 EL_SPACESHIP_LEFT, -1, -1
3244 Xtank_gon, FALSE, FALSE,
3245 EL_SPACESHIP_UP, -1, -1
3248 Xtank_goe, FALSE, FALSE,
3249 EL_SPACESHIP_RIGHT, -1, -1
3252 Xtank_gos, FALSE, FALSE,
3253 EL_SPACESHIP_DOWN, -1, -1
3256 Xtank_gow, FALSE, FALSE,
3257 EL_SPACESHIP_LEFT, -1, -1
3260 Ytank_n, FALSE, FALSE,
3261 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3264 Ytank_nB, FALSE, TRUE,
3265 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3268 Ytank_e, FALSE, FALSE,
3269 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3272 Ytank_eB, FALSE, TRUE,
3273 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3276 Ytank_s, FALSE, FALSE,
3277 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3280 Ytank_sB, FALSE, TRUE,
3281 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3284 Ytank_w, FALSE, FALSE,
3285 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3288 Ytank_wB, FALSE, TRUE,
3289 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3292 Ytank_w_n, FALSE, FALSE,
3293 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3296 Ytank_n_e, FALSE, FALSE,
3297 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3300 Ytank_e_s, FALSE, FALSE,
3301 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3304 Ytank_s_w, FALSE, FALSE,
3305 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3308 Ytank_e_n, FALSE, FALSE,
3309 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3312 Ytank_s_e, FALSE, FALSE,
3313 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3316 Ytank_w_s, FALSE, FALSE,
3317 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3320 Ytank_n_w, FALSE, FALSE,
3321 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3324 Ytank_stone, FALSE, FALSE,
3325 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3328 Ytank_spring, FALSE, FALSE,
3329 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3332 Xandroid, TRUE, FALSE,
3333 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3336 Xandroid_1_n, FALSE, FALSE,
3337 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3340 Xandroid_2_n, FALSE, FALSE,
3341 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3344 Xandroid_1_e, FALSE, FALSE,
3345 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3348 Xandroid_2_e, FALSE, FALSE,
3349 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3352 Xandroid_1_w, FALSE, FALSE,
3353 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3356 Xandroid_2_w, FALSE, FALSE,
3357 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3360 Xandroid_1_s, FALSE, FALSE,
3361 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3364 Xandroid_2_s, FALSE, FALSE,
3365 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3368 Yandroid_n, FALSE, FALSE,
3369 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3372 Yandroid_nB, FALSE, TRUE,
3373 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3376 Yandroid_ne, FALSE, FALSE,
3377 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3380 Yandroid_neB, FALSE, TRUE,
3381 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3384 Yandroid_e, FALSE, FALSE,
3385 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3388 Yandroid_eB, FALSE, TRUE,
3389 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3392 Yandroid_se, FALSE, FALSE,
3393 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3396 Yandroid_seB, FALSE, TRUE,
3397 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3400 Yandroid_s, FALSE, FALSE,
3401 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3404 Yandroid_sB, FALSE, TRUE,
3405 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3408 Yandroid_sw, FALSE, FALSE,
3409 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3412 Yandroid_swB, FALSE, TRUE,
3413 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3416 Yandroid_w, FALSE, FALSE,
3417 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3420 Yandroid_wB, FALSE, TRUE,
3421 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3424 Yandroid_nw, FALSE, FALSE,
3425 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3428 Yandroid_nwB, FALSE, TRUE,
3429 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3432 Xspring, TRUE, FALSE,
3436 Xspring_pause, FALSE, FALSE,
3440 Xspring_e, FALSE, FALSE,
3444 Xspring_w, FALSE, FALSE,
3448 Xspring_fall, FALSE, FALSE,
3452 Yspring_s, FALSE, FALSE,
3453 EL_SPRING, ACTION_FALLING, -1
3456 Yspring_sB, FALSE, TRUE,
3457 EL_SPRING, ACTION_FALLING, -1
3460 Yspring_e, FALSE, FALSE,
3461 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3464 Yspring_eB, FALSE, TRUE,
3465 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3468 Yspring_w, FALSE, FALSE,
3469 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3472 Yspring_wB, FALSE, TRUE,
3473 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3476 Yspring_kill_e, FALSE, FALSE,
3477 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3480 Yspring_kill_eB, FALSE, TRUE,
3481 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3484 Yspring_kill_w, FALSE, FALSE,
3485 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3488 Yspring_kill_wB, FALSE, TRUE,
3489 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3492 Xeater_n, TRUE, FALSE,
3493 EL_YAMYAM_UP, -1, -1
3496 Xeater_e, TRUE, FALSE,
3497 EL_YAMYAM_RIGHT, -1, -1
3500 Xeater_w, TRUE, FALSE,
3501 EL_YAMYAM_LEFT, -1, -1
3504 Xeater_s, TRUE, FALSE,
3505 EL_YAMYAM_DOWN, -1, -1
3508 Yeater_n, FALSE, FALSE,
3509 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3512 Yeater_nB, FALSE, TRUE,
3513 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3516 Yeater_e, FALSE, FALSE,
3517 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3520 Yeater_eB, FALSE, TRUE,
3521 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3524 Yeater_s, FALSE, FALSE,
3525 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3528 Yeater_sB, FALSE, TRUE,
3529 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3532 Yeater_w, FALSE, FALSE,
3533 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3536 Yeater_wB, FALSE, TRUE,
3537 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3540 Yeater_stone, FALSE, FALSE,
3541 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3544 Yeater_spring, FALSE, FALSE,
3545 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3548 Xalien, TRUE, FALSE,
3552 Xalien_pause, FALSE, FALSE,
3556 Yalien_n, FALSE, FALSE,
3557 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3560 Yalien_nB, FALSE, TRUE,
3561 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3564 Yalien_e, FALSE, FALSE,
3565 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3568 Yalien_eB, FALSE, TRUE,
3569 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3572 Yalien_s, FALSE, FALSE,
3573 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3576 Yalien_sB, FALSE, TRUE,
3577 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3580 Yalien_w, FALSE, FALSE,
3581 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3584 Yalien_wB, FALSE, TRUE,
3585 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3588 Yalien_stone, FALSE, FALSE,
3589 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3592 Yalien_spring, FALSE, FALSE,
3593 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3596 Xemerald, TRUE, FALSE,
3600 Xemerald_pause, FALSE, FALSE,
3604 Xemerald_fall, FALSE, FALSE,
3608 Xemerald_shine, FALSE, FALSE,
3609 EL_EMERALD, ACTION_TWINKLING, -1
3612 Yemerald_s, FALSE, FALSE,
3613 EL_EMERALD, ACTION_FALLING, -1
3616 Yemerald_sB, FALSE, TRUE,
3617 EL_EMERALD, ACTION_FALLING, -1
3620 Yemerald_e, FALSE, FALSE,
3621 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3624 Yemerald_eB, FALSE, TRUE,
3625 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3628 Yemerald_w, FALSE, FALSE,
3629 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3632 Yemerald_wB, FALSE, TRUE,
3633 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3636 Yemerald_eat, FALSE, FALSE,
3637 EL_EMERALD, ACTION_COLLECTING, -1
3640 Yemerald_stone, FALSE, FALSE,
3641 EL_NUT, ACTION_BREAKING, -1
3644 Xdiamond, TRUE, FALSE,
3648 Xdiamond_pause, FALSE, FALSE,
3652 Xdiamond_fall, FALSE, FALSE,
3656 Xdiamond_shine, FALSE, FALSE,
3657 EL_DIAMOND, ACTION_TWINKLING, -1
3660 Ydiamond_s, FALSE, FALSE,
3661 EL_DIAMOND, ACTION_FALLING, -1
3664 Ydiamond_sB, FALSE, TRUE,
3665 EL_DIAMOND, ACTION_FALLING, -1
3668 Ydiamond_e, FALSE, FALSE,
3669 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3672 Ydiamond_eB, FALSE, TRUE,
3673 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3676 Ydiamond_w, FALSE, FALSE,
3677 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3680 Ydiamond_wB, FALSE, TRUE,
3681 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3684 Ydiamond_eat, FALSE, FALSE,
3685 EL_DIAMOND, ACTION_COLLECTING, -1
3688 Ydiamond_stone, FALSE, FALSE,
3689 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3692 Xdrip_fall, TRUE, FALSE,
3693 EL_AMOEBA_DROP, -1, -1
3696 Xdrip_stretch, FALSE, FALSE,
3697 EL_AMOEBA_DROP, ACTION_FALLING, -1
3700 Xdrip_stretchB, FALSE, TRUE,
3701 EL_AMOEBA_DROP, ACTION_FALLING, -1
3704 Xdrip_eat, FALSE, FALSE,
3705 EL_AMOEBA_DROP, ACTION_GROWING, -1
3708 Ydrip_s1, FALSE, FALSE,
3709 EL_AMOEBA_DROP, ACTION_FALLING, -1
3712 Ydrip_s1B, FALSE, TRUE,
3713 EL_AMOEBA_DROP, ACTION_FALLING, -1
3716 Ydrip_s2, FALSE, FALSE,
3717 EL_AMOEBA_DROP, ACTION_FALLING, -1
3720 Ydrip_s2B, FALSE, TRUE,
3721 EL_AMOEBA_DROP, ACTION_FALLING, -1
3728 Xbomb_pause, FALSE, FALSE,
3732 Xbomb_fall, FALSE, FALSE,
3736 Ybomb_s, FALSE, FALSE,
3737 EL_BOMB, ACTION_FALLING, -1
3740 Ybomb_sB, FALSE, TRUE,
3741 EL_BOMB, ACTION_FALLING, -1
3744 Ybomb_e, FALSE, FALSE,
3745 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3748 Ybomb_eB, FALSE, TRUE,
3749 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3752 Ybomb_w, FALSE, FALSE,
3753 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3756 Ybomb_wB, FALSE, TRUE,
3757 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3760 Ybomb_eat, FALSE, FALSE,
3761 EL_BOMB, ACTION_ACTIVATING, -1
3764 Xballoon, TRUE, FALSE,
3768 Yballoon_n, FALSE, FALSE,
3769 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3772 Yballoon_nB, FALSE, TRUE,
3773 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3776 Yballoon_e, FALSE, FALSE,
3777 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3780 Yballoon_eB, FALSE, TRUE,
3781 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3784 Yballoon_s, FALSE, FALSE,
3785 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3788 Yballoon_sB, FALSE, TRUE,
3789 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3792 Yballoon_w, FALSE, FALSE,
3793 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3796 Yballoon_wB, FALSE, TRUE,
3797 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3800 Xgrass, TRUE, FALSE,
3801 EL_EMC_GRASS, -1, -1
3804 Ygrass_nB, FALSE, FALSE,
3805 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3808 Ygrass_eB, FALSE, FALSE,
3809 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3812 Ygrass_sB, FALSE, FALSE,
3813 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3816 Ygrass_wB, FALSE, FALSE,
3817 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3824 Ydirt_nB, FALSE, FALSE,
3825 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3828 Ydirt_eB, FALSE, FALSE,
3829 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3832 Ydirt_sB, FALSE, FALSE,
3833 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3836 Ydirt_wB, FALSE, FALSE,
3837 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3840 Xacid_ne, TRUE, FALSE,
3841 EL_ACID_POOL_TOPRIGHT, -1, -1
3844 Xacid_se, TRUE, FALSE,
3845 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3848 Xacid_s, TRUE, FALSE,
3849 EL_ACID_POOL_BOTTOM, -1, -1
3852 Xacid_sw, TRUE, FALSE,
3853 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3856 Xacid_nw, TRUE, FALSE,
3857 EL_ACID_POOL_TOPLEFT, -1, -1
3860 Xacid_1, TRUE, FALSE,
3864 Xacid_2, FALSE, FALSE,
3868 Xacid_3, FALSE, FALSE,
3872 Xacid_4, FALSE, FALSE,
3876 Xacid_5, FALSE, FALSE,
3880 Xacid_6, FALSE, FALSE,
3884 Xacid_7, FALSE, FALSE,
3888 Xacid_8, FALSE, FALSE,
3892 Xball_1, TRUE, FALSE,
3893 EL_EMC_MAGIC_BALL, -1, -1
3896 Xball_1B, FALSE, FALSE,
3897 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3900 Xball_2, FALSE, FALSE,
3901 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3904 Xball_2B, FALSE, FALSE,
3905 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3908 Yball_eat, FALSE, FALSE,
3909 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3912 Ykey_1_eat, FALSE, FALSE,
3913 EL_EM_KEY_1, ACTION_COLLECTING, -1
3916 Ykey_2_eat, FALSE, FALSE,
3917 EL_EM_KEY_2, ACTION_COLLECTING, -1
3920 Ykey_3_eat, FALSE, FALSE,
3921 EL_EM_KEY_3, ACTION_COLLECTING, -1
3924 Ykey_4_eat, FALSE, FALSE,
3925 EL_EM_KEY_4, ACTION_COLLECTING, -1
3928 Ykey_5_eat, FALSE, FALSE,
3929 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3932 Ykey_6_eat, FALSE, FALSE,
3933 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3936 Ykey_7_eat, FALSE, FALSE,
3937 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3940 Ykey_8_eat, FALSE, FALSE,
3941 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3944 Ylenses_eat, FALSE, FALSE,
3945 EL_EMC_LENSES, ACTION_COLLECTING, -1
3948 Ymagnify_eat, FALSE, FALSE,
3949 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3952 Ygrass_eat, FALSE, FALSE,
3953 EL_EMC_GRASS, ACTION_SNAPPING, -1
3956 Ydirt_eat, FALSE, FALSE,
3957 EL_SAND, ACTION_SNAPPING, -1
3960 Xgrow_ns, TRUE, FALSE,
3961 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3964 Ygrow_ns_eat, FALSE, FALSE,
3965 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3968 Xgrow_ew, TRUE, FALSE,
3969 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3972 Ygrow_ew_eat, FALSE, FALSE,
3973 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3976 Xwonderwall, TRUE, FALSE,
3977 EL_MAGIC_WALL, -1, -1
3980 XwonderwallB, FALSE, FALSE,
3981 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3984 Xamoeba_1, TRUE, FALSE,
3985 EL_AMOEBA_DRY, ACTION_OTHER, -1
3988 Xamoeba_2, FALSE, FALSE,
3989 EL_AMOEBA_DRY, ACTION_OTHER, -1
3992 Xamoeba_3, FALSE, FALSE,
3993 EL_AMOEBA_DRY, ACTION_OTHER, -1
3996 Xamoeba_4, FALSE, FALSE,
3997 EL_AMOEBA_DRY, ACTION_OTHER, -1
4000 Xamoeba_5, TRUE, FALSE,
4001 EL_AMOEBA_WET, ACTION_OTHER, -1
4004 Xamoeba_6, FALSE, FALSE,
4005 EL_AMOEBA_WET, ACTION_OTHER, -1
4008 Xamoeba_7, FALSE, FALSE,
4009 EL_AMOEBA_WET, ACTION_OTHER, -1
4012 Xamoeba_8, FALSE, FALSE,
4013 EL_AMOEBA_WET, ACTION_OTHER, -1
4016 Xdoor_1, TRUE, FALSE,
4017 EL_EM_GATE_1, -1, -1
4020 Xdoor_2, TRUE, FALSE,
4021 EL_EM_GATE_2, -1, -1
4024 Xdoor_3, TRUE, FALSE,
4025 EL_EM_GATE_3, -1, -1
4028 Xdoor_4, TRUE, FALSE,
4029 EL_EM_GATE_4, -1, -1
4032 Xdoor_5, TRUE, FALSE,
4033 EL_EMC_GATE_5, -1, -1
4036 Xdoor_6, TRUE, FALSE,
4037 EL_EMC_GATE_6, -1, -1
4040 Xdoor_7, TRUE, FALSE,
4041 EL_EMC_GATE_7, -1, -1
4044 Xdoor_8, TRUE, FALSE,
4045 EL_EMC_GATE_8, -1, -1
4048 Xkey_1, TRUE, FALSE,
4052 Xkey_2, TRUE, FALSE,
4056 Xkey_3, TRUE, FALSE,
4060 Xkey_4, TRUE, FALSE,
4064 Xkey_5, TRUE, FALSE,
4065 EL_EMC_KEY_5, -1, -1
4068 Xkey_6, TRUE, FALSE,
4069 EL_EMC_KEY_6, -1, -1
4072 Xkey_7, TRUE, FALSE,
4073 EL_EMC_KEY_7, -1, -1
4076 Xkey_8, TRUE, FALSE,
4077 EL_EMC_KEY_8, -1, -1
4080 Xwind_n, TRUE, FALSE,
4081 EL_BALLOON_SWITCH_UP, -1, -1
4084 Xwind_e, TRUE, FALSE,
4085 EL_BALLOON_SWITCH_RIGHT, -1, -1
4088 Xwind_s, TRUE, FALSE,
4089 EL_BALLOON_SWITCH_DOWN, -1, -1
4092 Xwind_w, TRUE, FALSE,
4093 EL_BALLOON_SWITCH_LEFT, -1, -1
4096 Xwind_nesw, TRUE, FALSE,
4097 EL_BALLOON_SWITCH_ANY, -1, -1
4100 Xwind_stop, TRUE, FALSE,
4101 EL_BALLOON_SWITCH_NONE, -1, -1
4105 EL_EXIT_CLOSED, -1, -1
4108 Xexit_1, TRUE, FALSE,
4109 EL_EXIT_OPEN, -1, -1
4112 Xexit_2, FALSE, FALSE,
4113 EL_EXIT_OPEN, -1, -1
4116 Xexit_3, FALSE, FALSE,
4117 EL_EXIT_OPEN, -1, -1
4120 Xdynamite, TRUE, FALSE,
4121 EL_EM_DYNAMITE, -1, -1
4124 Ydynamite_eat, FALSE, FALSE,
4125 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4128 Xdynamite_1, TRUE, FALSE,
4129 EL_EM_DYNAMITE_ACTIVE, -1, -1
4132 Xdynamite_2, FALSE, FALSE,
4133 EL_EM_DYNAMITE_ACTIVE, -1, -1
4136 Xdynamite_3, FALSE, FALSE,
4137 EL_EM_DYNAMITE_ACTIVE, -1, -1
4140 Xdynamite_4, FALSE, FALSE,
4141 EL_EM_DYNAMITE_ACTIVE, -1, -1
4144 Xbumper, TRUE, FALSE,
4145 EL_EMC_SPRING_BUMPER, -1, -1
4148 XbumperB, FALSE, FALSE,
4149 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4152 Xwheel, TRUE, FALSE,
4153 EL_ROBOT_WHEEL, -1, -1
4156 XwheelB, FALSE, FALSE,
4157 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4160 Xswitch, TRUE, FALSE,
4161 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4164 XswitchB, FALSE, FALSE,
4165 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4169 EL_QUICKSAND_EMPTY, -1, -1
4172 Xsand_stone, TRUE, FALSE,
4173 EL_QUICKSAND_FULL, -1, -1
4176 Xsand_stonein_1, FALSE, FALSE,
4177 EL_ROCK, ACTION_FILLING, -1
4180 Xsand_stonein_2, FALSE, FALSE,
4181 EL_ROCK, ACTION_FILLING, -1
4184 Xsand_stonein_3, FALSE, FALSE,
4185 EL_ROCK, ACTION_FILLING, -1
4188 Xsand_stonein_4, FALSE, FALSE,
4189 EL_ROCK, ACTION_FILLING, -1
4192 Xsand_stonesand_1, FALSE, FALSE,
4193 EL_QUICKSAND_FULL, -1, -1
4196 Xsand_stonesand_2, FALSE, FALSE,
4197 EL_QUICKSAND_FULL, -1, -1
4200 Xsand_stonesand_3, FALSE, FALSE,
4201 EL_QUICKSAND_FULL, -1, -1
4204 Xsand_stonesand_4, FALSE, FALSE,
4205 EL_QUICKSAND_FULL, -1, -1
4208 Xsand_stoneout_1, FALSE, FALSE,
4209 EL_ROCK, ACTION_EMPTYING, -1
4212 Xsand_stoneout_2, FALSE, FALSE,
4213 EL_ROCK, ACTION_EMPTYING, -1
4216 Xsand_sandstone_1, FALSE, FALSE,
4217 EL_QUICKSAND_FULL, -1, -1
4220 Xsand_sandstone_2, FALSE, FALSE,
4221 EL_QUICKSAND_FULL, -1, -1
4224 Xsand_sandstone_3, FALSE, FALSE,
4225 EL_QUICKSAND_FULL, -1, -1
4228 Xsand_sandstone_4, FALSE, FALSE,
4229 EL_QUICKSAND_FULL, -1, -1
4232 Xplant, TRUE, FALSE,
4233 EL_EMC_PLANT, -1, -1
4236 Yplant, FALSE, FALSE,
4237 EL_EMC_PLANT, -1, -1
4240 Xlenses, TRUE, FALSE,
4241 EL_EMC_LENSES, -1, -1
4244 Xmagnify, TRUE, FALSE,
4245 EL_EMC_MAGNIFIER, -1, -1
4248 Xdripper, TRUE, FALSE,
4249 EL_EMC_DRIPPER, -1, -1
4252 XdripperB, FALSE, FALSE,
4253 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4256 Xfake_blank, TRUE, FALSE,
4257 EL_INVISIBLE_WALL, -1, -1
4260 Xfake_blankB, FALSE, FALSE,
4261 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4264 Xfake_grass, TRUE, FALSE,
4265 EL_EMC_FAKE_GRASS, -1, -1
4268 Xfake_grassB, FALSE, FALSE,
4269 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4272 Xfake_door_1, TRUE, FALSE,
4273 EL_EM_GATE_1_GRAY, -1, -1
4276 Xfake_door_2, TRUE, FALSE,
4277 EL_EM_GATE_2_GRAY, -1, -1
4280 Xfake_door_3, TRUE, FALSE,
4281 EL_EM_GATE_3_GRAY, -1, -1
4284 Xfake_door_4, TRUE, FALSE,
4285 EL_EM_GATE_4_GRAY, -1, -1
4288 Xfake_door_5, TRUE, FALSE,
4289 EL_EMC_GATE_5_GRAY, -1, -1
4292 Xfake_door_6, TRUE, FALSE,
4293 EL_EMC_GATE_6_GRAY, -1, -1
4296 Xfake_door_7, TRUE, FALSE,
4297 EL_EMC_GATE_7_GRAY, -1, -1
4300 Xfake_door_8, TRUE, FALSE,
4301 EL_EMC_GATE_8_GRAY, -1, -1
4304 Xfake_acid_1, TRUE, FALSE,
4305 EL_EMC_FAKE_ACID, -1, -1
4308 Xfake_acid_2, FALSE, FALSE,
4309 EL_EMC_FAKE_ACID, -1, -1
4312 Xfake_acid_3, FALSE, FALSE,
4313 EL_EMC_FAKE_ACID, -1, -1
4316 Xfake_acid_4, FALSE, FALSE,
4317 EL_EMC_FAKE_ACID, -1, -1
4320 Xfake_acid_5, FALSE, FALSE,
4321 EL_EMC_FAKE_ACID, -1, -1
4324 Xfake_acid_6, FALSE, FALSE,
4325 EL_EMC_FAKE_ACID, -1, -1
4328 Xfake_acid_7, FALSE, FALSE,
4329 EL_EMC_FAKE_ACID, -1, -1
4332 Xfake_acid_8, FALSE, FALSE,
4333 EL_EMC_FAKE_ACID, -1, -1
4336 Xsteel_1, TRUE, FALSE,
4337 EL_STEELWALL, -1, -1
4340 Xsteel_2, TRUE, FALSE,
4341 EL_EMC_STEELWALL_2, -1, -1
4344 Xsteel_3, TRUE, FALSE,
4345 EL_EMC_STEELWALL_3, -1, -1
4348 Xsteel_4, TRUE, FALSE,
4349 EL_EMC_STEELWALL_4, -1, -1
4352 Xwall_1, TRUE, FALSE,
4356 Xwall_2, TRUE, FALSE,
4357 EL_EMC_WALL_14, -1, -1
4360 Xwall_3, TRUE, FALSE,
4361 EL_EMC_WALL_15, -1, -1
4364 Xwall_4, TRUE, FALSE,
4365 EL_EMC_WALL_16, -1, -1
4368 Xround_wall_1, TRUE, FALSE,
4369 EL_WALL_SLIPPERY, -1, -1
4372 Xround_wall_2, TRUE, FALSE,
4373 EL_EMC_WALL_SLIPPERY_2, -1, -1
4376 Xround_wall_3, TRUE, FALSE,
4377 EL_EMC_WALL_SLIPPERY_3, -1, -1
4380 Xround_wall_4, TRUE, FALSE,
4381 EL_EMC_WALL_SLIPPERY_4, -1, -1
4384 Xdecor_1, TRUE, FALSE,
4385 EL_EMC_WALL_8, -1, -1
4388 Xdecor_2, TRUE, FALSE,
4389 EL_EMC_WALL_6, -1, -1
4392 Xdecor_3, TRUE, FALSE,
4393 EL_EMC_WALL_4, -1, -1
4396 Xdecor_4, TRUE, FALSE,
4397 EL_EMC_WALL_7, -1, -1
4400 Xdecor_5, TRUE, FALSE,
4401 EL_EMC_WALL_5, -1, -1
4404 Xdecor_6, TRUE, FALSE,
4405 EL_EMC_WALL_9, -1, -1
4408 Xdecor_7, TRUE, FALSE,
4409 EL_EMC_WALL_10, -1, -1
4412 Xdecor_8, TRUE, FALSE,
4413 EL_EMC_WALL_1, -1, -1
4416 Xdecor_9, TRUE, FALSE,
4417 EL_EMC_WALL_2, -1, -1
4420 Xdecor_10, TRUE, FALSE,
4421 EL_EMC_WALL_3, -1, -1
4424 Xdecor_11, TRUE, FALSE,
4425 EL_EMC_WALL_11, -1, -1
4428 Xdecor_12, TRUE, FALSE,
4429 EL_EMC_WALL_12, -1, -1
4432 Xalpha_0, TRUE, FALSE,
4433 EL_CHAR('0'), -1, -1
4436 Xalpha_1, TRUE, FALSE,
4437 EL_CHAR('1'), -1, -1
4440 Xalpha_2, TRUE, FALSE,
4441 EL_CHAR('2'), -1, -1
4444 Xalpha_3, TRUE, FALSE,
4445 EL_CHAR('3'), -1, -1
4448 Xalpha_4, TRUE, FALSE,
4449 EL_CHAR('4'), -1, -1
4452 Xalpha_5, TRUE, FALSE,
4453 EL_CHAR('5'), -1, -1
4456 Xalpha_6, TRUE, FALSE,
4457 EL_CHAR('6'), -1, -1
4460 Xalpha_7, TRUE, FALSE,
4461 EL_CHAR('7'), -1, -1
4464 Xalpha_8, TRUE, FALSE,
4465 EL_CHAR('8'), -1, -1
4468 Xalpha_9, TRUE, FALSE,
4469 EL_CHAR('9'), -1, -1
4472 Xalpha_excla, TRUE, FALSE,
4473 EL_CHAR('!'), -1, -1
4476 Xalpha_quote, TRUE, FALSE,
4477 EL_CHAR('"'), -1, -1
4480 Xalpha_comma, TRUE, FALSE,
4481 EL_CHAR(','), -1, -1
4484 Xalpha_minus, TRUE, FALSE,
4485 EL_CHAR('-'), -1, -1
4488 Xalpha_perio, TRUE, FALSE,
4489 EL_CHAR('.'), -1, -1
4492 Xalpha_colon, TRUE, FALSE,
4493 EL_CHAR(':'), -1, -1
4496 Xalpha_quest, TRUE, FALSE,
4497 EL_CHAR('?'), -1, -1
4500 Xalpha_a, TRUE, FALSE,
4501 EL_CHAR('A'), -1, -1
4504 Xalpha_b, TRUE, FALSE,
4505 EL_CHAR('B'), -1, -1
4508 Xalpha_c, TRUE, FALSE,
4509 EL_CHAR('C'), -1, -1
4512 Xalpha_d, TRUE, FALSE,
4513 EL_CHAR('D'), -1, -1
4516 Xalpha_e, TRUE, FALSE,
4517 EL_CHAR('E'), -1, -1
4520 Xalpha_f, TRUE, FALSE,
4521 EL_CHAR('F'), -1, -1
4524 Xalpha_g, TRUE, FALSE,
4525 EL_CHAR('G'), -1, -1
4528 Xalpha_h, TRUE, FALSE,
4529 EL_CHAR('H'), -1, -1
4532 Xalpha_i, TRUE, FALSE,
4533 EL_CHAR('I'), -1, -1
4536 Xalpha_j, TRUE, FALSE,
4537 EL_CHAR('J'), -1, -1
4540 Xalpha_k, TRUE, FALSE,
4541 EL_CHAR('K'), -1, -1
4544 Xalpha_l, TRUE, FALSE,
4545 EL_CHAR('L'), -1, -1
4548 Xalpha_m, TRUE, FALSE,
4549 EL_CHAR('M'), -1, -1
4552 Xalpha_n, TRUE, FALSE,
4553 EL_CHAR('N'), -1, -1
4556 Xalpha_o, TRUE, FALSE,
4557 EL_CHAR('O'), -1, -1
4560 Xalpha_p, TRUE, FALSE,
4561 EL_CHAR('P'), -1, -1
4564 Xalpha_q, TRUE, FALSE,
4565 EL_CHAR('Q'), -1, -1
4568 Xalpha_r, TRUE, FALSE,
4569 EL_CHAR('R'), -1, -1
4572 Xalpha_s, TRUE, FALSE,
4573 EL_CHAR('S'), -1, -1
4576 Xalpha_t, TRUE, FALSE,
4577 EL_CHAR('T'), -1, -1
4580 Xalpha_u, TRUE, FALSE,
4581 EL_CHAR('U'), -1, -1
4584 Xalpha_v, TRUE, FALSE,
4585 EL_CHAR('V'), -1, -1
4588 Xalpha_w, TRUE, FALSE,
4589 EL_CHAR('W'), -1, -1
4592 Xalpha_x, TRUE, FALSE,
4593 EL_CHAR('X'), -1, -1
4596 Xalpha_y, TRUE, FALSE,
4597 EL_CHAR('Y'), -1, -1
4600 Xalpha_z, TRUE, FALSE,
4601 EL_CHAR('Z'), -1, -1
4604 Xalpha_arrow_e, TRUE, FALSE,
4605 EL_CHAR('>'), -1, -1
4608 Xalpha_arrow_w, TRUE, FALSE,
4609 EL_CHAR('<'), -1, -1
4612 Xalpha_copyr, TRUE, FALSE,
4613 EL_CHAR('©'), -1, -1
4617 Xboom_bug, FALSE, FALSE,
4618 EL_BUG, ACTION_EXPLODING, -1
4621 Xboom_bomb, FALSE, FALSE,
4622 EL_BOMB, ACTION_EXPLODING, -1
4625 Xboom_android, FALSE, FALSE,
4626 EL_EMC_ANDROID, ACTION_OTHER, -1
4629 Xboom_1, FALSE, FALSE,
4630 EL_DEFAULT, ACTION_EXPLODING, -1
4633 Xboom_2, FALSE, FALSE,
4634 EL_DEFAULT, ACTION_EXPLODING, -1
4637 Znormal, FALSE, FALSE,
4641 Zdynamite, FALSE, FALSE,
4645 Zplayer, FALSE, FALSE,
4649 ZBORDER, FALSE, FALSE,
4659 static struct Mapping_EM_to_RND_player
4668 em_player_mapping_list[] =
4672 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4676 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4680 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4684 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4688 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4692 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4696 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4700 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4704 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4708 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4712 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4716 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4720 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4724 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4728 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4732 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4736 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4740 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4744 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4748 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4752 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4756 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4760 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4764 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4768 EL_PLAYER_1, ACTION_DEFAULT, -1,
4772 EL_PLAYER_2, ACTION_DEFAULT, -1,
4776 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4780 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4784 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4788 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4792 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4796 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4800 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4804 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4808 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4812 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4816 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4820 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4824 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4828 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4832 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4836 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4840 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4844 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4848 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4852 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4856 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4860 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4864 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4868 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4872 EL_PLAYER_3, ACTION_DEFAULT, -1,
4876 EL_PLAYER_4, ACTION_DEFAULT, -1,
4885 int map_element_RND_to_EM(int element_rnd)
4887 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4888 static boolean mapping_initialized = FALSE;
4890 if (!mapping_initialized)
4894 /* return "Xalpha_quest" for all undefined elements in mapping array */
4895 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4896 mapping_RND_to_EM[i] = Xalpha_quest;
4898 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4899 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4900 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4901 em_object_mapping_list[i].element_em;
4903 mapping_initialized = TRUE;
4906 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4907 return mapping_RND_to_EM[element_rnd];
4909 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4914 int map_element_EM_to_RND(int element_em)
4916 static unsigned short mapping_EM_to_RND[TILE_MAX];
4917 static boolean mapping_initialized = FALSE;
4919 if (!mapping_initialized)
4923 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4924 for (i = 0; i < TILE_MAX; i++)
4925 mapping_EM_to_RND[i] = EL_UNKNOWN;
4927 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4928 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4929 em_object_mapping_list[i].element_rnd;
4931 mapping_initialized = TRUE;
4934 if (element_em >= 0 && element_em < TILE_MAX)
4935 return mapping_EM_to_RND[element_em];
4937 Error(ERR_WARN, "invalid EM level element %d", element_em);
4942 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4944 struct LevelInfo_EM *level_em = level->native_em_level;
4945 struct LEVEL *lev = level_em->lev;
4948 for (i = 0; i < TILE_MAX; i++)
4949 lev->android_array[i] = Xblank;
4951 for (i = 0; i < level->num_android_clone_elements; i++)
4953 int element_rnd = level->android_clone_element[i];
4954 int element_em = map_element_RND_to_EM(element_rnd);
4956 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4957 if (em_object_mapping_list[j].element_rnd == element_rnd)
4958 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4962 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4964 struct LevelInfo_EM *level_em = level->native_em_level;
4965 struct LEVEL *lev = level_em->lev;
4968 level->num_android_clone_elements = 0;
4970 for (i = 0; i < TILE_MAX; i++)
4972 int element_em = lev->android_array[i];
4974 boolean element_found = FALSE;
4976 if (element_em == Xblank)
4979 element_rnd = map_element_EM_to_RND(element_em);
4981 for (j = 0; j < level->num_android_clone_elements; j++)
4982 if (level->android_clone_element[j] == element_rnd)
4983 element_found = TRUE;
4987 level->android_clone_element[level->num_android_clone_elements++] =
4990 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
4995 if (level->num_android_clone_elements == 0)
4997 level->num_android_clone_elements = 1;
4998 level->android_clone_element[0] = EL_EMPTY;
5002 int map_direction_RND_to_EM(int direction)
5004 return (direction == MV_UP ? 0 :
5005 direction == MV_RIGHT ? 1 :
5006 direction == MV_DOWN ? 2 :
5007 direction == MV_LEFT ? 3 :
5011 int map_direction_EM_to_RND(int direction)
5013 return (direction == 0 ? MV_UP :
5014 direction == 1 ? MV_RIGHT :
5015 direction == 2 ? MV_DOWN :
5016 direction == 3 ? MV_LEFT :
5020 int get_next_element(int element)
5024 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5025 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5026 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5027 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5028 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5029 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5030 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5032 default: return element;
5037 int el_act_dir2img(int element, int action, int direction)
5039 element = GFX_ELEMENT(element);
5041 if (direction == MV_NONE)
5042 return element_info[element].graphic[action];
5044 direction = MV_DIR_TO_BIT(direction);
5046 return element_info[element].direction_graphic[action][direction];
5049 int el_act_dir2img(int element, int action, int direction)
5051 element = GFX_ELEMENT(element);
5052 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5054 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5055 return element_info[element].direction_graphic[action][direction];
5060 static int el_act_dir2crm(int element, int action, int direction)
5062 element = GFX_ELEMENT(element);
5064 if (direction == MV_NONE)
5065 return element_info[element].crumbled[action];
5067 direction = MV_DIR_TO_BIT(direction);
5069 return element_info[element].direction_crumbled[action][direction];
5072 static int el_act_dir2crm(int element, int action, int direction)
5074 element = GFX_ELEMENT(element);
5075 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5077 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5078 return element_info[element].direction_crumbled[action][direction];
5082 int el_act2img(int element, int action)
5084 element = GFX_ELEMENT(element);
5086 return element_info[element].graphic[action];
5089 int el_act2crm(int element, int action)
5091 element = GFX_ELEMENT(element);
5093 return element_info[element].crumbled[action];
5096 int el_dir2img(int element, int direction)
5098 element = GFX_ELEMENT(element);
5100 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5103 int el2baseimg(int element)
5105 return element_info[element].graphic[ACTION_DEFAULT];
5108 int el2img(int element)
5110 element = GFX_ELEMENT(element);
5112 return element_info[element].graphic[ACTION_DEFAULT];
5115 int el2edimg(int element)
5117 element = GFX_ELEMENT(element);
5119 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5122 int el2preimg(int element)
5124 element = GFX_ELEMENT(element);
5126 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5129 int font2baseimg(int font_nr)
5131 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5135 void setCenteredPlayerNr_EM(int centered_player_nr)
5137 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5140 int getCenteredPlayerNr_EM()
5143 if (game.centered_player_nr_next >= 0 &&
5144 !native_em_level.ply[game.centered_player_nr_next]->alive)
5145 game.centered_player_nr_next = game.centered_player_nr;
5148 if (game.centered_player_nr != game.centered_player_nr_next)
5149 game.centered_player_nr = game.centered_player_nr_next;
5151 return game.centered_player_nr;
5154 void setSetCenteredPlayer_EM(boolean set_centered_player)
5156 game.set_centered_player = set_centered_player;
5159 boolean getSetCenteredPlayer_EM()
5161 return game.set_centered_player;
5165 int getNumActivePlayers_EM()
5167 int num_players = 0;
5173 for (i = 0; i < MAX_PLAYERS; i++)
5174 if (tape.player_participates[i])
5181 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5183 int game_frame_delay_value;
5185 game_frame_delay_value =
5186 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5187 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5190 if (tape.playing && tape.warp_forward && !tape.pausing)
5191 game_frame_delay_value = 0;
5193 return game_frame_delay_value;
5197 unsigned int InitRND(long seed)
5199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5200 return InitEngineRND_EM(seed);
5202 return InitEngineRND(seed);
5205 #define DEBUG_EM_GFX 0
5207 void InitGraphicInfo_EM(void)
5209 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5210 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5214 if (graphic_info_em_object[0][0].bitmap == NULL)
5216 /* EM graphics not yet initialized in em_open_all() */
5222 /* always start with reliable default values */
5223 for (i = 0; i < TILE_MAX; i++)
5225 object_mapping[i].element_rnd = EL_UNKNOWN;
5226 object_mapping[i].is_backside = FALSE;
5227 object_mapping[i].action = ACTION_DEFAULT;
5228 object_mapping[i].direction = MV_NONE;
5231 /* always start with reliable default values */
5232 for (p = 0; p < MAX_PLAYERS; p++)
5234 for (i = 0; i < SPR_MAX; i++)
5236 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5237 player_mapping[p][i].action = ACTION_DEFAULT;
5238 player_mapping[p][i].direction = MV_NONE;
5242 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5244 int e = em_object_mapping_list[i].element_em;
5246 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5247 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5249 if (em_object_mapping_list[i].action != -1)
5250 object_mapping[e].action = em_object_mapping_list[i].action;
5252 if (em_object_mapping_list[i].direction != -1)
5253 object_mapping[e].direction =
5254 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5257 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5259 int a = em_player_mapping_list[i].action_em;
5260 int p = em_player_mapping_list[i].player_nr;
5262 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5264 if (em_player_mapping_list[i].action != -1)
5265 player_mapping[p][a].action = em_player_mapping_list[i].action;
5267 if (em_player_mapping_list[i].direction != -1)
5268 player_mapping[p][a].direction =
5269 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5272 for (i = 0; i < TILE_MAX; i++)
5274 int element = object_mapping[i].element_rnd;
5275 int action = object_mapping[i].action;
5276 int direction = object_mapping[i].direction;
5277 boolean is_backside = object_mapping[i].is_backside;
5278 boolean action_removing = (action == ACTION_DIGGING ||
5279 action == ACTION_SNAPPING ||
5280 action == ACTION_COLLECTING);
5281 boolean action_exploding = ((action == ACTION_EXPLODING ||
5282 action == ACTION_SMASHED_BY_ROCK ||
5283 action == ACTION_SMASHED_BY_SPRING) &&
5284 element != EL_DIAMOND);
5285 boolean action_active = (action == ACTION_ACTIVE);
5286 boolean action_other = (action == ACTION_OTHER);
5288 for (j = 0; j < 8; j++)
5290 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5291 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5293 i == Xdrip_stretch ? element :
5294 i == Xdrip_stretchB ? element :
5295 i == Ydrip_s1 ? element :
5296 i == Ydrip_s1B ? element :
5297 i == Xball_1B ? element :
5298 i == Xball_2 ? element :
5299 i == Xball_2B ? element :
5300 i == Yball_eat ? element :
5301 i == Ykey_1_eat ? element :
5302 i == Ykey_2_eat ? element :
5303 i == Ykey_3_eat ? element :
5304 i == Ykey_4_eat ? element :
5305 i == Ykey_5_eat ? element :
5306 i == Ykey_6_eat ? element :
5307 i == Ykey_7_eat ? element :
5308 i == Ykey_8_eat ? element :
5309 i == Ylenses_eat ? element :
5310 i == Ymagnify_eat ? element :
5311 i == Ygrass_eat ? element :
5312 i == Ydirt_eat ? element :
5313 i == Yspring_kill_e ? EL_SPRING :
5314 i == Yspring_kill_w ? EL_SPRING :
5315 i == Yemerald_stone ? EL_EMERALD :
5316 i == Ydiamond_stone ? EL_ROCK :
5317 i == Xsand_stonein_4 ? EL_EMPTY :
5318 i == Xsand_stoneout_2 ? EL_ROCK :
5319 is_backside ? EL_EMPTY :
5320 action_removing ? EL_EMPTY :
5322 int effective_action = (j < 7 ? action :
5323 i == Xdrip_stretch ? action :
5324 i == Xdrip_stretchB ? action :
5325 i == Ydrip_s1 ? action :
5326 i == Ydrip_s1B ? action :
5327 i == Xball_1B ? action :
5328 i == Xball_2 ? action :
5329 i == Xball_2B ? action :
5330 i == Yball_eat ? action :
5331 i == Ykey_1_eat ? action :
5332 i == Ykey_2_eat ? action :
5333 i == Ykey_3_eat ? action :
5334 i == Ykey_4_eat ? action :
5335 i == Ykey_5_eat ? action :
5336 i == Ykey_6_eat ? action :
5337 i == Ykey_7_eat ? action :
5338 i == Ykey_8_eat ? action :
5339 i == Ylenses_eat ? action :
5340 i == Ymagnify_eat ? action :
5341 i == Ygrass_eat ? action :
5342 i == Ydirt_eat ? action :
5343 i == Xsand_stonein_1 ? action :
5344 i == Xsand_stonein_2 ? action :
5345 i == Xsand_stonein_3 ? action :
5346 i == Xsand_stonein_4 ? action :
5347 i == Xsand_stoneout_1 ? action :
5348 i == Xsand_stoneout_2 ? action :
5349 i == Xboom_android ? ACTION_EXPLODING :
5350 action_exploding ? ACTION_EXPLODING :
5351 action_active ? action :
5352 action_other ? action :
5354 int graphic = (el_act_dir2img(effective_element, effective_action,
5356 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5358 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5359 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5360 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5361 struct GraphicInfo *g = &graphic_info[graphic];
5362 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5365 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5366 boolean special_animation = (action != ACTION_DEFAULT &&
5367 g->anim_frames == 3 &&
5368 g->anim_delay == 2 &&
5369 g->anim_mode & ANIM_LINEAR);
5370 int sync_frame = (i == Xdrip_stretch ? 7 :
5371 i == Xdrip_stretchB ? 7 :
5372 i == Ydrip_s2 ? j + 8 :
5373 i == Ydrip_s2B ? j + 8 :
5382 i == Xfake_acid_1 ? 0 :
5383 i == Xfake_acid_2 ? 10 :
5384 i == Xfake_acid_3 ? 20 :
5385 i == Xfake_acid_4 ? 30 :
5386 i == Xfake_acid_5 ? 40 :
5387 i == Xfake_acid_6 ? 50 :
5388 i == Xfake_acid_7 ? 60 :
5389 i == Xfake_acid_8 ? 70 :
5391 i == Xball_2B ? j + 8 :
5392 i == Yball_eat ? j + 1 :
5393 i == Ykey_1_eat ? j + 1 :
5394 i == Ykey_2_eat ? j + 1 :
5395 i == Ykey_3_eat ? j + 1 :
5396 i == Ykey_4_eat ? j + 1 :
5397 i == Ykey_5_eat ? j + 1 :
5398 i == Ykey_6_eat ? j + 1 :
5399 i == Ykey_7_eat ? j + 1 :
5400 i == Ykey_8_eat ? j + 1 :
5401 i == Ylenses_eat ? j + 1 :
5402 i == Ymagnify_eat ? j + 1 :
5403 i == Ygrass_eat ? j + 1 :
5404 i == Ydirt_eat ? j + 1 :
5405 i == Xamoeba_1 ? 0 :
5406 i == Xamoeba_2 ? 1 :
5407 i == Xamoeba_3 ? 2 :
5408 i == Xamoeba_4 ? 3 :
5409 i == Xamoeba_5 ? 0 :
5410 i == Xamoeba_6 ? 1 :
5411 i == Xamoeba_7 ? 2 :
5412 i == Xamoeba_8 ? 3 :
5413 i == Xexit_2 ? j + 8 :
5414 i == Xexit_3 ? j + 16 :
5415 i == Xdynamite_1 ? 0 :
5416 i == Xdynamite_2 ? 8 :
5417 i == Xdynamite_3 ? 16 :
5418 i == Xdynamite_4 ? 24 :
5419 i == Xsand_stonein_1 ? j + 1 :
5420 i == Xsand_stonein_2 ? j + 9 :
5421 i == Xsand_stonein_3 ? j + 17 :
5422 i == Xsand_stonein_4 ? j + 25 :
5423 i == Xsand_stoneout_1 && j == 0 ? 0 :
5424 i == Xsand_stoneout_1 && j == 1 ? 0 :
5425 i == Xsand_stoneout_1 && j == 2 ? 1 :
5426 i == Xsand_stoneout_1 && j == 3 ? 2 :
5427 i == Xsand_stoneout_1 && j == 4 ? 2 :
5428 i == Xsand_stoneout_1 && j == 5 ? 3 :
5429 i == Xsand_stoneout_1 && j == 6 ? 4 :
5430 i == Xsand_stoneout_1 && j == 7 ? 4 :
5431 i == Xsand_stoneout_2 && j == 0 ? 5 :
5432 i == Xsand_stoneout_2 && j == 1 ? 6 :
5433 i == Xsand_stoneout_2 && j == 2 ? 7 :
5434 i == Xsand_stoneout_2 && j == 3 ? 8 :
5435 i == Xsand_stoneout_2 && j == 4 ? 9 :
5436 i == Xsand_stoneout_2 && j == 5 ? 11 :
5437 i == Xsand_stoneout_2 && j == 6 ? 13 :
5438 i == Xsand_stoneout_2 && j == 7 ? 15 :
5439 i == Xboom_bug && j == 1 ? 2 :
5440 i == Xboom_bug && j == 2 ? 2 :
5441 i == Xboom_bug && j == 3 ? 4 :
5442 i == Xboom_bug && j == 4 ? 4 :
5443 i == Xboom_bug && j == 5 ? 2 :
5444 i == Xboom_bug && j == 6 ? 2 :
5445 i == Xboom_bug && j == 7 ? 0 :
5446 i == Xboom_bomb && j == 1 ? 2 :
5447 i == Xboom_bomb && j == 2 ? 2 :
5448 i == Xboom_bomb && j == 3 ? 4 :
5449 i == Xboom_bomb && j == 4 ? 4 :
5450 i == Xboom_bomb && j == 5 ? 2 :
5451 i == Xboom_bomb && j == 6 ? 2 :
5452 i == Xboom_bomb && j == 7 ? 0 :
5453 i == Xboom_android && j == 7 ? 6 :
5454 i == Xboom_1 && j == 1 ? 2 :
5455 i == Xboom_1 && j == 2 ? 2 :
5456 i == Xboom_1 && j == 3 ? 4 :
5457 i == Xboom_1 && j == 4 ? 4 :
5458 i == Xboom_1 && j == 5 ? 6 :
5459 i == Xboom_1 && j == 6 ? 6 :
5460 i == Xboom_1 && j == 7 ? 8 :
5461 i == Xboom_2 && j == 0 ? 8 :
5462 i == Xboom_2 && j == 1 ? 8 :
5463 i == Xboom_2 && j == 2 ? 10 :
5464 i == Xboom_2 && j == 3 ? 10 :
5465 i == Xboom_2 && j == 4 ? 10 :
5466 i == Xboom_2 && j == 5 ? 12 :
5467 i == Xboom_2 && j == 6 ? 12 :
5468 i == Xboom_2 && j == 7 ? 12 :
5469 special_animation && j == 4 ? 3 :
5470 effective_action != action ? 0 :
5474 Bitmap *debug_bitmap = g_em->bitmap;
5475 int debug_src_x = g_em->src_x;
5476 int debug_src_y = g_em->src_y;
5479 int frame = getAnimationFrame(g->anim_frames,
5482 g->anim_start_frame,
5485 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5486 g->double_movement && is_backside);
5488 g_em->bitmap = src_bitmap;
5489 g_em->src_x = src_x;
5490 g_em->src_y = src_y;
5491 g_em->src_offset_x = 0;
5492 g_em->src_offset_y = 0;
5493 g_em->dst_offset_x = 0;
5494 g_em->dst_offset_y = 0;
5495 g_em->width = TILEX;
5496 g_em->height = TILEY;
5498 g_em->crumbled_bitmap = NULL;
5499 g_em->crumbled_src_x = 0;
5500 g_em->crumbled_src_y = 0;
5501 g_em->crumbled_border_size = 0;
5503 g_em->has_crumbled_graphics = FALSE;
5504 g_em->preserve_background = FALSE;
5507 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5508 printf("::: empty crumbled: %d [%s], %d, %d\n",
5509 effective_element, element_info[effective_element].token_name,
5510 effective_action, direction);
5513 /* if element can be crumbled, but certain action graphics are just empty
5514 space (like snapping sand with the original R'n'D graphics), do not
5515 treat these empty space graphics as crumbled graphics in EMC engine */
5516 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5518 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5520 g_em->has_crumbled_graphics = TRUE;
5521 g_em->crumbled_bitmap = src_bitmap;
5522 g_em->crumbled_src_x = src_x;
5523 g_em->crumbled_src_y = src_y;
5524 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5527 if (!g->double_movement && (effective_action == ACTION_FALLING ||
5528 effective_action == ACTION_MOVING ||
5529 effective_action == ACTION_PUSHING ||
5530 effective_action == ACTION_EATING))
5533 (effective_action == ACTION_FALLING ? MV_DOWN : direction);
5534 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5535 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5536 int num_steps = (i == Ydrip_s1 ||
5539 i == Ydrip_s2B ? 16 : 8);
5540 int cx = ABS(dx) * (TILEX / num_steps);
5541 int cy = ABS(dy) * (TILEY / num_steps);
5542 int step_frame = (i == Ydrip_s2 ||
5543 i == Ydrip_s2B ? j + 8 : j) + 1;
5544 int step = (is_backside ? step_frame : num_steps - step_frame);
5546 if (is_backside) /* tile where movement starts */
5548 if (dx < 0 || dy < 0)
5550 g_em->src_offset_x = cx * step;
5551 g_em->src_offset_y = cy * step;
5555 g_em->dst_offset_x = cx * step;
5556 g_em->dst_offset_y = cy * step;
5559 else /* tile where movement ends */
5561 if (dx < 0 || dy < 0)
5563 g_em->dst_offset_x = cx * step;
5564 g_em->dst_offset_y = cy * step;
5568 g_em->src_offset_x = cx * step;
5569 g_em->src_offset_y = cy * step;
5573 g_em->width = TILEX - cx * step;
5574 g_em->height = TILEY - cy * step;
5578 /* create unique graphic identifier to decide if tile must be redrawn */
5579 /* bit 31 - 16 (16 bit): EM style graphic
5580 bit 15 - 12 ( 4 bit): EM style frame
5581 bit 11 - 6 ( 6 bit): graphic width
5582 bit 5 - 0 ( 6 bit): graphic height */
5583 g_em->unique_identifier =
5584 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5586 /* create unique graphic identifier to decide if tile must be redrawn */
5587 /* bit 31 - 16 (16 bit): EM style element
5588 bit 15 - 12 ( 4 bit): EM style frame
5589 bit 11 - 6 ( 6 bit): graphic width
5590 bit 5 - 0 ( 6 bit): graphic height */
5591 g_em->unique_identifier =
5592 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5596 if (effective_element == EL_ROCK)
5597 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5598 effective_action, j, graphic, frame, g_em->unique_identifier);
5604 /* skip check for EMC elements not contained in original EMC artwork */
5605 if (element == EL_EMC_FAKE_ACID)
5609 if (g_em->bitmap != debug_bitmap ||
5610 g_em->src_x != debug_src_x ||
5611 g_em->src_y != debug_src_y ||
5612 g_em->src_offset_x != 0 ||
5613 g_em->src_offset_y != 0 ||
5614 g_em->dst_offset_x != 0 ||
5615 g_em->dst_offset_y != 0 ||
5616 g_em->width != TILEX ||
5617 g_em->height != TILEY)
5619 static int last_i = -1;
5627 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5628 i, element, element_info[element].token_name,
5629 element_action_info[effective_action].suffix, direction);
5631 if (element != effective_element)
5632 printf(" [%d ('%s')]",
5634 element_info[effective_element].token_name);
5638 if (g_em->bitmap != debug_bitmap)
5639 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5640 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5642 if (g_em->src_x != debug_src_x ||
5643 g_em->src_y != debug_src_y)
5644 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5645 j, (is_backside ? 'B' : 'F'),
5646 g_em->src_x, g_em->src_y,
5647 g_em->src_x / 32, g_em->src_y / 32,
5648 debug_src_x, debug_src_y,
5649 debug_src_x / 32, debug_src_y / 32);
5651 if (g_em->src_offset_x != 0 ||
5652 g_em->src_offset_y != 0 ||
5653 g_em->dst_offset_x != 0 ||
5654 g_em->dst_offset_y != 0)
5655 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5657 g_em->src_offset_x, g_em->src_offset_y,
5658 g_em->dst_offset_x, g_em->dst_offset_y);
5660 if (g_em->width != TILEX ||
5661 g_em->height != TILEY)
5662 printf(" %d (%d): size %d,%d should be %d,%d\n",
5664 g_em->width, g_em->height, TILEX, TILEY);
5671 for (i = 0; i < TILE_MAX; i++)
5673 for (j = 0; j < 8; j++)
5675 int element = object_mapping[i].element_rnd;
5676 int action = object_mapping[i].action;
5677 int direction = object_mapping[i].direction;
5678 boolean is_backside = object_mapping[i].is_backside;
5680 int graphic_action = el_act_dir2img(element, action, direction);
5681 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5683 int graphic_action = element_info[element].graphic[action];
5684 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5687 if ((action == ACTION_SMASHED_BY_ROCK ||
5688 action == ACTION_SMASHED_BY_SPRING ||
5689 action == ACTION_EATING) &&
5690 graphic_action == graphic_default)
5692 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5693 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5694 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5695 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5698 /* no separate animation for "smashed by rock" -- use rock instead */
5699 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5700 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5702 g_em->bitmap = g_xx->bitmap;
5703 g_em->src_x = g_xx->src_x;
5704 g_em->src_y = g_xx->src_y;
5705 g_em->src_offset_x = g_xx->src_offset_x;
5706 g_em->src_offset_y = g_xx->src_offset_y;
5707 g_em->dst_offset_x = g_xx->dst_offset_x;
5708 g_em->dst_offset_y = g_xx->dst_offset_y;
5709 g_em->width = g_xx->width;
5710 g_em->height = g_xx->height;
5712 g_em->unique_identifier = g_xx->unique_identifier;
5716 g_em->preserve_background = TRUE;
5721 for (p = 0; p < MAX_PLAYERS; p++)
5723 for (i = 0; i < SPR_MAX; i++)
5725 int element = player_mapping[p][i].element_rnd;
5726 int action = player_mapping[p][i].action;
5727 int direction = player_mapping[p][i].direction;
5729 for (j = 0; j < 8; j++)
5731 int effective_element = element;
5732 int effective_action = action;
5733 int graphic = (direction == MV_NONE ?
5734 el_act2img(effective_element, effective_action) :
5735 el_act_dir2img(effective_element, effective_action,
5737 struct GraphicInfo *g = &graphic_info[graphic];
5738 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5744 Bitmap *debug_bitmap = g_em->bitmap;
5745 int debug_src_x = g_em->src_x;
5746 int debug_src_y = g_em->src_y;
5749 int frame = getAnimationFrame(g->anim_frames,
5752 g->anim_start_frame,
5755 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5757 g_em->bitmap = src_bitmap;
5758 g_em->src_x = src_x;
5759 g_em->src_y = src_y;
5760 g_em->src_offset_x = 0;
5761 g_em->src_offset_y = 0;
5762 g_em->dst_offset_x = 0;
5763 g_em->dst_offset_y = 0;
5764 g_em->width = TILEX;
5765 g_em->height = TILEY;
5770 /* skip check for EMC elements not contained in original EMC artwork */
5771 if (element == EL_PLAYER_3 ||
5772 element == EL_PLAYER_4)
5776 if (g_em->bitmap != debug_bitmap ||
5777 g_em->src_x != debug_src_x ||
5778 g_em->src_y != debug_src_y)
5780 static int last_i = -1;
5788 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5789 p, i, element, element_info[element].token_name,
5790 element_action_info[effective_action].suffix, direction);
5792 if (element != effective_element)
5793 printf(" [%d ('%s')]",
5795 element_info[effective_element].token_name);
5799 if (g_em->bitmap != debug_bitmap)
5800 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5801 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5803 if (g_em->src_x != debug_src_x ||
5804 g_em->src_y != debug_src_y)
5805 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5807 g_em->src_x, g_em->src_y,
5808 g_em->src_x / 32, g_em->src_y / 32,
5809 debug_src_x, debug_src_y,
5810 debug_src_x / 32, debug_src_y / 32);