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_xsize[envelope_nr];
1402 int max_ysize = level.envelope_ysize[envelope_nr];
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_text[envelope_nr], 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 &&
2619 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
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)
2737 int a = MIN(x * door_2.step_offset, door_size_2);
2738 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2739 int i = p + door_skip;
2741 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2743 BlitBitmap(bitmap_db_door, drawto,
2744 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2745 VXSIZE, VYSIZE, VX, VY);
2747 else if (x <= VYSIZE)
2749 BlitBitmap(bitmap_db_door, drawto,
2750 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2751 VXSIZE, VYSIZE - p / 2, VX, VY);
2753 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2756 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2758 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2759 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2760 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2761 int dst2_x = VX, dst2_y = VY;
2762 int width = i, height = VYSIZE;
2764 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2765 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2768 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2769 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2772 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2774 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2775 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2776 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2777 int dst2_x = VX, dst2_y = VY;
2778 int width = VXSIZE, height = i;
2780 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2781 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2784 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2785 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2788 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2790 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2792 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2793 BlitBitmapMasked(bitmap, drawto,
2794 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2795 VX + VXSIZE - i, VY + j);
2796 SetClipOrigin(bitmap, gc,
2797 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2798 BlitBitmapMasked(bitmap, drawto,
2799 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2802 BlitBitmapMasked(bitmap, drawto,
2803 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2804 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2805 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2806 BlitBitmapMasked(bitmap, drawto,
2807 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2809 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2812 redraw_mask |= REDRAW_DOOR_2;
2813 door_2_done = (a == VXSIZE);
2816 if (!(door_state & DOOR_NO_DELAY))
2820 if (game_status == GAME_MODE_MAIN)
2823 WaitUntilDelayReached(&door_delay, door_delay_value);
2828 if (door_state & DOOR_ACTION_1)
2829 door1 = door_state & DOOR_ACTION_1;
2830 if (door_state & DOOR_ACTION_2)
2831 door2 = door_state & DOOR_ACTION_2;
2833 return (door1 | door2);
2836 void DrawSpecialEditorDoor()
2838 /* draw bigger toolbox window */
2839 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2840 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2842 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2843 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2846 redraw_mask |= REDRAW_ALL;
2849 void UndrawSpecialEditorDoor()
2851 /* draw normal tape recorder window */
2852 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2853 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2856 redraw_mask |= REDRAW_ALL;
2860 /* ---------- new tool button stuff ---------------------------------------- */
2862 /* graphic position values for tool buttons */
2863 #define TOOL_BUTTON_YES_XPOS 2
2864 #define TOOL_BUTTON_YES_YPOS 250
2865 #define TOOL_BUTTON_YES_GFX_YPOS 0
2866 #define TOOL_BUTTON_YES_XSIZE 46
2867 #define TOOL_BUTTON_YES_YSIZE 28
2868 #define TOOL_BUTTON_NO_XPOS 52
2869 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2870 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2871 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2872 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2873 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2874 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2875 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2876 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2877 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2878 #define TOOL_BUTTON_PLAYER_XSIZE 30
2879 #define TOOL_BUTTON_PLAYER_YSIZE 30
2880 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2881 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2882 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2883 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2884 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2885 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2886 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2887 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2888 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2889 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2890 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2891 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2892 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2893 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2894 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2895 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2896 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2897 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2898 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2899 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2908 } toolbutton_info[NUM_TOOL_BUTTONS] =
2911 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2912 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2913 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2918 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2919 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2920 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2925 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2926 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2927 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2928 TOOL_CTRL_ID_CONFIRM,
2932 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2933 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2934 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2935 TOOL_CTRL_ID_PLAYER_1,
2939 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2940 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2941 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2942 TOOL_CTRL_ID_PLAYER_2,
2946 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2947 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2948 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2949 TOOL_CTRL_ID_PLAYER_3,
2953 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2954 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2955 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2956 TOOL_CTRL_ID_PLAYER_4,
2961 void CreateToolButtons()
2965 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2967 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2968 Bitmap *deco_bitmap = None;
2969 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2970 struct GadgetInfo *gi;
2971 unsigned long event_mask;
2972 int gd_xoffset, gd_yoffset;
2973 int gd_x1, gd_x2, gd_y;
2976 event_mask = GD_EVENT_RELEASED;
2978 gd_xoffset = toolbutton_info[i].xpos;
2979 gd_yoffset = toolbutton_info[i].ypos;
2980 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2981 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2982 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2984 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2986 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2988 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2989 &deco_bitmap, &deco_x, &deco_y);
2990 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2991 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2994 gi = CreateGadget(GDI_CUSTOM_ID, id,
2995 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2996 GDI_X, DX + toolbutton_info[i].x,
2997 GDI_Y, DY + toolbutton_info[i].y,
2998 GDI_WIDTH, toolbutton_info[i].width,
2999 GDI_HEIGHT, toolbutton_info[i].height,
3000 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3001 GDI_STATE, GD_BUTTON_UNPRESSED,
3002 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3003 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3004 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3005 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3006 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3007 GDI_DECORATION_SHIFTING, 1, 1,
3008 GDI_EVENT_MASK, event_mask,
3009 GDI_CALLBACK_ACTION, HandleToolButtons,
3013 Error(ERR_EXIT, "cannot create gadget");
3015 tool_gadget[id] = gi;
3019 void FreeToolButtons()
3023 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3024 FreeGadget(tool_gadget[i]);
3027 static void UnmapToolButtons()
3031 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3032 UnmapGadget(tool_gadget[i]);
3035 static void HandleToolButtons(struct GadgetInfo *gi)
3037 request_gadget_id = gi->custom_id;
3040 static struct Mapping_EM_to_RND_object
3043 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3044 boolean is_backside; /* backside of moving element */
3050 em_object_mapping_list[] =
3053 Xblank, TRUE, FALSE,
3057 Yacid_splash_eB, FALSE, FALSE,
3058 EL_ACID_SPLASH_RIGHT, -1, -1
3061 Yacid_splash_wB, FALSE, FALSE,
3062 EL_ACID_SPLASH_LEFT, -1, -1
3065 #ifdef EM_ENGINE_BAD_ROLL
3067 Xstone_force_e, FALSE, FALSE,
3068 EL_ROCK, -1, MV_BIT_RIGHT
3071 Xstone_force_w, FALSE, FALSE,
3072 EL_ROCK, -1, MV_BIT_LEFT
3075 Xnut_force_e, FALSE, FALSE,
3076 EL_NUT, -1, MV_BIT_RIGHT
3079 Xnut_force_w, FALSE, FALSE,
3080 EL_NUT, -1, MV_BIT_LEFT
3083 Xspring_force_e, FALSE, FALSE,
3084 EL_SPRING, -1, MV_BIT_RIGHT
3087 Xspring_force_w, FALSE, FALSE,
3088 EL_SPRING, -1, MV_BIT_LEFT
3091 Xemerald_force_e, FALSE, FALSE,
3092 EL_EMERALD, -1, MV_BIT_RIGHT
3095 Xemerald_force_w, FALSE, FALSE,
3096 EL_EMERALD, -1, MV_BIT_LEFT
3099 Xdiamond_force_e, FALSE, FALSE,
3100 EL_DIAMOND, -1, MV_BIT_RIGHT
3103 Xdiamond_force_w, FALSE, FALSE,
3104 EL_DIAMOND, -1, MV_BIT_LEFT
3107 Xbomb_force_e, FALSE, FALSE,
3108 EL_BOMB, -1, MV_BIT_RIGHT
3111 Xbomb_force_w, FALSE, FALSE,
3112 EL_BOMB, -1, MV_BIT_LEFT
3114 #endif /* EM_ENGINE_BAD_ROLL */
3117 Xstone, TRUE, FALSE,
3121 Xstone_pause, FALSE, FALSE,
3125 Xstone_fall, FALSE, FALSE,
3129 Ystone_s, FALSE, FALSE,
3130 EL_ROCK, ACTION_FALLING, -1
3133 Ystone_sB, FALSE, TRUE,
3134 EL_ROCK, ACTION_FALLING, -1
3137 Ystone_e, FALSE, FALSE,
3138 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3141 Ystone_eB, FALSE, TRUE,
3142 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3145 Ystone_w, FALSE, FALSE,
3146 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3149 Ystone_wB, FALSE, TRUE,
3150 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3157 Xnut_pause, FALSE, FALSE,
3161 Xnut_fall, FALSE, FALSE,
3165 Ynut_s, FALSE, FALSE,
3166 EL_NUT, ACTION_FALLING, -1
3169 Ynut_sB, FALSE, TRUE,
3170 EL_NUT, ACTION_FALLING, -1
3173 Ynut_e, FALSE, FALSE,
3174 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3177 Ynut_eB, FALSE, TRUE,
3178 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3181 Ynut_w, FALSE, FALSE,
3182 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3185 Ynut_wB, FALSE, TRUE,
3186 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3189 Xbug_n, TRUE, FALSE,
3193 Xbug_e, TRUE, FALSE,
3194 EL_BUG_RIGHT, -1, -1
3197 Xbug_s, TRUE, FALSE,
3201 Xbug_w, TRUE, FALSE,
3205 Xbug_gon, FALSE, FALSE,
3209 Xbug_goe, FALSE, FALSE,
3210 EL_BUG_RIGHT, -1, -1
3213 Xbug_gos, FALSE, FALSE,
3217 Xbug_gow, FALSE, FALSE,
3221 Ybug_n, FALSE, FALSE,
3222 EL_BUG, ACTION_MOVING, MV_BIT_UP
3225 Ybug_nB, FALSE, TRUE,
3226 EL_BUG, ACTION_MOVING, MV_BIT_UP
3229 Ybug_e, FALSE, FALSE,
3230 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3233 Ybug_eB, FALSE, TRUE,
3234 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3237 Ybug_s, FALSE, FALSE,
3238 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3241 Ybug_sB, FALSE, TRUE,
3242 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3245 Ybug_w, FALSE, FALSE,
3246 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3249 Ybug_wB, FALSE, TRUE,
3250 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3253 Ybug_w_n, FALSE, FALSE,
3254 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3257 Ybug_n_e, FALSE, FALSE,
3258 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3261 Ybug_e_s, FALSE, FALSE,
3262 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3265 Ybug_s_w, FALSE, FALSE,
3266 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3269 Ybug_e_n, FALSE, FALSE,
3270 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3273 Ybug_s_e, FALSE, FALSE,
3274 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3277 Ybug_w_s, FALSE, FALSE,
3278 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3281 Ybug_n_w, FALSE, FALSE,
3282 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3285 Ybug_stone, FALSE, FALSE,
3286 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3289 Ybug_spring, FALSE, FALSE,
3290 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3293 Xtank_n, TRUE, FALSE,
3294 EL_SPACESHIP_UP, -1, -1
3297 Xtank_e, TRUE, FALSE,
3298 EL_SPACESHIP_RIGHT, -1, -1
3301 Xtank_s, TRUE, FALSE,
3302 EL_SPACESHIP_DOWN, -1, -1
3305 Xtank_w, TRUE, FALSE,
3306 EL_SPACESHIP_LEFT, -1, -1
3309 Xtank_gon, FALSE, FALSE,
3310 EL_SPACESHIP_UP, -1, -1
3313 Xtank_goe, FALSE, FALSE,
3314 EL_SPACESHIP_RIGHT, -1, -1
3317 Xtank_gos, FALSE, FALSE,
3318 EL_SPACESHIP_DOWN, -1, -1
3321 Xtank_gow, FALSE, FALSE,
3322 EL_SPACESHIP_LEFT, -1, -1
3325 Ytank_n, FALSE, FALSE,
3326 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3329 Ytank_nB, FALSE, TRUE,
3330 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3333 Ytank_e, FALSE, FALSE,
3334 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3337 Ytank_eB, FALSE, TRUE,
3338 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3341 Ytank_s, FALSE, FALSE,
3342 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3345 Ytank_sB, FALSE, TRUE,
3346 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3349 Ytank_w, FALSE, FALSE,
3350 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3353 Ytank_wB, FALSE, TRUE,
3354 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3357 Ytank_w_n, FALSE, FALSE,
3358 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3361 Ytank_n_e, FALSE, FALSE,
3362 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3365 Ytank_e_s, FALSE, FALSE,
3366 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3369 Ytank_s_w, FALSE, FALSE,
3370 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3373 Ytank_e_n, FALSE, FALSE,
3374 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3377 Ytank_s_e, FALSE, FALSE,
3378 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3381 Ytank_w_s, FALSE, FALSE,
3382 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3385 Ytank_n_w, FALSE, FALSE,
3386 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3389 Ytank_stone, FALSE, FALSE,
3390 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3393 Ytank_spring, FALSE, FALSE,
3394 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3397 Xandroid, TRUE, FALSE,
3398 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3401 Xandroid_1_n, FALSE, FALSE,
3402 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3405 Xandroid_2_n, FALSE, FALSE,
3406 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3409 Xandroid_1_e, FALSE, FALSE,
3410 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3413 Xandroid_2_e, FALSE, FALSE,
3414 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3417 Xandroid_1_w, FALSE, FALSE,
3418 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3421 Xandroid_2_w, FALSE, FALSE,
3422 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3425 Xandroid_1_s, FALSE, FALSE,
3426 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3429 Xandroid_2_s, FALSE, FALSE,
3430 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3433 Yandroid_n, FALSE, FALSE,
3434 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3437 Yandroid_nB, FALSE, TRUE,
3438 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3441 Yandroid_ne, FALSE, FALSE,
3442 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3445 Yandroid_neB, FALSE, TRUE,
3446 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3449 Yandroid_e, FALSE, FALSE,
3450 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3453 Yandroid_eB, FALSE, TRUE,
3454 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3457 Yandroid_se, FALSE, FALSE,
3458 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3461 Yandroid_seB, FALSE, TRUE,
3462 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3465 Yandroid_s, FALSE, FALSE,
3466 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3469 Yandroid_sB, FALSE, TRUE,
3470 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3473 Yandroid_sw, FALSE, FALSE,
3474 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3477 Yandroid_swB, FALSE, TRUE,
3478 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3481 Yandroid_w, FALSE, FALSE,
3482 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3485 Yandroid_wB, FALSE, TRUE,
3486 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3489 Yandroid_nw, FALSE, FALSE,
3490 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3493 Yandroid_nwB, FALSE, TRUE,
3494 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3497 Xspring, TRUE, FALSE,
3501 Xspring_pause, FALSE, FALSE,
3505 Xspring_e, FALSE, FALSE,
3509 Xspring_w, FALSE, FALSE,
3513 Xspring_fall, FALSE, FALSE,
3517 Yspring_s, FALSE, FALSE,
3518 EL_SPRING, ACTION_FALLING, -1
3521 Yspring_sB, FALSE, TRUE,
3522 EL_SPRING, ACTION_FALLING, -1
3525 Yspring_e, FALSE, FALSE,
3526 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3529 Yspring_eB, FALSE, TRUE,
3530 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3533 Yspring_w, FALSE, FALSE,
3534 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3537 Yspring_wB, FALSE, TRUE,
3538 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3541 Yspring_kill_e, FALSE, FALSE,
3542 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3545 Yspring_kill_eB, FALSE, TRUE,
3546 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3549 Yspring_kill_w, FALSE, FALSE,
3550 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3553 Yspring_kill_wB, FALSE, TRUE,
3554 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3557 Xeater_n, TRUE, FALSE,
3558 EL_YAMYAM_UP, -1, -1
3561 Xeater_e, TRUE, FALSE,
3562 EL_YAMYAM_RIGHT, -1, -1
3565 Xeater_w, TRUE, FALSE,
3566 EL_YAMYAM_LEFT, -1, -1
3569 Xeater_s, TRUE, FALSE,
3570 EL_YAMYAM_DOWN, -1, -1
3573 Yeater_n, FALSE, FALSE,
3574 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3577 Yeater_nB, FALSE, TRUE,
3578 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3581 Yeater_e, FALSE, FALSE,
3582 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3585 Yeater_eB, FALSE, TRUE,
3586 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3589 Yeater_s, FALSE, FALSE,
3590 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3593 Yeater_sB, FALSE, TRUE,
3594 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3597 Yeater_w, FALSE, FALSE,
3598 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3601 Yeater_wB, FALSE, TRUE,
3602 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3605 Yeater_stone, FALSE, FALSE,
3606 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3609 Yeater_spring, FALSE, FALSE,
3610 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3613 Xalien, TRUE, FALSE,
3617 Xalien_pause, FALSE, FALSE,
3621 Yalien_n, FALSE, FALSE,
3622 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3625 Yalien_nB, FALSE, TRUE,
3626 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3629 Yalien_e, FALSE, FALSE,
3630 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3633 Yalien_eB, FALSE, TRUE,
3634 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3637 Yalien_s, FALSE, FALSE,
3638 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3641 Yalien_sB, FALSE, TRUE,
3642 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3645 Yalien_w, FALSE, FALSE,
3646 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3649 Yalien_wB, FALSE, TRUE,
3650 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3653 Yalien_stone, FALSE, FALSE,
3654 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3657 Yalien_spring, FALSE, FALSE,
3658 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3661 Xemerald, TRUE, FALSE,
3665 Xemerald_pause, FALSE, FALSE,
3669 Xemerald_fall, FALSE, FALSE,
3673 Xemerald_shine, FALSE, FALSE,
3674 EL_EMERALD, ACTION_TWINKLING, -1
3677 Yemerald_s, FALSE, FALSE,
3678 EL_EMERALD, ACTION_FALLING, -1
3681 Yemerald_sB, FALSE, TRUE,
3682 EL_EMERALD, ACTION_FALLING, -1
3685 Yemerald_e, FALSE, FALSE,
3686 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3689 Yemerald_eB, FALSE, TRUE,
3690 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3693 Yemerald_w, FALSE, FALSE,
3694 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3697 Yemerald_wB, FALSE, TRUE,
3698 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3701 Yemerald_eat, FALSE, FALSE,
3702 EL_EMERALD, ACTION_COLLECTING, -1
3705 Yemerald_stone, FALSE, FALSE,
3706 EL_NUT, ACTION_BREAKING, -1
3709 Xdiamond, TRUE, FALSE,
3713 Xdiamond_pause, FALSE, FALSE,
3717 Xdiamond_fall, FALSE, FALSE,
3721 Xdiamond_shine, FALSE, FALSE,
3722 EL_DIAMOND, ACTION_TWINKLING, -1
3725 Ydiamond_s, FALSE, FALSE,
3726 EL_DIAMOND, ACTION_FALLING, -1
3729 Ydiamond_sB, FALSE, TRUE,
3730 EL_DIAMOND, ACTION_FALLING, -1
3733 Ydiamond_e, FALSE, FALSE,
3734 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3737 Ydiamond_eB, FALSE, TRUE,
3738 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3741 Ydiamond_w, FALSE, FALSE,
3742 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3745 Ydiamond_wB, FALSE, TRUE,
3746 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3749 Ydiamond_eat, FALSE, FALSE,
3750 EL_DIAMOND, ACTION_COLLECTING, -1
3753 Ydiamond_stone, FALSE, FALSE,
3754 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3757 Xdrip_fall, TRUE, FALSE,
3758 EL_AMOEBA_DROP, -1, -1
3761 Xdrip_stretch, FALSE, FALSE,
3762 EL_AMOEBA_DROP, ACTION_FALLING, -1
3765 Xdrip_stretchB, FALSE, TRUE,
3766 EL_AMOEBA_DROP, ACTION_FALLING, -1
3769 Xdrip_eat, FALSE, FALSE,
3770 EL_AMOEBA_DROP, ACTION_GROWING, -1
3773 Ydrip_s1, FALSE, FALSE,
3774 EL_AMOEBA_DROP, ACTION_FALLING, -1
3777 Ydrip_s1B, FALSE, TRUE,
3778 EL_AMOEBA_DROP, ACTION_FALLING, -1
3781 Ydrip_s2, FALSE, FALSE,
3782 EL_AMOEBA_DROP, ACTION_FALLING, -1
3785 Ydrip_s2B, FALSE, TRUE,
3786 EL_AMOEBA_DROP, ACTION_FALLING, -1
3793 Xbomb_pause, FALSE, FALSE,
3797 Xbomb_fall, FALSE, FALSE,
3801 Ybomb_s, FALSE, FALSE,
3802 EL_BOMB, ACTION_FALLING, -1
3805 Ybomb_sB, FALSE, TRUE,
3806 EL_BOMB, ACTION_FALLING, -1
3809 Ybomb_e, FALSE, FALSE,
3810 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3813 Ybomb_eB, FALSE, TRUE,
3814 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3817 Ybomb_w, FALSE, FALSE,
3818 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3821 Ybomb_wB, FALSE, TRUE,
3822 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3825 Ybomb_eat, FALSE, FALSE,
3826 EL_BOMB, ACTION_ACTIVATING, -1
3829 Xballoon, TRUE, FALSE,
3833 Yballoon_n, FALSE, FALSE,
3834 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3837 Yballoon_nB, FALSE, TRUE,
3838 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3841 Yballoon_e, FALSE, FALSE,
3842 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3845 Yballoon_eB, FALSE, TRUE,
3846 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3849 Yballoon_s, FALSE, FALSE,
3850 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3853 Yballoon_sB, FALSE, TRUE,
3854 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3857 Yballoon_w, FALSE, FALSE,
3858 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3861 Yballoon_wB, FALSE, TRUE,
3862 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3865 Xgrass, TRUE, FALSE,
3866 EL_EMC_GRASS, -1, -1
3869 Ygrass_nB, FALSE, FALSE,
3870 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3873 Ygrass_eB, FALSE, FALSE,
3874 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3877 Ygrass_sB, FALSE, FALSE,
3878 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3881 Ygrass_wB, FALSE, FALSE,
3882 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3889 Ydirt_nB, FALSE, FALSE,
3890 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3893 Ydirt_eB, FALSE, FALSE,
3894 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3897 Ydirt_sB, FALSE, FALSE,
3898 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3901 Ydirt_wB, FALSE, FALSE,
3902 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3905 Xacid_ne, TRUE, FALSE,
3906 EL_ACID_POOL_TOPRIGHT, -1, -1
3909 Xacid_se, TRUE, FALSE,
3910 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3913 Xacid_s, TRUE, FALSE,
3914 EL_ACID_POOL_BOTTOM, -1, -1
3917 Xacid_sw, TRUE, FALSE,
3918 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3921 Xacid_nw, TRUE, FALSE,
3922 EL_ACID_POOL_TOPLEFT, -1, -1
3925 Xacid_1, TRUE, FALSE,
3929 Xacid_2, FALSE, FALSE,
3933 Xacid_3, FALSE, FALSE,
3937 Xacid_4, FALSE, FALSE,
3941 Xacid_5, FALSE, FALSE,
3945 Xacid_6, FALSE, FALSE,
3949 Xacid_7, FALSE, FALSE,
3953 Xacid_8, FALSE, FALSE,
3957 Xball_1, TRUE, FALSE,
3958 EL_EMC_MAGIC_BALL, -1, -1
3961 Xball_1B, FALSE, FALSE,
3962 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3965 Xball_2, FALSE, FALSE,
3966 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3969 Xball_2B, FALSE, FALSE,
3970 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3973 Yball_eat, FALSE, FALSE,
3974 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3977 Ykey_1_eat, FALSE, FALSE,
3978 EL_EM_KEY_1, ACTION_COLLECTING, -1
3981 Ykey_2_eat, FALSE, FALSE,
3982 EL_EM_KEY_2, ACTION_COLLECTING, -1
3985 Ykey_3_eat, FALSE, FALSE,
3986 EL_EM_KEY_3, ACTION_COLLECTING, -1
3989 Ykey_4_eat, FALSE, FALSE,
3990 EL_EM_KEY_4, ACTION_COLLECTING, -1
3993 Ykey_5_eat, FALSE, FALSE,
3994 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3997 Ykey_6_eat, FALSE, FALSE,
3998 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4001 Ykey_7_eat, FALSE, FALSE,
4002 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4005 Ykey_8_eat, FALSE, FALSE,
4006 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4009 Ylenses_eat, FALSE, FALSE,
4010 EL_EMC_LENSES, ACTION_COLLECTING, -1
4013 Ymagnify_eat, FALSE, FALSE,
4014 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4017 Ygrass_eat, FALSE, FALSE,
4018 EL_EMC_GRASS, ACTION_SNAPPING, -1
4021 Ydirt_eat, FALSE, FALSE,
4022 EL_SAND, ACTION_SNAPPING, -1
4025 Xgrow_ns, TRUE, FALSE,
4026 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4029 Ygrow_ns_eat, FALSE, FALSE,
4030 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4033 Xgrow_ew, TRUE, FALSE,
4034 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4037 Ygrow_ew_eat, FALSE, FALSE,
4038 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4041 Xwonderwall, TRUE, FALSE,
4042 EL_MAGIC_WALL, -1, -1
4045 XwonderwallB, FALSE, FALSE,
4046 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4049 Xamoeba_1, TRUE, FALSE,
4050 EL_AMOEBA_DRY, ACTION_OTHER, -1
4053 Xamoeba_2, FALSE, FALSE,
4054 EL_AMOEBA_DRY, ACTION_OTHER, -1
4057 Xamoeba_3, FALSE, FALSE,
4058 EL_AMOEBA_DRY, ACTION_OTHER, -1
4061 Xamoeba_4, FALSE, FALSE,
4062 EL_AMOEBA_DRY, ACTION_OTHER, -1
4065 Xamoeba_5, TRUE, FALSE,
4066 EL_AMOEBA_WET, ACTION_OTHER, -1
4069 Xamoeba_6, FALSE, FALSE,
4070 EL_AMOEBA_WET, ACTION_OTHER, -1
4073 Xamoeba_7, FALSE, FALSE,
4074 EL_AMOEBA_WET, ACTION_OTHER, -1
4077 Xamoeba_8, FALSE, FALSE,
4078 EL_AMOEBA_WET, ACTION_OTHER, -1
4081 Xdoor_1, TRUE, FALSE,
4082 EL_EM_GATE_1, -1, -1
4085 Xdoor_2, TRUE, FALSE,
4086 EL_EM_GATE_2, -1, -1
4089 Xdoor_3, TRUE, FALSE,
4090 EL_EM_GATE_3, -1, -1
4093 Xdoor_4, TRUE, FALSE,
4094 EL_EM_GATE_4, -1, -1
4097 Xdoor_5, TRUE, FALSE,
4098 EL_EMC_GATE_5, -1, -1
4101 Xdoor_6, TRUE, FALSE,
4102 EL_EMC_GATE_6, -1, -1
4105 Xdoor_7, TRUE, FALSE,
4106 EL_EMC_GATE_7, -1, -1
4109 Xdoor_8, TRUE, FALSE,
4110 EL_EMC_GATE_8, -1, -1
4113 Xkey_1, TRUE, FALSE,
4117 Xkey_2, TRUE, FALSE,
4121 Xkey_3, TRUE, FALSE,
4125 Xkey_4, TRUE, FALSE,
4129 Xkey_5, TRUE, FALSE,
4130 EL_EMC_KEY_5, -1, -1
4133 Xkey_6, TRUE, FALSE,
4134 EL_EMC_KEY_6, -1, -1
4137 Xkey_7, TRUE, FALSE,
4138 EL_EMC_KEY_7, -1, -1
4141 Xkey_8, TRUE, FALSE,
4142 EL_EMC_KEY_8, -1, -1
4145 Xwind_n, TRUE, FALSE,
4146 EL_BALLOON_SWITCH_UP, -1, -1
4149 Xwind_e, TRUE, FALSE,
4150 EL_BALLOON_SWITCH_RIGHT, -1, -1
4153 Xwind_s, TRUE, FALSE,
4154 EL_BALLOON_SWITCH_DOWN, -1, -1
4157 Xwind_w, TRUE, FALSE,
4158 EL_BALLOON_SWITCH_LEFT, -1, -1
4161 Xwind_nesw, TRUE, FALSE,
4162 EL_BALLOON_SWITCH_ANY, -1, -1
4165 Xwind_stop, TRUE, FALSE,
4166 EL_BALLOON_SWITCH_NONE, -1, -1
4170 EL_EXIT_CLOSED, -1, -1
4173 Xexit_1, TRUE, FALSE,
4174 EL_EXIT_OPEN, -1, -1
4177 Xexit_2, FALSE, FALSE,
4178 EL_EXIT_OPEN, -1, -1
4181 Xexit_3, FALSE, FALSE,
4182 EL_EXIT_OPEN, -1, -1
4185 Xdynamite, TRUE, FALSE,
4186 EL_EM_DYNAMITE, -1, -1
4189 Ydynamite_eat, FALSE, FALSE,
4190 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4193 Xdynamite_1, TRUE, FALSE,
4194 EL_EM_DYNAMITE_ACTIVE, -1, -1
4197 Xdynamite_2, FALSE, FALSE,
4198 EL_EM_DYNAMITE_ACTIVE, -1, -1
4201 Xdynamite_3, FALSE, FALSE,
4202 EL_EM_DYNAMITE_ACTIVE, -1, -1
4205 Xdynamite_4, FALSE, FALSE,
4206 EL_EM_DYNAMITE_ACTIVE, -1, -1
4209 Xbumper, TRUE, FALSE,
4210 EL_EMC_SPRING_BUMPER, -1, -1
4213 XbumperB, FALSE, FALSE,
4214 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4217 Xwheel, TRUE, FALSE,
4218 EL_ROBOT_WHEEL, -1, -1
4221 XwheelB, FALSE, FALSE,
4222 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4225 Xswitch, TRUE, FALSE,
4226 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4229 XswitchB, FALSE, FALSE,
4230 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4234 EL_QUICKSAND_EMPTY, -1, -1
4237 Xsand_stone, TRUE, FALSE,
4238 EL_QUICKSAND_FULL, -1, -1
4241 Xsand_stonein_1, FALSE, TRUE,
4242 EL_ROCK, ACTION_FILLING, -1
4245 Xsand_stonein_2, FALSE, TRUE,
4246 EL_ROCK, ACTION_FILLING, -1
4249 Xsand_stonein_3, FALSE, TRUE,
4250 EL_ROCK, ACTION_FILLING, -1
4253 Xsand_stonein_4, FALSE, TRUE,
4254 EL_ROCK, ACTION_FILLING, -1
4257 Xsand_stonesand_1, FALSE, FALSE,
4258 EL_QUICKSAND_FULL, -1, -1
4261 Xsand_stonesand_2, FALSE, FALSE,
4262 EL_QUICKSAND_FULL, -1, -1
4265 Xsand_stonesand_3, FALSE, FALSE,
4266 EL_QUICKSAND_FULL, -1, -1
4269 Xsand_stonesand_4, FALSE, FALSE,
4270 EL_QUICKSAND_FULL, -1, -1
4273 Xsand_stoneout_1, FALSE, FALSE,
4274 EL_ROCK, ACTION_EMPTYING, -1
4277 Xsand_stoneout_2, FALSE, FALSE,
4278 EL_ROCK, ACTION_EMPTYING, -1
4281 Xsand_sandstone_1, FALSE, FALSE,
4282 EL_QUICKSAND_FULL, -1, -1
4285 Xsand_sandstone_2, FALSE, FALSE,
4286 EL_QUICKSAND_FULL, -1, -1
4289 Xsand_sandstone_3, FALSE, FALSE,
4290 EL_QUICKSAND_FULL, -1, -1
4293 Xsand_sandstone_4, FALSE, FALSE,
4294 EL_QUICKSAND_FULL, -1, -1
4297 Xplant, TRUE, FALSE,
4298 EL_EMC_PLANT, -1, -1
4301 Yplant, FALSE, FALSE,
4302 EL_EMC_PLANT, -1, -1
4305 Xlenses, TRUE, FALSE,
4306 EL_EMC_LENSES, -1, -1
4309 Xmagnify, TRUE, FALSE,
4310 EL_EMC_MAGNIFIER, -1, -1
4313 Xdripper, TRUE, FALSE,
4314 EL_EMC_DRIPPER, -1, -1
4317 XdripperB, FALSE, FALSE,
4318 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4321 Xfake_blank, TRUE, FALSE,
4322 EL_INVISIBLE_WALL, -1, -1
4325 Xfake_blankB, FALSE, FALSE,
4326 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4329 Xfake_grass, TRUE, FALSE,
4330 EL_EMC_FAKE_GRASS, -1, -1
4333 Xfake_grassB, FALSE, FALSE,
4334 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4337 Xfake_door_1, TRUE, FALSE,
4338 EL_EM_GATE_1_GRAY, -1, -1
4341 Xfake_door_2, TRUE, FALSE,
4342 EL_EM_GATE_2_GRAY, -1, -1
4345 Xfake_door_3, TRUE, FALSE,
4346 EL_EM_GATE_3_GRAY, -1, -1
4349 Xfake_door_4, TRUE, FALSE,
4350 EL_EM_GATE_4_GRAY, -1, -1
4353 Xfake_door_5, TRUE, FALSE,
4354 EL_EMC_GATE_5_GRAY, -1, -1
4357 Xfake_door_6, TRUE, FALSE,
4358 EL_EMC_GATE_6_GRAY, -1, -1
4361 Xfake_door_7, TRUE, FALSE,
4362 EL_EMC_GATE_7_GRAY, -1, -1
4365 Xfake_door_8, TRUE, FALSE,
4366 EL_EMC_GATE_8_GRAY, -1, -1
4369 Xfake_acid_1, TRUE, FALSE,
4370 EL_EMC_FAKE_ACID, -1, -1
4373 Xfake_acid_2, FALSE, FALSE,
4374 EL_EMC_FAKE_ACID, -1, -1
4377 Xfake_acid_3, FALSE, FALSE,
4378 EL_EMC_FAKE_ACID, -1, -1
4381 Xfake_acid_4, FALSE, FALSE,
4382 EL_EMC_FAKE_ACID, -1, -1
4385 Xfake_acid_5, FALSE, FALSE,
4386 EL_EMC_FAKE_ACID, -1, -1
4389 Xfake_acid_6, FALSE, FALSE,
4390 EL_EMC_FAKE_ACID, -1, -1
4393 Xfake_acid_7, FALSE, FALSE,
4394 EL_EMC_FAKE_ACID, -1, -1
4397 Xfake_acid_8, FALSE, FALSE,
4398 EL_EMC_FAKE_ACID, -1, -1
4401 Xsteel_1, TRUE, FALSE,
4402 EL_STEELWALL, -1, -1
4405 Xsteel_2, TRUE, FALSE,
4406 EL_EMC_STEELWALL_2, -1, -1
4409 Xsteel_3, TRUE, FALSE,
4410 EL_EMC_STEELWALL_3, -1, -1
4413 Xsteel_4, TRUE, FALSE,
4414 EL_EMC_STEELWALL_4, -1, -1
4417 Xwall_1, TRUE, FALSE,
4421 Xwall_2, TRUE, FALSE,
4422 EL_EMC_WALL_14, -1, -1
4425 Xwall_3, TRUE, FALSE,
4426 EL_EMC_WALL_15, -1, -1
4429 Xwall_4, TRUE, FALSE,
4430 EL_EMC_WALL_16, -1, -1
4433 Xround_wall_1, TRUE, FALSE,
4434 EL_WALL_SLIPPERY, -1, -1
4437 Xround_wall_2, TRUE, FALSE,
4438 EL_EMC_WALL_SLIPPERY_2, -1, -1
4441 Xround_wall_3, TRUE, FALSE,
4442 EL_EMC_WALL_SLIPPERY_3, -1, -1
4445 Xround_wall_4, TRUE, FALSE,
4446 EL_EMC_WALL_SLIPPERY_4, -1, -1
4449 Xdecor_1, TRUE, FALSE,
4450 EL_EMC_WALL_8, -1, -1
4453 Xdecor_2, TRUE, FALSE,
4454 EL_EMC_WALL_6, -1, -1
4457 Xdecor_3, TRUE, FALSE,
4458 EL_EMC_WALL_4, -1, -1
4461 Xdecor_4, TRUE, FALSE,
4462 EL_EMC_WALL_7, -1, -1
4465 Xdecor_5, TRUE, FALSE,
4466 EL_EMC_WALL_5, -1, -1
4469 Xdecor_6, TRUE, FALSE,
4470 EL_EMC_WALL_9, -1, -1
4473 Xdecor_7, TRUE, FALSE,
4474 EL_EMC_WALL_10, -1, -1
4477 Xdecor_8, TRUE, FALSE,
4478 EL_EMC_WALL_1, -1, -1
4481 Xdecor_9, TRUE, FALSE,
4482 EL_EMC_WALL_2, -1, -1
4485 Xdecor_10, TRUE, FALSE,
4486 EL_EMC_WALL_3, -1, -1
4489 Xdecor_11, TRUE, FALSE,
4490 EL_EMC_WALL_11, -1, -1
4493 Xdecor_12, TRUE, FALSE,
4494 EL_EMC_WALL_12, -1, -1
4497 Xalpha_0, TRUE, FALSE,
4498 EL_CHAR('0'), -1, -1
4501 Xalpha_1, TRUE, FALSE,
4502 EL_CHAR('1'), -1, -1
4505 Xalpha_2, TRUE, FALSE,
4506 EL_CHAR('2'), -1, -1
4509 Xalpha_3, TRUE, FALSE,
4510 EL_CHAR('3'), -1, -1
4513 Xalpha_4, TRUE, FALSE,
4514 EL_CHAR('4'), -1, -1
4517 Xalpha_5, TRUE, FALSE,
4518 EL_CHAR('5'), -1, -1
4521 Xalpha_6, TRUE, FALSE,
4522 EL_CHAR('6'), -1, -1
4525 Xalpha_7, TRUE, FALSE,
4526 EL_CHAR('7'), -1, -1
4529 Xalpha_8, TRUE, FALSE,
4530 EL_CHAR('8'), -1, -1
4533 Xalpha_9, TRUE, FALSE,
4534 EL_CHAR('9'), -1, -1
4537 Xalpha_excla, TRUE, FALSE,
4538 EL_CHAR('!'), -1, -1
4541 Xalpha_quote, TRUE, FALSE,
4542 EL_CHAR('"'), -1, -1
4545 Xalpha_comma, TRUE, FALSE,
4546 EL_CHAR(','), -1, -1
4549 Xalpha_minus, TRUE, FALSE,
4550 EL_CHAR('-'), -1, -1
4553 Xalpha_perio, TRUE, FALSE,
4554 EL_CHAR('.'), -1, -1
4557 Xalpha_colon, TRUE, FALSE,
4558 EL_CHAR(':'), -1, -1
4561 Xalpha_quest, TRUE, FALSE,
4562 EL_CHAR('?'), -1, -1
4565 Xalpha_a, TRUE, FALSE,
4566 EL_CHAR('A'), -1, -1
4569 Xalpha_b, TRUE, FALSE,
4570 EL_CHAR('B'), -1, -1
4573 Xalpha_c, TRUE, FALSE,
4574 EL_CHAR('C'), -1, -1
4577 Xalpha_d, TRUE, FALSE,
4578 EL_CHAR('D'), -1, -1
4581 Xalpha_e, TRUE, FALSE,
4582 EL_CHAR('E'), -1, -1
4585 Xalpha_f, TRUE, FALSE,
4586 EL_CHAR('F'), -1, -1
4589 Xalpha_g, TRUE, FALSE,
4590 EL_CHAR('G'), -1, -1
4593 Xalpha_h, TRUE, FALSE,
4594 EL_CHAR('H'), -1, -1
4597 Xalpha_i, TRUE, FALSE,
4598 EL_CHAR('I'), -1, -1
4601 Xalpha_j, TRUE, FALSE,
4602 EL_CHAR('J'), -1, -1
4605 Xalpha_k, TRUE, FALSE,
4606 EL_CHAR('K'), -1, -1
4609 Xalpha_l, TRUE, FALSE,
4610 EL_CHAR('L'), -1, -1
4613 Xalpha_m, TRUE, FALSE,
4614 EL_CHAR('M'), -1, -1
4617 Xalpha_n, TRUE, FALSE,
4618 EL_CHAR('N'), -1, -1
4621 Xalpha_o, TRUE, FALSE,
4622 EL_CHAR('O'), -1, -1
4625 Xalpha_p, TRUE, FALSE,
4626 EL_CHAR('P'), -1, -1
4629 Xalpha_q, TRUE, FALSE,
4630 EL_CHAR('Q'), -1, -1
4633 Xalpha_r, TRUE, FALSE,
4634 EL_CHAR('R'), -1, -1
4637 Xalpha_s, TRUE, FALSE,
4638 EL_CHAR('S'), -1, -1
4641 Xalpha_t, TRUE, FALSE,
4642 EL_CHAR('T'), -1, -1
4645 Xalpha_u, TRUE, FALSE,
4646 EL_CHAR('U'), -1, -1
4649 Xalpha_v, TRUE, FALSE,
4650 EL_CHAR('V'), -1, -1
4653 Xalpha_w, TRUE, FALSE,
4654 EL_CHAR('W'), -1, -1
4657 Xalpha_x, TRUE, FALSE,
4658 EL_CHAR('X'), -1, -1
4661 Xalpha_y, TRUE, FALSE,
4662 EL_CHAR('Y'), -1, -1
4665 Xalpha_z, TRUE, FALSE,
4666 EL_CHAR('Z'), -1, -1
4669 Xalpha_arrow_e, TRUE, FALSE,
4670 EL_CHAR('>'), -1, -1
4673 Xalpha_arrow_w, TRUE, FALSE,
4674 EL_CHAR('<'), -1, -1
4677 Xalpha_copyr, TRUE, FALSE,
4678 EL_CHAR('©'), -1, -1
4682 Xboom_bug, FALSE, FALSE,
4683 EL_BUG, ACTION_EXPLODING, -1
4686 Xboom_bomb, FALSE, FALSE,
4687 EL_BOMB, ACTION_EXPLODING, -1
4690 Xboom_android, FALSE, FALSE,
4691 EL_EMC_ANDROID, ACTION_OTHER, -1
4694 Xboom_1, FALSE, FALSE,
4695 EL_DEFAULT, ACTION_EXPLODING, -1
4698 Xboom_2, FALSE, FALSE,
4699 EL_DEFAULT, ACTION_EXPLODING, -1
4702 Znormal, FALSE, FALSE,
4706 Zdynamite, FALSE, FALSE,
4710 Zplayer, FALSE, FALSE,
4714 ZBORDER, FALSE, FALSE,
4724 static struct Mapping_EM_to_RND_player
4733 em_player_mapping_list[] =
4737 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4741 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4745 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4749 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4753 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4757 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4761 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4765 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4769 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4773 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4777 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4781 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4785 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4789 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4793 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4797 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4801 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4805 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4809 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4813 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4817 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4821 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4825 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4829 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4833 EL_PLAYER_1, ACTION_DEFAULT, -1,
4837 EL_PLAYER_2, ACTION_DEFAULT, -1,
4841 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4845 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4849 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4853 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4857 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4861 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4865 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4869 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4873 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4877 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4881 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4885 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4889 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4893 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4897 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4901 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4905 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4909 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4913 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4917 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4921 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4925 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4929 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4933 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4937 EL_PLAYER_3, ACTION_DEFAULT, -1,
4941 EL_PLAYER_4, ACTION_DEFAULT, -1,
4950 int map_element_RND_to_EM(int element_rnd)
4952 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4953 static boolean mapping_initialized = FALSE;
4955 if (!mapping_initialized)
4959 /* return "Xalpha_quest" for all undefined elements in mapping array */
4960 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4961 mapping_RND_to_EM[i] = Xalpha_quest;
4963 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4964 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4965 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4966 em_object_mapping_list[i].element_em;
4968 mapping_initialized = TRUE;
4971 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4972 return mapping_RND_to_EM[element_rnd];
4974 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4979 int map_element_EM_to_RND(int element_em)
4981 static unsigned short mapping_EM_to_RND[TILE_MAX];
4982 static boolean mapping_initialized = FALSE;
4984 if (!mapping_initialized)
4988 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4989 for (i = 0; i < TILE_MAX; i++)
4990 mapping_EM_to_RND[i] = EL_UNKNOWN;
4992 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4993 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4994 em_object_mapping_list[i].element_rnd;
4996 mapping_initialized = TRUE;
4999 if (element_em >= 0 && element_em < TILE_MAX)
5000 return mapping_EM_to_RND[element_em];
5002 Error(ERR_WARN, "invalid EM level element %d", element_em);
5007 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5009 struct LevelInfo_EM *level_em = level->native_em_level;
5010 struct LEVEL *lev = level_em->lev;
5013 for (i = 0; i < TILE_MAX; i++)
5014 lev->android_array[i] = Xblank;
5016 for (i = 0; i < level->num_android_clone_elements; i++)
5018 int element_rnd = level->android_clone_element[i];
5019 int element_em = map_element_RND_to_EM(element_rnd);
5021 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5022 if (em_object_mapping_list[j].element_rnd == element_rnd)
5023 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5027 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5029 struct LevelInfo_EM *level_em = level->native_em_level;
5030 struct LEVEL *lev = level_em->lev;
5033 level->num_android_clone_elements = 0;
5035 for (i = 0; i < TILE_MAX; i++)
5037 int element_em = lev->android_array[i];
5039 boolean element_found = FALSE;
5041 if (element_em == Xblank)
5044 element_rnd = map_element_EM_to_RND(element_em);
5046 for (j = 0; j < level->num_android_clone_elements; j++)
5047 if (level->android_clone_element[j] == element_rnd)
5048 element_found = TRUE;
5052 level->android_clone_element[level->num_android_clone_elements++] =
5055 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5060 if (level->num_android_clone_elements == 0)
5062 level->num_android_clone_elements = 1;
5063 level->android_clone_element[0] = EL_EMPTY;
5067 int map_direction_RND_to_EM(int direction)
5069 return (direction == MV_UP ? 0 :
5070 direction == MV_RIGHT ? 1 :
5071 direction == MV_DOWN ? 2 :
5072 direction == MV_LEFT ? 3 :
5076 int map_direction_EM_to_RND(int direction)
5078 return (direction == 0 ? MV_UP :
5079 direction == 1 ? MV_RIGHT :
5080 direction == 2 ? MV_DOWN :
5081 direction == 3 ? MV_LEFT :
5085 int get_next_element(int element)
5089 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5090 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5091 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5092 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5093 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5094 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5095 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5097 default: return element;
5102 int el_act_dir2img(int element, int action, int direction)
5104 element = GFX_ELEMENT(element);
5106 if (direction == MV_NONE)
5107 return element_info[element].graphic[action];
5109 direction = MV_DIR_TO_BIT(direction);
5111 return element_info[element].direction_graphic[action][direction];
5114 int el_act_dir2img(int element, int action, int direction)
5116 element = GFX_ELEMENT(element);
5117 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5119 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5120 return element_info[element].direction_graphic[action][direction];
5125 static int el_act_dir2crm(int element, int action, int direction)
5127 element = GFX_ELEMENT(element);
5129 if (direction == MV_NONE)
5130 return element_info[element].crumbled[action];
5132 direction = MV_DIR_TO_BIT(direction);
5134 return element_info[element].direction_crumbled[action][direction];
5137 static int el_act_dir2crm(int element, int action, int direction)
5139 element = GFX_ELEMENT(element);
5140 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5142 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5143 return element_info[element].direction_crumbled[action][direction];
5147 int el_act2img(int element, int action)
5149 element = GFX_ELEMENT(element);
5151 return element_info[element].graphic[action];
5154 int el_act2crm(int element, int action)
5156 element = GFX_ELEMENT(element);
5158 return element_info[element].crumbled[action];
5161 int el_dir2img(int element, int direction)
5163 element = GFX_ELEMENT(element);
5165 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5168 int el2baseimg(int element)
5170 return element_info[element].graphic[ACTION_DEFAULT];
5173 int el2img(int element)
5175 element = GFX_ELEMENT(element);
5177 return element_info[element].graphic[ACTION_DEFAULT];
5180 int el2edimg(int element)
5182 element = GFX_ELEMENT(element);
5184 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5187 int el2preimg(int element)
5189 element = GFX_ELEMENT(element);
5191 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5194 int font2baseimg(int font_nr)
5196 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5200 void setCenteredPlayerNr_EM(int centered_player_nr)
5202 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5205 int getCenteredPlayerNr_EM()
5208 if (game.centered_player_nr_next >= 0 &&
5209 !native_em_level.ply[game.centered_player_nr_next]->alive)
5210 game.centered_player_nr_next = game.centered_player_nr;
5213 if (game.centered_player_nr != game.centered_player_nr_next)
5214 game.centered_player_nr = game.centered_player_nr_next;
5216 return game.centered_player_nr;
5219 void setSetCenteredPlayer_EM(boolean set_centered_player)
5221 game.set_centered_player = set_centered_player;
5224 boolean getSetCenteredPlayer_EM()
5226 return game.set_centered_player;
5230 int getNumActivePlayers_EM()
5232 int num_players = 0;
5238 for (i = 0; i < MAX_PLAYERS; i++)
5239 if (tape.player_participates[i])
5246 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5248 int game_frame_delay_value;
5250 game_frame_delay_value =
5251 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5252 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5255 if (tape.playing && tape.warp_forward && !tape.pausing)
5256 game_frame_delay_value = 0;
5258 return game_frame_delay_value;
5262 unsigned int InitRND(long seed)
5264 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5265 return InitEngineRND_EM(seed);
5267 return InitEngineRND(seed);
5270 void InitGraphicInfo_EM(void)
5272 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5273 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5277 int num_em_gfx_errors = 0;
5279 if (graphic_info_em_object[0][0].bitmap == NULL)
5281 /* EM graphics not yet initialized in em_open_all() */
5286 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5289 /* always start with reliable default values */
5290 for (i = 0; i < TILE_MAX; i++)
5292 object_mapping[i].element_rnd = EL_UNKNOWN;
5293 object_mapping[i].is_backside = FALSE;
5294 object_mapping[i].action = ACTION_DEFAULT;
5295 object_mapping[i].direction = MV_NONE;
5298 /* always start with reliable default values */
5299 for (p = 0; p < MAX_PLAYERS; p++)
5301 for (i = 0; i < SPR_MAX; i++)
5303 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5304 player_mapping[p][i].action = ACTION_DEFAULT;
5305 player_mapping[p][i].direction = MV_NONE;
5309 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5311 int e = em_object_mapping_list[i].element_em;
5313 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5314 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5316 if (em_object_mapping_list[i].action != -1)
5317 object_mapping[e].action = em_object_mapping_list[i].action;
5319 if (em_object_mapping_list[i].direction != -1)
5320 object_mapping[e].direction =
5321 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5324 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5326 int a = em_player_mapping_list[i].action_em;
5327 int p = em_player_mapping_list[i].player_nr;
5329 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5331 if (em_player_mapping_list[i].action != -1)
5332 player_mapping[p][a].action = em_player_mapping_list[i].action;
5334 if (em_player_mapping_list[i].direction != -1)
5335 player_mapping[p][a].direction =
5336 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5339 for (i = 0; i < TILE_MAX; i++)
5341 int element = object_mapping[i].element_rnd;
5342 int action = object_mapping[i].action;
5343 int direction = object_mapping[i].direction;
5344 boolean is_backside = object_mapping[i].is_backside;
5345 boolean action_removing = (action == ACTION_DIGGING ||
5346 action == ACTION_SNAPPING ||
5347 action == ACTION_COLLECTING);
5348 boolean action_exploding = ((action == ACTION_EXPLODING ||
5349 action == ACTION_SMASHED_BY_ROCK ||
5350 action == ACTION_SMASHED_BY_SPRING) &&
5351 element != EL_DIAMOND);
5352 boolean action_active = (action == ACTION_ACTIVE);
5353 boolean action_other = (action == ACTION_OTHER);
5355 for (j = 0; j < 8; j++)
5357 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5358 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5360 i == Xdrip_stretch ? element :
5361 i == Xdrip_stretchB ? element :
5362 i == Ydrip_s1 ? element :
5363 i == Ydrip_s1B ? element :
5364 i == Xball_1B ? element :
5365 i == Xball_2 ? element :
5366 i == Xball_2B ? element :
5367 i == Yball_eat ? element :
5368 i == Ykey_1_eat ? element :
5369 i == Ykey_2_eat ? element :
5370 i == Ykey_3_eat ? element :
5371 i == Ykey_4_eat ? element :
5372 i == Ykey_5_eat ? element :
5373 i == Ykey_6_eat ? element :
5374 i == Ykey_7_eat ? element :
5375 i == Ykey_8_eat ? element :
5376 i == Ylenses_eat ? element :
5377 i == Ymagnify_eat ? element :
5378 i == Ygrass_eat ? element :
5379 i == Ydirt_eat ? element :
5380 i == Yemerald_stone ? EL_EMERALD :
5381 i == Ydiamond_stone ? EL_ROCK :
5382 i == Xsand_stonein_1 ? element :
5383 i == Xsand_stonein_2 ? element :
5384 i == Xsand_stonein_3 ? element :
5385 i == Xsand_stonein_4 ? element :
5386 is_backside ? EL_EMPTY :
5387 action_removing ? EL_EMPTY :
5389 int effective_action = (j < 7 ? action :
5390 i == Xdrip_stretch ? action :
5391 i == Xdrip_stretchB ? action :
5392 i == Ydrip_s1 ? action :
5393 i == Ydrip_s1B ? action :
5394 i == Xball_1B ? action :
5395 i == Xball_2 ? action :
5396 i == Xball_2B ? action :
5397 i == Yball_eat ? action :
5398 i == Ykey_1_eat ? action :
5399 i == Ykey_2_eat ? action :
5400 i == Ykey_3_eat ? action :
5401 i == Ykey_4_eat ? action :
5402 i == Ykey_5_eat ? action :
5403 i == Ykey_6_eat ? action :
5404 i == Ykey_7_eat ? action :
5405 i == Ykey_8_eat ? action :
5406 i == Ylenses_eat ? action :
5407 i == Ymagnify_eat ? action :
5408 i == Ygrass_eat ? action :
5409 i == Ydirt_eat ? action :
5410 i == Xsand_stonein_1 ? action :
5411 i == Xsand_stonein_2 ? action :
5412 i == Xsand_stonein_3 ? action :
5413 i == Xsand_stonein_4 ? action :
5414 i == Xsand_stoneout_1 ? action :
5415 i == Xsand_stoneout_2 ? action :
5416 i == Xboom_android ? ACTION_EXPLODING :
5417 action_exploding ? ACTION_EXPLODING :
5418 action_active ? action :
5419 action_other ? action :
5421 int graphic = (el_act_dir2img(effective_element, effective_action,
5423 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5425 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5426 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5427 boolean has_action_graphics = (graphic != base_graphic);
5428 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5429 struct GraphicInfo *g = &graphic_info[graphic];
5430 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5433 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5434 boolean special_animation = (action != ACTION_DEFAULT &&
5435 g->anim_frames == 3 &&
5436 g->anim_delay == 2 &&
5437 g->anim_mode & ANIM_LINEAR);
5438 int sync_frame = (i == Xdrip_stretch ? 7 :
5439 i == Xdrip_stretchB ? 7 :
5440 i == Ydrip_s2 ? j + 8 :
5441 i == Ydrip_s2B ? j + 8 :
5450 i == Xfake_acid_1 ? 0 :
5451 i == Xfake_acid_2 ? 10 :
5452 i == Xfake_acid_3 ? 20 :
5453 i == Xfake_acid_4 ? 30 :
5454 i == Xfake_acid_5 ? 40 :
5455 i == Xfake_acid_6 ? 50 :
5456 i == Xfake_acid_7 ? 60 :
5457 i == Xfake_acid_8 ? 70 :
5459 i == Xball_2B ? j + 8 :
5460 i == Yball_eat ? j + 1 :
5461 i == Ykey_1_eat ? j + 1 :
5462 i == Ykey_2_eat ? j + 1 :
5463 i == Ykey_3_eat ? j + 1 :
5464 i == Ykey_4_eat ? j + 1 :
5465 i == Ykey_5_eat ? j + 1 :
5466 i == Ykey_6_eat ? j + 1 :
5467 i == Ykey_7_eat ? j + 1 :
5468 i == Ykey_8_eat ? j + 1 :
5469 i == Ylenses_eat ? j + 1 :
5470 i == Ymagnify_eat ? j + 1 :
5471 i == Ygrass_eat ? j + 1 :
5472 i == Ydirt_eat ? j + 1 :
5473 i == Xamoeba_1 ? 0 :
5474 i == Xamoeba_2 ? 1 :
5475 i == Xamoeba_3 ? 2 :
5476 i == Xamoeba_4 ? 3 :
5477 i == Xamoeba_5 ? 0 :
5478 i == Xamoeba_6 ? 1 :
5479 i == Xamoeba_7 ? 2 :
5480 i == Xamoeba_8 ? 3 :
5481 i == Xexit_2 ? j + 8 :
5482 i == Xexit_3 ? j + 16 :
5483 i == Xdynamite_1 ? 0 :
5484 i == Xdynamite_2 ? 8 :
5485 i == Xdynamite_3 ? 16 :
5486 i == Xdynamite_4 ? 24 :
5487 i == Xsand_stonein_1 ? j + 1 :
5488 i == Xsand_stonein_2 ? j + 9 :
5489 i == Xsand_stonein_3 ? j + 17 :
5490 i == Xsand_stonein_4 ? j + 25 :
5491 i == Xsand_stoneout_1 && j == 0 ? 0 :
5492 i == Xsand_stoneout_1 && j == 1 ? 0 :
5493 i == Xsand_stoneout_1 && j == 2 ? 1 :
5494 i == Xsand_stoneout_1 && j == 3 ? 2 :
5495 i == Xsand_stoneout_1 && j == 4 ? 2 :
5496 i == Xsand_stoneout_1 && j == 5 ? 3 :
5497 i == Xsand_stoneout_1 && j == 6 ? 4 :
5498 i == Xsand_stoneout_1 && j == 7 ? 4 :
5499 i == Xsand_stoneout_2 && j == 0 ? 5 :
5500 i == Xsand_stoneout_2 && j == 1 ? 6 :
5501 i == Xsand_stoneout_2 && j == 2 ? 7 :
5502 i == Xsand_stoneout_2 && j == 3 ? 8 :
5503 i == Xsand_stoneout_2 && j == 4 ? 9 :
5504 i == Xsand_stoneout_2 && j == 5 ? 11 :
5505 i == Xsand_stoneout_2 && j == 6 ? 13 :
5506 i == Xsand_stoneout_2 && j == 7 ? 15 :
5507 i == Xboom_bug && j == 1 ? 2 :
5508 i == Xboom_bug && j == 2 ? 2 :
5509 i == Xboom_bug && j == 3 ? 4 :
5510 i == Xboom_bug && j == 4 ? 4 :
5511 i == Xboom_bug && j == 5 ? 2 :
5512 i == Xboom_bug && j == 6 ? 2 :
5513 i == Xboom_bug && j == 7 ? 0 :
5514 i == Xboom_bomb && j == 1 ? 2 :
5515 i == Xboom_bomb && j == 2 ? 2 :
5516 i == Xboom_bomb && j == 3 ? 4 :
5517 i == Xboom_bomb && j == 4 ? 4 :
5518 i == Xboom_bomb && j == 5 ? 2 :
5519 i == Xboom_bomb && j == 6 ? 2 :
5520 i == Xboom_bomb && j == 7 ? 0 :
5521 i == Xboom_android && j == 7 ? 6 :
5522 i == Xboom_1 && j == 1 ? 2 :
5523 i == Xboom_1 && j == 2 ? 2 :
5524 i == Xboom_1 && j == 3 ? 4 :
5525 i == Xboom_1 && j == 4 ? 4 :
5526 i == Xboom_1 && j == 5 ? 6 :
5527 i == Xboom_1 && j == 6 ? 6 :
5528 i == Xboom_1 && j == 7 ? 8 :
5529 i == Xboom_2 && j == 0 ? 8 :
5530 i == Xboom_2 && j == 1 ? 8 :
5531 i == Xboom_2 && j == 2 ? 10 :
5532 i == Xboom_2 && j == 3 ? 10 :
5533 i == Xboom_2 && j == 4 ? 10 :
5534 i == Xboom_2 && j == 5 ? 12 :
5535 i == Xboom_2 && j == 6 ? 12 :
5536 i == Xboom_2 && j == 7 ? 12 :
5537 special_animation && j == 4 ? 3 :
5538 effective_action != action ? 0 :
5542 Bitmap *debug_bitmap = g_em->bitmap;
5543 int debug_src_x = g_em->src_x;
5544 int debug_src_y = g_em->src_y;
5547 int frame = getAnimationFrame(g->anim_frames,
5550 g->anim_start_frame,
5553 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5554 g->double_movement && is_backside);
5556 g_em->bitmap = src_bitmap;
5557 g_em->src_x = src_x;
5558 g_em->src_y = src_y;
5559 g_em->src_offset_x = 0;
5560 g_em->src_offset_y = 0;
5561 g_em->dst_offset_x = 0;
5562 g_em->dst_offset_y = 0;
5563 g_em->width = TILEX;
5564 g_em->height = TILEY;
5566 g_em->crumbled_bitmap = NULL;
5567 g_em->crumbled_src_x = 0;
5568 g_em->crumbled_src_y = 0;
5569 g_em->crumbled_border_size = 0;
5571 g_em->has_crumbled_graphics = FALSE;
5572 g_em->preserve_background = FALSE;
5575 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5576 printf("::: empty crumbled: %d [%s], %d, %d\n",
5577 effective_element, element_info[effective_element].token_name,
5578 effective_action, direction);
5581 /* if element can be crumbled, but certain action graphics are just empty
5582 space (like snapping sand with the original R'n'D graphics), do not
5583 treat these empty space graphics as crumbled graphics in EMC engine */
5584 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5586 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5588 g_em->has_crumbled_graphics = TRUE;
5589 g_em->crumbled_bitmap = src_bitmap;
5590 g_em->crumbled_src_x = src_x;
5591 g_em->crumbled_src_y = src_y;
5592 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5596 if (element == EL_ROCK &&
5597 effective_action == ACTION_FILLING)
5598 printf("::: has_action_graphics == %d\n", has_action_graphics);
5601 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5602 effective_action == ACTION_MOVING ||
5603 effective_action == ACTION_PUSHING ||
5604 effective_action == ACTION_EATING)) ||
5605 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5606 effective_action == ACTION_EMPTYING)))
5609 (effective_action == ACTION_FALLING ||
5610 effective_action == ACTION_FILLING ||
5611 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5612 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5613 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5614 int num_steps = (i == Ydrip_s1 ? 16 :
5615 i == Ydrip_s1B ? 16 :
5616 i == Ydrip_s2 ? 16 :
5617 i == Ydrip_s2B ? 16 :
5618 i == Xsand_stonein_1 ? 32 :
5619 i == Xsand_stonein_2 ? 32 :
5620 i == Xsand_stonein_3 ? 32 :
5621 i == Xsand_stonein_4 ? 32 :
5622 i == Xsand_stoneout_1 ? 16 :
5623 i == Xsand_stoneout_2 ? 16 : 8);
5624 int cx = ABS(dx) * (TILEX / num_steps);
5625 int cy = ABS(dy) * (TILEY / num_steps);
5626 int step_frame = (i == Ydrip_s2 ? j + 8 :
5627 i == Ydrip_s2B ? j + 8 :
5628 i == Xsand_stonein_2 ? j + 8 :
5629 i == Xsand_stonein_3 ? j + 16 :
5630 i == Xsand_stonein_4 ? j + 24 :
5631 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5632 int step = (is_backside ? step_frame : num_steps - step_frame);
5634 if (is_backside) /* tile where movement starts */
5636 if (dx < 0 || dy < 0)
5638 g_em->src_offset_x = cx * step;
5639 g_em->src_offset_y = cy * step;
5643 g_em->dst_offset_x = cx * step;
5644 g_em->dst_offset_y = cy * step;
5647 else /* tile where movement ends */
5649 if (dx < 0 || dy < 0)
5651 g_em->dst_offset_x = cx * step;
5652 g_em->dst_offset_y = cy * step;
5656 g_em->src_offset_x = cx * step;
5657 g_em->src_offset_y = cy * step;
5661 g_em->width = TILEX - cx * step;
5662 g_em->height = TILEY - cy * step;
5666 /* create unique graphic identifier to decide if tile must be redrawn */
5667 /* bit 31 - 16 (16 bit): EM style graphic
5668 bit 15 - 12 ( 4 bit): EM style frame
5669 bit 11 - 6 ( 6 bit): graphic width
5670 bit 5 - 0 ( 6 bit): graphic height */
5671 g_em->unique_identifier =
5672 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5674 /* create unique graphic identifier to decide if tile must be redrawn */
5675 /* bit 31 - 16 (16 bit): EM style element
5676 bit 15 - 12 ( 4 bit): EM style frame
5677 bit 11 - 6 ( 6 bit): graphic width
5678 bit 5 - 0 ( 6 bit): graphic height */
5679 g_em->unique_identifier =
5680 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5684 if (effective_element == EL_ROCK)
5685 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5686 effective_action, j, graphic, frame, g_em->unique_identifier);
5692 /* skip check for EMC elements not contained in original EMC artwork */
5693 if (element == EL_EMC_FAKE_ACID)
5697 if (g_em->bitmap != debug_bitmap ||
5698 g_em->src_x != debug_src_x ||
5699 g_em->src_y != debug_src_y ||
5700 g_em->src_offset_x != 0 ||
5701 g_em->src_offset_y != 0 ||
5702 g_em->dst_offset_x != 0 ||
5703 g_em->dst_offset_y != 0 ||
5704 g_em->width != TILEX ||
5705 g_em->height != TILEY)
5707 static int last_i = -1;
5715 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5716 i, element, element_info[element].token_name,
5717 element_action_info[effective_action].suffix, direction);
5719 if (element != effective_element)
5720 printf(" [%d ('%s')]",
5722 element_info[effective_element].token_name);
5726 if (g_em->bitmap != debug_bitmap)
5727 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5728 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5730 if (g_em->src_x != debug_src_x ||
5731 g_em->src_y != debug_src_y)
5732 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5733 j, (is_backside ? 'B' : 'F'),
5734 g_em->src_x, g_em->src_y,
5735 g_em->src_x / 32, g_em->src_y / 32,
5736 debug_src_x, debug_src_y,
5737 debug_src_x / 32, debug_src_y / 32);
5739 if (g_em->src_offset_x != 0 ||
5740 g_em->src_offset_y != 0 ||
5741 g_em->dst_offset_x != 0 ||
5742 g_em->dst_offset_y != 0)
5743 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5745 g_em->src_offset_x, g_em->src_offset_y,
5746 g_em->dst_offset_x, g_em->dst_offset_y);
5748 if (g_em->width != TILEX ||
5749 g_em->height != TILEY)
5750 printf(" %d (%d): size %d,%d should be %d,%d\n",
5752 g_em->width, g_em->height, TILEX, TILEY);
5754 num_em_gfx_errors++;
5761 for (i = 0; i < TILE_MAX; i++)
5763 for (j = 0; j < 8; j++)
5765 int element = object_mapping[i].element_rnd;
5766 int action = object_mapping[i].action;
5767 int direction = object_mapping[i].direction;
5768 boolean is_backside = object_mapping[i].is_backside;
5770 int graphic_action = el_act_dir2img(element, action, direction);
5771 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5773 int graphic_action = element_info[element].graphic[action];
5774 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5777 if ((action == ACTION_SMASHED_BY_ROCK ||
5778 action == ACTION_SMASHED_BY_SPRING ||
5779 action == ACTION_EATING) &&
5780 graphic_action == graphic_default)
5782 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5783 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5784 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5785 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5788 /* no separate animation for "smashed by rock" -- use rock instead */
5789 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5790 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5792 g_em->bitmap = g_xx->bitmap;
5793 g_em->src_x = g_xx->src_x;
5794 g_em->src_y = g_xx->src_y;
5795 g_em->src_offset_x = g_xx->src_offset_x;
5796 g_em->src_offset_y = g_xx->src_offset_y;
5797 g_em->dst_offset_x = g_xx->dst_offset_x;
5798 g_em->dst_offset_y = g_xx->dst_offset_y;
5799 g_em->width = g_xx->width;
5800 g_em->height = g_xx->height;
5802 g_em->unique_identifier = g_xx->unique_identifier;
5806 g_em->preserve_background = TRUE;
5811 for (p = 0; p < MAX_PLAYERS; p++)
5813 for (i = 0; i < SPR_MAX; i++)
5815 int element = player_mapping[p][i].element_rnd;
5816 int action = player_mapping[p][i].action;
5817 int direction = player_mapping[p][i].direction;
5819 for (j = 0; j < 8; j++)
5821 int effective_element = element;
5822 int effective_action = action;
5823 int graphic = (direction == MV_NONE ?
5824 el_act2img(effective_element, effective_action) :
5825 el_act_dir2img(effective_element, effective_action,
5827 struct GraphicInfo *g = &graphic_info[graphic];
5828 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5834 Bitmap *debug_bitmap = g_em->bitmap;
5835 int debug_src_x = g_em->src_x;
5836 int debug_src_y = g_em->src_y;
5839 int frame = getAnimationFrame(g->anim_frames,
5842 g->anim_start_frame,
5845 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5847 g_em->bitmap = src_bitmap;
5848 g_em->src_x = src_x;
5849 g_em->src_y = src_y;
5850 g_em->src_offset_x = 0;
5851 g_em->src_offset_y = 0;
5852 g_em->dst_offset_x = 0;
5853 g_em->dst_offset_y = 0;
5854 g_em->width = TILEX;
5855 g_em->height = TILEY;
5860 /* skip check for EMC elements not contained in original EMC artwork */
5861 if (element == EL_PLAYER_3 ||
5862 element == EL_PLAYER_4)
5866 if (g_em->bitmap != debug_bitmap ||
5867 g_em->src_x != debug_src_x ||
5868 g_em->src_y != debug_src_y)
5870 static int last_i = -1;
5878 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5879 p, i, element, element_info[element].token_name,
5880 element_action_info[effective_action].suffix, direction);
5882 if (element != effective_element)
5883 printf(" [%d ('%s')]",
5885 element_info[effective_element].token_name);
5889 if (g_em->bitmap != debug_bitmap)
5890 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5891 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5893 if (g_em->src_x != debug_src_x ||
5894 g_em->src_y != debug_src_y)
5895 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5897 g_em->src_x, g_em->src_y,
5898 g_em->src_x / 32, g_em->src_y / 32,
5899 debug_src_x, debug_src_y,
5900 debug_src_x / 32, debug_src_y / 32);
5902 num_em_gfx_errors++;
5912 printf("::: [%d errors found]\n", num_em_gfx_errors);
5918 void PlayMenuSound()
5920 int sound = menu.sound[game_status];
5922 if (sound == SND_UNDEFINED)
5925 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5926 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5929 if (IS_LOOP_SOUND(sound))
5930 PlaySoundLoop(sound);
5935 void PlayMenuSoundStereo(int sound, int stereo_position)
5937 if (sound == SND_UNDEFINED)
5940 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5941 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5944 if (IS_LOOP_SOUND(sound))
5945 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
5947 PlaySoundStereo(sound, stereo_position);
5950 void PlayMenuSoundIfLoop()
5952 int sound = menu.sound[game_status];
5954 if (sound == SND_UNDEFINED)
5957 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5958 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5961 if (IS_LOOP_SOUND(sound))
5962 PlaySoundLoop(sound);
5965 void PlayMenuMusic()
5967 int music = menu.music[game_status];
5969 if (music == MUS_UNDEFINED)