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"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
150 width = gfx.sxsize + 2 * TILEX;
151 height = gfx.sysize + 2 * TILEY;
154 if (force_redraw || setup.direct_draw)
157 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
158 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
160 if (setup.direct_draw)
161 SetDrawtoField(DRAW_BACKBUFFER);
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
169 if (setup.direct_draw)
170 SetDrawtoField(DRAW_DIRECT);
173 if (setup.soft_scrolling)
175 int fx = FX, fy = FY;
177 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
178 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
180 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
184 BlitBitmap(drawto, window, x, y, width, height, x, y);
190 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
192 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
193 redraw_mask &= ~REDRAW_MAIN;
195 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
196 redraw_mask |= REDRAW_FIELD;
198 if (redraw_mask & REDRAW_FIELD)
199 redraw_mask &= ~REDRAW_TILES;
201 if (redraw_mask == REDRAW_NONE)
204 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
206 static boolean last_frame_skipped = FALSE;
207 boolean skip_even_when_not_scrolling = TRUE;
208 boolean just_scrolling = (ScreenMovDir != 0);
209 boolean verbose = FALSE;
211 if (global.fps_slowdown_factor > 1 &&
212 (FrameCounter % global.fps_slowdown_factor) &&
213 (just_scrolling || skip_even_when_not_scrolling))
215 redraw_mask &= ~REDRAW_MAIN;
217 last_frame_skipped = TRUE;
220 printf("FRAME SKIPPED\n");
224 if (last_frame_skipped)
225 redraw_mask |= REDRAW_FIELD;
227 last_frame_skipped = FALSE;
230 printf("frame not skipped\n");
234 /* synchronize X11 graphics at this point; if we would synchronize the
235 display immediately after the buffer switching (after the XFlush),
236 this could mean that we have to wait for the graphics to complete,
237 although we could go on doing calculations for the next frame */
241 if (redraw_mask & REDRAW_ALL)
243 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
245 redraw_mask = REDRAW_NONE;
248 if (redraw_mask & REDRAW_FIELD)
250 if (game_status != GAME_MODE_PLAYING ||
251 redraw_mask & REDRAW_FROM_BACKBUFFER)
253 BlitBitmap(backbuffer, window,
254 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
258 int fx = FX, fy = FY;
260 if (setup.soft_scrolling)
262 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
263 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
266 if (setup.soft_scrolling ||
267 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
268 ABS(ScreenMovPos) == ScrollStepSize ||
269 redraw_tiles > REDRAWTILES_THRESHOLD)
271 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
275 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
277 (setup.soft_scrolling ?
278 "setup.soft_scrolling" :
279 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
280 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
281 ABS(ScreenGfxPos) == ScrollStepSize ?
282 "ABS(ScreenGfxPos) == ScrollStepSize" :
283 "redraw_tiles > REDRAWTILES_THRESHOLD"));
289 redraw_mask &= ~REDRAW_MAIN;
292 if (redraw_mask & REDRAW_DOORS)
294 if (redraw_mask & REDRAW_DOOR_1)
295 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
297 if (redraw_mask & REDRAW_DOOR_2)
298 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
300 if (redraw_mask & REDRAW_DOOR_3)
301 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
303 redraw_mask &= ~REDRAW_DOORS;
306 if (redraw_mask & REDRAW_MICROLEVEL)
308 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
309 SX, SY + 10 * TILEY);
311 redraw_mask &= ~REDRAW_MICROLEVEL;
314 if (redraw_mask & REDRAW_TILES)
316 for (x = 0; x < SCR_FIELDX; x++)
317 for (y = 0 ; y < SCR_FIELDY; y++)
318 if (redraw[redraw_x1 + x][redraw_y1 + y])
319 BlitBitmap(buffer, window,
320 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
321 SX + x * TILEX, SY + y * TILEY);
324 if (redraw_mask & REDRAW_FPS) /* display frames per second */
329 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
330 if (!global.fps_slowdown)
333 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
334 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
339 for (x = 0; x < MAX_BUF_XSIZE; x++)
340 for (y = 0; y < MAX_BUF_YSIZE; y++)
343 redraw_mask = REDRAW_NONE;
349 long fading_delay = 300;
351 if (setup.fading && (redraw_mask & REDRAW_FIELD))
358 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
361 for (i = 0; i < 2 * FULL_SYSIZE; i++)
363 for (y = 0; y < FULL_SYSIZE; y++)
365 BlitBitmap(backbuffer, window,
366 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
374 for (i = 1; i < FULL_SYSIZE; i+=2)
375 BlitBitmap(backbuffer, window,
376 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
382 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
383 BlitBitmapMasked(backbuffer, window,
384 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
389 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
390 BlitBitmapMasked(backbuffer, window,
391 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
396 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
397 BlitBitmapMasked(backbuffer, window,
398 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
403 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
404 BlitBitmapMasked(backbuffer, window,
405 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
410 redraw_mask &= ~REDRAW_MAIN;
417 void FadeIn(int fade_delay)
419 FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
421 redraw_mask = REDRAW_NONE;
424 void FadeOut(int fade_delay, int post_delay)
426 FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
428 redraw_mask = REDRAW_NONE;
431 void FadeCross(Bitmap *bitmap, int fade_delay)
433 FadeScreen(bitmap, FADE_MODE_CROSSFADE, fade_delay, 0);
435 redraw_mask = REDRAW_NONE;
438 void SetMainBackgroundImageIfDefined(int graphic)
440 if (graphic_info[graphic].bitmap)
441 SetMainBackgroundImage(graphic);
444 void SetMainBackgroundImage(int graphic)
446 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
447 graphic_info[graphic].bitmap ?
448 graphic_info[graphic].bitmap :
449 graphic_info[IMG_BACKGROUND].bitmap);
452 void SetDoorBackgroundImage(int graphic)
454 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
455 graphic_info[graphic].bitmap ?
456 graphic_info[graphic].bitmap :
457 graphic_info[IMG_BACKGROUND].bitmap);
460 void DrawBackground(int dst_x, int dst_y, int width, int height)
462 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
464 redraw_mask |= REDRAW_FIELD;
469 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
471 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
473 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
474 SetDrawtoField(DRAW_BUFFERED);
477 SetDrawtoField(DRAW_BACKBUFFER);
479 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
481 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
482 SetDrawtoField(DRAW_DIRECT);
486 void MarkTileDirty(int x, int y)
488 int xx = redraw_x1 + x;
489 int yy = redraw_y1 + y;
494 redraw[xx][yy] = TRUE;
495 redraw_mask |= REDRAW_TILES;
498 void SetBorderElement()
502 BorderElement = EL_EMPTY;
504 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
506 for (x = 0; x < lev_fieldx; x++)
508 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
509 BorderElement = EL_STEELWALL;
511 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
517 void SetRandomAnimationValue(int x, int y)
519 gfx.anim_random_frame = GfxRandom[x][y];
522 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
524 /* animation synchronized with global frame counter, not move position */
525 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
526 sync_frame = FrameCounter;
529 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
535 printf("::: FOO!\n");
539 return getAnimationFrame(graphic_info[graphic].anim_frames,
540 graphic_info[graphic].anim_delay,
541 graphic_info[graphic].anim_mode,
542 graphic_info[graphic].anim_start_frame,
546 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
547 int *x, int *y, boolean get_backside)
549 struct GraphicInfo *g = &graphic_info[graphic];
550 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
551 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
555 if (g->offset_y == 0) /* frames are ordered horizontally */
557 int max_width = g->anim_frames_per_line * g->width;
558 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
560 *x = pos % max_width;
561 *y = src_y % g->height + pos / max_width * g->height;
563 else if (g->offset_x == 0) /* frames are ordered vertically */
565 int max_height = g->anim_frames_per_line * g->height;
566 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
568 *x = src_x % g->width + pos / max_height * g->width;
569 *y = pos % max_height;
571 else /* frames are ordered diagonally */
573 *x = src_x + frame * g->offset_x;
574 *y = src_y + frame * g->offset_y;
578 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
580 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
583 void DrawGraphic(int x, int y, int graphic, int frame)
586 if (!IN_SCR_FIELD(x, y))
588 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
589 printf("DrawGraphic(): This should never happen!\n");
594 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
598 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
604 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
605 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
608 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
611 if (!IN_SCR_FIELD(x, y))
613 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
614 printf("DrawGraphicThruMask(): This should never happen!\n");
619 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
624 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
630 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
632 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
633 dst_x - src_x, dst_y - src_y);
634 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
637 void DrawMiniGraphic(int x, int y, int graphic)
639 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
640 MarkTileDirty(x / 2, y / 2);
643 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
645 struct GraphicInfo *g = &graphic_info[graphic];
647 int mini_starty = g->bitmap->height * 2 / 3;
650 *x = mini_startx + g->src_x / 2;
651 *y = mini_starty + g->src_y / 2;
654 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
659 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
660 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
663 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
664 int graphic, int frame,
665 int cut_mode, int mask_mode)
670 int width = TILEX, height = TILEY;
673 if (dx || dy) /* shifted graphic */
675 if (x < BX1) /* object enters playfield from the left */
682 else if (x > BX2) /* object enters playfield from the right */
688 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
694 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
696 else if (dx) /* general horizontal movement */
697 MarkTileDirty(x + SIGN(dx), y);
699 if (y < BY1) /* object enters playfield from the top */
701 if (cut_mode==CUT_BELOW) /* object completely above top border */
709 else if (y > BY2) /* object enters playfield from the bottom */
715 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
721 else if (dy > 0 && cut_mode == CUT_ABOVE)
723 if (y == BY2) /* object completely above bottom border */
729 MarkTileDirty(x, y + 1);
730 } /* object leaves playfield to the bottom */
731 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
733 else if (dy) /* general vertical movement */
734 MarkTileDirty(x, y + SIGN(dy));
738 if (!IN_SCR_FIELD(x, y))
740 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
741 printf("DrawGraphicShifted(): This should never happen!\n");
746 if (width > 0 && height > 0)
748 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
753 dst_x = FX + x * TILEX + dx;
754 dst_y = FY + y * TILEY + dy;
756 if (mask_mode == USE_MASKING)
758 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
759 dst_x - src_x, dst_y - src_y);
760 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
764 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
771 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
772 int graphic, int frame,
773 int cut_mode, int mask_mode)
778 int width = TILEX, height = TILEY;
781 int x2 = x + SIGN(dx);
782 int y2 = y + SIGN(dy);
783 int anim_frames = graphic_info[graphic].anim_frames;
784 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
785 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
786 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
788 /* re-calculate animation frame for two-tile movement animation */
789 frame = getGraphicAnimationFrame(graphic, sync_frame);
791 /* check if movement start graphic inside screen area and should be drawn */
792 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
794 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
796 dst_x = FX + x1 * TILEX;
797 dst_y = FY + y1 * TILEY;
799 if (mask_mode == USE_MASKING)
801 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
802 dst_x - src_x, dst_y - src_y);
803 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
807 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
810 MarkTileDirty(x1, y1);
813 /* check if movement end graphic inside screen area and should be drawn */
814 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
816 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
818 dst_x = FX + x2 * TILEX;
819 dst_y = FY + y2 * TILEY;
821 if (mask_mode == USE_MASKING)
823 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
824 dst_x - src_x, dst_y - src_y);
825 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
829 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
832 MarkTileDirty(x2, y2);
836 static void DrawGraphicShifted(int x, int y, int dx, int dy,
837 int graphic, int frame,
838 int cut_mode, int mask_mode)
842 DrawGraphic(x, y, graphic, frame);
847 if (graphic_info[graphic].double_movement) /* EM style movement images */
848 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
850 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
853 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
854 int frame, int cut_mode)
856 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
859 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
860 int cut_mode, int mask_mode)
862 int lx = LEVELX(x), ly = LEVELY(y);
866 if (IN_LEV_FIELD(lx, ly))
868 SetRandomAnimationValue(lx, ly);
870 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
871 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
873 /* do not use double (EM style) movement graphic when not moving */
874 if (graphic_info[graphic].double_movement && !dx && !dy)
876 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
877 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
880 else /* border element */
882 graphic = el2img(element);
883 frame = getGraphicAnimationFrame(graphic, -1);
886 if (element == EL_EXPANDABLE_WALL)
888 boolean left_stopped = FALSE, right_stopped = FALSE;
890 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
892 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
893 right_stopped = TRUE;
895 if (left_stopped && right_stopped)
897 else if (left_stopped)
899 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
900 frame = graphic_info[graphic].anim_frames - 1;
902 else if (right_stopped)
904 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
905 frame = graphic_info[graphic].anim_frames - 1;
910 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
911 else if (mask_mode == USE_MASKING)
912 DrawGraphicThruMask(x, y, graphic, frame);
914 DrawGraphic(x, y, graphic, frame);
917 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
918 int cut_mode, int mask_mode)
920 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
921 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
922 cut_mode, mask_mode);
925 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
928 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
931 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
934 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
937 void DrawLevelElementThruMask(int x, int y, int element)
939 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
942 void DrawLevelFieldThruMask(int x, int y)
944 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
947 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
951 int sx = SCREENX(x), sy = SCREENY(y);
953 int width, height, cx, cy, i;
954 int crumbled_border_size = graphic_info[graphic].border_size;
955 static int xy[4][2] =
963 if (!IN_LEV_FIELD(x, y))
966 element = TILE_GFX_ELEMENT(x, y);
968 /* crumble field itself */
969 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
971 if (!IN_SCR_FIELD(sx, sy))
974 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
976 for (i = 0; i < 4; i++)
978 int xx = x + xy[i][0];
979 int yy = y + xy[i][1];
981 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
984 /* check if neighbour field is of same type */
985 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
988 if (i == 1 || i == 2)
990 width = crumbled_border_size;
992 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
998 height = crumbled_border_size;
1000 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1003 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1004 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1007 MarkTileDirty(sx, sy);
1009 else /* crumble neighbour fields */
1011 for (i = 0; i < 4; i++)
1013 int xx = x + xy[i][0];
1014 int yy = y + xy[i][1];
1015 int sxx = sx + xy[i][0];
1016 int syy = sy + xy[i][1];
1019 if (!IN_LEV_FIELD(xx, yy) ||
1020 !IN_SCR_FIELD(sxx, syy) ||
1025 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1029 element = TILE_GFX_ELEMENT(xx, yy);
1031 if (!GFX_CRUMBLED(element))
1034 if (!IN_LEV_FIELD(xx, yy) ||
1035 !IN_SCR_FIELD(sxx, syy) ||
1036 !GFX_CRUMBLED(Feld[xx][yy]) ||
1042 graphic = el_act2crm(element, ACTION_DEFAULT);
1044 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1046 crumbled_border_size = graphic_info[graphic].border_size;
1048 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1050 if (i == 1 || i == 2)
1052 width = crumbled_border_size;
1054 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1060 height = crumbled_border_size;
1062 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1065 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1066 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1068 MarkTileDirty(sxx, syy);
1073 void DrawLevelFieldCrumbledSand(int x, int y)
1077 if (!IN_LEV_FIELD(x, y))
1081 /* !!! CHECK THIS !!! */
1084 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1085 GFX_CRUMBLED(GfxElement[x][y]))
1088 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1089 GfxElement[x][y] != EL_UNDEFINED &&
1090 GFX_CRUMBLED(GfxElement[x][y]))
1092 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1099 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1101 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1104 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1107 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1110 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1111 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1112 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1113 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1114 int sx = SCREENX(x), sy = SCREENY(y);
1116 DrawGraphic(sx, sy, graphic1, frame1);
1117 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1120 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1122 int sx = SCREENX(x), sy = SCREENY(y);
1123 static int xy[4][2] =
1132 for (i = 0; i < 4; i++)
1134 int xx = x + xy[i][0];
1135 int yy = y + xy[i][1];
1136 int sxx = sx + xy[i][0];
1137 int syy = sy + xy[i][1];
1139 if (!IN_LEV_FIELD(xx, yy) ||
1140 !IN_SCR_FIELD(sxx, syy) ||
1141 !GFX_CRUMBLED(Feld[xx][yy]) ||
1145 DrawLevelField(xx, yy);
1149 static int getBorderElement(int x, int y)
1153 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1154 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1155 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1156 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1157 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1158 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1159 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1161 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1162 int steel_position = (x == -1 && y == -1 ? 0 :
1163 x == lev_fieldx && y == -1 ? 1 :
1164 x == -1 && y == lev_fieldy ? 2 :
1165 x == lev_fieldx && y == lev_fieldy ? 3 :
1166 x == -1 || x == lev_fieldx ? 4 :
1167 y == -1 || y == lev_fieldy ? 5 : 6);
1169 return border[steel_position][steel_type];
1172 void DrawScreenElement(int x, int y, int element)
1174 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1175 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1178 void DrawLevelElement(int x, int y, int element)
1180 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1181 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1184 void DrawScreenField(int x, int y)
1186 int lx = LEVELX(x), ly = LEVELY(y);
1187 int element, content;
1189 if (!IN_LEV_FIELD(lx, ly))
1191 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1194 element = getBorderElement(lx, ly);
1196 DrawScreenElement(x, y, element);
1200 element = Feld[lx][ly];
1201 content = Store[lx][ly];
1203 if (IS_MOVING(lx, ly))
1205 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1206 boolean cut_mode = NO_CUTTING;
1208 if (element == EL_QUICKSAND_EMPTYING ||
1209 element == EL_MAGIC_WALL_EMPTYING ||
1210 element == EL_BD_MAGIC_WALL_EMPTYING ||
1211 element == EL_AMOEBA_DROPPING)
1212 cut_mode = CUT_ABOVE;
1213 else if (element == EL_QUICKSAND_FILLING ||
1214 element == EL_MAGIC_WALL_FILLING ||
1215 element == EL_BD_MAGIC_WALL_FILLING)
1216 cut_mode = CUT_BELOW;
1218 if (cut_mode == CUT_ABOVE)
1219 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1221 DrawScreenElement(x, y, EL_EMPTY);
1224 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1225 else if (cut_mode == NO_CUTTING)
1226 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1228 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1230 if (content == EL_ACID)
1232 int dir = MovDir[lx][ly];
1233 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1234 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1236 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1239 else if (IS_BLOCKED(lx, ly))
1244 boolean cut_mode = NO_CUTTING;
1245 int element_old, content_old;
1247 Blocked2Moving(lx, ly, &oldx, &oldy);
1250 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1251 MovDir[oldx][oldy] == MV_RIGHT);
1253 element_old = Feld[oldx][oldy];
1254 content_old = Store[oldx][oldy];
1256 if (element_old == EL_QUICKSAND_EMPTYING ||
1257 element_old == EL_MAGIC_WALL_EMPTYING ||
1258 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1259 element_old == EL_AMOEBA_DROPPING)
1260 cut_mode = CUT_ABOVE;
1262 DrawScreenElement(x, y, EL_EMPTY);
1265 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1267 else if (cut_mode == NO_CUTTING)
1268 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1271 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1274 else if (IS_DRAWABLE(element))
1275 DrawScreenElement(x, y, element);
1277 DrawScreenElement(x, y, EL_EMPTY);
1280 void DrawLevelField(int x, int y)
1282 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1283 DrawScreenField(SCREENX(x), SCREENY(y));
1284 else if (IS_MOVING(x, y))
1288 Moving2Blocked(x, y, &newx, &newy);
1289 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1290 DrawScreenField(SCREENX(newx), SCREENY(newy));
1292 else if (IS_BLOCKED(x, y))
1296 Blocked2Moving(x, y, &oldx, &oldy);
1297 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1298 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1302 void DrawMiniElement(int x, int y, int element)
1306 graphic = el2edimg(element);
1307 DrawMiniGraphic(x, y, graphic);
1310 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1312 int x = sx + scroll_x, y = sy + scroll_y;
1314 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1315 DrawMiniElement(sx, sy, EL_EMPTY);
1316 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1317 DrawMiniElement(sx, sy, Feld[x][y]);
1319 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1322 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1323 int x, int y, int xsize, int ysize, int font_nr)
1325 int font_width = getFontWidth(font_nr);
1326 int font_height = getFontHeight(font_nr);
1327 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1330 int dst_x = SX + startx + x * font_width;
1331 int dst_y = SY + starty + y * font_height;
1332 int width = graphic_info[graphic].width;
1333 int height = graphic_info[graphic].height;
1334 int inner_width = MAX(width - 2 * font_width, font_width);
1335 int inner_height = MAX(height - 2 * font_height, font_height);
1336 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1337 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1338 boolean draw_masked = graphic_info[graphic].draw_masked;
1340 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1342 if (src_bitmap == NULL || width < font_width || height < font_height)
1344 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1348 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1349 inner_sx + (x - 1) * font_width % inner_width);
1350 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1351 inner_sy + (y - 1) * font_height % inner_height);
1355 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1356 dst_x - src_x, dst_y - src_y);
1357 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1361 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1365 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1367 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1368 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1369 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1370 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1371 boolean no_delay = (tape.warp_forward);
1372 unsigned long anim_delay = 0;
1373 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1374 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1375 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1376 int font_width = getFontWidth(font_nr);
1377 int font_height = getFontHeight(font_nr);
1378 int max_xsize = level.envelope_xsize[envelope_nr];
1379 int max_ysize = level.envelope_ysize[envelope_nr];
1380 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1381 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1382 int xend = max_xsize;
1383 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1384 int xstep = (xstart < xend ? 1 : 0);
1385 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1388 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1390 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1391 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1392 int sx = (SXSIZE - xsize * font_width) / 2;
1393 int sy = (SYSIZE - ysize * font_height) / 2;
1396 SetDrawtoField(DRAW_BUFFERED);
1398 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1400 SetDrawtoField(DRAW_BACKBUFFER);
1402 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1403 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1405 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1406 level.envelope_text[envelope_nr], font_nr, max_xsize,
1407 xsize - 2, ysize - 2, mask_mode);
1409 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1412 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1416 void ShowEnvelope(int envelope_nr)
1418 int element = EL_ENVELOPE_1 + envelope_nr;
1419 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1420 int sound_opening = element_info[element].sound[ACTION_OPENING];
1421 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1422 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1423 boolean no_delay = (tape.warp_forward);
1424 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1425 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1426 int anim_mode = graphic_info[graphic].anim_mode;
1427 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1428 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1430 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1432 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1434 if (anim_mode == ANIM_DEFAULT)
1435 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1437 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1440 Delay(wait_delay_value);
1442 WaitForEventToContinue();
1444 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1446 if (anim_mode != ANIM_NONE)
1447 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1449 if (anim_mode == ANIM_DEFAULT)
1450 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1452 game.envelope_active = FALSE;
1454 SetDrawtoField(DRAW_BUFFERED);
1456 redraw_mask |= REDRAW_FIELD;
1460 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1462 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1463 int mini_startx = src_bitmap->width * 3 / 4;
1464 int mini_starty = src_bitmap->height * 2 / 3;
1465 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1466 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1468 *bitmap = src_bitmap;
1473 void DrawMicroElement(int xpos, int ypos, int element)
1477 int graphic = el2preimg(element);
1479 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1480 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1488 SetDrawBackgroundMask(REDRAW_NONE);
1491 for (x = BX1; x <= BX2; x++)
1492 for (y = BY1; y <= BY2; y++)
1493 DrawScreenField(x, y);
1495 redraw_mask |= REDRAW_FIELD;
1498 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1502 for (x = 0; x < size_x; x++)
1503 for (y = 0; y < size_y; y++)
1504 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1506 redraw_mask |= REDRAW_FIELD;
1509 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1513 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1515 if (lev_fieldx < STD_LEV_FIELDX)
1516 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1517 if (lev_fieldy < STD_LEV_FIELDY)
1518 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1520 xpos += MICRO_TILEX;
1521 ypos += MICRO_TILEY;
1523 for (x = -1; x <= STD_LEV_FIELDX; x++)
1525 for (y = -1; y <= STD_LEV_FIELDY; y++)
1527 int lx = from_x + x, ly = from_y + y;
1529 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1530 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1531 level.field[lx][ly]);
1532 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1533 && BorderElement != EL_EMPTY)
1534 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1535 getBorderElement(lx, ly));
1539 redraw_mask |= REDRAW_MICROLEVEL;
1542 #define MICROLABEL_EMPTY 0
1543 #define MICROLABEL_LEVEL_NAME 1
1544 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1545 #define MICROLABEL_LEVEL_AUTHOR 3
1546 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1547 #define MICROLABEL_IMPORTED_FROM 5
1548 #define MICROLABEL_IMPORTED_BY_HEAD 6
1549 #define MICROLABEL_IMPORTED_BY 7
1551 static void DrawMicroLevelLabelExt(int mode)
1553 char label_text[MAX_OUTPUT_LINESIZE + 1];
1554 int max_len_label_text;
1555 int font_nr = FONT_TEXT_2;
1558 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1559 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1560 mode == MICROLABEL_IMPORTED_BY_HEAD)
1561 font_nr = FONT_TEXT_3;
1563 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1565 for (i = 0; i < max_len_label_text; i++)
1566 label_text[i] = ' ';
1567 label_text[max_len_label_text] = '\0';
1569 if (strlen(label_text) > 0)
1571 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1572 int lypos = MICROLABEL2_YPOS;
1574 DrawText(lxpos, lypos, label_text, font_nr);
1578 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1579 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1580 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1581 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1582 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1583 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1584 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1585 max_len_label_text);
1586 label_text[max_len_label_text] = '\0';
1588 if (strlen(label_text) > 0)
1590 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1591 int lypos = MICROLABEL2_YPOS;
1593 DrawText(lxpos, lypos, label_text, font_nr);
1596 redraw_mask |= REDRAW_MICROLEVEL;
1599 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1601 static unsigned long scroll_delay = 0;
1602 static unsigned long label_delay = 0;
1603 static int from_x, from_y, scroll_direction;
1604 static int label_state, label_counter;
1605 int last_game_status = game_status; /* save current game status */
1607 /* force PREVIEW font on preview level */
1608 game_status = GAME_MODE_PSEUDO_PREVIEW;
1612 from_x = from_y = 0;
1613 scroll_direction = MV_RIGHT;
1617 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1618 DrawMicroLevelLabelExt(label_state);
1620 /* initialize delay counters */
1621 DelayReached(&scroll_delay, 0);
1622 DelayReached(&label_delay, 0);
1624 if (leveldir_current->name)
1626 char label_text[MAX_OUTPUT_LINESIZE + 1];
1627 int font_nr = FONT_TEXT_1;
1628 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1631 strncpy(label_text, leveldir_current->name, max_len_label_text);
1632 label_text[max_len_label_text] = '\0';
1634 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1635 lypos = SY + MICROLABEL1_YPOS;
1637 DrawText(lxpos, lypos, label_text, font_nr);
1640 game_status = last_game_status; /* restore current game status */
1645 /* scroll micro level, if needed */
1646 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1647 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1649 switch (scroll_direction)
1655 scroll_direction = MV_UP;
1659 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1662 scroll_direction = MV_DOWN;
1669 scroll_direction = MV_RIGHT;
1673 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1676 scroll_direction = MV_LEFT;
1683 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1686 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1687 /* redraw micro level label, if needed */
1688 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1689 !strEqual(level.author, ANONYMOUS_NAME) &&
1690 !strEqual(level.author, leveldir_current->name) &&
1691 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1693 int max_label_counter = 23;
1695 if (leveldir_current->imported_from != NULL &&
1696 strlen(leveldir_current->imported_from) > 0)
1697 max_label_counter += 14;
1698 if (leveldir_current->imported_by != NULL &&
1699 strlen(leveldir_current->imported_by) > 0)
1700 max_label_counter += 14;
1702 label_counter = (label_counter + 1) % max_label_counter;
1703 label_state = (label_counter >= 0 && label_counter <= 7 ?
1704 MICROLABEL_LEVEL_NAME :
1705 label_counter >= 9 && label_counter <= 12 ?
1706 MICROLABEL_LEVEL_AUTHOR_HEAD :
1707 label_counter >= 14 && label_counter <= 21 ?
1708 MICROLABEL_LEVEL_AUTHOR :
1709 label_counter >= 23 && label_counter <= 26 ?
1710 MICROLABEL_IMPORTED_FROM_HEAD :
1711 label_counter >= 28 && label_counter <= 35 ?
1712 MICROLABEL_IMPORTED_FROM :
1713 label_counter >= 37 && label_counter <= 40 ?
1714 MICROLABEL_IMPORTED_BY_HEAD :
1715 label_counter >= 42 && label_counter <= 49 ?
1716 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1718 if (leveldir_current->imported_from == NULL &&
1719 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1720 label_state == MICROLABEL_IMPORTED_FROM))
1721 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1722 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1724 DrawMicroLevelLabelExt(label_state);
1727 game_status = last_game_status; /* restore current game status */
1730 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1731 int graphic, int sync_frame, int mask_mode)
1733 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1735 if (mask_mode == USE_MASKING)
1736 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1738 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1741 inline void DrawGraphicAnimation(int x, int y, int graphic)
1743 int lx = LEVELX(x), ly = LEVELY(y);
1745 if (!IN_SCR_FIELD(x, y))
1748 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1749 graphic, GfxFrame[lx][ly], NO_MASKING);
1750 MarkTileDirty(x, y);
1753 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1755 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1758 void DrawLevelElementAnimation(int x, int y, int element)
1760 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1762 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1765 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1767 int sx = SCREENX(x), sy = SCREENY(y);
1769 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1772 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1775 DrawGraphicAnimation(sx, sy, graphic);
1778 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1779 DrawLevelFieldCrumbledSand(x, y);
1781 if (GFX_CRUMBLED(Feld[x][y]))
1782 DrawLevelFieldCrumbledSand(x, y);
1786 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1788 int sx = SCREENX(x), sy = SCREENY(y);
1791 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1794 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1796 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1799 DrawGraphicAnimation(sx, sy, graphic);
1801 if (GFX_CRUMBLED(element))
1802 DrawLevelFieldCrumbledSand(x, y);
1805 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1807 if (player->use_murphy)
1809 /* this works only because currently only one player can be "murphy" ... */
1810 static int last_horizontal_dir = MV_LEFT;
1811 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1813 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1814 last_horizontal_dir = move_dir;
1816 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1818 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1820 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1826 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1829 static boolean equalGraphics(int graphic1, int graphic2)
1831 struct GraphicInfo *g1 = &graphic_info[graphic1];
1832 struct GraphicInfo *g2 = &graphic_info[graphic2];
1834 return (g1->bitmap == g2->bitmap &&
1835 g1->src_x == g2->src_x &&
1836 g1->src_y == g2->src_y &&
1837 g1->anim_frames == g2->anim_frames &&
1838 g1->anim_delay == g2->anim_delay &&
1839 g1->anim_mode == g2->anim_mode);
1842 void DrawAllPlayers()
1846 for (i = 0; i < MAX_PLAYERS; i++)
1847 if (stored_player[i].active)
1848 DrawPlayer(&stored_player[i]);
1851 void DrawPlayerField(int x, int y)
1853 if (!IS_PLAYER(x, y))
1856 DrawPlayer(PLAYERINFO(x, y));
1859 void DrawPlayer(struct PlayerInfo *player)
1861 int jx = player->jx;
1862 int jy = player->jy;
1863 int move_dir = player->MovDir;
1864 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1865 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1866 int last_jx = (player->is_moving ? jx - dx : jx);
1867 int last_jy = (player->is_moving ? jy - dy : jy);
1868 int next_jx = jx + dx;
1869 int next_jy = jy + dy;
1870 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1871 boolean player_is_opaque = FALSE;
1872 int sx = SCREENX(jx), sy = SCREENY(jy);
1873 int sxx = 0, syy = 0;
1874 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1876 int action = ACTION_DEFAULT;
1877 int last_player_graphic = getPlayerGraphic(player, move_dir);
1878 int last_player_frame = player->Frame;
1882 /* GfxElement[][] is set to the element the player is digging or collecting;
1883 remove also for off-screen player if the player is not moving anymore */
1884 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1885 GfxElement[jx][jy] = EL_UNDEFINED;
1888 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1892 if (!IN_LEV_FIELD(jx, jy))
1894 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1895 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1896 printf("DrawPlayerField(): This should never happen!\n");
1901 if (element == EL_EXPLOSION)
1904 action = (player->is_pushing ? ACTION_PUSHING :
1905 player->is_digging ? ACTION_DIGGING :
1906 player->is_collecting ? ACTION_COLLECTING :
1907 player->is_moving ? ACTION_MOVING :
1908 player->is_snapping ? ACTION_SNAPPING :
1909 player->is_dropping ? ACTION_DROPPING :
1910 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1913 if (player->is_waiting)
1914 move_dir = player->dir_waiting;
1917 InitPlayerGfxAnimation(player, action, move_dir);
1919 /* ----------------------------------------------------------------------- */
1920 /* draw things in the field the player is leaving, if needed */
1921 /* ----------------------------------------------------------------------- */
1923 if (player->is_moving)
1925 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1927 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1929 if (last_element == EL_DYNAMITE_ACTIVE ||
1930 last_element == EL_EM_DYNAMITE_ACTIVE ||
1931 last_element == EL_SP_DISK_RED_ACTIVE)
1932 DrawDynamite(last_jx, last_jy);
1934 DrawLevelFieldThruMask(last_jx, last_jy);
1936 else if (last_element == EL_DYNAMITE_ACTIVE ||
1937 last_element == EL_EM_DYNAMITE_ACTIVE ||
1938 last_element == EL_SP_DISK_RED_ACTIVE)
1939 DrawDynamite(last_jx, last_jy);
1941 DrawLevelField(last_jx, last_jy);
1943 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1944 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1947 if (!IN_SCR_FIELD(sx, sy))
1950 if (setup.direct_draw)
1951 SetDrawtoField(DRAW_BUFFERED);
1953 /* ----------------------------------------------------------------------- */
1954 /* draw things behind the player, if needed */
1955 /* ----------------------------------------------------------------------- */
1958 DrawLevelElement(jx, jy, Back[jx][jy]);
1959 else if (IS_ACTIVE_BOMB(element))
1960 DrawLevelElement(jx, jy, EL_EMPTY);
1963 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1965 int old_element = GfxElement[jx][jy];
1966 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1967 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1969 if (GFX_CRUMBLED(old_element))
1970 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1972 DrawGraphic(sx, sy, old_graphic, frame);
1974 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
1975 player_is_opaque = TRUE;
1979 GfxElement[jx][jy] = EL_UNDEFINED;
1981 /* make sure that pushed elements are drawn with correct frame rate */
1982 if (player->is_pushing && player->is_moving)
1983 GfxFrame[jx][jy] = player->StepFrame;
1985 DrawLevelField(jx, jy);
1989 /* ----------------------------------------------------------------------- */
1990 /* draw player himself */
1991 /* ----------------------------------------------------------------------- */
1993 graphic = getPlayerGraphic(player, move_dir);
1995 /* in the case of changed player action or direction, prevent the current
1996 animation frame from being restarted for identical animations */
1997 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1998 player->Frame = last_player_frame;
2000 frame = getGraphicAnimationFrame(graphic, player->Frame);
2004 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2005 sxx = player->GfxPos;
2007 syy = player->GfxPos;
2010 if (!setup.soft_scrolling && ScreenMovPos)
2013 if (player_is_opaque)
2014 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2016 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2018 if (SHIELD_ON(player))
2020 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2021 IMG_SHIELD_NORMAL_ACTIVE);
2022 int frame = getGraphicAnimationFrame(graphic, -1);
2024 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2027 /* ----------------------------------------------------------------------- */
2028 /* draw things the player is pushing, if needed */
2029 /* ----------------------------------------------------------------------- */
2032 printf("::: %d, %d [%d, %d] [%d]\n",
2033 player->is_pushing, player_is_moving, player->GfxAction,
2034 player->is_moving, player_is_moving);
2038 if (player->is_pushing && player->is_moving)
2040 int px = SCREENX(jx), py = SCREENY(jy);
2041 int pxx = (TILEX - ABS(sxx)) * dx;
2042 int pyy = (TILEY - ABS(syy)) * dy;
2047 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2048 element = Feld[next_jx][next_jy];
2050 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2051 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2053 /* draw background element under pushed element (like the Sokoban field) */
2054 if (Back[next_jx][next_jy])
2055 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2057 /* masked drawing is needed for EMC style (double) movement graphics */
2058 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2062 /* ----------------------------------------------------------------------- */
2063 /* draw things in front of player (active dynamite or dynabombs) */
2064 /* ----------------------------------------------------------------------- */
2066 if (IS_ACTIVE_BOMB(element))
2068 graphic = el2img(element);
2069 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2071 if (game.emulation == EMU_SUPAPLEX)
2072 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2074 DrawGraphicThruMask(sx, sy, graphic, frame);
2077 if (player_is_moving && last_element == EL_EXPLOSION)
2079 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2080 GfxElement[last_jx][last_jy] : EL_EMPTY);
2081 int graphic = el_act2img(element, ACTION_EXPLODING);
2082 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2083 int phase = ExplodePhase[last_jx][last_jy] - 1;
2084 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2087 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2090 /* ----------------------------------------------------------------------- */
2091 /* draw elements the player is just walking/passing through/under */
2092 /* ----------------------------------------------------------------------- */
2094 if (player_is_moving)
2096 /* handle the field the player is leaving ... */
2097 if (IS_ACCESSIBLE_INSIDE(last_element))
2098 DrawLevelField(last_jx, last_jy);
2099 else if (IS_ACCESSIBLE_UNDER(last_element))
2100 DrawLevelFieldThruMask(last_jx, last_jy);
2103 /* do not redraw accessible elements if the player is just pushing them */
2104 if (!player_is_moving || !player->is_pushing)
2106 /* ... and the field the player is entering */
2107 if (IS_ACCESSIBLE_INSIDE(element))
2108 DrawLevelField(jx, jy);
2109 else if (IS_ACCESSIBLE_UNDER(element))
2110 DrawLevelFieldThruMask(jx, jy);
2113 if (setup.direct_draw)
2115 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2116 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2117 int x_size = TILEX * (1 + ABS(jx - last_jx));
2118 int y_size = TILEY * (1 + ABS(jy - last_jy));
2120 BlitBitmap(drawto_field, window,
2121 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2122 SetDrawtoField(DRAW_DIRECT);
2125 MarkTileDirty(sx, sy);
2128 /* ------------------------------------------------------------------------- */
2130 void WaitForEventToContinue()
2132 boolean still_wait = TRUE;
2134 /* simulate releasing mouse button over last gadget, if still pressed */
2136 HandleGadgets(-1, -1, 0);
2138 button_status = MB_RELEASED;
2150 case EVENT_BUTTONPRESS:
2151 case EVENT_KEYPRESS:
2155 case EVENT_KEYRELEASE:
2156 ClearPlayerAction();
2160 HandleOtherEvents(&event);
2164 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2171 /* don't eat all CPU time */
2176 #define MAX_REQUEST_LINES 13
2177 #define MAX_REQUEST_LINE_FONT1_LEN 7
2178 #define MAX_REQUEST_LINE_FONT2_LEN 10
2180 boolean Request(char *text, unsigned int req_state)
2182 int mx, my, ty, result = -1;
2183 unsigned int old_door_state;
2184 int last_game_status = game_status; /* save current game status */
2185 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2186 int font_nr = FONT_TEXT_2;
2187 int max_word_len = 0;
2190 for (text_ptr = text; *text_ptr; text_ptr++)
2192 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2194 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2196 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2197 font_nr = FONT_LEVEL_NUMBER;
2203 if (game_status == GAME_MODE_PLAYING &&
2204 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2205 BlitScreenToBitmap_EM(backbuffer);
2207 /* disable deactivated drawing when quick-loading level tape recording */
2208 if (tape.playing && tape.deactivate_display)
2209 TapeDeactivateDisplayOff(TRUE);
2211 SetMouseCursor(CURSOR_DEFAULT);
2213 #if defined(NETWORK_AVALIABLE)
2214 /* pause network game while waiting for request to answer */
2215 if (options.network &&
2216 game_status == GAME_MODE_PLAYING &&
2217 req_state & REQUEST_WAIT_FOR_INPUT)
2218 SendToServer_PausePlaying();
2221 old_door_state = GetDoorState();
2223 /* simulate releasing mouse button over last gadget, if still pressed */
2225 HandleGadgets(-1, -1, 0);
2229 if (old_door_state & DOOR_OPEN_1)
2231 CloseDoor(DOOR_CLOSE_1);
2233 /* save old door content */
2234 BlitBitmap(bitmap_db_door, bitmap_db_door,
2235 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2236 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2239 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2241 /* clear door drawing field */
2242 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2244 /* force DOOR font on preview level */
2245 game_status = GAME_MODE_PSEUDO_DOOR;
2247 /* write text for request */
2248 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2250 char text_line[max_request_line_len + 1];
2256 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2259 if (!tc || tc == ' ')
2270 strncpy(text_line, text, tl);
2273 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2274 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2275 text_line, font_nr);
2277 text += tl + (tc == ' ' ? 1 : 0);
2280 game_status = last_game_status; /* restore current game status */
2282 if (req_state & REQ_ASK)
2284 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2285 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2287 else if (req_state & REQ_CONFIRM)
2289 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2291 else if (req_state & REQ_PLAYER)
2293 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2294 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2295 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2296 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2299 /* copy request gadgets to door backbuffer */
2300 BlitBitmap(drawto, bitmap_db_door,
2301 DX, DY, DXSIZE, DYSIZE,
2302 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2304 OpenDoor(DOOR_OPEN_1);
2306 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2308 SetDrawBackgroundMask(REDRAW_FIELD);
2313 if (game_status != GAME_MODE_MAIN)
2316 button_status = MB_RELEASED;
2318 request_gadget_id = -1;
2320 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2332 case EVENT_BUTTONPRESS:
2333 case EVENT_BUTTONRELEASE:
2334 case EVENT_MOTIONNOTIFY:
2336 if (event.type == EVENT_MOTIONNOTIFY)
2338 if (!PointerInWindow(window))
2339 continue; /* window and pointer are on different screens */
2344 motion_status = TRUE;
2345 mx = ((MotionEvent *) &event)->x;
2346 my = ((MotionEvent *) &event)->y;
2350 motion_status = FALSE;
2351 mx = ((ButtonEvent *) &event)->x;
2352 my = ((ButtonEvent *) &event)->y;
2353 if (event.type == EVENT_BUTTONPRESS)
2354 button_status = ((ButtonEvent *) &event)->button;
2356 button_status = MB_RELEASED;
2359 /* this sets 'request_gadget_id' */
2360 HandleGadgets(mx, my, button_status);
2362 switch(request_gadget_id)
2364 case TOOL_CTRL_ID_YES:
2367 case TOOL_CTRL_ID_NO:
2370 case TOOL_CTRL_ID_CONFIRM:
2371 result = TRUE | FALSE;
2374 case TOOL_CTRL_ID_PLAYER_1:
2377 case TOOL_CTRL_ID_PLAYER_2:
2380 case TOOL_CTRL_ID_PLAYER_3:
2383 case TOOL_CTRL_ID_PLAYER_4:
2394 case EVENT_KEYPRESS:
2395 switch(GetEventKey((KeyEvent *)&event, TRUE))
2408 if (req_state & REQ_PLAYER)
2412 case EVENT_KEYRELEASE:
2413 ClearPlayerAction();
2417 HandleOtherEvents(&event);
2421 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2423 int joy = AnyJoystick();
2425 if (joy & JOY_BUTTON_1)
2427 else if (joy & JOY_BUTTON_2)
2433 /* don't eat all CPU time */
2437 if (game_status != GAME_MODE_MAIN)
2442 if (!(req_state & REQ_STAY_OPEN))
2444 CloseDoor(DOOR_CLOSE_1);
2446 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2447 (req_state & REQ_REOPEN))
2448 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2453 SetDrawBackgroundMask(REDRAW_FIELD);
2455 #if defined(NETWORK_AVALIABLE)
2456 /* continue network game after request */
2457 if (options.network &&
2458 game_status == GAME_MODE_PLAYING &&
2459 req_state & REQUEST_WAIT_FOR_INPUT)
2460 SendToServer_ContinuePlaying();
2463 /* restore deactivated drawing when quick-loading level tape recording */
2464 if (tape.playing && tape.deactivate_display)
2465 TapeDeactivateDisplayOn();
2470 unsigned int OpenDoor(unsigned int door_state)
2472 if (door_state & DOOR_COPY_BACK)
2474 if (door_state & DOOR_OPEN_1)
2475 BlitBitmap(bitmap_db_door, bitmap_db_door,
2476 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2477 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2479 if (door_state & DOOR_OPEN_2)
2480 BlitBitmap(bitmap_db_door, bitmap_db_door,
2481 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2482 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2484 door_state &= ~DOOR_COPY_BACK;
2487 return MoveDoor(door_state);
2490 unsigned int CloseDoor(unsigned int door_state)
2492 unsigned int old_door_state = GetDoorState();
2494 if (!(door_state & DOOR_NO_COPY_BACK))
2496 if (old_door_state & DOOR_OPEN_1)
2497 BlitBitmap(backbuffer, bitmap_db_door,
2498 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2500 if (old_door_state & DOOR_OPEN_2)
2501 BlitBitmap(backbuffer, bitmap_db_door,
2502 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2504 door_state &= ~DOOR_NO_COPY_BACK;
2507 return MoveDoor(door_state);
2510 unsigned int GetDoorState()
2512 return MoveDoor(DOOR_GET_STATE);
2515 unsigned int SetDoorState(unsigned int door_state)
2517 return MoveDoor(door_state | DOOR_SET_STATE);
2520 unsigned int MoveDoor(unsigned int door_state)
2522 static int door1 = DOOR_OPEN_1;
2523 static int door2 = DOOR_CLOSE_2;
2524 unsigned long door_delay = 0;
2525 unsigned long door_delay_value;
2528 if (door_1.width < 0 || door_1.width > DXSIZE)
2529 door_1.width = DXSIZE;
2530 if (door_1.height < 0 || door_1.height > DYSIZE)
2531 door_1.height = DYSIZE;
2532 if (door_2.width < 0 || door_2.width > VXSIZE)
2533 door_2.width = VXSIZE;
2534 if (door_2.height < 0 || door_2.height > VYSIZE)
2535 door_2.height = VYSIZE;
2537 if (door_state == DOOR_GET_STATE)
2538 return (door1 | door2);
2540 if (door_state & DOOR_SET_STATE)
2542 if (door_state & DOOR_ACTION_1)
2543 door1 = door_state & DOOR_ACTION_1;
2544 if (door_state & DOOR_ACTION_2)
2545 door2 = door_state & DOOR_ACTION_2;
2547 return (door1 | door2);
2550 if (!(door_state & DOOR_FORCE_REDRAW))
2552 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2553 door_state &= ~DOOR_OPEN_1;
2554 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2555 door_state &= ~DOOR_CLOSE_1;
2556 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2557 door_state &= ~DOOR_OPEN_2;
2558 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2559 door_state &= ~DOOR_CLOSE_2;
2562 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2565 if (setup.quick_doors)
2567 stepsize = 20; /* must be choosen to always draw last frame */
2568 door_delay_value = 0;
2571 if (global.autoplay_leveldir)
2573 door_state |= DOOR_NO_DELAY;
2574 door_state &= ~DOOR_CLOSE_ALL;
2577 if (door_state & DOOR_ACTION)
2579 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2580 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2581 boolean door_1_done = (!handle_door_1);
2582 boolean door_2_done = (!handle_door_2);
2583 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2584 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2585 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2586 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2587 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2588 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2589 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2590 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2591 int door_skip = max_door_size - door_size;
2593 int end = door_size;
2595 int end = (door_state & DOOR_ACTION_1 &&
2596 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2599 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2601 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2605 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2607 /* opening door sound has priority over simultaneously closing door */
2608 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2609 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2610 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2611 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2614 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2617 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2618 GC gc = bitmap->stored_clip_gc;
2620 if (door_state & DOOR_ACTION_1)
2622 int a = MIN(x * door_1.step_offset, end);
2623 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2624 int i = p + door_skip;
2626 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2628 BlitBitmap(bitmap_db_door, drawto,
2629 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2630 DXSIZE, DYSIZE, DX, DY);
2634 BlitBitmap(bitmap_db_door, drawto,
2635 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2636 DXSIZE, DYSIZE - p / 2, DX, DY);
2638 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2641 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2643 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2644 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2645 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2646 int dst2_x = DX, dst2_y = DY;
2647 int width = i, height = DYSIZE;
2649 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2650 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2653 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2654 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2657 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2659 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2660 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2661 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2662 int dst2_x = DX, dst2_y = DY;
2663 int width = DXSIZE, height = i;
2665 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2666 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2669 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2670 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2673 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2675 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2677 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2678 BlitBitmapMasked(bitmap, drawto,
2679 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2680 DX + DXSIZE - i, DY + j);
2681 BlitBitmapMasked(bitmap, drawto,
2682 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2683 DX + DXSIZE - i, DY + 140 + j);
2684 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2685 DY - (DOOR_GFX_PAGEY1 + j));
2686 BlitBitmapMasked(bitmap, drawto,
2687 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2689 BlitBitmapMasked(bitmap, drawto,
2690 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2693 BlitBitmapMasked(bitmap, drawto,
2694 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2696 BlitBitmapMasked(bitmap, drawto,
2697 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2699 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2700 BlitBitmapMasked(bitmap, drawto,
2701 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2702 DX + DXSIZE - i, DY + 77 + j);
2703 BlitBitmapMasked(bitmap, drawto,
2704 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2705 DX + DXSIZE - i, DY + 203 + j);
2708 redraw_mask |= REDRAW_DOOR_1;
2709 door_1_done = (a == end);
2712 if (door_state & DOOR_ACTION_2)
2714 int a = MIN(x * door_2.step_offset, door_size_2);
2715 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2716 int i = p + door_skip;
2718 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2720 BlitBitmap(bitmap_db_door, drawto,
2721 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2722 VXSIZE, VYSIZE, VX, VY);
2724 else if (x <= VYSIZE)
2726 BlitBitmap(bitmap_db_door, drawto,
2727 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2728 VXSIZE, VYSIZE - p / 2, VX, VY);
2730 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2733 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2735 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2736 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2737 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2738 int dst2_x = VX, dst2_y = VY;
2739 int width = i, height = VYSIZE;
2741 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2742 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2745 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2746 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2749 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2751 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2752 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2753 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2754 int dst2_x = VX, dst2_y = VY;
2755 int width = VXSIZE, height = i;
2757 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2758 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2761 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2762 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2765 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2767 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2769 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2770 BlitBitmapMasked(bitmap, drawto,
2771 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2772 VX + VXSIZE - i, VY + j);
2773 SetClipOrigin(bitmap, gc,
2774 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2775 BlitBitmapMasked(bitmap, drawto,
2776 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2779 BlitBitmapMasked(bitmap, drawto,
2780 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2781 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2782 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2783 BlitBitmapMasked(bitmap, drawto,
2784 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2786 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2789 redraw_mask |= REDRAW_DOOR_2;
2790 door_2_done = (a == VXSIZE);
2793 if (!(door_state & DOOR_NO_DELAY))
2797 if (game_status == GAME_MODE_MAIN)
2800 WaitUntilDelayReached(&door_delay, door_delay_value);
2805 if (door_state & DOOR_ACTION_1)
2806 door1 = door_state & DOOR_ACTION_1;
2807 if (door_state & DOOR_ACTION_2)
2808 door2 = door_state & DOOR_ACTION_2;
2810 return (door1 | door2);
2813 void DrawSpecialEditorDoor()
2815 /* draw bigger toolbox window */
2816 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2817 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2819 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2820 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2823 redraw_mask |= REDRAW_ALL;
2826 void UndrawSpecialEditorDoor()
2828 /* draw normal tape recorder window */
2829 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2830 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2833 redraw_mask |= REDRAW_ALL;
2837 /* ---------- new tool button stuff ---------------------------------------- */
2839 /* graphic position values for tool buttons */
2840 #define TOOL_BUTTON_YES_XPOS 2
2841 #define TOOL_BUTTON_YES_YPOS 250
2842 #define TOOL_BUTTON_YES_GFX_YPOS 0
2843 #define TOOL_BUTTON_YES_XSIZE 46
2844 #define TOOL_BUTTON_YES_YSIZE 28
2845 #define TOOL_BUTTON_NO_XPOS 52
2846 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2847 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2848 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2849 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2850 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2851 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2852 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2853 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2854 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2855 #define TOOL_BUTTON_PLAYER_XSIZE 30
2856 #define TOOL_BUTTON_PLAYER_YSIZE 30
2857 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2858 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2859 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2860 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2861 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2862 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2863 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2864 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2865 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2866 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2867 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2868 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2869 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2870 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2871 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2872 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2873 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2874 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2875 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2876 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2885 } toolbutton_info[NUM_TOOL_BUTTONS] =
2888 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2889 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2890 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2895 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2896 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2897 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2902 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2903 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2904 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2905 TOOL_CTRL_ID_CONFIRM,
2909 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2910 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2911 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2912 TOOL_CTRL_ID_PLAYER_1,
2916 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2917 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2918 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2919 TOOL_CTRL_ID_PLAYER_2,
2923 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2924 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2925 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2926 TOOL_CTRL_ID_PLAYER_3,
2930 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2931 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2932 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2933 TOOL_CTRL_ID_PLAYER_4,
2938 void CreateToolButtons()
2942 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2944 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2945 Bitmap *deco_bitmap = None;
2946 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2947 struct GadgetInfo *gi;
2948 unsigned long event_mask;
2949 int gd_xoffset, gd_yoffset;
2950 int gd_x1, gd_x2, gd_y;
2953 event_mask = GD_EVENT_RELEASED;
2955 gd_xoffset = toolbutton_info[i].xpos;
2956 gd_yoffset = toolbutton_info[i].ypos;
2957 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2958 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2959 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2961 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2963 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2965 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2966 &deco_bitmap, &deco_x, &deco_y);
2967 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2968 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2971 gi = CreateGadget(GDI_CUSTOM_ID, id,
2972 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2973 GDI_X, DX + toolbutton_info[i].x,
2974 GDI_Y, DY + toolbutton_info[i].y,
2975 GDI_WIDTH, toolbutton_info[i].width,
2976 GDI_HEIGHT, toolbutton_info[i].height,
2977 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2978 GDI_STATE, GD_BUTTON_UNPRESSED,
2979 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2980 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2981 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2982 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2983 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2984 GDI_DECORATION_SHIFTING, 1, 1,
2985 GDI_EVENT_MASK, event_mask,
2986 GDI_CALLBACK_ACTION, HandleToolButtons,
2990 Error(ERR_EXIT, "cannot create gadget");
2992 tool_gadget[id] = gi;
2996 void FreeToolButtons()
3000 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3001 FreeGadget(tool_gadget[i]);
3004 static void UnmapToolButtons()
3008 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3009 UnmapGadget(tool_gadget[i]);
3012 static void HandleToolButtons(struct GadgetInfo *gi)
3014 request_gadget_id = gi->custom_id;
3017 static struct Mapping_EM_to_RND_object
3020 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3021 boolean is_backside; /* backside of moving element */
3027 em_object_mapping_list[] =
3030 Xblank, TRUE, FALSE,
3034 Yacid_splash_eB, FALSE, FALSE,
3035 EL_ACID_SPLASH_RIGHT, -1, -1
3038 Yacid_splash_wB, FALSE, FALSE,
3039 EL_ACID_SPLASH_LEFT, -1, -1
3042 #ifdef EM_ENGINE_BAD_ROLL
3044 Xstone_force_e, FALSE, FALSE,
3045 EL_ROCK, -1, MV_BIT_RIGHT
3048 Xstone_force_w, FALSE, FALSE,
3049 EL_ROCK, -1, MV_BIT_LEFT
3052 Xnut_force_e, FALSE, FALSE,
3053 EL_NUT, -1, MV_BIT_RIGHT
3056 Xnut_force_w, FALSE, FALSE,
3057 EL_NUT, -1, MV_BIT_LEFT
3060 Xspring_force_e, FALSE, FALSE,
3061 EL_SPRING, -1, MV_BIT_RIGHT
3064 Xspring_force_w, FALSE, FALSE,
3065 EL_SPRING, -1, MV_BIT_LEFT
3068 Xemerald_force_e, FALSE, FALSE,
3069 EL_EMERALD, -1, MV_BIT_RIGHT
3072 Xemerald_force_w, FALSE, FALSE,
3073 EL_EMERALD, -1, MV_BIT_LEFT
3076 Xdiamond_force_e, FALSE, FALSE,
3077 EL_DIAMOND, -1, MV_BIT_RIGHT
3080 Xdiamond_force_w, FALSE, FALSE,
3081 EL_DIAMOND, -1, MV_BIT_LEFT
3084 Xbomb_force_e, FALSE, FALSE,
3085 EL_BOMB, -1, MV_BIT_RIGHT
3088 Xbomb_force_w, FALSE, FALSE,
3089 EL_BOMB, -1, MV_BIT_LEFT
3091 #endif /* EM_ENGINE_BAD_ROLL */
3094 Xstone, TRUE, FALSE,
3098 Xstone_pause, FALSE, FALSE,
3102 Xstone_fall, FALSE, FALSE,
3106 Ystone_s, FALSE, FALSE,
3107 EL_ROCK, ACTION_FALLING, -1
3110 Ystone_sB, FALSE, TRUE,
3111 EL_ROCK, ACTION_FALLING, -1
3114 Ystone_e, FALSE, FALSE,
3115 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3118 Ystone_eB, FALSE, TRUE,
3119 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3122 Ystone_w, FALSE, FALSE,
3123 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3126 Ystone_wB, FALSE, TRUE,
3127 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3134 Xnut_pause, FALSE, FALSE,
3138 Xnut_fall, FALSE, FALSE,
3142 Ynut_s, FALSE, FALSE,
3143 EL_NUT, ACTION_FALLING, -1
3146 Ynut_sB, FALSE, TRUE,
3147 EL_NUT, ACTION_FALLING, -1
3150 Ynut_e, FALSE, FALSE,
3151 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3154 Ynut_eB, FALSE, TRUE,
3155 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3158 Ynut_w, FALSE, FALSE,
3159 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3162 Ynut_wB, FALSE, TRUE,
3163 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3166 Xbug_n, TRUE, FALSE,
3170 Xbug_e, TRUE, FALSE,
3171 EL_BUG_RIGHT, -1, -1
3174 Xbug_s, TRUE, FALSE,
3178 Xbug_w, TRUE, FALSE,
3182 Xbug_gon, FALSE, FALSE,
3186 Xbug_goe, FALSE, FALSE,
3187 EL_BUG_RIGHT, -1, -1
3190 Xbug_gos, FALSE, FALSE,
3194 Xbug_gow, FALSE, FALSE,
3198 Ybug_n, FALSE, FALSE,
3199 EL_BUG, ACTION_MOVING, MV_BIT_UP
3202 Ybug_nB, FALSE, TRUE,
3203 EL_BUG, ACTION_MOVING, MV_BIT_UP
3206 Ybug_e, FALSE, FALSE,
3207 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3210 Ybug_eB, FALSE, TRUE,
3211 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3214 Ybug_s, FALSE, FALSE,
3215 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3218 Ybug_sB, FALSE, TRUE,
3219 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3222 Ybug_w, FALSE, FALSE,
3223 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3226 Ybug_wB, FALSE, TRUE,
3227 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3230 Ybug_w_n, FALSE, FALSE,
3231 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3234 Ybug_n_e, FALSE, FALSE,
3235 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3238 Ybug_e_s, FALSE, FALSE,
3239 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3242 Ybug_s_w, FALSE, FALSE,
3243 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3246 Ybug_e_n, FALSE, FALSE,
3247 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3250 Ybug_s_e, FALSE, FALSE,
3251 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3254 Ybug_w_s, FALSE, FALSE,
3255 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3258 Ybug_n_w, FALSE, FALSE,
3259 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3262 Ybug_stone, FALSE, FALSE,
3263 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3266 Ybug_spring, FALSE, FALSE,
3267 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3270 Xtank_n, TRUE, FALSE,
3271 EL_SPACESHIP_UP, -1, -1
3274 Xtank_e, TRUE, FALSE,
3275 EL_SPACESHIP_RIGHT, -1, -1
3278 Xtank_s, TRUE, FALSE,
3279 EL_SPACESHIP_DOWN, -1, -1
3282 Xtank_w, TRUE, FALSE,
3283 EL_SPACESHIP_LEFT, -1, -1
3286 Xtank_gon, FALSE, FALSE,
3287 EL_SPACESHIP_UP, -1, -1
3290 Xtank_goe, FALSE, FALSE,
3291 EL_SPACESHIP_RIGHT, -1, -1
3294 Xtank_gos, FALSE, FALSE,
3295 EL_SPACESHIP_DOWN, -1, -1
3298 Xtank_gow, FALSE, FALSE,
3299 EL_SPACESHIP_LEFT, -1, -1
3302 Ytank_n, FALSE, FALSE,
3303 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3306 Ytank_nB, FALSE, TRUE,
3307 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3310 Ytank_e, FALSE, FALSE,
3311 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3314 Ytank_eB, FALSE, TRUE,
3315 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3318 Ytank_s, FALSE, FALSE,
3319 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3322 Ytank_sB, FALSE, TRUE,
3323 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3326 Ytank_w, FALSE, FALSE,
3327 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3330 Ytank_wB, FALSE, TRUE,
3331 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3334 Ytank_w_n, FALSE, FALSE,
3335 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3338 Ytank_n_e, FALSE, FALSE,
3339 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3342 Ytank_e_s, FALSE, FALSE,
3343 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3346 Ytank_s_w, FALSE, FALSE,
3347 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3350 Ytank_e_n, FALSE, FALSE,
3351 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3354 Ytank_s_e, FALSE, FALSE,
3355 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3358 Ytank_w_s, FALSE, FALSE,
3359 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3362 Ytank_n_w, FALSE, FALSE,
3363 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3366 Ytank_stone, FALSE, FALSE,
3367 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3370 Ytank_spring, FALSE, FALSE,
3371 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3374 Xandroid, TRUE, FALSE,
3375 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3378 Xandroid_1_n, FALSE, FALSE,
3379 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3382 Xandroid_2_n, FALSE, FALSE,
3383 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3386 Xandroid_1_e, FALSE, FALSE,
3387 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3390 Xandroid_2_e, FALSE, FALSE,
3391 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3394 Xandroid_1_w, FALSE, FALSE,
3395 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3398 Xandroid_2_w, FALSE, FALSE,
3399 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3402 Xandroid_1_s, FALSE, FALSE,
3403 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3406 Xandroid_2_s, FALSE, FALSE,
3407 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3410 Yandroid_n, FALSE, FALSE,
3411 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3414 Yandroid_nB, FALSE, TRUE,
3415 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3418 Yandroid_ne, FALSE, FALSE,
3419 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3422 Yandroid_neB, FALSE, TRUE,
3423 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3426 Yandroid_e, FALSE, FALSE,
3427 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3430 Yandroid_eB, FALSE, TRUE,
3431 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3434 Yandroid_se, FALSE, FALSE,
3435 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3438 Yandroid_seB, FALSE, TRUE,
3439 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3442 Yandroid_s, FALSE, FALSE,
3443 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3446 Yandroid_sB, FALSE, TRUE,
3447 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3450 Yandroid_sw, FALSE, FALSE,
3451 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3454 Yandroid_swB, FALSE, TRUE,
3455 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3458 Yandroid_w, FALSE, FALSE,
3459 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3462 Yandroid_wB, FALSE, TRUE,
3463 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3466 Yandroid_nw, FALSE, FALSE,
3467 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3470 Yandroid_nwB, FALSE, TRUE,
3471 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3474 Xspring, TRUE, FALSE,
3478 Xspring_pause, FALSE, FALSE,
3482 Xspring_e, FALSE, FALSE,
3486 Xspring_w, FALSE, FALSE,
3490 Xspring_fall, FALSE, FALSE,
3494 Yspring_s, FALSE, FALSE,
3495 EL_SPRING, ACTION_FALLING, -1
3498 Yspring_sB, FALSE, TRUE,
3499 EL_SPRING, ACTION_FALLING, -1
3502 Yspring_e, FALSE, FALSE,
3503 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3506 Yspring_eB, FALSE, TRUE,
3507 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3510 Yspring_w, FALSE, FALSE,
3511 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3514 Yspring_wB, FALSE, TRUE,
3515 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3518 Yspring_kill_e, FALSE, FALSE,
3519 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3522 Yspring_kill_eB, FALSE, TRUE,
3523 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3526 Yspring_kill_w, FALSE, FALSE,
3527 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3530 Yspring_kill_wB, FALSE, TRUE,
3531 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3534 Xeater_n, TRUE, FALSE,
3535 EL_YAMYAM_UP, -1, -1
3538 Xeater_e, TRUE, FALSE,
3539 EL_YAMYAM_RIGHT, -1, -1
3542 Xeater_w, TRUE, FALSE,
3543 EL_YAMYAM_LEFT, -1, -1
3546 Xeater_s, TRUE, FALSE,
3547 EL_YAMYAM_DOWN, -1, -1
3550 Yeater_n, FALSE, FALSE,
3551 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3554 Yeater_nB, FALSE, TRUE,
3555 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3558 Yeater_e, FALSE, FALSE,
3559 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3562 Yeater_eB, FALSE, TRUE,
3563 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3566 Yeater_s, FALSE, FALSE,
3567 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3570 Yeater_sB, FALSE, TRUE,
3571 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3574 Yeater_w, FALSE, FALSE,
3575 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3578 Yeater_wB, FALSE, TRUE,
3579 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3582 Yeater_stone, FALSE, FALSE,
3583 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3586 Yeater_spring, FALSE, FALSE,
3587 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3590 Xalien, TRUE, FALSE,
3594 Xalien_pause, FALSE, FALSE,
3598 Yalien_n, FALSE, FALSE,
3599 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3602 Yalien_nB, FALSE, TRUE,
3603 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3606 Yalien_e, FALSE, FALSE,
3607 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3610 Yalien_eB, FALSE, TRUE,
3611 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3614 Yalien_s, FALSE, FALSE,
3615 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3618 Yalien_sB, FALSE, TRUE,
3619 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3622 Yalien_w, FALSE, FALSE,
3623 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3626 Yalien_wB, FALSE, TRUE,
3627 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3630 Yalien_stone, FALSE, FALSE,
3631 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3634 Yalien_spring, FALSE, FALSE,
3635 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3638 Xemerald, TRUE, FALSE,
3642 Xemerald_pause, FALSE, FALSE,
3646 Xemerald_fall, FALSE, FALSE,
3650 Xemerald_shine, FALSE, FALSE,
3651 EL_EMERALD, ACTION_TWINKLING, -1
3654 Yemerald_s, FALSE, FALSE,
3655 EL_EMERALD, ACTION_FALLING, -1
3658 Yemerald_sB, FALSE, TRUE,
3659 EL_EMERALD, ACTION_FALLING, -1
3662 Yemerald_e, FALSE, FALSE,
3663 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3666 Yemerald_eB, FALSE, TRUE,
3667 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3670 Yemerald_w, FALSE, FALSE,
3671 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3674 Yemerald_wB, FALSE, TRUE,
3675 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3678 Yemerald_eat, FALSE, FALSE,
3679 EL_EMERALD, ACTION_COLLECTING, -1
3682 Yemerald_stone, FALSE, FALSE,
3683 EL_NUT, ACTION_BREAKING, -1
3686 Xdiamond, TRUE, FALSE,
3690 Xdiamond_pause, FALSE, FALSE,
3694 Xdiamond_fall, FALSE, FALSE,
3698 Xdiamond_shine, FALSE, FALSE,
3699 EL_DIAMOND, ACTION_TWINKLING, -1
3702 Ydiamond_s, FALSE, FALSE,
3703 EL_DIAMOND, ACTION_FALLING, -1
3706 Ydiamond_sB, FALSE, TRUE,
3707 EL_DIAMOND, ACTION_FALLING, -1
3710 Ydiamond_e, FALSE, FALSE,
3711 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3714 Ydiamond_eB, FALSE, TRUE,
3715 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3718 Ydiamond_w, FALSE, FALSE,
3719 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3722 Ydiamond_wB, FALSE, TRUE,
3723 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3726 Ydiamond_eat, FALSE, FALSE,
3727 EL_DIAMOND, ACTION_COLLECTING, -1
3730 Ydiamond_stone, FALSE, FALSE,
3731 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3734 Xdrip_fall, TRUE, FALSE,
3735 EL_AMOEBA_DROP, -1, -1
3738 Xdrip_stretch, FALSE, FALSE,
3739 EL_AMOEBA_DROP, ACTION_FALLING, -1
3742 Xdrip_stretchB, FALSE, TRUE,
3743 EL_AMOEBA_DROP, ACTION_FALLING, -1
3746 Xdrip_eat, FALSE, FALSE,
3747 EL_AMOEBA_DROP, ACTION_GROWING, -1
3750 Ydrip_s1, FALSE, FALSE,
3751 EL_AMOEBA_DROP, ACTION_FALLING, -1
3754 Ydrip_s1B, FALSE, TRUE,
3755 EL_AMOEBA_DROP, ACTION_FALLING, -1
3758 Ydrip_s2, FALSE, FALSE,
3759 EL_AMOEBA_DROP, ACTION_FALLING, -1
3762 Ydrip_s2B, FALSE, TRUE,
3763 EL_AMOEBA_DROP, ACTION_FALLING, -1
3770 Xbomb_pause, FALSE, FALSE,
3774 Xbomb_fall, FALSE, FALSE,
3778 Ybomb_s, FALSE, FALSE,
3779 EL_BOMB, ACTION_FALLING, -1
3782 Ybomb_sB, FALSE, TRUE,
3783 EL_BOMB, ACTION_FALLING, -1
3786 Ybomb_e, FALSE, FALSE,
3787 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3790 Ybomb_eB, FALSE, TRUE,
3791 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3794 Ybomb_w, FALSE, FALSE,
3795 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3798 Ybomb_wB, FALSE, TRUE,
3799 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3802 Ybomb_eat, FALSE, FALSE,
3803 EL_BOMB, ACTION_ACTIVATING, -1
3806 Xballoon, TRUE, FALSE,
3810 Yballoon_n, FALSE, FALSE,
3811 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3814 Yballoon_nB, FALSE, TRUE,
3815 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3818 Yballoon_e, FALSE, FALSE,
3819 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3822 Yballoon_eB, FALSE, TRUE,
3823 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3826 Yballoon_s, FALSE, FALSE,
3827 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3830 Yballoon_sB, FALSE, TRUE,
3831 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3834 Yballoon_w, FALSE, FALSE,
3835 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3838 Yballoon_wB, FALSE, TRUE,
3839 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3842 Xgrass, TRUE, FALSE,
3843 EL_EMC_GRASS, -1, -1
3846 Ygrass_nB, FALSE, FALSE,
3847 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3850 Ygrass_eB, FALSE, FALSE,
3851 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3854 Ygrass_sB, FALSE, FALSE,
3855 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3858 Ygrass_wB, FALSE, FALSE,
3859 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3866 Ydirt_nB, FALSE, FALSE,
3867 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3870 Ydirt_eB, FALSE, FALSE,
3871 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3874 Ydirt_sB, FALSE, FALSE,
3875 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3878 Ydirt_wB, FALSE, FALSE,
3879 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3882 Xacid_ne, TRUE, FALSE,
3883 EL_ACID_POOL_TOPRIGHT, -1, -1
3886 Xacid_se, TRUE, FALSE,
3887 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3890 Xacid_s, TRUE, FALSE,
3891 EL_ACID_POOL_BOTTOM, -1, -1
3894 Xacid_sw, TRUE, FALSE,
3895 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3898 Xacid_nw, TRUE, FALSE,
3899 EL_ACID_POOL_TOPLEFT, -1, -1
3902 Xacid_1, TRUE, FALSE,
3906 Xacid_2, FALSE, FALSE,
3910 Xacid_3, FALSE, FALSE,
3914 Xacid_4, FALSE, FALSE,
3918 Xacid_5, FALSE, FALSE,
3922 Xacid_6, FALSE, FALSE,
3926 Xacid_7, FALSE, FALSE,
3930 Xacid_8, FALSE, FALSE,
3934 Xball_1, TRUE, FALSE,
3935 EL_EMC_MAGIC_BALL, -1, -1
3938 Xball_1B, FALSE, FALSE,
3939 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3942 Xball_2, FALSE, FALSE,
3943 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3946 Xball_2B, FALSE, FALSE,
3947 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3950 Yball_eat, FALSE, FALSE,
3951 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3954 Ykey_1_eat, FALSE, FALSE,
3955 EL_EM_KEY_1, ACTION_COLLECTING, -1
3958 Ykey_2_eat, FALSE, FALSE,
3959 EL_EM_KEY_2, ACTION_COLLECTING, -1
3962 Ykey_3_eat, FALSE, FALSE,
3963 EL_EM_KEY_3, ACTION_COLLECTING, -1
3966 Ykey_4_eat, FALSE, FALSE,
3967 EL_EM_KEY_4, ACTION_COLLECTING, -1
3970 Ykey_5_eat, FALSE, FALSE,
3971 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3974 Ykey_6_eat, FALSE, FALSE,
3975 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3978 Ykey_7_eat, FALSE, FALSE,
3979 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3982 Ykey_8_eat, FALSE, FALSE,
3983 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3986 Ylenses_eat, FALSE, FALSE,
3987 EL_EMC_LENSES, ACTION_COLLECTING, -1
3990 Ymagnify_eat, FALSE, FALSE,
3991 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3994 Ygrass_eat, FALSE, FALSE,
3995 EL_EMC_GRASS, ACTION_SNAPPING, -1
3998 Ydirt_eat, FALSE, FALSE,
3999 EL_SAND, ACTION_SNAPPING, -1
4002 Xgrow_ns, TRUE, FALSE,
4003 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4006 Ygrow_ns_eat, FALSE, FALSE,
4007 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4010 Xgrow_ew, TRUE, FALSE,
4011 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4014 Ygrow_ew_eat, FALSE, FALSE,
4015 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4018 Xwonderwall, TRUE, FALSE,
4019 EL_MAGIC_WALL, -1, -1
4022 XwonderwallB, FALSE, FALSE,
4023 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4026 Xamoeba_1, TRUE, FALSE,
4027 EL_AMOEBA_DRY, ACTION_OTHER, -1
4030 Xamoeba_2, FALSE, FALSE,
4031 EL_AMOEBA_DRY, ACTION_OTHER, -1
4034 Xamoeba_3, FALSE, FALSE,
4035 EL_AMOEBA_DRY, ACTION_OTHER, -1
4038 Xamoeba_4, FALSE, FALSE,
4039 EL_AMOEBA_DRY, ACTION_OTHER, -1
4042 Xamoeba_5, TRUE, FALSE,
4043 EL_AMOEBA_WET, ACTION_OTHER, -1
4046 Xamoeba_6, FALSE, FALSE,
4047 EL_AMOEBA_WET, ACTION_OTHER, -1
4050 Xamoeba_7, FALSE, FALSE,
4051 EL_AMOEBA_WET, ACTION_OTHER, -1
4054 Xamoeba_8, FALSE, FALSE,
4055 EL_AMOEBA_WET, ACTION_OTHER, -1
4058 Xdoor_1, TRUE, FALSE,
4059 EL_EM_GATE_1, -1, -1
4062 Xdoor_2, TRUE, FALSE,
4063 EL_EM_GATE_2, -1, -1
4066 Xdoor_3, TRUE, FALSE,
4067 EL_EM_GATE_3, -1, -1
4070 Xdoor_4, TRUE, FALSE,
4071 EL_EM_GATE_4, -1, -1
4074 Xdoor_5, TRUE, FALSE,
4075 EL_EMC_GATE_5, -1, -1
4078 Xdoor_6, TRUE, FALSE,
4079 EL_EMC_GATE_6, -1, -1
4082 Xdoor_7, TRUE, FALSE,
4083 EL_EMC_GATE_7, -1, -1
4086 Xdoor_8, TRUE, FALSE,
4087 EL_EMC_GATE_8, -1, -1
4090 Xkey_1, TRUE, FALSE,
4094 Xkey_2, TRUE, FALSE,
4098 Xkey_3, TRUE, FALSE,
4102 Xkey_4, TRUE, FALSE,
4106 Xkey_5, TRUE, FALSE,
4107 EL_EMC_KEY_5, -1, -1
4110 Xkey_6, TRUE, FALSE,
4111 EL_EMC_KEY_6, -1, -1
4114 Xkey_7, TRUE, FALSE,
4115 EL_EMC_KEY_7, -1, -1
4118 Xkey_8, TRUE, FALSE,
4119 EL_EMC_KEY_8, -1, -1
4122 Xwind_n, TRUE, FALSE,
4123 EL_BALLOON_SWITCH_UP, -1, -1
4126 Xwind_e, TRUE, FALSE,
4127 EL_BALLOON_SWITCH_RIGHT, -1, -1
4130 Xwind_s, TRUE, FALSE,
4131 EL_BALLOON_SWITCH_DOWN, -1, -1
4134 Xwind_w, TRUE, FALSE,
4135 EL_BALLOON_SWITCH_LEFT, -1, -1
4138 Xwind_nesw, TRUE, FALSE,
4139 EL_BALLOON_SWITCH_ANY, -1, -1
4142 Xwind_stop, TRUE, FALSE,
4143 EL_BALLOON_SWITCH_NONE, -1, -1
4147 EL_EXIT_CLOSED, -1, -1
4150 Xexit_1, TRUE, FALSE,
4151 EL_EXIT_OPEN, -1, -1
4154 Xexit_2, FALSE, FALSE,
4155 EL_EXIT_OPEN, -1, -1
4158 Xexit_3, FALSE, FALSE,
4159 EL_EXIT_OPEN, -1, -1
4162 Xdynamite, TRUE, FALSE,
4163 EL_EM_DYNAMITE, -1, -1
4166 Ydynamite_eat, FALSE, FALSE,
4167 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4170 Xdynamite_1, TRUE, FALSE,
4171 EL_EM_DYNAMITE_ACTIVE, -1, -1
4174 Xdynamite_2, FALSE, FALSE,
4175 EL_EM_DYNAMITE_ACTIVE, -1, -1
4178 Xdynamite_3, FALSE, FALSE,
4179 EL_EM_DYNAMITE_ACTIVE, -1, -1
4182 Xdynamite_4, FALSE, FALSE,
4183 EL_EM_DYNAMITE_ACTIVE, -1, -1
4186 Xbumper, TRUE, FALSE,
4187 EL_EMC_SPRING_BUMPER, -1, -1
4190 XbumperB, FALSE, FALSE,
4191 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4194 Xwheel, TRUE, FALSE,
4195 EL_ROBOT_WHEEL, -1, -1
4198 XwheelB, FALSE, FALSE,
4199 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4202 Xswitch, TRUE, FALSE,
4203 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4206 XswitchB, FALSE, FALSE,
4207 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4211 EL_QUICKSAND_EMPTY, -1, -1
4214 Xsand_stone, TRUE, FALSE,
4215 EL_QUICKSAND_FULL, -1, -1
4218 Xsand_stonein_1, FALSE, TRUE,
4219 EL_ROCK, ACTION_FILLING, -1
4222 Xsand_stonein_2, FALSE, TRUE,
4223 EL_ROCK, ACTION_FILLING, -1
4226 Xsand_stonein_3, FALSE, TRUE,
4227 EL_ROCK, ACTION_FILLING, -1
4230 Xsand_stonein_4, FALSE, TRUE,
4231 EL_ROCK, ACTION_FILLING, -1
4234 Xsand_stonesand_1, FALSE, FALSE,
4235 EL_QUICKSAND_FULL, -1, -1
4238 Xsand_stonesand_2, FALSE, FALSE,
4239 EL_QUICKSAND_FULL, -1, -1
4242 Xsand_stonesand_3, FALSE, FALSE,
4243 EL_QUICKSAND_FULL, -1, -1
4246 Xsand_stonesand_4, FALSE, FALSE,
4247 EL_QUICKSAND_FULL, -1, -1
4250 Xsand_stoneout_1, FALSE, FALSE,
4251 EL_ROCK, ACTION_EMPTYING, -1
4254 Xsand_stoneout_2, FALSE, FALSE,
4255 EL_ROCK, ACTION_EMPTYING, -1
4258 Xsand_sandstone_1, FALSE, FALSE,
4259 EL_QUICKSAND_FULL, -1, -1
4262 Xsand_sandstone_2, FALSE, FALSE,
4263 EL_QUICKSAND_FULL, -1, -1
4266 Xsand_sandstone_3, FALSE, FALSE,
4267 EL_QUICKSAND_FULL, -1, -1
4270 Xsand_sandstone_4, FALSE, FALSE,
4271 EL_QUICKSAND_FULL, -1, -1
4274 Xplant, TRUE, FALSE,
4275 EL_EMC_PLANT, -1, -1
4278 Yplant, FALSE, FALSE,
4279 EL_EMC_PLANT, -1, -1
4282 Xlenses, TRUE, FALSE,
4283 EL_EMC_LENSES, -1, -1
4286 Xmagnify, TRUE, FALSE,
4287 EL_EMC_MAGNIFIER, -1, -1
4290 Xdripper, TRUE, FALSE,
4291 EL_EMC_DRIPPER, -1, -1
4294 XdripperB, FALSE, FALSE,
4295 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4298 Xfake_blank, TRUE, FALSE,
4299 EL_INVISIBLE_WALL, -1, -1
4302 Xfake_blankB, FALSE, FALSE,
4303 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4306 Xfake_grass, TRUE, FALSE,
4307 EL_EMC_FAKE_GRASS, -1, -1
4310 Xfake_grassB, FALSE, FALSE,
4311 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4314 Xfake_door_1, TRUE, FALSE,
4315 EL_EM_GATE_1_GRAY, -1, -1
4318 Xfake_door_2, TRUE, FALSE,
4319 EL_EM_GATE_2_GRAY, -1, -1
4322 Xfake_door_3, TRUE, FALSE,
4323 EL_EM_GATE_3_GRAY, -1, -1
4326 Xfake_door_4, TRUE, FALSE,
4327 EL_EM_GATE_4_GRAY, -1, -1
4330 Xfake_door_5, TRUE, FALSE,
4331 EL_EMC_GATE_5_GRAY, -1, -1
4334 Xfake_door_6, TRUE, FALSE,
4335 EL_EMC_GATE_6_GRAY, -1, -1
4338 Xfake_door_7, TRUE, FALSE,
4339 EL_EMC_GATE_7_GRAY, -1, -1
4342 Xfake_door_8, TRUE, FALSE,
4343 EL_EMC_GATE_8_GRAY, -1, -1
4346 Xfake_acid_1, TRUE, FALSE,
4347 EL_EMC_FAKE_ACID, -1, -1
4350 Xfake_acid_2, FALSE, FALSE,
4351 EL_EMC_FAKE_ACID, -1, -1
4354 Xfake_acid_3, FALSE, FALSE,
4355 EL_EMC_FAKE_ACID, -1, -1
4358 Xfake_acid_4, FALSE, FALSE,
4359 EL_EMC_FAKE_ACID, -1, -1
4362 Xfake_acid_5, FALSE, FALSE,
4363 EL_EMC_FAKE_ACID, -1, -1
4366 Xfake_acid_6, FALSE, FALSE,
4367 EL_EMC_FAKE_ACID, -1, -1
4370 Xfake_acid_7, FALSE, FALSE,
4371 EL_EMC_FAKE_ACID, -1, -1
4374 Xfake_acid_8, FALSE, FALSE,
4375 EL_EMC_FAKE_ACID, -1, -1
4378 Xsteel_1, TRUE, FALSE,
4379 EL_STEELWALL, -1, -1
4382 Xsteel_2, TRUE, FALSE,
4383 EL_EMC_STEELWALL_2, -1, -1
4386 Xsteel_3, TRUE, FALSE,
4387 EL_EMC_STEELWALL_3, -1, -1
4390 Xsteel_4, TRUE, FALSE,
4391 EL_EMC_STEELWALL_4, -1, -1
4394 Xwall_1, TRUE, FALSE,
4398 Xwall_2, TRUE, FALSE,
4399 EL_EMC_WALL_14, -1, -1
4402 Xwall_3, TRUE, FALSE,
4403 EL_EMC_WALL_15, -1, -1
4406 Xwall_4, TRUE, FALSE,
4407 EL_EMC_WALL_16, -1, -1
4410 Xround_wall_1, TRUE, FALSE,
4411 EL_WALL_SLIPPERY, -1, -1
4414 Xround_wall_2, TRUE, FALSE,
4415 EL_EMC_WALL_SLIPPERY_2, -1, -1
4418 Xround_wall_3, TRUE, FALSE,
4419 EL_EMC_WALL_SLIPPERY_3, -1, -1
4422 Xround_wall_4, TRUE, FALSE,
4423 EL_EMC_WALL_SLIPPERY_4, -1, -1
4426 Xdecor_1, TRUE, FALSE,
4427 EL_EMC_WALL_8, -1, -1
4430 Xdecor_2, TRUE, FALSE,
4431 EL_EMC_WALL_6, -1, -1
4434 Xdecor_3, TRUE, FALSE,
4435 EL_EMC_WALL_4, -1, -1
4438 Xdecor_4, TRUE, FALSE,
4439 EL_EMC_WALL_7, -1, -1
4442 Xdecor_5, TRUE, FALSE,
4443 EL_EMC_WALL_5, -1, -1
4446 Xdecor_6, TRUE, FALSE,
4447 EL_EMC_WALL_9, -1, -1
4450 Xdecor_7, TRUE, FALSE,
4451 EL_EMC_WALL_10, -1, -1
4454 Xdecor_8, TRUE, FALSE,
4455 EL_EMC_WALL_1, -1, -1
4458 Xdecor_9, TRUE, FALSE,
4459 EL_EMC_WALL_2, -1, -1
4462 Xdecor_10, TRUE, FALSE,
4463 EL_EMC_WALL_3, -1, -1
4466 Xdecor_11, TRUE, FALSE,
4467 EL_EMC_WALL_11, -1, -1
4470 Xdecor_12, TRUE, FALSE,
4471 EL_EMC_WALL_12, -1, -1
4474 Xalpha_0, TRUE, FALSE,
4475 EL_CHAR('0'), -1, -1
4478 Xalpha_1, TRUE, FALSE,
4479 EL_CHAR('1'), -1, -1
4482 Xalpha_2, TRUE, FALSE,
4483 EL_CHAR('2'), -1, -1
4486 Xalpha_3, TRUE, FALSE,
4487 EL_CHAR('3'), -1, -1
4490 Xalpha_4, TRUE, FALSE,
4491 EL_CHAR('4'), -1, -1
4494 Xalpha_5, TRUE, FALSE,
4495 EL_CHAR('5'), -1, -1
4498 Xalpha_6, TRUE, FALSE,
4499 EL_CHAR('6'), -1, -1
4502 Xalpha_7, TRUE, FALSE,
4503 EL_CHAR('7'), -1, -1
4506 Xalpha_8, TRUE, FALSE,
4507 EL_CHAR('8'), -1, -1
4510 Xalpha_9, TRUE, FALSE,
4511 EL_CHAR('9'), -1, -1
4514 Xalpha_excla, TRUE, FALSE,
4515 EL_CHAR('!'), -1, -1
4518 Xalpha_quote, TRUE, FALSE,
4519 EL_CHAR('"'), -1, -1
4522 Xalpha_comma, TRUE, FALSE,
4523 EL_CHAR(','), -1, -1
4526 Xalpha_minus, TRUE, FALSE,
4527 EL_CHAR('-'), -1, -1
4530 Xalpha_perio, TRUE, FALSE,
4531 EL_CHAR('.'), -1, -1
4534 Xalpha_colon, TRUE, FALSE,
4535 EL_CHAR(':'), -1, -1
4538 Xalpha_quest, TRUE, FALSE,
4539 EL_CHAR('?'), -1, -1
4542 Xalpha_a, TRUE, FALSE,
4543 EL_CHAR('A'), -1, -1
4546 Xalpha_b, TRUE, FALSE,
4547 EL_CHAR('B'), -1, -1
4550 Xalpha_c, TRUE, FALSE,
4551 EL_CHAR('C'), -1, -1
4554 Xalpha_d, TRUE, FALSE,
4555 EL_CHAR('D'), -1, -1
4558 Xalpha_e, TRUE, FALSE,
4559 EL_CHAR('E'), -1, -1
4562 Xalpha_f, TRUE, FALSE,
4563 EL_CHAR('F'), -1, -1
4566 Xalpha_g, TRUE, FALSE,
4567 EL_CHAR('G'), -1, -1
4570 Xalpha_h, TRUE, FALSE,
4571 EL_CHAR('H'), -1, -1
4574 Xalpha_i, TRUE, FALSE,
4575 EL_CHAR('I'), -1, -1
4578 Xalpha_j, TRUE, FALSE,
4579 EL_CHAR('J'), -1, -1
4582 Xalpha_k, TRUE, FALSE,
4583 EL_CHAR('K'), -1, -1
4586 Xalpha_l, TRUE, FALSE,
4587 EL_CHAR('L'), -1, -1
4590 Xalpha_m, TRUE, FALSE,
4591 EL_CHAR('M'), -1, -1
4594 Xalpha_n, TRUE, FALSE,
4595 EL_CHAR('N'), -1, -1
4598 Xalpha_o, TRUE, FALSE,
4599 EL_CHAR('O'), -1, -1
4602 Xalpha_p, TRUE, FALSE,
4603 EL_CHAR('P'), -1, -1
4606 Xalpha_q, TRUE, FALSE,
4607 EL_CHAR('Q'), -1, -1
4610 Xalpha_r, TRUE, FALSE,
4611 EL_CHAR('R'), -1, -1
4614 Xalpha_s, TRUE, FALSE,
4615 EL_CHAR('S'), -1, -1
4618 Xalpha_t, TRUE, FALSE,
4619 EL_CHAR('T'), -1, -1
4622 Xalpha_u, TRUE, FALSE,
4623 EL_CHAR('U'), -1, -1
4626 Xalpha_v, TRUE, FALSE,
4627 EL_CHAR('V'), -1, -1
4630 Xalpha_w, TRUE, FALSE,
4631 EL_CHAR('W'), -1, -1
4634 Xalpha_x, TRUE, FALSE,
4635 EL_CHAR('X'), -1, -1
4638 Xalpha_y, TRUE, FALSE,
4639 EL_CHAR('Y'), -1, -1
4642 Xalpha_z, TRUE, FALSE,
4643 EL_CHAR('Z'), -1, -1
4646 Xalpha_arrow_e, TRUE, FALSE,
4647 EL_CHAR('>'), -1, -1
4650 Xalpha_arrow_w, TRUE, FALSE,
4651 EL_CHAR('<'), -1, -1
4654 Xalpha_copyr, TRUE, FALSE,
4655 EL_CHAR('©'), -1, -1
4659 Xboom_bug, FALSE, FALSE,
4660 EL_BUG, ACTION_EXPLODING, -1
4663 Xboom_bomb, FALSE, FALSE,
4664 EL_BOMB, ACTION_EXPLODING, -1
4667 Xboom_android, FALSE, FALSE,
4668 EL_EMC_ANDROID, ACTION_OTHER, -1
4671 Xboom_1, FALSE, FALSE,
4672 EL_DEFAULT, ACTION_EXPLODING, -1
4675 Xboom_2, FALSE, FALSE,
4676 EL_DEFAULT, ACTION_EXPLODING, -1
4679 Znormal, FALSE, FALSE,
4683 Zdynamite, FALSE, FALSE,
4687 Zplayer, FALSE, FALSE,
4691 ZBORDER, FALSE, FALSE,
4701 static struct Mapping_EM_to_RND_player
4710 em_player_mapping_list[] =
4714 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4718 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4722 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4726 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4730 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4734 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4738 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4742 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4746 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4750 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4754 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4758 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4762 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4766 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4770 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4774 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4778 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4782 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4786 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4790 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4794 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4798 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4802 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4806 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4810 EL_PLAYER_1, ACTION_DEFAULT, -1,
4814 EL_PLAYER_2, ACTION_DEFAULT, -1,
4818 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4822 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4826 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4830 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4834 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4838 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4842 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4846 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4850 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4854 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4858 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4862 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4866 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4870 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4874 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4878 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4882 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4886 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4890 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4894 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4898 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4902 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4906 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4910 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4914 EL_PLAYER_3, ACTION_DEFAULT, -1,
4918 EL_PLAYER_4, ACTION_DEFAULT, -1,
4927 int map_element_RND_to_EM(int element_rnd)
4929 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4930 static boolean mapping_initialized = FALSE;
4932 if (!mapping_initialized)
4936 /* return "Xalpha_quest" for all undefined elements in mapping array */
4937 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4938 mapping_RND_to_EM[i] = Xalpha_quest;
4940 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4941 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4942 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4943 em_object_mapping_list[i].element_em;
4945 mapping_initialized = TRUE;
4948 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4949 return mapping_RND_to_EM[element_rnd];
4951 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4956 int map_element_EM_to_RND(int element_em)
4958 static unsigned short mapping_EM_to_RND[TILE_MAX];
4959 static boolean mapping_initialized = FALSE;
4961 if (!mapping_initialized)
4965 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4966 for (i = 0; i < TILE_MAX; i++)
4967 mapping_EM_to_RND[i] = EL_UNKNOWN;
4969 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4970 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4971 em_object_mapping_list[i].element_rnd;
4973 mapping_initialized = TRUE;
4976 if (element_em >= 0 && element_em < TILE_MAX)
4977 return mapping_EM_to_RND[element_em];
4979 Error(ERR_WARN, "invalid EM level element %d", element_em);
4984 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4986 struct LevelInfo_EM *level_em = level->native_em_level;
4987 struct LEVEL *lev = level_em->lev;
4990 for (i = 0; i < TILE_MAX; i++)
4991 lev->android_array[i] = Xblank;
4993 for (i = 0; i < level->num_android_clone_elements; i++)
4995 int element_rnd = level->android_clone_element[i];
4996 int element_em = map_element_RND_to_EM(element_rnd);
4998 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4999 if (em_object_mapping_list[j].element_rnd == element_rnd)
5000 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5004 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5006 struct LevelInfo_EM *level_em = level->native_em_level;
5007 struct LEVEL *lev = level_em->lev;
5010 level->num_android_clone_elements = 0;
5012 for (i = 0; i < TILE_MAX; i++)
5014 int element_em = lev->android_array[i];
5016 boolean element_found = FALSE;
5018 if (element_em == Xblank)
5021 element_rnd = map_element_EM_to_RND(element_em);
5023 for (j = 0; j < level->num_android_clone_elements; j++)
5024 if (level->android_clone_element[j] == element_rnd)
5025 element_found = TRUE;
5029 level->android_clone_element[level->num_android_clone_elements++] =
5032 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5037 if (level->num_android_clone_elements == 0)
5039 level->num_android_clone_elements = 1;
5040 level->android_clone_element[0] = EL_EMPTY;
5044 int map_direction_RND_to_EM(int direction)
5046 return (direction == MV_UP ? 0 :
5047 direction == MV_RIGHT ? 1 :
5048 direction == MV_DOWN ? 2 :
5049 direction == MV_LEFT ? 3 :
5053 int map_direction_EM_to_RND(int direction)
5055 return (direction == 0 ? MV_UP :
5056 direction == 1 ? MV_RIGHT :
5057 direction == 2 ? MV_DOWN :
5058 direction == 3 ? MV_LEFT :
5062 int get_next_element(int element)
5066 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5067 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5068 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5069 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5070 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5071 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5072 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5074 default: return element;
5079 int el_act_dir2img(int element, int action, int direction)
5081 element = GFX_ELEMENT(element);
5083 if (direction == MV_NONE)
5084 return element_info[element].graphic[action];
5086 direction = MV_DIR_TO_BIT(direction);
5088 return element_info[element].direction_graphic[action][direction];
5091 int el_act_dir2img(int element, int action, int direction)
5093 element = GFX_ELEMENT(element);
5094 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5096 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5097 return element_info[element].direction_graphic[action][direction];
5102 static int el_act_dir2crm(int element, int action, int direction)
5104 element = GFX_ELEMENT(element);
5106 if (direction == MV_NONE)
5107 return element_info[element].crumbled[action];
5109 direction = MV_DIR_TO_BIT(direction);
5111 return element_info[element].direction_crumbled[action][direction];
5114 static int el_act_dir2crm(int element, int action, int direction)
5116 element = GFX_ELEMENT(element);
5117 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5119 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5120 return element_info[element].direction_crumbled[action][direction];
5124 int el_act2img(int element, int action)
5126 element = GFX_ELEMENT(element);
5128 return element_info[element].graphic[action];
5131 int el_act2crm(int element, int action)
5133 element = GFX_ELEMENT(element);
5135 return element_info[element].crumbled[action];
5138 int el_dir2img(int element, int direction)
5140 element = GFX_ELEMENT(element);
5142 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5145 int el2baseimg(int element)
5147 return element_info[element].graphic[ACTION_DEFAULT];
5150 int el2img(int element)
5152 element = GFX_ELEMENT(element);
5154 return element_info[element].graphic[ACTION_DEFAULT];
5157 int el2edimg(int element)
5159 element = GFX_ELEMENT(element);
5161 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5164 int el2preimg(int element)
5166 element = GFX_ELEMENT(element);
5168 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5171 int font2baseimg(int font_nr)
5173 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5177 void setCenteredPlayerNr_EM(int centered_player_nr)
5179 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5182 int getCenteredPlayerNr_EM()
5185 if (game.centered_player_nr_next >= 0 &&
5186 !native_em_level.ply[game.centered_player_nr_next]->alive)
5187 game.centered_player_nr_next = game.centered_player_nr;
5190 if (game.centered_player_nr != game.centered_player_nr_next)
5191 game.centered_player_nr = game.centered_player_nr_next;
5193 return game.centered_player_nr;
5196 void setSetCenteredPlayer_EM(boolean set_centered_player)
5198 game.set_centered_player = set_centered_player;
5201 boolean getSetCenteredPlayer_EM()
5203 return game.set_centered_player;
5207 int getNumActivePlayers_EM()
5209 int num_players = 0;
5215 for (i = 0; i < MAX_PLAYERS; i++)
5216 if (tape.player_participates[i])
5223 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5225 int game_frame_delay_value;
5227 game_frame_delay_value =
5228 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5229 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5232 if (tape.playing && tape.warp_forward && !tape.pausing)
5233 game_frame_delay_value = 0;
5235 return game_frame_delay_value;
5239 unsigned int InitRND(long seed)
5241 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5242 return InitEngineRND_EM(seed);
5244 return InitEngineRND(seed);
5247 void InitGraphicInfo_EM(void)
5249 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5250 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5254 int num_em_gfx_errors = 0;
5256 if (graphic_info_em_object[0][0].bitmap == NULL)
5258 /* EM graphics not yet initialized in em_open_all() */
5263 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5266 /* always start with reliable default values */
5267 for (i = 0; i < TILE_MAX; i++)
5269 object_mapping[i].element_rnd = EL_UNKNOWN;
5270 object_mapping[i].is_backside = FALSE;
5271 object_mapping[i].action = ACTION_DEFAULT;
5272 object_mapping[i].direction = MV_NONE;
5275 /* always start with reliable default values */
5276 for (p = 0; p < MAX_PLAYERS; p++)
5278 for (i = 0; i < SPR_MAX; i++)
5280 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5281 player_mapping[p][i].action = ACTION_DEFAULT;
5282 player_mapping[p][i].direction = MV_NONE;
5286 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5288 int e = em_object_mapping_list[i].element_em;
5290 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5291 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5293 if (em_object_mapping_list[i].action != -1)
5294 object_mapping[e].action = em_object_mapping_list[i].action;
5296 if (em_object_mapping_list[i].direction != -1)
5297 object_mapping[e].direction =
5298 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5301 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5303 int a = em_player_mapping_list[i].action_em;
5304 int p = em_player_mapping_list[i].player_nr;
5306 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5308 if (em_player_mapping_list[i].action != -1)
5309 player_mapping[p][a].action = em_player_mapping_list[i].action;
5311 if (em_player_mapping_list[i].direction != -1)
5312 player_mapping[p][a].direction =
5313 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5316 for (i = 0; i < TILE_MAX; i++)
5318 int element = object_mapping[i].element_rnd;
5319 int action = object_mapping[i].action;
5320 int direction = object_mapping[i].direction;
5321 boolean is_backside = object_mapping[i].is_backside;
5322 boolean action_removing = (action == ACTION_DIGGING ||
5323 action == ACTION_SNAPPING ||
5324 action == ACTION_COLLECTING);
5325 boolean action_exploding = ((action == ACTION_EXPLODING ||
5326 action == ACTION_SMASHED_BY_ROCK ||
5327 action == ACTION_SMASHED_BY_SPRING) &&
5328 element != EL_DIAMOND);
5329 boolean action_active = (action == ACTION_ACTIVE);
5330 boolean action_other = (action == ACTION_OTHER);
5332 for (j = 0; j < 8; j++)
5334 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5335 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5337 i == Xdrip_stretch ? element :
5338 i == Xdrip_stretchB ? element :
5339 i == Ydrip_s1 ? element :
5340 i == Ydrip_s1B ? element :
5341 i == Xball_1B ? element :
5342 i == Xball_2 ? element :
5343 i == Xball_2B ? element :
5344 i == Yball_eat ? element :
5345 i == Ykey_1_eat ? element :
5346 i == Ykey_2_eat ? element :
5347 i == Ykey_3_eat ? element :
5348 i == Ykey_4_eat ? element :
5349 i == Ykey_5_eat ? element :
5350 i == Ykey_6_eat ? element :
5351 i == Ykey_7_eat ? element :
5352 i == Ykey_8_eat ? element :
5353 i == Ylenses_eat ? element :
5354 i == Ymagnify_eat ? element :
5355 i == Ygrass_eat ? element :
5356 i == Ydirt_eat ? element :
5357 i == Yemerald_stone ? EL_EMERALD :
5358 i == Ydiamond_stone ? EL_ROCK :
5359 i == Xsand_stonein_1 ? element :
5360 i == Xsand_stonein_2 ? element :
5361 i == Xsand_stonein_3 ? element :
5362 i == Xsand_stonein_4 ? element :
5363 is_backside ? EL_EMPTY :
5364 action_removing ? EL_EMPTY :
5366 int effective_action = (j < 7 ? action :
5367 i == Xdrip_stretch ? action :
5368 i == Xdrip_stretchB ? action :
5369 i == Ydrip_s1 ? action :
5370 i == Ydrip_s1B ? action :
5371 i == Xball_1B ? action :
5372 i == Xball_2 ? action :
5373 i == Xball_2B ? action :
5374 i == Yball_eat ? action :
5375 i == Ykey_1_eat ? action :
5376 i == Ykey_2_eat ? action :
5377 i == Ykey_3_eat ? action :
5378 i == Ykey_4_eat ? action :
5379 i == Ykey_5_eat ? action :
5380 i == Ykey_6_eat ? action :
5381 i == Ykey_7_eat ? action :
5382 i == Ykey_8_eat ? action :
5383 i == Ylenses_eat ? action :
5384 i == Ymagnify_eat ? action :
5385 i == Ygrass_eat ? action :
5386 i == Ydirt_eat ? action :
5387 i == Xsand_stonein_1 ? action :
5388 i == Xsand_stonein_2 ? action :
5389 i == Xsand_stonein_3 ? action :
5390 i == Xsand_stonein_4 ? action :
5391 i == Xsand_stoneout_1 ? action :
5392 i == Xsand_stoneout_2 ? action :
5393 i == Xboom_android ? ACTION_EXPLODING :
5394 action_exploding ? ACTION_EXPLODING :
5395 action_active ? action :
5396 action_other ? action :
5398 int graphic = (el_act_dir2img(effective_element, effective_action,
5400 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5402 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5403 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5404 boolean has_action_graphics = (graphic != base_graphic);
5405 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5406 struct GraphicInfo *g = &graphic_info[graphic];
5407 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5410 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5411 boolean special_animation = (action != ACTION_DEFAULT &&
5412 g->anim_frames == 3 &&
5413 g->anim_delay == 2 &&
5414 g->anim_mode & ANIM_LINEAR);
5415 int sync_frame = (i == Xdrip_stretch ? 7 :
5416 i == Xdrip_stretchB ? 7 :
5417 i == Ydrip_s2 ? j + 8 :
5418 i == Ydrip_s2B ? j + 8 :
5427 i == Xfake_acid_1 ? 0 :
5428 i == Xfake_acid_2 ? 10 :
5429 i == Xfake_acid_3 ? 20 :
5430 i == Xfake_acid_4 ? 30 :
5431 i == Xfake_acid_5 ? 40 :
5432 i == Xfake_acid_6 ? 50 :
5433 i == Xfake_acid_7 ? 60 :
5434 i == Xfake_acid_8 ? 70 :
5436 i == Xball_2B ? j + 8 :
5437 i == Yball_eat ? j + 1 :
5438 i == Ykey_1_eat ? j + 1 :
5439 i == Ykey_2_eat ? j + 1 :
5440 i == Ykey_3_eat ? j + 1 :
5441 i == Ykey_4_eat ? j + 1 :
5442 i == Ykey_5_eat ? j + 1 :
5443 i == Ykey_6_eat ? j + 1 :
5444 i == Ykey_7_eat ? j + 1 :
5445 i == Ykey_8_eat ? j + 1 :
5446 i == Ylenses_eat ? j + 1 :
5447 i == Ymagnify_eat ? j + 1 :
5448 i == Ygrass_eat ? j + 1 :
5449 i == Ydirt_eat ? j + 1 :
5450 i == Xamoeba_1 ? 0 :
5451 i == Xamoeba_2 ? 1 :
5452 i == Xamoeba_3 ? 2 :
5453 i == Xamoeba_4 ? 3 :
5454 i == Xamoeba_5 ? 0 :
5455 i == Xamoeba_6 ? 1 :
5456 i == Xamoeba_7 ? 2 :
5457 i == Xamoeba_8 ? 3 :
5458 i == Xexit_2 ? j + 8 :
5459 i == Xexit_3 ? j + 16 :
5460 i == Xdynamite_1 ? 0 :
5461 i == Xdynamite_2 ? 8 :
5462 i == Xdynamite_3 ? 16 :
5463 i == Xdynamite_4 ? 24 :
5464 i == Xsand_stonein_1 ? j + 1 :
5465 i == Xsand_stonein_2 ? j + 9 :
5466 i == Xsand_stonein_3 ? j + 17 :
5467 i == Xsand_stonein_4 ? j + 25 :
5468 i == Xsand_stoneout_1 && j == 0 ? 0 :
5469 i == Xsand_stoneout_1 && j == 1 ? 0 :
5470 i == Xsand_stoneout_1 && j == 2 ? 1 :
5471 i == Xsand_stoneout_1 && j == 3 ? 2 :
5472 i == Xsand_stoneout_1 && j == 4 ? 2 :
5473 i == Xsand_stoneout_1 && j == 5 ? 3 :
5474 i == Xsand_stoneout_1 && j == 6 ? 4 :
5475 i == Xsand_stoneout_1 && j == 7 ? 4 :
5476 i == Xsand_stoneout_2 && j == 0 ? 5 :
5477 i == Xsand_stoneout_2 && j == 1 ? 6 :
5478 i == Xsand_stoneout_2 && j == 2 ? 7 :
5479 i == Xsand_stoneout_2 && j == 3 ? 8 :
5480 i == Xsand_stoneout_2 && j == 4 ? 9 :
5481 i == Xsand_stoneout_2 && j == 5 ? 11 :
5482 i == Xsand_stoneout_2 && j == 6 ? 13 :
5483 i == Xsand_stoneout_2 && j == 7 ? 15 :
5484 i == Xboom_bug && j == 1 ? 2 :
5485 i == Xboom_bug && j == 2 ? 2 :
5486 i == Xboom_bug && j == 3 ? 4 :
5487 i == Xboom_bug && j == 4 ? 4 :
5488 i == Xboom_bug && j == 5 ? 2 :
5489 i == Xboom_bug && j == 6 ? 2 :
5490 i == Xboom_bug && j == 7 ? 0 :
5491 i == Xboom_bomb && j == 1 ? 2 :
5492 i == Xboom_bomb && j == 2 ? 2 :
5493 i == Xboom_bomb && j == 3 ? 4 :
5494 i == Xboom_bomb && j == 4 ? 4 :
5495 i == Xboom_bomb && j == 5 ? 2 :
5496 i == Xboom_bomb && j == 6 ? 2 :
5497 i == Xboom_bomb && j == 7 ? 0 :
5498 i == Xboom_android && j == 7 ? 6 :
5499 i == Xboom_1 && j == 1 ? 2 :
5500 i == Xboom_1 && j == 2 ? 2 :
5501 i == Xboom_1 && j == 3 ? 4 :
5502 i == Xboom_1 && j == 4 ? 4 :
5503 i == Xboom_1 && j == 5 ? 6 :
5504 i == Xboom_1 && j == 6 ? 6 :
5505 i == Xboom_1 && j == 7 ? 8 :
5506 i == Xboom_2 && j == 0 ? 8 :
5507 i == Xboom_2 && j == 1 ? 8 :
5508 i == Xboom_2 && j == 2 ? 10 :
5509 i == Xboom_2 && j == 3 ? 10 :
5510 i == Xboom_2 && j == 4 ? 10 :
5511 i == Xboom_2 && j == 5 ? 12 :
5512 i == Xboom_2 && j == 6 ? 12 :
5513 i == Xboom_2 && j == 7 ? 12 :
5514 special_animation && j == 4 ? 3 :
5515 effective_action != action ? 0 :
5519 Bitmap *debug_bitmap = g_em->bitmap;
5520 int debug_src_x = g_em->src_x;
5521 int debug_src_y = g_em->src_y;
5524 int frame = getAnimationFrame(g->anim_frames,
5527 g->anim_start_frame,
5530 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5531 g->double_movement && is_backside);
5533 g_em->bitmap = src_bitmap;
5534 g_em->src_x = src_x;
5535 g_em->src_y = src_y;
5536 g_em->src_offset_x = 0;
5537 g_em->src_offset_y = 0;
5538 g_em->dst_offset_x = 0;
5539 g_em->dst_offset_y = 0;
5540 g_em->width = TILEX;
5541 g_em->height = TILEY;
5543 g_em->crumbled_bitmap = NULL;
5544 g_em->crumbled_src_x = 0;
5545 g_em->crumbled_src_y = 0;
5546 g_em->crumbled_border_size = 0;
5548 g_em->has_crumbled_graphics = FALSE;
5549 g_em->preserve_background = FALSE;
5552 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5553 printf("::: empty crumbled: %d [%s], %d, %d\n",
5554 effective_element, element_info[effective_element].token_name,
5555 effective_action, direction);
5558 /* if element can be crumbled, but certain action graphics are just empty
5559 space (like snapping sand with the original R'n'D graphics), do not
5560 treat these empty space graphics as crumbled graphics in EMC engine */
5561 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5563 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5565 g_em->has_crumbled_graphics = TRUE;
5566 g_em->crumbled_bitmap = src_bitmap;
5567 g_em->crumbled_src_x = src_x;
5568 g_em->crumbled_src_y = src_y;
5569 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5573 if (element == EL_ROCK &&
5574 effective_action == ACTION_FILLING)
5575 printf("::: has_action_graphics == %d\n", has_action_graphics);
5578 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5579 effective_action == ACTION_MOVING ||
5580 effective_action == ACTION_PUSHING ||
5581 effective_action == ACTION_EATING)) ||
5582 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5583 effective_action == ACTION_EMPTYING)))
5586 (effective_action == ACTION_FALLING ||
5587 effective_action == ACTION_FILLING ||
5588 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5589 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5590 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5591 int num_steps = (i == Ydrip_s1 ? 16 :
5592 i == Ydrip_s1B ? 16 :
5593 i == Ydrip_s2 ? 16 :
5594 i == Ydrip_s2B ? 16 :
5595 i == Xsand_stonein_1 ? 32 :
5596 i == Xsand_stonein_2 ? 32 :
5597 i == Xsand_stonein_3 ? 32 :
5598 i == Xsand_stonein_4 ? 32 :
5599 i == Xsand_stoneout_1 ? 16 :
5600 i == Xsand_stoneout_2 ? 16 : 8);
5601 int cx = ABS(dx) * (TILEX / num_steps);
5602 int cy = ABS(dy) * (TILEY / num_steps);
5603 int step_frame = (i == Ydrip_s2 ? j + 8 :
5604 i == Ydrip_s2B ? j + 8 :
5605 i == Xsand_stonein_2 ? j + 8 :
5606 i == Xsand_stonein_3 ? j + 16 :
5607 i == Xsand_stonein_4 ? j + 24 :
5608 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5609 int step = (is_backside ? step_frame : num_steps - step_frame);
5611 if (is_backside) /* tile where movement starts */
5613 if (dx < 0 || dy < 0)
5615 g_em->src_offset_x = cx * step;
5616 g_em->src_offset_y = cy * step;
5620 g_em->dst_offset_x = cx * step;
5621 g_em->dst_offset_y = cy * step;
5624 else /* tile where movement ends */
5626 if (dx < 0 || dy < 0)
5628 g_em->dst_offset_x = cx * step;
5629 g_em->dst_offset_y = cy * step;
5633 g_em->src_offset_x = cx * step;
5634 g_em->src_offset_y = cy * step;
5638 g_em->width = TILEX - cx * step;
5639 g_em->height = TILEY - cy * step;
5643 /* create unique graphic identifier to decide if tile must be redrawn */
5644 /* bit 31 - 16 (16 bit): EM style graphic
5645 bit 15 - 12 ( 4 bit): EM style frame
5646 bit 11 - 6 ( 6 bit): graphic width
5647 bit 5 - 0 ( 6 bit): graphic height */
5648 g_em->unique_identifier =
5649 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5651 /* create unique graphic identifier to decide if tile must be redrawn */
5652 /* bit 31 - 16 (16 bit): EM style element
5653 bit 15 - 12 ( 4 bit): EM style frame
5654 bit 11 - 6 ( 6 bit): graphic width
5655 bit 5 - 0 ( 6 bit): graphic height */
5656 g_em->unique_identifier =
5657 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5661 if (effective_element == EL_ROCK)
5662 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5663 effective_action, j, graphic, frame, g_em->unique_identifier);
5669 /* skip check for EMC elements not contained in original EMC artwork */
5670 if (element == EL_EMC_FAKE_ACID)
5674 if (g_em->bitmap != debug_bitmap ||
5675 g_em->src_x != debug_src_x ||
5676 g_em->src_y != debug_src_y ||
5677 g_em->src_offset_x != 0 ||
5678 g_em->src_offset_y != 0 ||
5679 g_em->dst_offset_x != 0 ||
5680 g_em->dst_offset_y != 0 ||
5681 g_em->width != TILEX ||
5682 g_em->height != TILEY)
5684 static int last_i = -1;
5692 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5693 i, element, element_info[element].token_name,
5694 element_action_info[effective_action].suffix, direction);
5696 if (element != effective_element)
5697 printf(" [%d ('%s')]",
5699 element_info[effective_element].token_name);
5703 if (g_em->bitmap != debug_bitmap)
5704 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5705 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5707 if (g_em->src_x != debug_src_x ||
5708 g_em->src_y != debug_src_y)
5709 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5710 j, (is_backside ? 'B' : 'F'),
5711 g_em->src_x, g_em->src_y,
5712 g_em->src_x / 32, g_em->src_y / 32,
5713 debug_src_x, debug_src_y,
5714 debug_src_x / 32, debug_src_y / 32);
5716 if (g_em->src_offset_x != 0 ||
5717 g_em->src_offset_y != 0 ||
5718 g_em->dst_offset_x != 0 ||
5719 g_em->dst_offset_y != 0)
5720 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5722 g_em->src_offset_x, g_em->src_offset_y,
5723 g_em->dst_offset_x, g_em->dst_offset_y);
5725 if (g_em->width != TILEX ||
5726 g_em->height != TILEY)
5727 printf(" %d (%d): size %d,%d should be %d,%d\n",
5729 g_em->width, g_em->height, TILEX, TILEY);
5731 num_em_gfx_errors++;
5738 for (i = 0; i < TILE_MAX; i++)
5740 for (j = 0; j < 8; j++)
5742 int element = object_mapping[i].element_rnd;
5743 int action = object_mapping[i].action;
5744 int direction = object_mapping[i].direction;
5745 boolean is_backside = object_mapping[i].is_backside;
5747 int graphic_action = el_act_dir2img(element, action, direction);
5748 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5750 int graphic_action = element_info[element].graphic[action];
5751 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5754 if ((action == ACTION_SMASHED_BY_ROCK ||
5755 action == ACTION_SMASHED_BY_SPRING ||
5756 action == ACTION_EATING) &&
5757 graphic_action == graphic_default)
5759 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5760 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5761 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5762 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5765 /* no separate animation for "smashed by rock" -- use rock instead */
5766 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5767 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5769 g_em->bitmap = g_xx->bitmap;
5770 g_em->src_x = g_xx->src_x;
5771 g_em->src_y = g_xx->src_y;
5772 g_em->src_offset_x = g_xx->src_offset_x;
5773 g_em->src_offset_y = g_xx->src_offset_y;
5774 g_em->dst_offset_x = g_xx->dst_offset_x;
5775 g_em->dst_offset_y = g_xx->dst_offset_y;
5776 g_em->width = g_xx->width;
5777 g_em->height = g_xx->height;
5779 g_em->unique_identifier = g_xx->unique_identifier;
5783 g_em->preserve_background = TRUE;
5788 for (p = 0; p < MAX_PLAYERS; p++)
5790 for (i = 0; i < SPR_MAX; i++)
5792 int element = player_mapping[p][i].element_rnd;
5793 int action = player_mapping[p][i].action;
5794 int direction = player_mapping[p][i].direction;
5796 for (j = 0; j < 8; j++)
5798 int effective_element = element;
5799 int effective_action = action;
5800 int graphic = (direction == MV_NONE ?
5801 el_act2img(effective_element, effective_action) :
5802 el_act_dir2img(effective_element, effective_action,
5804 struct GraphicInfo *g = &graphic_info[graphic];
5805 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5811 Bitmap *debug_bitmap = g_em->bitmap;
5812 int debug_src_x = g_em->src_x;
5813 int debug_src_y = g_em->src_y;
5816 int frame = getAnimationFrame(g->anim_frames,
5819 g->anim_start_frame,
5822 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5824 g_em->bitmap = src_bitmap;
5825 g_em->src_x = src_x;
5826 g_em->src_y = src_y;
5827 g_em->src_offset_x = 0;
5828 g_em->src_offset_y = 0;
5829 g_em->dst_offset_x = 0;
5830 g_em->dst_offset_y = 0;
5831 g_em->width = TILEX;
5832 g_em->height = TILEY;
5837 /* skip check for EMC elements not contained in original EMC artwork */
5838 if (element == EL_PLAYER_3 ||
5839 element == EL_PLAYER_4)
5843 if (g_em->bitmap != debug_bitmap ||
5844 g_em->src_x != debug_src_x ||
5845 g_em->src_y != debug_src_y)
5847 static int last_i = -1;
5855 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5856 p, i, element, element_info[element].token_name,
5857 element_action_info[effective_action].suffix, direction);
5859 if (element != effective_element)
5860 printf(" [%d ('%s')]",
5862 element_info[effective_element].token_name);
5866 if (g_em->bitmap != debug_bitmap)
5867 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5868 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5870 if (g_em->src_x != debug_src_x ||
5871 g_em->src_y != debug_src_y)
5872 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5874 g_em->src_x, g_em->src_y,
5875 g_em->src_x / 32, g_em->src_y / 32,
5876 debug_src_x, debug_src_y,
5877 debug_src_x / 32, debug_src_y / 32);
5879 num_em_gfx_errors++;
5889 printf("::: [%d errors found]\n", num_em_gfx_errors);