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 int preview_tilesize = TILEX / 8;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
120 drawto_field = fieldbuffer;
122 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
128 BX2 = SCR_FIELDX - 1;
129 BY2 = SCR_FIELDY - 1;
133 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
137 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
139 if (game_status == GAME_MODE_PLAYING &&
140 level.game_engine_type == GAME_ENGINE_TYPE_EM)
142 /* currently there is no partial redraw -- always redraw whole playfield */
144 RedrawPlayfield_EM(TRUE);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
186 BlitBitmap(drawto, window, x, y, width, height, x, y);
192 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
194 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
195 redraw_mask &= ~REDRAW_MAIN;
197 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
198 redraw_mask |= REDRAW_FIELD;
200 if (redraw_mask & REDRAW_FIELD)
201 redraw_mask &= ~REDRAW_TILES;
203 if (redraw_mask == REDRAW_NONE)
206 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
208 static boolean last_frame_skipped = FALSE;
209 boolean skip_even_when_not_scrolling = TRUE;
210 boolean just_scrolling = (ScreenMovDir != 0);
211 boolean verbose = FALSE;
213 if (global.fps_slowdown_factor > 1 &&
214 (FrameCounter % global.fps_slowdown_factor) &&
215 (just_scrolling || skip_even_when_not_scrolling))
217 redraw_mask &= ~REDRAW_MAIN;
219 last_frame_skipped = TRUE;
222 printf("FRAME SKIPPED\n");
226 if (last_frame_skipped)
227 redraw_mask |= REDRAW_FIELD;
229 last_frame_skipped = FALSE;
232 printf("frame not skipped\n");
236 /* synchronize X11 graphics at this point; if we would synchronize the
237 display immediately after the buffer switching (after the XFlush),
238 this could mean that we have to wait for the graphics to complete,
239 although we could go on doing calculations for the next frame */
243 if (redraw_mask & REDRAW_ALL)
245 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
247 redraw_mask = REDRAW_NONE;
250 if (redraw_mask & REDRAW_FIELD)
252 if (game_status != GAME_MODE_PLAYING ||
253 redraw_mask & REDRAW_FROM_BACKBUFFER)
255 BlitBitmap(backbuffer, window,
256 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
260 int fx = FX, fy = FY;
262 if (setup.soft_scrolling)
264 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
265 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
268 if (setup.soft_scrolling ||
269 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
270 ABS(ScreenMovPos) == ScrollStepSize ||
271 redraw_tiles > REDRAWTILES_THRESHOLD)
273 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
277 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
279 (setup.soft_scrolling ?
280 "setup.soft_scrolling" :
281 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
282 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
283 ABS(ScreenGfxPos) == ScrollStepSize ?
284 "ABS(ScreenGfxPos) == ScrollStepSize" :
285 "redraw_tiles > REDRAWTILES_THRESHOLD"));
291 redraw_mask &= ~REDRAW_MAIN;
294 if (redraw_mask & REDRAW_DOORS)
296 if (redraw_mask & REDRAW_DOOR_1)
297 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
299 if (redraw_mask & REDRAW_DOOR_2)
300 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
302 if (redraw_mask & REDRAW_DOOR_3)
303 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
305 redraw_mask &= ~REDRAW_DOORS;
308 if (redraw_mask & REDRAW_MICROLEVEL)
310 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
311 SX, SY + 10 * TILEY);
313 redraw_mask &= ~REDRAW_MICROLEVEL;
316 if (redraw_mask & REDRAW_TILES)
318 for (x = 0; x < SCR_FIELDX; x++)
319 for (y = 0 ; y < SCR_FIELDY; y++)
320 if (redraw[redraw_x1 + x][redraw_y1 + y])
321 BlitBitmap(buffer, window,
322 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
323 SX + x * TILEX, SY + y * TILEY);
326 if (redraw_mask & REDRAW_FPS) /* display frames per second */
331 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
332 if (!global.fps_slowdown)
335 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
336 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
341 for (x = 0; x < MAX_BUF_XSIZE; x++)
342 for (y = 0; y < MAX_BUF_YSIZE; y++)
345 redraw_mask = REDRAW_NONE;
351 long fading_delay = 300;
353 if (setup.fading && (redraw_mask & REDRAW_FIELD))
360 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
363 for (i = 0; i < 2 * FULL_SYSIZE; i++)
365 for (y = 0; y < FULL_SYSIZE; y++)
367 BlitBitmap(backbuffer, window,
368 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
376 for (i = 1; i < FULL_SYSIZE; i+=2)
377 BlitBitmap(backbuffer, window,
378 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
384 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
385 BlitBitmapMasked(backbuffer, window,
386 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
391 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
392 BlitBitmapMasked(backbuffer, window,
393 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
398 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
399 BlitBitmapMasked(backbuffer, window,
400 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
405 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
406 BlitBitmapMasked(backbuffer, window,
407 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
412 redraw_mask &= ~REDRAW_MAIN;
419 void FadeIn(int fade_delay)
428 FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
430 redraw_mask = REDRAW_NONE;
433 void FadeOut(int fade_delay, int post_delay)
437 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
443 FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
445 redraw_mask = REDRAW_NONE;
448 void FadeCross(int fade_delay)
452 BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
458 FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
460 redraw_mask = REDRAW_NONE;
463 void SetMainBackgroundImageIfDefined(int graphic)
465 if (graphic_info[graphic].bitmap)
466 SetMainBackgroundImage(graphic);
469 void SetMainBackgroundImage(int graphic)
471 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
472 graphic_info[graphic].bitmap ?
473 graphic_info[graphic].bitmap :
474 graphic_info[IMG_BACKGROUND].bitmap);
477 void SetDoorBackgroundImage(int graphic)
479 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
480 graphic_info[graphic].bitmap ?
481 graphic_info[graphic].bitmap :
482 graphic_info[IMG_BACKGROUND].bitmap);
485 void DrawBackground(int dst_x, int dst_y, int width, int height)
487 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
489 redraw_mask |= REDRAW_FIELD;
494 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
496 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
498 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
499 SetDrawtoField(DRAW_BUFFERED);
502 SetDrawtoField(DRAW_BACKBUFFER);
504 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
506 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
507 SetDrawtoField(DRAW_DIRECT);
511 void MarkTileDirty(int x, int y)
513 int xx = redraw_x1 + x;
514 int yy = redraw_y1 + y;
519 redraw[xx][yy] = TRUE;
520 redraw_mask |= REDRAW_TILES;
523 void SetBorderElement()
527 BorderElement = EL_EMPTY;
529 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
531 for (x = 0; x < lev_fieldx; x++)
533 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
534 BorderElement = EL_STEELWALL;
536 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
542 void SetRandomAnimationValue(int x, int y)
544 gfx.anim_random_frame = GfxRandom[x][y];
547 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
549 /* animation synchronized with global frame counter, not move position */
550 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
551 sync_frame = FrameCounter;
554 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
560 printf("::: FOO!\n");
564 return getAnimationFrame(graphic_info[graphic].anim_frames,
565 graphic_info[graphic].anim_delay,
566 graphic_info[graphic].anim_mode,
567 graphic_info[graphic].anim_start_frame,
571 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
572 int *x, int *y, boolean get_backside)
574 struct GraphicInfo *g = &graphic_info[graphic];
575 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
576 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
580 if (g->offset_y == 0) /* frames are ordered horizontally */
582 int max_width = g->anim_frames_per_line * g->width;
583 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
585 *x = pos % max_width;
586 *y = src_y % g->height + pos / max_width * g->height;
588 else if (g->offset_x == 0) /* frames are ordered vertically */
590 int max_height = g->anim_frames_per_line * g->height;
591 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
593 *x = src_x % g->width + pos / max_height * g->width;
594 *y = pos % max_height;
596 else /* frames are ordered diagonally */
598 *x = src_x + frame * g->offset_x;
599 *y = src_y + frame * g->offset_y;
603 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
605 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
608 void DrawGraphic(int x, int y, int graphic, int frame)
611 if (!IN_SCR_FIELD(x, y))
613 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
614 printf("DrawGraphic(): This should never happen!\n");
619 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
623 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
629 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
630 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
633 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
636 if (!IN_SCR_FIELD(x, y))
638 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
639 printf("DrawGraphicThruMask(): This should never happen!\n");
644 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
649 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
655 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
657 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
658 dst_x - src_x, dst_y - src_y);
659 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
662 void DrawMiniGraphic(int x, int y, int graphic)
664 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
665 MarkTileDirty(x / 2, y / 2);
668 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
670 struct GraphicInfo *g = &graphic_info[graphic];
672 int mini_starty = g->bitmap->height * 2 / 3;
675 *x = mini_startx + g->src_x / 2;
676 *y = mini_starty + g->src_y / 2;
679 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
684 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
685 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
688 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
689 int graphic, int frame,
690 int cut_mode, int mask_mode)
695 int width = TILEX, height = TILEY;
698 if (dx || dy) /* shifted graphic */
700 if (x < BX1) /* object enters playfield from the left */
707 else if (x > BX2) /* object enters playfield from the right */
713 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
719 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
721 else if (dx) /* general horizontal movement */
722 MarkTileDirty(x + SIGN(dx), y);
724 if (y < BY1) /* object enters playfield from the top */
726 if (cut_mode==CUT_BELOW) /* object completely above top border */
734 else if (y > BY2) /* object enters playfield from the bottom */
740 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
746 else if (dy > 0 && cut_mode == CUT_ABOVE)
748 if (y == BY2) /* object completely above bottom border */
754 MarkTileDirty(x, y + 1);
755 } /* object leaves playfield to the bottom */
756 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
758 else if (dy) /* general vertical movement */
759 MarkTileDirty(x, y + SIGN(dy));
763 if (!IN_SCR_FIELD(x, y))
765 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
766 printf("DrawGraphicShifted(): This should never happen!\n");
771 if (width > 0 && height > 0)
773 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
778 dst_x = FX + x * TILEX + dx;
779 dst_y = FY + y * TILEY + dy;
781 if (mask_mode == USE_MASKING)
783 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
784 dst_x - src_x, dst_y - src_y);
785 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
789 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
796 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
797 int graphic, int frame,
798 int cut_mode, int mask_mode)
803 int width = TILEX, height = TILEY;
806 int x2 = x + SIGN(dx);
807 int y2 = y + SIGN(dy);
808 int anim_frames = graphic_info[graphic].anim_frames;
809 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
810 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
811 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
813 /* re-calculate animation frame for two-tile movement animation */
814 frame = getGraphicAnimationFrame(graphic, sync_frame);
816 /* check if movement start graphic inside screen area and should be drawn */
817 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
819 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
821 dst_x = FX + x1 * TILEX;
822 dst_y = FY + y1 * TILEY;
824 if (mask_mode == USE_MASKING)
826 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
827 dst_x - src_x, dst_y - src_y);
828 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
832 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
835 MarkTileDirty(x1, y1);
838 /* check if movement end graphic inside screen area and should be drawn */
839 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
841 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
843 dst_x = FX + x2 * TILEX;
844 dst_y = FY + y2 * TILEY;
846 if (mask_mode == USE_MASKING)
848 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
849 dst_x - src_x, dst_y - src_y);
850 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
854 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
857 MarkTileDirty(x2, y2);
861 static void DrawGraphicShifted(int x, int y, int dx, int dy,
862 int graphic, int frame,
863 int cut_mode, int mask_mode)
867 DrawGraphic(x, y, graphic, frame);
872 if (graphic_info[graphic].double_movement) /* EM style movement images */
873 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
875 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
878 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
879 int frame, int cut_mode)
881 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
884 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
885 int cut_mode, int mask_mode)
887 int lx = LEVELX(x), ly = LEVELY(y);
891 if (IN_LEV_FIELD(lx, ly))
893 SetRandomAnimationValue(lx, ly);
895 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
896 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
898 /* do not use double (EM style) movement graphic when not moving */
899 if (graphic_info[graphic].double_movement && !dx && !dy)
901 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
902 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
905 else /* border element */
907 graphic = el2img(element);
908 frame = getGraphicAnimationFrame(graphic, -1);
911 if (element == EL_EXPANDABLE_WALL)
913 boolean left_stopped = FALSE, right_stopped = FALSE;
915 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
917 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
918 right_stopped = TRUE;
920 if (left_stopped && right_stopped)
922 else if (left_stopped)
924 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
925 frame = graphic_info[graphic].anim_frames - 1;
927 else if (right_stopped)
929 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
930 frame = graphic_info[graphic].anim_frames - 1;
935 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
936 else if (mask_mode == USE_MASKING)
937 DrawGraphicThruMask(x, y, graphic, frame);
939 DrawGraphic(x, y, graphic, frame);
942 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
943 int cut_mode, int mask_mode)
945 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
946 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
947 cut_mode, mask_mode);
950 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
953 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
956 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
959 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
962 void DrawLevelElementThruMask(int x, int y, int element)
964 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
967 void DrawLevelFieldThruMask(int x, int y)
969 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
972 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
976 int sx = SCREENX(x), sy = SCREENY(y);
978 int width, height, cx, cy, i;
979 int crumbled_border_size = graphic_info[graphic].border_size;
980 static int xy[4][2] =
988 if (!IN_LEV_FIELD(x, y))
991 element = TILE_GFX_ELEMENT(x, y);
993 /* crumble field itself */
994 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
996 if (!IN_SCR_FIELD(sx, sy))
999 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1001 for (i = 0; i < 4; i++)
1003 int xx = x + xy[i][0];
1004 int yy = y + xy[i][1];
1006 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1009 /* check if neighbour field is of same type */
1010 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1013 if (i == 1 || i == 2)
1015 width = crumbled_border_size;
1017 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1023 height = crumbled_border_size;
1025 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1028 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1029 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1032 MarkTileDirty(sx, sy);
1034 else /* crumble neighbour fields */
1036 for (i = 0; i < 4; i++)
1038 int xx = x + xy[i][0];
1039 int yy = y + xy[i][1];
1040 int sxx = sx + xy[i][0];
1041 int syy = sy + xy[i][1];
1044 if (!IN_LEV_FIELD(xx, yy) ||
1045 !IN_SCR_FIELD(sxx, syy) ||
1050 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1054 element = TILE_GFX_ELEMENT(xx, yy);
1056 if (!GFX_CRUMBLED(element))
1059 if (!IN_LEV_FIELD(xx, yy) ||
1060 !IN_SCR_FIELD(sxx, syy) ||
1061 !GFX_CRUMBLED(Feld[xx][yy]) ||
1067 graphic = el_act2crm(element, ACTION_DEFAULT);
1069 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1071 crumbled_border_size = graphic_info[graphic].border_size;
1073 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1075 if (i == 1 || i == 2)
1077 width = crumbled_border_size;
1079 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1085 height = crumbled_border_size;
1087 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1090 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1091 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1093 MarkTileDirty(sxx, syy);
1098 void DrawLevelFieldCrumbledSand(int x, int y)
1102 if (!IN_LEV_FIELD(x, y))
1106 /* !!! CHECK THIS !!! */
1109 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1110 GFX_CRUMBLED(GfxElement[x][y]))
1113 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1114 GfxElement[x][y] != EL_UNDEFINED &&
1115 GFX_CRUMBLED(GfxElement[x][y]))
1117 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1124 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1126 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1129 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1132 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1135 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1136 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1137 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1138 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1139 int sx = SCREENX(x), sy = SCREENY(y);
1141 DrawGraphic(sx, sy, graphic1, frame1);
1142 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1145 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1147 int sx = SCREENX(x), sy = SCREENY(y);
1148 static int xy[4][2] =
1157 for (i = 0; i < 4; i++)
1159 int xx = x + xy[i][0];
1160 int yy = y + xy[i][1];
1161 int sxx = sx + xy[i][0];
1162 int syy = sy + xy[i][1];
1164 if (!IN_LEV_FIELD(xx, yy) ||
1165 !IN_SCR_FIELD(sxx, syy) ||
1166 !GFX_CRUMBLED(Feld[xx][yy]) ||
1170 DrawLevelField(xx, yy);
1174 static int getBorderElement(int x, int y)
1178 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1179 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1180 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1181 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1182 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1183 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1184 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1186 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1187 int steel_position = (x == -1 && y == -1 ? 0 :
1188 x == lev_fieldx && y == -1 ? 1 :
1189 x == -1 && y == lev_fieldy ? 2 :
1190 x == lev_fieldx && y == lev_fieldy ? 3 :
1191 x == -1 || x == lev_fieldx ? 4 :
1192 y == -1 || y == lev_fieldy ? 5 : 6);
1194 return border[steel_position][steel_type];
1197 void DrawScreenElement(int x, int y, int element)
1199 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1200 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1203 void DrawLevelElement(int x, int y, int element)
1205 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1206 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1209 void DrawScreenField(int x, int y)
1211 int lx = LEVELX(x), ly = LEVELY(y);
1212 int element, content;
1214 if (!IN_LEV_FIELD(lx, ly))
1216 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1219 element = getBorderElement(lx, ly);
1221 DrawScreenElement(x, y, element);
1225 element = Feld[lx][ly];
1226 content = Store[lx][ly];
1228 if (IS_MOVING(lx, ly))
1230 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1231 boolean cut_mode = NO_CUTTING;
1233 if (element == EL_QUICKSAND_EMPTYING ||
1234 element == EL_MAGIC_WALL_EMPTYING ||
1235 element == EL_BD_MAGIC_WALL_EMPTYING ||
1236 element == EL_AMOEBA_DROPPING)
1237 cut_mode = CUT_ABOVE;
1238 else if (element == EL_QUICKSAND_FILLING ||
1239 element == EL_MAGIC_WALL_FILLING ||
1240 element == EL_BD_MAGIC_WALL_FILLING)
1241 cut_mode = CUT_BELOW;
1243 if (cut_mode == CUT_ABOVE)
1244 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1246 DrawScreenElement(x, y, EL_EMPTY);
1249 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1250 else if (cut_mode == NO_CUTTING)
1251 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1253 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1255 if (content == EL_ACID)
1257 int dir = MovDir[lx][ly];
1258 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1259 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1261 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1264 else if (IS_BLOCKED(lx, ly))
1269 boolean cut_mode = NO_CUTTING;
1270 int element_old, content_old;
1272 Blocked2Moving(lx, ly, &oldx, &oldy);
1275 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1276 MovDir[oldx][oldy] == MV_RIGHT);
1278 element_old = Feld[oldx][oldy];
1279 content_old = Store[oldx][oldy];
1281 if (element_old == EL_QUICKSAND_EMPTYING ||
1282 element_old == EL_MAGIC_WALL_EMPTYING ||
1283 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1284 element_old == EL_AMOEBA_DROPPING)
1285 cut_mode = CUT_ABOVE;
1287 DrawScreenElement(x, y, EL_EMPTY);
1290 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1292 else if (cut_mode == NO_CUTTING)
1293 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1296 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1299 else if (IS_DRAWABLE(element))
1300 DrawScreenElement(x, y, element);
1302 DrawScreenElement(x, y, EL_EMPTY);
1305 void DrawLevelField(int x, int y)
1307 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1308 DrawScreenField(SCREENX(x), SCREENY(y));
1309 else if (IS_MOVING(x, y))
1313 Moving2Blocked(x, y, &newx, &newy);
1314 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1315 DrawScreenField(SCREENX(newx), SCREENY(newy));
1317 else if (IS_BLOCKED(x, y))
1321 Blocked2Moving(x, y, &oldx, &oldy);
1322 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1323 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1327 void DrawMiniElement(int x, int y, int element)
1331 graphic = el2edimg(element);
1332 DrawMiniGraphic(x, y, graphic);
1335 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1337 int x = sx + scroll_x, y = sy + scroll_y;
1339 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1340 DrawMiniElement(sx, sy, EL_EMPTY);
1341 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1342 DrawMiniElement(sx, sy, Feld[x][y]);
1344 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1347 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1348 int x, int y, int xsize, int ysize, int font_nr)
1350 int font_width = getFontWidth(font_nr);
1351 int font_height = getFontHeight(font_nr);
1352 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1355 int dst_x = SX + startx + x * font_width;
1356 int dst_y = SY + starty + y * font_height;
1357 int width = graphic_info[graphic].width;
1358 int height = graphic_info[graphic].height;
1359 int inner_width = MAX(width - 2 * font_width, font_width);
1360 int inner_height = MAX(height - 2 * font_height, font_height);
1361 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1362 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1363 boolean draw_masked = graphic_info[graphic].draw_masked;
1365 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1367 if (src_bitmap == NULL || width < font_width || height < font_height)
1369 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1373 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1374 inner_sx + (x - 1) * font_width % inner_width);
1375 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1376 inner_sy + (y - 1) * font_height % inner_height);
1380 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1381 dst_x - src_x, dst_y - src_y);
1382 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1386 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1390 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1392 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1393 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1394 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1395 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1396 boolean no_delay = (tape.warp_forward);
1397 unsigned long anim_delay = 0;
1398 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1399 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1400 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1401 int font_width = getFontWidth(font_nr);
1402 int font_height = getFontHeight(font_nr);
1403 int max_xsize = level.envelope[envelope_nr].xsize;
1404 int max_ysize = level.envelope[envelope_nr].ysize;
1405 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1406 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1407 int xend = max_xsize;
1408 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1409 int xstep = (xstart < xend ? 1 : 0);
1410 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1413 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1415 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1416 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1417 int sx = (SXSIZE - xsize * font_width) / 2;
1418 int sy = (SYSIZE - ysize * font_height) / 2;
1421 SetDrawtoField(DRAW_BUFFERED);
1423 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1425 SetDrawtoField(DRAW_BACKBUFFER);
1427 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1428 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1430 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1431 level.envelope[envelope_nr].text, font_nr, max_xsize,
1432 xsize - 2, ysize - 2, mask_mode);
1434 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1437 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1441 void ShowEnvelope(int envelope_nr)
1443 int element = EL_ENVELOPE_1 + envelope_nr;
1444 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1445 int sound_opening = element_info[element].sound[ACTION_OPENING];
1446 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1447 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1448 boolean no_delay = (tape.warp_forward);
1449 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1450 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1451 int anim_mode = graphic_info[graphic].anim_mode;
1452 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1453 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1455 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1457 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1459 if (anim_mode == ANIM_DEFAULT)
1460 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1462 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1465 Delay(wait_delay_value);
1467 WaitForEventToContinue();
1469 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1471 if (anim_mode != ANIM_NONE)
1472 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1474 if (anim_mode == ANIM_DEFAULT)
1475 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1477 game.envelope_active = FALSE;
1479 SetDrawtoField(DRAW_BUFFERED);
1481 redraw_mask |= REDRAW_FIELD;
1485 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1487 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1488 int mini_startx = src_bitmap->width * 3 / 4;
1489 int mini_starty = src_bitmap->height * 2 / 3;
1490 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1491 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1493 *bitmap = src_bitmap;
1498 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1503 int width_mult, width_div;
1504 int height_mult, height_div;
1512 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1513 5 - log_2(tilesize));
1514 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1515 int width_mult = offset_calc[offset_calc_pos].width_mult;
1516 int width_div = offset_calc[offset_calc_pos].width_div;
1517 int height_mult = offset_calc[offset_calc_pos].height_mult;
1518 int height_div = offset_calc[offset_calc_pos].height_div;
1519 int mini_startx = src_bitmap->width * width_mult / width_div;
1520 int mini_starty = src_bitmap->height * height_mult / height_div;
1521 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1522 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1524 *bitmap = src_bitmap;
1529 void DrawMicroElement(int xpos, int ypos, int element)
1533 int graphic = el2preimg(element);
1535 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1536 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1540 void DrawPreviewElement(int xpos, int ypos, int element, int tilesize)
1544 int graphic = el2preimg(element);
1546 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1547 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, xpos, ypos);
1554 SetDrawBackgroundMask(REDRAW_NONE);
1557 for (x = BX1; x <= BX2; x++)
1558 for (y = BY1; y <= BY2; y++)
1559 DrawScreenField(x, y);
1561 redraw_mask |= REDRAW_FIELD;
1564 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1568 for (x = 0; x < size_x; x++)
1569 for (y = 0; y < size_y; y++)
1570 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1572 redraw_mask |= REDRAW_FIELD;
1575 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y,
1576 int preview_size_x, int preview_size_y)
1580 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1582 if (lev_fieldx < preview_size_x)
1583 xpos += (preview_size_x - lev_fieldx) / 2 * preview_tilesize;
1584 if (lev_fieldy < preview_size_y)
1585 ypos += (preview_size_y - lev_fieldy) / 2 * preview_tilesize;
1588 xpos += MICRO_TILEX;
1589 ypos += MICRO_TILEY;
1591 xpos += preview_tilesize;
1592 ypos += preview_tilesize;
1595 for (x = -1; x <= preview_size_x; x++)
1597 for (y = -1; y <= preview_size_y; y++)
1599 int lx = from_x + x, ly = from_y + y;
1601 if (lx >= 0 && lx < lev_fieldx &&
1602 ly >= 0 && ly < lev_fieldy)
1603 DrawPreviewElement(xpos + x * preview_tilesize,
1604 ypos + y * preview_tilesize,
1605 level.field[lx][ly], preview_tilesize);
1606 else if (lx >= -1 && lx < lev_fieldx+1 &&
1607 ly >= -1 && ly < lev_fieldy+1 && BorderElement != EL_EMPTY)
1608 DrawPreviewElement(xpos + x * preview_tilesize,
1609 ypos + y * preview_tilesize,
1610 getBorderElement(lx, ly), preview_tilesize);
1614 redraw_mask |= REDRAW_MICROLEVEL;
1617 #define MICROLABEL_EMPTY 0
1618 #define MICROLABEL_LEVEL_NAME 1
1619 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1620 #define MICROLABEL_LEVEL_AUTHOR 3
1621 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1622 #define MICROLABEL_IMPORTED_FROM 5
1623 #define MICROLABEL_IMPORTED_BY_HEAD 6
1624 #define MICROLABEL_IMPORTED_BY 7
1626 static void DrawMicroLevelLabelExt(int mode)
1628 char label_text[MAX_OUTPUT_LINESIZE + 1];
1629 int max_len_label_text;
1630 int font_nr = FONT_TEXT_2;
1633 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1634 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1635 mode == MICROLABEL_IMPORTED_BY_HEAD)
1636 font_nr = FONT_TEXT_3;
1638 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1640 for (i = 0; i < max_len_label_text; i++)
1641 label_text[i] = ' ';
1642 label_text[max_len_label_text] = '\0';
1644 if (strlen(label_text) > 0)
1646 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1647 int lypos = MICROLABEL2_YPOS;
1649 DrawText(lxpos, lypos, label_text, font_nr);
1653 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1654 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1655 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1656 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1657 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1658 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1659 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1660 max_len_label_text);
1661 label_text[max_len_label_text] = '\0';
1663 if (strlen(label_text) > 0)
1665 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1666 int lypos = MICROLABEL2_YPOS;
1668 DrawText(lxpos, lypos, label_text, font_nr);
1671 redraw_mask |= REDRAW_MICROLEVEL;
1674 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1676 static unsigned long scroll_delay = 0;
1677 static unsigned long label_delay = 0;
1678 static int from_x, from_y, scroll_direction;
1679 static int label_state, label_counter;
1680 int preview_size_x = STD_LEV_FIELDX * MICRO_TILESIZE / preview_tilesize;
1681 int preview_size_y = STD_LEV_FIELDY * MICRO_TILESIZE / preview_tilesize;
1682 int last_game_status = game_status; /* save current game status */
1684 /* force PREVIEW font on preview level */
1685 game_status = GAME_MODE_PSEUDO_PREVIEW;
1689 from_x = from_y = 0;
1690 scroll_direction = MV_RIGHT;
1694 DrawMicroLevelExt(xpos, ypos, from_x, from_y,
1695 preview_size_x, preview_size_y);
1696 DrawMicroLevelLabelExt(label_state);
1698 /* initialize delay counters */
1699 DelayReached(&scroll_delay, 0);
1700 DelayReached(&label_delay, 0);
1702 if (leveldir_current->name)
1704 char label_text[MAX_OUTPUT_LINESIZE + 1];
1705 int font_nr = FONT_TEXT_1;
1706 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1709 strncpy(label_text, leveldir_current->name, max_len_label_text);
1710 label_text[max_len_label_text] = '\0';
1712 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1713 lypos = SY + MICROLABEL1_YPOS;
1715 DrawText(lxpos, lypos, label_text, font_nr);
1718 game_status = last_game_status; /* restore current game status */
1723 /* scroll micro level, if needed */
1724 if ((lev_fieldx > preview_size_x || lev_fieldy > preview_size_y) &&
1725 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1727 switch (scroll_direction)
1733 scroll_direction = MV_UP;
1737 if (from_x < lev_fieldx - preview_size_x)
1740 scroll_direction = MV_DOWN;
1747 scroll_direction = MV_RIGHT;
1751 if (from_y < lev_fieldy - preview_size_y)
1754 scroll_direction = MV_LEFT;
1761 DrawMicroLevelExt(xpos, ypos, from_x, from_y,
1762 preview_size_x, preview_size_y);
1765 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1766 /* redraw micro level label, if needed */
1767 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1768 !strEqual(level.author, ANONYMOUS_NAME) &&
1769 !strEqual(level.author, leveldir_current->name) &&
1770 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1772 int max_label_counter = 23;
1774 if (leveldir_current->imported_from != NULL &&
1775 strlen(leveldir_current->imported_from) > 0)
1776 max_label_counter += 14;
1777 if (leveldir_current->imported_by != NULL &&
1778 strlen(leveldir_current->imported_by) > 0)
1779 max_label_counter += 14;
1781 label_counter = (label_counter + 1) % max_label_counter;
1782 label_state = (label_counter >= 0 && label_counter <= 7 ?
1783 MICROLABEL_LEVEL_NAME :
1784 label_counter >= 9 && label_counter <= 12 ?
1785 MICROLABEL_LEVEL_AUTHOR_HEAD :
1786 label_counter >= 14 && label_counter <= 21 ?
1787 MICROLABEL_LEVEL_AUTHOR :
1788 label_counter >= 23 && label_counter <= 26 ?
1789 MICROLABEL_IMPORTED_FROM_HEAD :
1790 label_counter >= 28 && label_counter <= 35 ?
1791 MICROLABEL_IMPORTED_FROM :
1792 label_counter >= 37 && label_counter <= 40 ?
1793 MICROLABEL_IMPORTED_BY_HEAD :
1794 label_counter >= 42 && label_counter <= 49 ?
1795 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1797 if (leveldir_current->imported_from == NULL &&
1798 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1799 label_state == MICROLABEL_IMPORTED_FROM))
1800 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1801 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1803 DrawMicroLevelLabelExt(label_state);
1806 game_status = last_game_status; /* restore current game status */
1809 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1810 int graphic, int sync_frame, int mask_mode)
1812 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1814 if (mask_mode == USE_MASKING)
1815 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1817 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1820 inline void DrawGraphicAnimation(int x, int y, int graphic)
1822 int lx = LEVELX(x), ly = LEVELY(y);
1824 if (!IN_SCR_FIELD(x, y))
1827 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1828 graphic, GfxFrame[lx][ly], NO_MASKING);
1829 MarkTileDirty(x, y);
1832 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1834 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1837 void DrawLevelElementAnimation(int x, int y, int element)
1839 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1841 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1844 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1846 int sx = SCREENX(x), sy = SCREENY(y);
1848 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1851 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1854 DrawGraphicAnimation(sx, sy, graphic);
1857 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1858 DrawLevelFieldCrumbledSand(x, y);
1860 if (GFX_CRUMBLED(Feld[x][y]))
1861 DrawLevelFieldCrumbledSand(x, y);
1865 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1867 int sx = SCREENX(x), sy = SCREENY(y);
1870 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1873 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1875 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1878 DrawGraphicAnimation(sx, sy, graphic);
1880 if (GFX_CRUMBLED(element))
1881 DrawLevelFieldCrumbledSand(x, y);
1884 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1886 if (player->use_murphy)
1888 /* this works only because currently only one player can be "murphy" ... */
1889 static int last_horizontal_dir = MV_LEFT;
1890 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1892 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1893 last_horizontal_dir = move_dir;
1895 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1897 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1899 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1905 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1908 static boolean equalGraphics(int graphic1, int graphic2)
1910 struct GraphicInfo *g1 = &graphic_info[graphic1];
1911 struct GraphicInfo *g2 = &graphic_info[graphic2];
1913 return (g1->bitmap == g2->bitmap &&
1914 g1->src_x == g2->src_x &&
1915 g1->src_y == g2->src_y &&
1916 g1->anim_frames == g2->anim_frames &&
1917 g1->anim_delay == g2->anim_delay &&
1918 g1->anim_mode == g2->anim_mode);
1921 void DrawAllPlayers()
1925 for (i = 0; i < MAX_PLAYERS; i++)
1926 if (stored_player[i].active)
1927 DrawPlayer(&stored_player[i]);
1930 void DrawPlayerField(int x, int y)
1932 if (!IS_PLAYER(x, y))
1935 DrawPlayer(PLAYERINFO(x, y));
1938 void DrawPlayer(struct PlayerInfo *player)
1940 int jx = player->jx;
1941 int jy = player->jy;
1942 int move_dir = player->MovDir;
1943 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1944 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1945 int last_jx = (player->is_moving ? jx - dx : jx);
1946 int last_jy = (player->is_moving ? jy - dy : jy);
1947 int next_jx = jx + dx;
1948 int next_jy = jy + dy;
1949 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1950 boolean player_is_opaque = FALSE;
1951 int sx = SCREENX(jx), sy = SCREENY(jy);
1952 int sxx = 0, syy = 0;
1953 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1955 int action = ACTION_DEFAULT;
1956 int last_player_graphic = getPlayerGraphic(player, move_dir);
1957 int last_player_frame = player->Frame;
1961 /* GfxElement[][] is set to the element the player is digging or collecting;
1962 remove also for off-screen player if the player is not moving anymore */
1963 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1964 GfxElement[jx][jy] = EL_UNDEFINED;
1967 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1971 if (!IN_LEV_FIELD(jx, jy))
1973 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1974 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1975 printf("DrawPlayerField(): This should never happen!\n");
1980 if (element == EL_EXPLOSION)
1983 action = (player->is_pushing ? ACTION_PUSHING :
1984 player->is_digging ? ACTION_DIGGING :
1985 player->is_collecting ? ACTION_COLLECTING :
1986 player->is_moving ? ACTION_MOVING :
1987 player->is_snapping ? ACTION_SNAPPING :
1988 player->is_dropping ? ACTION_DROPPING :
1989 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1992 if (player->is_waiting)
1993 move_dir = player->dir_waiting;
1996 InitPlayerGfxAnimation(player, action, move_dir);
1998 /* ----------------------------------------------------------------------- */
1999 /* draw things in the field the player is leaving, if needed */
2000 /* ----------------------------------------------------------------------- */
2002 if (player->is_moving)
2004 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2006 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2008 if (last_element == EL_DYNAMITE_ACTIVE ||
2009 last_element == EL_EM_DYNAMITE_ACTIVE ||
2010 last_element == EL_SP_DISK_RED_ACTIVE)
2011 DrawDynamite(last_jx, last_jy);
2013 DrawLevelFieldThruMask(last_jx, last_jy);
2015 else if (last_element == EL_DYNAMITE_ACTIVE ||
2016 last_element == EL_EM_DYNAMITE_ACTIVE ||
2017 last_element == EL_SP_DISK_RED_ACTIVE)
2018 DrawDynamite(last_jx, last_jy);
2020 /* !!! this is not enough to prevent flickering of players which are
2021 moving next to each others without a free tile between them -- this
2022 can only be solved by drawing all players layer by layer (first the
2023 background, then the foreground etc.) !!! => TODO */
2024 else if (!IS_PLAYER(last_jx, last_jy))
2025 DrawLevelField(last_jx, last_jy);
2028 DrawLevelField(last_jx, last_jy);
2031 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2032 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2035 if (!IN_SCR_FIELD(sx, sy))
2038 if (setup.direct_draw)
2039 SetDrawtoField(DRAW_BUFFERED);
2041 /* ----------------------------------------------------------------------- */
2042 /* draw things behind the player, if needed */
2043 /* ----------------------------------------------------------------------- */
2046 DrawLevelElement(jx, jy, Back[jx][jy]);
2047 else if (IS_ACTIVE_BOMB(element))
2048 DrawLevelElement(jx, jy, EL_EMPTY);
2051 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2053 int old_element = GfxElement[jx][jy];
2054 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2055 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2057 if (GFX_CRUMBLED(old_element))
2058 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2060 DrawGraphic(sx, sy, old_graphic, frame);
2062 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2063 player_is_opaque = TRUE;
2067 GfxElement[jx][jy] = EL_UNDEFINED;
2069 /* make sure that pushed elements are drawn with correct frame rate */
2070 if (player->is_pushing && player->is_moving)
2071 GfxFrame[jx][jy] = player->StepFrame;
2073 DrawLevelField(jx, jy);
2077 /* ----------------------------------------------------------------------- */
2078 /* draw player himself */
2079 /* ----------------------------------------------------------------------- */
2081 graphic = getPlayerGraphic(player, move_dir);
2083 /* in the case of changed player action or direction, prevent the current
2084 animation frame from being restarted for identical animations */
2085 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2086 player->Frame = last_player_frame;
2088 frame = getGraphicAnimationFrame(graphic, player->Frame);
2092 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2093 sxx = player->GfxPos;
2095 syy = player->GfxPos;
2098 if (!setup.soft_scrolling && ScreenMovPos)
2101 if (player_is_opaque)
2102 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2104 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2106 if (SHIELD_ON(player))
2108 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2109 IMG_SHIELD_NORMAL_ACTIVE);
2110 int frame = getGraphicAnimationFrame(graphic, -1);
2112 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2115 /* ----------------------------------------------------------------------- */
2116 /* draw things the player is pushing, if needed */
2117 /* ----------------------------------------------------------------------- */
2120 printf("::: %d, %d [%d, %d] [%d]\n",
2121 player->is_pushing, player_is_moving, player->GfxAction,
2122 player->is_moving, player_is_moving);
2126 if (player->is_pushing && player->is_moving)
2128 int px = SCREENX(jx), py = SCREENY(jy);
2129 int pxx = (TILEX - ABS(sxx)) * dx;
2130 int pyy = (TILEY - ABS(syy)) * dy;
2135 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2136 element = Feld[next_jx][next_jy];
2138 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2139 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2141 /* draw background element under pushed element (like the Sokoban field) */
2142 if (Back[next_jx][next_jy])
2143 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2145 /* masked drawing is needed for EMC style (double) movement graphics */
2146 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2150 /* ----------------------------------------------------------------------- */
2151 /* draw things in front of player (active dynamite or dynabombs) */
2152 /* ----------------------------------------------------------------------- */
2154 if (IS_ACTIVE_BOMB(element))
2156 graphic = el2img(element);
2157 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2159 if (game.emulation == EMU_SUPAPLEX)
2160 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2162 DrawGraphicThruMask(sx, sy, graphic, frame);
2165 if (player_is_moving && last_element == EL_EXPLOSION)
2167 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2168 GfxElement[last_jx][last_jy] : EL_EMPTY);
2169 int graphic = el_act2img(element, ACTION_EXPLODING);
2170 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2171 int phase = ExplodePhase[last_jx][last_jy] - 1;
2172 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2175 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2178 /* ----------------------------------------------------------------------- */
2179 /* draw elements the player is just walking/passing through/under */
2180 /* ----------------------------------------------------------------------- */
2182 if (player_is_moving)
2184 /* handle the field the player is leaving ... */
2185 if (IS_ACCESSIBLE_INSIDE(last_element))
2186 DrawLevelField(last_jx, last_jy);
2187 else if (IS_ACCESSIBLE_UNDER(last_element))
2188 DrawLevelFieldThruMask(last_jx, last_jy);
2191 /* do not redraw accessible elements if the player is just pushing them */
2192 if (!player_is_moving || !player->is_pushing)
2194 /* ... and the field the player is entering */
2195 if (IS_ACCESSIBLE_INSIDE(element))
2196 DrawLevelField(jx, jy);
2197 else if (IS_ACCESSIBLE_UNDER(element))
2198 DrawLevelFieldThruMask(jx, jy);
2201 if (setup.direct_draw)
2203 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2204 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2205 int x_size = TILEX * (1 + ABS(jx - last_jx));
2206 int y_size = TILEY * (1 + ABS(jy - last_jy));
2208 BlitBitmap(drawto_field, window,
2209 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2210 SetDrawtoField(DRAW_DIRECT);
2213 MarkTileDirty(sx, sy);
2216 /* ------------------------------------------------------------------------- */
2218 void WaitForEventToContinue()
2220 boolean still_wait = TRUE;
2222 /* simulate releasing mouse button over last gadget, if still pressed */
2224 HandleGadgets(-1, -1, 0);
2226 button_status = MB_RELEASED;
2238 case EVENT_BUTTONPRESS:
2239 case EVENT_KEYPRESS:
2243 case EVENT_KEYRELEASE:
2244 ClearPlayerAction();
2248 HandleOtherEvents(&event);
2252 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2259 /* don't eat all CPU time */
2264 #define MAX_REQUEST_LINES 13
2265 #define MAX_REQUEST_LINE_FONT1_LEN 7
2266 #define MAX_REQUEST_LINE_FONT2_LEN 10
2268 boolean Request(char *text, unsigned int req_state)
2270 int mx, my, ty, result = -1;
2271 unsigned int old_door_state;
2272 int last_game_status = game_status; /* save current game status */
2273 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2274 int font_nr = FONT_TEXT_2;
2275 int max_word_len = 0;
2278 for (text_ptr = text; *text_ptr; text_ptr++)
2280 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2282 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2284 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2285 font_nr = FONT_LEVEL_NUMBER;
2291 if (game_status == GAME_MODE_PLAYING &&
2292 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2293 BlitScreenToBitmap_EM(backbuffer);
2295 /* disable deactivated drawing when quick-loading level tape recording */
2296 if (tape.playing && tape.deactivate_display)
2297 TapeDeactivateDisplayOff(TRUE);
2299 SetMouseCursor(CURSOR_DEFAULT);
2301 #if defined(NETWORK_AVALIABLE)
2302 /* pause network game while waiting for request to answer */
2303 if (options.network &&
2304 game_status == GAME_MODE_PLAYING &&
2305 req_state & REQUEST_WAIT_FOR_INPUT)
2306 SendToServer_PausePlaying();
2309 old_door_state = GetDoorState();
2311 /* simulate releasing mouse button over last gadget, if still pressed */
2313 HandleGadgets(-1, -1, 0);
2317 if (old_door_state & DOOR_OPEN_1)
2319 CloseDoor(DOOR_CLOSE_1);
2321 /* save old door content */
2322 BlitBitmap(bitmap_db_door, bitmap_db_door,
2323 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2324 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2327 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2329 /* clear door drawing field */
2330 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2332 /* force DOOR font on preview level */
2333 game_status = GAME_MODE_PSEUDO_DOOR;
2335 /* write text for request */
2336 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2338 char text_line[max_request_line_len + 1];
2344 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2347 if (!tc || tc == ' ')
2358 strncpy(text_line, text, tl);
2361 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2362 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2363 text_line, font_nr);
2365 text += tl + (tc == ' ' ? 1 : 0);
2368 game_status = last_game_status; /* restore current game status */
2370 if (req_state & REQ_ASK)
2372 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2373 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2375 else if (req_state & REQ_CONFIRM)
2377 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2379 else if (req_state & REQ_PLAYER)
2381 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2382 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2383 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2384 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2387 /* copy request gadgets to door backbuffer */
2388 BlitBitmap(drawto, bitmap_db_door,
2389 DX, DY, DXSIZE, DYSIZE,
2390 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2392 OpenDoor(DOOR_OPEN_1);
2394 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2396 SetDrawBackgroundMask(REDRAW_FIELD);
2401 if (game_status != GAME_MODE_MAIN)
2404 button_status = MB_RELEASED;
2406 request_gadget_id = -1;
2408 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2420 case EVENT_BUTTONPRESS:
2421 case EVENT_BUTTONRELEASE:
2422 case EVENT_MOTIONNOTIFY:
2424 if (event.type == EVENT_MOTIONNOTIFY)
2426 if (!PointerInWindow(window))
2427 continue; /* window and pointer are on different screens */
2432 motion_status = TRUE;
2433 mx = ((MotionEvent *) &event)->x;
2434 my = ((MotionEvent *) &event)->y;
2438 motion_status = FALSE;
2439 mx = ((ButtonEvent *) &event)->x;
2440 my = ((ButtonEvent *) &event)->y;
2441 if (event.type == EVENT_BUTTONPRESS)
2442 button_status = ((ButtonEvent *) &event)->button;
2444 button_status = MB_RELEASED;
2447 /* this sets 'request_gadget_id' */
2448 HandleGadgets(mx, my, button_status);
2450 switch(request_gadget_id)
2452 case TOOL_CTRL_ID_YES:
2455 case TOOL_CTRL_ID_NO:
2458 case TOOL_CTRL_ID_CONFIRM:
2459 result = TRUE | FALSE;
2462 case TOOL_CTRL_ID_PLAYER_1:
2465 case TOOL_CTRL_ID_PLAYER_2:
2468 case TOOL_CTRL_ID_PLAYER_3:
2471 case TOOL_CTRL_ID_PLAYER_4:
2482 case EVENT_KEYPRESS:
2483 switch(GetEventKey((KeyEvent *)&event, TRUE))
2496 if (req_state & REQ_PLAYER)
2500 case EVENT_KEYRELEASE:
2501 ClearPlayerAction();
2505 HandleOtherEvents(&event);
2509 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2511 int joy = AnyJoystick();
2513 if (joy & JOY_BUTTON_1)
2515 else if (joy & JOY_BUTTON_2)
2521 /* don't eat all CPU time */
2525 if (game_status != GAME_MODE_MAIN)
2530 if (!(req_state & REQ_STAY_OPEN))
2532 CloseDoor(DOOR_CLOSE_1);
2534 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2535 (req_state & REQ_REOPEN))
2536 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2541 SetDrawBackgroundMask(REDRAW_FIELD);
2543 #if defined(NETWORK_AVALIABLE)
2544 /* continue network game after request */
2545 if (options.network &&
2546 game_status == GAME_MODE_PLAYING &&
2547 req_state & REQUEST_WAIT_FOR_INPUT)
2548 SendToServer_ContinuePlaying();
2551 /* restore deactivated drawing when quick-loading level tape recording */
2552 if (tape.playing && tape.deactivate_display)
2553 TapeDeactivateDisplayOn();
2558 unsigned int OpenDoor(unsigned int door_state)
2560 if (door_state & DOOR_COPY_BACK)
2562 if (door_state & DOOR_OPEN_1)
2563 BlitBitmap(bitmap_db_door, bitmap_db_door,
2564 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2565 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2567 if (door_state & DOOR_OPEN_2)
2568 BlitBitmap(bitmap_db_door, bitmap_db_door,
2569 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2570 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2572 door_state &= ~DOOR_COPY_BACK;
2575 return MoveDoor(door_state);
2578 unsigned int CloseDoor(unsigned int door_state)
2580 unsigned int old_door_state = GetDoorState();
2582 if (!(door_state & DOOR_NO_COPY_BACK))
2584 if (old_door_state & DOOR_OPEN_1)
2585 BlitBitmap(backbuffer, bitmap_db_door,
2586 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2588 if (old_door_state & DOOR_OPEN_2)
2589 BlitBitmap(backbuffer, bitmap_db_door,
2590 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2592 door_state &= ~DOOR_NO_COPY_BACK;
2595 return MoveDoor(door_state);
2598 unsigned int GetDoorState()
2600 return MoveDoor(DOOR_GET_STATE);
2603 unsigned int SetDoorState(unsigned int door_state)
2605 return MoveDoor(door_state | DOOR_SET_STATE);
2608 unsigned int MoveDoor(unsigned int door_state)
2610 static int door1 = DOOR_OPEN_1;
2611 static int door2 = DOOR_CLOSE_2;
2612 unsigned long door_delay = 0;
2613 unsigned long door_delay_value;
2616 if (door_1.width < 0 || door_1.width > DXSIZE)
2617 door_1.width = DXSIZE;
2618 if (door_1.height < 0 || door_1.height > DYSIZE)
2619 door_1.height = DYSIZE;
2620 if (door_2.width < 0 || door_2.width > VXSIZE)
2621 door_2.width = VXSIZE;
2622 if (door_2.height < 0 || door_2.height > VYSIZE)
2623 door_2.height = VYSIZE;
2625 if (door_state == DOOR_GET_STATE)
2626 return (door1 | door2);
2628 if (door_state & DOOR_SET_STATE)
2630 if (door_state & DOOR_ACTION_1)
2631 door1 = door_state & DOOR_ACTION_1;
2632 if (door_state & DOOR_ACTION_2)
2633 door2 = door_state & DOOR_ACTION_2;
2635 return (door1 | door2);
2638 if (!(door_state & DOOR_FORCE_REDRAW))
2640 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2641 door_state &= ~DOOR_OPEN_1;
2642 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2643 door_state &= ~DOOR_CLOSE_1;
2644 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2645 door_state &= ~DOOR_OPEN_2;
2646 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2647 door_state &= ~DOOR_CLOSE_2;
2650 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2653 if (setup.quick_doors)
2655 stepsize = 20; /* must be choosen to always draw last frame */
2656 door_delay_value = 0;
2659 if (global.autoplay_leveldir)
2661 door_state |= DOOR_NO_DELAY;
2662 door_state &= ~DOOR_CLOSE_ALL;
2665 if (door_state & DOOR_ACTION)
2667 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2668 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2669 boolean door_1_done = (!handle_door_1);
2670 boolean door_2_done = (!handle_door_2);
2671 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2672 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2673 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2674 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2675 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2676 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2677 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2678 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2679 int door_skip = max_door_size - door_size;
2681 int end = door_size;
2683 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2687 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2689 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2693 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2695 /* opening door sound has priority over simultaneously closing door */
2696 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2697 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2698 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2699 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2702 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2705 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2706 GC gc = bitmap->stored_clip_gc;
2708 if (door_state & DOOR_ACTION_1)
2710 int a = MIN(x * door_1.step_offset, end);
2711 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2712 int i = p + door_skip;
2714 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2716 BlitBitmap(bitmap_db_door, drawto,
2717 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2718 DXSIZE, DYSIZE, DX, DY);
2722 BlitBitmap(bitmap_db_door, drawto,
2723 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2724 DXSIZE, DYSIZE - p / 2, DX, DY);
2726 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2729 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2731 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2732 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2733 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2734 int dst2_x = DX, dst2_y = DY;
2735 int width = i, height = DYSIZE;
2737 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2738 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2741 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2742 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2745 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2747 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2748 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2749 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2750 int dst2_x = DX, dst2_y = DY;
2751 int width = DXSIZE, height = i;
2753 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2754 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2757 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2758 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2761 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2763 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2765 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2766 BlitBitmapMasked(bitmap, drawto,
2767 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2768 DX + DXSIZE - i, DY + j);
2769 BlitBitmapMasked(bitmap, drawto,
2770 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2771 DX + DXSIZE - i, DY + 140 + j);
2772 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2773 DY - (DOOR_GFX_PAGEY1 + j));
2774 BlitBitmapMasked(bitmap, drawto,
2775 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2777 BlitBitmapMasked(bitmap, drawto,
2778 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2781 BlitBitmapMasked(bitmap, drawto,
2782 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2784 BlitBitmapMasked(bitmap, drawto,
2785 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2787 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2788 BlitBitmapMasked(bitmap, drawto,
2789 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2790 DX + DXSIZE - i, DY + 77 + j);
2791 BlitBitmapMasked(bitmap, drawto,
2792 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2793 DX + DXSIZE - i, DY + 203 + j);
2796 redraw_mask |= REDRAW_DOOR_1;
2797 door_1_done = (a == end);
2800 if (door_state & DOOR_ACTION_2)
2803 int a = MIN(x * door_2.step_offset, door_size);
2804 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2805 int i = p + door_skip;
2807 int a = MIN(x * door_2.step_offset, door_size_2);
2808 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2809 int i = p + door_skip;
2812 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2814 BlitBitmap(bitmap_db_door, drawto,
2815 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2816 VXSIZE, VYSIZE, VX, VY);
2818 else if (x <= VYSIZE)
2820 BlitBitmap(bitmap_db_door, drawto,
2821 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2822 VXSIZE, VYSIZE - p / 2, VX, VY);
2824 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2827 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2829 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2830 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2831 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2832 int dst2_x = VX, dst2_y = VY;
2833 int width = i, height = VYSIZE;
2835 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2836 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2839 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2840 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2843 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2845 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2846 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2847 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2848 int dst2_x = VX, dst2_y = VY;
2849 int width = VXSIZE, height = i;
2851 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2852 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2855 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2856 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2859 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2861 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2863 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2864 BlitBitmapMasked(bitmap, drawto,
2865 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2866 VX + VXSIZE - i, VY + j);
2867 SetClipOrigin(bitmap, gc,
2868 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2869 BlitBitmapMasked(bitmap, drawto,
2870 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2873 BlitBitmapMasked(bitmap, drawto,
2874 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2875 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2876 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2877 BlitBitmapMasked(bitmap, drawto,
2878 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2880 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2883 redraw_mask |= REDRAW_DOOR_2;
2884 door_2_done = (a == VXSIZE);
2887 if (!(door_state & DOOR_NO_DELAY))
2891 if (game_status == GAME_MODE_MAIN)
2894 WaitUntilDelayReached(&door_delay, door_delay_value);
2899 if (door_state & DOOR_ACTION_1)
2900 door1 = door_state & DOOR_ACTION_1;
2901 if (door_state & DOOR_ACTION_2)
2902 door2 = door_state & DOOR_ACTION_2;
2904 return (door1 | door2);
2907 void DrawSpecialEditorDoor()
2909 /* draw bigger toolbox window */
2910 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2911 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2913 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2914 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2917 redraw_mask |= REDRAW_ALL;
2920 void UndrawSpecialEditorDoor()
2922 /* draw normal tape recorder window */
2923 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2924 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2927 redraw_mask |= REDRAW_ALL;
2931 /* ---------- new tool button stuff ---------------------------------------- */
2933 /* graphic position values for tool buttons */
2934 #define TOOL_BUTTON_YES_XPOS 2
2935 #define TOOL_BUTTON_YES_YPOS 250
2936 #define TOOL_BUTTON_YES_GFX_YPOS 0
2937 #define TOOL_BUTTON_YES_XSIZE 46
2938 #define TOOL_BUTTON_YES_YSIZE 28
2939 #define TOOL_BUTTON_NO_XPOS 52
2940 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2941 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2942 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2943 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2944 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2945 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2946 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2947 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2948 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2949 #define TOOL_BUTTON_PLAYER_XSIZE 30
2950 #define TOOL_BUTTON_PLAYER_YSIZE 30
2951 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2952 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2953 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2954 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2955 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2956 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2957 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2958 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2959 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2960 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2961 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2962 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2963 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2964 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2965 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2966 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2967 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2968 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2969 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2970 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2979 } toolbutton_info[NUM_TOOL_BUTTONS] =
2982 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2983 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2984 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2989 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2990 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2991 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2996 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2997 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2998 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2999 TOOL_CTRL_ID_CONFIRM,
3003 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3004 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3005 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3006 TOOL_CTRL_ID_PLAYER_1,
3010 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3011 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3012 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3013 TOOL_CTRL_ID_PLAYER_2,
3017 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3018 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3019 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3020 TOOL_CTRL_ID_PLAYER_3,
3024 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3025 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3026 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3027 TOOL_CTRL_ID_PLAYER_4,
3032 void CreateToolButtons()
3036 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3038 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3039 Bitmap *deco_bitmap = None;
3040 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3041 struct GadgetInfo *gi;
3042 unsigned long event_mask;
3043 int gd_xoffset, gd_yoffset;
3044 int gd_x1, gd_x2, gd_y;
3047 event_mask = GD_EVENT_RELEASED;
3049 gd_xoffset = toolbutton_info[i].xpos;
3050 gd_yoffset = toolbutton_info[i].ypos;
3051 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3052 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3053 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3055 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3057 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3059 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3060 &deco_bitmap, &deco_x, &deco_y);
3061 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3062 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3065 gi = CreateGadget(GDI_CUSTOM_ID, id,
3066 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3067 GDI_X, DX + toolbutton_info[i].x,
3068 GDI_Y, DY + toolbutton_info[i].y,
3069 GDI_WIDTH, toolbutton_info[i].width,
3070 GDI_HEIGHT, toolbutton_info[i].height,
3071 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3072 GDI_STATE, GD_BUTTON_UNPRESSED,
3073 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3074 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3075 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3076 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3077 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3078 GDI_DECORATION_SHIFTING, 1, 1,
3079 GDI_EVENT_MASK, event_mask,
3080 GDI_CALLBACK_ACTION, HandleToolButtons,
3084 Error(ERR_EXIT, "cannot create gadget");
3086 tool_gadget[id] = gi;
3090 void FreeToolButtons()
3094 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3095 FreeGadget(tool_gadget[i]);
3098 static void UnmapToolButtons()
3102 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3103 UnmapGadget(tool_gadget[i]);
3106 static void HandleToolButtons(struct GadgetInfo *gi)
3108 request_gadget_id = gi->custom_id;
3111 static struct Mapping_EM_to_RND_object
3114 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3115 boolean is_backside; /* backside of moving element */
3121 em_object_mapping_list[] =
3124 Xblank, TRUE, FALSE,
3128 Yacid_splash_eB, FALSE, FALSE,
3129 EL_ACID_SPLASH_RIGHT, -1, -1
3132 Yacid_splash_wB, FALSE, FALSE,
3133 EL_ACID_SPLASH_LEFT, -1, -1
3136 #ifdef EM_ENGINE_BAD_ROLL
3138 Xstone_force_e, FALSE, FALSE,
3139 EL_ROCK, -1, MV_BIT_RIGHT
3142 Xstone_force_w, FALSE, FALSE,
3143 EL_ROCK, -1, MV_BIT_LEFT
3146 Xnut_force_e, FALSE, FALSE,
3147 EL_NUT, -1, MV_BIT_RIGHT
3150 Xnut_force_w, FALSE, FALSE,
3151 EL_NUT, -1, MV_BIT_LEFT
3154 Xspring_force_e, FALSE, FALSE,
3155 EL_SPRING, -1, MV_BIT_RIGHT
3158 Xspring_force_w, FALSE, FALSE,
3159 EL_SPRING, -1, MV_BIT_LEFT
3162 Xemerald_force_e, FALSE, FALSE,
3163 EL_EMERALD, -1, MV_BIT_RIGHT
3166 Xemerald_force_w, FALSE, FALSE,
3167 EL_EMERALD, -1, MV_BIT_LEFT
3170 Xdiamond_force_e, FALSE, FALSE,
3171 EL_DIAMOND, -1, MV_BIT_RIGHT
3174 Xdiamond_force_w, FALSE, FALSE,
3175 EL_DIAMOND, -1, MV_BIT_LEFT
3178 Xbomb_force_e, FALSE, FALSE,
3179 EL_BOMB, -1, MV_BIT_RIGHT
3182 Xbomb_force_w, FALSE, FALSE,
3183 EL_BOMB, -1, MV_BIT_LEFT
3185 #endif /* EM_ENGINE_BAD_ROLL */
3188 Xstone, TRUE, FALSE,
3192 Xstone_pause, FALSE, FALSE,
3196 Xstone_fall, FALSE, FALSE,
3200 Ystone_s, FALSE, FALSE,
3201 EL_ROCK, ACTION_FALLING, -1
3204 Ystone_sB, FALSE, TRUE,
3205 EL_ROCK, ACTION_FALLING, -1
3208 Ystone_e, FALSE, FALSE,
3209 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3212 Ystone_eB, FALSE, TRUE,
3213 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3216 Ystone_w, FALSE, FALSE,
3217 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3220 Ystone_wB, FALSE, TRUE,
3221 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3228 Xnut_pause, FALSE, FALSE,
3232 Xnut_fall, FALSE, FALSE,
3236 Ynut_s, FALSE, FALSE,
3237 EL_NUT, ACTION_FALLING, -1
3240 Ynut_sB, FALSE, TRUE,
3241 EL_NUT, ACTION_FALLING, -1
3244 Ynut_e, FALSE, FALSE,
3245 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3248 Ynut_eB, FALSE, TRUE,
3249 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3252 Ynut_w, FALSE, FALSE,
3253 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3256 Ynut_wB, FALSE, TRUE,
3257 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3260 Xbug_n, TRUE, FALSE,
3264 Xbug_e, TRUE, FALSE,
3265 EL_BUG_RIGHT, -1, -1
3268 Xbug_s, TRUE, FALSE,
3272 Xbug_w, TRUE, FALSE,
3276 Xbug_gon, FALSE, FALSE,
3280 Xbug_goe, FALSE, FALSE,
3281 EL_BUG_RIGHT, -1, -1
3284 Xbug_gos, FALSE, FALSE,
3288 Xbug_gow, FALSE, FALSE,
3292 Ybug_n, FALSE, FALSE,
3293 EL_BUG, ACTION_MOVING, MV_BIT_UP
3296 Ybug_nB, FALSE, TRUE,
3297 EL_BUG, ACTION_MOVING, MV_BIT_UP
3300 Ybug_e, FALSE, FALSE,
3301 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3304 Ybug_eB, FALSE, TRUE,
3305 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3308 Ybug_s, FALSE, FALSE,
3309 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3312 Ybug_sB, FALSE, TRUE,
3313 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3316 Ybug_w, FALSE, FALSE,
3317 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3320 Ybug_wB, FALSE, TRUE,
3321 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3324 Ybug_w_n, FALSE, FALSE,
3325 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3328 Ybug_n_e, FALSE, FALSE,
3329 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3332 Ybug_e_s, FALSE, FALSE,
3333 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3336 Ybug_s_w, FALSE, FALSE,
3337 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3340 Ybug_e_n, FALSE, FALSE,
3341 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3344 Ybug_s_e, FALSE, FALSE,
3345 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3348 Ybug_w_s, FALSE, FALSE,
3349 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3352 Ybug_n_w, FALSE, FALSE,
3353 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3356 Ybug_stone, FALSE, FALSE,
3357 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3360 Ybug_spring, FALSE, FALSE,
3361 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3364 Xtank_n, TRUE, FALSE,
3365 EL_SPACESHIP_UP, -1, -1
3368 Xtank_e, TRUE, FALSE,
3369 EL_SPACESHIP_RIGHT, -1, -1
3372 Xtank_s, TRUE, FALSE,
3373 EL_SPACESHIP_DOWN, -1, -1
3376 Xtank_w, TRUE, FALSE,
3377 EL_SPACESHIP_LEFT, -1, -1
3380 Xtank_gon, FALSE, FALSE,
3381 EL_SPACESHIP_UP, -1, -1
3384 Xtank_goe, FALSE, FALSE,
3385 EL_SPACESHIP_RIGHT, -1, -1
3388 Xtank_gos, FALSE, FALSE,
3389 EL_SPACESHIP_DOWN, -1, -1
3392 Xtank_gow, FALSE, FALSE,
3393 EL_SPACESHIP_LEFT, -1, -1
3396 Ytank_n, FALSE, FALSE,
3397 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3400 Ytank_nB, FALSE, TRUE,
3401 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3404 Ytank_e, FALSE, FALSE,
3405 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3408 Ytank_eB, FALSE, TRUE,
3409 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3412 Ytank_s, FALSE, FALSE,
3413 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3416 Ytank_sB, FALSE, TRUE,
3417 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3420 Ytank_w, FALSE, FALSE,
3421 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3424 Ytank_wB, FALSE, TRUE,
3425 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3428 Ytank_w_n, FALSE, FALSE,
3429 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3432 Ytank_n_e, FALSE, FALSE,
3433 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3436 Ytank_e_s, FALSE, FALSE,
3437 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3440 Ytank_s_w, FALSE, FALSE,
3441 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3444 Ytank_e_n, FALSE, FALSE,
3445 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3448 Ytank_s_e, FALSE, FALSE,
3449 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3452 Ytank_w_s, FALSE, FALSE,
3453 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3456 Ytank_n_w, FALSE, FALSE,
3457 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3460 Ytank_stone, FALSE, FALSE,
3461 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3464 Ytank_spring, FALSE, FALSE,
3465 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3468 Xandroid, TRUE, FALSE,
3469 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3472 Xandroid_1_n, FALSE, FALSE,
3473 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3476 Xandroid_2_n, FALSE, FALSE,
3477 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3480 Xandroid_1_e, FALSE, FALSE,
3481 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3484 Xandroid_2_e, FALSE, FALSE,
3485 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3488 Xandroid_1_w, FALSE, FALSE,
3489 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3492 Xandroid_2_w, FALSE, FALSE,
3493 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3496 Xandroid_1_s, FALSE, FALSE,
3497 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3500 Xandroid_2_s, FALSE, FALSE,
3501 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3504 Yandroid_n, FALSE, FALSE,
3505 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3508 Yandroid_nB, FALSE, TRUE,
3509 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3512 Yandroid_ne, FALSE, FALSE,
3513 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3516 Yandroid_neB, FALSE, TRUE,
3517 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3520 Yandroid_e, FALSE, FALSE,
3521 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3524 Yandroid_eB, FALSE, TRUE,
3525 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3528 Yandroid_se, FALSE, FALSE,
3529 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3532 Yandroid_seB, FALSE, TRUE,
3533 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3536 Yandroid_s, FALSE, FALSE,
3537 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3540 Yandroid_sB, FALSE, TRUE,
3541 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3544 Yandroid_sw, FALSE, FALSE,
3545 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3548 Yandroid_swB, FALSE, TRUE,
3549 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3552 Yandroid_w, FALSE, FALSE,
3553 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3556 Yandroid_wB, FALSE, TRUE,
3557 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3560 Yandroid_nw, FALSE, FALSE,
3561 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3564 Yandroid_nwB, FALSE, TRUE,
3565 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3568 Xspring, TRUE, FALSE,
3572 Xspring_pause, FALSE, FALSE,
3576 Xspring_e, FALSE, FALSE,
3580 Xspring_w, FALSE, FALSE,
3584 Xspring_fall, FALSE, FALSE,
3588 Yspring_s, FALSE, FALSE,
3589 EL_SPRING, ACTION_FALLING, -1
3592 Yspring_sB, FALSE, TRUE,
3593 EL_SPRING, ACTION_FALLING, -1
3596 Yspring_e, FALSE, FALSE,
3597 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3600 Yspring_eB, FALSE, TRUE,
3601 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3604 Yspring_w, FALSE, FALSE,
3605 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3608 Yspring_wB, FALSE, TRUE,
3609 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3612 Yspring_kill_e, FALSE, FALSE,
3613 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3616 Yspring_kill_eB, FALSE, TRUE,
3617 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3620 Yspring_kill_w, FALSE, FALSE,
3621 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3624 Yspring_kill_wB, FALSE, TRUE,
3625 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3628 Xeater_n, TRUE, FALSE,
3629 EL_YAMYAM_UP, -1, -1
3632 Xeater_e, TRUE, FALSE,
3633 EL_YAMYAM_RIGHT, -1, -1
3636 Xeater_w, TRUE, FALSE,
3637 EL_YAMYAM_LEFT, -1, -1
3640 Xeater_s, TRUE, FALSE,
3641 EL_YAMYAM_DOWN, -1, -1
3644 Yeater_n, FALSE, FALSE,
3645 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3648 Yeater_nB, FALSE, TRUE,
3649 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3652 Yeater_e, FALSE, FALSE,
3653 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3656 Yeater_eB, FALSE, TRUE,
3657 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3660 Yeater_s, FALSE, FALSE,
3661 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3664 Yeater_sB, FALSE, TRUE,
3665 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3668 Yeater_w, FALSE, FALSE,
3669 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3672 Yeater_wB, FALSE, TRUE,
3673 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3676 Yeater_stone, FALSE, FALSE,
3677 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3680 Yeater_spring, FALSE, FALSE,
3681 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3684 Xalien, TRUE, FALSE,
3688 Xalien_pause, FALSE, FALSE,
3692 Yalien_n, FALSE, FALSE,
3693 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3696 Yalien_nB, FALSE, TRUE,
3697 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3700 Yalien_e, FALSE, FALSE,
3701 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3704 Yalien_eB, FALSE, TRUE,
3705 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3708 Yalien_s, FALSE, FALSE,
3709 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3712 Yalien_sB, FALSE, TRUE,
3713 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3716 Yalien_w, FALSE, FALSE,
3717 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3720 Yalien_wB, FALSE, TRUE,
3721 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3724 Yalien_stone, FALSE, FALSE,
3725 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3728 Yalien_spring, FALSE, FALSE,
3729 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3732 Xemerald, TRUE, FALSE,
3736 Xemerald_pause, FALSE, FALSE,
3740 Xemerald_fall, FALSE, FALSE,
3744 Xemerald_shine, FALSE, FALSE,
3745 EL_EMERALD, ACTION_TWINKLING, -1
3748 Yemerald_s, FALSE, FALSE,
3749 EL_EMERALD, ACTION_FALLING, -1
3752 Yemerald_sB, FALSE, TRUE,
3753 EL_EMERALD, ACTION_FALLING, -1
3756 Yemerald_e, FALSE, FALSE,
3757 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3760 Yemerald_eB, FALSE, TRUE,
3761 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3764 Yemerald_w, FALSE, FALSE,
3765 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3768 Yemerald_wB, FALSE, TRUE,
3769 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3772 Yemerald_eat, FALSE, FALSE,
3773 EL_EMERALD, ACTION_COLLECTING, -1
3776 Yemerald_stone, FALSE, FALSE,
3777 EL_NUT, ACTION_BREAKING, -1
3780 Xdiamond, TRUE, FALSE,
3784 Xdiamond_pause, FALSE, FALSE,
3788 Xdiamond_fall, FALSE, FALSE,
3792 Xdiamond_shine, FALSE, FALSE,
3793 EL_DIAMOND, ACTION_TWINKLING, -1
3796 Ydiamond_s, FALSE, FALSE,
3797 EL_DIAMOND, ACTION_FALLING, -1
3800 Ydiamond_sB, FALSE, TRUE,
3801 EL_DIAMOND, ACTION_FALLING, -1
3804 Ydiamond_e, FALSE, FALSE,
3805 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3808 Ydiamond_eB, FALSE, TRUE,
3809 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3812 Ydiamond_w, FALSE, FALSE,
3813 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3816 Ydiamond_wB, FALSE, TRUE,
3817 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3820 Ydiamond_eat, FALSE, FALSE,
3821 EL_DIAMOND, ACTION_COLLECTING, -1
3824 Ydiamond_stone, FALSE, FALSE,
3825 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3828 Xdrip_fall, TRUE, FALSE,
3829 EL_AMOEBA_DROP, -1, -1
3832 Xdrip_stretch, FALSE, FALSE,
3833 EL_AMOEBA_DROP, ACTION_FALLING, -1
3836 Xdrip_stretchB, FALSE, TRUE,
3837 EL_AMOEBA_DROP, ACTION_FALLING, -1
3840 Xdrip_eat, FALSE, FALSE,
3841 EL_AMOEBA_DROP, ACTION_GROWING, -1
3844 Ydrip_s1, FALSE, FALSE,
3845 EL_AMOEBA_DROP, ACTION_FALLING, -1
3848 Ydrip_s1B, FALSE, TRUE,
3849 EL_AMOEBA_DROP, ACTION_FALLING, -1
3852 Ydrip_s2, FALSE, FALSE,
3853 EL_AMOEBA_DROP, ACTION_FALLING, -1
3856 Ydrip_s2B, FALSE, TRUE,
3857 EL_AMOEBA_DROP, ACTION_FALLING, -1
3864 Xbomb_pause, FALSE, FALSE,
3868 Xbomb_fall, FALSE, FALSE,
3872 Ybomb_s, FALSE, FALSE,
3873 EL_BOMB, ACTION_FALLING, -1
3876 Ybomb_sB, FALSE, TRUE,
3877 EL_BOMB, ACTION_FALLING, -1
3880 Ybomb_e, FALSE, FALSE,
3881 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3884 Ybomb_eB, FALSE, TRUE,
3885 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3888 Ybomb_w, FALSE, FALSE,
3889 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3892 Ybomb_wB, FALSE, TRUE,
3893 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3896 Ybomb_eat, FALSE, FALSE,
3897 EL_BOMB, ACTION_ACTIVATING, -1
3900 Xballoon, TRUE, FALSE,
3904 Yballoon_n, FALSE, FALSE,
3905 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3908 Yballoon_nB, FALSE, TRUE,
3909 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3912 Yballoon_e, FALSE, FALSE,
3913 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3916 Yballoon_eB, FALSE, TRUE,
3917 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3920 Yballoon_s, FALSE, FALSE,
3921 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3924 Yballoon_sB, FALSE, TRUE,
3925 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3928 Yballoon_w, FALSE, FALSE,
3929 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3932 Yballoon_wB, FALSE, TRUE,
3933 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3936 Xgrass, TRUE, FALSE,
3937 EL_EMC_GRASS, -1, -1
3940 Ygrass_nB, FALSE, FALSE,
3941 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3944 Ygrass_eB, FALSE, FALSE,
3945 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3948 Ygrass_sB, FALSE, FALSE,
3949 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3952 Ygrass_wB, FALSE, FALSE,
3953 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3960 Ydirt_nB, FALSE, FALSE,
3961 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3964 Ydirt_eB, FALSE, FALSE,
3965 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3968 Ydirt_sB, FALSE, FALSE,
3969 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3972 Ydirt_wB, FALSE, FALSE,
3973 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3976 Xacid_ne, TRUE, FALSE,
3977 EL_ACID_POOL_TOPRIGHT, -1, -1
3980 Xacid_se, TRUE, FALSE,
3981 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3984 Xacid_s, TRUE, FALSE,
3985 EL_ACID_POOL_BOTTOM, -1, -1
3988 Xacid_sw, TRUE, FALSE,
3989 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3992 Xacid_nw, TRUE, FALSE,
3993 EL_ACID_POOL_TOPLEFT, -1, -1
3996 Xacid_1, TRUE, FALSE,
4000 Xacid_2, FALSE, FALSE,
4004 Xacid_3, FALSE, FALSE,
4008 Xacid_4, FALSE, FALSE,
4012 Xacid_5, FALSE, FALSE,
4016 Xacid_6, FALSE, FALSE,
4020 Xacid_7, FALSE, FALSE,
4024 Xacid_8, FALSE, FALSE,
4028 Xball_1, TRUE, FALSE,
4029 EL_EMC_MAGIC_BALL, -1, -1
4032 Xball_1B, FALSE, FALSE,
4033 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4036 Xball_2, FALSE, FALSE,
4037 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4040 Xball_2B, FALSE, FALSE,
4041 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4044 Yball_eat, FALSE, FALSE,
4045 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4048 Ykey_1_eat, FALSE, FALSE,
4049 EL_EM_KEY_1, ACTION_COLLECTING, -1
4052 Ykey_2_eat, FALSE, FALSE,
4053 EL_EM_KEY_2, ACTION_COLLECTING, -1
4056 Ykey_3_eat, FALSE, FALSE,
4057 EL_EM_KEY_3, ACTION_COLLECTING, -1
4060 Ykey_4_eat, FALSE, FALSE,
4061 EL_EM_KEY_4, ACTION_COLLECTING, -1
4064 Ykey_5_eat, FALSE, FALSE,
4065 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4068 Ykey_6_eat, FALSE, FALSE,
4069 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4072 Ykey_7_eat, FALSE, FALSE,
4073 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4076 Ykey_8_eat, FALSE, FALSE,
4077 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4080 Ylenses_eat, FALSE, FALSE,
4081 EL_EMC_LENSES, ACTION_COLLECTING, -1
4084 Ymagnify_eat, FALSE, FALSE,
4085 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4088 Ygrass_eat, FALSE, FALSE,
4089 EL_EMC_GRASS, ACTION_SNAPPING, -1
4092 Ydirt_eat, FALSE, FALSE,
4093 EL_SAND, ACTION_SNAPPING, -1
4096 Xgrow_ns, TRUE, FALSE,
4097 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4100 Ygrow_ns_eat, FALSE, FALSE,
4101 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4104 Xgrow_ew, TRUE, FALSE,
4105 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4108 Ygrow_ew_eat, FALSE, FALSE,
4109 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4112 Xwonderwall, TRUE, FALSE,
4113 EL_MAGIC_WALL, -1, -1
4116 XwonderwallB, FALSE, FALSE,
4117 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4120 Xamoeba_1, TRUE, FALSE,
4121 EL_AMOEBA_DRY, ACTION_OTHER, -1
4124 Xamoeba_2, FALSE, FALSE,
4125 EL_AMOEBA_DRY, ACTION_OTHER, -1
4128 Xamoeba_3, FALSE, FALSE,
4129 EL_AMOEBA_DRY, ACTION_OTHER, -1
4132 Xamoeba_4, FALSE, FALSE,
4133 EL_AMOEBA_DRY, ACTION_OTHER, -1
4136 Xamoeba_5, TRUE, FALSE,
4137 EL_AMOEBA_WET, ACTION_OTHER, -1
4140 Xamoeba_6, FALSE, FALSE,
4141 EL_AMOEBA_WET, ACTION_OTHER, -1
4144 Xamoeba_7, FALSE, FALSE,
4145 EL_AMOEBA_WET, ACTION_OTHER, -1
4148 Xamoeba_8, FALSE, FALSE,
4149 EL_AMOEBA_WET, ACTION_OTHER, -1
4152 Xdoor_1, TRUE, FALSE,
4153 EL_EM_GATE_1, -1, -1
4156 Xdoor_2, TRUE, FALSE,
4157 EL_EM_GATE_2, -1, -1
4160 Xdoor_3, TRUE, FALSE,
4161 EL_EM_GATE_3, -1, -1
4164 Xdoor_4, TRUE, FALSE,
4165 EL_EM_GATE_4, -1, -1
4168 Xdoor_5, TRUE, FALSE,
4169 EL_EMC_GATE_5, -1, -1
4172 Xdoor_6, TRUE, FALSE,
4173 EL_EMC_GATE_6, -1, -1
4176 Xdoor_7, TRUE, FALSE,
4177 EL_EMC_GATE_7, -1, -1
4180 Xdoor_8, TRUE, FALSE,
4181 EL_EMC_GATE_8, -1, -1
4184 Xkey_1, TRUE, FALSE,
4188 Xkey_2, TRUE, FALSE,
4192 Xkey_3, TRUE, FALSE,
4196 Xkey_4, TRUE, FALSE,
4200 Xkey_5, TRUE, FALSE,
4201 EL_EMC_KEY_5, -1, -1
4204 Xkey_6, TRUE, FALSE,
4205 EL_EMC_KEY_6, -1, -1
4208 Xkey_7, TRUE, FALSE,
4209 EL_EMC_KEY_7, -1, -1
4212 Xkey_8, TRUE, FALSE,
4213 EL_EMC_KEY_8, -1, -1
4216 Xwind_n, TRUE, FALSE,
4217 EL_BALLOON_SWITCH_UP, -1, -1
4220 Xwind_e, TRUE, FALSE,
4221 EL_BALLOON_SWITCH_RIGHT, -1, -1
4224 Xwind_s, TRUE, FALSE,
4225 EL_BALLOON_SWITCH_DOWN, -1, -1
4228 Xwind_w, TRUE, FALSE,
4229 EL_BALLOON_SWITCH_LEFT, -1, -1
4232 Xwind_nesw, TRUE, FALSE,
4233 EL_BALLOON_SWITCH_ANY, -1, -1
4236 Xwind_stop, TRUE, FALSE,
4237 EL_BALLOON_SWITCH_NONE, -1, -1
4241 EL_EXIT_CLOSED, -1, -1
4244 Xexit_1, TRUE, FALSE,
4245 EL_EXIT_OPEN, -1, -1
4248 Xexit_2, FALSE, FALSE,
4249 EL_EXIT_OPEN, -1, -1
4252 Xexit_3, FALSE, FALSE,
4253 EL_EXIT_OPEN, -1, -1
4256 Xdynamite, TRUE, FALSE,
4257 EL_EM_DYNAMITE, -1, -1
4260 Ydynamite_eat, FALSE, FALSE,
4261 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4264 Xdynamite_1, TRUE, FALSE,
4265 EL_EM_DYNAMITE_ACTIVE, -1, -1
4268 Xdynamite_2, FALSE, FALSE,
4269 EL_EM_DYNAMITE_ACTIVE, -1, -1
4272 Xdynamite_3, FALSE, FALSE,
4273 EL_EM_DYNAMITE_ACTIVE, -1, -1
4276 Xdynamite_4, FALSE, FALSE,
4277 EL_EM_DYNAMITE_ACTIVE, -1, -1
4280 Xbumper, TRUE, FALSE,
4281 EL_EMC_SPRING_BUMPER, -1, -1
4284 XbumperB, FALSE, FALSE,
4285 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4288 Xwheel, TRUE, FALSE,
4289 EL_ROBOT_WHEEL, -1, -1
4292 XwheelB, FALSE, FALSE,
4293 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4296 Xswitch, TRUE, FALSE,
4297 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4300 XswitchB, FALSE, FALSE,
4301 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4305 EL_QUICKSAND_EMPTY, -1, -1
4308 Xsand_stone, TRUE, FALSE,
4309 EL_QUICKSAND_FULL, -1, -1
4312 Xsand_stonein_1, FALSE, TRUE,
4313 EL_ROCK, ACTION_FILLING, -1
4316 Xsand_stonein_2, FALSE, TRUE,
4317 EL_ROCK, ACTION_FILLING, -1
4320 Xsand_stonein_3, FALSE, TRUE,
4321 EL_ROCK, ACTION_FILLING, -1
4324 Xsand_stonein_4, FALSE, TRUE,
4325 EL_ROCK, ACTION_FILLING, -1
4328 Xsand_stonesand_1, FALSE, FALSE,
4329 EL_QUICKSAND_FULL, -1, -1
4332 Xsand_stonesand_2, FALSE, FALSE,
4333 EL_QUICKSAND_FULL, -1, -1
4336 Xsand_stonesand_3, FALSE, FALSE,
4337 EL_QUICKSAND_FULL, -1, -1
4340 Xsand_stonesand_4, FALSE, FALSE,
4341 EL_QUICKSAND_FULL, -1, -1
4344 Xsand_stoneout_1, FALSE, FALSE,
4345 EL_ROCK, ACTION_EMPTYING, -1
4348 Xsand_stoneout_2, FALSE, FALSE,
4349 EL_ROCK, ACTION_EMPTYING, -1
4352 Xsand_sandstone_1, FALSE, FALSE,
4353 EL_QUICKSAND_FULL, -1, -1
4356 Xsand_sandstone_2, FALSE, FALSE,
4357 EL_QUICKSAND_FULL, -1, -1
4360 Xsand_sandstone_3, FALSE, FALSE,
4361 EL_QUICKSAND_FULL, -1, -1
4364 Xsand_sandstone_4, FALSE, FALSE,
4365 EL_QUICKSAND_FULL, -1, -1
4368 Xplant, TRUE, FALSE,
4369 EL_EMC_PLANT, -1, -1
4372 Yplant, FALSE, FALSE,
4373 EL_EMC_PLANT, -1, -1
4376 Xlenses, TRUE, FALSE,
4377 EL_EMC_LENSES, -1, -1
4380 Xmagnify, TRUE, FALSE,
4381 EL_EMC_MAGNIFIER, -1, -1
4384 Xdripper, TRUE, FALSE,
4385 EL_EMC_DRIPPER, -1, -1
4388 XdripperB, FALSE, FALSE,
4389 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4392 Xfake_blank, TRUE, FALSE,
4393 EL_INVISIBLE_WALL, -1, -1
4396 Xfake_blankB, FALSE, FALSE,
4397 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4400 Xfake_grass, TRUE, FALSE,
4401 EL_EMC_FAKE_GRASS, -1, -1
4404 Xfake_grassB, FALSE, FALSE,
4405 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4408 Xfake_door_1, TRUE, FALSE,
4409 EL_EM_GATE_1_GRAY, -1, -1
4412 Xfake_door_2, TRUE, FALSE,
4413 EL_EM_GATE_2_GRAY, -1, -1
4416 Xfake_door_3, TRUE, FALSE,
4417 EL_EM_GATE_3_GRAY, -1, -1
4420 Xfake_door_4, TRUE, FALSE,
4421 EL_EM_GATE_4_GRAY, -1, -1
4424 Xfake_door_5, TRUE, FALSE,
4425 EL_EMC_GATE_5_GRAY, -1, -1
4428 Xfake_door_6, TRUE, FALSE,
4429 EL_EMC_GATE_6_GRAY, -1, -1
4432 Xfake_door_7, TRUE, FALSE,
4433 EL_EMC_GATE_7_GRAY, -1, -1
4436 Xfake_door_8, TRUE, FALSE,
4437 EL_EMC_GATE_8_GRAY, -1, -1
4440 Xfake_acid_1, TRUE, FALSE,
4441 EL_EMC_FAKE_ACID, -1, -1
4444 Xfake_acid_2, FALSE, FALSE,
4445 EL_EMC_FAKE_ACID, -1, -1
4448 Xfake_acid_3, FALSE, FALSE,
4449 EL_EMC_FAKE_ACID, -1, -1
4452 Xfake_acid_4, FALSE, FALSE,
4453 EL_EMC_FAKE_ACID, -1, -1
4456 Xfake_acid_5, FALSE, FALSE,
4457 EL_EMC_FAKE_ACID, -1, -1
4460 Xfake_acid_6, FALSE, FALSE,
4461 EL_EMC_FAKE_ACID, -1, -1
4464 Xfake_acid_7, FALSE, FALSE,
4465 EL_EMC_FAKE_ACID, -1, -1
4468 Xfake_acid_8, FALSE, FALSE,
4469 EL_EMC_FAKE_ACID, -1, -1
4472 Xsteel_1, TRUE, FALSE,
4473 EL_STEELWALL, -1, -1
4476 Xsteel_2, TRUE, FALSE,
4477 EL_EMC_STEELWALL_2, -1, -1
4480 Xsteel_3, TRUE, FALSE,
4481 EL_EMC_STEELWALL_3, -1, -1
4484 Xsteel_4, TRUE, FALSE,
4485 EL_EMC_STEELWALL_4, -1, -1
4488 Xwall_1, TRUE, FALSE,
4492 Xwall_2, TRUE, FALSE,
4493 EL_EMC_WALL_14, -1, -1
4496 Xwall_3, TRUE, FALSE,
4497 EL_EMC_WALL_15, -1, -1
4500 Xwall_4, TRUE, FALSE,
4501 EL_EMC_WALL_16, -1, -1
4504 Xround_wall_1, TRUE, FALSE,
4505 EL_WALL_SLIPPERY, -1, -1
4508 Xround_wall_2, TRUE, FALSE,
4509 EL_EMC_WALL_SLIPPERY_2, -1, -1
4512 Xround_wall_3, TRUE, FALSE,
4513 EL_EMC_WALL_SLIPPERY_3, -1, -1
4516 Xround_wall_4, TRUE, FALSE,
4517 EL_EMC_WALL_SLIPPERY_4, -1, -1
4520 Xdecor_1, TRUE, FALSE,
4521 EL_EMC_WALL_8, -1, -1
4524 Xdecor_2, TRUE, FALSE,
4525 EL_EMC_WALL_6, -1, -1
4528 Xdecor_3, TRUE, FALSE,
4529 EL_EMC_WALL_4, -1, -1
4532 Xdecor_4, TRUE, FALSE,
4533 EL_EMC_WALL_7, -1, -1
4536 Xdecor_5, TRUE, FALSE,
4537 EL_EMC_WALL_5, -1, -1
4540 Xdecor_6, TRUE, FALSE,
4541 EL_EMC_WALL_9, -1, -1
4544 Xdecor_7, TRUE, FALSE,
4545 EL_EMC_WALL_10, -1, -1
4548 Xdecor_8, TRUE, FALSE,
4549 EL_EMC_WALL_1, -1, -1
4552 Xdecor_9, TRUE, FALSE,
4553 EL_EMC_WALL_2, -1, -1
4556 Xdecor_10, TRUE, FALSE,
4557 EL_EMC_WALL_3, -1, -1
4560 Xdecor_11, TRUE, FALSE,
4561 EL_EMC_WALL_11, -1, -1
4564 Xdecor_12, TRUE, FALSE,
4565 EL_EMC_WALL_12, -1, -1
4568 Xalpha_0, TRUE, FALSE,
4569 EL_CHAR('0'), -1, -1
4572 Xalpha_1, TRUE, FALSE,
4573 EL_CHAR('1'), -1, -1
4576 Xalpha_2, TRUE, FALSE,
4577 EL_CHAR('2'), -1, -1
4580 Xalpha_3, TRUE, FALSE,
4581 EL_CHAR('3'), -1, -1
4584 Xalpha_4, TRUE, FALSE,
4585 EL_CHAR('4'), -1, -1
4588 Xalpha_5, TRUE, FALSE,
4589 EL_CHAR('5'), -1, -1
4592 Xalpha_6, TRUE, FALSE,
4593 EL_CHAR('6'), -1, -1
4596 Xalpha_7, TRUE, FALSE,
4597 EL_CHAR('7'), -1, -1
4600 Xalpha_8, TRUE, FALSE,
4601 EL_CHAR('8'), -1, -1
4604 Xalpha_9, TRUE, FALSE,
4605 EL_CHAR('9'), -1, -1
4608 Xalpha_excla, TRUE, FALSE,
4609 EL_CHAR('!'), -1, -1
4612 Xalpha_quote, TRUE, FALSE,
4613 EL_CHAR('"'), -1, -1
4616 Xalpha_comma, TRUE, FALSE,
4617 EL_CHAR(','), -1, -1
4620 Xalpha_minus, TRUE, FALSE,
4621 EL_CHAR('-'), -1, -1
4624 Xalpha_perio, TRUE, FALSE,
4625 EL_CHAR('.'), -1, -1
4628 Xalpha_colon, TRUE, FALSE,
4629 EL_CHAR(':'), -1, -1
4632 Xalpha_quest, TRUE, FALSE,
4633 EL_CHAR('?'), -1, -1
4636 Xalpha_a, TRUE, FALSE,
4637 EL_CHAR('A'), -1, -1
4640 Xalpha_b, TRUE, FALSE,
4641 EL_CHAR('B'), -1, -1
4644 Xalpha_c, TRUE, FALSE,
4645 EL_CHAR('C'), -1, -1
4648 Xalpha_d, TRUE, FALSE,
4649 EL_CHAR('D'), -1, -1
4652 Xalpha_e, TRUE, FALSE,
4653 EL_CHAR('E'), -1, -1
4656 Xalpha_f, TRUE, FALSE,
4657 EL_CHAR('F'), -1, -1
4660 Xalpha_g, TRUE, FALSE,
4661 EL_CHAR('G'), -1, -1
4664 Xalpha_h, TRUE, FALSE,
4665 EL_CHAR('H'), -1, -1
4668 Xalpha_i, TRUE, FALSE,
4669 EL_CHAR('I'), -1, -1
4672 Xalpha_j, TRUE, FALSE,
4673 EL_CHAR('J'), -1, -1
4676 Xalpha_k, TRUE, FALSE,
4677 EL_CHAR('K'), -1, -1
4680 Xalpha_l, TRUE, FALSE,
4681 EL_CHAR('L'), -1, -1
4684 Xalpha_m, TRUE, FALSE,
4685 EL_CHAR('M'), -1, -1
4688 Xalpha_n, TRUE, FALSE,
4689 EL_CHAR('N'), -1, -1
4692 Xalpha_o, TRUE, FALSE,
4693 EL_CHAR('O'), -1, -1
4696 Xalpha_p, TRUE, FALSE,
4697 EL_CHAR('P'), -1, -1
4700 Xalpha_q, TRUE, FALSE,
4701 EL_CHAR('Q'), -1, -1
4704 Xalpha_r, TRUE, FALSE,
4705 EL_CHAR('R'), -1, -1
4708 Xalpha_s, TRUE, FALSE,
4709 EL_CHAR('S'), -1, -1
4712 Xalpha_t, TRUE, FALSE,
4713 EL_CHAR('T'), -1, -1
4716 Xalpha_u, TRUE, FALSE,
4717 EL_CHAR('U'), -1, -1
4720 Xalpha_v, TRUE, FALSE,
4721 EL_CHAR('V'), -1, -1
4724 Xalpha_w, TRUE, FALSE,
4725 EL_CHAR('W'), -1, -1
4728 Xalpha_x, TRUE, FALSE,
4729 EL_CHAR('X'), -1, -1
4732 Xalpha_y, TRUE, FALSE,
4733 EL_CHAR('Y'), -1, -1
4736 Xalpha_z, TRUE, FALSE,
4737 EL_CHAR('Z'), -1, -1
4740 Xalpha_arrow_e, TRUE, FALSE,
4741 EL_CHAR('>'), -1, -1
4744 Xalpha_arrow_w, TRUE, FALSE,
4745 EL_CHAR('<'), -1, -1
4748 Xalpha_copyr, TRUE, FALSE,
4749 EL_CHAR('©'), -1, -1
4753 Xboom_bug, FALSE, FALSE,
4754 EL_BUG, ACTION_EXPLODING, -1
4757 Xboom_bomb, FALSE, FALSE,
4758 EL_BOMB, ACTION_EXPLODING, -1
4761 Xboom_android, FALSE, FALSE,
4762 EL_EMC_ANDROID, ACTION_OTHER, -1
4765 Xboom_1, FALSE, FALSE,
4766 EL_DEFAULT, ACTION_EXPLODING, -1
4769 Xboom_2, FALSE, FALSE,
4770 EL_DEFAULT, ACTION_EXPLODING, -1
4773 Znormal, FALSE, FALSE,
4777 Zdynamite, FALSE, FALSE,
4781 Zplayer, FALSE, FALSE,
4785 ZBORDER, FALSE, FALSE,
4795 static struct Mapping_EM_to_RND_player
4804 em_player_mapping_list[] =
4808 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4812 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4816 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4820 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4824 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4828 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4832 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4836 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4840 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4844 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4848 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4852 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4856 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4860 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4864 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4868 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4872 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4876 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4880 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4884 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4888 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4892 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4896 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4900 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4904 EL_PLAYER_1, ACTION_DEFAULT, -1,
4908 EL_PLAYER_2, ACTION_DEFAULT, -1,
4912 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4916 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4920 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4924 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4928 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4932 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4936 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4940 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4944 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4948 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4952 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4956 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4960 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4964 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4968 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4972 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4976 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4980 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4984 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4988 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4992 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4996 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5000 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5004 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5008 EL_PLAYER_3, ACTION_DEFAULT, -1,
5012 EL_PLAYER_4, ACTION_DEFAULT, -1,
5021 int map_element_RND_to_EM(int element_rnd)
5023 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5024 static boolean mapping_initialized = FALSE;
5026 if (!mapping_initialized)
5030 /* return "Xalpha_quest" for all undefined elements in mapping array */
5031 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5032 mapping_RND_to_EM[i] = Xalpha_quest;
5034 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5035 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5036 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5037 em_object_mapping_list[i].element_em;
5039 mapping_initialized = TRUE;
5042 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5043 return mapping_RND_to_EM[element_rnd];
5045 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5050 int map_element_EM_to_RND(int element_em)
5052 static unsigned short mapping_EM_to_RND[TILE_MAX];
5053 static boolean mapping_initialized = FALSE;
5055 if (!mapping_initialized)
5059 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5060 for (i = 0; i < TILE_MAX; i++)
5061 mapping_EM_to_RND[i] = EL_UNKNOWN;
5063 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5064 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5065 em_object_mapping_list[i].element_rnd;
5067 mapping_initialized = TRUE;
5070 if (element_em >= 0 && element_em < TILE_MAX)
5071 return mapping_EM_to_RND[element_em];
5073 Error(ERR_WARN, "invalid EM level element %d", element_em);
5078 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5080 struct LevelInfo_EM *level_em = level->native_em_level;
5081 struct LEVEL *lev = level_em->lev;
5084 for (i = 0; i < TILE_MAX; i++)
5085 lev->android_array[i] = Xblank;
5087 for (i = 0; i < level->num_android_clone_elements; i++)
5089 int element_rnd = level->android_clone_element[i];
5090 int element_em = map_element_RND_to_EM(element_rnd);
5092 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5093 if (em_object_mapping_list[j].element_rnd == element_rnd)
5094 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5098 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5100 struct LevelInfo_EM *level_em = level->native_em_level;
5101 struct LEVEL *lev = level_em->lev;
5104 level->num_android_clone_elements = 0;
5106 for (i = 0; i < TILE_MAX; i++)
5108 int element_em = lev->android_array[i];
5110 boolean element_found = FALSE;
5112 if (element_em == Xblank)
5115 element_rnd = map_element_EM_to_RND(element_em);
5117 for (j = 0; j < level->num_android_clone_elements; j++)
5118 if (level->android_clone_element[j] == element_rnd)
5119 element_found = TRUE;
5123 level->android_clone_element[level->num_android_clone_elements++] =
5126 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5131 if (level->num_android_clone_elements == 0)
5133 level->num_android_clone_elements = 1;
5134 level->android_clone_element[0] = EL_EMPTY;
5138 int map_direction_RND_to_EM(int direction)
5140 return (direction == MV_UP ? 0 :
5141 direction == MV_RIGHT ? 1 :
5142 direction == MV_DOWN ? 2 :
5143 direction == MV_LEFT ? 3 :
5147 int map_direction_EM_to_RND(int direction)
5149 return (direction == 0 ? MV_UP :
5150 direction == 1 ? MV_RIGHT :
5151 direction == 2 ? MV_DOWN :
5152 direction == 3 ? MV_LEFT :
5156 int get_next_element(int element)
5160 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5161 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5162 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5163 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5164 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5165 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5166 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5168 default: return element;
5173 int el_act_dir2img(int element, int action, int direction)
5175 element = GFX_ELEMENT(element);
5177 if (direction == MV_NONE)
5178 return element_info[element].graphic[action];
5180 direction = MV_DIR_TO_BIT(direction);
5182 return element_info[element].direction_graphic[action][direction];
5185 int el_act_dir2img(int element, int action, int direction)
5187 element = GFX_ELEMENT(element);
5188 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5190 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5191 return element_info[element].direction_graphic[action][direction];
5196 static int el_act_dir2crm(int element, int action, int direction)
5198 element = GFX_ELEMENT(element);
5200 if (direction == MV_NONE)
5201 return element_info[element].crumbled[action];
5203 direction = MV_DIR_TO_BIT(direction);
5205 return element_info[element].direction_crumbled[action][direction];
5208 static int el_act_dir2crm(int element, int action, int direction)
5210 element = GFX_ELEMENT(element);
5211 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5213 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5214 return element_info[element].direction_crumbled[action][direction];
5218 int el_act2img(int element, int action)
5220 element = GFX_ELEMENT(element);
5222 return element_info[element].graphic[action];
5225 int el_act2crm(int element, int action)
5227 element = GFX_ELEMENT(element);
5229 return element_info[element].crumbled[action];
5232 int el_dir2img(int element, int direction)
5234 element = GFX_ELEMENT(element);
5236 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5239 int el2baseimg(int element)
5241 return element_info[element].graphic[ACTION_DEFAULT];
5244 int el2img(int element)
5246 element = GFX_ELEMENT(element);
5248 return element_info[element].graphic[ACTION_DEFAULT];
5251 int el2edimg(int element)
5253 element = GFX_ELEMENT(element);
5255 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5258 int el2preimg(int element)
5260 element = GFX_ELEMENT(element);
5262 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5265 int font2baseimg(int font_nr)
5267 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5271 void setCenteredPlayerNr_EM(int centered_player_nr)
5273 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5276 int getCenteredPlayerNr_EM()
5279 if (game.centered_player_nr_next >= 0 &&
5280 !native_em_level.ply[game.centered_player_nr_next]->alive)
5281 game.centered_player_nr_next = game.centered_player_nr;
5284 if (game.centered_player_nr != game.centered_player_nr_next)
5285 game.centered_player_nr = game.centered_player_nr_next;
5287 return game.centered_player_nr;
5290 void setSetCenteredPlayer_EM(boolean set_centered_player)
5292 game.set_centered_player = set_centered_player;
5295 boolean getSetCenteredPlayer_EM()
5297 return game.set_centered_player;
5301 int getNumActivePlayers_EM()
5303 int num_players = 0;
5309 for (i = 0; i < MAX_PLAYERS; i++)
5310 if (tape.player_participates[i])
5317 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5319 int game_frame_delay_value;
5321 game_frame_delay_value =
5322 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5323 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5326 if (tape.playing && tape.warp_forward && !tape.pausing)
5327 game_frame_delay_value = 0;
5329 return game_frame_delay_value;
5333 unsigned int InitRND(long seed)
5335 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5336 return InitEngineRND_EM(seed);
5338 return InitEngineRND(seed);
5341 void InitGraphicInfo_EM(void)
5343 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5344 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5348 int num_em_gfx_errors = 0;
5350 if (graphic_info_em_object[0][0].bitmap == NULL)
5352 /* EM graphics not yet initialized in em_open_all() */
5357 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5360 /* always start with reliable default values */
5361 for (i = 0; i < TILE_MAX; i++)
5363 object_mapping[i].element_rnd = EL_UNKNOWN;
5364 object_mapping[i].is_backside = FALSE;
5365 object_mapping[i].action = ACTION_DEFAULT;
5366 object_mapping[i].direction = MV_NONE;
5369 /* always start with reliable default values */
5370 for (p = 0; p < MAX_PLAYERS; p++)
5372 for (i = 0; i < SPR_MAX; i++)
5374 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5375 player_mapping[p][i].action = ACTION_DEFAULT;
5376 player_mapping[p][i].direction = MV_NONE;
5380 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5382 int e = em_object_mapping_list[i].element_em;
5384 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5385 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5387 if (em_object_mapping_list[i].action != -1)
5388 object_mapping[e].action = em_object_mapping_list[i].action;
5390 if (em_object_mapping_list[i].direction != -1)
5391 object_mapping[e].direction =
5392 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5395 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5397 int a = em_player_mapping_list[i].action_em;
5398 int p = em_player_mapping_list[i].player_nr;
5400 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5402 if (em_player_mapping_list[i].action != -1)
5403 player_mapping[p][a].action = em_player_mapping_list[i].action;
5405 if (em_player_mapping_list[i].direction != -1)
5406 player_mapping[p][a].direction =
5407 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5410 for (i = 0; i < TILE_MAX; i++)
5412 int element = object_mapping[i].element_rnd;
5413 int action = object_mapping[i].action;
5414 int direction = object_mapping[i].direction;
5415 boolean is_backside = object_mapping[i].is_backside;
5416 boolean action_removing = (action == ACTION_DIGGING ||
5417 action == ACTION_SNAPPING ||
5418 action == ACTION_COLLECTING);
5419 boolean action_exploding = ((action == ACTION_EXPLODING ||
5420 action == ACTION_SMASHED_BY_ROCK ||
5421 action == ACTION_SMASHED_BY_SPRING) &&
5422 element != EL_DIAMOND);
5423 boolean action_active = (action == ACTION_ACTIVE);
5424 boolean action_other = (action == ACTION_OTHER);
5426 for (j = 0; j < 8; j++)
5428 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5429 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5431 i == Xdrip_stretch ? element :
5432 i == Xdrip_stretchB ? element :
5433 i == Ydrip_s1 ? element :
5434 i == Ydrip_s1B ? element :
5435 i == Xball_1B ? element :
5436 i == Xball_2 ? element :
5437 i == Xball_2B ? element :
5438 i == Yball_eat ? element :
5439 i == Ykey_1_eat ? element :
5440 i == Ykey_2_eat ? element :
5441 i == Ykey_3_eat ? element :
5442 i == Ykey_4_eat ? element :
5443 i == Ykey_5_eat ? element :
5444 i == Ykey_6_eat ? element :
5445 i == Ykey_7_eat ? element :
5446 i == Ykey_8_eat ? element :
5447 i == Ylenses_eat ? element :
5448 i == Ymagnify_eat ? element :
5449 i == Ygrass_eat ? element :
5450 i == Ydirt_eat ? element :
5451 i == Yemerald_stone ? EL_EMERALD :
5452 i == Ydiamond_stone ? EL_ROCK :
5453 i == Xsand_stonein_1 ? element :
5454 i == Xsand_stonein_2 ? element :
5455 i == Xsand_stonein_3 ? element :
5456 i == Xsand_stonein_4 ? element :
5457 is_backside ? EL_EMPTY :
5458 action_removing ? EL_EMPTY :
5460 int effective_action = (j < 7 ? action :
5461 i == Xdrip_stretch ? action :
5462 i == Xdrip_stretchB ? action :
5463 i == Ydrip_s1 ? action :
5464 i == Ydrip_s1B ? action :
5465 i == Xball_1B ? action :
5466 i == Xball_2 ? action :
5467 i == Xball_2B ? action :
5468 i == Yball_eat ? action :
5469 i == Ykey_1_eat ? action :
5470 i == Ykey_2_eat ? action :
5471 i == Ykey_3_eat ? action :
5472 i == Ykey_4_eat ? action :
5473 i == Ykey_5_eat ? action :
5474 i == Ykey_6_eat ? action :
5475 i == Ykey_7_eat ? action :
5476 i == Ykey_8_eat ? action :
5477 i == Ylenses_eat ? action :
5478 i == Ymagnify_eat ? action :
5479 i == Ygrass_eat ? action :
5480 i == Ydirt_eat ? action :
5481 i == Xsand_stonein_1 ? action :
5482 i == Xsand_stonein_2 ? action :
5483 i == Xsand_stonein_3 ? action :
5484 i == Xsand_stonein_4 ? action :
5485 i == Xsand_stoneout_1 ? action :
5486 i == Xsand_stoneout_2 ? action :
5487 i == Xboom_android ? ACTION_EXPLODING :
5488 action_exploding ? ACTION_EXPLODING :
5489 action_active ? action :
5490 action_other ? action :
5492 int graphic = (el_act_dir2img(effective_element, effective_action,
5494 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5496 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5497 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5498 boolean has_action_graphics = (graphic != base_graphic);
5499 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5500 struct GraphicInfo *g = &graphic_info[graphic];
5501 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5504 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5505 boolean special_animation = (action != ACTION_DEFAULT &&
5506 g->anim_frames == 3 &&
5507 g->anim_delay == 2 &&
5508 g->anim_mode & ANIM_LINEAR);
5509 int sync_frame = (i == Xdrip_stretch ? 7 :
5510 i == Xdrip_stretchB ? 7 :
5511 i == Ydrip_s2 ? j + 8 :
5512 i == Ydrip_s2B ? j + 8 :
5521 i == Xfake_acid_1 ? 0 :
5522 i == Xfake_acid_2 ? 10 :
5523 i == Xfake_acid_3 ? 20 :
5524 i == Xfake_acid_4 ? 30 :
5525 i == Xfake_acid_5 ? 40 :
5526 i == Xfake_acid_6 ? 50 :
5527 i == Xfake_acid_7 ? 60 :
5528 i == Xfake_acid_8 ? 70 :
5530 i == Xball_2B ? j + 8 :
5531 i == Yball_eat ? j + 1 :
5532 i == Ykey_1_eat ? j + 1 :
5533 i == Ykey_2_eat ? j + 1 :
5534 i == Ykey_3_eat ? j + 1 :
5535 i == Ykey_4_eat ? j + 1 :
5536 i == Ykey_5_eat ? j + 1 :
5537 i == Ykey_6_eat ? j + 1 :
5538 i == Ykey_7_eat ? j + 1 :
5539 i == Ykey_8_eat ? j + 1 :
5540 i == Ylenses_eat ? j + 1 :
5541 i == Ymagnify_eat ? j + 1 :
5542 i == Ygrass_eat ? j + 1 :
5543 i == Ydirt_eat ? j + 1 :
5544 i == Xamoeba_1 ? 0 :
5545 i == Xamoeba_2 ? 1 :
5546 i == Xamoeba_3 ? 2 :
5547 i == Xamoeba_4 ? 3 :
5548 i == Xamoeba_5 ? 0 :
5549 i == Xamoeba_6 ? 1 :
5550 i == Xamoeba_7 ? 2 :
5551 i == Xamoeba_8 ? 3 :
5552 i == Xexit_2 ? j + 8 :
5553 i == Xexit_3 ? j + 16 :
5554 i == Xdynamite_1 ? 0 :
5555 i == Xdynamite_2 ? 8 :
5556 i == Xdynamite_3 ? 16 :
5557 i == Xdynamite_4 ? 24 :
5558 i == Xsand_stonein_1 ? j + 1 :
5559 i == Xsand_stonein_2 ? j + 9 :
5560 i == Xsand_stonein_3 ? j + 17 :
5561 i == Xsand_stonein_4 ? j + 25 :
5562 i == Xsand_stoneout_1 && j == 0 ? 0 :
5563 i == Xsand_stoneout_1 && j == 1 ? 0 :
5564 i == Xsand_stoneout_1 && j == 2 ? 1 :
5565 i == Xsand_stoneout_1 && j == 3 ? 2 :
5566 i == Xsand_stoneout_1 && j == 4 ? 2 :
5567 i == Xsand_stoneout_1 && j == 5 ? 3 :
5568 i == Xsand_stoneout_1 && j == 6 ? 4 :
5569 i == Xsand_stoneout_1 && j == 7 ? 4 :
5570 i == Xsand_stoneout_2 && j == 0 ? 5 :
5571 i == Xsand_stoneout_2 && j == 1 ? 6 :
5572 i == Xsand_stoneout_2 && j == 2 ? 7 :
5573 i == Xsand_stoneout_2 && j == 3 ? 8 :
5574 i == Xsand_stoneout_2 && j == 4 ? 9 :
5575 i == Xsand_stoneout_2 && j == 5 ? 11 :
5576 i == Xsand_stoneout_2 && j == 6 ? 13 :
5577 i == Xsand_stoneout_2 && j == 7 ? 15 :
5578 i == Xboom_bug && j == 1 ? 2 :
5579 i == Xboom_bug && j == 2 ? 2 :
5580 i == Xboom_bug && j == 3 ? 4 :
5581 i == Xboom_bug && j == 4 ? 4 :
5582 i == Xboom_bug && j == 5 ? 2 :
5583 i == Xboom_bug && j == 6 ? 2 :
5584 i == Xboom_bug && j == 7 ? 0 :
5585 i == Xboom_bomb && j == 1 ? 2 :
5586 i == Xboom_bomb && j == 2 ? 2 :
5587 i == Xboom_bomb && j == 3 ? 4 :
5588 i == Xboom_bomb && j == 4 ? 4 :
5589 i == Xboom_bomb && j == 5 ? 2 :
5590 i == Xboom_bomb && j == 6 ? 2 :
5591 i == Xboom_bomb && j == 7 ? 0 :
5592 i == Xboom_android && j == 7 ? 6 :
5593 i == Xboom_1 && j == 1 ? 2 :
5594 i == Xboom_1 && j == 2 ? 2 :
5595 i == Xboom_1 && j == 3 ? 4 :
5596 i == Xboom_1 && j == 4 ? 4 :
5597 i == Xboom_1 && j == 5 ? 6 :
5598 i == Xboom_1 && j == 6 ? 6 :
5599 i == Xboom_1 && j == 7 ? 8 :
5600 i == Xboom_2 && j == 0 ? 8 :
5601 i == Xboom_2 && j == 1 ? 8 :
5602 i == Xboom_2 && j == 2 ? 10 :
5603 i == Xboom_2 && j == 3 ? 10 :
5604 i == Xboom_2 && j == 4 ? 10 :
5605 i == Xboom_2 && j == 5 ? 12 :
5606 i == Xboom_2 && j == 6 ? 12 :
5607 i == Xboom_2 && j == 7 ? 12 :
5608 special_animation && j == 4 ? 3 :
5609 effective_action != action ? 0 :
5613 Bitmap *debug_bitmap = g_em->bitmap;
5614 int debug_src_x = g_em->src_x;
5615 int debug_src_y = g_em->src_y;
5618 int frame = getAnimationFrame(g->anim_frames,
5621 g->anim_start_frame,
5624 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5625 g->double_movement && is_backside);
5627 g_em->bitmap = src_bitmap;
5628 g_em->src_x = src_x;
5629 g_em->src_y = src_y;
5630 g_em->src_offset_x = 0;
5631 g_em->src_offset_y = 0;
5632 g_em->dst_offset_x = 0;
5633 g_em->dst_offset_y = 0;
5634 g_em->width = TILEX;
5635 g_em->height = TILEY;
5637 g_em->crumbled_bitmap = NULL;
5638 g_em->crumbled_src_x = 0;
5639 g_em->crumbled_src_y = 0;
5640 g_em->crumbled_border_size = 0;
5642 g_em->has_crumbled_graphics = FALSE;
5643 g_em->preserve_background = FALSE;
5646 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5647 printf("::: empty crumbled: %d [%s], %d, %d\n",
5648 effective_element, element_info[effective_element].token_name,
5649 effective_action, direction);
5652 /* if element can be crumbled, but certain action graphics are just empty
5653 space (like snapping sand with the original R'n'D graphics), do not
5654 treat these empty space graphics as crumbled graphics in EMC engine */
5655 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5657 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5659 g_em->has_crumbled_graphics = TRUE;
5660 g_em->crumbled_bitmap = src_bitmap;
5661 g_em->crumbled_src_x = src_x;
5662 g_em->crumbled_src_y = src_y;
5663 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5667 if (element == EL_ROCK &&
5668 effective_action == ACTION_FILLING)
5669 printf("::: has_action_graphics == %d\n", has_action_graphics);
5672 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5673 effective_action == ACTION_MOVING ||
5674 effective_action == ACTION_PUSHING ||
5675 effective_action == ACTION_EATING)) ||
5676 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5677 effective_action == ACTION_EMPTYING)))
5680 (effective_action == ACTION_FALLING ||
5681 effective_action == ACTION_FILLING ||
5682 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5683 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5684 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5685 int num_steps = (i == Ydrip_s1 ? 16 :
5686 i == Ydrip_s1B ? 16 :
5687 i == Ydrip_s2 ? 16 :
5688 i == Ydrip_s2B ? 16 :
5689 i == Xsand_stonein_1 ? 32 :
5690 i == Xsand_stonein_2 ? 32 :
5691 i == Xsand_stonein_3 ? 32 :
5692 i == Xsand_stonein_4 ? 32 :
5693 i == Xsand_stoneout_1 ? 16 :
5694 i == Xsand_stoneout_2 ? 16 : 8);
5695 int cx = ABS(dx) * (TILEX / num_steps);
5696 int cy = ABS(dy) * (TILEY / num_steps);
5697 int step_frame = (i == Ydrip_s2 ? j + 8 :
5698 i == Ydrip_s2B ? j + 8 :
5699 i == Xsand_stonein_2 ? j + 8 :
5700 i == Xsand_stonein_3 ? j + 16 :
5701 i == Xsand_stonein_4 ? j + 24 :
5702 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5703 int step = (is_backside ? step_frame : num_steps - step_frame);
5705 if (is_backside) /* tile where movement starts */
5707 if (dx < 0 || dy < 0)
5709 g_em->src_offset_x = cx * step;
5710 g_em->src_offset_y = cy * step;
5714 g_em->dst_offset_x = cx * step;
5715 g_em->dst_offset_y = cy * step;
5718 else /* tile where movement ends */
5720 if (dx < 0 || dy < 0)
5722 g_em->dst_offset_x = cx * step;
5723 g_em->dst_offset_y = cy * step;
5727 g_em->src_offset_x = cx * step;
5728 g_em->src_offset_y = cy * step;
5732 g_em->width = TILEX - cx * step;
5733 g_em->height = TILEY - cy * step;
5737 /* create unique graphic identifier to decide if tile must be redrawn */
5738 /* bit 31 - 16 (16 bit): EM style graphic
5739 bit 15 - 12 ( 4 bit): EM style frame
5740 bit 11 - 6 ( 6 bit): graphic width
5741 bit 5 - 0 ( 6 bit): graphic height */
5742 g_em->unique_identifier =
5743 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5745 /* create unique graphic identifier to decide if tile must be redrawn */
5746 /* bit 31 - 16 (16 bit): EM style element
5747 bit 15 - 12 ( 4 bit): EM style frame
5748 bit 11 - 6 ( 6 bit): graphic width
5749 bit 5 - 0 ( 6 bit): graphic height */
5750 g_em->unique_identifier =
5751 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5755 if (effective_element == EL_ROCK)
5756 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5757 effective_action, j, graphic, frame, g_em->unique_identifier);
5763 /* skip check for EMC elements not contained in original EMC artwork */
5764 if (element == EL_EMC_FAKE_ACID)
5768 if (g_em->bitmap != debug_bitmap ||
5769 g_em->src_x != debug_src_x ||
5770 g_em->src_y != debug_src_y ||
5771 g_em->src_offset_x != 0 ||
5772 g_em->src_offset_y != 0 ||
5773 g_em->dst_offset_x != 0 ||
5774 g_em->dst_offset_y != 0 ||
5775 g_em->width != TILEX ||
5776 g_em->height != TILEY)
5778 static int last_i = -1;
5786 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5787 i, element, element_info[element].token_name,
5788 element_action_info[effective_action].suffix, direction);
5790 if (element != effective_element)
5791 printf(" [%d ('%s')]",
5793 element_info[effective_element].token_name);
5797 if (g_em->bitmap != debug_bitmap)
5798 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5799 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5801 if (g_em->src_x != debug_src_x ||
5802 g_em->src_y != debug_src_y)
5803 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5804 j, (is_backside ? 'B' : 'F'),
5805 g_em->src_x, g_em->src_y,
5806 g_em->src_x / 32, g_em->src_y / 32,
5807 debug_src_x, debug_src_y,
5808 debug_src_x / 32, debug_src_y / 32);
5810 if (g_em->src_offset_x != 0 ||
5811 g_em->src_offset_y != 0 ||
5812 g_em->dst_offset_x != 0 ||
5813 g_em->dst_offset_y != 0)
5814 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5816 g_em->src_offset_x, g_em->src_offset_y,
5817 g_em->dst_offset_x, g_em->dst_offset_y);
5819 if (g_em->width != TILEX ||
5820 g_em->height != TILEY)
5821 printf(" %d (%d): size %d,%d should be %d,%d\n",
5823 g_em->width, g_em->height, TILEX, TILEY);
5825 num_em_gfx_errors++;
5832 for (i = 0; i < TILE_MAX; i++)
5834 for (j = 0; j < 8; j++)
5836 int element = object_mapping[i].element_rnd;
5837 int action = object_mapping[i].action;
5838 int direction = object_mapping[i].direction;
5839 boolean is_backside = object_mapping[i].is_backside;
5841 int graphic_action = el_act_dir2img(element, action, direction);
5842 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5844 int graphic_action = element_info[element].graphic[action];
5845 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5848 if ((action == ACTION_SMASHED_BY_ROCK ||
5849 action == ACTION_SMASHED_BY_SPRING ||
5850 action == ACTION_EATING) &&
5851 graphic_action == graphic_default)
5853 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5854 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5855 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5856 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5859 /* no separate animation for "smashed by rock" -- use rock instead */
5860 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5861 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5863 g_em->bitmap = g_xx->bitmap;
5864 g_em->src_x = g_xx->src_x;
5865 g_em->src_y = g_xx->src_y;
5866 g_em->src_offset_x = g_xx->src_offset_x;
5867 g_em->src_offset_y = g_xx->src_offset_y;
5868 g_em->dst_offset_x = g_xx->dst_offset_x;
5869 g_em->dst_offset_y = g_xx->dst_offset_y;
5870 g_em->width = g_xx->width;
5871 g_em->height = g_xx->height;
5873 g_em->unique_identifier = g_xx->unique_identifier;
5877 g_em->preserve_background = TRUE;
5882 for (p = 0; p < MAX_PLAYERS; p++)
5884 for (i = 0; i < SPR_MAX; i++)
5886 int element = player_mapping[p][i].element_rnd;
5887 int action = player_mapping[p][i].action;
5888 int direction = player_mapping[p][i].direction;
5890 for (j = 0; j < 8; j++)
5892 int effective_element = element;
5893 int effective_action = action;
5894 int graphic = (direction == MV_NONE ?
5895 el_act2img(effective_element, effective_action) :
5896 el_act_dir2img(effective_element, effective_action,
5898 struct GraphicInfo *g = &graphic_info[graphic];
5899 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5905 Bitmap *debug_bitmap = g_em->bitmap;
5906 int debug_src_x = g_em->src_x;
5907 int debug_src_y = g_em->src_y;
5910 int frame = getAnimationFrame(g->anim_frames,
5913 g->anim_start_frame,
5916 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5918 g_em->bitmap = src_bitmap;
5919 g_em->src_x = src_x;
5920 g_em->src_y = src_y;
5921 g_em->src_offset_x = 0;
5922 g_em->src_offset_y = 0;
5923 g_em->dst_offset_x = 0;
5924 g_em->dst_offset_y = 0;
5925 g_em->width = TILEX;
5926 g_em->height = TILEY;
5931 /* skip check for EMC elements not contained in original EMC artwork */
5932 if (element == EL_PLAYER_3 ||
5933 element == EL_PLAYER_4)
5937 if (g_em->bitmap != debug_bitmap ||
5938 g_em->src_x != debug_src_x ||
5939 g_em->src_y != debug_src_y)
5941 static int last_i = -1;
5949 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5950 p, i, element, element_info[element].token_name,
5951 element_action_info[effective_action].suffix, direction);
5953 if (element != effective_element)
5954 printf(" [%d ('%s')]",
5956 element_info[effective_element].token_name);
5960 if (g_em->bitmap != debug_bitmap)
5961 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5962 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5964 if (g_em->src_x != debug_src_x ||
5965 g_em->src_y != debug_src_y)
5966 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5968 g_em->src_x, g_em->src_y,
5969 g_em->src_x / 32, g_em->src_y / 32,
5970 debug_src_x, debug_src_y,
5971 debug_src_x / 32, debug_src_y / 32);
5973 num_em_gfx_errors++;
5983 printf("::: [%d errors found]\n", num_em_gfx_errors);
5989 void PlayMenuSound()
5991 int sound = menu.sound[game_status];
5993 if (sound == SND_UNDEFINED)
5996 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5997 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6000 if (IS_LOOP_SOUND(sound))
6001 PlaySoundLoop(sound);
6006 void PlayMenuSoundStereo(int sound, int stereo_position)
6008 if (sound == SND_UNDEFINED)
6011 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6012 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6015 if (IS_LOOP_SOUND(sound))
6016 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6018 PlaySoundStereo(sound, stereo_position);
6021 void PlayMenuSoundIfLoop()
6023 int sound = menu.sound[game_status];
6025 if (sound == SND_UNDEFINED)
6028 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6029 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6032 if (IS_LOOP_SOUND(sound))
6033 PlaySoundLoop(sound);
6036 void PlayMenuMusic()
6038 int music = menu.music[game_status];
6040 if (music == MUS_UNDEFINED)