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)
426 FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
428 redraw_mask = REDRAW_NONE;
431 void FadeOut(int fade_delay, int post_delay)
435 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
441 FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
443 redraw_mask = REDRAW_NONE;
446 void FadeCross(int fade_delay)
450 BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
456 FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
458 redraw_mask = REDRAW_NONE;
461 void SetMainBackgroundImageIfDefined(int graphic)
463 if (graphic_info[graphic].bitmap)
464 SetMainBackgroundImage(graphic);
467 void SetMainBackgroundImage(int graphic)
469 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
470 graphic_info[graphic].bitmap ?
471 graphic_info[graphic].bitmap :
472 graphic_info[IMG_BACKGROUND].bitmap);
475 void SetDoorBackgroundImage(int graphic)
477 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
478 graphic_info[graphic].bitmap ?
479 graphic_info[graphic].bitmap :
480 graphic_info[IMG_BACKGROUND].bitmap);
483 void DrawBackground(int dst_x, int dst_y, int width, int height)
485 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
487 redraw_mask |= REDRAW_FIELD;
492 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
494 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
496 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
497 SetDrawtoField(DRAW_BUFFERED);
500 SetDrawtoField(DRAW_BACKBUFFER);
502 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
504 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
505 SetDrawtoField(DRAW_DIRECT);
509 void MarkTileDirty(int x, int y)
511 int xx = redraw_x1 + x;
512 int yy = redraw_y1 + y;
517 redraw[xx][yy] = TRUE;
518 redraw_mask |= REDRAW_TILES;
521 void SetBorderElement()
525 BorderElement = EL_EMPTY;
527 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
529 for (x = 0; x < lev_fieldx; x++)
531 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
532 BorderElement = EL_STEELWALL;
534 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
540 void SetRandomAnimationValue(int x, int y)
542 gfx.anim_random_frame = GfxRandom[x][y];
545 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
547 /* animation synchronized with global frame counter, not move position */
548 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
549 sync_frame = FrameCounter;
552 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
558 printf("::: FOO!\n");
562 return getAnimationFrame(graphic_info[graphic].anim_frames,
563 graphic_info[graphic].anim_delay,
564 graphic_info[graphic].anim_mode,
565 graphic_info[graphic].anim_start_frame,
569 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
570 int *x, int *y, boolean get_backside)
572 struct GraphicInfo *g = &graphic_info[graphic];
573 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
574 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
578 if (g->offset_y == 0) /* frames are ordered horizontally */
580 int max_width = g->anim_frames_per_line * g->width;
581 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
583 *x = pos % max_width;
584 *y = src_y % g->height + pos / max_width * g->height;
586 else if (g->offset_x == 0) /* frames are ordered vertically */
588 int max_height = g->anim_frames_per_line * g->height;
589 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
591 *x = src_x % g->width + pos / max_height * g->width;
592 *y = pos % max_height;
594 else /* frames are ordered diagonally */
596 *x = src_x + frame * g->offset_x;
597 *y = src_y + frame * g->offset_y;
601 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
603 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
606 void DrawGraphic(int x, int y, int graphic, int frame)
609 if (!IN_SCR_FIELD(x, y))
611 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
612 printf("DrawGraphic(): This should never happen!\n");
617 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
621 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
627 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
628 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
631 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
634 if (!IN_SCR_FIELD(x, y))
636 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
637 printf("DrawGraphicThruMask(): This should never happen!\n");
642 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
647 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
653 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
655 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
656 dst_x - src_x, dst_y - src_y);
657 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
660 void DrawMiniGraphic(int x, int y, int graphic)
662 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
663 MarkTileDirty(x / 2, y / 2);
666 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
668 struct GraphicInfo *g = &graphic_info[graphic];
670 int mini_starty = g->bitmap->height * 2 / 3;
673 *x = mini_startx + g->src_x / 2;
674 *y = mini_starty + g->src_y / 2;
677 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
682 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
683 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
686 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
687 int graphic, int frame,
688 int cut_mode, int mask_mode)
693 int width = TILEX, height = TILEY;
696 if (dx || dy) /* shifted graphic */
698 if (x < BX1) /* object enters playfield from the left */
705 else if (x > BX2) /* object enters playfield from the right */
711 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
717 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
719 else if (dx) /* general horizontal movement */
720 MarkTileDirty(x + SIGN(dx), y);
722 if (y < BY1) /* object enters playfield from the top */
724 if (cut_mode==CUT_BELOW) /* object completely above top border */
732 else if (y > BY2) /* object enters playfield from the bottom */
738 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
744 else if (dy > 0 && cut_mode == CUT_ABOVE)
746 if (y == BY2) /* object completely above bottom border */
752 MarkTileDirty(x, y + 1);
753 } /* object leaves playfield to the bottom */
754 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
756 else if (dy) /* general vertical movement */
757 MarkTileDirty(x, y + SIGN(dy));
761 if (!IN_SCR_FIELD(x, y))
763 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
764 printf("DrawGraphicShifted(): This should never happen!\n");
769 if (width > 0 && height > 0)
771 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
776 dst_x = FX + x * TILEX + dx;
777 dst_y = FY + y * TILEY + dy;
779 if (mask_mode == USE_MASKING)
781 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
782 dst_x - src_x, dst_y - src_y);
783 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
787 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
794 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
795 int graphic, int frame,
796 int cut_mode, int mask_mode)
801 int width = TILEX, height = TILEY;
804 int x2 = x + SIGN(dx);
805 int y2 = y + SIGN(dy);
806 int anim_frames = graphic_info[graphic].anim_frames;
807 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
808 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
809 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
811 /* re-calculate animation frame for two-tile movement animation */
812 frame = getGraphicAnimationFrame(graphic, sync_frame);
814 /* check if movement start graphic inside screen area and should be drawn */
815 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
817 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
819 dst_x = FX + x1 * TILEX;
820 dst_y = FY + y1 * TILEY;
822 if (mask_mode == USE_MASKING)
824 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
825 dst_x - src_x, dst_y - src_y);
826 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
830 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
833 MarkTileDirty(x1, y1);
836 /* check if movement end graphic inside screen area and should be drawn */
837 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
839 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
841 dst_x = FX + x2 * TILEX;
842 dst_y = FY + y2 * TILEY;
844 if (mask_mode == USE_MASKING)
846 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
847 dst_x - src_x, dst_y - src_y);
848 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
852 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
855 MarkTileDirty(x2, y2);
859 static void DrawGraphicShifted(int x, int y, int dx, int dy,
860 int graphic, int frame,
861 int cut_mode, int mask_mode)
865 DrawGraphic(x, y, graphic, frame);
870 if (graphic_info[graphic].double_movement) /* EM style movement images */
871 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
873 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
876 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
877 int frame, int cut_mode)
879 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
882 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
883 int cut_mode, int mask_mode)
885 int lx = LEVELX(x), ly = LEVELY(y);
889 if (IN_LEV_FIELD(lx, ly))
891 SetRandomAnimationValue(lx, ly);
893 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
894 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
896 /* do not use double (EM style) movement graphic when not moving */
897 if (graphic_info[graphic].double_movement && !dx && !dy)
899 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
900 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
903 else /* border element */
905 graphic = el2img(element);
906 frame = getGraphicAnimationFrame(graphic, -1);
909 if (element == EL_EXPANDABLE_WALL)
911 boolean left_stopped = FALSE, right_stopped = FALSE;
913 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
915 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
916 right_stopped = TRUE;
918 if (left_stopped && right_stopped)
920 else if (left_stopped)
922 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
923 frame = graphic_info[graphic].anim_frames - 1;
925 else if (right_stopped)
927 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
928 frame = graphic_info[graphic].anim_frames - 1;
933 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
934 else if (mask_mode == USE_MASKING)
935 DrawGraphicThruMask(x, y, graphic, frame);
937 DrawGraphic(x, y, graphic, frame);
940 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
941 int cut_mode, int mask_mode)
943 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
944 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
945 cut_mode, mask_mode);
948 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
951 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
954 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
957 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
960 void DrawLevelElementThruMask(int x, int y, int element)
962 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
965 void DrawLevelFieldThruMask(int x, int y)
967 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
970 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
974 int sx = SCREENX(x), sy = SCREENY(y);
976 int width, height, cx, cy, i;
977 int crumbled_border_size = graphic_info[graphic].border_size;
978 static int xy[4][2] =
986 if (!IN_LEV_FIELD(x, y))
989 element = TILE_GFX_ELEMENT(x, y);
991 /* crumble field itself */
992 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
994 if (!IN_SCR_FIELD(sx, sy))
997 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
999 for (i = 0; i < 4; i++)
1001 int xx = x + xy[i][0];
1002 int yy = y + xy[i][1];
1004 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1007 /* check if neighbour field is of same type */
1008 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1011 if (i == 1 || i == 2)
1013 width = crumbled_border_size;
1015 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1021 height = crumbled_border_size;
1023 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1026 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1027 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1030 MarkTileDirty(sx, sy);
1032 else /* crumble neighbour fields */
1034 for (i = 0; i < 4; i++)
1036 int xx = x + xy[i][0];
1037 int yy = y + xy[i][1];
1038 int sxx = sx + xy[i][0];
1039 int syy = sy + xy[i][1];
1042 if (!IN_LEV_FIELD(xx, yy) ||
1043 !IN_SCR_FIELD(sxx, syy) ||
1048 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1052 element = TILE_GFX_ELEMENT(xx, yy);
1054 if (!GFX_CRUMBLED(element))
1057 if (!IN_LEV_FIELD(xx, yy) ||
1058 !IN_SCR_FIELD(sxx, syy) ||
1059 !GFX_CRUMBLED(Feld[xx][yy]) ||
1065 graphic = el_act2crm(element, ACTION_DEFAULT);
1067 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1069 crumbled_border_size = graphic_info[graphic].border_size;
1071 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1073 if (i == 1 || i == 2)
1075 width = crumbled_border_size;
1077 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1083 height = crumbled_border_size;
1085 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1088 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1089 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1091 MarkTileDirty(sxx, syy);
1096 void DrawLevelFieldCrumbledSand(int x, int y)
1100 if (!IN_LEV_FIELD(x, y))
1104 /* !!! CHECK THIS !!! */
1107 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1108 GFX_CRUMBLED(GfxElement[x][y]))
1111 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1112 GfxElement[x][y] != EL_UNDEFINED &&
1113 GFX_CRUMBLED(GfxElement[x][y]))
1115 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1122 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1124 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1127 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1130 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1133 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1134 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1135 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1136 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1137 int sx = SCREENX(x), sy = SCREENY(y);
1139 DrawGraphic(sx, sy, graphic1, frame1);
1140 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1143 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1145 int sx = SCREENX(x), sy = SCREENY(y);
1146 static int xy[4][2] =
1155 for (i = 0; i < 4; i++)
1157 int xx = x + xy[i][0];
1158 int yy = y + xy[i][1];
1159 int sxx = sx + xy[i][0];
1160 int syy = sy + xy[i][1];
1162 if (!IN_LEV_FIELD(xx, yy) ||
1163 !IN_SCR_FIELD(sxx, syy) ||
1164 !GFX_CRUMBLED(Feld[xx][yy]) ||
1168 DrawLevelField(xx, yy);
1172 static int getBorderElement(int x, int y)
1176 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1177 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1178 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1179 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1180 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1181 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1182 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1184 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1185 int steel_position = (x == -1 && y == -1 ? 0 :
1186 x == lev_fieldx && y == -1 ? 1 :
1187 x == -1 && y == lev_fieldy ? 2 :
1188 x == lev_fieldx && y == lev_fieldy ? 3 :
1189 x == -1 || x == lev_fieldx ? 4 :
1190 y == -1 || y == lev_fieldy ? 5 : 6);
1192 return border[steel_position][steel_type];
1195 void DrawScreenElement(int x, int y, int element)
1197 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1198 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1201 void DrawLevelElement(int x, int y, int element)
1203 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1204 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1207 void DrawScreenField(int x, int y)
1209 int lx = LEVELX(x), ly = LEVELY(y);
1210 int element, content;
1212 if (!IN_LEV_FIELD(lx, ly))
1214 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1217 element = getBorderElement(lx, ly);
1219 DrawScreenElement(x, y, element);
1223 element = Feld[lx][ly];
1224 content = Store[lx][ly];
1226 if (IS_MOVING(lx, ly))
1228 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1229 boolean cut_mode = NO_CUTTING;
1231 if (element == EL_QUICKSAND_EMPTYING ||
1232 element == EL_MAGIC_WALL_EMPTYING ||
1233 element == EL_BD_MAGIC_WALL_EMPTYING ||
1234 element == EL_AMOEBA_DROPPING)
1235 cut_mode = CUT_ABOVE;
1236 else if (element == EL_QUICKSAND_FILLING ||
1237 element == EL_MAGIC_WALL_FILLING ||
1238 element == EL_BD_MAGIC_WALL_FILLING)
1239 cut_mode = CUT_BELOW;
1241 if (cut_mode == CUT_ABOVE)
1242 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1244 DrawScreenElement(x, y, EL_EMPTY);
1247 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1248 else if (cut_mode == NO_CUTTING)
1249 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1251 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1253 if (content == EL_ACID)
1255 int dir = MovDir[lx][ly];
1256 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1257 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1259 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1262 else if (IS_BLOCKED(lx, ly))
1267 boolean cut_mode = NO_CUTTING;
1268 int element_old, content_old;
1270 Blocked2Moving(lx, ly, &oldx, &oldy);
1273 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1274 MovDir[oldx][oldy] == MV_RIGHT);
1276 element_old = Feld[oldx][oldy];
1277 content_old = Store[oldx][oldy];
1279 if (element_old == EL_QUICKSAND_EMPTYING ||
1280 element_old == EL_MAGIC_WALL_EMPTYING ||
1281 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1282 element_old == EL_AMOEBA_DROPPING)
1283 cut_mode = CUT_ABOVE;
1285 DrawScreenElement(x, y, EL_EMPTY);
1288 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1290 else if (cut_mode == NO_CUTTING)
1291 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1294 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1297 else if (IS_DRAWABLE(element))
1298 DrawScreenElement(x, y, element);
1300 DrawScreenElement(x, y, EL_EMPTY);
1303 void DrawLevelField(int x, int y)
1305 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1306 DrawScreenField(SCREENX(x), SCREENY(y));
1307 else if (IS_MOVING(x, y))
1311 Moving2Blocked(x, y, &newx, &newy);
1312 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1313 DrawScreenField(SCREENX(newx), SCREENY(newy));
1315 else if (IS_BLOCKED(x, y))
1319 Blocked2Moving(x, y, &oldx, &oldy);
1320 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1321 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1325 void DrawMiniElement(int x, int y, int element)
1329 graphic = el2edimg(element);
1330 DrawMiniGraphic(x, y, graphic);
1333 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1335 int x = sx + scroll_x, y = sy + scroll_y;
1337 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1338 DrawMiniElement(sx, sy, EL_EMPTY);
1339 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1340 DrawMiniElement(sx, sy, Feld[x][y]);
1342 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1345 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1346 int x, int y, int xsize, int ysize, int font_nr)
1348 int font_width = getFontWidth(font_nr);
1349 int font_height = getFontHeight(font_nr);
1350 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1353 int dst_x = SX + startx + x * font_width;
1354 int dst_y = SY + starty + y * font_height;
1355 int width = graphic_info[graphic].width;
1356 int height = graphic_info[graphic].height;
1357 int inner_width = MAX(width - 2 * font_width, font_width);
1358 int inner_height = MAX(height - 2 * font_height, font_height);
1359 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1360 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1361 boolean draw_masked = graphic_info[graphic].draw_masked;
1363 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1365 if (src_bitmap == NULL || width < font_width || height < font_height)
1367 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1371 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1372 inner_sx + (x - 1) * font_width % inner_width);
1373 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1374 inner_sy + (y - 1) * font_height % inner_height);
1378 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1379 dst_x - src_x, dst_y - src_y);
1380 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1384 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1388 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1390 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1391 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1392 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1393 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1394 boolean no_delay = (tape.warp_forward);
1395 unsigned long anim_delay = 0;
1396 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1397 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1398 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1399 int font_width = getFontWidth(font_nr);
1400 int font_height = getFontHeight(font_nr);
1401 int max_xsize = level.envelope[envelope_nr].xsize;
1402 int max_ysize = level.envelope[envelope_nr].ysize;
1403 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1404 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1405 int xend = max_xsize;
1406 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1407 int xstep = (xstart < xend ? 1 : 0);
1408 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1411 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1413 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1414 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1415 int sx = (SXSIZE - xsize * font_width) / 2;
1416 int sy = (SYSIZE - ysize * font_height) / 2;
1419 SetDrawtoField(DRAW_BUFFERED);
1421 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1423 SetDrawtoField(DRAW_BACKBUFFER);
1425 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1426 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1428 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1429 level.envelope[envelope_nr].text, font_nr, max_xsize,
1430 xsize - 2, ysize - 2, mask_mode);
1432 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1435 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1439 void ShowEnvelope(int envelope_nr)
1441 int element = EL_ENVELOPE_1 + envelope_nr;
1442 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1443 int sound_opening = element_info[element].sound[ACTION_OPENING];
1444 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1445 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1446 boolean no_delay = (tape.warp_forward);
1447 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1448 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1449 int anim_mode = graphic_info[graphic].anim_mode;
1450 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1451 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1453 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1455 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1457 if (anim_mode == ANIM_DEFAULT)
1458 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1460 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1463 Delay(wait_delay_value);
1465 WaitForEventToContinue();
1467 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1469 if (anim_mode != ANIM_NONE)
1470 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1472 if (anim_mode == ANIM_DEFAULT)
1473 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1475 game.envelope_active = FALSE;
1477 SetDrawtoField(DRAW_BUFFERED);
1479 redraw_mask |= REDRAW_FIELD;
1483 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1485 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1486 int mini_startx = src_bitmap->width * 3 / 4;
1487 int mini_starty = src_bitmap->height * 2 / 3;
1488 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1489 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1491 *bitmap = src_bitmap;
1496 void DrawMicroElement(int xpos, int ypos, int element)
1500 int graphic = el2preimg(element);
1502 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1503 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1511 SetDrawBackgroundMask(REDRAW_NONE);
1514 for (x = BX1; x <= BX2; x++)
1515 for (y = BY1; y <= BY2; y++)
1516 DrawScreenField(x, y);
1518 redraw_mask |= REDRAW_FIELD;
1521 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1525 for (x = 0; x < size_x; x++)
1526 for (y = 0; y < size_y; y++)
1527 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1529 redraw_mask |= REDRAW_FIELD;
1532 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1536 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1538 if (lev_fieldx < STD_LEV_FIELDX)
1539 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1540 if (lev_fieldy < STD_LEV_FIELDY)
1541 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1543 xpos += MICRO_TILEX;
1544 ypos += MICRO_TILEY;
1546 for (x = -1; x <= STD_LEV_FIELDX; x++)
1548 for (y = -1; y <= STD_LEV_FIELDY; y++)
1550 int lx = from_x + x, ly = from_y + y;
1552 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1553 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1554 level.field[lx][ly]);
1555 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1556 && BorderElement != EL_EMPTY)
1557 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1558 getBorderElement(lx, ly));
1562 redraw_mask |= REDRAW_MICROLEVEL;
1565 #define MICROLABEL_EMPTY 0
1566 #define MICROLABEL_LEVEL_NAME 1
1567 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1568 #define MICROLABEL_LEVEL_AUTHOR 3
1569 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1570 #define MICROLABEL_IMPORTED_FROM 5
1571 #define MICROLABEL_IMPORTED_BY_HEAD 6
1572 #define MICROLABEL_IMPORTED_BY 7
1574 static void DrawMicroLevelLabelExt(int mode)
1576 char label_text[MAX_OUTPUT_LINESIZE + 1];
1577 int max_len_label_text;
1578 int font_nr = FONT_TEXT_2;
1581 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1582 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1583 mode == MICROLABEL_IMPORTED_BY_HEAD)
1584 font_nr = FONT_TEXT_3;
1586 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1588 for (i = 0; i < max_len_label_text; i++)
1589 label_text[i] = ' ';
1590 label_text[max_len_label_text] = '\0';
1592 if (strlen(label_text) > 0)
1594 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1595 int lypos = MICROLABEL2_YPOS;
1597 DrawText(lxpos, lypos, label_text, font_nr);
1601 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1602 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1603 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1604 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1605 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1606 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1607 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1608 max_len_label_text);
1609 label_text[max_len_label_text] = '\0';
1611 if (strlen(label_text) > 0)
1613 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1614 int lypos = MICROLABEL2_YPOS;
1616 DrawText(lxpos, lypos, label_text, font_nr);
1619 redraw_mask |= REDRAW_MICROLEVEL;
1622 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1624 static unsigned long scroll_delay = 0;
1625 static unsigned long label_delay = 0;
1626 static int from_x, from_y, scroll_direction;
1627 static int label_state, label_counter;
1628 int last_game_status = game_status; /* save current game status */
1630 /* force PREVIEW font on preview level */
1631 game_status = GAME_MODE_PSEUDO_PREVIEW;
1635 from_x = from_y = 0;
1636 scroll_direction = MV_RIGHT;
1640 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1641 DrawMicroLevelLabelExt(label_state);
1643 /* initialize delay counters */
1644 DelayReached(&scroll_delay, 0);
1645 DelayReached(&label_delay, 0);
1647 if (leveldir_current->name)
1649 char label_text[MAX_OUTPUT_LINESIZE + 1];
1650 int font_nr = FONT_TEXT_1;
1651 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1654 strncpy(label_text, leveldir_current->name, max_len_label_text);
1655 label_text[max_len_label_text] = '\0';
1657 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1658 lypos = SY + MICROLABEL1_YPOS;
1660 DrawText(lxpos, lypos, label_text, font_nr);
1663 game_status = last_game_status; /* restore current game status */
1668 /* scroll micro level, if needed */
1669 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1670 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1672 switch (scroll_direction)
1678 scroll_direction = MV_UP;
1682 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1685 scroll_direction = MV_DOWN;
1692 scroll_direction = MV_RIGHT;
1696 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1699 scroll_direction = MV_LEFT;
1706 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1709 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1710 /* redraw micro level label, if needed */
1711 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1712 !strEqual(level.author, ANONYMOUS_NAME) &&
1713 !strEqual(level.author, leveldir_current->name) &&
1714 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1716 int max_label_counter = 23;
1718 if (leveldir_current->imported_from != NULL &&
1719 strlen(leveldir_current->imported_from) > 0)
1720 max_label_counter += 14;
1721 if (leveldir_current->imported_by != NULL &&
1722 strlen(leveldir_current->imported_by) > 0)
1723 max_label_counter += 14;
1725 label_counter = (label_counter + 1) % max_label_counter;
1726 label_state = (label_counter >= 0 && label_counter <= 7 ?
1727 MICROLABEL_LEVEL_NAME :
1728 label_counter >= 9 && label_counter <= 12 ?
1729 MICROLABEL_LEVEL_AUTHOR_HEAD :
1730 label_counter >= 14 && label_counter <= 21 ?
1731 MICROLABEL_LEVEL_AUTHOR :
1732 label_counter >= 23 && label_counter <= 26 ?
1733 MICROLABEL_IMPORTED_FROM_HEAD :
1734 label_counter >= 28 && label_counter <= 35 ?
1735 MICROLABEL_IMPORTED_FROM :
1736 label_counter >= 37 && label_counter <= 40 ?
1737 MICROLABEL_IMPORTED_BY_HEAD :
1738 label_counter >= 42 && label_counter <= 49 ?
1739 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1741 if (leveldir_current->imported_from == NULL &&
1742 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1743 label_state == MICROLABEL_IMPORTED_FROM))
1744 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1745 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1747 DrawMicroLevelLabelExt(label_state);
1750 game_status = last_game_status; /* restore current game status */
1753 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1754 int graphic, int sync_frame, int mask_mode)
1756 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1758 if (mask_mode == USE_MASKING)
1759 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1761 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1764 inline void DrawGraphicAnimation(int x, int y, int graphic)
1766 int lx = LEVELX(x), ly = LEVELY(y);
1768 if (!IN_SCR_FIELD(x, y))
1771 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1772 graphic, GfxFrame[lx][ly], NO_MASKING);
1773 MarkTileDirty(x, y);
1776 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1778 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1781 void DrawLevelElementAnimation(int x, int y, int element)
1783 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1785 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1788 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1790 int sx = SCREENX(x), sy = SCREENY(y);
1792 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1795 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1798 DrawGraphicAnimation(sx, sy, graphic);
1801 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1802 DrawLevelFieldCrumbledSand(x, y);
1804 if (GFX_CRUMBLED(Feld[x][y]))
1805 DrawLevelFieldCrumbledSand(x, y);
1809 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1811 int sx = SCREENX(x), sy = SCREENY(y);
1814 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1817 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1819 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1822 DrawGraphicAnimation(sx, sy, graphic);
1824 if (GFX_CRUMBLED(element))
1825 DrawLevelFieldCrumbledSand(x, y);
1828 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1830 if (player->use_murphy)
1832 /* this works only because currently only one player can be "murphy" ... */
1833 static int last_horizontal_dir = MV_LEFT;
1834 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1836 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1837 last_horizontal_dir = move_dir;
1839 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1841 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1843 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1849 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1852 static boolean equalGraphics(int graphic1, int graphic2)
1854 struct GraphicInfo *g1 = &graphic_info[graphic1];
1855 struct GraphicInfo *g2 = &graphic_info[graphic2];
1857 return (g1->bitmap == g2->bitmap &&
1858 g1->src_x == g2->src_x &&
1859 g1->src_y == g2->src_y &&
1860 g1->anim_frames == g2->anim_frames &&
1861 g1->anim_delay == g2->anim_delay &&
1862 g1->anim_mode == g2->anim_mode);
1865 void DrawAllPlayers()
1869 for (i = 0; i < MAX_PLAYERS; i++)
1870 if (stored_player[i].active)
1871 DrawPlayer(&stored_player[i]);
1874 void DrawPlayerField(int x, int y)
1876 if (!IS_PLAYER(x, y))
1879 DrawPlayer(PLAYERINFO(x, y));
1882 void DrawPlayer(struct PlayerInfo *player)
1884 int jx = player->jx;
1885 int jy = player->jy;
1886 int move_dir = player->MovDir;
1887 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1888 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1889 int last_jx = (player->is_moving ? jx - dx : jx);
1890 int last_jy = (player->is_moving ? jy - dy : jy);
1891 int next_jx = jx + dx;
1892 int next_jy = jy + dy;
1893 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1894 boolean player_is_opaque = FALSE;
1895 int sx = SCREENX(jx), sy = SCREENY(jy);
1896 int sxx = 0, syy = 0;
1897 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1899 int action = ACTION_DEFAULT;
1900 int last_player_graphic = getPlayerGraphic(player, move_dir);
1901 int last_player_frame = player->Frame;
1905 /* GfxElement[][] is set to the element the player is digging or collecting;
1906 remove also for off-screen player if the player is not moving anymore */
1907 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1908 GfxElement[jx][jy] = EL_UNDEFINED;
1911 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1915 if (!IN_LEV_FIELD(jx, jy))
1917 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1918 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1919 printf("DrawPlayerField(): This should never happen!\n");
1924 if (element == EL_EXPLOSION)
1927 action = (player->is_pushing ? ACTION_PUSHING :
1928 player->is_digging ? ACTION_DIGGING :
1929 player->is_collecting ? ACTION_COLLECTING :
1930 player->is_moving ? ACTION_MOVING :
1931 player->is_snapping ? ACTION_SNAPPING :
1932 player->is_dropping ? ACTION_DROPPING :
1933 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1936 if (player->is_waiting)
1937 move_dir = player->dir_waiting;
1940 InitPlayerGfxAnimation(player, action, move_dir);
1942 /* ----------------------------------------------------------------------- */
1943 /* draw things in the field the player is leaving, if needed */
1944 /* ----------------------------------------------------------------------- */
1946 if (player->is_moving)
1948 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1950 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1952 if (last_element == EL_DYNAMITE_ACTIVE ||
1953 last_element == EL_EM_DYNAMITE_ACTIVE ||
1954 last_element == EL_SP_DISK_RED_ACTIVE)
1955 DrawDynamite(last_jx, last_jy);
1957 DrawLevelFieldThruMask(last_jx, last_jy);
1959 else if (last_element == EL_DYNAMITE_ACTIVE ||
1960 last_element == EL_EM_DYNAMITE_ACTIVE ||
1961 last_element == EL_SP_DISK_RED_ACTIVE)
1962 DrawDynamite(last_jx, last_jy);
1964 /* !!! this is not enough to prevent flickering of players which are
1965 moving next to each others without a free tile between them -- this
1966 can only be solved by drawing all players layer by layer (first the
1967 background, then the foreground etc.) !!! => TODO */
1968 else if (!IS_PLAYER(last_jx, last_jy))
1969 DrawLevelField(last_jx, last_jy);
1972 DrawLevelField(last_jx, last_jy);
1975 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1976 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1979 if (!IN_SCR_FIELD(sx, sy))
1982 if (setup.direct_draw)
1983 SetDrawtoField(DRAW_BUFFERED);
1985 /* ----------------------------------------------------------------------- */
1986 /* draw things behind the player, if needed */
1987 /* ----------------------------------------------------------------------- */
1990 DrawLevelElement(jx, jy, Back[jx][jy]);
1991 else if (IS_ACTIVE_BOMB(element))
1992 DrawLevelElement(jx, jy, EL_EMPTY);
1995 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1997 int old_element = GfxElement[jx][jy];
1998 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1999 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2001 if (GFX_CRUMBLED(old_element))
2002 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2004 DrawGraphic(sx, sy, old_graphic, frame);
2006 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2007 player_is_opaque = TRUE;
2011 GfxElement[jx][jy] = EL_UNDEFINED;
2013 /* make sure that pushed elements are drawn with correct frame rate */
2014 if (player->is_pushing && player->is_moving)
2015 GfxFrame[jx][jy] = player->StepFrame;
2017 DrawLevelField(jx, jy);
2021 /* ----------------------------------------------------------------------- */
2022 /* draw player himself */
2023 /* ----------------------------------------------------------------------- */
2025 graphic = getPlayerGraphic(player, move_dir);
2027 /* in the case of changed player action or direction, prevent the current
2028 animation frame from being restarted for identical animations */
2029 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2030 player->Frame = last_player_frame;
2032 frame = getGraphicAnimationFrame(graphic, player->Frame);
2036 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2037 sxx = player->GfxPos;
2039 syy = player->GfxPos;
2042 if (!setup.soft_scrolling && ScreenMovPos)
2045 if (player_is_opaque)
2046 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2048 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2050 if (SHIELD_ON(player))
2052 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2053 IMG_SHIELD_NORMAL_ACTIVE);
2054 int frame = getGraphicAnimationFrame(graphic, -1);
2056 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2059 /* ----------------------------------------------------------------------- */
2060 /* draw things the player is pushing, if needed */
2061 /* ----------------------------------------------------------------------- */
2064 printf("::: %d, %d [%d, %d] [%d]\n",
2065 player->is_pushing, player_is_moving, player->GfxAction,
2066 player->is_moving, player_is_moving);
2070 if (player->is_pushing && player->is_moving)
2072 int px = SCREENX(jx), py = SCREENY(jy);
2073 int pxx = (TILEX - ABS(sxx)) * dx;
2074 int pyy = (TILEY - ABS(syy)) * dy;
2079 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2080 element = Feld[next_jx][next_jy];
2082 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2083 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2085 /* draw background element under pushed element (like the Sokoban field) */
2086 if (Back[next_jx][next_jy])
2087 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2089 /* masked drawing is needed for EMC style (double) movement graphics */
2090 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2094 /* ----------------------------------------------------------------------- */
2095 /* draw things in front of player (active dynamite or dynabombs) */
2096 /* ----------------------------------------------------------------------- */
2098 if (IS_ACTIVE_BOMB(element))
2100 graphic = el2img(element);
2101 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2103 if (game.emulation == EMU_SUPAPLEX)
2104 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2106 DrawGraphicThruMask(sx, sy, graphic, frame);
2109 if (player_is_moving && last_element == EL_EXPLOSION)
2111 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2112 GfxElement[last_jx][last_jy] : EL_EMPTY);
2113 int graphic = el_act2img(element, ACTION_EXPLODING);
2114 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2115 int phase = ExplodePhase[last_jx][last_jy] - 1;
2116 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2119 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2122 /* ----------------------------------------------------------------------- */
2123 /* draw elements the player is just walking/passing through/under */
2124 /* ----------------------------------------------------------------------- */
2126 if (player_is_moving)
2128 /* handle the field the player is leaving ... */
2129 if (IS_ACCESSIBLE_INSIDE(last_element))
2130 DrawLevelField(last_jx, last_jy);
2131 else if (IS_ACCESSIBLE_UNDER(last_element))
2132 DrawLevelFieldThruMask(last_jx, last_jy);
2135 /* do not redraw accessible elements if the player is just pushing them */
2136 if (!player_is_moving || !player->is_pushing)
2138 /* ... and the field the player is entering */
2139 if (IS_ACCESSIBLE_INSIDE(element))
2140 DrawLevelField(jx, jy);
2141 else if (IS_ACCESSIBLE_UNDER(element))
2142 DrawLevelFieldThruMask(jx, jy);
2145 if (setup.direct_draw)
2147 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2148 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2149 int x_size = TILEX * (1 + ABS(jx - last_jx));
2150 int y_size = TILEY * (1 + ABS(jy - last_jy));
2152 BlitBitmap(drawto_field, window,
2153 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2154 SetDrawtoField(DRAW_DIRECT);
2157 MarkTileDirty(sx, sy);
2160 /* ------------------------------------------------------------------------- */
2162 void WaitForEventToContinue()
2164 boolean still_wait = TRUE;
2166 /* simulate releasing mouse button over last gadget, if still pressed */
2168 HandleGadgets(-1, -1, 0);
2170 button_status = MB_RELEASED;
2182 case EVENT_BUTTONPRESS:
2183 case EVENT_KEYPRESS:
2187 case EVENT_KEYRELEASE:
2188 ClearPlayerAction();
2192 HandleOtherEvents(&event);
2196 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2203 /* don't eat all CPU time */
2208 #define MAX_REQUEST_LINES 13
2209 #define MAX_REQUEST_LINE_FONT1_LEN 7
2210 #define MAX_REQUEST_LINE_FONT2_LEN 10
2212 boolean Request(char *text, unsigned int req_state)
2214 int mx, my, ty, result = -1;
2215 unsigned int old_door_state;
2216 int last_game_status = game_status; /* save current game status */
2217 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2218 int font_nr = FONT_TEXT_2;
2219 int max_word_len = 0;
2222 for (text_ptr = text; *text_ptr; text_ptr++)
2224 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2226 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2228 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2229 font_nr = FONT_LEVEL_NUMBER;
2235 if (game_status == GAME_MODE_PLAYING &&
2236 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2237 BlitScreenToBitmap_EM(backbuffer);
2239 /* disable deactivated drawing when quick-loading level tape recording */
2240 if (tape.playing && tape.deactivate_display)
2241 TapeDeactivateDisplayOff(TRUE);
2243 SetMouseCursor(CURSOR_DEFAULT);
2245 #if defined(NETWORK_AVALIABLE)
2246 /* pause network game while waiting for request to answer */
2247 if (options.network &&
2248 game_status == GAME_MODE_PLAYING &&
2249 req_state & REQUEST_WAIT_FOR_INPUT)
2250 SendToServer_PausePlaying();
2253 old_door_state = GetDoorState();
2255 /* simulate releasing mouse button over last gadget, if still pressed */
2257 HandleGadgets(-1, -1, 0);
2261 if (old_door_state & DOOR_OPEN_1)
2263 CloseDoor(DOOR_CLOSE_1);
2265 /* save old door content */
2266 BlitBitmap(bitmap_db_door, bitmap_db_door,
2267 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2268 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2271 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2273 /* clear door drawing field */
2274 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2276 /* force DOOR font on preview level */
2277 game_status = GAME_MODE_PSEUDO_DOOR;
2279 /* write text for request */
2280 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2282 char text_line[max_request_line_len + 1];
2288 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2291 if (!tc || tc == ' ')
2302 strncpy(text_line, text, tl);
2305 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2306 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2307 text_line, font_nr);
2309 text += tl + (tc == ' ' ? 1 : 0);
2312 game_status = last_game_status; /* restore current game status */
2314 if (req_state & REQ_ASK)
2316 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2317 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2319 else if (req_state & REQ_CONFIRM)
2321 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2323 else if (req_state & REQ_PLAYER)
2325 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2326 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2327 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2328 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2331 /* copy request gadgets to door backbuffer */
2332 BlitBitmap(drawto, bitmap_db_door,
2333 DX, DY, DXSIZE, DYSIZE,
2334 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2336 OpenDoor(DOOR_OPEN_1);
2338 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2340 SetDrawBackgroundMask(REDRAW_FIELD);
2345 if (game_status != GAME_MODE_MAIN)
2348 button_status = MB_RELEASED;
2350 request_gadget_id = -1;
2352 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2364 case EVENT_BUTTONPRESS:
2365 case EVENT_BUTTONRELEASE:
2366 case EVENT_MOTIONNOTIFY:
2368 if (event.type == EVENT_MOTIONNOTIFY)
2370 if (!PointerInWindow(window))
2371 continue; /* window and pointer are on different screens */
2376 motion_status = TRUE;
2377 mx = ((MotionEvent *) &event)->x;
2378 my = ((MotionEvent *) &event)->y;
2382 motion_status = FALSE;
2383 mx = ((ButtonEvent *) &event)->x;
2384 my = ((ButtonEvent *) &event)->y;
2385 if (event.type == EVENT_BUTTONPRESS)
2386 button_status = ((ButtonEvent *) &event)->button;
2388 button_status = MB_RELEASED;
2391 /* this sets 'request_gadget_id' */
2392 HandleGadgets(mx, my, button_status);
2394 switch(request_gadget_id)
2396 case TOOL_CTRL_ID_YES:
2399 case TOOL_CTRL_ID_NO:
2402 case TOOL_CTRL_ID_CONFIRM:
2403 result = TRUE | FALSE;
2406 case TOOL_CTRL_ID_PLAYER_1:
2409 case TOOL_CTRL_ID_PLAYER_2:
2412 case TOOL_CTRL_ID_PLAYER_3:
2415 case TOOL_CTRL_ID_PLAYER_4:
2426 case EVENT_KEYPRESS:
2427 switch(GetEventKey((KeyEvent *)&event, TRUE))
2440 if (req_state & REQ_PLAYER)
2444 case EVENT_KEYRELEASE:
2445 ClearPlayerAction();
2449 HandleOtherEvents(&event);
2453 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2455 int joy = AnyJoystick();
2457 if (joy & JOY_BUTTON_1)
2459 else if (joy & JOY_BUTTON_2)
2465 /* don't eat all CPU time */
2469 if (game_status != GAME_MODE_MAIN)
2474 if (!(req_state & REQ_STAY_OPEN))
2476 CloseDoor(DOOR_CLOSE_1);
2478 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2479 (req_state & REQ_REOPEN))
2480 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2485 SetDrawBackgroundMask(REDRAW_FIELD);
2487 #if defined(NETWORK_AVALIABLE)
2488 /* continue network game after request */
2489 if (options.network &&
2490 game_status == GAME_MODE_PLAYING &&
2491 req_state & REQUEST_WAIT_FOR_INPUT)
2492 SendToServer_ContinuePlaying();
2495 /* restore deactivated drawing when quick-loading level tape recording */
2496 if (tape.playing && tape.deactivate_display)
2497 TapeDeactivateDisplayOn();
2502 unsigned int OpenDoor(unsigned int door_state)
2504 if (door_state & DOOR_COPY_BACK)
2506 if (door_state & DOOR_OPEN_1)
2507 BlitBitmap(bitmap_db_door, bitmap_db_door,
2508 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2509 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2511 if (door_state & DOOR_OPEN_2)
2512 BlitBitmap(bitmap_db_door, bitmap_db_door,
2513 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2514 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2516 door_state &= ~DOOR_COPY_BACK;
2519 return MoveDoor(door_state);
2522 unsigned int CloseDoor(unsigned int door_state)
2524 unsigned int old_door_state = GetDoorState();
2526 if (!(door_state & DOOR_NO_COPY_BACK))
2528 if (old_door_state & DOOR_OPEN_1)
2529 BlitBitmap(backbuffer, bitmap_db_door,
2530 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2532 if (old_door_state & DOOR_OPEN_2)
2533 BlitBitmap(backbuffer, bitmap_db_door,
2534 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2536 door_state &= ~DOOR_NO_COPY_BACK;
2539 return MoveDoor(door_state);
2542 unsigned int GetDoorState()
2544 return MoveDoor(DOOR_GET_STATE);
2547 unsigned int SetDoorState(unsigned int door_state)
2549 return MoveDoor(door_state | DOOR_SET_STATE);
2552 unsigned int MoveDoor(unsigned int door_state)
2554 static int door1 = DOOR_OPEN_1;
2555 static int door2 = DOOR_CLOSE_2;
2556 unsigned long door_delay = 0;
2557 unsigned long door_delay_value;
2560 if (door_1.width < 0 || door_1.width > DXSIZE)
2561 door_1.width = DXSIZE;
2562 if (door_1.height < 0 || door_1.height > DYSIZE)
2563 door_1.height = DYSIZE;
2564 if (door_2.width < 0 || door_2.width > VXSIZE)
2565 door_2.width = VXSIZE;
2566 if (door_2.height < 0 || door_2.height > VYSIZE)
2567 door_2.height = VYSIZE;
2569 if (door_state == DOOR_GET_STATE)
2570 return (door1 | door2);
2572 if (door_state & DOOR_SET_STATE)
2574 if (door_state & DOOR_ACTION_1)
2575 door1 = door_state & DOOR_ACTION_1;
2576 if (door_state & DOOR_ACTION_2)
2577 door2 = door_state & DOOR_ACTION_2;
2579 return (door1 | door2);
2582 if (!(door_state & DOOR_FORCE_REDRAW))
2584 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2585 door_state &= ~DOOR_OPEN_1;
2586 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2587 door_state &= ~DOOR_CLOSE_1;
2588 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2589 door_state &= ~DOOR_OPEN_2;
2590 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2591 door_state &= ~DOOR_CLOSE_2;
2594 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2597 if (setup.quick_doors)
2599 stepsize = 20; /* must be choosen to always draw last frame */
2600 door_delay_value = 0;
2603 if (global.autoplay_leveldir)
2605 door_state |= DOOR_NO_DELAY;
2606 door_state &= ~DOOR_CLOSE_ALL;
2609 if (door_state & DOOR_ACTION)
2611 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2612 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2613 boolean door_1_done = (!handle_door_1);
2614 boolean door_2_done = (!handle_door_2);
2615 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2616 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2617 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2618 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2619 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2620 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2621 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2622 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2623 int door_skip = max_door_size - door_size;
2625 int end = door_size;
2627 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2631 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2633 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2637 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2639 /* opening door sound has priority over simultaneously closing door */
2640 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2641 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2642 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2643 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2646 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2649 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2650 GC gc = bitmap->stored_clip_gc;
2652 if (door_state & DOOR_ACTION_1)
2654 int a = MIN(x * door_1.step_offset, end);
2655 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2656 int i = p + door_skip;
2658 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2660 BlitBitmap(bitmap_db_door, drawto,
2661 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2662 DXSIZE, DYSIZE, DX, DY);
2666 BlitBitmap(bitmap_db_door, drawto,
2667 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2668 DXSIZE, DYSIZE - p / 2, DX, DY);
2670 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2673 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2675 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2676 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2677 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2678 int dst2_x = DX, dst2_y = DY;
2679 int width = i, height = DYSIZE;
2681 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2682 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2685 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2686 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2689 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2691 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2692 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2693 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2694 int dst2_x = DX, dst2_y = DY;
2695 int width = DXSIZE, height = i;
2697 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2698 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2701 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2702 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2705 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2707 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2709 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2710 BlitBitmapMasked(bitmap, drawto,
2711 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2712 DX + DXSIZE - i, DY + j);
2713 BlitBitmapMasked(bitmap, drawto,
2714 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2715 DX + DXSIZE - i, DY + 140 + j);
2716 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2717 DY - (DOOR_GFX_PAGEY1 + j));
2718 BlitBitmapMasked(bitmap, drawto,
2719 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2721 BlitBitmapMasked(bitmap, drawto,
2722 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2725 BlitBitmapMasked(bitmap, drawto,
2726 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2728 BlitBitmapMasked(bitmap, drawto,
2729 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2731 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2732 BlitBitmapMasked(bitmap, drawto,
2733 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2734 DX + DXSIZE - i, DY + 77 + j);
2735 BlitBitmapMasked(bitmap, drawto,
2736 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2737 DX + DXSIZE - i, DY + 203 + j);
2740 redraw_mask |= REDRAW_DOOR_1;
2741 door_1_done = (a == end);
2744 if (door_state & DOOR_ACTION_2)
2747 int a = MIN(x * door_2.step_offset, door_size);
2748 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2749 int i = p + door_skip;
2751 int a = MIN(x * door_2.step_offset, door_size_2);
2752 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2753 int i = p + door_skip;
2756 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2758 BlitBitmap(bitmap_db_door, drawto,
2759 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2760 VXSIZE, VYSIZE, VX, VY);
2762 else if (x <= VYSIZE)
2764 BlitBitmap(bitmap_db_door, drawto,
2765 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2766 VXSIZE, VYSIZE - p / 2, VX, VY);
2768 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2771 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2773 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2774 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2775 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2776 int dst2_x = VX, dst2_y = VY;
2777 int width = i, height = VYSIZE;
2779 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2780 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2783 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2784 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2787 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2789 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2790 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2791 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2792 int dst2_x = VX, dst2_y = VY;
2793 int width = VXSIZE, height = i;
2795 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2796 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2799 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2800 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2803 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2805 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2807 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2808 BlitBitmapMasked(bitmap, drawto,
2809 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2810 VX + VXSIZE - i, VY + j);
2811 SetClipOrigin(bitmap, gc,
2812 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2813 BlitBitmapMasked(bitmap, drawto,
2814 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2817 BlitBitmapMasked(bitmap, drawto,
2818 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2819 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2820 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2821 BlitBitmapMasked(bitmap, drawto,
2822 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2824 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2827 redraw_mask |= REDRAW_DOOR_2;
2828 door_2_done = (a == VXSIZE);
2831 if (!(door_state & DOOR_NO_DELAY))
2835 if (game_status == GAME_MODE_MAIN)
2838 WaitUntilDelayReached(&door_delay, door_delay_value);
2843 if (door_state & DOOR_ACTION_1)
2844 door1 = door_state & DOOR_ACTION_1;
2845 if (door_state & DOOR_ACTION_2)
2846 door2 = door_state & DOOR_ACTION_2;
2848 return (door1 | door2);
2851 void DrawSpecialEditorDoor()
2853 /* draw bigger toolbox window */
2854 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2855 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2857 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2858 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2861 redraw_mask |= REDRAW_ALL;
2864 void UndrawSpecialEditorDoor()
2866 /* draw normal tape recorder window */
2867 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2868 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2871 redraw_mask |= REDRAW_ALL;
2875 /* ---------- new tool button stuff ---------------------------------------- */
2877 /* graphic position values for tool buttons */
2878 #define TOOL_BUTTON_YES_XPOS 2
2879 #define TOOL_BUTTON_YES_YPOS 250
2880 #define TOOL_BUTTON_YES_GFX_YPOS 0
2881 #define TOOL_BUTTON_YES_XSIZE 46
2882 #define TOOL_BUTTON_YES_YSIZE 28
2883 #define TOOL_BUTTON_NO_XPOS 52
2884 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2885 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2886 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2887 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2888 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2889 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2890 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2891 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2892 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2893 #define TOOL_BUTTON_PLAYER_XSIZE 30
2894 #define TOOL_BUTTON_PLAYER_YSIZE 30
2895 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2896 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2897 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2898 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2899 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2900 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2901 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2902 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2903 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2904 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2905 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2906 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2907 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2908 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2909 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2910 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2911 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2912 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2913 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2914 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2923 } toolbutton_info[NUM_TOOL_BUTTONS] =
2926 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2927 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2928 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2933 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2934 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2935 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2940 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2941 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2942 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2943 TOOL_CTRL_ID_CONFIRM,
2947 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2948 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2949 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2950 TOOL_CTRL_ID_PLAYER_1,
2954 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2955 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2956 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2957 TOOL_CTRL_ID_PLAYER_2,
2961 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2962 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2963 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2964 TOOL_CTRL_ID_PLAYER_3,
2968 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2969 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2970 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2971 TOOL_CTRL_ID_PLAYER_4,
2976 void CreateToolButtons()
2980 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2982 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2983 Bitmap *deco_bitmap = None;
2984 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2985 struct GadgetInfo *gi;
2986 unsigned long event_mask;
2987 int gd_xoffset, gd_yoffset;
2988 int gd_x1, gd_x2, gd_y;
2991 event_mask = GD_EVENT_RELEASED;
2993 gd_xoffset = toolbutton_info[i].xpos;
2994 gd_yoffset = toolbutton_info[i].ypos;
2995 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2996 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2997 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2999 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3001 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3003 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3004 &deco_bitmap, &deco_x, &deco_y);
3005 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3006 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3009 gi = CreateGadget(GDI_CUSTOM_ID, id,
3010 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3011 GDI_X, DX + toolbutton_info[i].x,
3012 GDI_Y, DY + toolbutton_info[i].y,
3013 GDI_WIDTH, toolbutton_info[i].width,
3014 GDI_HEIGHT, toolbutton_info[i].height,
3015 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3016 GDI_STATE, GD_BUTTON_UNPRESSED,
3017 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3018 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3019 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3020 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3021 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3022 GDI_DECORATION_SHIFTING, 1, 1,
3023 GDI_EVENT_MASK, event_mask,
3024 GDI_CALLBACK_ACTION, HandleToolButtons,
3028 Error(ERR_EXIT, "cannot create gadget");
3030 tool_gadget[id] = gi;
3034 void FreeToolButtons()
3038 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3039 FreeGadget(tool_gadget[i]);
3042 static void UnmapToolButtons()
3046 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3047 UnmapGadget(tool_gadget[i]);
3050 static void HandleToolButtons(struct GadgetInfo *gi)
3052 request_gadget_id = gi->custom_id;
3055 static struct Mapping_EM_to_RND_object
3058 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3059 boolean is_backside; /* backside of moving element */
3065 em_object_mapping_list[] =
3068 Xblank, TRUE, FALSE,
3072 Yacid_splash_eB, FALSE, FALSE,
3073 EL_ACID_SPLASH_RIGHT, -1, -1
3076 Yacid_splash_wB, FALSE, FALSE,
3077 EL_ACID_SPLASH_LEFT, -1, -1
3080 #ifdef EM_ENGINE_BAD_ROLL
3082 Xstone_force_e, FALSE, FALSE,
3083 EL_ROCK, -1, MV_BIT_RIGHT
3086 Xstone_force_w, FALSE, FALSE,
3087 EL_ROCK, -1, MV_BIT_LEFT
3090 Xnut_force_e, FALSE, FALSE,
3091 EL_NUT, -1, MV_BIT_RIGHT
3094 Xnut_force_w, FALSE, FALSE,
3095 EL_NUT, -1, MV_BIT_LEFT
3098 Xspring_force_e, FALSE, FALSE,
3099 EL_SPRING, -1, MV_BIT_RIGHT
3102 Xspring_force_w, FALSE, FALSE,
3103 EL_SPRING, -1, MV_BIT_LEFT
3106 Xemerald_force_e, FALSE, FALSE,
3107 EL_EMERALD, -1, MV_BIT_RIGHT
3110 Xemerald_force_w, FALSE, FALSE,
3111 EL_EMERALD, -1, MV_BIT_LEFT
3114 Xdiamond_force_e, FALSE, FALSE,
3115 EL_DIAMOND, -1, MV_BIT_RIGHT
3118 Xdiamond_force_w, FALSE, FALSE,
3119 EL_DIAMOND, -1, MV_BIT_LEFT
3122 Xbomb_force_e, FALSE, FALSE,
3123 EL_BOMB, -1, MV_BIT_RIGHT
3126 Xbomb_force_w, FALSE, FALSE,
3127 EL_BOMB, -1, MV_BIT_LEFT
3129 #endif /* EM_ENGINE_BAD_ROLL */
3132 Xstone, TRUE, FALSE,
3136 Xstone_pause, FALSE, FALSE,
3140 Xstone_fall, FALSE, FALSE,
3144 Ystone_s, FALSE, FALSE,
3145 EL_ROCK, ACTION_FALLING, -1
3148 Ystone_sB, FALSE, TRUE,
3149 EL_ROCK, ACTION_FALLING, -1
3152 Ystone_e, FALSE, FALSE,
3153 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3156 Ystone_eB, FALSE, TRUE,
3157 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3160 Ystone_w, FALSE, FALSE,
3161 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3164 Ystone_wB, FALSE, TRUE,
3165 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3172 Xnut_pause, FALSE, FALSE,
3176 Xnut_fall, FALSE, FALSE,
3180 Ynut_s, FALSE, FALSE,
3181 EL_NUT, ACTION_FALLING, -1
3184 Ynut_sB, FALSE, TRUE,
3185 EL_NUT, ACTION_FALLING, -1
3188 Ynut_e, FALSE, FALSE,
3189 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3192 Ynut_eB, FALSE, TRUE,
3193 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3196 Ynut_w, FALSE, FALSE,
3197 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3200 Ynut_wB, FALSE, TRUE,
3201 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3204 Xbug_n, TRUE, FALSE,
3208 Xbug_e, TRUE, FALSE,
3209 EL_BUG_RIGHT, -1, -1
3212 Xbug_s, TRUE, FALSE,
3216 Xbug_w, TRUE, FALSE,
3220 Xbug_gon, FALSE, FALSE,
3224 Xbug_goe, FALSE, FALSE,
3225 EL_BUG_RIGHT, -1, -1
3228 Xbug_gos, FALSE, FALSE,
3232 Xbug_gow, FALSE, FALSE,
3236 Ybug_n, FALSE, FALSE,
3237 EL_BUG, ACTION_MOVING, MV_BIT_UP
3240 Ybug_nB, FALSE, TRUE,
3241 EL_BUG, ACTION_MOVING, MV_BIT_UP
3244 Ybug_e, FALSE, FALSE,
3245 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3248 Ybug_eB, FALSE, TRUE,
3249 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3252 Ybug_s, FALSE, FALSE,
3253 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3256 Ybug_sB, FALSE, TRUE,
3257 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3260 Ybug_w, FALSE, FALSE,
3261 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3264 Ybug_wB, FALSE, TRUE,
3265 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3268 Ybug_w_n, FALSE, FALSE,
3269 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3272 Ybug_n_e, FALSE, FALSE,
3273 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3276 Ybug_e_s, FALSE, FALSE,
3277 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3280 Ybug_s_w, FALSE, FALSE,
3281 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3284 Ybug_e_n, FALSE, FALSE,
3285 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3288 Ybug_s_e, FALSE, FALSE,
3289 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3292 Ybug_w_s, FALSE, FALSE,
3293 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3296 Ybug_n_w, FALSE, FALSE,
3297 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3300 Ybug_stone, FALSE, FALSE,
3301 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3304 Ybug_spring, FALSE, FALSE,
3305 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3308 Xtank_n, TRUE, FALSE,
3309 EL_SPACESHIP_UP, -1, -1
3312 Xtank_e, TRUE, FALSE,
3313 EL_SPACESHIP_RIGHT, -1, -1
3316 Xtank_s, TRUE, FALSE,
3317 EL_SPACESHIP_DOWN, -1, -1
3320 Xtank_w, TRUE, FALSE,
3321 EL_SPACESHIP_LEFT, -1, -1
3324 Xtank_gon, FALSE, FALSE,
3325 EL_SPACESHIP_UP, -1, -1
3328 Xtank_goe, FALSE, FALSE,
3329 EL_SPACESHIP_RIGHT, -1, -1
3332 Xtank_gos, FALSE, FALSE,
3333 EL_SPACESHIP_DOWN, -1, -1
3336 Xtank_gow, FALSE, FALSE,
3337 EL_SPACESHIP_LEFT, -1, -1
3340 Ytank_n, FALSE, FALSE,
3341 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3344 Ytank_nB, FALSE, TRUE,
3345 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3348 Ytank_e, FALSE, FALSE,
3349 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3352 Ytank_eB, FALSE, TRUE,
3353 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3356 Ytank_s, FALSE, FALSE,
3357 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3360 Ytank_sB, FALSE, TRUE,
3361 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3364 Ytank_w, FALSE, FALSE,
3365 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3368 Ytank_wB, FALSE, TRUE,
3369 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3372 Ytank_w_n, FALSE, FALSE,
3373 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3376 Ytank_n_e, FALSE, FALSE,
3377 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3380 Ytank_e_s, FALSE, FALSE,
3381 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3384 Ytank_s_w, FALSE, FALSE,
3385 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3388 Ytank_e_n, FALSE, FALSE,
3389 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3392 Ytank_s_e, FALSE, FALSE,
3393 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3396 Ytank_w_s, FALSE, FALSE,
3397 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3400 Ytank_n_w, FALSE, FALSE,
3401 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3404 Ytank_stone, FALSE, FALSE,
3405 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3408 Ytank_spring, FALSE, FALSE,
3409 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3412 Xandroid, TRUE, FALSE,
3413 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3416 Xandroid_1_n, FALSE, FALSE,
3417 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3420 Xandroid_2_n, FALSE, FALSE,
3421 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3424 Xandroid_1_e, FALSE, FALSE,
3425 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3428 Xandroid_2_e, FALSE, FALSE,
3429 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3432 Xandroid_1_w, FALSE, FALSE,
3433 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3436 Xandroid_2_w, FALSE, FALSE,
3437 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3440 Xandroid_1_s, FALSE, FALSE,
3441 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3444 Xandroid_2_s, FALSE, FALSE,
3445 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3448 Yandroid_n, FALSE, FALSE,
3449 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3452 Yandroid_nB, FALSE, TRUE,
3453 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3456 Yandroid_ne, FALSE, FALSE,
3457 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3460 Yandroid_neB, FALSE, TRUE,
3461 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3464 Yandroid_e, FALSE, FALSE,
3465 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3468 Yandroid_eB, FALSE, TRUE,
3469 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3472 Yandroid_se, FALSE, FALSE,
3473 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3476 Yandroid_seB, FALSE, TRUE,
3477 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3480 Yandroid_s, FALSE, FALSE,
3481 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3484 Yandroid_sB, FALSE, TRUE,
3485 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3488 Yandroid_sw, FALSE, FALSE,
3489 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3492 Yandroid_swB, FALSE, TRUE,
3493 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3496 Yandroid_w, FALSE, FALSE,
3497 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3500 Yandroid_wB, FALSE, TRUE,
3501 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3504 Yandroid_nw, FALSE, FALSE,
3505 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3508 Yandroid_nwB, FALSE, TRUE,
3509 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3512 Xspring, TRUE, FALSE,
3516 Xspring_pause, FALSE, FALSE,
3520 Xspring_e, FALSE, FALSE,
3524 Xspring_w, FALSE, FALSE,
3528 Xspring_fall, FALSE, FALSE,
3532 Yspring_s, FALSE, FALSE,
3533 EL_SPRING, ACTION_FALLING, -1
3536 Yspring_sB, FALSE, TRUE,
3537 EL_SPRING, ACTION_FALLING, -1
3540 Yspring_e, FALSE, FALSE,
3541 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3544 Yspring_eB, FALSE, TRUE,
3545 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3548 Yspring_w, FALSE, FALSE,
3549 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3552 Yspring_wB, FALSE, TRUE,
3553 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3556 Yspring_kill_e, FALSE, FALSE,
3557 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3560 Yspring_kill_eB, FALSE, TRUE,
3561 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3564 Yspring_kill_w, FALSE, FALSE,
3565 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3568 Yspring_kill_wB, FALSE, TRUE,
3569 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3572 Xeater_n, TRUE, FALSE,
3573 EL_YAMYAM_UP, -1, -1
3576 Xeater_e, TRUE, FALSE,
3577 EL_YAMYAM_RIGHT, -1, -1
3580 Xeater_w, TRUE, FALSE,
3581 EL_YAMYAM_LEFT, -1, -1
3584 Xeater_s, TRUE, FALSE,
3585 EL_YAMYAM_DOWN, -1, -1
3588 Yeater_n, FALSE, FALSE,
3589 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3592 Yeater_nB, FALSE, TRUE,
3593 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3596 Yeater_e, FALSE, FALSE,
3597 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3600 Yeater_eB, FALSE, TRUE,
3601 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3604 Yeater_s, FALSE, FALSE,
3605 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3608 Yeater_sB, FALSE, TRUE,
3609 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3612 Yeater_w, FALSE, FALSE,
3613 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3616 Yeater_wB, FALSE, TRUE,
3617 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3620 Yeater_stone, FALSE, FALSE,
3621 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3624 Yeater_spring, FALSE, FALSE,
3625 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3628 Xalien, TRUE, FALSE,
3632 Xalien_pause, FALSE, FALSE,
3636 Yalien_n, FALSE, FALSE,
3637 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3640 Yalien_nB, FALSE, TRUE,
3641 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3644 Yalien_e, FALSE, FALSE,
3645 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3648 Yalien_eB, FALSE, TRUE,
3649 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3652 Yalien_s, FALSE, FALSE,
3653 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3656 Yalien_sB, FALSE, TRUE,
3657 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3660 Yalien_w, FALSE, FALSE,
3661 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3664 Yalien_wB, FALSE, TRUE,
3665 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3668 Yalien_stone, FALSE, FALSE,
3669 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3672 Yalien_spring, FALSE, FALSE,
3673 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3676 Xemerald, TRUE, FALSE,
3680 Xemerald_pause, FALSE, FALSE,
3684 Xemerald_fall, FALSE, FALSE,
3688 Xemerald_shine, FALSE, FALSE,
3689 EL_EMERALD, ACTION_TWINKLING, -1
3692 Yemerald_s, FALSE, FALSE,
3693 EL_EMERALD, ACTION_FALLING, -1
3696 Yemerald_sB, FALSE, TRUE,
3697 EL_EMERALD, ACTION_FALLING, -1
3700 Yemerald_e, FALSE, FALSE,
3701 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3704 Yemerald_eB, FALSE, TRUE,
3705 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3708 Yemerald_w, FALSE, FALSE,
3709 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3712 Yemerald_wB, FALSE, TRUE,
3713 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3716 Yemerald_eat, FALSE, FALSE,
3717 EL_EMERALD, ACTION_COLLECTING, -1
3720 Yemerald_stone, FALSE, FALSE,
3721 EL_NUT, ACTION_BREAKING, -1
3724 Xdiamond, TRUE, FALSE,
3728 Xdiamond_pause, FALSE, FALSE,
3732 Xdiamond_fall, FALSE, FALSE,
3736 Xdiamond_shine, FALSE, FALSE,
3737 EL_DIAMOND, ACTION_TWINKLING, -1
3740 Ydiamond_s, FALSE, FALSE,
3741 EL_DIAMOND, ACTION_FALLING, -1
3744 Ydiamond_sB, FALSE, TRUE,
3745 EL_DIAMOND, ACTION_FALLING, -1
3748 Ydiamond_e, FALSE, FALSE,
3749 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3752 Ydiamond_eB, FALSE, TRUE,
3753 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3756 Ydiamond_w, FALSE, FALSE,
3757 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3760 Ydiamond_wB, FALSE, TRUE,
3761 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3764 Ydiamond_eat, FALSE, FALSE,
3765 EL_DIAMOND, ACTION_COLLECTING, -1
3768 Ydiamond_stone, FALSE, FALSE,
3769 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3772 Xdrip_fall, TRUE, FALSE,
3773 EL_AMOEBA_DROP, -1, -1
3776 Xdrip_stretch, FALSE, FALSE,
3777 EL_AMOEBA_DROP, ACTION_FALLING, -1
3780 Xdrip_stretchB, FALSE, TRUE,
3781 EL_AMOEBA_DROP, ACTION_FALLING, -1
3784 Xdrip_eat, FALSE, FALSE,
3785 EL_AMOEBA_DROP, ACTION_GROWING, -1
3788 Ydrip_s1, FALSE, FALSE,
3789 EL_AMOEBA_DROP, ACTION_FALLING, -1
3792 Ydrip_s1B, FALSE, TRUE,
3793 EL_AMOEBA_DROP, ACTION_FALLING, -1
3796 Ydrip_s2, FALSE, FALSE,
3797 EL_AMOEBA_DROP, ACTION_FALLING, -1
3800 Ydrip_s2B, FALSE, TRUE,
3801 EL_AMOEBA_DROP, ACTION_FALLING, -1
3808 Xbomb_pause, FALSE, FALSE,
3812 Xbomb_fall, FALSE, FALSE,
3816 Ybomb_s, FALSE, FALSE,
3817 EL_BOMB, ACTION_FALLING, -1
3820 Ybomb_sB, FALSE, TRUE,
3821 EL_BOMB, ACTION_FALLING, -1
3824 Ybomb_e, FALSE, FALSE,
3825 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3828 Ybomb_eB, FALSE, TRUE,
3829 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3832 Ybomb_w, FALSE, FALSE,
3833 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3836 Ybomb_wB, FALSE, TRUE,
3837 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3840 Ybomb_eat, FALSE, FALSE,
3841 EL_BOMB, ACTION_ACTIVATING, -1
3844 Xballoon, TRUE, FALSE,
3848 Yballoon_n, FALSE, FALSE,
3849 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3852 Yballoon_nB, FALSE, TRUE,
3853 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3856 Yballoon_e, FALSE, FALSE,
3857 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3860 Yballoon_eB, FALSE, TRUE,
3861 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3864 Yballoon_s, FALSE, FALSE,
3865 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3868 Yballoon_sB, FALSE, TRUE,
3869 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3872 Yballoon_w, FALSE, FALSE,
3873 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3876 Yballoon_wB, FALSE, TRUE,
3877 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3880 Xgrass, TRUE, FALSE,
3881 EL_EMC_GRASS, -1, -1
3884 Ygrass_nB, FALSE, FALSE,
3885 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3888 Ygrass_eB, FALSE, FALSE,
3889 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3892 Ygrass_sB, FALSE, FALSE,
3893 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3896 Ygrass_wB, FALSE, FALSE,
3897 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3904 Ydirt_nB, FALSE, FALSE,
3905 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3908 Ydirt_eB, FALSE, FALSE,
3909 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3912 Ydirt_sB, FALSE, FALSE,
3913 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3916 Ydirt_wB, FALSE, FALSE,
3917 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3920 Xacid_ne, TRUE, FALSE,
3921 EL_ACID_POOL_TOPRIGHT, -1, -1
3924 Xacid_se, TRUE, FALSE,
3925 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3928 Xacid_s, TRUE, FALSE,
3929 EL_ACID_POOL_BOTTOM, -1, -1
3932 Xacid_sw, TRUE, FALSE,
3933 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3936 Xacid_nw, TRUE, FALSE,
3937 EL_ACID_POOL_TOPLEFT, -1, -1
3940 Xacid_1, TRUE, FALSE,
3944 Xacid_2, FALSE, FALSE,
3948 Xacid_3, FALSE, FALSE,
3952 Xacid_4, FALSE, FALSE,
3956 Xacid_5, FALSE, FALSE,
3960 Xacid_6, FALSE, FALSE,
3964 Xacid_7, FALSE, FALSE,
3968 Xacid_8, FALSE, FALSE,
3972 Xball_1, TRUE, FALSE,
3973 EL_EMC_MAGIC_BALL, -1, -1
3976 Xball_1B, FALSE, FALSE,
3977 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3980 Xball_2, FALSE, FALSE,
3981 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3984 Xball_2B, FALSE, FALSE,
3985 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3988 Yball_eat, FALSE, FALSE,
3989 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3992 Ykey_1_eat, FALSE, FALSE,
3993 EL_EM_KEY_1, ACTION_COLLECTING, -1
3996 Ykey_2_eat, FALSE, FALSE,
3997 EL_EM_KEY_2, ACTION_COLLECTING, -1
4000 Ykey_3_eat, FALSE, FALSE,
4001 EL_EM_KEY_3, ACTION_COLLECTING, -1
4004 Ykey_4_eat, FALSE, FALSE,
4005 EL_EM_KEY_4, ACTION_COLLECTING, -1
4008 Ykey_5_eat, FALSE, FALSE,
4009 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4012 Ykey_6_eat, FALSE, FALSE,
4013 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4016 Ykey_7_eat, FALSE, FALSE,
4017 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4020 Ykey_8_eat, FALSE, FALSE,
4021 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4024 Ylenses_eat, FALSE, FALSE,
4025 EL_EMC_LENSES, ACTION_COLLECTING, -1
4028 Ymagnify_eat, FALSE, FALSE,
4029 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4032 Ygrass_eat, FALSE, FALSE,
4033 EL_EMC_GRASS, ACTION_SNAPPING, -1
4036 Ydirt_eat, FALSE, FALSE,
4037 EL_SAND, ACTION_SNAPPING, -1
4040 Xgrow_ns, TRUE, FALSE,
4041 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4044 Ygrow_ns_eat, FALSE, FALSE,
4045 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4048 Xgrow_ew, TRUE, FALSE,
4049 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4052 Ygrow_ew_eat, FALSE, FALSE,
4053 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4056 Xwonderwall, TRUE, FALSE,
4057 EL_MAGIC_WALL, -1, -1
4060 XwonderwallB, FALSE, FALSE,
4061 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4064 Xamoeba_1, TRUE, FALSE,
4065 EL_AMOEBA_DRY, ACTION_OTHER, -1
4068 Xamoeba_2, FALSE, FALSE,
4069 EL_AMOEBA_DRY, ACTION_OTHER, -1
4072 Xamoeba_3, FALSE, FALSE,
4073 EL_AMOEBA_DRY, ACTION_OTHER, -1
4076 Xamoeba_4, FALSE, FALSE,
4077 EL_AMOEBA_DRY, ACTION_OTHER, -1
4080 Xamoeba_5, TRUE, FALSE,
4081 EL_AMOEBA_WET, ACTION_OTHER, -1
4084 Xamoeba_6, FALSE, FALSE,
4085 EL_AMOEBA_WET, ACTION_OTHER, -1
4088 Xamoeba_7, FALSE, FALSE,
4089 EL_AMOEBA_WET, ACTION_OTHER, -1
4092 Xamoeba_8, FALSE, FALSE,
4093 EL_AMOEBA_WET, ACTION_OTHER, -1
4096 Xdoor_1, TRUE, FALSE,
4097 EL_EM_GATE_1, -1, -1
4100 Xdoor_2, TRUE, FALSE,
4101 EL_EM_GATE_2, -1, -1
4104 Xdoor_3, TRUE, FALSE,
4105 EL_EM_GATE_3, -1, -1
4108 Xdoor_4, TRUE, FALSE,
4109 EL_EM_GATE_4, -1, -1
4112 Xdoor_5, TRUE, FALSE,
4113 EL_EMC_GATE_5, -1, -1
4116 Xdoor_6, TRUE, FALSE,
4117 EL_EMC_GATE_6, -1, -1
4120 Xdoor_7, TRUE, FALSE,
4121 EL_EMC_GATE_7, -1, -1
4124 Xdoor_8, TRUE, FALSE,
4125 EL_EMC_GATE_8, -1, -1
4128 Xkey_1, TRUE, FALSE,
4132 Xkey_2, TRUE, FALSE,
4136 Xkey_3, TRUE, FALSE,
4140 Xkey_4, TRUE, FALSE,
4144 Xkey_5, TRUE, FALSE,
4145 EL_EMC_KEY_5, -1, -1
4148 Xkey_6, TRUE, FALSE,
4149 EL_EMC_KEY_6, -1, -1
4152 Xkey_7, TRUE, FALSE,
4153 EL_EMC_KEY_7, -1, -1
4156 Xkey_8, TRUE, FALSE,
4157 EL_EMC_KEY_8, -1, -1
4160 Xwind_n, TRUE, FALSE,
4161 EL_BALLOON_SWITCH_UP, -1, -1
4164 Xwind_e, TRUE, FALSE,
4165 EL_BALLOON_SWITCH_RIGHT, -1, -1
4168 Xwind_s, TRUE, FALSE,
4169 EL_BALLOON_SWITCH_DOWN, -1, -1
4172 Xwind_w, TRUE, FALSE,
4173 EL_BALLOON_SWITCH_LEFT, -1, -1
4176 Xwind_nesw, TRUE, FALSE,
4177 EL_BALLOON_SWITCH_ANY, -1, -1
4180 Xwind_stop, TRUE, FALSE,
4181 EL_BALLOON_SWITCH_NONE, -1, -1
4185 EL_EXIT_CLOSED, -1, -1
4188 Xexit_1, TRUE, FALSE,
4189 EL_EXIT_OPEN, -1, -1
4192 Xexit_2, FALSE, FALSE,
4193 EL_EXIT_OPEN, -1, -1
4196 Xexit_3, FALSE, FALSE,
4197 EL_EXIT_OPEN, -1, -1
4200 Xdynamite, TRUE, FALSE,
4201 EL_EM_DYNAMITE, -1, -1
4204 Ydynamite_eat, FALSE, FALSE,
4205 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4208 Xdynamite_1, TRUE, FALSE,
4209 EL_EM_DYNAMITE_ACTIVE, -1, -1
4212 Xdynamite_2, FALSE, FALSE,
4213 EL_EM_DYNAMITE_ACTIVE, -1, -1
4216 Xdynamite_3, FALSE, FALSE,
4217 EL_EM_DYNAMITE_ACTIVE, -1, -1
4220 Xdynamite_4, FALSE, FALSE,
4221 EL_EM_DYNAMITE_ACTIVE, -1, -1
4224 Xbumper, TRUE, FALSE,
4225 EL_EMC_SPRING_BUMPER, -1, -1
4228 XbumperB, FALSE, FALSE,
4229 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4232 Xwheel, TRUE, FALSE,
4233 EL_ROBOT_WHEEL, -1, -1
4236 XwheelB, FALSE, FALSE,
4237 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4240 Xswitch, TRUE, FALSE,
4241 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4244 XswitchB, FALSE, FALSE,
4245 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4249 EL_QUICKSAND_EMPTY, -1, -1
4252 Xsand_stone, TRUE, FALSE,
4253 EL_QUICKSAND_FULL, -1, -1
4256 Xsand_stonein_1, FALSE, TRUE,
4257 EL_ROCK, ACTION_FILLING, -1
4260 Xsand_stonein_2, FALSE, TRUE,
4261 EL_ROCK, ACTION_FILLING, -1
4264 Xsand_stonein_3, FALSE, TRUE,
4265 EL_ROCK, ACTION_FILLING, -1
4268 Xsand_stonein_4, FALSE, TRUE,
4269 EL_ROCK, ACTION_FILLING, -1
4272 Xsand_stonesand_1, FALSE, FALSE,
4273 EL_QUICKSAND_FULL, -1, -1
4276 Xsand_stonesand_2, FALSE, FALSE,
4277 EL_QUICKSAND_FULL, -1, -1
4280 Xsand_stonesand_3, FALSE, FALSE,
4281 EL_QUICKSAND_FULL, -1, -1
4284 Xsand_stonesand_4, FALSE, FALSE,
4285 EL_QUICKSAND_FULL, -1, -1
4288 Xsand_stoneout_1, FALSE, FALSE,
4289 EL_ROCK, ACTION_EMPTYING, -1
4292 Xsand_stoneout_2, FALSE, FALSE,
4293 EL_ROCK, ACTION_EMPTYING, -1
4296 Xsand_sandstone_1, FALSE, FALSE,
4297 EL_QUICKSAND_FULL, -1, -1
4300 Xsand_sandstone_2, FALSE, FALSE,
4301 EL_QUICKSAND_FULL, -1, -1
4304 Xsand_sandstone_3, FALSE, FALSE,
4305 EL_QUICKSAND_FULL, -1, -1
4308 Xsand_sandstone_4, FALSE, FALSE,
4309 EL_QUICKSAND_FULL, -1, -1
4312 Xplant, TRUE, FALSE,
4313 EL_EMC_PLANT, -1, -1
4316 Yplant, FALSE, FALSE,
4317 EL_EMC_PLANT, -1, -1
4320 Xlenses, TRUE, FALSE,
4321 EL_EMC_LENSES, -1, -1
4324 Xmagnify, TRUE, FALSE,
4325 EL_EMC_MAGNIFIER, -1, -1
4328 Xdripper, TRUE, FALSE,
4329 EL_EMC_DRIPPER, -1, -1
4332 XdripperB, FALSE, FALSE,
4333 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4336 Xfake_blank, TRUE, FALSE,
4337 EL_INVISIBLE_WALL, -1, -1
4340 Xfake_blankB, FALSE, FALSE,
4341 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4344 Xfake_grass, TRUE, FALSE,
4345 EL_EMC_FAKE_GRASS, -1, -1
4348 Xfake_grassB, FALSE, FALSE,
4349 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4352 Xfake_door_1, TRUE, FALSE,
4353 EL_EM_GATE_1_GRAY, -1, -1
4356 Xfake_door_2, TRUE, FALSE,
4357 EL_EM_GATE_2_GRAY, -1, -1
4360 Xfake_door_3, TRUE, FALSE,
4361 EL_EM_GATE_3_GRAY, -1, -1
4364 Xfake_door_4, TRUE, FALSE,
4365 EL_EM_GATE_4_GRAY, -1, -1
4368 Xfake_door_5, TRUE, FALSE,
4369 EL_EMC_GATE_5_GRAY, -1, -1
4372 Xfake_door_6, TRUE, FALSE,
4373 EL_EMC_GATE_6_GRAY, -1, -1
4376 Xfake_door_7, TRUE, FALSE,
4377 EL_EMC_GATE_7_GRAY, -1, -1
4380 Xfake_door_8, TRUE, FALSE,
4381 EL_EMC_GATE_8_GRAY, -1, -1
4384 Xfake_acid_1, TRUE, FALSE,
4385 EL_EMC_FAKE_ACID, -1, -1
4388 Xfake_acid_2, FALSE, FALSE,
4389 EL_EMC_FAKE_ACID, -1, -1
4392 Xfake_acid_3, FALSE, FALSE,
4393 EL_EMC_FAKE_ACID, -1, -1
4396 Xfake_acid_4, FALSE, FALSE,
4397 EL_EMC_FAKE_ACID, -1, -1
4400 Xfake_acid_5, FALSE, FALSE,
4401 EL_EMC_FAKE_ACID, -1, -1
4404 Xfake_acid_6, FALSE, FALSE,
4405 EL_EMC_FAKE_ACID, -1, -1
4408 Xfake_acid_7, FALSE, FALSE,
4409 EL_EMC_FAKE_ACID, -1, -1
4412 Xfake_acid_8, FALSE, FALSE,
4413 EL_EMC_FAKE_ACID, -1, -1
4416 Xsteel_1, TRUE, FALSE,
4417 EL_STEELWALL, -1, -1
4420 Xsteel_2, TRUE, FALSE,
4421 EL_EMC_STEELWALL_2, -1, -1
4424 Xsteel_3, TRUE, FALSE,
4425 EL_EMC_STEELWALL_3, -1, -1
4428 Xsteel_4, TRUE, FALSE,
4429 EL_EMC_STEELWALL_4, -1, -1
4432 Xwall_1, TRUE, FALSE,
4436 Xwall_2, TRUE, FALSE,
4437 EL_EMC_WALL_14, -1, -1
4440 Xwall_3, TRUE, FALSE,
4441 EL_EMC_WALL_15, -1, -1
4444 Xwall_4, TRUE, FALSE,
4445 EL_EMC_WALL_16, -1, -1
4448 Xround_wall_1, TRUE, FALSE,
4449 EL_WALL_SLIPPERY, -1, -1
4452 Xround_wall_2, TRUE, FALSE,
4453 EL_EMC_WALL_SLIPPERY_2, -1, -1
4456 Xround_wall_3, TRUE, FALSE,
4457 EL_EMC_WALL_SLIPPERY_3, -1, -1
4460 Xround_wall_4, TRUE, FALSE,
4461 EL_EMC_WALL_SLIPPERY_4, -1, -1
4464 Xdecor_1, TRUE, FALSE,
4465 EL_EMC_WALL_8, -1, -1
4468 Xdecor_2, TRUE, FALSE,
4469 EL_EMC_WALL_6, -1, -1
4472 Xdecor_3, TRUE, FALSE,
4473 EL_EMC_WALL_4, -1, -1
4476 Xdecor_4, TRUE, FALSE,
4477 EL_EMC_WALL_7, -1, -1
4480 Xdecor_5, TRUE, FALSE,
4481 EL_EMC_WALL_5, -1, -1
4484 Xdecor_6, TRUE, FALSE,
4485 EL_EMC_WALL_9, -1, -1
4488 Xdecor_7, TRUE, FALSE,
4489 EL_EMC_WALL_10, -1, -1
4492 Xdecor_8, TRUE, FALSE,
4493 EL_EMC_WALL_1, -1, -1
4496 Xdecor_9, TRUE, FALSE,
4497 EL_EMC_WALL_2, -1, -1
4500 Xdecor_10, TRUE, FALSE,
4501 EL_EMC_WALL_3, -1, -1
4504 Xdecor_11, TRUE, FALSE,
4505 EL_EMC_WALL_11, -1, -1
4508 Xdecor_12, TRUE, FALSE,
4509 EL_EMC_WALL_12, -1, -1
4512 Xalpha_0, TRUE, FALSE,
4513 EL_CHAR('0'), -1, -1
4516 Xalpha_1, TRUE, FALSE,
4517 EL_CHAR('1'), -1, -1
4520 Xalpha_2, TRUE, FALSE,
4521 EL_CHAR('2'), -1, -1
4524 Xalpha_3, TRUE, FALSE,
4525 EL_CHAR('3'), -1, -1
4528 Xalpha_4, TRUE, FALSE,
4529 EL_CHAR('4'), -1, -1
4532 Xalpha_5, TRUE, FALSE,
4533 EL_CHAR('5'), -1, -1
4536 Xalpha_6, TRUE, FALSE,
4537 EL_CHAR('6'), -1, -1
4540 Xalpha_7, TRUE, FALSE,
4541 EL_CHAR('7'), -1, -1
4544 Xalpha_8, TRUE, FALSE,
4545 EL_CHAR('8'), -1, -1
4548 Xalpha_9, TRUE, FALSE,
4549 EL_CHAR('9'), -1, -1
4552 Xalpha_excla, TRUE, FALSE,
4553 EL_CHAR('!'), -1, -1
4556 Xalpha_quote, TRUE, FALSE,
4557 EL_CHAR('"'), -1, -1
4560 Xalpha_comma, TRUE, FALSE,
4561 EL_CHAR(','), -1, -1
4564 Xalpha_minus, TRUE, FALSE,
4565 EL_CHAR('-'), -1, -1
4568 Xalpha_perio, TRUE, FALSE,
4569 EL_CHAR('.'), -1, -1
4572 Xalpha_colon, TRUE, FALSE,
4573 EL_CHAR(':'), -1, -1
4576 Xalpha_quest, TRUE, FALSE,
4577 EL_CHAR('?'), -1, -1
4580 Xalpha_a, TRUE, FALSE,
4581 EL_CHAR('A'), -1, -1
4584 Xalpha_b, TRUE, FALSE,
4585 EL_CHAR('B'), -1, -1
4588 Xalpha_c, TRUE, FALSE,
4589 EL_CHAR('C'), -1, -1
4592 Xalpha_d, TRUE, FALSE,
4593 EL_CHAR('D'), -1, -1
4596 Xalpha_e, TRUE, FALSE,
4597 EL_CHAR('E'), -1, -1
4600 Xalpha_f, TRUE, FALSE,
4601 EL_CHAR('F'), -1, -1
4604 Xalpha_g, TRUE, FALSE,
4605 EL_CHAR('G'), -1, -1
4608 Xalpha_h, TRUE, FALSE,
4609 EL_CHAR('H'), -1, -1
4612 Xalpha_i, TRUE, FALSE,
4613 EL_CHAR('I'), -1, -1
4616 Xalpha_j, TRUE, FALSE,
4617 EL_CHAR('J'), -1, -1
4620 Xalpha_k, TRUE, FALSE,
4621 EL_CHAR('K'), -1, -1
4624 Xalpha_l, TRUE, FALSE,
4625 EL_CHAR('L'), -1, -1
4628 Xalpha_m, TRUE, FALSE,
4629 EL_CHAR('M'), -1, -1
4632 Xalpha_n, TRUE, FALSE,
4633 EL_CHAR('N'), -1, -1
4636 Xalpha_o, TRUE, FALSE,
4637 EL_CHAR('O'), -1, -1
4640 Xalpha_p, TRUE, FALSE,
4641 EL_CHAR('P'), -1, -1
4644 Xalpha_q, TRUE, FALSE,
4645 EL_CHAR('Q'), -1, -1
4648 Xalpha_r, TRUE, FALSE,
4649 EL_CHAR('R'), -1, -1
4652 Xalpha_s, TRUE, FALSE,
4653 EL_CHAR('S'), -1, -1
4656 Xalpha_t, TRUE, FALSE,
4657 EL_CHAR('T'), -1, -1
4660 Xalpha_u, TRUE, FALSE,
4661 EL_CHAR('U'), -1, -1
4664 Xalpha_v, TRUE, FALSE,
4665 EL_CHAR('V'), -1, -1
4668 Xalpha_w, TRUE, FALSE,
4669 EL_CHAR('W'), -1, -1
4672 Xalpha_x, TRUE, FALSE,
4673 EL_CHAR('X'), -1, -1
4676 Xalpha_y, TRUE, FALSE,
4677 EL_CHAR('Y'), -1, -1
4680 Xalpha_z, TRUE, FALSE,
4681 EL_CHAR('Z'), -1, -1
4684 Xalpha_arrow_e, TRUE, FALSE,
4685 EL_CHAR('>'), -1, -1
4688 Xalpha_arrow_w, TRUE, FALSE,
4689 EL_CHAR('<'), -1, -1
4692 Xalpha_copyr, TRUE, FALSE,
4693 EL_CHAR('©'), -1, -1
4697 Xboom_bug, FALSE, FALSE,
4698 EL_BUG, ACTION_EXPLODING, -1
4701 Xboom_bomb, FALSE, FALSE,
4702 EL_BOMB, ACTION_EXPLODING, -1
4705 Xboom_android, FALSE, FALSE,
4706 EL_EMC_ANDROID, ACTION_OTHER, -1
4709 Xboom_1, FALSE, FALSE,
4710 EL_DEFAULT, ACTION_EXPLODING, -1
4713 Xboom_2, FALSE, FALSE,
4714 EL_DEFAULT, ACTION_EXPLODING, -1
4717 Znormal, FALSE, FALSE,
4721 Zdynamite, FALSE, FALSE,
4725 Zplayer, FALSE, FALSE,
4729 ZBORDER, FALSE, FALSE,
4739 static struct Mapping_EM_to_RND_player
4748 em_player_mapping_list[] =
4752 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4756 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4760 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4764 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4768 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4772 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4776 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4780 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4784 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4788 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4792 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4796 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4800 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4804 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4808 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4812 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4816 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4820 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4824 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4828 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4832 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4836 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4840 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4844 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4848 EL_PLAYER_1, ACTION_DEFAULT, -1,
4852 EL_PLAYER_2, ACTION_DEFAULT, -1,
4856 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4860 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4864 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4868 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4872 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4876 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4880 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4884 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4888 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4892 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4896 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4900 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4904 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4908 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4912 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4916 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4920 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4924 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4928 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4932 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4936 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4940 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4944 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4948 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4952 EL_PLAYER_3, ACTION_DEFAULT, -1,
4956 EL_PLAYER_4, ACTION_DEFAULT, -1,
4965 int map_element_RND_to_EM(int element_rnd)
4967 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4968 static boolean mapping_initialized = FALSE;
4970 if (!mapping_initialized)
4974 /* return "Xalpha_quest" for all undefined elements in mapping array */
4975 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4976 mapping_RND_to_EM[i] = Xalpha_quest;
4978 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4979 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4980 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4981 em_object_mapping_list[i].element_em;
4983 mapping_initialized = TRUE;
4986 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4987 return mapping_RND_to_EM[element_rnd];
4989 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4994 int map_element_EM_to_RND(int element_em)
4996 static unsigned short mapping_EM_to_RND[TILE_MAX];
4997 static boolean mapping_initialized = FALSE;
4999 if (!mapping_initialized)
5003 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5004 for (i = 0; i < TILE_MAX; i++)
5005 mapping_EM_to_RND[i] = EL_UNKNOWN;
5007 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5008 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5009 em_object_mapping_list[i].element_rnd;
5011 mapping_initialized = TRUE;
5014 if (element_em >= 0 && element_em < TILE_MAX)
5015 return mapping_EM_to_RND[element_em];
5017 Error(ERR_WARN, "invalid EM level element %d", element_em);
5022 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5024 struct LevelInfo_EM *level_em = level->native_em_level;
5025 struct LEVEL *lev = level_em->lev;
5028 for (i = 0; i < TILE_MAX; i++)
5029 lev->android_array[i] = Xblank;
5031 for (i = 0; i < level->num_android_clone_elements; i++)
5033 int element_rnd = level->android_clone_element[i];
5034 int element_em = map_element_RND_to_EM(element_rnd);
5036 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5037 if (em_object_mapping_list[j].element_rnd == element_rnd)
5038 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5042 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5044 struct LevelInfo_EM *level_em = level->native_em_level;
5045 struct LEVEL *lev = level_em->lev;
5048 level->num_android_clone_elements = 0;
5050 for (i = 0; i < TILE_MAX; i++)
5052 int element_em = lev->android_array[i];
5054 boolean element_found = FALSE;
5056 if (element_em == Xblank)
5059 element_rnd = map_element_EM_to_RND(element_em);
5061 for (j = 0; j < level->num_android_clone_elements; j++)
5062 if (level->android_clone_element[j] == element_rnd)
5063 element_found = TRUE;
5067 level->android_clone_element[level->num_android_clone_elements++] =
5070 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5075 if (level->num_android_clone_elements == 0)
5077 level->num_android_clone_elements = 1;
5078 level->android_clone_element[0] = EL_EMPTY;
5082 int map_direction_RND_to_EM(int direction)
5084 return (direction == MV_UP ? 0 :
5085 direction == MV_RIGHT ? 1 :
5086 direction == MV_DOWN ? 2 :
5087 direction == MV_LEFT ? 3 :
5091 int map_direction_EM_to_RND(int direction)
5093 return (direction == 0 ? MV_UP :
5094 direction == 1 ? MV_RIGHT :
5095 direction == 2 ? MV_DOWN :
5096 direction == 3 ? MV_LEFT :
5100 int get_next_element(int element)
5104 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5105 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5106 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5107 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5108 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5109 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5110 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5112 default: return element;
5117 int el_act_dir2img(int element, int action, int direction)
5119 element = GFX_ELEMENT(element);
5121 if (direction == MV_NONE)
5122 return element_info[element].graphic[action];
5124 direction = MV_DIR_TO_BIT(direction);
5126 return element_info[element].direction_graphic[action][direction];
5129 int el_act_dir2img(int element, int action, int direction)
5131 element = GFX_ELEMENT(element);
5132 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5134 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5135 return element_info[element].direction_graphic[action][direction];
5140 static int el_act_dir2crm(int element, int action, int direction)
5142 element = GFX_ELEMENT(element);
5144 if (direction == MV_NONE)
5145 return element_info[element].crumbled[action];
5147 direction = MV_DIR_TO_BIT(direction);
5149 return element_info[element].direction_crumbled[action][direction];
5152 static int el_act_dir2crm(int element, int action, int direction)
5154 element = GFX_ELEMENT(element);
5155 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5157 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5158 return element_info[element].direction_crumbled[action][direction];
5162 int el_act2img(int element, int action)
5164 element = GFX_ELEMENT(element);
5166 return element_info[element].graphic[action];
5169 int el_act2crm(int element, int action)
5171 element = GFX_ELEMENT(element);
5173 return element_info[element].crumbled[action];
5176 int el_dir2img(int element, int direction)
5178 element = GFX_ELEMENT(element);
5180 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5183 int el2baseimg(int element)
5185 return element_info[element].graphic[ACTION_DEFAULT];
5188 int el2img(int element)
5190 element = GFX_ELEMENT(element);
5192 return element_info[element].graphic[ACTION_DEFAULT];
5195 int el2edimg(int element)
5197 element = GFX_ELEMENT(element);
5199 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5202 int el2preimg(int element)
5204 element = GFX_ELEMENT(element);
5206 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5209 int font2baseimg(int font_nr)
5211 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5215 void setCenteredPlayerNr_EM(int centered_player_nr)
5217 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5220 int getCenteredPlayerNr_EM()
5223 if (game.centered_player_nr_next >= 0 &&
5224 !native_em_level.ply[game.centered_player_nr_next]->alive)
5225 game.centered_player_nr_next = game.centered_player_nr;
5228 if (game.centered_player_nr != game.centered_player_nr_next)
5229 game.centered_player_nr = game.centered_player_nr_next;
5231 return game.centered_player_nr;
5234 void setSetCenteredPlayer_EM(boolean set_centered_player)
5236 game.set_centered_player = set_centered_player;
5239 boolean getSetCenteredPlayer_EM()
5241 return game.set_centered_player;
5245 int getNumActivePlayers_EM()
5247 int num_players = 0;
5253 for (i = 0; i < MAX_PLAYERS; i++)
5254 if (tape.player_participates[i])
5261 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5263 int game_frame_delay_value;
5265 game_frame_delay_value =
5266 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5267 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5270 if (tape.playing && tape.warp_forward && !tape.pausing)
5271 game_frame_delay_value = 0;
5273 return game_frame_delay_value;
5277 unsigned int InitRND(long seed)
5279 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5280 return InitEngineRND_EM(seed);
5282 return InitEngineRND(seed);
5285 void InitGraphicInfo_EM(void)
5287 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5288 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5292 int num_em_gfx_errors = 0;
5294 if (graphic_info_em_object[0][0].bitmap == NULL)
5296 /* EM graphics not yet initialized in em_open_all() */
5301 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5304 /* always start with reliable default values */
5305 for (i = 0; i < TILE_MAX; i++)
5307 object_mapping[i].element_rnd = EL_UNKNOWN;
5308 object_mapping[i].is_backside = FALSE;
5309 object_mapping[i].action = ACTION_DEFAULT;
5310 object_mapping[i].direction = MV_NONE;
5313 /* always start with reliable default values */
5314 for (p = 0; p < MAX_PLAYERS; p++)
5316 for (i = 0; i < SPR_MAX; i++)
5318 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5319 player_mapping[p][i].action = ACTION_DEFAULT;
5320 player_mapping[p][i].direction = MV_NONE;
5324 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5326 int e = em_object_mapping_list[i].element_em;
5328 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5329 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5331 if (em_object_mapping_list[i].action != -1)
5332 object_mapping[e].action = em_object_mapping_list[i].action;
5334 if (em_object_mapping_list[i].direction != -1)
5335 object_mapping[e].direction =
5336 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5339 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5341 int a = em_player_mapping_list[i].action_em;
5342 int p = em_player_mapping_list[i].player_nr;
5344 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5346 if (em_player_mapping_list[i].action != -1)
5347 player_mapping[p][a].action = em_player_mapping_list[i].action;
5349 if (em_player_mapping_list[i].direction != -1)
5350 player_mapping[p][a].direction =
5351 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5354 for (i = 0; i < TILE_MAX; i++)
5356 int element = object_mapping[i].element_rnd;
5357 int action = object_mapping[i].action;
5358 int direction = object_mapping[i].direction;
5359 boolean is_backside = object_mapping[i].is_backside;
5360 boolean action_removing = (action == ACTION_DIGGING ||
5361 action == ACTION_SNAPPING ||
5362 action == ACTION_COLLECTING);
5363 boolean action_exploding = ((action == ACTION_EXPLODING ||
5364 action == ACTION_SMASHED_BY_ROCK ||
5365 action == ACTION_SMASHED_BY_SPRING) &&
5366 element != EL_DIAMOND);
5367 boolean action_active = (action == ACTION_ACTIVE);
5368 boolean action_other = (action == ACTION_OTHER);
5370 for (j = 0; j < 8; j++)
5372 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5373 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5375 i == Xdrip_stretch ? element :
5376 i == Xdrip_stretchB ? element :
5377 i == Ydrip_s1 ? element :
5378 i == Ydrip_s1B ? element :
5379 i == Xball_1B ? element :
5380 i == Xball_2 ? element :
5381 i == Xball_2B ? element :
5382 i == Yball_eat ? element :
5383 i == Ykey_1_eat ? element :
5384 i == Ykey_2_eat ? element :
5385 i == Ykey_3_eat ? element :
5386 i == Ykey_4_eat ? element :
5387 i == Ykey_5_eat ? element :
5388 i == Ykey_6_eat ? element :
5389 i == Ykey_7_eat ? element :
5390 i == Ykey_8_eat ? element :
5391 i == Ylenses_eat ? element :
5392 i == Ymagnify_eat ? element :
5393 i == Ygrass_eat ? element :
5394 i == Ydirt_eat ? element :
5395 i == Yemerald_stone ? EL_EMERALD :
5396 i == Ydiamond_stone ? EL_ROCK :
5397 i == Xsand_stonein_1 ? element :
5398 i == Xsand_stonein_2 ? element :
5399 i == Xsand_stonein_3 ? element :
5400 i == Xsand_stonein_4 ? element :
5401 is_backside ? EL_EMPTY :
5402 action_removing ? EL_EMPTY :
5404 int effective_action = (j < 7 ? action :
5405 i == Xdrip_stretch ? action :
5406 i == Xdrip_stretchB ? action :
5407 i == Ydrip_s1 ? action :
5408 i == Ydrip_s1B ? action :
5409 i == Xball_1B ? action :
5410 i == Xball_2 ? action :
5411 i == Xball_2B ? action :
5412 i == Yball_eat ? action :
5413 i == Ykey_1_eat ? action :
5414 i == Ykey_2_eat ? action :
5415 i == Ykey_3_eat ? action :
5416 i == Ykey_4_eat ? action :
5417 i == Ykey_5_eat ? action :
5418 i == Ykey_6_eat ? action :
5419 i == Ykey_7_eat ? action :
5420 i == Ykey_8_eat ? action :
5421 i == Ylenses_eat ? action :
5422 i == Ymagnify_eat ? action :
5423 i == Ygrass_eat ? action :
5424 i == Ydirt_eat ? action :
5425 i == Xsand_stonein_1 ? action :
5426 i == Xsand_stonein_2 ? action :
5427 i == Xsand_stonein_3 ? action :
5428 i == Xsand_stonein_4 ? action :
5429 i == Xsand_stoneout_1 ? action :
5430 i == Xsand_stoneout_2 ? action :
5431 i == Xboom_android ? ACTION_EXPLODING :
5432 action_exploding ? ACTION_EXPLODING :
5433 action_active ? action :
5434 action_other ? action :
5436 int graphic = (el_act_dir2img(effective_element, effective_action,
5438 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5440 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5441 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5442 boolean has_action_graphics = (graphic != base_graphic);
5443 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5444 struct GraphicInfo *g = &graphic_info[graphic];
5445 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5448 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5449 boolean special_animation = (action != ACTION_DEFAULT &&
5450 g->anim_frames == 3 &&
5451 g->anim_delay == 2 &&
5452 g->anim_mode & ANIM_LINEAR);
5453 int sync_frame = (i == Xdrip_stretch ? 7 :
5454 i == Xdrip_stretchB ? 7 :
5455 i == Ydrip_s2 ? j + 8 :
5456 i == Ydrip_s2B ? j + 8 :
5465 i == Xfake_acid_1 ? 0 :
5466 i == Xfake_acid_2 ? 10 :
5467 i == Xfake_acid_3 ? 20 :
5468 i == Xfake_acid_4 ? 30 :
5469 i == Xfake_acid_5 ? 40 :
5470 i == Xfake_acid_6 ? 50 :
5471 i == Xfake_acid_7 ? 60 :
5472 i == Xfake_acid_8 ? 70 :
5474 i == Xball_2B ? j + 8 :
5475 i == Yball_eat ? j + 1 :
5476 i == Ykey_1_eat ? j + 1 :
5477 i == Ykey_2_eat ? j + 1 :
5478 i == Ykey_3_eat ? j + 1 :
5479 i == Ykey_4_eat ? j + 1 :
5480 i == Ykey_5_eat ? j + 1 :
5481 i == Ykey_6_eat ? j + 1 :
5482 i == Ykey_7_eat ? j + 1 :
5483 i == Ykey_8_eat ? j + 1 :
5484 i == Ylenses_eat ? j + 1 :
5485 i == Ymagnify_eat ? j + 1 :
5486 i == Ygrass_eat ? j + 1 :
5487 i == Ydirt_eat ? j + 1 :
5488 i == Xamoeba_1 ? 0 :
5489 i == Xamoeba_2 ? 1 :
5490 i == Xamoeba_3 ? 2 :
5491 i == Xamoeba_4 ? 3 :
5492 i == Xamoeba_5 ? 0 :
5493 i == Xamoeba_6 ? 1 :
5494 i == Xamoeba_7 ? 2 :
5495 i == Xamoeba_8 ? 3 :
5496 i == Xexit_2 ? j + 8 :
5497 i == Xexit_3 ? j + 16 :
5498 i == Xdynamite_1 ? 0 :
5499 i == Xdynamite_2 ? 8 :
5500 i == Xdynamite_3 ? 16 :
5501 i == Xdynamite_4 ? 24 :
5502 i == Xsand_stonein_1 ? j + 1 :
5503 i == Xsand_stonein_2 ? j + 9 :
5504 i == Xsand_stonein_3 ? j + 17 :
5505 i == Xsand_stonein_4 ? j + 25 :
5506 i == Xsand_stoneout_1 && j == 0 ? 0 :
5507 i == Xsand_stoneout_1 && j == 1 ? 0 :
5508 i == Xsand_stoneout_1 && j == 2 ? 1 :
5509 i == Xsand_stoneout_1 && j == 3 ? 2 :
5510 i == Xsand_stoneout_1 && j == 4 ? 2 :
5511 i == Xsand_stoneout_1 && j == 5 ? 3 :
5512 i == Xsand_stoneout_1 && j == 6 ? 4 :
5513 i == Xsand_stoneout_1 && j == 7 ? 4 :
5514 i == Xsand_stoneout_2 && j == 0 ? 5 :
5515 i == Xsand_stoneout_2 && j == 1 ? 6 :
5516 i == Xsand_stoneout_2 && j == 2 ? 7 :
5517 i == Xsand_stoneout_2 && j == 3 ? 8 :
5518 i == Xsand_stoneout_2 && j == 4 ? 9 :
5519 i == Xsand_stoneout_2 && j == 5 ? 11 :
5520 i == Xsand_stoneout_2 && j == 6 ? 13 :
5521 i == Xsand_stoneout_2 && j == 7 ? 15 :
5522 i == Xboom_bug && j == 1 ? 2 :
5523 i == Xboom_bug && j == 2 ? 2 :
5524 i == Xboom_bug && j == 3 ? 4 :
5525 i == Xboom_bug && j == 4 ? 4 :
5526 i == Xboom_bug && j == 5 ? 2 :
5527 i == Xboom_bug && j == 6 ? 2 :
5528 i == Xboom_bug && j == 7 ? 0 :
5529 i == Xboom_bomb && j == 1 ? 2 :
5530 i == Xboom_bomb && j == 2 ? 2 :
5531 i == Xboom_bomb && j == 3 ? 4 :
5532 i == Xboom_bomb && j == 4 ? 4 :
5533 i == Xboom_bomb && j == 5 ? 2 :
5534 i == Xboom_bomb && j == 6 ? 2 :
5535 i == Xboom_bomb && j == 7 ? 0 :
5536 i == Xboom_android && j == 7 ? 6 :
5537 i == Xboom_1 && j == 1 ? 2 :
5538 i == Xboom_1 && j == 2 ? 2 :
5539 i == Xboom_1 && j == 3 ? 4 :
5540 i == Xboom_1 && j == 4 ? 4 :
5541 i == Xboom_1 && j == 5 ? 6 :
5542 i == Xboom_1 && j == 6 ? 6 :
5543 i == Xboom_1 && j == 7 ? 8 :
5544 i == Xboom_2 && j == 0 ? 8 :
5545 i == Xboom_2 && j == 1 ? 8 :
5546 i == Xboom_2 && j == 2 ? 10 :
5547 i == Xboom_2 && j == 3 ? 10 :
5548 i == Xboom_2 && j == 4 ? 10 :
5549 i == Xboom_2 && j == 5 ? 12 :
5550 i == Xboom_2 && j == 6 ? 12 :
5551 i == Xboom_2 && j == 7 ? 12 :
5552 special_animation && j == 4 ? 3 :
5553 effective_action != action ? 0 :
5557 Bitmap *debug_bitmap = g_em->bitmap;
5558 int debug_src_x = g_em->src_x;
5559 int debug_src_y = g_em->src_y;
5562 int frame = getAnimationFrame(g->anim_frames,
5565 g->anim_start_frame,
5568 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5569 g->double_movement && is_backside);
5571 g_em->bitmap = src_bitmap;
5572 g_em->src_x = src_x;
5573 g_em->src_y = src_y;
5574 g_em->src_offset_x = 0;
5575 g_em->src_offset_y = 0;
5576 g_em->dst_offset_x = 0;
5577 g_em->dst_offset_y = 0;
5578 g_em->width = TILEX;
5579 g_em->height = TILEY;
5581 g_em->crumbled_bitmap = NULL;
5582 g_em->crumbled_src_x = 0;
5583 g_em->crumbled_src_y = 0;
5584 g_em->crumbled_border_size = 0;
5586 g_em->has_crumbled_graphics = FALSE;
5587 g_em->preserve_background = FALSE;
5590 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5591 printf("::: empty crumbled: %d [%s], %d, %d\n",
5592 effective_element, element_info[effective_element].token_name,
5593 effective_action, direction);
5596 /* if element can be crumbled, but certain action graphics are just empty
5597 space (like snapping sand with the original R'n'D graphics), do not
5598 treat these empty space graphics as crumbled graphics in EMC engine */
5599 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5601 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5603 g_em->has_crumbled_graphics = TRUE;
5604 g_em->crumbled_bitmap = src_bitmap;
5605 g_em->crumbled_src_x = src_x;
5606 g_em->crumbled_src_y = src_y;
5607 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5611 if (element == EL_ROCK &&
5612 effective_action == ACTION_FILLING)
5613 printf("::: has_action_graphics == %d\n", has_action_graphics);
5616 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5617 effective_action == ACTION_MOVING ||
5618 effective_action == ACTION_PUSHING ||
5619 effective_action == ACTION_EATING)) ||
5620 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5621 effective_action == ACTION_EMPTYING)))
5624 (effective_action == ACTION_FALLING ||
5625 effective_action == ACTION_FILLING ||
5626 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5627 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5628 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5629 int num_steps = (i == Ydrip_s1 ? 16 :
5630 i == Ydrip_s1B ? 16 :
5631 i == Ydrip_s2 ? 16 :
5632 i == Ydrip_s2B ? 16 :
5633 i == Xsand_stonein_1 ? 32 :
5634 i == Xsand_stonein_2 ? 32 :
5635 i == Xsand_stonein_3 ? 32 :
5636 i == Xsand_stonein_4 ? 32 :
5637 i == Xsand_stoneout_1 ? 16 :
5638 i == Xsand_stoneout_2 ? 16 : 8);
5639 int cx = ABS(dx) * (TILEX / num_steps);
5640 int cy = ABS(dy) * (TILEY / num_steps);
5641 int step_frame = (i == Ydrip_s2 ? j + 8 :
5642 i == Ydrip_s2B ? j + 8 :
5643 i == Xsand_stonein_2 ? j + 8 :
5644 i == Xsand_stonein_3 ? j + 16 :
5645 i == Xsand_stonein_4 ? j + 24 :
5646 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5647 int step = (is_backside ? step_frame : num_steps - step_frame);
5649 if (is_backside) /* tile where movement starts */
5651 if (dx < 0 || dy < 0)
5653 g_em->src_offset_x = cx * step;
5654 g_em->src_offset_y = cy * step;
5658 g_em->dst_offset_x = cx * step;
5659 g_em->dst_offset_y = cy * step;
5662 else /* tile where movement ends */
5664 if (dx < 0 || dy < 0)
5666 g_em->dst_offset_x = cx * step;
5667 g_em->dst_offset_y = cy * step;
5671 g_em->src_offset_x = cx * step;
5672 g_em->src_offset_y = cy * step;
5676 g_em->width = TILEX - cx * step;
5677 g_em->height = TILEY - cy * step;
5681 /* create unique graphic identifier to decide if tile must be redrawn */
5682 /* bit 31 - 16 (16 bit): EM style graphic
5683 bit 15 - 12 ( 4 bit): EM style frame
5684 bit 11 - 6 ( 6 bit): graphic width
5685 bit 5 - 0 ( 6 bit): graphic height */
5686 g_em->unique_identifier =
5687 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5689 /* create unique graphic identifier to decide if tile must be redrawn */
5690 /* bit 31 - 16 (16 bit): EM style element
5691 bit 15 - 12 ( 4 bit): EM style frame
5692 bit 11 - 6 ( 6 bit): graphic width
5693 bit 5 - 0 ( 6 bit): graphic height */
5694 g_em->unique_identifier =
5695 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5699 if (effective_element == EL_ROCK)
5700 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5701 effective_action, j, graphic, frame, g_em->unique_identifier);
5707 /* skip check for EMC elements not contained in original EMC artwork */
5708 if (element == EL_EMC_FAKE_ACID)
5712 if (g_em->bitmap != debug_bitmap ||
5713 g_em->src_x != debug_src_x ||
5714 g_em->src_y != debug_src_y ||
5715 g_em->src_offset_x != 0 ||
5716 g_em->src_offset_y != 0 ||
5717 g_em->dst_offset_x != 0 ||
5718 g_em->dst_offset_y != 0 ||
5719 g_em->width != TILEX ||
5720 g_em->height != TILEY)
5722 static int last_i = -1;
5730 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5731 i, element, element_info[element].token_name,
5732 element_action_info[effective_action].suffix, direction);
5734 if (element != effective_element)
5735 printf(" [%d ('%s')]",
5737 element_info[effective_element].token_name);
5741 if (g_em->bitmap != debug_bitmap)
5742 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5743 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5745 if (g_em->src_x != debug_src_x ||
5746 g_em->src_y != debug_src_y)
5747 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5748 j, (is_backside ? 'B' : 'F'),
5749 g_em->src_x, g_em->src_y,
5750 g_em->src_x / 32, g_em->src_y / 32,
5751 debug_src_x, debug_src_y,
5752 debug_src_x / 32, debug_src_y / 32);
5754 if (g_em->src_offset_x != 0 ||
5755 g_em->src_offset_y != 0 ||
5756 g_em->dst_offset_x != 0 ||
5757 g_em->dst_offset_y != 0)
5758 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5760 g_em->src_offset_x, g_em->src_offset_y,
5761 g_em->dst_offset_x, g_em->dst_offset_y);
5763 if (g_em->width != TILEX ||
5764 g_em->height != TILEY)
5765 printf(" %d (%d): size %d,%d should be %d,%d\n",
5767 g_em->width, g_em->height, TILEX, TILEY);
5769 num_em_gfx_errors++;
5776 for (i = 0; i < TILE_MAX; i++)
5778 for (j = 0; j < 8; j++)
5780 int element = object_mapping[i].element_rnd;
5781 int action = object_mapping[i].action;
5782 int direction = object_mapping[i].direction;
5783 boolean is_backside = object_mapping[i].is_backside;
5785 int graphic_action = el_act_dir2img(element, action, direction);
5786 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5788 int graphic_action = element_info[element].graphic[action];
5789 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5792 if ((action == ACTION_SMASHED_BY_ROCK ||
5793 action == ACTION_SMASHED_BY_SPRING ||
5794 action == ACTION_EATING) &&
5795 graphic_action == graphic_default)
5797 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5798 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5799 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5800 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5803 /* no separate animation for "smashed by rock" -- use rock instead */
5804 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5805 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5807 g_em->bitmap = g_xx->bitmap;
5808 g_em->src_x = g_xx->src_x;
5809 g_em->src_y = g_xx->src_y;
5810 g_em->src_offset_x = g_xx->src_offset_x;
5811 g_em->src_offset_y = g_xx->src_offset_y;
5812 g_em->dst_offset_x = g_xx->dst_offset_x;
5813 g_em->dst_offset_y = g_xx->dst_offset_y;
5814 g_em->width = g_xx->width;
5815 g_em->height = g_xx->height;
5817 g_em->unique_identifier = g_xx->unique_identifier;
5821 g_em->preserve_background = TRUE;
5826 for (p = 0; p < MAX_PLAYERS; p++)
5828 for (i = 0; i < SPR_MAX; i++)
5830 int element = player_mapping[p][i].element_rnd;
5831 int action = player_mapping[p][i].action;
5832 int direction = player_mapping[p][i].direction;
5834 for (j = 0; j < 8; j++)
5836 int effective_element = element;
5837 int effective_action = action;
5838 int graphic = (direction == MV_NONE ?
5839 el_act2img(effective_element, effective_action) :
5840 el_act_dir2img(effective_element, effective_action,
5842 struct GraphicInfo *g = &graphic_info[graphic];
5843 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5849 Bitmap *debug_bitmap = g_em->bitmap;
5850 int debug_src_x = g_em->src_x;
5851 int debug_src_y = g_em->src_y;
5854 int frame = getAnimationFrame(g->anim_frames,
5857 g->anim_start_frame,
5860 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5862 g_em->bitmap = src_bitmap;
5863 g_em->src_x = src_x;
5864 g_em->src_y = src_y;
5865 g_em->src_offset_x = 0;
5866 g_em->src_offset_y = 0;
5867 g_em->dst_offset_x = 0;
5868 g_em->dst_offset_y = 0;
5869 g_em->width = TILEX;
5870 g_em->height = TILEY;
5875 /* skip check for EMC elements not contained in original EMC artwork */
5876 if (element == EL_PLAYER_3 ||
5877 element == EL_PLAYER_4)
5881 if (g_em->bitmap != debug_bitmap ||
5882 g_em->src_x != debug_src_x ||
5883 g_em->src_y != debug_src_y)
5885 static int last_i = -1;
5893 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5894 p, i, element, element_info[element].token_name,
5895 element_action_info[effective_action].suffix, direction);
5897 if (element != effective_element)
5898 printf(" [%d ('%s')]",
5900 element_info[effective_element].token_name);
5904 if (g_em->bitmap != debug_bitmap)
5905 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5906 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5908 if (g_em->src_x != debug_src_x ||
5909 g_em->src_y != debug_src_y)
5910 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5912 g_em->src_x, g_em->src_y,
5913 g_em->src_x / 32, g_em->src_y / 32,
5914 debug_src_x, debug_src_y,
5915 debug_src_x / 32, debug_src_y / 32);
5917 num_em_gfx_errors++;
5927 printf("::: [%d errors found]\n", num_em_gfx_errors);
5933 void PlayMenuSound()
5935 int sound = menu.sound[game_status];
5937 if (sound == SND_UNDEFINED)
5940 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5941 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5944 if (IS_LOOP_SOUND(sound))
5945 PlaySoundLoop(sound);
5950 void PlayMenuSoundStereo(int sound, int stereo_position)
5952 if (sound == SND_UNDEFINED)
5955 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5956 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5959 if (IS_LOOP_SOUND(sound))
5960 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
5962 PlaySoundStereo(sound, stereo_position);
5965 void PlayMenuSoundIfLoop()
5967 int sound = menu.sound[game_status];
5969 if (sound == SND_UNDEFINED)
5972 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5973 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5976 if (IS_LOOP_SOUND(sound))
5977 PlaySoundLoop(sound);
5980 void PlayMenuMusic()
5982 int music = menu.music[game_status];
5984 if (music == MUS_UNDEFINED)