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 DrawLevelField(last_jx, last_jy);
1966 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1967 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1970 if (!IN_SCR_FIELD(sx, sy))
1973 if (setup.direct_draw)
1974 SetDrawtoField(DRAW_BUFFERED);
1976 /* ----------------------------------------------------------------------- */
1977 /* draw things behind the player, if needed */
1978 /* ----------------------------------------------------------------------- */
1981 DrawLevelElement(jx, jy, Back[jx][jy]);
1982 else if (IS_ACTIVE_BOMB(element))
1983 DrawLevelElement(jx, jy, EL_EMPTY);
1986 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1988 int old_element = GfxElement[jx][jy];
1989 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1990 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1992 if (GFX_CRUMBLED(old_element))
1993 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1995 DrawGraphic(sx, sy, old_graphic, frame);
1997 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
1998 player_is_opaque = TRUE;
2002 GfxElement[jx][jy] = EL_UNDEFINED;
2004 /* make sure that pushed elements are drawn with correct frame rate */
2005 if (player->is_pushing && player->is_moving)
2006 GfxFrame[jx][jy] = player->StepFrame;
2008 DrawLevelField(jx, jy);
2012 /* ----------------------------------------------------------------------- */
2013 /* draw player himself */
2014 /* ----------------------------------------------------------------------- */
2016 graphic = getPlayerGraphic(player, move_dir);
2018 /* in the case of changed player action or direction, prevent the current
2019 animation frame from being restarted for identical animations */
2020 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2021 player->Frame = last_player_frame;
2023 frame = getGraphicAnimationFrame(graphic, player->Frame);
2027 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2028 sxx = player->GfxPos;
2030 syy = player->GfxPos;
2033 if (!setup.soft_scrolling && ScreenMovPos)
2036 if (player_is_opaque)
2037 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2039 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2041 if (SHIELD_ON(player))
2043 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2044 IMG_SHIELD_NORMAL_ACTIVE);
2045 int frame = getGraphicAnimationFrame(graphic, -1);
2047 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2050 /* ----------------------------------------------------------------------- */
2051 /* draw things the player is pushing, if needed */
2052 /* ----------------------------------------------------------------------- */
2055 printf("::: %d, %d [%d, %d] [%d]\n",
2056 player->is_pushing, player_is_moving, player->GfxAction,
2057 player->is_moving, player_is_moving);
2061 if (player->is_pushing && player->is_moving)
2063 int px = SCREENX(jx), py = SCREENY(jy);
2064 int pxx = (TILEX - ABS(sxx)) * dx;
2065 int pyy = (TILEY - ABS(syy)) * dy;
2070 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2071 element = Feld[next_jx][next_jy];
2073 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2074 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2076 /* draw background element under pushed element (like the Sokoban field) */
2077 if (Back[next_jx][next_jy])
2078 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2080 /* masked drawing is needed for EMC style (double) movement graphics */
2081 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2085 /* ----------------------------------------------------------------------- */
2086 /* draw things in front of player (active dynamite or dynabombs) */
2087 /* ----------------------------------------------------------------------- */
2089 if (IS_ACTIVE_BOMB(element))
2091 graphic = el2img(element);
2092 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2094 if (game.emulation == EMU_SUPAPLEX)
2095 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2097 DrawGraphicThruMask(sx, sy, graphic, frame);
2100 if (player_is_moving && last_element == EL_EXPLOSION)
2102 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2103 GfxElement[last_jx][last_jy] : EL_EMPTY);
2104 int graphic = el_act2img(element, ACTION_EXPLODING);
2105 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2106 int phase = ExplodePhase[last_jx][last_jy] - 1;
2107 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2110 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2113 /* ----------------------------------------------------------------------- */
2114 /* draw elements the player is just walking/passing through/under */
2115 /* ----------------------------------------------------------------------- */
2117 if (player_is_moving)
2119 /* handle the field the player is leaving ... */
2120 if (IS_ACCESSIBLE_INSIDE(last_element))
2121 DrawLevelField(last_jx, last_jy);
2122 else if (IS_ACCESSIBLE_UNDER(last_element))
2123 DrawLevelFieldThruMask(last_jx, last_jy);
2126 /* do not redraw accessible elements if the player is just pushing them */
2127 if (!player_is_moving || !player->is_pushing)
2129 /* ... and the field the player is entering */
2130 if (IS_ACCESSIBLE_INSIDE(element))
2131 DrawLevelField(jx, jy);
2132 else if (IS_ACCESSIBLE_UNDER(element))
2133 DrawLevelFieldThruMask(jx, jy);
2136 if (setup.direct_draw)
2138 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2139 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2140 int x_size = TILEX * (1 + ABS(jx - last_jx));
2141 int y_size = TILEY * (1 + ABS(jy - last_jy));
2143 BlitBitmap(drawto_field, window,
2144 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2145 SetDrawtoField(DRAW_DIRECT);
2148 MarkTileDirty(sx, sy);
2151 /* ------------------------------------------------------------------------- */
2153 void WaitForEventToContinue()
2155 boolean still_wait = TRUE;
2157 /* simulate releasing mouse button over last gadget, if still pressed */
2159 HandleGadgets(-1, -1, 0);
2161 button_status = MB_RELEASED;
2173 case EVENT_BUTTONPRESS:
2174 case EVENT_KEYPRESS:
2178 case EVENT_KEYRELEASE:
2179 ClearPlayerAction();
2183 HandleOtherEvents(&event);
2187 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2194 /* don't eat all CPU time */
2199 #define MAX_REQUEST_LINES 13
2200 #define MAX_REQUEST_LINE_FONT1_LEN 7
2201 #define MAX_REQUEST_LINE_FONT2_LEN 10
2203 boolean Request(char *text, unsigned int req_state)
2205 int mx, my, ty, result = -1;
2206 unsigned int old_door_state;
2207 int last_game_status = game_status; /* save current game status */
2208 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2209 int font_nr = FONT_TEXT_2;
2210 int max_word_len = 0;
2213 for (text_ptr = text; *text_ptr; text_ptr++)
2215 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2217 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2219 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2220 font_nr = FONT_LEVEL_NUMBER;
2226 if (game_status == GAME_MODE_PLAYING &&
2227 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2228 BlitScreenToBitmap_EM(backbuffer);
2230 /* disable deactivated drawing when quick-loading level tape recording */
2231 if (tape.playing && tape.deactivate_display)
2232 TapeDeactivateDisplayOff(TRUE);
2234 SetMouseCursor(CURSOR_DEFAULT);
2236 #if defined(NETWORK_AVALIABLE)
2237 /* pause network game while waiting for request to answer */
2238 if (options.network &&
2239 game_status == GAME_MODE_PLAYING &&
2240 req_state & REQUEST_WAIT_FOR_INPUT)
2241 SendToServer_PausePlaying();
2244 old_door_state = GetDoorState();
2246 /* simulate releasing mouse button over last gadget, if still pressed */
2248 HandleGadgets(-1, -1, 0);
2252 if (old_door_state & DOOR_OPEN_1)
2254 CloseDoor(DOOR_CLOSE_1);
2256 /* save old door content */
2257 BlitBitmap(bitmap_db_door, bitmap_db_door,
2258 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2259 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2262 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2264 /* clear door drawing field */
2265 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2267 /* force DOOR font on preview level */
2268 game_status = GAME_MODE_PSEUDO_DOOR;
2270 /* write text for request */
2271 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2273 char text_line[max_request_line_len + 1];
2279 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2282 if (!tc || tc == ' ')
2293 strncpy(text_line, text, tl);
2296 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2297 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2298 text_line, font_nr);
2300 text += tl + (tc == ' ' ? 1 : 0);
2303 game_status = last_game_status; /* restore current game status */
2305 if (req_state & REQ_ASK)
2307 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2308 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2310 else if (req_state & REQ_CONFIRM)
2312 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2314 else if (req_state & REQ_PLAYER)
2316 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2317 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2318 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2319 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2322 /* copy request gadgets to door backbuffer */
2323 BlitBitmap(drawto, bitmap_db_door,
2324 DX, DY, DXSIZE, DYSIZE,
2325 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2327 OpenDoor(DOOR_OPEN_1);
2329 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2331 SetDrawBackgroundMask(REDRAW_FIELD);
2336 if (game_status != GAME_MODE_MAIN)
2339 button_status = MB_RELEASED;
2341 request_gadget_id = -1;
2343 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2355 case EVENT_BUTTONPRESS:
2356 case EVENT_BUTTONRELEASE:
2357 case EVENT_MOTIONNOTIFY:
2359 if (event.type == EVENT_MOTIONNOTIFY)
2361 if (!PointerInWindow(window))
2362 continue; /* window and pointer are on different screens */
2367 motion_status = TRUE;
2368 mx = ((MotionEvent *) &event)->x;
2369 my = ((MotionEvent *) &event)->y;
2373 motion_status = FALSE;
2374 mx = ((ButtonEvent *) &event)->x;
2375 my = ((ButtonEvent *) &event)->y;
2376 if (event.type == EVENT_BUTTONPRESS)
2377 button_status = ((ButtonEvent *) &event)->button;
2379 button_status = MB_RELEASED;
2382 /* this sets 'request_gadget_id' */
2383 HandleGadgets(mx, my, button_status);
2385 switch(request_gadget_id)
2387 case TOOL_CTRL_ID_YES:
2390 case TOOL_CTRL_ID_NO:
2393 case TOOL_CTRL_ID_CONFIRM:
2394 result = TRUE | FALSE;
2397 case TOOL_CTRL_ID_PLAYER_1:
2400 case TOOL_CTRL_ID_PLAYER_2:
2403 case TOOL_CTRL_ID_PLAYER_3:
2406 case TOOL_CTRL_ID_PLAYER_4:
2417 case EVENT_KEYPRESS:
2418 switch(GetEventKey((KeyEvent *)&event, TRUE))
2431 if (req_state & REQ_PLAYER)
2435 case EVENT_KEYRELEASE:
2436 ClearPlayerAction();
2440 HandleOtherEvents(&event);
2444 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2446 int joy = AnyJoystick();
2448 if (joy & JOY_BUTTON_1)
2450 else if (joy & JOY_BUTTON_2)
2456 /* don't eat all CPU time */
2460 if (game_status != GAME_MODE_MAIN)
2465 if (!(req_state & REQ_STAY_OPEN))
2467 CloseDoor(DOOR_CLOSE_1);
2469 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2470 (req_state & REQ_REOPEN))
2471 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2476 SetDrawBackgroundMask(REDRAW_FIELD);
2478 #if defined(NETWORK_AVALIABLE)
2479 /* continue network game after request */
2480 if (options.network &&
2481 game_status == GAME_MODE_PLAYING &&
2482 req_state & REQUEST_WAIT_FOR_INPUT)
2483 SendToServer_ContinuePlaying();
2486 /* restore deactivated drawing when quick-loading level tape recording */
2487 if (tape.playing && tape.deactivate_display)
2488 TapeDeactivateDisplayOn();
2493 unsigned int OpenDoor(unsigned int door_state)
2495 if (door_state & DOOR_COPY_BACK)
2497 if (door_state & DOOR_OPEN_1)
2498 BlitBitmap(bitmap_db_door, bitmap_db_door,
2499 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2500 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2502 if (door_state & DOOR_OPEN_2)
2503 BlitBitmap(bitmap_db_door, bitmap_db_door,
2504 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2505 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2507 door_state &= ~DOOR_COPY_BACK;
2510 return MoveDoor(door_state);
2513 unsigned int CloseDoor(unsigned int door_state)
2515 unsigned int old_door_state = GetDoorState();
2517 if (!(door_state & DOOR_NO_COPY_BACK))
2519 if (old_door_state & DOOR_OPEN_1)
2520 BlitBitmap(backbuffer, bitmap_db_door,
2521 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2523 if (old_door_state & DOOR_OPEN_2)
2524 BlitBitmap(backbuffer, bitmap_db_door,
2525 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2527 door_state &= ~DOOR_NO_COPY_BACK;
2530 return MoveDoor(door_state);
2533 unsigned int GetDoorState()
2535 return MoveDoor(DOOR_GET_STATE);
2538 unsigned int SetDoorState(unsigned int door_state)
2540 return MoveDoor(door_state | DOOR_SET_STATE);
2543 unsigned int MoveDoor(unsigned int door_state)
2545 static int door1 = DOOR_OPEN_1;
2546 static int door2 = DOOR_CLOSE_2;
2547 unsigned long door_delay = 0;
2548 unsigned long door_delay_value;
2551 if (door_1.width < 0 || door_1.width > DXSIZE)
2552 door_1.width = DXSIZE;
2553 if (door_1.height < 0 || door_1.height > DYSIZE)
2554 door_1.height = DYSIZE;
2555 if (door_2.width < 0 || door_2.width > VXSIZE)
2556 door_2.width = VXSIZE;
2557 if (door_2.height < 0 || door_2.height > VYSIZE)
2558 door_2.height = VYSIZE;
2560 if (door_state == DOOR_GET_STATE)
2561 return (door1 | door2);
2563 if (door_state & DOOR_SET_STATE)
2565 if (door_state & DOOR_ACTION_1)
2566 door1 = door_state & DOOR_ACTION_1;
2567 if (door_state & DOOR_ACTION_2)
2568 door2 = door_state & DOOR_ACTION_2;
2570 return (door1 | door2);
2573 if (!(door_state & DOOR_FORCE_REDRAW))
2575 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2576 door_state &= ~DOOR_OPEN_1;
2577 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2578 door_state &= ~DOOR_CLOSE_1;
2579 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2580 door_state &= ~DOOR_OPEN_2;
2581 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2582 door_state &= ~DOOR_CLOSE_2;
2585 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2588 if (setup.quick_doors)
2590 stepsize = 20; /* must be choosen to always draw last frame */
2591 door_delay_value = 0;
2594 if (global.autoplay_leveldir)
2596 door_state |= DOOR_NO_DELAY;
2597 door_state &= ~DOOR_CLOSE_ALL;
2600 if (door_state & DOOR_ACTION)
2602 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2603 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2604 boolean door_1_done = (!handle_door_1);
2605 boolean door_2_done = (!handle_door_2);
2606 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2607 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2608 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2609 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2610 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2611 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2612 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2613 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2614 int door_skip = max_door_size - door_size;
2616 int end = door_size;
2618 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2622 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2624 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2628 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2630 /* opening door sound has priority over simultaneously closing door */
2631 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2632 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2633 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2634 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2637 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2640 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2641 GC gc = bitmap->stored_clip_gc;
2643 if (door_state & DOOR_ACTION_1)
2645 int a = MIN(x * door_1.step_offset, end);
2646 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2647 int i = p + door_skip;
2649 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2651 BlitBitmap(bitmap_db_door, drawto,
2652 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2653 DXSIZE, DYSIZE, DX, DY);
2657 BlitBitmap(bitmap_db_door, drawto,
2658 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2659 DXSIZE, DYSIZE - p / 2, DX, DY);
2661 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2664 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2666 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2667 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2668 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2669 int dst2_x = DX, dst2_y = DY;
2670 int width = i, height = DYSIZE;
2672 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2673 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2676 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2677 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2680 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2682 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2683 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2684 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2685 int dst2_x = DX, dst2_y = DY;
2686 int width = DXSIZE, height = i;
2688 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2689 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2692 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2693 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2696 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2698 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2700 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2701 BlitBitmapMasked(bitmap, drawto,
2702 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2703 DX + DXSIZE - i, DY + j);
2704 BlitBitmapMasked(bitmap, drawto,
2705 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2706 DX + DXSIZE - i, DY + 140 + j);
2707 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2708 DY - (DOOR_GFX_PAGEY1 + j));
2709 BlitBitmapMasked(bitmap, drawto,
2710 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2712 BlitBitmapMasked(bitmap, drawto,
2713 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2716 BlitBitmapMasked(bitmap, drawto,
2717 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2719 BlitBitmapMasked(bitmap, drawto,
2720 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2722 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2723 BlitBitmapMasked(bitmap, drawto,
2724 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2725 DX + DXSIZE - i, DY + 77 + j);
2726 BlitBitmapMasked(bitmap, drawto,
2727 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2728 DX + DXSIZE - i, DY + 203 + j);
2731 redraw_mask |= REDRAW_DOOR_1;
2732 door_1_done = (a == end);
2735 if (door_state & DOOR_ACTION_2)
2738 int a = MIN(x * door_2.step_offset, door_size);
2739 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2740 int i = p + door_skip;
2742 int a = MIN(x * door_2.step_offset, door_size_2);
2743 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2744 int i = p + door_skip;
2747 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2749 BlitBitmap(bitmap_db_door, drawto,
2750 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2751 VXSIZE, VYSIZE, VX, VY);
2753 else if (x <= VYSIZE)
2755 BlitBitmap(bitmap_db_door, drawto,
2756 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2757 VXSIZE, VYSIZE - p / 2, VX, VY);
2759 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2762 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2764 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2765 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2766 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2767 int dst2_x = VX, dst2_y = VY;
2768 int width = i, height = VYSIZE;
2770 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2771 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2774 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2775 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2778 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2780 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2781 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2782 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2783 int dst2_x = VX, dst2_y = VY;
2784 int width = VXSIZE, height = i;
2786 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2787 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2790 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2791 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2794 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2796 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2798 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2799 BlitBitmapMasked(bitmap, drawto,
2800 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2801 VX + VXSIZE - i, VY + j);
2802 SetClipOrigin(bitmap, gc,
2803 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2804 BlitBitmapMasked(bitmap, drawto,
2805 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2808 BlitBitmapMasked(bitmap, drawto,
2809 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2810 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2811 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2812 BlitBitmapMasked(bitmap, drawto,
2813 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2815 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2818 redraw_mask |= REDRAW_DOOR_2;
2819 door_2_done = (a == VXSIZE);
2822 if (!(door_state & DOOR_NO_DELAY))
2826 if (game_status == GAME_MODE_MAIN)
2829 WaitUntilDelayReached(&door_delay, door_delay_value);
2834 if (door_state & DOOR_ACTION_1)
2835 door1 = door_state & DOOR_ACTION_1;
2836 if (door_state & DOOR_ACTION_2)
2837 door2 = door_state & DOOR_ACTION_2;
2839 return (door1 | door2);
2842 void DrawSpecialEditorDoor()
2844 /* draw bigger toolbox window */
2845 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2846 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2848 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2849 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2852 redraw_mask |= REDRAW_ALL;
2855 void UndrawSpecialEditorDoor()
2857 /* draw normal tape recorder window */
2858 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2859 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2862 redraw_mask |= REDRAW_ALL;
2866 /* ---------- new tool button stuff ---------------------------------------- */
2868 /* graphic position values for tool buttons */
2869 #define TOOL_BUTTON_YES_XPOS 2
2870 #define TOOL_BUTTON_YES_YPOS 250
2871 #define TOOL_BUTTON_YES_GFX_YPOS 0
2872 #define TOOL_BUTTON_YES_XSIZE 46
2873 #define TOOL_BUTTON_YES_YSIZE 28
2874 #define TOOL_BUTTON_NO_XPOS 52
2875 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2876 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2877 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2878 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2879 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2880 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2881 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2882 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2883 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2884 #define TOOL_BUTTON_PLAYER_XSIZE 30
2885 #define TOOL_BUTTON_PLAYER_YSIZE 30
2886 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2887 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2888 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2889 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2890 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2891 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2892 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2893 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2894 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2895 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2896 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2897 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2898 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2899 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2900 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2901 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2902 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2903 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2904 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2905 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2914 } toolbutton_info[NUM_TOOL_BUTTONS] =
2917 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2918 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2919 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2924 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2925 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2926 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2931 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2932 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2933 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2934 TOOL_CTRL_ID_CONFIRM,
2938 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2939 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2940 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2941 TOOL_CTRL_ID_PLAYER_1,
2945 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2946 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2947 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2948 TOOL_CTRL_ID_PLAYER_2,
2952 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2953 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2954 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2955 TOOL_CTRL_ID_PLAYER_3,
2959 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2960 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2961 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2962 TOOL_CTRL_ID_PLAYER_4,
2967 void CreateToolButtons()
2971 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2973 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2974 Bitmap *deco_bitmap = None;
2975 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2976 struct GadgetInfo *gi;
2977 unsigned long event_mask;
2978 int gd_xoffset, gd_yoffset;
2979 int gd_x1, gd_x2, gd_y;
2982 event_mask = GD_EVENT_RELEASED;
2984 gd_xoffset = toolbutton_info[i].xpos;
2985 gd_yoffset = toolbutton_info[i].ypos;
2986 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2987 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2988 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2990 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2992 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2994 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2995 &deco_bitmap, &deco_x, &deco_y);
2996 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2997 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3000 gi = CreateGadget(GDI_CUSTOM_ID, id,
3001 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3002 GDI_X, DX + toolbutton_info[i].x,
3003 GDI_Y, DY + toolbutton_info[i].y,
3004 GDI_WIDTH, toolbutton_info[i].width,
3005 GDI_HEIGHT, toolbutton_info[i].height,
3006 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3007 GDI_STATE, GD_BUTTON_UNPRESSED,
3008 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3009 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3010 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3011 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3012 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3013 GDI_DECORATION_SHIFTING, 1, 1,
3014 GDI_EVENT_MASK, event_mask,
3015 GDI_CALLBACK_ACTION, HandleToolButtons,
3019 Error(ERR_EXIT, "cannot create gadget");
3021 tool_gadget[id] = gi;
3025 void FreeToolButtons()
3029 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3030 FreeGadget(tool_gadget[i]);
3033 static void UnmapToolButtons()
3037 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3038 UnmapGadget(tool_gadget[i]);
3041 static void HandleToolButtons(struct GadgetInfo *gi)
3043 request_gadget_id = gi->custom_id;
3046 static struct Mapping_EM_to_RND_object
3049 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3050 boolean is_backside; /* backside of moving element */
3056 em_object_mapping_list[] =
3059 Xblank, TRUE, FALSE,
3063 Yacid_splash_eB, FALSE, FALSE,
3064 EL_ACID_SPLASH_RIGHT, -1, -1
3067 Yacid_splash_wB, FALSE, FALSE,
3068 EL_ACID_SPLASH_LEFT, -1, -1
3071 #ifdef EM_ENGINE_BAD_ROLL
3073 Xstone_force_e, FALSE, FALSE,
3074 EL_ROCK, -1, MV_BIT_RIGHT
3077 Xstone_force_w, FALSE, FALSE,
3078 EL_ROCK, -1, MV_BIT_LEFT
3081 Xnut_force_e, FALSE, FALSE,
3082 EL_NUT, -1, MV_BIT_RIGHT
3085 Xnut_force_w, FALSE, FALSE,
3086 EL_NUT, -1, MV_BIT_LEFT
3089 Xspring_force_e, FALSE, FALSE,
3090 EL_SPRING, -1, MV_BIT_RIGHT
3093 Xspring_force_w, FALSE, FALSE,
3094 EL_SPRING, -1, MV_BIT_LEFT
3097 Xemerald_force_e, FALSE, FALSE,
3098 EL_EMERALD, -1, MV_BIT_RIGHT
3101 Xemerald_force_w, FALSE, FALSE,
3102 EL_EMERALD, -1, MV_BIT_LEFT
3105 Xdiamond_force_e, FALSE, FALSE,
3106 EL_DIAMOND, -1, MV_BIT_RIGHT
3109 Xdiamond_force_w, FALSE, FALSE,
3110 EL_DIAMOND, -1, MV_BIT_LEFT
3113 Xbomb_force_e, FALSE, FALSE,
3114 EL_BOMB, -1, MV_BIT_RIGHT
3117 Xbomb_force_w, FALSE, FALSE,
3118 EL_BOMB, -1, MV_BIT_LEFT
3120 #endif /* EM_ENGINE_BAD_ROLL */
3123 Xstone, TRUE, FALSE,
3127 Xstone_pause, FALSE, FALSE,
3131 Xstone_fall, FALSE, FALSE,
3135 Ystone_s, FALSE, FALSE,
3136 EL_ROCK, ACTION_FALLING, -1
3139 Ystone_sB, FALSE, TRUE,
3140 EL_ROCK, ACTION_FALLING, -1
3143 Ystone_e, FALSE, FALSE,
3144 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3147 Ystone_eB, FALSE, TRUE,
3148 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3151 Ystone_w, FALSE, FALSE,
3152 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3155 Ystone_wB, FALSE, TRUE,
3156 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3163 Xnut_pause, FALSE, FALSE,
3167 Xnut_fall, FALSE, FALSE,
3171 Ynut_s, FALSE, FALSE,
3172 EL_NUT, ACTION_FALLING, -1
3175 Ynut_sB, FALSE, TRUE,
3176 EL_NUT, ACTION_FALLING, -1
3179 Ynut_e, FALSE, FALSE,
3180 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3183 Ynut_eB, FALSE, TRUE,
3184 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3187 Ynut_w, FALSE, FALSE,
3188 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3191 Ynut_wB, FALSE, TRUE,
3192 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3195 Xbug_n, TRUE, FALSE,
3199 Xbug_e, TRUE, FALSE,
3200 EL_BUG_RIGHT, -1, -1
3203 Xbug_s, TRUE, FALSE,
3207 Xbug_w, TRUE, FALSE,
3211 Xbug_gon, FALSE, FALSE,
3215 Xbug_goe, FALSE, FALSE,
3216 EL_BUG_RIGHT, -1, -1
3219 Xbug_gos, FALSE, FALSE,
3223 Xbug_gow, FALSE, FALSE,
3227 Ybug_n, FALSE, FALSE,
3228 EL_BUG, ACTION_MOVING, MV_BIT_UP
3231 Ybug_nB, FALSE, TRUE,
3232 EL_BUG, ACTION_MOVING, MV_BIT_UP
3235 Ybug_e, FALSE, FALSE,
3236 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3239 Ybug_eB, FALSE, TRUE,
3240 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3243 Ybug_s, FALSE, FALSE,
3244 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3247 Ybug_sB, FALSE, TRUE,
3248 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3251 Ybug_w, FALSE, FALSE,
3252 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3255 Ybug_wB, FALSE, TRUE,
3256 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3259 Ybug_w_n, FALSE, FALSE,
3260 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3263 Ybug_n_e, FALSE, FALSE,
3264 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3267 Ybug_e_s, FALSE, FALSE,
3268 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3271 Ybug_s_w, FALSE, FALSE,
3272 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3275 Ybug_e_n, FALSE, FALSE,
3276 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3279 Ybug_s_e, FALSE, FALSE,
3280 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3283 Ybug_w_s, FALSE, FALSE,
3284 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3287 Ybug_n_w, FALSE, FALSE,
3288 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3291 Ybug_stone, FALSE, FALSE,
3292 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3295 Ybug_spring, FALSE, FALSE,
3296 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3299 Xtank_n, TRUE, FALSE,
3300 EL_SPACESHIP_UP, -1, -1
3303 Xtank_e, TRUE, FALSE,
3304 EL_SPACESHIP_RIGHT, -1, -1
3307 Xtank_s, TRUE, FALSE,
3308 EL_SPACESHIP_DOWN, -1, -1
3311 Xtank_w, TRUE, FALSE,
3312 EL_SPACESHIP_LEFT, -1, -1
3315 Xtank_gon, FALSE, FALSE,
3316 EL_SPACESHIP_UP, -1, -1
3319 Xtank_goe, FALSE, FALSE,
3320 EL_SPACESHIP_RIGHT, -1, -1
3323 Xtank_gos, FALSE, FALSE,
3324 EL_SPACESHIP_DOWN, -1, -1
3327 Xtank_gow, FALSE, FALSE,
3328 EL_SPACESHIP_LEFT, -1, -1
3331 Ytank_n, FALSE, FALSE,
3332 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3335 Ytank_nB, FALSE, TRUE,
3336 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3339 Ytank_e, FALSE, FALSE,
3340 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3343 Ytank_eB, FALSE, TRUE,
3344 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3347 Ytank_s, FALSE, FALSE,
3348 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3351 Ytank_sB, FALSE, TRUE,
3352 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3355 Ytank_w, FALSE, FALSE,
3356 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3359 Ytank_wB, FALSE, TRUE,
3360 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3363 Ytank_w_n, FALSE, FALSE,
3364 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3367 Ytank_n_e, FALSE, FALSE,
3368 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3371 Ytank_e_s, FALSE, FALSE,
3372 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3375 Ytank_s_w, FALSE, FALSE,
3376 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3379 Ytank_e_n, FALSE, FALSE,
3380 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3383 Ytank_s_e, FALSE, FALSE,
3384 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3387 Ytank_w_s, FALSE, FALSE,
3388 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3391 Ytank_n_w, FALSE, FALSE,
3392 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3395 Ytank_stone, FALSE, FALSE,
3396 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3399 Ytank_spring, FALSE, FALSE,
3400 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3403 Xandroid, TRUE, FALSE,
3404 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3407 Xandroid_1_n, FALSE, FALSE,
3408 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3411 Xandroid_2_n, FALSE, FALSE,
3412 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3415 Xandroid_1_e, FALSE, FALSE,
3416 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3419 Xandroid_2_e, FALSE, FALSE,
3420 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3423 Xandroid_1_w, FALSE, FALSE,
3424 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3427 Xandroid_2_w, FALSE, FALSE,
3428 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3431 Xandroid_1_s, FALSE, FALSE,
3432 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3435 Xandroid_2_s, FALSE, FALSE,
3436 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3439 Yandroid_n, FALSE, FALSE,
3440 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3443 Yandroid_nB, FALSE, TRUE,
3444 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3447 Yandroid_ne, FALSE, FALSE,
3448 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3451 Yandroid_neB, FALSE, TRUE,
3452 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3455 Yandroid_e, FALSE, FALSE,
3456 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3459 Yandroid_eB, FALSE, TRUE,
3460 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3463 Yandroid_se, FALSE, FALSE,
3464 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3467 Yandroid_seB, FALSE, TRUE,
3468 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3471 Yandroid_s, FALSE, FALSE,
3472 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3475 Yandroid_sB, FALSE, TRUE,
3476 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3479 Yandroid_sw, FALSE, FALSE,
3480 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3483 Yandroid_swB, FALSE, TRUE,
3484 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3487 Yandroid_w, FALSE, FALSE,
3488 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3491 Yandroid_wB, FALSE, TRUE,
3492 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3495 Yandroid_nw, FALSE, FALSE,
3496 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3499 Yandroid_nwB, FALSE, TRUE,
3500 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3503 Xspring, TRUE, FALSE,
3507 Xspring_pause, FALSE, FALSE,
3511 Xspring_e, FALSE, FALSE,
3515 Xspring_w, FALSE, FALSE,
3519 Xspring_fall, FALSE, FALSE,
3523 Yspring_s, FALSE, FALSE,
3524 EL_SPRING, ACTION_FALLING, -1
3527 Yspring_sB, FALSE, TRUE,
3528 EL_SPRING, ACTION_FALLING, -1
3531 Yspring_e, FALSE, FALSE,
3532 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3535 Yspring_eB, FALSE, TRUE,
3536 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3539 Yspring_w, FALSE, FALSE,
3540 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3543 Yspring_wB, FALSE, TRUE,
3544 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3547 Yspring_kill_e, FALSE, FALSE,
3548 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3551 Yspring_kill_eB, FALSE, TRUE,
3552 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3555 Yspring_kill_w, FALSE, FALSE,
3556 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3559 Yspring_kill_wB, FALSE, TRUE,
3560 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3563 Xeater_n, TRUE, FALSE,
3564 EL_YAMYAM_UP, -1, -1
3567 Xeater_e, TRUE, FALSE,
3568 EL_YAMYAM_RIGHT, -1, -1
3571 Xeater_w, TRUE, FALSE,
3572 EL_YAMYAM_LEFT, -1, -1
3575 Xeater_s, TRUE, FALSE,
3576 EL_YAMYAM_DOWN, -1, -1
3579 Yeater_n, FALSE, FALSE,
3580 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3583 Yeater_nB, FALSE, TRUE,
3584 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3587 Yeater_e, FALSE, FALSE,
3588 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3591 Yeater_eB, FALSE, TRUE,
3592 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3595 Yeater_s, FALSE, FALSE,
3596 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3599 Yeater_sB, FALSE, TRUE,
3600 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3603 Yeater_w, FALSE, FALSE,
3604 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3607 Yeater_wB, FALSE, TRUE,
3608 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3611 Yeater_stone, FALSE, FALSE,
3612 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3615 Yeater_spring, FALSE, FALSE,
3616 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3619 Xalien, TRUE, FALSE,
3623 Xalien_pause, FALSE, FALSE,
3627 Yalien_n, FALSE, FALSE,
3628 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3631 Yalien_nB, FALSE, TRUE,
3632 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3635 Yalien_e, FALSE, FALSE,
3636 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3639 Yalien_eB, FALSE, TRUE,
3640 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3643 Yalien_s, FALSE, FALSE,
3644 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3647 Yalien_sB, FALSE, TRUE,
3648 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3651 Yalien_w, FALSE, FALSE,
3652 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3655 Yalien_wB, FALSE, TRUE,
3656 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3659 Yalien_stone, FALSE, FALSE,
3660 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3663 Yalien_spring, FALSE, FALSE,
3664 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3667 Xemerald, TRUE, FALSE,
3671 Xemerald_pause, FALSE, FALSE,
3675 Xemerald_fall, FALSE, FALSE,
3679 Xemerald_shine, FALSE, FALSE,
3680 EL_EMERALD, ACTION_TWINKLING, -1
3683 Yemerald_s, FALSE, FALSE,
3684 EL_EMERALD, ACTION_FALLING, -1
3687 Yemerald_sB, FALSE, TRUE,
3688 EL_EMERALD, ACTION_FALLING, -1
3691 Yemerald_e, FALSE, FALSE,
3692 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3695 Yemerald_eB, FALSE, TRUE,
3696 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3699 Yemerald_w, FALSE, FALSE,
3700 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3703 Yemerald_wB, FALSE, TRUE,
3704 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3707 Yemerald_eat, FALSE, FALSE,
3708 EL_EMERALD, ACTION_COLLECTING, -1
3711 Yemerald_stone, FALSE, FALSE,
3712 EL_NUT, ACTION_BREAKING, -1
3715 Xdiamond, TRUE, FALSE,
3719 Xdiamond_pause, FALSE, FALSE,
3723 Xdiamond_fall, FALSE, FALSE,
3727 Xdiamond_shine, FALSE, FALSE,
3728 EL_DIAMOND, ACTION_TWINKLING, -1
3731 Ydiamond_s, FALSE, FALSE,
3732 EL_DIAMOND, ACTION_FALLING, -1
3735 Ydiamond_sB, FALSE, TRUE,
3736 EL_DIAMOND, ACTION_FALLING, -1
3739 Ydiamond_e, FALSE, FALSE,
3740 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3743 Ydiamond_eB, FALSE, TRUE,
3744 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3747 Ydiamond_w, FALSE, FALSE,
3748 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3751 Ydiamond_wB, FALSE, TRUE,
3752 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3755 Ydiamond_eat, FALSE, FALSE,
3756 EL_DIAMOND, ACTION_COLLECTING, -1
3759 Ydiamond_stone, FALSE, FALSE,
3760 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3763 Xdrip_fall, TRUE, FALSE,
3764 EL_AMOEBA_DROP, -1, -1
3767 Xdrip_stretch, FALSE, FALSE,
3768 EL_AMOEBA_DROP, ACTION_FALLING, -1
3771 Xdrip_stretchB, FALSE, TRUE,
3772 EL_AMOEBA_DROP, ACTION_FALLING, -1
3775 Xdrip_eat, FALSE, FALSE,
3776 EL_AMOEBA_DROP, ACTION_GROWING, -1
3779 Ydrip_s1, FALSE, FALSE,
3780 EL_AMOEBA_DROP, ACTION_FALLING, -1
3783 Ydrip_s1B, FALSE, TRUE,
3784 EL_AMOEBA_DROP, ACTION_FALLING, -1
3787 Ydrip_s2, FALSE, FALSE,
3788 EL_AMOEBA_DROP, ACTION_FALLING, -1
3791 Ydrip_s2B, FALSE, TRUE,
3792 EL_AMOEBA_DROP, ACTION_FALLING, -1
3799 Xbomb_pause, FALSE, FALSE,
3803 Xbomb_fall, FALSE, FALSE,
3807 Ybomb_s, FALSE, FALSE,
3808 EL_BOMB, ACTION_FALLING, -1
3811 Ybomb_sB, FALSE, TRUE,
3812 EL_BOMB, ACTION_FALLING, -1
3815 Ybomb_e, FALSE, FALSE,
3816 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3819 Ybomb_eB, FALSE, TRUE,
3820 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3823 Ybomb_w, FALSE, FALSE,
3824 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3827 Ybomb_wB, FALSE, TRUE,
3828 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3831 Ybomb_eat, FALSE, FALSE,
3832 EL_BOMB, ACTION_ACTIVATING, -1
3835 Xballoon, TRUE, FALSE,
3839 Yballoon_n, FALSE, FALSE,
3840 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3843 Yballoon_nB, FALSE, TRUE,
3844 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3847 Yballoon_e, FALSE, FALSE,
3848 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3851 Yballoon_eB, FALSE, TRUE,
3852 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3855 Yballoon_s, FALSE, FALSE,
3856 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3859 Yballoon_sB, FALSE, TRUE,
3860 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3863 Yballoon_w, FALSE, FALSE,
3864 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3867 Yballoon_wB, FALSE, TRUE,
3868 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3871 Xgrass, TRUE, FALSE,
3872 EL_EMC_GRASS, -1, -1
3875 Ygrass_nB, FALSE, FALSE,
3876 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3879 Ygrass_eB, FALSE, FALSE,
3880 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3883 Ygrass_sB, FALSE, FALSE,
3884 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3887 Ygrass_wB, FALSE, FALSE,
3888 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3895 Ydirt_nB, FALSE, FALSE,
3896 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3899 Ydirt_eB, FALSE, FALSE,
3900 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3903 Ydirt_sB, FALSE, FALSE,
3904 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3907 Ydirt_wB, FALSE, FALSE,
3908 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3911 Xacid_ne, TRUE, FALSE,
3912 EL_ACID_POOL_TOPRIGHT, -1, -1
3915 Xacid_se, TRUE, FALSE,
3916 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3919 Xacid_s, TRUE, FALSE,
3920 EL_ACID_POOL_BOTTOM, -1, -1
3923 Xacid_sw, TRUE, FALSE,
3924 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3927 Xacid_nw, TRUE, FALSE,
3928 EL_ACID_POOL_TOPLEFT, -1, -1
3931 Xacid_1, TRUE, FALSE,
3935 Xacid_2, FALSE, FALSE,
3939 Xacid_3, FALSE, FALSE,
3943 Xacid_4, FALSE, FALSE,
3947 Xacid_5, FALSE, FALSE,
3951 Xacid_6, FALSE, FALSE,
3955 Xacid_7, FALSE, FALSE,
3959 Xacid_8, FALSE, FALSE,
3963 Xball_1, TRUE, FALSE,
3964 EL_EMC_MAGIC_BALL, -1, -1
3967 Xball_1B, FALSE, FALSE,
3968 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3971 Xball_2, FALSE, FALSE,
3972 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3975 Xball_2B, FALSE, FALSE,
3976 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3979 Yball_eat, FALSE, FALSE,
3980 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3983 Ykey_1_eat, FALSE, FALSE,
3984 EL_EM_KEY_1, ACTION_COLLECTING, -1
3987 Ykey_2_eat, FALSE, FALSE,
3988 EL_EM_KEY_2, ACTION_COLLECTING, -1
3991 Ykey_3_eat, FALSE, FALSE,
3992 EL_EM_KEY_3, ACTION_COLLECTING, -1
3995 Ykey_4_eat, FALSE, FALSE,
3996 EL_EM_KEY_4, ACTION_COLLECTING, -1
3999 Ykey_5_eat, FALSE, FALSE,
4000 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4003 Ykey_6_eat, FALSE, FALSE,
4004 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4007 Ykey_7_eat, FALSE, FALSE,
4008 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4011 Ykey_8_eat, FALSE, FALSE,
4012 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4015 Ylenses_eat, FALSE, FALSE,
4016 EL_EMC_LENSES, ACTION_COLLECTING, -1
4019 Ymagnify_eat, FALSE, FALSE,
4020 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4023 Ygrass_eat, FALSE, FALSE,
4024 EL_EMC_GRASS, ACTION_SNAPPING, -1
4027 Ydirt_eat, FALSE, FALSE,
4028 EL_SAND, ACTION_SNAPPING, -1
4031 Xgrow_ns, TRUE, FALSE,
4032 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4035 Ygrow_ns_eat, FALSE, FALSE,
4036 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4039 Xgrow_ew, TRUE, FALSE,
4040 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4043 Ygrow_ew_eat, FALSE, FALSE,
4044 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4047 Xwonderwall, TRUE, FALSE,
4048 EL_MAGIC_WALL, -1, -1
4051 XwonderwallB, FALSE, FALSE,
4052 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4055 Xamoeba_1, TRUE, FALSE,
4056 EL_AMOEBA_DRY, ACTION_OTHER, -1
4059 Xamoeba_2, FALSE, FALSE,
4060 EL_AMOEBA_DRY, ACTION_OTHER, -1
4063 Xamoeba_3, FALSE, FALSE,
4064 EL_AMOEBA_DRY, ACTION_OTHER, -1
4067 Xamoeba_4, FALSE, FALSE,
4068 EL_AMOEBA_DRY, ACTION_OTHER, -1
4071 Xamoeba_5, TRUE, FALSE,
4072 EL_AMOEBA_WET, ACTION_OTHER, -1
4075 Xamoeba_6, FALSE, FALSE,
4076 EL_AMOEBA_WET, ACTION_OTHER, -1
4079 Xamoeba_7, FALSE, FALSE,
4080 EL_AMOEBA_WET, ACTION_OTHER, -1
4083 Xamoeba_8, FALSE, FALSE,
4084 EL_AMOEBA_WET, ACTION_OTHER, -1
4087 Xdoor_1, TRUE, FALSE,
4088 EL_EM_GATE_1, -1, -1
4091 Xdoor_2, TRUE, FALSE,
4092 EL_EM_GATE_2, -1, -1
4095 Xdoor_3, TRUE, FALSE,
4096 EL_EM_GATE_3, -1, -1
4099 Xdoor_4, TRUE, FALSE,
4100 EL_EM_GATE_4, -1, -1
4103 Xdoor_5, TRUE, FALSE,
4104 EL_EMC_GATE_5, -1, -1
4107 Xdoor_6, TRUE, FALSE,
4108 EL_EMC_GATE_6, -1, -1
4111 Xdoor_7, TRUE, FALSE,
4112 EL_EMC_GATE_7, -1, -1
4115 Xdoor_8, TRUE, FALSE,
4116 EL_EMC_GATE_8, -1, -1
4119 Xkey_1, TRUE, FALSE,
4123 Xkey_2, TRUE, FALSE,
4127 Xkey_3, TRUE, FALSE,
4131 Xkey_4, TRUE, FALSE,
4135 Xkey_5, TRUE, FALSE,
4136 EL_EMC_KEY_5, -1, -1
4139 Xkey_6, TRUE, FALSE,
4140 EL_EMC_KEY_6, -1, -1
4143 Xkey_7, TRUE, FALSE,
4144 EL_EMC_KEY_7, -1, -1
4147 Xkey_8, TRUE, FALSE,
4148 EL_EMC_KEY_8, -1, -1
4151 Xwind_n, TRUE, FALSE,
4152 EL_BALLOON_SWITCH_UP, -1, -1
4155 Xwind_e, TRUE, FALSE,
4156 EL_BALLOON_SWITCH_RIGHT, -1, -1
4159 Xwind_s, TRUE, FALSE,
4160 EL_BALLOON_SWITCH_DOWN, -1, -1
4163 Xwind_w, TRUE, FALSE,
4164 EL_BALLOON_SWITCH_LEFT, -1, -1
4167 Xwind_nesw, TRUE, FALSE,
4168 EL_BALLOON_SWITCH_ANY, -1, -1
4171 Xwind_stop, TRUE, FALSE,
4172 EL_BALLOON_SWITCH_NONE, -1, -1
4176 EL_EXIT_CLOSED, -1, -1
4179 Xexit_1, TRUE, FALSE,
4180 EL_EXIT_OPEN, -1, -1
4183 Xexit_2, FALSE, FALSE,
4184 EL_EXIT_OPEN, -1, -1
4187 Xexit_3, FALSE, FALSE,
4188 EL_EXIT_OPEN, -1, -1
4191 Xdynamite, TRUE, FALSE,
4192 EL_EM_DYNAMITE, -1, -1
4195 Ydynamite_eat, FALSE, FALSE,
4196 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4199 Xdynamite_1, TRUE, FALSE,
4200 EL_EM_DYNAMITE_ACTIVE, -1, -1
4203 Xdynamite_2, FALSE, FALSE,
4204 EL_EM_DYNAMITE_ACTIVE, -1, -1
4207 Xdynamite_3, FALSE, FALSE,
4208 EL_EM_DYNAMITE_ACTIVE, -1, -1
4211 Xdynamite_4, FALSE, FALSE,
4212 EL_EM_DYNAMITE_ACTIVE, -1, -1
4215 Xbumper, TRUE, FALSE,
4216 EL_EMC_SPRING_BUMPER, -1, -1
4219 XbumperB, FALSE, FALSE,
4220 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4223 Xwheel, TRUE, FALSE,
4224 EL_ROBOT_WHEEL, -1, -1
4227 XwheelB, FALSE, FALSE,
4228 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4231 Xswitch, TRUE, FALSE,
4232 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4235 XswitchB, FALSE, FALSE,
4236 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4240 EL_QUICKSAND_EMPTY, -1, -1
4243 Xsand_stone, TRUE, FALSE,
4244 EL_QUICKSAND_FULL, -1, -1
4247 Xsand_stonein_1, FALSE, TRUE,
4248 EL_ROCK, ACTION_FILLING, -1
4251 Xsand_stonein_2, FALSE, TRUE,
4252 EL_ROCK, ACTION_FILLING, -1
4255 Xsand_stonein_3, FALSE, TRUE,
4256 EL_ROCK, ACTION_FILLING, -1
4259 Xsand_stonein_4, FALSE, TRUE,
4260 EL_ROCK, ACTION_FILLING, -1
4263 Xsand_stonesand_1, FALSE, FALSE,
4264 EL_QUICKSAND_FULL, -1, -1
4267 Xsand_stonesand_2, FALSE, FALSE,
4268 EL_QUICKSAND_FULL, -1, -1
4271 Xsand_stonesand_3, FALSE, FALSE,
4272 EL_QUICKSAND_FULL, -1, -1
4275 Xsand_stonesand_4, FALSE, FALSE,
4276 EL_QUICKSAND_FULL, -1, -1
4279 Xsand_stoneout_1, FALSE, FALSE,
4280 EL_ROCK, ACTION_EMPTYING, -1
4283 Xsand_stoneout_2, FALSE, FALSE,
4284 EL_ROCK, ACTION_EMPTYING, -1
4287 Xsand_sandstone_1, FALSE, FALSE,
4288 EL_QUICKSAND_FULL, -1, -1
4291 Xsand_sandstone_2, FALSE, FALSE,
4292 EL_QUICKSAND_FULL, -1, -1
4295 Xsand_sandstone_3, FALSE, FALSE,
4296 EL_QUICKSAND_FULL, -1, -1
4299 Xsand_sandstone_4, FALSE, FALSE,
4300 EL_QUICKSAND_FULL, -1, -1
4303 Xplant, TRUE, FALSE,
4304 EL_EMC_PLANT, -1, -1
4307 Yplant, FALSE, FALSE,
4308 EL_EMC_PLANT, -1, -1
4311 Xlenses, TRUE, FALSE,
4312 EL_EMC_LENSES, -1, -1
4315 Xmagnify, TRUE, FALSE,
4316 EL_EMC_MAGNIFIER, -1, -1
4319 Xdripper, TRUE, FALSE,
4320 EL_EMC_DRIPPER, -1, -1
4323 XdripperB, FALSE, FALSE,
4324 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4327 Xfake_blank, TRUE, FALSE,
4328 EL_INVISIBLE_WALL, -1, -1
4331 Xfake_blankB, FALSE, FALSE,
4332 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4335 Xfake_grass, TRUE, FALSE,
4336 EL_EMC_FAKE_GRASS, -1, -1
4339 Xfake_grassB, FALSE, FALSE,
4340 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4343 Xfake_door_1, TRUE, FALSE,
4344 EL_EM_GATE_1_GRAY, -1, -1
4347 Xfake_door_2, TRUE, FALSE,
4348 EL_EM_GATE_2_GRAY, -1, -1
4351 Xfake_door_3, TRUE, FALSE,
4352 EL_EM_GATE_3_GRAY, -1, -1
4355 Xfake_door_4, TRUE, FALSE,
4356 EL_EM_GATE_4_GRAY, -1, -1
4359 Xfake_door_5, TRUE, FALSE,
4360 EL_EMC_GATE_5_GRAY, -1, -1
4363 Xfake_door_6, TRUE, FALSE,
4364 EL_EMC_GATE_6_GRAY, -1, -1
4367 Xfake_door_7, TRUE, FALSE,
4368 EL_EMC_GATE_7_GRAY, -1, -1
4371 Xfake_door_8, TRUE, FALSE,
4372 EL_EMC_GATE_8_GRAY, -1, -1
4375 Xfake_acid_1, TRUE, FALSE,
4376 EL_EMC_FAKE_ACID, -1, -1
4379 Xfake_acid_2, FALSE, FALSE,
4380 EL_EMC_FAKE_ACID, -1, -1
4383 Xfake_acid_3, FALSE, FALSE,
4384 EL_EMC_FAKE_ACID, -1, -1
4387 Xfake_acid_4, FALSE, FALSE,
4388 EL_EMC_FAKE_ACID, -1, -1
4391 Xfake_acid_5, FALSE, FALSE,
4392 EL_EMC_FAKE_ACID, -1, -1
4395 Xfake_acid_6, FALSE, FALSE,
4396 EL_EMC_FAKE_ACID, -1, -1
4399 Xfake_acid_7, FALSE, FALSE,
4400 EL_EMC_FAKE_ACID, -1, -1
4403 Xfake_acid_8, FALSE, FALSE,
4404 EL_EMC_FAKE_ACID, -1, -1
4407 Xsteel_1, TRUE, FALSE,
4408 EL_STEELWALL, -1, -1
4411 Xsteel_2, TRUE, FALSE,
4412 EL_EMC_STEELWALL_2, -1, -1
4415 Xsteel_3, TRUE, FALSE,
4416 EL_EMC_STEELWALL_3, -1, -1
4419 Xsteel_4, TRUE, FALSE,
4420 EL_EMC_STEELWALL_4, -1, -1
4423 Xwall_1, TRUE, FALSE,
4427 Xwall_2, TRUE, FALSE,
4428 EL_EMC_WALL_14, -1, -1
4431 Xwall_3, TRUE, FALSE,
4432 EL_EMC_WALL_15, -1, -1
4435 Xwall_4, TRUE, FALSE,
4436 EL_EMC_WALL_16, -1, -1
4439 Xround_wall_1, TRUE, FALSE,
4440 EL_WALL_SLIPPERY, -1, -1
4443 Xround_wall_2, TRUE, FALSE,
4444 EL_EMC_WALL_SLIPPERY_2, -1, -1
4447 Xround_wall_3, TRUE, FALSE,
4448 EL_EMC_WALL_SLIPPERY_3, -1, -1
4451 Xround_wall_4, TRUE, FALSE,
4452 EL_EMC_WALL_SLIPPERY_4, -1, -1
4455 Xdecor_1, TRUE, FALSE,
4456 EL_EMC_WALL_8, -1, -1
4459 Xdecor_2, TRUE, FALSE,
4460 EL_EMC_WALL_6, -1, -1
4463 Xdecor_3, TRUE, FALSE,
4464 EL_EMC_WALL_4, -1, -1
4467 Xdecor_4, TRUE, FALSE,
4468 EL_EMC_WALL_7, -1, -1
4471 Xdecor_5, TRUE, FALSE,
4472 EL_EMC_WALL_5, -1, -1
4475 Xdecor_6, TRUE, FALSE,
4476 EL_EMC_WALL_9, -1, -1
4479 Xdecor_7, TRUE, FALSE,
4480 EL_EMC_WALL_10, -1, -1
4483 Xdecor_8, TRUE, FALSE,
4484 EL_EMC_WALL_1, -1, -1
4487 Xdecor_9, TRUE, FALSE,
4488 EL_EMC_WALL_2, -1, -1
4491 Xdecor_10, TRUE, FALSE,
4492 EL_EMC_WALL_3, -1, -1
4495 Xdecor_11, TRUE, FALSE,
4496 EL_EMC_WALL_11, -1, -1
4499 Xdecor_12, TRUE, FALSE,
4500 EL_EMC_WALL_12, -1, -1
4503 Xalpha_0, TRUE, FALSE,
4504 EL_CHAR('0'), -1, -1
4507 Xalpha_1, TRUE, FALSE,
4508 EL_CHAR('1'), -1, -1
4511 Xalpha_2, TRUE, FALSE,
4512 EL_CHAR('2'), -1, -1
4515 Xalpha_3, TRUE, FALSE,
4516 EL_CHAR('3'), -1, -1
4519 Xalpha_4, TRUE, FALSE,
4520 EL_CHAR('4'), -1, -1
4523 Xalpha_5, TRUE, FALSE,
4524 EL_CHAR('5'), -1, -1
4527 Xalpha_6, TRUE, FALSE,
4528 EL_CHAR('6'), -1, -1
4531 Xalpha_7, TRUE, FALSE,
4532 EL_CHAR('7'), -1, -1
4535 Xalpha_8, TRUE, FALSE,
4536 EL_CHAR('8'), -1, -1
4539 Xalpha_9, TRUE, FALSE,
4540 EL_CHAR('9'), -1, -1
4543 Xalpha_excla, TRUE, FALSE,
4544 EL_CHAR('!'), -1, -1
4547 Xalpha_quote, TRUE, FALSE,
4548 EL_CHAR('"'), -1, -1
4551 Xalpha_comma, TRUE, FALSE,
4552 EL_CHAR(','), -1, -1
4555 Xalpha_minus, TRUE, FALSE,
4556 EL_CHAR('-'), -1, -1
4559 Xalpha_perio, TRUE, FALSE,
4560 EL_CHAR('.'), -1, -1
4563 Xalpha_colon, TRUE, FALSE,
4564 EL_CHAR(':'), -1, -1
4567 Xalpha_quest, TRUE, FALSE,
4568 EL_CHAR('?'), -1, -1
4571 Xalpha_a, TRUE, FALSE,
4572 EL_CHAR('A'), -1, -1
4575 Xalpha_b, TRUE, FALSE,
4576 EL_CHAR('B'), -1, -1
4579 Xalpha_c, TRUE, FALSE,
4580 EL_CHAR('C'), -1, -1
4583 Xalpha_d, TRUE, FALSE,
4584 EL_CHAR('D'), -1, -1
4587 Xalpha_e, TRUE, FALSE,
4588 EL_CHAR('E'), -1, -1
4591 Xalpha_f, TRUE, FALSE,
4592 EL_CHAR('F'), -1, -1
4595 Xalpha_g, TRUE, FALSE,
4596 EL_CHAR('G'), -1, -1
4599 Xalpha_h, TRUE, FALSE,
4600 EL_CHAR('H'), -1, -1
4603 Xalpha_i, TRUE, FALSE,
4604 EL_CHAR('I'), -1, -1
4607 Xalpha_j, TRUE, FALSE,
4608 EL_CHAR('J'), -1, -1
4611 Xalpha_k, TRUE, FALSE,
4612 EL_CHAR('K'), -1, -1
4615 Xalpha_l, TRUE, FALSE,
4616 EL_CHAR('L'), -1, -1
4619 Xalpha_m, TRUE, FALSE,
4620 EL_CHAR('M'), -1, -1
4623 Xalpha_n, TRUE, FALSE,
4624 EL_CHAR('N'), -1, -1
4627 Xalpha_o, TRUE, FALSE,
4628 EL_CHAR('O'), -1, -1
4631 Xalpha_p, TRUE, FALSE,
4632 EL_CHAR('P'), -1, -1
4635 Xalpha_q, TRUE, FALSE,
4636 EL_CHAR('Q'), -1, -1
4639 Xalpha_r, TRUE, FALSE,
4640 EL_CHAR('R'), -1, -1
4643 Xalpha_s, TRUE, FALSE,
4644 EL_CHAR('S'), -1, -1
4647 Xalpha_t, TRUE, FALSE,
4648 EL_CHAR('T'), -1, -1
4651 Xalpha_u, TRUE, FALSE,
4652 EL_CHAR('U'), -1, -1
4655 Xalpha_v, TRUE, FALSE,
4656 EL_CHAR('V'), -1, -1
4659 Xalpha_w, TRUE, FALSE,
4660 EL_CHAR('W'), -1, -1
4663 Xalpha_x, TRUE, FALSE,
4664 EL_CHAR('X'), -1, -1
4667 Xalpha_y, TRUE, FALSE,
4668 EL_CHAR('Y'), -1, -1
4671 Xalpha_z, TRUE, FALSE,
4672 EL_CHAR('Z'), -1, -1
4675 Xalpha_arrow_e, TRUE, FALSE,
4676 EL_CHAR('>'), -1, -1
4679 Xalpha_arrow_w, TRUE, FALSE,
4680 EL_CHAR('<'), -1, -1
4683 Xalpha_copyr, TRUE, FALSE,
4684 EL_CHAR('©'), -1, -1
4688 Xboom_bug, FALSE, FALSE,
4689 EL_BUG, ACTION_EXPLODING, -1
4692 Xboom_bomb, FALSE, FALSE,
4693 EL_BOMB, ACTION_EXPLODING, -1
4696 Xboom_android, FALSE, FALSE,
4697 EL_EMC_ANDROID, ACTION_OTHER, -1
4700 Xboom_1, FALSE, FALSE,
4701 EL_DEFAULT, ACTION_EXPLODING, -1
4704 Xboom_2, FALSE, FALSE,
4705 EL_DEFAULT, ACTION_EXPLODING, -1
4708 Znormal, FALSE, FALSE,
4712 Zdynamite, FALSE, FALSE,
4716 Zplayer, FALSE, FALSE,
4720 ZBORDER, FALSE, FALSE,
4730 static struct Mapping_EM_to_RND_player
4739 em_player_mapping_list[] =
4743 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4747 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4751 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4755 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4759 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4763 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4767 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4771 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4775 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4779 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4783 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4787 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4791 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4795 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4799 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4803 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4807 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4811 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4815 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4819 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4823 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4827 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4831 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4835 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4839 EL_PLAYER_1, ACTION_DEFAULT, -1,
4843 EL_PLAYER_2, ACTION_DEFAULT, -1,
4847 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4851 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4855 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4859 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4863 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4867 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4871 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4875 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4879 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4883 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4887 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4891 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4895 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4899 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4903 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4907 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4911 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4915 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4919 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4923 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4927 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4931 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4935 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4939 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4943 EL_PLAYER_3, ACTION_DEFAULT, -1,
4947 EL_PLAYER_4, ACTION_DEFAULT, -1,
4956 int map_element_RND_to_EM(int element_rnd)
4958 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4959 static boolean mapping_initialized = FALSE;
4961 if (!mapping_initialized)
4965 /* return "Xalpha_quest" for all undefined elements in mapping array */
4966 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4967 mapping_RND_to_EM[i] = Xalpha_quest;
4969 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4970 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4971 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4972 em_object_mapping_list[i].element_em;
4974 mapping_initialized = TRUE;
4977 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4978 return mapping_RND_to_EM[element_rnd];
4980 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4985 int map_element_EM_to_RND(int element_em)
4987 static unsigned short mapping_EM_to_RND[TILE_MAX];
4988 static boolean mapping_initialized = FALSE;
4990 if (!mapping_initialized)
4994 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4995 for (i = 0; i < TILE_MAX; i++)
4996 mapping_EM_to_RND[i] = EL_UNKNOWN;
4998 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4999 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5000 em_object_mapping_list[i].element_rnd;
5002 mapping_initialized = TRUE;
5005 if (element_em >= 0 && element_em < TILE_MAX)
5006 return mapping_EM_to_RND[element_em];
5008 Error(ERR_WARN, "invalid EM level element %d", element_em);
5013 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5015 struct LevelInfo_EM *level_em = level->native_em_level;
5016 struct LEVEL *lev = level_em->lev;
5019 for (i = 0; i < TILE_MAX; i++)
5020 lev->android_array[i] = Xblank;
5022 for (i = 0; i < level->num_android_clone_elements; i++)
5024 int element_rnd = level->android_clone_element[i];
5025 int element_em = map_element_RND_to_EM(element_rnd);
5027 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5028 if (em_object_mapping_list[j].element_rnd == element_rnd)
5029 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5033 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5035 struct LevelInfo_EM *level_em = level->native_em_level;
5036 struct LEVEL *lev = level_em->lev;
5039 level->num_android_clone_elements = 0;
5041 for (i = 0; i < TILE_MAX; i++)
5043 int element_em = lev->android_array[i];
5045 boolean element_found = FALSE;
5047 if (element_em == Xblank)
5050 element_rnd = map_element_EM_to_RND(element_em);
5052 for (j = 0; j < level->num_android_clone_elements; j++)
5053 if (level->android_clone_element[j] == element_rnd)
5054 element_found = TRUE;
5058 level->android_clone_element[level->num_android_clone_elements++] =
5061 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5066 if (level->num_android_clone_elements == 0)
5068 level->num_android_clone_elements = 1;
5069 level->android_clone_element[0] = EL_EMPTY;
5073 int map_direction_RND_to_EM(int direction)
5075 return (direction == MV_UP ? 0 :
5076 direction == MV_RIGHT ? 1 :
5077 direction == MV_DOWN ? 2 :
5078 direction == MV_LEFT ? 3 :
5082 int map_direction_EM_to_RND(int direction)
5084 return (direction == 0 ? MV_UP :
5085 direction == 1 ? MV_RIGHT :
5086 direction == 2 ? MV_DOWN :
5087 direction == 3 ? MV_LEFT :
5091 int get_next_element(int element)
5095 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5096 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5097 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5098 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5099 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5100 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5101 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5103 default: return element;
5108 int el_act_dir2img(int element, int action, int direction)
5110 element = GFX_ELEMENT(element);
5112 if (direction == MV_NONE)
5113 return element_info[element].graphic[action];
5115 direction = MV_DIR_TO_BIT(direction);
5117 return element_info[element].direction_graphic[action][direction];
5120 int el_act_dir2img(int element, int action, int direction)
5122 element = GFX_ELEMENT(element);
5123 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5125 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5126 return element_info[element].direction_graphic[action][direction];
5131 static int el_act_dir2crm(int element, int action, int direction)
5133 element = GFX_ELEMENT(element);
5135 if (direction == MV_NONE)
5136 return element_info[element].crumbled[action];
5138 direction = MV_DIR_TO_BIT(direction);
5140 return element_info[element].direction_crumbled[action][direction];
5143 static int el_act_dir2crm(int element, int action, int direction)
5145 element = GFX_ELEMENT(element);
5146 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5148 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5149 return element_info[element].direction_crumbled[action][direction];
5153 int el_act2img(int element, int action)
5155 element = GFX_ELEMENT(element);
5157 return element_info[element].graphic[action];
5160 int el_act2crm(int element, int action)
5162 element = GFX_ELEMENT(element);
5164 return element_info[element].crumbled[action];
5167 int el_dir2img(int element, int direction)
5169 element = GFX_ELEMENT(element);
5171 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5174 int el2baseimg(int element)
5176 return element_info[element].graphic[ACTION_DEFAULT];
5179 int el2img(int element)
5181 element = GFX_ELEMENT(element);
5183 return element_info[element].graphic[ACTION_DEFAULT];
5186 int el2edimg(int element)
5188 element = GFX_ELEMENT(element);
5190 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5193 int el2preimg(int element)
5195 element = GFX_ELEMENT(element);
5197 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5200 int font2baseimg(int font_nr)
5202 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5206 void setCenteredPlayerNr_EM(int centered_player_nr)
5208 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5211 int getCenteredPlayerNr_EM()
5214 if (game.centered_player_nr_next >= 0 &&
5215 !native_em_level.ply[game.centered_player_nr_next]->alive)
5216 game.centered_player_nr_next = game.centered_player_nr;
5219 if (game.centered_player_nr != game.centered_player_nr_next)
5220 game.centered_player_nr = game.centered_player_nr_next;
5222 return game.centered_player_nr;
5225 void setSetCenteredPlayer_EM(boolean set_centered_player)
5227 game.set_centered_player = set_centered_player;
5230 boolean getSetCenteredPlayer_EM()
5232 return game.set_centered_player;
5236 int getNumActivePlayers_EM()
5238 int num_players = 0;
5244 for (i = 0; i < MAX_PLAYERS; i++)
5245 if (tape.player_participates[i])
5252 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5254 int game_frame_delay_value;
5256 game_frame_delay_value =
5257 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5258 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5261 if (tape.playing && tape.warp_forward && !tape.pausing)
5262 game_frame_delay_value = 0;
5264 return game_frame_delay_value;
5268 unsigned int InitRND(long seed)
5270 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5271 return InitEngineRND_EM(seed);
5273 return InitEngineRND(seed);
5276 void InitGraphicInfo_EM(void)
5278 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5279 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5283 int num_em_gfx_errors = 0;
5285 if (graphic_info_em_object[0][0].bitmap == NULL)
5287 /* EM graphics not yet initialized in em_open_all() */
5292 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5295 /* always start with reliable default values */
5296 for (i = 0; i < TILE_MAX; i++)
5298 object_mapping[i].element_rnd = EL_UNKNOWN;
5299 object_mapping[i].is_backside = FALSE;
5300 object_mapping[i].action = ACTION_DEFAULT;
5301 object_mapping[i].direction = MV_NONE;
5304 /* always start with reliable default values */
5305 for (p = 0; p < MAX_PLAYERS; p++)
5307 for (i = 0; i < SPR_MAX; i++)
5309 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5310 player_mapping[p][i].action = ACTION_DEFAULT;
5311 player_mapping[p][i].direction = MV_NONE;
5315 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5317 int e = em_object_mapping_list[i].element_em;
5319 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5320 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5322 if (em_object_mapping_list[i].action != -1)
5323 object_mapping[e].action = em_object_mapping_list[i].action;
5325 if (em_object_mapping_list[i].direction != -1)
5326 object_mapping[e].direction =
5327 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5330 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5332 int a = em_player_mapping_list[i].action_em;
5333 int p = em_player_mapping_list[i].player_nr;
5335 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5337 if (em_player_mapping_list[i].action != -1)
5338 player_mapping[p][a].action = em_player_mapping_list[i].action;
5340 if (em_player_mapping_list[i].direction != -1)
5341 player_mapping[p][a].direction =
5342 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5345 for (i = 0; i < TILE_MAX; i++)
5347 int element = object_mapping[i].element_rnd;
5348 int action = object_mapping[i].action;
5349 int direction = object_mapping[i].direction;
5350 boolean is_backside = object_mapping[i].is_backside;
5351 boolean action_removing = (action == ACTION_DIGGING ||
5352 action == ACTION_SNAPPING ||
5353 action == ACTION_COLLECTING);
5354 boolean action_exploding = ((action == ACTION_EXPLODING ||
5355 action == ACTION_SMASHED_BY_ROCK ||
5356 action == ACTION_SMASHED_BY_SPRING) &&
5357 element != EL_DIAMOND);
5358 boolean action_active = (action == ACTION_ACTIVE);
5359 boolean action_other = (action == ACTION_OTHER);
5361 for (j = 0; j < 8; j++)
5363 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5364 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5366 i == Xdrip_stretch ? element :
5367 i == Xdrip_stretchB ? element :
5368 i == Ydrip_s1 ? element :
5369 i == Ydrip_s1B ? element :
5370 i == Xball_1B ? element :
5371 i == Xball_2 ? element :
5372 i == Xball_2B ? element :
5373 i == Yball_eat ? element :
5374 i == Ykey_1_eat ? element :
5375 i == Ykey_2_eat ? element :
5376 i == Ykey_3_eat ? element :
5377 i == Ykey_4_eat ? element :
5378 i == Ykey_5_eat ? element :
5379 i == Ykey_6_eat ? element :
5380 i == Ykey_7_eat ? element :
5381 i == Ykey_8_eat ? element :
5382 i == Ylenses_eat ? element :
5383 i == Ymagnify_eat ? element :
5384 i == Ygrass_eat ? element :
5385 i == Ydirt_eat ? element :
5386 i == Yemerald_stone ? EL_EMERALD :
5387 i == Ydiamond_stone ? EL_ROCK :
5388 i == Xsand_stonein_1 ? element :
5389 i == Xsand_stonein_2 ? element :
5390 i == Xsand_stonein_3 ? element :
5391 i == Xsand_stonein_4 ? element :
5392 is_backside ? EL_EMPTY :
5393 action_removing ? EL_EMPTY :
5395 int effective_action = (j < 7 ? action :
5396 i == Xdrip_stretch ? action :
5397 i == Xdrip_stretchB ? action :
5398 i == Ydrip_s1 ? action :
5399 i == Ydrip_s1B ? action :
5400 i == Xball_1B ? action :
5401 i == Xball_2 ? action :
5402 i == Xball_2B ? action :
5403 i == Yball_eat ? action :
5404 i == Ykey_1_eat ? action :
5405 i == Ykey_2_eat ? action :
5406 i == Ykey_3_eat ? action :
5407 i == Ykey_4_eat ? action :
5408 i == Ykey_5_eat ? action :
5409 i == Ykey_6_eat ? action :
5410 i == Ykey_7_eat ? action :
5411 i == Ykey_8_eat ? action :
5412 i == Ylenses_eat ? action :
5413 i == Ymagnify_eat ? action :
5414 i == Ygrass_eat ? action :
5415 i == Ydirt_eat ? action :
5416 i == Xsand_stonein_1 ? action :
5417 i == Xsand_stonein_2 ? action :
5418 i == Xsand_stonein_3 ? action :
5419 i == Xsand_stonein_4 ? action :
5420 i == Xsand_stoneout_1 ? action :
5421 i == Xsand_stoneout_2 ? action :
5422 i == Xboom_android ? ACTION_EXPLODING :
5423 action_exploding ? ACTION_EXPLODING :
5424 action_active ? action :
5425 action_other ? action :
5427 int graphic = (el_act_dir2img(effective_element, effective_action,
5429 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5431 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5432 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5433 boolean has_action_graphics = (graphic != base_graphic);
5434 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5435 struct GraphicInfo *g = &graphic_info[graphic];
5436 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5439 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5440 boolean special_animation = (action != ACTION_DEFAULT &&
5441 g->anim_frames == 3 &&
5442 g->anim_delay == 2 &&
5443 g->anim_mode & ANIM_LINEAR);
5444 int sync_frame = (i == Xdrip_stretch ? 7 :
5445 i == Xdrip_stretchB ? 7 :
5446 i == Ydrip_s2 ? j + 8 :
5447 i == Ydrip_s2B ? j + 8 :
5456 i == Xfake_acid_1 ? 0 :
5457 i == Xfake_acid_2 ? 10 :
5458 i == Xfake_acid_3 ? 20 :
5459 i == Xfake_acid_4 ? 30 :
5460 i == Xfake_acid_5 ? 40 :
5461 i == Xfake_acid_6 ? 50 :
5462 i == Xfake_acid_7 ? 60 :
5463 i == Xfake_acid_8 ? 70 :
5465 i == Xball_2B ? j + 8 :
5466 i == Yball_eat ? j + 1 :
5467 i == Ykey_1_eat ? j + 1 :
5468 i == Ykey_2_eat ? j + 1 :
5469 i == Ykey_3_eat ? j + 1 :
5470 i == Ykey_4_eat ? j + 1 :
5471 i == Ykey_5_eat ? j + 1 :
5472 i == Ykey_6_eat ? j + 1 :
5473 i == Ykey_7_eat ? j + 1 :
5474 i == Ykey_8_eat ? j + 1 :
5475 i == Ylenses_eat ? j + 1 :
5476 i == Ymagnify_eat ? j + 1 :
5477 i == Ygrass_eat ? j + 1 :
5478 i == Ydirt_eat ? j + 1 :
5479 i == Xamoeba_1 ? 0 :
5480 i == Xamoeba_2 ? 1 :
5481 i == Xamoeba_3 ? 2 :
5482 i == Xamoeba_4 ? 3 :
5483 i == Xamoeba_5 ? 0 :
5484 i == Xamoeba_6 ? 1 :
5485 i == Xamoeba_7 ? 2 :
5486 i == Xamoeba_8 ? 3 :
5487 i == Xexit_2 ? j + 8 :
5488 i == Xexit_3 ? j + 16 :
5489 i == Xdynamite_1 ? 0 :
5490 i == Xdynamite_2 ? 8 :
5491 i == Xdynamite_3 ? 16 :
5492 i == Xdynamite_4 ? 24 :
5493 i == Xsand_stonein_1 ? j + 1 :
5494 i == Xsand_stonein_2 ? j + 9 :
5495 i == Xsand_stonein_3 ? j + 17 :
5496 i == Xsand_stonein_4 ? j + 25 :
5497 i == Xsand_stoneout_1 && j == 0 ? 0 :
5498 i == Xsand_stoneout_1 && j == 1 ? 0 :
5499 i == Xsand_stoneout_1 && j == 2 ? 1 :
5500 i == Xsand_stoneout_1 && j == 3 ? 2 :
5501 i == Xsand_stoneout_1 && j == 4 ? 2 :
5502 i == Xsand_stoneout_1 && j == 5 ? 3 :
5503 i == Xsand_stoneout_1 && j == 6 ? 4 :
5504 i == Xsand_stoneout_1 && j == 7 ? 4 :
5505 i == Xsand_stoneout_2 && j == 0 ? 5 :
5506 i == Xsand_stoneout_2 && j == 1 ? 6 :
5507 i == Xsand_stoneout_2 && j == 2 ? 7 :
5508 i == Xsand_stoneout_2 && j == 3 ? 8 :
5509 i == Xsand_stoneout_2 && j == 4 ? 9 :
5510 i == Xsand_stoneout_2 && j == 5 ? 11 :
5511 i == Xsand_stoneout_2 && j == 6 ? 13 :
5512 i == Xsand_stoneout_2 && j == 7 ? 15 :
5513 i == Xboom_bug && j == 1 ? 2 :
5514 i == Xboom_bug && j == 2 ? 2 :
5515 i == Xboom_bug && j == 3 ? 4 :
5516 i == Xboom_bug && j == 4 ? 4 :
5517 i == Xboom_bug && j == 5 ? 2 :
5518 i == Xboom_bug && j == 6 ? 2 :
5519 i == Xboom_bug && j == 7 ? 0 :
5520 i == Xboom_bomb && j == 1 ? 2 :
5521 i == Xboom_bomb && j == 2 ? 2 :
5522 i == Xboom_bomb && j == 3 ? 4 :
5523 i == Xboom_bomb && j == 4 ? 4 :
5524 i == Xboom_bomb && j == 5 ? 2 :
5525 i == Xboom_bomb && j == 6 ? 2 :
5526 i == Xboom_bomb && j == 7 ? 0 :
5527 i == Xboom_android && j == 7 ? 6 :
5528 i == Xboom_1 && j == 1 ? 2 :
5529 i == Xboom_1 && j == 2 ? 2 :
5530 i == Xboom_1 && j == 3 ? 4 :
5531 i == Xboom_1 && j == 4 ? 4 :
5532 i == Xboom_1 && j == 5 ? 6 :
5533 i == Xboom_1 && j == 6 ? 6 :
5534 i == Xboom_1 && j == 7 ? 8 :
5535 i == Xboom_2 && j == 0 ? 8 :
5536 i == Xboom_2 && j == 1 ? 8 :
5537 i == Xboom_2 && j == 2 ? 10 :
5538 i == Xboom_2 && j == 3 ? 10 :
5539 i == Xboom_2 && j == 4 ? 10 :
5540 i == Xboom_2 && j == 5 ? 12 :
5541 i == Xboom_2 && j == 6 ? 12 :
5542 i == Xboom_2 && j == 7 ? 12 :
5543 special_animation && j == 4 ? 3 :
5544 effective_action != action ? 0 :
5548 Bitmap *debug_bitmap = g_em->bitmap;
5549 int debug_src_x = g_em->src_x;
5550 int debug_src_y = g_em->src_y;
5553 int frame = getAnimationFrame(g->anim_frames,
5556 g->anim_start_frame,
5559 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5560 g->double_movement && is_backside);
5562 g_em->bitmap = src_bitmap;
5563 g_em->src_x = src_x;
5564 g_em->src_y = src_y;
5565 g_em->src_offset_x = 0;
5566 g_em->src_offset_y = 0;
5567 g_em->dst_offset_x = 0;
5568 g_em->dst_offset_y = 0;
5569 g_em->width = TILEX;
5570 g_em->height = TILEY;
5572 g_em->crumbled_bitmap = NULL;
5573 g_em->crumbled_src_x = 0;
5574 g_em->crumbled_src_y = 0;
5575 g_em->crumbled_border_size = 0;
5577 g_em->has_crumbled_graphics = FALSE;
5578 g_em->preserve_background = FALSE;
5581 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5582 printf("::: empty crumbled: %d [%s], %d, %d\n",
5583 effective_element, element_info[effective_element].token_name,
5584 effective_action, direction);
5587 /* if element can be crumbled, but certain action graphics are just empty
5588 space (like snapping sand with the original R'n'D graphics), do not
5589 treat these empty space graphics as crumbled graphics in EMC engine */
5590 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5592 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5594 g_em->has_crumbled_graphics = TRUE;
5595 g_em->crumbled_bitmap = src_bitmap;
5596 g_em->crumbled_src_x = src_x;
5597 g_em->crumbled_src_y = src_y;
5598 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5602 if (element == EL_ROCK &&
5603 effective_action == ACTION_FILLING)
5604 printf("::: has_action_graphics == %d\n", has_action_graphics);
5607 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5608 effective_action == ACTION_MOVING ||
5609 effective_action == ACTION_PUSHING ||
5610 effective_action == ACTION_EATING)) ||
5611 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5612 effective_action == ACTION_EMPTYING)))
5615 (effective_action == ACTION_FALLING ||
5616 effective_action == ACTION_FILLING ||
5617 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5618 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5619 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5620 int num_steps = (i == Ydrip_s1 ? 16 :
5621 i == Ydrip_s1B ? 16 :
5622 i == Ydrip_s2 ? 16 :
5623 i == Ydrip_s2B ? 16 :
5624 i == Xsand_stonein_1 ? 32 :
5625 i == Xsand_stonein_2 ? 32 :
5626 i == Xsand_stonein_3 ? 32 :
5627 i == Xsand_stonein_4 ? 32 :
5628 i == Xsand_stoneout_1 ? 16 :
5629 i == Xsand_stoneout_2 ? 16 : 8);
5630 int cx = ABS(dx) * (TILEX / num_steps);
5631 int cy = ABS(dy) * (TILEY / num_steps);
5632 int step_frame = (i == Ydrip_s2 ? j + 8 :
5633 i == Ydrip_s2B ? j + 8 :
5634 i == Xsand_stonein_2 ? j + 8 :
5635 i == Xsand_stonein_3 ? j + 16 :
5636 i == Xsand_stonein_4 ? j + 24 :
5637 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5638 int step = (is_backside ? step_frame : num_steps - step_frame);
5640 if (is_backside) /* tile where movement starts */
5642 if (dx < 0 || dy < 0)
5644 g_em->src_offset_x = cx * step;
5645 g_em->src_offset_y = cy * step;
5649 g_em->dst_offset_x = cx * step;
5650 g_em->dst_offset_y = cy * step;
5653 else /* tile where movement ends */
5655 if (dx < 0 || dy < 0)
5657 g_em->dst_offset_x = cx * step;
5658 g_em->dst_offset_y = cy * step;
5662 g_em->src_offset_x = cx * step;
5663 g_em->src_offset_y = cy * step;
5667 g_em->width = TILEX - cx * step;
5668 g_em->height = TILEY - cy * step;
5672 /* create unique graphic identifier to decide if tile must be redrawn */
5673 /* bit 31 - 16 (16 bit): EM style graphic
5674 bit 15 - 12 ( 4 bit): EM style frame
5675 bit 11 - 6 ( 6 bit): graphic width
5676 bit 5 - 0 ( 6 bit): graphic height */
5677 g_em->unique_identifier =
5678 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5680 /* create unique graphic identifier to decide if tile must be redrawn */
5681 /* bit 31 - 16 (16 bit): EM style element
5682 bit 15 - 12 ( 4 bit): EM style frame
5683 bit 11 - 6 ( 6 bit): graphic width
5684 bit 5 - 0 ( 6 bit): graphic height */
5685 g_em->unique_identifier =
5686 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5690 if (effective_element == EL_ROCK)
5691 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5692 effective_action, j, graphic, frame, g_em->unique_identifier);
5698 /* skip check for EMC elements not contained in original EMC artwork */
5699 if (element == EL_EMC_FAKE_ACID)
5703 if (g_em->bitmap != debug_bitmap ||
5704 g_em->src_x != debug_src_x ||
5705 g_em->src_y != debug_src_y ||
5706 g_em->src_offset_x != 0 ||
5707 g_em->src_offset_y != 0 ||
5708 g_em->dst_offset_x != 0 ||
5709 g_em->dst_offset_y != 0 ||
5710 g_em->width != TILEX ||
5711 g_em->height != TILEY)
5713 static int last_i = -1;
5721 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5722 i, element, element_info[element].token_name,
5723 element_action_info[effective_action].suffix, direction);
5725 if (element != effective_element)
5726 printf(" [%d ('%s')]",
5728 element_info[effective_element].token_name);
5732 if (g_em->bitmap != debug_bitmap)
5733 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5734 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5736 if (g_em->src_x != debug_src_x ||
5737 g_em->src_y != debug_src_y)
5738 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5739 j, (is_backside ? 'B' : 'F'),
5740 g_em->src_x, g_em->src_y,
5741 g_em->src_x / 32, g_em->src_y / 32,
5742 debug_src_x, debug_src_y,
5743 debug_src_x / 32, debug_src_y / 32);
5745 if (g_em->src_offset_x != 0 ||
5746 g_em->src_offset_y != 0 ||
5747 g_em->dst_offset_x != 0 ||
5748 g_em->dst_offset_y != 0)
5749 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5751 g_em->src_offset_x, g_em->src_offset_y,
5752 g_em->dst_offset_x, g_em->dst_offset_y);
5754 if (g_em->width != TILEX ||
5755 g_em->height != TILEY)
5756 printf(" %d (%d): size %d,%d should be %d,%d\n",
5758 g_em->width, g_em->height, TILEX, TILEY);
5760 num_em_gfx_errors++;
5767 for (i = 0; i < TILE_MAX; i++)
5769 for (j = 0; j < 8; j++)
5771 int element = object_mapping[i].element_rnd;
5772 int action = object_mapping[i].action;
5773 int direction = object_mapping[i].direction;
5774 boolean is_backside = object_mapping[i].is_backside;
5776 int graphic_action = el_act_dir2img(element, action, direction);
5777 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5779 int graphic_action = element_info[element].graphic[action];
5780 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5783 if ((action == ACTION_SMASHED_BY_ROCK ||
5784 action == ACTION_SMASHED_BY_SPRING ||
5785 action == ACTION_EATING) &&
5786 graphic_action == graphic_default)
5788 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5789 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5790 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5791 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5794 /* no separate animation for "smashed by rock" -- use rock instead */
5795 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5796 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5798 g_em->bitmap = g_xx->bitmap;
5799 g_em->src_x = g_xx->src_x;
5800 g_em->src_y = g_xx->src_y;
5801 g_em->src_offset_x = g_xx->src_offset_x;
5802 g_em->src_offset_y = g_xx->src_offset_y;
5803 g_em->dst_offset_x = g_xx->dst_offset_x;
5804 g_em->dst_offset_y = g_xx->dst_offset_y;
5805 g_em->width = g_xx->width;
5806 g_em->height = g_xx->height;
5808 g_em->unique_identifier = g_xx->unique_identifier;
5812 g_em->preserve_background = TRUE;
5817 for (p = 0; p < MAX_PLAYERS; p++)
5819 for (i = 0; i < SPR_MAX; i++)
5821 int element = player_mapping[p][i].element_rnd;
5822 int action = player_mapping[p][i].action;
5823 int direction = player_mapping[p][i].direction;
5825 for (j = 0; j < 8; j++)
5827 int effective_element = element;
5828 int effective_action = action;
5829 int graphic = (direction == MV_NONE ?
5830 el_act2img(effective_element, effective_action) :
5831 el_act_dir2img(effective_element, effective_action,
5833 struct GraphicInfo *g = &graphic_info[graphic];
5834 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5840 Bitmap *debug_bitmap = g_em->bitmap;
5841 int debug_src_x = g_em->src_x;
5842 int debug_src_y = g_em->src_y;
5845 int frame = getAnimationFrame(g->anim_frames,
5848 g->anim_start_frame,
5851 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5853 g_em->bitmap = src_bitmap;
5854 g_em->src_x = src_x;
5855 g_em->src_y = src_y;
5856 g_em->src_offset_x = 0;
5857 g_em->src_offset_y = 0;
5858 g_em->dst_offset_x = 0;
5859 g_em->dst_offset_y = 0;
5860 g_em->width = TILEX;
5861 g_em->height = TILEY;
5866 /* skip check for EMC elements not contained in original EMC artwork */
5867 if (element == EL_PLAYER_3 ||
5868 element == EL_PLAYER_4)
5872 if (g_em->bitmap != debug_bitmap ||
5873 g_em->src_x != debug_src_x ||
5874 g_em->src_y != debug_src_y)
5876 static int last_i = -1;
5884 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5885 p, i, element, element_info[element].token_name,
5886 element_action_info[effective_action].suffix, direction);
5888 if (element != effective_element)
5889 printf(" [%d ('%s')]",
5891 element_info[effective_element].token_name);
5895 if (g_em->bitmap != debug_bitmap)
5896 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5897 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5899 if (g_em->src_x != debug_src_x ||
5900 g_em->src_y != debug_src_y)
5901 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5903 g_em->src_x, g_em->src_y,
5904 g_em->src_x / 32, g_em->src_y / 32,
5905 debug_src_x, debug_src_y,
5906 debug_src_x / 32, debug_src_y / 32);
5908 num_em_gfx_errors++;
5918 printf("::: [%d errors found]\n", num_em_gfx_errors);
5924 void PlayMenuSound()
5926 int sound = menu.sound[game_status];
5928 if (sound == SND_UNDEFINED)
5931 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5932 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5935 if (IS_LOOP_SOUND(sound))
5936 PlaySoundLoop(sound);
5941 void PlayMenuSoundStereo(int sound, int stereo_position)
5943 if (sound == SND_UNDEFINED)
5946 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5947 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5950 if (IS_LOOP_SOUND(sound))
5951 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
5953 PlaySoundStereo(sound, stereo_position);
5956 void PlayMenuSoundIfLoop()
5958 int sound = menu.sound[game_status];
5960 if (sound == SND_UNDEFINED)
5963 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5964 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5967 if (IS_LOOP_SOUND(sound))
5968 PlaySoundLoop(sound);
5971 void PlayMenuMusic()
5973 int music = menu.music[game_status];
5975 if (music == MUS_UNDEFINED)