1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
187 BlitBitmap(drawto, window, x, y, width, height, x, y);
193 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
195 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
196 redraw_mask &= ~REDRAW_MAIN;
198 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
199 redraw_mask |= REDRAW_FIELD;
201 if (redraw_mask & REDRAW_FIELD)
202 redraw_mask &= ~REDRAW_TILES;
204 if (redraw_mask == REDRAW_NONE)
207 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
209 static boolean last_frame_skipped = FALSE;
210 boolean skip_even_when_not_scrolling = TRUE;
211 boolean just_scrolling = (ScreenMovDir != 0);
212 boolean verbose = FALSE;
214 if (global.fps_slowdown_factor > 1 &&
215 (FrameCounter % global.fps_slowdown_factor) &&
216 (just_scrolling || skip_even_when_not_scrolling))
218 redraw_mask &= ~REDRAW_MAIN;
220 last_frame_skipped = TRUE;
223 printf("FRAME SKIPPED\n");
227 if (last_frame_skipped)
228 redraw_mask |= REDRAW_FIELD;
230 last_frame_skipped = FALSE;
233 printf("frame not skipped\n");
237 /* synchronize X11 graphics at this point; if we would synchronize the
238 display immediately after the buffer switching (after the XFlush),
239 this could mean that we have to wait for the graphics to complete,
240 although we could go on doing calculations for the next frame */
244 if (redraw_mask & REDRAW_ALL)
246 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
248 redraw_mask = REDRAW_NONE;
251 if (redraw_mask & REDRAW_FIELD)
253 if (game_status != GAME_MODE_PLAYING ||
254 redraw_mask & REDRAW_FROM_BACKBUFFER)
256 BlitBitmap(backbuffer, window,
257 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
261 int fx = FX, fy = FY;
263 if (setup.soft_scrolling)
265 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
266 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
269 if (setup.soft_scrolling ||
270 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
271 ABS(ScreenMovPos) == ScrollStepSize ||
272 redraw_tiles > REDRAWTILES_THRESHOLD)
274 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
278 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
280 (setup.soft_scrolling ?
281 "setup.soft_scrolling" :
282 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
283 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
284 ABS(ScreenGfxPos) == ScrollStepSize ?
285 "ABS(ScreenGfxPos) == ScrollStepSize" :
286 "redraw_tiles > REDRAWTILES_THRESHOLD"));
292 redraw_mask &= ~REDRAW_MAIN;
295 if (redraw_mask & REDRAW_DOORS)
297 if (redraw_mask & REDRAW_DOOR_1)
298 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
300 if (redraw_mask & REDRAW_DOOR_2)
301 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
303 if (redraw_mask & REDRAW_DOOR_3)
304 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
306 redraw_mask &= ~REDRAW_DOORS;
309 if (redraw_mask & REDRAW_MICROLEVEL)
311 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
312 SX, SY + 10 * TILEY);
314 redraw_mask &= ~REDRAW_MICROLEVEL;
317 if (redraw_mask & REDRAW_TILES)
319 for (x = 0; x < SCR_FIELDX; x++)
320 for (y = 0 ; y < SCR_FIELDY; y++)
321 if (redraw[redraw_x1 + x][redraw_y1 + y])
322 BlitBitmap(buffer, window,
323 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
324 SX + x * TILEX, SY + y * TILEY);
327 if (redraw_mask & REDRAW_FPS) /* display frames per second */
332 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
333 if (!global.fps_slowdown)
336 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
337 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
342 for (x = 0; x < MAX_BUF_XSIZE; x++)
343 for (y = 0; y < MAX_BUF_YSIZE; y++)
346 redraw_mask = REDRAW_NONE;
352 long fading_delay = 300;
354 if (setup.fading && (redraw_mask & REDRAW_FIELD))
361 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
364 for (i = 0; i < 2 * FULL_SYSIZE; i++)
366 for (y = 0; y < FULL_SYSIZE; y++)
368 BlitBitmap(backbuffer, window,
369 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
377 for (i = 1; i < FULL_SYSIZE; i+=2)
378 BlitBitmap(backbuffer, window,
379 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
385 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
386 BlitBitmapMasked(backbuffer, window,
387 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
392 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
393 BlitBitmapMasked(backbuffer, window,
394 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
399 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
400 BlitBitmapMasked(backbuffer, window,
401 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
406 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
407 BlitBitmapMasked(backbuffer, window,
408 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
413 redraw_mask &= ~REDRAW_MAIN;
420 void FadeExt(int fade_mask, int fade_mode)
422 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
423 int fade_delay = menu.fade_delay;
424 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
425 int x, y, width, height;
427 if (fade_mask & REDRAW_ALL)
434 else if (fade_mask & REDRAW_FIELD)
439 height = FULL_SYSIZE;
442 redraw_mask |= fade_mask;
444 if (!setup.fading || fade_delay == 0)
446 if (fade_mode == FADE_MODE_FADE_OUT)
447 ClearRectangle(backbuffer, x, y, width, height);
454 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay);
456 redraw_mask &= ~fade_mask;
459 void FadeIn(int fade_mask)
461 FadeExt(fade_mask, FADE_MODE_FADE_IN);
464 void FadeOut(int fade_mask)
466 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
469 void FadeCross(int fade_mask)
471 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
474 void FadeCrossSaveBackbuffer()
476 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
479 void SetMainBackgroundImageIfDefined(int graphic)
481 if (graphic_info[graphic].bitmap)
482 SetMainBackgroundImage(graphic);
485 void SetMainBackgroundImage(int graphic)
487 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
488 graphic_info[graphic].bitmap ?
489 graphic_info[graphic].bitmap :
490 graphic_info[IMG_BACKGROUND].bitmap);
493 void SetDoorBackgroundImage(int graphic)
495 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
496 graphic_info[graphic].bitmap ?
497 graphic_info[graphic].bitmap :
498 graphic_info[IMG_BACKGROUND].bitmap);
501 void SetPanelBackground()
503 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
504 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
506 SetDoorBackgroundBitmap(bitmap_db_panel);
509 void DrawBackground(int dst_x, int dst_y, int width, int height)
512 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
514 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
517 redraw_mask |= REDRAW_FIELD;
522 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
524 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
526 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
527 SetDrawtoField(DRAW_BUFFERED);
530 SetDrawtoField(DRAW_BACKBUFFER);
532 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
534 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
535 SetDrawtoField(DRAW_DIRECT);
539 void MarkTileDirty(int x, int y)
541 int xx = redraw_x1 + x;
542 int yy = redraw_y1 + y;
547 redraw[xx][yy] = TRUE;
548 redraw_mask |= REDRAW_TILES;
551 void SetBorderElement()
555 BorderElement = EL_EMPTY;
557 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
559 for (x = 0; x < lev_fieldx; x++)
561 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
562 BorderElement = EL_STEELWALL;
564 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
570 void SetRandomAnimationValue(int x, int y)
572 gfx.anim_random_frame = GfxRandom[x][y];
575 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
577 /* animation synchronized with global frame counter, not move position */
578 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
579 sync_frame = FrameCounter;
581 return getAnimationFrame(graphic_info[graphic].anim_frames,
582 graphic_info[graphic].anim_delay,
583 graphic_info[graphic].anim_mode,
584 graphic_info[graphic].anim_start_frame,
588 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
589 int *x, int *y, boolean get_backside)
591 struct GraphicInfo *g = &graphic_info[graphic];
592 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
593 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
597 if (g->offset_y == 0) /* frames are ordered horizontally */
599 int max_width = g->anim_frames_per_line * g->width;
600 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
602 *x = pos % max_width;
603 *y = src_y % g->height + pos / max_width * g->height;
605 else if (g->offset_x == 0) /* frames are ordered vertically */
607 int max_height = g->anim_frames_per_line * g->height;
608 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
610 *x = src_x % g->width + pos / max_height * g->width;
611 *y = pos % max_height;
613 else /* frames are ordered diagonally */
615 *x = src_x + frame * g->offset_x;
616 *y = src_y + frame * g->offset_y;
620 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
622 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
625 void DrawGraphic(int x, int y, int graphic, int frame)
628 if (!IN_SCR_FIELD(x, y))
630 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
631 printf("DrawGraphic(): This should never happen!\n");
636 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
640 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
646 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
647 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
650 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
653 if (!IN_SCR_FIELD(x, y))
655 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
656 printf("DrawGraphicThruMask(): This should never happen!\n");
661 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
666 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
672 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
674 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
675 dst_x - src_x, dst_y - src_y);
676 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
679 void DrawMiniGraphic(int x, int y, int graphic)
681 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
682 MarkTileDirty(x / 2, y / 2);
685 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
687 struct GraphicInfo *g = &graphic_info[graphic];
689 int mini_starty = g->bitmap->height * 2 / 3;
692 *x = mini_startx + g->src_x / 2;
693 *y = mini_starty + g->src_y / 2;
696 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
701 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
702 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
705 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
706 int graphic, int frame,
707 int cut_mode, int mask_mode)
712 int width = TILEX, height = TILEY;
715 if (dx || dy) /* shifted graphic */
717 if (x < BX1) /* object enters playfield from the left */
724 else if (x > BX2) /* object enters playfield from the right */
730 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
736 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
738 else if (dx) /* general horizontal movement */
739 MarkTileDirty(x + SIGN(dx), y);
741 if (y < BY1) /* object enters playfield from the top */
743 if (cut_mode==CUT_BELOW) /* object completely above top border */
751 else if (y > BY2) /* object enters playfield from the bottom */
757 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
763 else if (dy > 0 && cut_mode == CUT_ABOVE)
765 if (y == BY2) /* object completely above bottom border */
771 MarkTileDirty(x, y + 1);
772 } /* object leaves playfield to the bottom */
773 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
775 else if (dy) /* general vertical movement */
776 MarkTileDirty(x, y + SIGN(dy));
780 if (!IN_SCR_FIELD(x, y))
782 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
783 printf("DrawGraphicShifted(): This should never happen!\n");
788 if (width > 0 && height > 0)
790 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
795 dst_x = FX + x * TILEX + dx;
796 dst_y = FY + y * TILEY + dy;
798 if (mask_mode == USE_MASKING)
800 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
801 dst_x - src_x, dst_y - src_y);
802 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
806 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
813 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
814 int graphic, int frame,
815 int cut_mode, int mask_mode)
820 int width = TILEX, height = TILEY;
823 int x2 = x + SIGN(dx);
824 int y2 = y + SIGN(dy);
825 int anim_frames = graphic_info[graphic].anim_frames;
826 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
827 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
828 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
830 /* re-calculate animation frame for two-tile movement animation */
831 frame = getGraphicAnimationFrame(graphic, sync_frame);
833 /* check if movement start graphic inside screen area and should be drawn */
834 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
836 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
838 dst_x = FX + x1 * TILEX;
839 dst_y = FY + y1 * TILEY;
841 if (mask_mode == USE_MASKING)
843 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
844 dst_x - src_x, dst_y - src_y);
845 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
849 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
852 MarkTileDirty(x1, y1);
855 /* check if movement end graphic inside screen area and should be drawn */
856 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
858 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
860 dst_x = FX + x2 * TILEX;
861 dst_y = FY + y2 * TILEY;
863 if (mask_mode == USE_MASKING)
865 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
866 dst_x - src_x, dst_y - src_y);
867 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
871 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
874 MarkTileDirty(x2, y2);
878 static void DrawGraphicShifted(int x, int y, int dx, int dy,
879 int graphic, int frame,
880 int cut_mode, int mask_mode)
884 DrawGraphic(x, y, graphic, frame);
889 if (graphic_info[graphic].double_movement) /* EM style movement images */
890 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
892 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
895 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
896 int frame, int cut_mode)
898 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
901 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
902 int cut_mode, int mask_mode)
904 int lx = LEVELX(x), ly = LEVELY(y);
908 if (IN_LEV_FIELD(lx, ly))
910 SetRandomAnimationValue(lx, ly);
912 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
913 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
915 /* do not use double (EM style) movement graphic when not moving */
916 if (graphic_info[graphic].double_movement && !dx && !dy)
918 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
919 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
922 else /* border element */
924 graphic = el2img(element);
925 frame = getGraphicAnimationFrame(graphic, -1);
928 if (element == EL_EXPANDABLE_WALL)
930 boolean left_stopped = FALSE, right_stopped = FALSE;
932 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
934 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
935 right_stopped = TRUE;
937 if (left_stopped && right_stopped)
939 else if (left_stopped)
941 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
942 frame = graphic_info[graphic].anim_frames - 1;
944 else if (right_stopped)
946 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
947 frame = graphic_info[graphic].anim_frames - 1;
952 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
953 else if (mask_mode == USE_MASKING)
954 DrawGraphicThruMask(x, y, graphic, frame);
956 DrawGraphic(x, y, graphic, frame);
959 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
960 int cut_mode, int mask_mode)
962 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
963 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
964 cut_mode, mask_mode);
967 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
970 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
973 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
976 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
979 void DrawLevelElementThruMask(int x, int y, int element)
981 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
984 void DrawLevelFieldThruMask(int x, int y)
986 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
989 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
993 int sx = SCREENX(x), sy = SCREENY(y);
995 int width, height, cx, cy, i;
996 int crumbled_border_size = graphic_info[graphic].border_size;
997 static int xy[4][2] =
1005 if (!IN_LEV_FIELD(x, y))
1008 element = TILE_GFX_ELEMENT(x, y);
1010 /* crumble field itself */
1011 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1013 if (!IN_SCR_FIELD(sx, sy))
1016 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1018 for (i = 0; i < 4; i++)
1020 int xx = x + xy[i][0];
1021 int yy = y + xy[i][1];
1023 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1026 /* check if neighbour field is of same type */
1027 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1030 if (i == 1 || i == 2)
1032 width = crumbled_border_size;
1034 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1040 height = crumbled_border_size;
1042 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1045 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1046 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1049 MarkTileDirty(sx, sy);
1051 else /* crumble neighbour fields */
1053 for (i = 0; i < 4; i++)
1055 int xx = x + xy[i][0];
1056 int yy = y + xy[i][1];
1057 int sxx = sx + xy[i][0];
1058 int syy = sy + xy[i][1];
1060 if (!IN_LEV_FIELD(xx, yy) ||
1061 !IN_SCR_FIELD(sxx, syy) ||
1065 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1068 element = TILE_GFX_ELEMENT(xx, yy);
1070 if (!GFX_CRUMBLED(element))
1073 graphic = el_act2crm(element, ACTION_DEFAULT);
1074 crumbled_border_size = graphic_info[graphic].border_size;
1076 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1078 if (i == 1 || i == 2)
1080 width = crumbled_border_size;
1082 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1088 height = crumbled_border_size;
1090 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1093 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1094 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1096 MarkTileDirty(sxx, syy);
1101 void DrawLevelFieldCrumbledSand(int x, int y)
1105 if (!IN_LEV_FIELD(x, y))
1109 /* !!! CHECK THIS !!! */
1112 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1113 GFX_CRUMBLED(GfxElement[x][y]))
1116 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1117 GfxElement[x][y] != EL_UNDEFINED &&
1118 GFX_CRUMBLED(GfxElement[x][y]))
1120 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1127 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1129 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1132 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1135 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1138 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1139 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1140 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1141 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1142 int sx = SCREENX(x), sy = SCREENY(y);
1144 DrawGraphic(sx, sy, graphic1, frame1);
1145 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1148 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1150 int sx = SCREENX(x), sy = SCREENY(y);
1151 static int xy[4][2] =
1160 for (i = 0; i < 4; i++)
1162 int xx = x + xy[i][0];
1163 int yy = y + xy[i][1];
1164 int sxx = sx + xy[i][0];
1165 int syy = sy + xy[i][1];
1167 if (!IN_LEV_FIELD(xx, yy) ||
1168 !IN_SCR_FIELD(sxx, syy) ||
1169 !GFX_CRUMBLED(Feld[xx][yy]) ||
1173 DrawLevelField(xx, yy);
1177 static int getBorderElement(int x, int y)
1181 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1182 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1183 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1184 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1185 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1186 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1187 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1189 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1190 int steel_position = (x == -1 && y == -1 ? 0 :
1191 x == lev_fieldx && y == -1 ? 1 :
1192 x == -1 && y == lev_fieldy ? 2 :
1193 x == lev_fieldx && y == lev_fieldy ? 3 :
1194 x == -1 || x == lev_fieldx ? 4 :
1195 y == -1 || y == lev_fieldy ? 5 : 6);
1197 return border[steel_position][steel_type];
1200 void DrawScreenElement(int x, int y, int element)
1202 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1203 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1206 void DrawLevelElement(int x, int y, int element)
1208 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1209 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1212 void DrawScreenField(int x, int y)
1214 int lx = LEVELX(x), ly = LEVELY(y);
1215 int element, content;
1217 if (!IN_LEV_FIELD(lx, ly))
1219 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1222 element = getBorderElement(lx, ly);
1224 DrawScreenElement(x, y, element);
1228 element = Feld[lx][ly];
1229 content = Store[lx][ly];
1231 if (IS_MOVING(lx, ly))
1233 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1234 boolean cut_mode = NO_CUTTING;
1236 if (element == EL_QUICKSAND_EMPTYING ||
1237 element == EL_MAGIC_WALL_EMPTYING ||
1238 element == EL_BD_MAGIC_WALL_EMPTYING ||
1239 element == EL_AMOEBA_DROPPING)
1240 cut_mode = CUT_ABOVE;
1241 else if (element == EL_QUICKSAND_FILLING ||
1242 element == EL_MAGIC_WALL_FILLING ||
1243 element == EL_BD_MAGIC_WALL_FILLING)
1244 cut_mode = CUT_BELOW;
1246 if (cut_mode == CUT_ABOVE)
1247 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1249 DrawScreenElement(x, y, EL_EMPTY);
1252 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1253 else if (cut_mode == NO_CUTTING)
1254 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1256 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1258 if (content == EL_ACID)
1260 int dir = MovDir[lx][ly];
1261 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1262 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1264 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1267 else if (IS_BLOCKED(lx, ly))
1272 boolean cut_mode = NO_CUTTING;
1273 int element_old, content_old;
1275 Blocked2Moving(lx, ly, &oldx, &oldy);
1278 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1279 MovDir[oldx][oldy] == MV_RIGHT);
1281 element_old = Feld[oldx][oldy];
1282 content_old = Store[oldx][oldy];
1284 if (element_old == EL_QUICKSAND_EMPTYING ||
1285 element_old == EL_MAGIC_WALL_EMPTYING ||
1286 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1287 element_old == EL_AMOEBA_DROPPING)
1288 cut_mode = CUT_ABOVE;
1290 DrawScreenElement(x, y, EL_EMPTY);
1293 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1295 else if (cut_mode == NO_CUTTING)
1296 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1299 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1302 else if (IS_DRAWABLE(element))
1303 DrawScreenElement(x, y, element);
1305 DrawScreenElement(x, y, EL_EMPTY);
1308 void DrawLevelField(int x, int y)
1310 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1311 DrawScreenField(SCREENX(x), SCREENY(y));
1312 else if (IS_MOVING(x, y))
1316 Moving2Blocked(x, y, &newx, &newy);
1317 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1318 DrawScreenField(SCREENX(newx), SCREENY(newy));
1320 else if (IS_BLOCKED(x, y))
1324 Blocked2Moving(x, y, &oldx, &oldy);
1325 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1326 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1330 void DrawMiniElement(int x, int y, int element)
1334 graphic = el2edimg(element);
1335 DrawMiniGraphic(x, y, graphic);
1338 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1340 int x = sx + scroll_x, y = sy + scroll_y;
1342 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1343 DrawMiniElement(sx, sy, EL_EMPTY);
1344 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1345 DrawMiniElement(sx, sy, Feld[x][y]);
1347 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1350 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1351 int x, int y, int xsize, int ysize, int font_nr)
1353 int font_width = getFontWidth(font_nr);
1354 int font_height = getFontHeight(font_nr);
1355 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1358 int dst_x = SX + startx + x * font_width;
1359 int dst_y = SY + starty + y * font_height;
1360 int width = graphic_info[graphic].width;
1361 int height = graphic_info[graphic].height;
1362 int inner_width = MAX(width - 2 * font_width, font_width);
1363 int inner_height = MAX(height - 2 * font_height, font_height);
1364 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1365 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1366 boolean draw_masked = graphic_info[graphic].draw_masked;
1368 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1370 if (src_bitmap == NULL || width < font_width || height < font_height)
1372 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1376 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1377 inner_sx + (x - 1) * font_width % inner_width);
1378 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1379 inner_sy + (y - 1) * font_height % inner_height);
1383 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1384 dst_x - src_x, dst_y - src_y);
1385 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1389 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1393 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1395 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1396 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1397 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1398 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1399 boolean no_delay = (tape.warp_forward);
1400 unsigned long anim_delay = 0;
1401 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1402 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1403 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1404 int font_width = getFontWidth(font_nr);
1405 int font_height = getFontHeight(font_nr);
1406 int max_xsize = level.envelope[envelope_nr].xsize;
1407 int max_ysize = level.envelope[envelope_nr].ysize;
1408 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1409 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1410 int xend = max_xsize;
1411 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1412 int xstep = (xstart < xend ? 1 : 0);
1413 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1416 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1418 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1419 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1420 int sx = (SXSIZE - xsize * font_width) / 2;
1421 int sy = (SYSIZE - ysize * font_height) / 2;
1424 SetDrawtoField(DRAW_BUFFERED);
1426 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1428 SetDrawtoField(DRAW_BACKBUFFER);
1430 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1431 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1433 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1434 level.envelope[envelope_nr].text, font_nr, max_xsize,
1435 xsize - 2, ysize - 2, mask_mode);
1437 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1440 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1444 void ShowEnvelope(int envelope_nr)
1446 int element = EL_ENVELOPE_1 + envelope_nr;
1447 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1448 int sound_opening = element_info[element].sound[ACTION_OPENING];
1449 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1450 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1451 boolean no_delay = (tape.warp_forward);
1452 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1453 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1454 int anim_mode = graphic_info[graphic].anim_mode;
1455 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1456 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1458 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1460 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1462 if (anim_mode == ANIM_DEFAULT)
1463 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1465 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1468 Delay(wait_delay_value);
1470 WaitForEventToContinue();
1472 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1474 if (anim_mode != ANIM_NONE)
1475 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1477 if (anim_mode == ANIM_DEFAULT)
1478 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1480 game.envelope_active = FALSE;
1482 SetDrawtoField(DRAW_BUFFERED);
1484 redraw_mask |= REDRAW_FIELD;
1488 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1493 int width_mult, width_div;
1494 int height_mult, height_div;
1502 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1503 5 - log_2(tilesize));
1504 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1505 int width_mult = offset_calc[offset_calc_pos].width_mult;
1506 int width_div = offset_calc[offset_calc_pos].width_div;
1507 int height_mult = offset_calc[offset_calc_pos].height_mult;
1508 int height_div = offset_calc[offset_calc_pos].height_div;
1509 int mini_startx = src_bitmap->width * width_mult / width_div;
1510 int mini_starty = src_bitmap->height * height_mult / height_div;
1511 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1512 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1514 *bitmap = src_bitmap;
1519 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1523 int graphic = el2preimg(element);
1525 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1526 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1533 SetDrawBackgroundMask(REDRAW_NONE);
1536 for (x = BX1; x <= BX2; x++)
1537 for (y = BY1; y <= BY2; y++)
1538 DrawScreenField(x, y);
1540 redraw_mask |= REDRAW_FIELD;
1543 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1547 for (x = 0; x < size_x; x++)
1548 for (y = 0; y < size_y; y++)
1549 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1551 redraw_mask |= REDRAW_FIELD;
1554 static void DrawPreviewLevelExt(int from_x, int from_y)
1556 boolean show_level_border = (BorderElement != EL_EMPTY);
1557 int dst_x = preview.x;
1558 int dst_y = preview.y;
1559 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1560 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1561 int tile_size = preview.tile_size;
1562 int preview_width = preview.xsize * tile_size;
1563 int preview_height = preview.ysize * tile_size;
1564 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1565 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1568 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1570 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1571 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1573 for (x = 0; x < real_preview_xsize; x++)
1575 for (y = 0; y < real_preview_ysize; y++)
1577 int lx = from_x + x + (show_level_border ? -1 : 0);
1578 int ly = from_y + y + (show_level_border ? -1 : 0);
1579 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1580 getBorderElement(lx, ly));
1582 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1583 element, tile_size);
1587 redraw_mask |= REDRAW_MICROLEVEL;
1590 #define MICROLABEL_EMPTY 0
1591 #define MICROLABEL_LEVEL_NAME 1
1592 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1593 #define MICROLABEL_LEVEL_AUTHOR 3
1594 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1595 #define MICROLABEL_IMPORTED_FROM 5
1596 #define MICROLABEL_IMPORTED_BY_HEAD 6
1597 #define MICROLABEL_IMPORTED_BY 7
1599 static void DrawPreviewLevelLabelExt(int mode)
1601 char label_text[MAX_OUTPUT_LINESIZE + 1];
1602 int max_len_label_text;
1603 int font_nr = FONT_TEXT_2;
1606 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1607 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1608 mode == MICROLABEL_IMPORTED_BY_HEAD)
1609 font_nr = FONT_TEXT_3;
1611 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1613 for (i = 0; i < max_len_label_text; i++)
1614 label_text[i] = ' ';
1615 label_text[max_len_label_text] = '\0';
1617 if (strlen(label_text) > 0)
1619 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1620 int lypos = MICROLABEL2_YPOS;
1622 DrawText(lxpos, lypos, label_text, font_nr);
1626 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1627 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1628 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1629 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1630 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1631 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1632 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1633 max_len_label_text);
1634 label_text[max_len_label_text] = '\0';
1636 if (strlen(label_text) > 0)
1638 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1639 int lypos = MICROLABEL2_YPOS;
1641 DrawText(lxpos, lypos, label_text, font_nr);
1644 redraw_mask |= REDRAW_MICROLEVEL;
1647 void DrawPreviewLevel(boolean restart)
1649 static unsigned long scroll_delay = 0;
1650 static unsigned long label_delay = 0;
1651 static int from_x, from_y, scroll_direction;
1652 static int label_state, label_counter;
1653 unsigned long scroll_delay_value = preview.step_delay;
1654 boolean show_level_border = (BorderElement != EL_EMPTY);
1655 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1656 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1657 int last_game_status = game_status; /* save current game status */
1659 /* force PREVIEW font on preview level */
1660 game_status = GAME_MODE_PSEUDO_PREVIEW;
1664 from_x = from_y = 0;
1665 scroll_direction = MV_RIGHT;
1669 DrawPreviewLevelExt(from_x, from_y);
1670 DrawPreviewLevelLabelExt(label_state);
1672 /* initialize delay counters */
1673 DelayReached(&scroll_delay, 0);
1674 DelayReached(&label_delay, 0);
1676 if (leveldir_current->name)
1678 char label_text[MAX_OUTPUT_LINESIZE + 1];
1679 int font_nr = FONT_TEXT_1;
1680 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1683 strncpy(label_text, leveldir_current->name, max_len_label_text);
1684 label_text[max_len_label_text] = '\0';
1686 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1687 lypos = SY + MICROLABEL1_YPOS;
1689 DrawText(lxpos, lypos, label_text, font_nr);
1692 game_status = last_game_status; /* restore current game status */
1697 /* scroll preview level, if needed */
1698 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1699 DelayReached(&scroll_delay, scroll_delay_value))
1701 switch (scroll_direction)
1706 from_x -= preview.step_offset;
1707 from_x = (from_x < 0 ? 0 : from_x);
1710 scroll_direction = MV_UP;
1714 if (from_x < level_xsize - preview.xsize)
1716 from_x += preview.step_offset;
1717 from_x = (from_x > level_xsize - preview.xsize ?
1718 level_xsize - preview.xsize : from_x);
1721 scroll_direction = MV_DOWN;
1727 from_y -= preview.step_offset;
1728 from_y = (from_y < 0 ? 0 : from_y);
1731 scroll_direction = MV_RIGHT;
1735 if (from_y < level_ysize - preview.ysize)
1737 from_y += preview.step_offset;
1738 from_y = (from_y > level_ysize - preview.ysize ?
1739 level_ysize - preview.ysize : from_y);
1742 scroll_direction = MV_LEFT;
1749 DrawPreviewLevelExt(from_x, from_y);
1752 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1753 /* redraw micro level label, if needed */
1754 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1755 !strEqual(level.author, ANONYMOUS_NAME) &&
1756 !strEqual(level.author, leveldir_current->name) &&
1757 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1759 int max_label_counter = 23;
1761 if (leveldir_current->imported_from != NULL &&
1762 strlen(leveldir_current->imported_from) > 0)
1763 max_label_counter += 14;
1764 if (leveldir_current->imported_by != NULL &&
1765 strlen(leveldir_current->imported_by) > 0)
1766 max_label_counter += 14;
1768 label_counter = (label_counter + 1) % max_label_counter;
1769 label_state = (label_counter >= 0 && label_counter <= 7 ?
1770 MICROLABEL_LEVEL_NAME :
1771 label_counter >= 9 && label_counter <= 12 ?
1772 MICROLABEL_LEVEL_AUTHOR_HEAD :
1773 label_counter >= 14 && label_counter <= 21 ?
1774 MICROLABEL_LEVEL_AUTHOR :
1775 label_counter >= 23 && label_counter <= 26 ?
1776 MICROLABEL_IMPORTED_FROM_HEAD :
1777 label_counter >= 28 && label_counter <= 35 ?
1778 MICROLABEL_IMPORTED_FROM :
1779 label_counter >= 37 && label_counter <= 40 ?
1780 MICROLABEL_IMPORTED_BY_HEAD :
1781 label_counter >= 42 && label_counter <= 49 ?
1782 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1784 if (leveldir_current->imported_from == NULL &&
1785 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1786 label_state == MICROLABEL_IMPORTED_FROM))
1787 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1788 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1790 DrawPreviewLevelLabelExt(label_state);
1793 game_status = last_game_status; /* restore current game status */
1796 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1797 int graphic, int sync_frame, int mask_mode)
1799 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1801 if (mask_mode == USE_MASKING)
1802 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1804 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1807 inline void DrawGraphicAnimation(int x, int y, int graphic)
1809 int lx = LEVELX(x), ly = LEVELY(y);
1811 if (!IN_SCR_FIELD(x, y))
1814 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1815 graphic, GfxFrame[lx][ly], NO_MASKING);
1816 MarkTileDirty(x, y);
1819 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1821 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1824 void DrawLevelElementAnimation(int x, int y, int element)
1826 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1828 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1831 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1833 int sx = SCREENX(x), sy = SCREENY(y);
1835 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1838 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1841 DrawGraphicAnimation(sx, sy, graphic);
1844 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1845 DrawLevelFieldCrumbledSand(x, y);
1847 if (GFX_CRUMBLED(Feld[x][y]))
1848 DrawLevelFieldCrumbledSand(x, y);
1852 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1854 int sx = SCREENX(x), sy = SCREENY(y);
1857 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1860 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1862 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1865 DrawGraphicAnimation(sx, sy, graphic);
1867 if (GFX_CRUMBLED(element))
1868 DrawLevelFieldCrumbledSand(x, y);
1871 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1873 if (player->use_murphy)
1875 /* this works only because currently only one player can be "murphy" ... */
1876 static int last_horizontal_dir = MV_LEFT;
1877 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1879 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1880 last_horizontal_dir = move_dir;
1882 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1884 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1886 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1892 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1895 static boolean equalGraphics(int graphic1, int graphic2)
1897 struct GraphicInfo *g1 = &graphic_info[graphic1];
1898 struct GraphicInfo *g2 = &graphic_info[graphic2];
1900 return (g1->bitmap == g2->bitmap &&
1901 g1->src_x == g2->src_x &&
1902 g1->src_y == g2->src_y &&
1903 g1->anim_frames == g2->anim_frames &&
1904 g1->anim_delay == g2->anim_delay &&
1905 g1->anim_mode == g2->anim_mode);
1908 void DrawAllPlayers()
1912 for (i = 0; i < MAX_PLAYERS; i++)
1913 if (stored_player[i].active)
1914 DrawPlayer(&stored_player[i]);
1917 void DrawPlayerField(int x, int y)
1919 if (!IS_PLAYER(x, y))
1922 DrawPlayer(PLAYERINFO(x, y));
1925 void DrawPlayer(struct PlayerInfo *player)
1927 int jx = player->jx;
1928 int jy = player->jy;
1929 int move_dir = player->MovDir;
1930 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1931 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1932 int last_jx = (player->is_moving ? jx - dx : jx);
1933 int last_jy = (player->is_moving ? jy - dy : jy);
1934 int next_jx = jx + dx;
1935 int next_jy = jy + dy;
1936 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1937 boolean player_is_opaque = FALSE;
1938 int sx = SCREENX(jx), sy = SCREENY(jy);
1939 int sxx = 0, syy = 0;
1940 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1942 int action = ACTION_DEFAULT;
1943 int last_player_graphic = getPlayerGraphic(player, move_dir);
1944 int last_player_frame = player->Frame;
1947 /* GfxElement[][] is set to the element the player is digging or collecting;
1948 remove also for off-screen player if the player is not moving anymore */
1949 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1950 GfxElement[jx][jy] = EL_UNDEFINED;
1952 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1956 if (!IN_LEV_FIELD(jx, jy))
1958 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1959 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1960 printf("DrawPlayerField(): This should never happen!\n");
1965 if (element == EL_EXPLOSION)
1968 action = (player->is_pushing ? ACTION_PUSHING :
1969 player->is_digging ? ACTION_DIGGING :
1970 player->is_collecting ? ACTION_COLLECTING :
1971 player->is_moving ? ACTION_MOVING :
1972 player->is_snapping ? ACTION_SNAPPING :
1973 player->is_dropping ? ACTION_DROPPING :
1974 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1976 if (player->is_waiting)
1977 move_dir = player->dir_waiting;
1979 InitPlayerGfxAnimation(player, action, move_dir);
1981 /* ----------------------------------------------------------------------- */
1982 /* draw things in the field the player is leaving, if needed */
1983 /* ----------------------------------------------------------------------- */
1985 if (player->is_moving)
1987 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1989 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1991 if (last_element == EL_DYNAMITE_ACTIVE ||
1992 last_element == EL_EM_DYNAMITE_ACTIVE ||
1993 last_element == EL_SP_DISK_RED_ACTIVE)
1994 DrawDynamite(last_jx, last_jy);
1996 DrawLevelFieldThruMask(last_jx, last_jy);
1998 else if (last_element == EL_DYNAMITE_ACTIVE ||
1999 last_element == EL_EM_DYNAMITE_ACTIVE ||
2000 last_element == EL_SP_DISK_RED_ACTIVE)
2001 DrawDynamite(last_jx, last_jy);
2003 /* !!! this is not enough to prevent flickering of players which are
2004 moving next to each others without a free tile between them -- this
2005 can only be solved by drawing all players layer by layer (first the
2006 background, then the foreground etc.) !!! => TODO */
2007 else if (!IS_PLAYER(last_jx, last_jy))
2008 DrawLevelField(last_jx, last_jy);
2011 DrawLevelField(last_jx, last_jy);
2014 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2015 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2018 if (!IN_SCR_FIELD(sx, sy))
2021 if (setup.direct_draw)
2022 SetDrawtoField(DRAW_BUFFERED);
2024 /* ----------------------------------------------------------------------- */
2025 /* draw things behind the player, if needed */
2026 /* ----------------------------------------------------------------------- */
2029 DrawLevelElement(jx, jy, Back[jx][jy]);
2030 else if (IS_ACTIVE_BOMB(element))
2031 DrawLevelElement(jx, jy, EL_EMPTY);
2034 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2036 int old_element = GfxElement[jx][jy];
2037 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2038 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2040 if (GFX_CRUMBLED(old_element))
2041 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2043 DrawGraphic(sx, sy, old_graphic, frame);
2045 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2046 player_is_opaque = TRUE;
2050 GfxElement[jx][jy] = EL_UNDEFINED;
2052 /* make sure that pushed elements are drawn with correct frame rate */
2054 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2056 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2057 GfxFrame[jx][jy] = player->StepFrame;
2059 if (player->is_pushing && player->is_moving)
2060 GfxFrame[jx][jy] = player->StepFrame;
2063 DrawLevelField(jx, jy);
2067 /* ----------------------------------------------------------------------- */
2068 /* draw player himself */
2069 /* ----------------------------------------------------------------------- */
2071 graphic = getPlayerGraphic(player, move_dir);
2073 /* in the case of changed player action or direction, prevent the current
2074 animation frame from being restarted for identical animations */
2075 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2076 player->Frame = last_player_frame;
2078 frame = getGraphicAnimationFrame(graphic, player->Frame);
2082 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2083 sxx = player->GfxPos;
2085 syy = player->GfxPos;
2088 if (!setup.soft_scrolling && ScreenMovPos)
2091 if (player_is_opaque)
2092 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2094 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2096 if (SHIELD_ON(player))
2098 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2099 IMG_SHIELD_NORMAL_ACTIVE);
2100 int frame = getGraphicAnimationFrame(graphic, -1);
2102 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2105 /* ----------------------------------------------------------------------- */
2106 /* draw things the player is pushing, if needed */
2107 /* ----------------------------------------------------------------------- */
2110 printf("::: %d, %d [%d, %d] [%d]\n",
2111 player->is_pushing, player_is_moving, player->GfxAction,
2112 player->is_moving, player_is_moving);
2116 if (player->is_pushing && player->is_moving)
2118 int px = SCREENX(jx), py = SCREENY(jy);
2119 int pxx = (TILEX - ABS(sxx)) * dx;
2120 int pyy = (TILEY - ABS(syy)) * dy;
2121 int gfx_frame = GfxFrame[jx][jy];
2127 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2129 element = Feld[next_jx][next_jy];
2130 gfx_frame = GfxFrame[next_jx][next_jy];
2133 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2136 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2137 frame = getGraphicAnimationFrame(graphic, sync_frame);
2139 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2142 /* draw background element under pushed element (like the Sokoban field) */
2143 if (Back[next_jx][next_jy])
2144 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2146 /* masked drawing is needed for EMC style (double) movement graphics */
2147 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2151 /* ----------------------------------------------------------------------- */
2152 /* draw things in front of player (active dynamite or dynabombs) */
2153 /* ----------------------------------------------------------------------- */
2155 if (IS_ACTIVE_BOMB(element))
2157 graphic = el2img(element);
2158 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2160 if (game.emulation == EMU_SUPAPLEX)
2161 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2163 DrawGraphicThruMask(sx, sy, graphic, frame);
2166 if (player_is_moving && last_element == EL_EXPLOSION)
2168 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2169 GfxElement[last_jx][last_jy] : EL_EMPTY);
2170 int graphic = el_act2img(element, ACTION_EXPLODING);
2171 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2172 int phase = ExplodePhase[last_jx][last_jy] - 1;
2173 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2176 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2179 /* ----------------------------------------------------------------------- */
2180 /* draw elements the player is just walking/passing through/under */
2181 /* ----------------------------------------------------------------------- */
2183 if (player_is_moving)
2185 /* handle the field the player is leaving ... */
2186 if (IS_ACCESSIBLE_INSIDE(last_element))
2187 DrawLevelField(last_jx, last_jy);
2188 else if (IS_ACCESSIBLE_UNDER(last_element))
2189 DrawLevelFieldThruMask(last_jx, last_jy);
2192 /* do not redraw accessible elements if the player is just pushing them */
2193 if (!player_is_moving || !player->is_pushing)
2195 /* ... and the field the player is entering */
2196 if (IS_ACCESSIBLE_INSIDE(element))
2197 DrawLevelField(jx, jy);
2198 else if (IS_ACCESSIBLE_UNDER(element))
2199 DrawLevelFieldThruMask(jx, jy);
2202 if (setup.direct_draw)
2204 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2205 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2206 int x_size = TILEX * (1 + ABS(jx - last_jx));
2207 int y_size = TILEY * (1 + ABS(jy - last_jy));
2209 BlitBitmap(drawto_field, window,
2210 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2211 SetDrawtoField(DRAW_DIRECT);
2214 MarkTileDirty(sx, sy);
2217 /* ------------------------------------------------------------------------- */
2219 void WaitForEventToContinue()
2221 boolean still_wait = TRUE;
2223 /* simulate releasing mouse button over last gadget, if still pressed */
2225 HandleGadgets(-1, -1, 0);
2227 button_status = MB_RELEASED;
2239 case EVENT_BUTTONPRESS:
2240 case EVENT_KEYPRESS:
2244 case EVENT_KEYRELEASE:
2245 ClearPlayerAction();
2249 HandleOtherEvents(&event);
2253 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2260 /* don't eat all CPU time */
2265 #define MAX_REQUEST_LINES 13
2266 #define MAX_REQUEST_LINE_FONT1_LEN 7
2267 #define MAX_REQUEST_LINE_FONT2_LEN 10
2269 boolean Request(char *text, unsigned int req_state)
2271 int mx, my, ty, result = -1;
2272 unsigned int old_door_state;
2273 int last_game_status = game_status; /* save current game status */
2274 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2275 int font_nr = FONT_TEXT_2;
2276 int max_word_len = 0;
2279 for (text_ptr = text; *text_ptr; text_ptr++)
2281 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2283 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2285 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2286 font_nr = FONT_LEVEL_NUMBER;
2292 if (game_status == GAME_MODE_PLAYING &&
2293 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2294 BlitScreenToBitmap_EM(backbuffer);
2296 /* disable deactivated drawing when quick-loading level tape recording */
2297 if (tape.playing && tape.deactivate_display)
2298 TapeDeactivateDisplayOff(TRUE);
2300 SetMouseCursor(CURSOR_DEFAULT);
2302 #if defined(NETWORK_AVALIABLE)
2303 /* pause network game while waiting for request to answer */
2304 if (options.network &&
2305 game_status == GAME_MODE_PLAYING &&
2306 req_state & REQUEST_WAIT_FOR_INPUT)
2307 SendToServer_PausePlaying();
2310 old_door_state = GetDoorState();
2312 /* simulate releasing mouse button over last gadget, if still pressed */
2314 HandleGadgets(-1, -1, 0);
2318 if (old_door_state & DOOR_OPEN_1)
2320 CloseDoor(DOOR_CLOSE_1);
2322 /* save old door content */
2323 BlitBitmap(bitmap_db_door, bitmap_db_door,
2324 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2325 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2329 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2332 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2334 /* clear door drawing field */
2335 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2337 /* force DOOR font on preview level */
2338 game_status = GAME_MODE_PSEUDO_DOOR;
2340 /* write text for request */
2341 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2343 char text_line[max_request_line_len + 1];
2349 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2352 if (!tc || tc == ' ')
2363 strncpy(text_line, text, tl);
2366 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2367 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2368 text_line, font_nr);
2370 text += tl + (tc == ' ' ? 1 : 0);
2373 game_status = last_game_status; /* restore current game status */
2375 if (req_state & REQ_ASK)
2377 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2378 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2380 else if (req_state & REQ_CONFIRM)
2382 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2384 else if (req_state & REQ_PLAYER)
2386 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2387 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2388 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2389 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2392 /* copy request gadgets to door backbuffer */
2393 BlitBitmap(drawto, bitmap_db_door,
2394 DX, DY, DXSIZE, DYSIZE,
2395 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2397 OpenDoor(DOOR_OPEN_1);
2399 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2401 if (game_status == GAME_MODE_PLAYING)
2403 SetPanelBackground();
2404 SetDrawBackgroundMask(REDRAW_DOOR_1);
2408 SetDrawBackgroundMask(REDRAW_FIELD);
2414 if (game_status != GAME_MODE_MAIN)
2417 button_status = MB_RELEASED;
2419 request_gadget_id = -1;
2421 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2433 case EVENT_BUTTONPRESS:
2434 case EVENT_BUTTONRELEASE:
2435 case EVENT_MOTIONNOTIFY:
2437 if (event.type == EVENT_MOTIONNOTIFY)
2439 if (!PointerInWindow(window))
2440 continue; /* window and pointer are on different screens */
2445 motion_status = TRUE;
2446 mx = ((MotionEvent *) &event)->x;
2447 my = ((MotionEvent *) &event)->y;
2451 motion_status = FALSE;
2452 mx = ((ButtonEvent *) &event)->x;
2453 my = ((ButtonEvent *) &event)->y;
2454 if (event.type == EVENT_BUTTONPRESS)
2455 button_status = ((ButtonEvent *) &event)->button;
2457 button_status = MB_RELEASED;
2460 /* this sets 'request_gadget_id' */
2461 HandleGadgets(mx, my, button_status);
2463 switch(request_gadget_id)
2465 case TOOL_CTRL_ID_YES:
2468 case TOOL_CTRL_ID_NO:
2471 case TOOL_CTRL_ID_CONFIRM:
2472 result = TRUE | FALSE;
2475 case TOOL_CTRL_ID_PLAYER_1:
2478 case TOOL_CTRL_ID_PLAYER_2:
2481 case TOOL_CTRL_ID_PLAYER_3:
2484 case TOOL_CTRL_ID_PLAYER_4:
2495 case EVENT_KEYPRESS:
2496 switch(GetEventKey((KeyEvent *)&event, TRUE))
2509 if (req_state & REQ_PLAYER)
2513 case EVENT_KEYRELEASE:
2514 ClearPlayerAction();
2518 HandleOtherEvents(&event);
2522 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2524 int joy = AnyJoystick();
2526 if (joy & JOY_BUTTON_1)
2528 else if (joy & JOY_BUTTON_2)
2534 /* don't eat all CPU time */
2538 if (game_status != GAME_MODE_MAIN)
2543 if (!(req_state & REQ_STAY_OPEN))
2545 CloseDoor(DOOR_CLOSE_1);
2547 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2548 (req_state & REQ_REOPEN))
2549 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2554 if (game_status == GAME_MODE_PLAYING)
2556 SetPanelBackground();
2557 SetDrawBackgroundMask(REDRAW_DOOR_1);
2561 SetDrawBackgroundMask(REDRAW_FIELD);
2564 #if defined(NETWORK_AVALIABLE)
2565 /* continue network game after request */
2566 if (options.network &&
2567 game_status == GAME_MODE_PLAYING &&
2568 req_state & REQUEST_WAIT_FOR_INPUT)
2569 SendToServer_ContinuePlaying();
2572 /* restore deactivated drawing when quick-loading level tape recording */
2573 if (tape.playing && tape.deactivate_display)
2574 TapeDeactivateDisplayOn();
2579 unsigned int OpenDoor(unsigned int door_state)
2581 if (door_state & DOOR_COPY_BACK)
2583 if (door_state & DOOR_OPEN_1)
2584 BlitBitmap(bitmap_db_door, bitmap_db_door,
2585 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2586 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2588 if (door_state & DOOR_OPEN_2)
2589 BlitBitmap(bitmap_db_door, bitmap_db_door,
2590 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2591 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2593 door_state &= ~DOOR_COPY_BACK;
2596 return MoveDoor(door_state);
2599 unsigned int CloseDoor(unsigned int door_state)
2601 unsigned int old_door_state = GetDoorState();
2603 if (!(door_state & DOOR_NO_COPY_BACK))
2605 if (old_door_state & DOOR_OPEN_1)
2606 BlitBitmap(backbuffer, bitmap_db_door,
2607 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2609 if (old_door_state & DOOR_OPEN_2)
2610 BlitBitmap(backbuffer, bitmap_db_door,
2611 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2613 door_state &= ~DOOR_NO_COPY_BACK;
2616 return MoveDoor(door_state);
2619 unsigned int GetDoorState()
2621 return MoveDoor(DOOR_GET_STATE);
2624 unsigned int SetDoorState(unsigned int door_state)
2626 return MoveDoor(door_state | DOOR_SET_STATE);
2629 unsigned int MoveDoor(unsigned int door_state)
2631 static int door1 = DOOR_OPEN_1;
2632 static int door2 = DOOR_CLOSE_2;
2633 unsigned long door_delay = 0;
2634 unsigned long door_delay_value;
2637 if (door_1.width < 0 || door_1.width > DXSIZE)
2638 door_1.width = DXSIZE;
2639 if (door_1.height < 0 || door_1.height > DYSIZE)
2640 door_1.height = DYSIZE;
2641 if (door_2.width < 0 || door_2.width > VXSIZE)
2642 door_2.width = VXSIZE;
2643 if (door_2.height < 0 || door_2.height > VYSIZE)
2644 door_2.height = VYSIZE;
2646 if (door_state == DOOR_GET_STATE)
2647 return (door1 | door2);
2649 if (door_state & DOOR_SET_STATE)
2651 if (door_state & DOOR_ACTION_1)
2652 door1 = door_state & DOOR_ACTION_1;
2653 if (door_state & DOOR_ACTION_2)
2654 door2 = door_state & DOOR_ACTION_2;
2656 return (door1 | door2);
2659 if (!(door_state & DOOR_FORCE_REDRAW))
2661 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2662 door_state &= ~DOOR_OPEN_1;
2663 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2664 door_state &= ~DOOR_CLOSE_1;
2665 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2666 door_state &= ~DOOR_OPEN_2;
2667 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2668 door_state &= ~DOOR_CLOSE_2;
2671 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2674 if (setup.quick_doors)
2676 stepsize = 20; /* must be choosen to always draw last frame */
2677 door_delay_value = 0;
2680 if (global.autoplay_leveldir)
2682 door_state |= DOOR_NO_DELAY;
2683 door_state &= ~DOOR_CLOSE_ALL;
2686 if (door_state & DOOR_ACTION)
2688 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2689 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2690 boolean door_1_done = (!handle_door_1);
2691 boolean door_2_done = (!handle_door_2);
2692 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2693 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2694 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2695 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2696 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2697 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2698 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2699 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2700 int door_skip = max_door_size - door_size;
2701 int end = door_size;
2702 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2705 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2707 /* opening door sound has priority over simultaneously closing door */
2708 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2709 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2710 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2711 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2714 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2717 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2718 GC gc = bitmap->stored_clip_gc;
2720 if (door_state & DOOR_ACTION_1)
2722 int a = MIN(x * door_1.step_offset, end);
2723 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2724 int i = p + door_skip;
2726 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2728 BlitBitmap(bitmap_db_door, drawto,
2729 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2730 DXSIZE, DYSIZE, DX, DY);
2734 BlitBitmap(bitmap_db_door, drawto,
2735 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2736 DXSIZE, DYSIZE - p / 2, DX, DY);
2738 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2741 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2743 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2744 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2745 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2746 int dst2_x = DX, dst2_y = DY;
2747 int width = i, height = DYSIZE;
2749 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2750 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2753 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2754 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2757 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2759 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2760 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2761 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2762 int dst2_x = DX, dst2_y = DY;
2763 int width = DXSIZE, height = i;
2765 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2766 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2769 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2770 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2773 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2775 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2777 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2778 BlitBitmapMasked(bitmap, drawto,
2779 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2780 DX + DXSIZE - i, DY + j);
2781 BlitBitmapMasked(bitmap, drawto,
2782 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2783 DX + DXSIZE - i, DY + 140 + j);
2784 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2785 DY - (DOOR_GFX_PAGEY1 + j));
2786 BlitBitmapMasked(bitmap, drawto,
2787 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2789 BlitBitmapMasked(bitmap, drawto,
2790 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2793 BlitBitmapMasked(bitmap, drawto,
2794 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2796 BlitBitmapMasked(bitmap, drawto,
2797 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2799 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2800 BlitBitmapMasked(bitmap, drawto,
2801 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2802 DX + DXSIZE - i, DY + 77 + j);
2803 BlitBitmapMasked(bitmap, drawto,
2804 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2805 DX + DXSIZE - i, DY + 203 + j);
2808 redraw_mask |= REDRAW_DOOR_1;
2809 door_1_done = (a == end);
2812 if (door_state & DOOR_ACTION_2)
2814 int a = MIN(x * door_2.step_offset, door_size);
2815 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2816 int i = p + door_skip;
2818 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2820 BlitBitmap(bitmap_db_door, drawto,
2821 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2822 VXSIZE, VYSIZE, VX, VY);
2824 else if (x <= VYSIZE)
2826 BlitBitmap(bitmap_db_door, drawto,
2827 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2828 VXSIZE, VYSIZE - p / 2, VX, VY);
2830 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2833 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2835 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2836 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2837 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2838 int dst2_x = VX, dst2_y = VY;
2839 int width = i, height = VYSIZE;
2841 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2842 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2845 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2846 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2849 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2851 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2852 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2853 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2854 int dst2_x = VX, dst2_y = VY;
2855 int width = VXSIZE, height = i;
2857 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2858 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2861 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2862 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2865 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2867 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2869 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2870 BlitBitmapMasked(bitmap, drawto,
2871 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2872 VX + VXSIZE - i, VY + j);
2873 SetClipOrigin(bitmap, gc,
2874 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2875 BlitBitmapMasked(bitmap, drawto,
2876 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2879 BlitBitmapMasked(bitmap, drawto,
2880 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2881 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2882 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2883 BlitBitmapMasked(bitmap, drawto,
2884 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2886 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2889 redraw_mask |= REDRAW_DOOR_2;
2890 door_2_done = (a == VXSIZE);
2893 if (!(door_state & DOOR_NO_DELAY))
2897 if (game_status == GAME_MODE_MAIN)
2900 WaitUntilDelayReached(&door_delay, door_delay_value);
2905 if (door_state & DOOR_ACTION_1)
2906 door1 = door_state & DOOR_ACTION_1;
2907 if (door_state & DOOR_ACTION_2)
2908 door2 = door_state & DOOR_ACTION_2;
2910 return (door1 | door2);
2913 void DrawSpecialEditorDoor()
2915 /* draw bigger toolbox window */
2916 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2917 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2919 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2920 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2923 redraw_mask |= REDRAW_ALL;
2926 void UndrawSpecialEditorDoor()
2928 /* draw normal tape recorder window */
2929 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2930 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2933 redraw_mask |= REDRAW_ALL;
2937 /* ---------- new tool button stuff ---------------------------------------- */
2939 /* graphic position values for tool buttons */
2940 #define TOOL_BUTTON_YES_XPOS 2
2941 #define TOOL_BUTTON_YES_YPOS 250
2942 #define TOOL_BUTTON_YES_GFX_YPOS 0
2943 #define TOOL_BUTTON_YES_XSIZE 46
2944 #define TOOL_BUTTON_YES_YSIZE 28
2945 #define TOOL_BUTTON_NO_XPOS 52
2946 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2947 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2948 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2949 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2950 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2951 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2952 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2953 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2954 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2955 #define TOOL_BUTTON_PLAYER_XSIZE 30
2956 #define TOOL_BUTTON_PLAYER_YSIZE 30
2957 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2958 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2959 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2960 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2961 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2962 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2963 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2964 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2965 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2966 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2967 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2968 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2969 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2970 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2971 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2972 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2973 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2974 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2975 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2976 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2985 } toolbutton_info[NUM_TOOL_BUTTONS] =
2988 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2989 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2990 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2995 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2996 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2997 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3002 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3003 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3004 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3005 TOOL_CTRL_ID_CONFIRM,
3009 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3010 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3011 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3012 TOOL_CTRL_ID_PLAYER_1,
3016 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3017 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3018 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3019 TOOL_CTRL_ID_PLAYER_2,
3023 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3024 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3025 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3026 TOOL_CTRL_ID_PLAYER_3,
3030 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3031 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3032 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3033 TOOL_CTRL_ID_PLAYER_4,
3038 void CreateToolButtons()
3042 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3044 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3045 Bitmap *deco_bitmap = None;
3046 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3047 struct GadgetInfo *gi;
3048 unsigned long event_mask;
3049 int gd_xoffset, gd_yoffset;
3050 int gd_x1, gd_x2, gd_y;
3053 event_mask = GD_EVENT_RELEASED;
3055 gd_xoffset = toolbutton_info[i].xpos;
3056 gd_yoffset = toolbutton_info[i].ypos;
3057 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3058 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3059 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3061 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3063 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3065 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3066 &deco_bitmap, &deco_x, &deco_y);
3067 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3068 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3071 gi = CreateGadget(GDI_CUSTOM_ID, id,
3072 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3073 GDI_X, DX + toolbutton_info[i].x,
3074 GDI_Y, DY + toolbutton_info[i].y,
3075 GDI_WIDTH, toolbutton_info[i].width,
3076 GDI_HEIGHT, toolbutton_info[i].height,
3077 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3078 GDI_STATE, GD_BUTTON_UNPRESSED,
3079 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3080 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3081 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3082 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3083 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3084 GDI_DECORATION_SHIFTING, 1, 1,
3085 GDI_EVENT_MASK, event_mask,
3086 GDI_CALLBACK_ACTION, HandleToolButtons,
3090 Error(ERR_EXIT, "cannot create gadget");
3092 tool_gadget[id] = gi;
3096 void FreeToolButtons()
3100 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3101 FreeGadget(tool_gadget[i]);
3104 static void UnmapToolButtons()
3108 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3109 UnmapGadget(tool_gadget[i]);
3112 static void HandleToolButtons(struct GadgetInfo *gi)
3114 request_gadget_id = gi->custom_id;
3117 static struct Mapping_EM_to_RND_object
3120 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3121 boolean is_backside; /* backside of moving element */
3127 em_object_mapping_list[] =
3130 Xblank, TRUE, FALSE,
3134 Yacid_splash_eB, FALSE, FALSE,
3135 EL_ACID_SPLASH_RIGHT, -1, -1
3138 Yacid_splash_wB, FALSE, FALSE,
3139 EL_ACID_SPLASH_LEFT, -1, -1
3142 #ifdef EM_ENGINE_BAD_ROLL
3144 Xstone_force_e, FALSE, FALSE,
3145 EL_ROCK, -1, MV_BIT_RIGHT
3148 Xstone_force_w, FALSE, FALSE,
3149 EL_ROCK, -1, MV_BIT_LEFT
3152 Xnut_force_e, FALSE, FALSE,
3153 EL_NUT, -1, MV_BIT_RIGHT
3156 Xnut_force_w, FALSE, FALSE,
3157 EL_NUT, -1, MV_BIT_LEFT
3160 Xspring_force_e, FALSE, FALSE,
3161 EL_SPRING, -1, MV_BIT_RIGHT
3164 Xspring_force_w, FALSE, FALSE,
3165 EL_SPRING, -1, MV_BIT_LEFT
3168 Xemerald_force_e, FALSE, FALSE,
3169 EL_EMERALD, -1, MV_BIT_RIGHT
3172 Xemerald_force_w, FALSE, FALSE,
3173 EL_EMERALD, -1, MV_BIT_LEFT
3176 Xdiamond_force_e, FALSE, FALSE,
3177 EL_DIAMOND, -1, MV_BIT_RIGHT
3180 Xdiamond_force_w, FALSE, FALSE,
3181 EL_DIAMOND, -1, MV_BIT_LEFT
3184 Xbomb_force_e, FALSE, FALSE,
3185 EL_BOMB, -1, MV_BIT_RIGHT
3188 Xbomb_force_w, FALSE, FALSE,
3189 EL_BOMB, -1, MV_BIT_LEFT
3191 #endif /* EM_ENGINE_BAD_ROLL */
3194 Xstone, TRUE, FALSE,
3198 Xstone_pause, FALSE, FALSE,
3202 Xstone_fall, FALSE, FALSE,
3206 Ystone_s, FALSE, FALSE,
3207 EL_ROCK, ACTION_FALLING, -1
3210 Ystone_sB, FALSE, TRUE,
3211 EL_ROCK, ACTION_FALLING, -1
3214 Ystone_e, FALSE, FALSE,
3215 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3218 Ystone_eB, FALSE, TRUE,
3219 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3222 Ystone_w, FALSE, FALSE,
3223 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3226 Ystone_wB, FALSE, TRUE,
3227 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3234 Xnut_pause, FALSE, FALSE,
3238 Xnut_fall, FALSE, FALSE,
3242 Ynut_s, FALSE, FALSE,
3243 EL_NUT, ACTION_FALLING, -1
3246 Ynut_sB, FALSE, TRUE,
3247 EL_NUT, ACTION_FALLING, -1
3250 Ynut_e, FALSE, FALSE,
3251 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3254 Ynut_eB, FALSE, TRUE,
3255 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3258 Ynut_w, FALSE, FALSE,
3259 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3262 Ynut_wB, FALSE, TRUE,
3263 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3266 Xbug_n, TRUE, FALSE,
3270 Xbug_e, TRUE, FALSE,
3271 EL_BUG_RIGHT, -1, -1
3274 Xbug_s, TRUE, FALSE,
3278 Xbug_w, TRUE, FALSE,
3282 Xbug_gon, FALSE, FALSE,
3286 Xbug_goe, FALSE, FALSE,
3287 EL_BUG_RIGHT, -1, -1
3290 Xbug_gos, FALSE, FALSE,
3294 Xbug_gow, FALSE, FALSE,
3298 Ybug_n, FALSE, FALSE,
3299 EL_BUG, ACTION_MOVING, MV_BIT_UP
3302 Ybug_nB, FALSE, TRUE,
3303 EL_BUG, ACTION_MOVING, MV_BIT_UP
3306 Ybug_e, FALSE, FALSE,
3307 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3310 Ybug_eB, FALSE, TRUE,
3311 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3314 Ybug_s, FALSE, FALSE,
3315 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3318 Ybug_sB, FALSE, TRUE,
3319 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3322 Ybug_w, FALSE, FALSE,
3323 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3326 Ybug_wB, FALSE, TRUE,
3327 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3330 Ybug_w_n, FALSE, FALSE,
3331 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3334 Ybug_n_e, FALSE, FALSE,
3335 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3338 Ybug_e_s, FALSE, FALSE,
3339 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3342 Ybug_s_w, FALSE, FALSE,
3343 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3346 Ybug_e_n, FALSE, FALSE,
3347 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3350 Ybug_s_e, FALSE, FALSE,
3351 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3354 Ybug_w_s, FALSE, FALSE,
3355 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3358 Ybug_n_w, FALSE, FALSE,
3359 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3362 Ybug_stone, FALSE, FALSE,
3363 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3366 Ybug_spring, FALSE, FALSE,
3367 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3370 Xtank_n, TRUE, FALSE,
3371 EL_SPACESHIP_UP, -1, -1
3374 Xtank_e, TRUE, FALSE,
3375 EL_SPACESHIP_RIGHT, -1, -1
3378 Xtank_s, TRUE, FALSE,
3379 EL_SPACESHIP_DOWN, -1, -1
3382 Xtank_w, TRUE, FALSE,
3383 EL_SPACESHIP_LEFT, -1, -1
3386 Xtank_gon, FALSE, FALSE,
3387 EL_SPACESHIP_UP, -1, -1
3390 Xtank_goe, FALSE, FALSE,
3391 EL_SPACESHIP_RIGHT, -1, -1
3394 Xtank_gos, FALSE, FALSE,
3395 EL_SPACESHIP_DOWN, -1, -1
3398 Xtank_gow, FALSE, FALSE,
3399 EL_SPACESHIP_LEFT, -1, -1
3402 Ytank_n, FALSE, FALSE,
3403 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3406 Ytank_nB, FALSE, TRUE,
3407 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3410 Ytank_e, FALSE, FALSE,
3411 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3414 Ytank_eB, FALSE, TRUE,
3415 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3418 Ytank_s, FALSE, FALSE,
3419 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3422 Ytank_sB, FALSE, TRUE,
3423 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3426 Ytank_w, FALSE, FALSE,
3427 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3430 Ytank_wB, FALSE, TRUE,
3431 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3434 Ytank_w_n, FALSE, FALSE,
3435 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3438 Ytank_n_e, FALSE, FALSE,
3439 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3442 Ytank_e_s, FALSE, FALSE,
3443 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3446 Ytank_s_w, FALSE, FALSE,
3447 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3450 Ytank_e_n, FALSE, FALSE,
3451 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3454 Ytank_s_e, FALSE, FALSE,
3455 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3458 Ytank_w_s, FALSE, FALSE,
3459 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3462 Ytank_n_w, FALSE, FALSE,
3463 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3466 Ytank_stone, FALSE, FALSE,
3467 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3470 Ytank_spring, FALSE, FALSE,
3471 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3474 Xandroid, TRUE, FALSE,
3475 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3478 Xandroid_1_n, FALSE, FALSE,
3479 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3482 Xandroid_2_n, FALSE, FALSE,
3483 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3486 Xandroid_1_e, FALSE, FALSE,
3487 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3490 Xandroid_2_e, FALSE, FALSE,
3491 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3494 Xandroid_1_w, FALSE, FALSE,
3495 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3498 Xandroid_2_w, FALSE, FALSE,
3499 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3502 Xandroid_1_s, FALSE, FALSE,
3503 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3506 Xandroid_2_s, FALSE, FALSE,
3507 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3510 Yandroid_n, FALSE, FALSE,
3511 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3514 Yandroid_nB, FALSE, TRUE,
3515 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3518 Yandroid_ne, FALSE, FALSE,
3519 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3522 Yandroid_neB, FALSE, TRUE,
3523 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3526 Yandroid_e, FALSE, FALSE,
3527 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3530 Yandroid_eB, FALSE, TRUE,
3531 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3534 Yandroid_se, FALSE, FALSE,
3535 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3538 Yandroid_seB, FALSE, TRUE,
3539 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3542 Yandroid_s, FALSE, FALSE,
3543 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3546 Yandroid_sB, FALSE, TRUE,
3547 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3550 Yandroid_sw, FALSE, FALSE,
3551 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3554 Yandroid_swB, FALSE, TRUE,
3555 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3558 Yandroid_w, FALSE, FALSE,
3559 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3562 Yandroid_wB, FALSE, TRUE,
3563 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3566 Yandroid_nw, FALSE, FALSE,
3567 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3570 Yandroid_nwB, FALSE, TRUE,
3571 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3574 Xspring, TRUE, FALSE,
3578 Xspring_pause, FALSE, FALSE,
3582 Xspring_e, FALSE, FALSE,
3586 Xspring_w, FALSE, FALSE,
3590 Xspring_fall, FALSE, FALSE,
3594 Yspring_s, FALSE, FALSE,
3595 EL_SPRING, ACTION_FALLING, -1
3598 Yspring_sB, FALSE, TRUE,
3599 EL_SPRING, ACTION_FALLING, -1
3602 Yspring_e, FALSE, FALSE,
3603 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3606 Yspring_eB, FALSE, TRUE,
3607 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3610 Yspring_w, FALSE, FALSE,
3611 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3614 Yspring_wB, FALSE, TRUE,
3615 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3618 Yspring_kill_e, FALSE, FALSE,
3619 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3622 Yspring_kill_eB, FALSE, TRUE,
3623 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3626 Yspring_kill_w, FALSE, FALSE,
3627 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3630 Yspring_kill_wB, FALSE, TRUE,
3631 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3634 Xeater_n, TRUE, FALSE,
3635 EL_YAMYAM_UP, -1, -1
3638 Xeater_e, TRUE, FALSE,
3639 EL_YAMYAM_RIGHT, -1, -1
3642 Xeater_w, TRUE, FALSE,
3643 EL_YAMYAM_LEFT, -1, -1
3646 Xeater_s, TRUE, FALSE,
3647 EL_YAMYAM_DOWN, -1, -1
3650 Yeater_n, FALSE, FALSE,
3651 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3654 Yeater_nB, FALSE, TRUE,
3655 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3658 Yeater_e, FALSE, FALSE,
3659 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3662 Yeater_eB, FALSE, TRUE,
3663 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3666 Yeater_s, FALSE, FALSE,
3667 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3670 Yeater_sB, FALSE, TRUE,
3671 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3674 Yeater_w, FALSE, FALSE,
3675 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3678 Yeater_wB, FALSE, TRUE,
3679 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3682 Yeater_stone, FALSE, FALSE,
3683 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3686 Yeater_spring, FALSE, FALSE,
3687 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3690 Xalien, TRUE, FALSE,
3694 Xalien_pause, FALSE, FALSE,
3698 Yalien_n, FALSE, FALSE,
3699 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3702 Yalien_nB, FALSE, TRUE,
3703 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3706 Yalien_e, FALSE, FALSE,
3707 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3710 Yalien_eB, FALSE, TRUE,
3711 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3714 Yalien_s, FALSE, FALSE,
3715 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3718 Yalien_sB, FALSE, TRUE,
3719 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3722 Yalien_w, FALSE, FALSE,
3723 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3726 Yalien_wB, FALSE, TRUE,
3727 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3730 Yalien_stone, FALSE, FALSE,
3731 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3734 Yalien_spring, FALSE, FALSE,
3735 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3738 Xemerald, TRUE, FALSE,
3742 Xemerald_pause, FALSE, FALSE,
3746 Xemerald_fall, FALSE, FALSE,
3750 Xemerald_shine, FALSE, FALSE,
3751 EL_EMERALD, ACTION_TWINKLING, -1
3754 Yemerald_s, FALSE, FALSE,
3755 EL_EMERALD, ACTION_FALLING, -1
3758 Yemerald_sB, FALSE, TRUE,
3759 EL_EMERALD, ACTION_FALLING, -1
3762 Yemerald_e, FALSE, FALSE,
3763 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3766 Yemerald_eB, FALSE, TRUE,
3767 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3770 Yemerald_w, FALSE, FALSE,
3771 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3774 Yemerald_wB, FALSE, TRUE,
3775 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3778 Yemerald_eat, FALSE, FALSE,
3779 EL_EMERALD, ACTION_COLLECTING, -1
3782 Yemerald_stone, FALSE, FALSE,
3783 EL_NUT, ACTION_BREAKING, -1
3786 Xdiamond, TRUE, FALSE,
3790 Xdiamond_pause, FALSE, FALSE,
3794 Xdiamond_fall, FALSE, FALSE,
3798 Xdiamond_shine, FALSE, FALSE,
3799 EL_DIAMOND, ACTION_TWINKLING, -1
3802 Ydiamond_s, FALSE, FALSE,
3803 EL_DIAMOND, ACTION_FALLING, -1
3806 Ydiamond_sB, FALSE, TRUE,
3807 EL_DIAMOND, ACTION_FALLING, -1
3810 Ydiamond_e, FALSE, FALSE,
3811 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3814 Ydiamond_eB, FALSE, TRUE,
3815 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3818 Ydiamond_w, FALSE, FALSE,
3819 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3822 Ydiamond_wB, FALSE, TRUE,
3823 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3826 Ydiamond_eat, FALSE, FALSE,
3827 EL_DIAMOND, ACTION_COLLECTING, -1
3830 Ydiamond_stone, FALSE, FALSE,
3831 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3834 Xdrip_fall, TRUE, FALSE,
3835 EL_AMOEBA_DROP, -1, -1
3838 Xdrip_stretch, FALSE, FALSE,
3839 EL_AMOEBA_DROP, ACTION_FALLING, -1
3842 Xdrip_stretchB, FALSE, TRUE,
3843 EL_AMOEBA_DROP, ACTION_FALLING, -1
3846 Xdrip_eat, FALSE, FALSE,
3847 EL_AMOEBA_DROP, ACTION_GROWING, -1
3850 Ydrip_s1, FALSE, FALSE,
3851 EL_AMOEBA_DROP, ACTION_FALLING, -1
3854 Ydrip_s1B, FALSE, TRUE,
3855 EL_AMOEBA_DROP, ACTION_FALLING, -1
3858 Ydrip_s2, FALSE, FALSE,
3859 EL_AMOEBA_DROP, ACTION_FALLING, -1
3862 Ydrip_s2B, FALSE, TRUE,
3863 EL_AMOEBA_DROP, ACTION_FALLING, -1
3870 Xbomb_pause, FALSE, FALSE,
3874 Xbomb_fall, FALSE, FALSE,
3878 Ybomb_s, FALSE, FALSE,
3879 EL_BOMB, ACTION_FALLING, -1
3882 Ybomb_sB, FALSE, TRUE,
3883 EL_BOMB, ACTION_FALLING, -1
3886 Ybomb_e, FALSE, FALSE,
3887 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3890 Ybomb_eB, FALSE, TRUE,
3891 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3894 Ybomb_w, FALSE, FALSE,
3895 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3898 Ybomb_wB, FALSE, TRUE,
3899 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3902 Ybomb_eat, FALSE, FALSE,
3903 EL_BOMB, ACTION_ACTIVATING, -1
3906 Xballoon, TRUE, FALSE,
3910 Yballoon_n, FALSE, FALSE,
3911 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3914 Yballoon_nB, FALSE, TRUE,
3915 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3918 Yballoon_e, FALSE, FALSE,
3919 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3922 Yballoon_eB, FALSE, TRUE,
3923 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3926 Yballoon_s, FALSE, FALSE,
3927 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3930 Yballoon_sB, FALSE, TRUE,
3931 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3934 Yballoon_w, FALSE, FALSE,
3935 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3938 Yballoon_wB, FALSE, TRUE,
3939 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3942 Xgrass, TRUE, FALSE,
3943 EL_EMC_GRASS, -1, -1
3946 Ygrass_nB, FALSE, FALSE,
3947 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3950 Ygrass_eB, FALSE, FALSE,
3951 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3954 Ygrass_sB, FALSE, FALSE,
3955 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3958 Ygrass_wB, FALSE, FALSE,
3959 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3966 Ydirt_nB, FALSE, FALSE,
3967 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3970 Ydirt_eB, FALSE, FALSE,
3971 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3974 Ydirt_sB, FALSE, FALSE,
3975 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3978 Ydirt_wB, FALSE, FALSE,
3979 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3982 Xacid_ne, TRUE, FALSE,
3983 EL_ACID_POOL_TOPRIGHT, -1, -1
3986 Xacid_se, TRUE, FALSE,
3987 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3990 Xacid_s, TRUE, FALSE,
3991 EL_ACID_POOL_BOTTOM, -1, -1
3994 Xacid_sw, TRUE, FALSE,
3995 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3998 Xacid_nw, TRUE, FALSE,
3999 EL_ACID_POOL_TOPLEFT, -1, -1
4002 Xacid_1, TRUE, FALSE,
4006 Xacid_2, FALSE, FALSE,
4010 Xacid_3, FALSE, FALSE,
4014 Xacid_4, FALSE, FALSE,
4018 Xacid_5, FALSE, FALSE,
4022 Xacid_6, FALSE, FALSE,
4026 Xacid_7, FALSE, FALSE,
4030 Xacid_8, FALSE, FALSE,
4034 Xball_1, TRUE, FALSE,
4035 EL_EMC_MAGIC_BALL, -1, -1
4038 Xball_1B, FALSE, FALSE,
4039 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4042 Xball_2, FALSE, FALSE,
4043 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4046 Xball_2B, FALSE, FALSE,
4047 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4050 Yball_eat, FALSE, FALSE,
4051 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4054 Ykey_1_eat, FALSE, FALSE,
4055 EL_EM_KEY_1, ACTION_COLLECTING, -1
4058 Ykey_2_eat, FALSE, FALSE,
4059 EL_EM_KEY_2, ACTION_COLLECTING, -1
4062 Ykey_3_eat, FALSE, FALSE,
4063 EL_EM_KEY_3, ACTION_COLLECTING, -1
4066 Ykey_4_eat, FALSE, FALSE,
4067 EL_EM_KEY_4, ACTION_COLLECTING, -1
4070 Ykey_5_eat, FALSE, FALSE,
4071 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4074 Ykey_6_eat, FALSE, FALSE,
4075 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4078 Ykey_7_eat, FALSE, FALSE,
4079 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4082 Ykey_8_eat, FALSE, FALSE,
4083 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4086 Ylenses_eat, FALSE, FALSE,
4087 EL_EMC_LENSES, ACTION_COLLECTING, -1
4090 Ymagnify_eat, FALSE, FALSE,
4091 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4094 Ygrass_eat, FALSE, FALSE,
4095 EL_EMC_GRASS, ACTION_SNAPPING, -1
4098 Ydirt_eat, FALSE, FALSE,
4099 EL_SAND, ACTION_SNAPPING, -1
4102 Xgrow_ns, TRUE, FALSE,
4103 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4106 Ygrow_ns_eat, FALSE, FALSE,
4107 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4110 Xgrow_ew, TRUE, FALSE,
4111 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4114 Ygrow_ew_eat, FALSE, FALSE,
4115 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4118 Xwonderwall, TRUE, FALSE,
4119 EL_MAGIC_WALL, -1, -1
4122 XwonderwallB, FALSE, FALSE,
4123 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4126 Xamoeba_1, TRUE, FALSE,
4127 EL_AMOEBA_DRY, ACTION_OTHER, -1
4130 Xamoeba_2, FALSE, FALSE,
4131 EL_AMOEBA_DRY, ACTION_OTHER, -1
4134 Xamoeba_3, FALSE, FALSE,
4135 EL_AMOEBA_DRY, ACTION_OTHER, -1
4138 Xamoeba_4, FALSE, FALSE,
4139 EL_AMOEBA_DRY, ACTION_OTHER, -1
4142 Xamoeba_5, TRUE, FALSE,
4143 EL_AMOEBA_WET, ACTION_OTHER, -1
4146 Xamoeba_6, FALSE, FALSE,
4147 EL_AMOEBA_WET, ACTION_OTHER, -1
4150 Xamoeba_7, FALSE, FALSE,
4151 EL_AMOEBA_WET, ACTION_OTHER, -1
4154 Xamoeba_8, FALSE, FALSE,
4155 EL_AMOEBA_WET, ACTION_OTHER, -1
4158 Xdoor_1, TRUE, FALSE,
4159 EL_EM_GATE_1, -1, -1
4162 Xdoor_2, TRUE, FALSE,
4163 EL_EM_GATE_2, -1, -1
4166 Xdoor_3, TRUE, FALSE,
4167 EL_EM_GATE_3, -1, -1
4170 Xdoor_4, TRUE, FALSE,
4171 EL_EM_GATE_4, -1, -1
4174 Xdoor_5, TRUE, FALSE,
4175 EL_EMC_GATE_5, -1, -1
4178 Xdoor_6, TRUE, FALSE,
4179 EL_EMC_GATE_6, -1, -1
4182 Xdoor_7, TRUE, FALSE,
4183 EL_EMC_GATE_7, -1, -1
4186 Xdoor_8, TRUE, FALSE,
4187 EL_EMC_GATE_8, -1, -1
4190 Xkey_1, TRUE, FALSE,
4194 Xkey_2, TRUE, FALSE,
4198 Xkey_3, TRUE, FALSE,
4202 Xkey_4, TRUE, FALSE,
4206 Xkey_5, TRUE, FALSE,
4207 EL_EMC_KEY_5, -1, -1
4210 Xkey_6, TRUE, FALSE,
4211 EL_EMC_KEY_6, -1, -1
4214 Xkey_7, TRUE, FALSE,
4215 EL_EMC_KEY_7, -1, -1
4218 Xkey_8, TRUE, FALSE,
4219 EL_EMC_KEY_8, -1, -1
4222 Xwind_n, TRUE, FALSE,
4223 EL_BALLOON_SWITCH_UP, -1, -1
4226 Xwind_e, TRUE, FALSE,
4227 EL_BALLOON_SWITCH_RIGHT, -1, -1
4230 Xwind_s, TRUE, FALSE,
4231 EL_BALLOON_SWITCH_DOWN, -1, -1
4234 Xwind_w, TRUE, FALSE,
4235 EL_BALLOON_SWITCH_LEFT, -1, -1
4238 Xwind_nesw, TRUE, FALSE,
4239 EL_BALLOON_SWITCH_ANY, -1, -1
4242 Xwind_stop, TRUE, FALSE,
4243 EL_BALLOON_SWITCH_NONE, -1, -1
4247 EL_EXIT_CLOSED, -1, -1
4250 Xexit_1, TRUE, FALSE,
4251 EL_EXIT_OPEN, -1, -1
4254 Xexit_2, FALSE, FALSE,
4255 EL_EXIT_OPEN, -1, -1
4258 Xexit_3, FALSE, FALSE,
4259 EL_EXIT_OPEN, -1, -1
4262 Xdynamite, TRUE, FALSE,
4263 EL_EM_DYNAMITE, -1, -1
4266 Ydynamite_eat, FALSE, FALSE,
4267 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4270 Xdynamite_1, TRUE, FALSE,
4271 EL_EM_DYNAMITE_ACTIVE, -1, -1
4274 Xdynamite_2, FALSE, FALSE,
4275 EL_EM_DYNAMITE_ACTIVE, -1, -1
4278 Xdynamite_3, FALSE, FALSE,
4279 EL_EM_DYNAMITE_ACTIVE, -1, -1
4282 Xdynamite_4, FALSE, FALSE,
4283 EL_EM_DYNAMITE_ACTIVE, -1, -1
4286 Xbumper, TRUE, FALSE,
4287 EL_EMC_SPRING_BUMPER, -1, -1
4290 XbumperB, FALSE, FALSE,
4291 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4294 Xwheel, TRUE, FALSE,
4295 EL_ROBOT_WHEEL, -1, -1
4298 XwheelB, FALSE, FALSE,
4299 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4302 Xswitch, TRUE, FALSE,
4303 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4306 XswitchB, FALSE, FALSE,
4307 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4311 EL_QUICKSAND_EMPTY, -1, -1
4314 Xsand_stone, TRUE, FALSE,
4315 EL_QUICKSAND_FULL, -1, -1
4318 Xsand_stonein_1, FALSE, TRUE,
4319 EL_ROCK, ACTION_FILLING, -1
4322 Xsand_stonein_2, FALSE, TRUE,
4323 EL_ROCK, ACTION_FILLING, -1
4326 Xsand_stonein_3, FALSE, TRUE,
4327 EL_ROCK, ACTION_FILLING, -1
4330 Xsand_stonein_4, FALSE, TRUE,
4331 EL_ROCK, ACTION_FILLING, -1
4334 Xsand_stonesand_1, FALSE, FALSE,
4335 EL_QUICKSAND_FULL, -1, -1
4338 Xsand_stonesand_2, FALSE, FALSE,
4339 EL_QUICKSAND_FULL, -1, -1
4342 Xsand_stonesand_3, FALSE, FALSE,
4343 EL_QUICKSAND_FULL, -1, -1
4346 Xsand_stonesand_4, FALSE, FALSE,
4347 EL_QUICKSAND_FULL, -1, -1
4350 Xsand_stoneout_1, FALSE, FALSE,
4351 EL_ROCK, ACTION_EMPTYING, -1
4354 Xsand_stoneout_2, FALSE, FALSE,
4355 EL_ROCK, ACTION_EMPTYING, -1
4358 Xsand_sandstone_1, FALSE, FALSE,
4359 EL_QUICKSAND_FULL, -1, -1
4362 Xsand_sandstone_2, FALSE, FALSE,
4363 EL_QUICKSAND_FULL, -1, -1
4366 Xsand_sandstone_3, FALSE, FALSE,
4367 EL_QUICKSAND_FULL, -1, -1
4370 Xsand_sandstone_4, FALSE, FALSE,
4371 EL_QUICKSAND_FULL, -1, -1
4374 Xplant, TRUE, FALSE,
4375 EL_EMC_PLANT, -1, -1
4378 Yplant, FALSE, FALSE,
4379 EL_EMC_PLANT, -1, -1
4382 Xlenses, TRUE, FALSE,
4383 EL_EMC_LENSES, -1, -1
4386 Xmagnify, TRUE, FALSE,
4387 EL_EMC_MAGNIFIER, -1, -1
4390 Xdripper, TRUE, FALSE,
4391 EL_EMC_DRIPPER, -1, -1
4394 XdripperB, FALSE, FALSE,
4395 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4398 Xfake_blank, TRUE, FALSE,
4399 EL_INVISIBLE_WALL, -1, -1
4402 Xfake_blankB, FALSE, FALSE,
4403 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4406 Xfake_grass, TRUE, FALSE,
4407 EL_EMC_FAKE_GRASS, -1, -1
4410 Xfake_grassB, FALSE, FALSE,
4411 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4414 Xfake_door_1, TRUE, FALSE,
4415 EL_EM_GATE_1_GRAY, -1, -1
4418 Xfake_door_2, TRUE, FALSE,
4419 EL_EM_GATE_2_GRAY, -1, -1
4422 Xfake_door_3, TRUE, FALSE,
4423 EL_EM_GATE_3_GRAY, -1, -1
4426 Xfake_door_4, TRUE, FALSE,
4427 EL_EM_GATE_4_GRAY, -1, -1
4430 Xfake_door_5, TRUE, FALSE,
4431 EL_EMC_GATE_5_GRAY, -1, -1
4434 Xfake_door_6, TRUE, FALSE,
4435 EL_EMC_GATE_6_GRAY, -1, -1
4438 Xfake_door_7, TRUE, FALSE,
4439 EL_EMC_GATE_7_GRAY, -1, -1
4442 Xfake_door_8, TRUE, FALSE,
4443 EL_EMC_GATE_8_GRAY, -1, -1
4446 Xfake_acid_1, TRUE, FALSE,
4447 EL_EMC_FAKE_ACID, -1, -1
4450 Xfake_acid_2, FALSE, FALSE,
4451 EL_EMC_FAKE_ACID, -1, -1
4454 Xfake_acid_3, FALSE, FALSE,
4455 EL_EMC_FAKE_ACID, -1, -1
4458 Xfake_acid_4, FALSE, FALSE,
4459 EL_EMC_FAKE_ACID, -1, -1
4462 Xfake_acid_5, FALSE, FALSE,
4463 EL_EMC_FAKE_ACID, -1, -1
4466 Xfake_acid_6, FALSE, FALSE,
4467 EL_EMC_FAKE_ACID, -1, -1
4470 Xfake_acid_7, FALSE, FALSE,
4471 EL_EMC_FAKE_ACID, -1, -1
4474 Xfake_acid_8, FALSE, FALSE,
4475 EL_EMC_FAKE_ACID, -1, -1
4478 Xsteel_1, TRUE, FALSE,
4479 EL_STEELWALL, -1, -1
4482 Xsteel_2, TRUE, FALSE,
4483 EL_EMC_STEELWALL_2, -1, -1
4486 Xsteel_3, TRUE, FALSE,
4487 EL_EMC_STEELWALL_3, -1, -1
4490 Xsteel_4, TRUE, FALSE,
4491 EL_EMC_STEELWALL_4, -1, -1
4494 Xwall_1, TRUE, FALSE,
4498 Xwall_2, TRUE, FALSE,
4499 EL_EMC_WALL_14, -1, -1
4502 Xwall_3, TRUE, FALSE,
4503 EL_EMC_WALL_15, -1, -1
4506 Xwall_4, TRUE, FALSE,
4507 EL_EMC_WALL_16, -1, -1
4510 Xround_wall_1, TRUE, FALSE,
4511 EL_WALL_SLIPPERY, -1, -1
4514 Xround_wall_2, TRUE, FALSE,
4515 EL_EMC_WALL_SLIPPERY_2, -1, -1
4518 Xround_wall_3, TRUE, FALSE,
4519 EL_EMC_WALL_SLIPPERY_3, -1, -1
4522 Xround_wall_4, TRUE, FALSE,
4523 EL_EMC_WALL_SLIPPERY_4, -1, -1
4526 Xdecor_1, TRUE, FALSE,
4527 EL_EMC_WALL_8, -1, -1
4530 Xdecor_2, TRUE, FALSE,
4531 EL_EMC_WALL_6, -1, -1
4534 Xdecor_3, TRUE, FALSE,
4535 EL_EMC_WALL_4, -1, -1
4538 Xdecor_4, TRUE, FALSE,
4539 EL_EMC_WALL_7, -1, -1
4542 Xdecor_5, TRUE, FALSE,
4543 EL_EMC_WALL_5, -1, -1
4546 Xdecor_6, TRUE, FALSE,
4547 EL_EMC_WALL_9, -1, -1
4550 Xdecor_7, TRUE, FALSE,
4551 EL_EMC_WALL_10, -1, -1
4554 Xdecor_8, TRUE, FALSE,
4555 EL_EMC_WALL_1, -1, -1
4558 Xdecor_9, TRUE, FALSE,
4559 EL_EMC_WALL_2, -1, -1
4562 Xdecor_10, TRUE, FALSE,
4563 EL_EMC_WALL_3, -1, -1
4566 Xdecor_11, TRUE, FALSE,
4567 EL_EMC_WALL_11, -1, -1
4570 Xdecor_12, TRUE, FALSE,
4571 EL_EMC_WALL_12, -1, -1
4574 Xalpha_0, TRUE, FALSE,
4575 EL_CHAR('0'), -1, -1
4578 Xalpha_1, TRUE, FALSE,
4579 EL_CHAR('1'), -1, -1
4582 Xalpha_2, TRUE, FALSE,
4583 EL_CHAR('2'), -1, -1
4586 Xalpha_3, TRUE, FALSE,
4587 EL_CHAR('3'), -1, -1
4590 Xalpha_4, TRUE, FALSE,
4591 EL_CHAR('4'), -1, -1
4594 Xalpha_5, TRUE, FALSE,
4595 EL_CHAR('5'), -1, -1
4598 Xalpha_6, TRUE, FALSE,
4599 EL_CHAR('6'), -1, -1
4602 Xalpha_7, TRUE, FALSE,
4603 EL_CHAR('7'), -1, -1
4606 Xalpha_8, TRUE, FALSE,
4607 EL_CHAR('8'), -1, -1
4610 Xalpha_9, TRUE, FALSE,
4611 EL_CHAR('9'), -1, -1
4614 Xalpha_excla, TRUE, FALSE,
4615 EL_CHAR('!'), -1, -1
4618 Xalpha_quote, TRUE, FALSE,
4619 EL_CHAR('"'), -1, -1
4622 Xalpha_comma, TRUE, FALSE,
4623 EL_CHAR(','), -1, -1
4626 Xalpha_minus, TRUE, FALSE,
4627 EL_CHAR('-'), -1, -1
4630 Xalpha_perio, TRUE, FALSE,
4631 EL_CHAR('.'), -1, -1
4634 Xalpha_colon, TRUE, FALSE,
4635 EL_CHAR(':'), -1, -1
4638 Xalpha_quest, TRUE, FALSE,
4639 EL_CHAR('?'), -1, -1
4642 Xalpha_a, TRUE, FALSE,
4643 EL_CHAR('A'), -1, -1
4646 Xalpha_b, TRUE, FALSE,
4647 EL_CHAR('B'), -1, -1
4650 Xalpha_c, TRUE, FALSE,
4651 EL_CHAR('C'), -1, -1
4654 Xalpha_d, TRUE, FALSE,
4655 EL_CHAR('D'), -1, -1
4658 Xalpha_e, TRUE, FALSE,
4659 EL_CHAR('E'), -1, -1
4662 Xalpha_f, TRUE, FALSE,
4663 EL_CHAR('F'), -1, -1
4666 Xalpha_g, TRUE, FALSE,
4667 EL_CHAR('G'), -1, -1
4670 Xalpha_h, TRUE, FALSE,
4671 EL_CHAR('H'), -1, -1
4674 Xalpha_i, TRUE, FALSE,
4675 EL_CHAR('I'), -1, -1
4678 Xalpha_j, TRUE, FALSE,
4679 EL_CHAR('J'), -1, -1
4682 Xalpha_k, TRUE, FALSE,
4683 EL_CHAR('K'), -1, -1
4686 Xalpha_l, TRUE, FALSE,
4687 EL_CHAR('L'), -1, -1
4690 Xalpha_m, TRUE, FALSE,
4691 EL_CHAR('M'), -1, -1
4694 Xalpha_n, TRUE, FALSE,
4695 EL_CHAR('N'), -1, -1
4698 Xalpha_o, TRUE, FALSE,
4699 EL_CHAR('O'), -1, -1
4702 Xalpha_p, TRUE, FALSE,
4703 EL_CHAR('P'), -1, -1
4706 Xalpha_q, TRUE, FALSE,
4707 EL_CHAR('Q'), -1, -1
4710 Xalpha_r, TRUE, FALSE,
4711 EL_CHAR('R'), -1, -1
4714 Xalpha_s, TRUE, FALSE,
4715 EL_CHAR('S'), -1, -1
4718 Xalpha_t, TRUE, FALSE,
4719 EL_CHAR('T'), -1, -1
4722 Xalpha_u, TRUE, FALSE,
4723 EL_CHAR('U'), -1, -1
4726 Xalpha_v, TRUE, FALSE,
4727 EL_CHAR('V'), -1, -1
4730 Xalpha_w, TRUE, FALSE,
4731 EL_CHAR('W'), -1, -1
4734 Xalpha_x, TRUE, FALSE,
4735 EL_CHAR('X'), -1, -1
4738 Xalpha_y, TRUE, FALSE,
4739 EL_CHAR('Y'), -1, -1
4742 Xalpha_z, TRUE, FALSE,
4743 EL_CHAR('Z'), -1, -1
4746 Xalpha_arrow_e, TRUE, FALSE,
4747 EL_CHAR('>'), -1, -1
4750 Xalpha_arrow_w, TRUE, FALSE,
4751 EL_CHAR('<'), -1, -1
4754 Xalpha_copyr, TRUE, FALSE,
4755 EL_CHAR('©'), -1, -1
4759 Xboom_bug, FALSE, FALSE,
4760 EL_BUG, ACTION_EXPLODING, -1
4763 Xboom_bomb, FALSE, FALSE,
4764 EL_BOMB, ACTION_EXPLODING, -1
4767 Xboom_android, FALSE, FALSE,
4768 EL_EMC_ANDROID, ACTION_OTHER, -1
4771 Xboom_1, FALSE, FALSE,
4772 EL_DEFAULT, ACTION_EXPLODING, -1
4775 Xboom_2, FALSE, FALSE,
4776 EL_DEFAULT, ACTION_EXPLODING, -1
4779 Znormal, FALSE, FALSE,
4783 Zdynamite, FALSE, FALSE,
4787 Zplayer, FALSE, FALSE,
4791 ZBORDER, FALSE, FALSE,
4801 static struct Mapping_EM_to_RND_player
4810 em_player_mapping_list[] =
4814 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4818 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4822 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4826 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4830 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4834 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4838 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4842 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4846 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4850 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4854 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4858 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4862 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4866 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4870 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4874 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4878 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4882 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4886 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4890 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4894 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4898 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4902 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4906 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4910 EL_PLAYER_1, ACTION_DEFAULT, -1,
4914 EL_PLAYER_2, ACTION_DEFAULT, -1,
4918 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4922 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4926 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4930 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4934 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4938 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4942 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4946 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4950 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4954 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4958 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4962 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4966 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4970 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4974 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4978 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4982 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4986 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4990 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4994 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4998 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5002 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5006 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5010 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5014 EL_PLAYER_3, ACTION_DEFAULT, -1,
5018 EL_PLAYER_4, ACTION_DEFAULT, -1,
5027 int map_element_RND_to_EM(int element_rnd)
5029 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5030 static boolean mapping_initialized = FALSE;
5032 if (!mapping_initialized)
5036 /* return "Xalpha_quest" for all undefined elements in mapping array */
5037 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5038 mapping_RND_to_EM[i] = Xalpha_quest;
5040 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5041 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5042 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5043 em_object_mapping_list[i].element_em;
5045 mapping_initialized = TRUE;
5048 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5049 return mapping_RND_to_EM[element_rnd];
5051 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5056 int map_element_EM_to_RND(int element_em)
5058 static unsigned short mapping_EM_to_RND[TILE_MAX];
5059 static boolean mapping_initialized = FALSE;
5061 if (!mapping_initialized)
5065 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5066 for (i = 0; i < TILE_MAX; i++)
5067 mapping_EM_to_RND[i] = EL_UNKNOWN;
5069 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5070 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5071 em_object_mapping_list[i].element_rnd;
5073 mapping_initialized = TRUE;
5076 if (element_em >= 0 && element_em < TILE_MAX)
5077 return mapping_EM_to_RND[element_em];
5079 Error(ERR_WARN, "invalid EM level element %d", element_em);
5084 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5086 struct LevelInfo_EM *level_em = level->native_em_level;
5087 struct LEVEL *lev = level_em->lev;
5090 for (i = 0; i < TILE_MAX; i++)
5091 lev->android_array[i] = Xblank;
5093 for (i = 0; i < level->num_android_clone_elements; i++)
5095 int element_rnd = level->android_clone_element[i];
5096 int element_em = map_element_RND_to_EM(element_rnd);
5098 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5099 if (em_object_mapping_list[j].element_rnd == element_rnd)
5100 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5104 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5106 struct LevelInfo_EM *level_em = level->native_em_level;
5107 struct LEVEL *lev = level_em->lev;
5110 level->num_android_clone_elements = 0;
5112 for (i = 0; i < TILE_MAX; i++)
5114 int element_em = lev->android_array[i];
5116 boolean element_found = FALSE;
5118 if (element_em == Xblank)
5121 element_rnd = map_element_EM_to_RND(element_em);
5123 for (j = 0; j < level->num_android_clone_elements; j++)
5124 if (level->android_clone_element[j] == element_rnd)
5125 element_found = TRUE;
5129 level->android_clone_element[level->num_android_clone_elements++] =
5132 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5137 if (level->num_android_clone_elements == 0)
5139 level->num_android_clone_elements = 1;
5140 level->android_clone_element[0] = EL_EMPTY;
5144 int map_direction_RND_to_EM(int direction)
5146 return (direction == MV_UP ? 0 :
5147 direction == MV_RIGHT ? 1 :
5148 direction == MV_DOWN ? 2 :
5149 direction == MV_LEFT ? 3 :
5153 int map_direction_EM_to_RND(int direction)
5155 return (direction == 0 ? MV_UP :
5156 direction == 1 ? MV_RIGHT :
5157 direction == 2 ? MV_DOWN :
5158 direction == 3 ? MV_LEFT :
5162 int get_next_element(int element)
5166 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5167 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5168 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5169 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5170 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5171 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5172 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5174 default: return element;
5179 int el_act_dir2img(int element, int action, int direction)
5181 element = GFX_ELEMENT(element);
5183 if (direction == MV_NONE)
5184 return element_info[element].graphic[action];
5186 direction = MV_DIR_TO_BIT(direction);
5188 return element_info[element].direction_graphic[action][direction];
5191 int el_act_dir2img(int element, int action, int direction)
5193 element = GFX_ELEMENT(element);
5194 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5196 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5197 return element_info[element].direction_graphic[action][direction];
5202 static int el_act_dir2crm(int element, int action, int direction)
5204 element = GFX_ELEMENT(element);
5206 if (direction == MV_NONE)
5207 return element_info[element].crumbled[action];
5209 direction = MV_DIR_TO_BIT(direction);
5211 return element_info[element].direction_crumbled[action][direction];
5214 static int el_act_dir2crm(int element, int action, int direction)
5216 element = GFX_ELEMENT(element);
5217 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5219 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5220 return element_info[element].direction_crumbled[action][direction];
5224 int el_act2img(int element, int action)
5226 element = GFX_ELEMENT(element);
5228 return element_info[element].graphic[action];
5231 int el_act2crm(int element, int action)
5233 element = GFX_ELEMENT(element);
5235 return element_info[element].crumbled[action];
5238 int el_dir2img(int element, int direction)
5240 element = GFX_ELEMENT(element);
5242 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5245 int el2baseimg(int element)
5247 return element_info[element].graphic[ACTION_DEFAULT];
5250 int el2img(int element)
5252 element = GFX_ELEMENT(element);
5254 return element_info[element].graphic[ACTION_DEFAULT];
5257 int el2edimg(int element)
5259 element = GFX_ELEMENT(element);
5261 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5264 int el2preimg(int element)
5266 element = GFX_ELEMENT(element);
5268 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5271 int font2baseimg(int font_nr)
5273 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5276 int getNumActivePlayers_EM()
5278 int num_players = 0;
5284 for (i = 0; i < MAX_PLAYERS; i++)
5285 if (tape.player_participates[i])
5291 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5293 int game_frame_delay_value;
5295 game_frame_delay_value =
5296 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5297 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5300 if (tape.playing && tape.warp_forward && !tape.pausing)
5301 game_frame_delay_value = 0;
5303 return game_frame_delay_value;
5306 unsigned int InitRND(long seed)
5308 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5309 return InitEngineRND_EM(seed);
5311 return InitEngineRND(seed);
5314 void InitGraphicInfo_EM(void)
5316 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5317 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5321 int num_em_gfx_errors = 0;
5323 if (graphic_info_em_object[0][0].bitmap == NULL)
5325 /* EM graphics not yet initialized in em_open_all() */
5330 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5333 /* always start with reliable default values */
5334 for (i = 0; i < TILE_MAX; i++)
5336 object_mapping[i].element_rnd = EL_UNKNOWN;
5337 object_mapping[i].is_backside = FALSE;
5338 object_mapping[i].action = ACTION_DEFAULT;
5339 object_mapping[i].direction = MV_NONE;
5342 /* always start with reliable default values */
5343 for (p = 0; p < MAX_PLAYERS; p++)
5345 for (i = 0; i < SPR_MAX; i++)
5347 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5348 player_mapping[p][i].action = ACTION_DEFAULT;
5349 player_mapping[p][i].direction = MV_NONE;
5353 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5355 int e = em_object_mapping_list[i].element_em;
5357 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5358 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5360 if (em_object_mapping_list[i].action != -1)
5361 object_mapping[e].action = em_object_mapping_list[i].action;
5363 if (em_object_mapping_list[i].direction != -1)
5364 object_mapping[e].direction =
5365 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5368 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5370 int a = em_player_mapping_list[i].action_em;
5371 int p = em_player_mapping_list[i].player_nr;
5373 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5375 if (em_player_mapping_list[i].action != -1)
5376 player_mapping[p][a].action = em_player_mapping_list[i].action;
5378 if (em_player_mapping_list[i].direction != -1)
5379 player_mapping[p][a].direction =
5380 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5383 for (i = 0; i < TILE_MAX; i++)
5385 int element = object_mapping[i].element_rnd;
5386 int action = object_mapping[i].action;
5387 int direction = object_mapping[i].direction;
5388 boolean is_backside = object_mapping[i].is_backside;
5389 boolean action_removing = (action == ACTION_DIGGING ||
5390 action == ACTION_SNAPPING ||
5391 action == ACTION_COLLECTING);
5392 boolean action_exploding = ((action == ACTION_EXPLODING ||
5393 action == ACTION_SMASHED_BY_ROCK ||
5394 action == ACTION_SMASHED_BY_SPRING) &&
5395 element != EL_DIAMOND);
5396 boolean action_active = (action == ACTION_ACTIVE);
5397 boolean action_other = (action == ACTION_OTHER);
5399 for (j = 0; j < 8; j++)
5401 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5402 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5404 i == Xdrip_stretch ? element :
5405 i == Xdrip_stretchB ? element :
5406 i == Ydrip_s1 ? element :
5407 i == Ydrip_s1B ? element :
5408 i == Xball_1B ? element :
5409 i == Xball_2 ? element :
5410 i == Xball_2B ? element :
5411 i == Yball_eat ? element :
5412 i == Ykey_1_eat ? element :
5413 i == Ykey_2_eat ? element :
5414 i == Ykey_3_eat ? element :
5415 i == Ykey_4_eat ? element :
5416 i == Ykey_5_eat ? element :
5417 i == Ykey_6_eat ? element :
5418 i == Ykey_7_eat ? element :
5419 i == Ykey_8_eat ? element :
5420 i == Ylenses_eat ? element :
5421 i == Ymagnify_eat ? element :
5422 i == Ygrass_eat ? element :
5423 i == Ydirt_eat ? element :
5424 i == Yemerald_stone ? EL_EMERALD :
5425 i == Ydiamond_stone ? EL_ROCK :
5426 i == Xsand_stonein_1 ? element :
5427 i == Xsand_stonein_2 ? element :
5428 i == Xsand_stonein_3 ? element :
5429 i == Xsand_stonein_4 ? element :
5430 is_backside ? EL_EMPTY :
5431 action_removing ? EL_EMPTY :
5433 int effective_action = (j < 7 ? action :
5434 i == Xdrip_stretch ? action :
5435 i == Xdrip_stretchB ? action :
5436 i == Ydrip_s1 ? action :
5437 i == Ydrip_s1B ? action :
5438 i == Xball_1B ? action :
5439 i == Xball_2 ? action :
5440 i == Xball_2B ? action :
5441 i == Yball_eat ? action :
5442 i == Ykey_1_eat ? action :
5443 i == Ykey_2_eat ? action :
5444 i == Ykey_3_eat ? action :
5445 i == Ykey_4_eat ? action :
5446 i == Ykey_5_eat ? action :
5447 i == Ykey_6_eat ? action :
5448 i == Ykey_7_eat ? action :
5449 i == Ykey_8_eat ? action :
5450 i == Ylenses_eat ? action :
5451 i == Ymagnify_eat ? action :
5452 i == Ygrass_eat ? action :
5453 i == Ydirt_eat ? action :
5454 i == Xsand_stonein_1 ? action :
5455 i == Xsand_stonein_2 ? action :
5456 i == Xsand_stonein_3 ? action :
5457 i == Xsand_stonein_4 ? action :
5458 i == Xsand_stoneout_1 ? action :
5459 i == Xsand_stoneout_2 ? action :
5460 i == Xboom_android ? ACTION_EXPLODING :
5461 action_exploding ? ACTION_EXPLODING :
5462 action_active ? action :
5463 action_other ? action :
5465 int graphic = (el_act_dir2img(effective_element, effective_action,
5467 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5469 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5470 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5471 boolean has_action_graphics = (graphic != base_graphic);
5472 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5473 struct GraphicInfo *g = &graphic_info[graphic];
5474 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5477 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5478 boolean special_animation = (action != ACTION_DEFAULT &&
5479 g->anim_frames == 3 &&
5480 g->anim_delay == 2 &&
5481 g->anim_mode & ANIM_LINEAR);
5482 int sync_frame = (i == Xdrip_stretch ? 7 :
5483 i == Xdrip_stretchB ? 7 :
5484 i == Ydrip_s2 ? j + 8 :
5485 i == Ydrip_s2B ? j + 8 :
5494 i == Xfake_acid_1 ? 0 :
5495 i == Xfake_acid_2 ? 10 :
5496 i == Xfake_acid_3 ? 20 :
5497 i == Xfake_acid_4 ? 30 :
5498 i == Xfake_acid_5 ? 40 :
5499 i == Xfake_acid_6 ? 50 :
5500 i == Xfake_acid_7 ? 60 :
5501 i == Xfake_acid_8 ? 70 :
5503 i == Xball_2B ? j + 8 :
5504 i == Yball_eat ? j + 1 :
5505 i == Ykey_1_eat ? j + 1 :
5506 i == Ykey_2_eat ? j + 1 :
5507 i == Ykey_3_eat ? j + 1 :
5508 i == Ykey_4_eat ? j + 1 :
5509 i == Ykey_5_eat ? j + 1 :
5510 i == Ykey_6_eat ? j + 1 :
5511 i == Ykey_7_eat ? j + 1 :
5512 i == Ykey_8_eat ? j + 1 :
5513 i == Ylenses_eat ? j + 1 :
5514 i == Ymagnify_eat ? j + 1 :
5515 i == Ygrass_eat ? j + 1 :
5516 i == Ydirt_eat ? j + 1 :
5517 i == Xamoeba_1 ? 0 :
5518 i == Xamoeba_2 ? 1 :
5519 i == Xamoeba_3 ? 2 :
5520 i == Xamoeba_4 ? 3 :
5521 i == Xamoeba_5 ? 0 :
5522 i == Xamoeba_6 ? 1 :
5523 i == Xamoeba_7 ? 2 :
5524 i == Xamoeba_8 ? 3 :
5525 i == Xexit_2 ? j + 8 :
5526 i == Xexit_3 ? j + 16 :
5527 i == Xdynamite_1 ? 0 :
5528 i == Xdynamite_2 ? 8 :
5529 i == Xdynamite_3 ? 16 :
5530 i == Xdynamite_4 ? 24 :
5531 i == Xsand_stonein_1 ? j + 1 :
5532 i == Xsand_stonein_2 ? j + 9 :
5533 i == Xsand_stonein_3 ? j + 17 :
5534 i == Xsand_stonein_4 ? j + 25 :
5535 i == Xsand_stoneout_1 && j == 0 ? 0 :
5536 i == Xsand_stoneout_1 && j == 1 ? 0 :
5537 i == Xsand_stoneout_1 && j == 2 ? 1 :
5538 i == Xsand_stoneout_1 && j == 3 ? 2 :
5539 i == Xsand_stoneout_1 && j == 4 ? 2 :
5540 i == Xsand_stoneout_1 && j == 5 ? 3 :
5541 i == Xsand_stoneout_1 && j == 6 ? 4 :
5542 i == Xsand_stoneout_1 && j == 7 ? 4 :
5543 i == Xsand_stoneout_2 && j == 0 ? 5 :
5544 i == Xsand_stoneout_2 && j == 1 ? 6 :
5545 i == Xsand_stoneout_2 && j == 2 ? 7 :
5546 i == Xsand_stoneout_2 && j == 3 ? 8 :
5547 i == Xsand_stoneout_2 && j == 4 ? 9 :
5548 i == Xsand_stoneout_2 && j == 5 ? 11 :
5549 i == Xsand_stoneout_2 && j == 6 ? 13 :
5550 i == Xsand_stoneout_2 && j == 7 ? 15 :
5551 i == Xboom_bug && j == 1 ? 2 :
5552 i == Xboom_bug && j == 2 ? 2 :
5553 i == Xboom_bug && j == 3 ? 4 :
5554 i == Xboom_bug && j == 4 ? 4 :
5555 i == Xboom_bug && j == 5 ? 2 :
5556 i == Xboom_bug && j == 6 ? 2 :
5557 i == Xboom_bug && j == 7 ? 0 :
5558 i == Xboom_bomb && j == 1 ? 2 :
5559 i == Xboom_bomb && j == 2 ? 2 :
5560 i == Xboom_bomb && j == 3 ? 4 :
5561 i == Xboom_bomb && j == 4 ? 4 :
5562 i == Xboom_bomb && j == 5 ? 2 :
5563 i == Xboom_bomb && j == 6 ? 2 :
5564 i == Xboom_bomb && j == 7 ? 0 :
5565 i == Xboom_android && j == 7 ? 6 :
5566 i == Xboom_1 && j == 1 ? 2 :
5567 i == Xboom_1 && j == 2 ? 2 :
5568 i == Xboom_1 && j == 3 ? 4 :
5569 i == Xboom_1 && j == 4 ? 4 :
5570 i == Xboom_1 && j == 5 ? 6 :
5571 i == Xboom_1 && j == 6 ? 6 :
5572 i == Xboom_1 && j == 7 ? 8 :
5573 i == Xboom_2 && j == 0 ? 8 :
5574 i == Xboom_2 && j == 1 ? 8 :
5575 i == Xboom_2 && j == 2 ? 10 :
5576 i == Xboom_2 && j == 3 ? 10 :
5577 i == Xboom_2 && j == 4 ? 10 :
5578 i == Xboom_2 && j == 5 ? 12 :
5579 i == Xboom_2 && j == 6 ? 12 :
5580 i == Xboom_2 && j == 7 ? 12 :
5581 special_animation && j == 4 ? 3 :
5582 effective_action != action ? 0 :
5586 Bitmap *debug_bitmap = g_em->bitmap;
5587 int debug_src_x = g_em->src_x;
5588 int debug_src_y = g_em->src_y;
5591 int frame = getAnimationFrame(g->anim_frames,
5594 g->anim_start_frame,
5597 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5598 g->double_movement && is_backside);
5600 g_em->bitmap = src_bitmap;
5601 g_em->src_x = src_x;
5602 g_em->src_y = src_y;
5603 g_em->src_offset_x = 0;
5604 g_em->src_offset_y = 0;
5605 g_em->dst_offset_x = 0;
5606 g_em->dst_offset_y = 0;
5607 g_em->width = TILEX;
5608 g_em->height = TILEY;
5610 g_em->crumbled_bitmap = NULL;
5611 g_em->crumbled_src_x = 0;
5612 g_em->crumbled_src_y = 0;
5613 g_em->crumbled_border_size = 0;
5615 g_em->has_crumbled_graphics = FALSE;
5616 g_em->preserve_background = FALSE;
5619 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5620 printf("::: empty crumbled: %d [%s], %d, %d\n",
5621 effective_element, element_info[effective_element].token_name,
5622 effective_action, direction);
5625 /* if element can be crumbled, but certain action graphics are just empty
5626 space (like snapping sand with the original R'n'D graphics), do not
5627 treat these empty space graphics as crumbled graphics in EMC engine */
5628 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5630 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5632 g_em->has_crumbled_graphics = TRUE;
5633 g_em->crumbled_bitmap = src_bitmap;
5634 g_em->crumbled_src_x = src_x;
5635 g_em->crumbled_src_y = src_y;
5636 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5640 if (element == EL_ROCK &&
5641 effective_action == ACTION_FILLING)
5642 printf("::: has_action_graphics == %d\n", has_action_graphics);
5645 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5646 effective_action == ACTION_MOVING ||
5647 effective_action == ACTION_PUSHING ||
5648 effective_action == ACTION_EATING)) ||
5649 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5650 effective_action == ACTION_EMPTYING)))
5653 (effective_action == ACTION_FALLING ||
5654 effective_action == ACTION_FILLING ||
5655 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5656 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5657 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5658 int num_steps = (i == Ydrip_s1 ? 16 :
5659 i == Ydrip_s1B ? 16 :
5660 i == Ydrip_s2 ? 16 :
5661 i == Ydrip_s2B ? 16 :
5662 i == Xsand_stonein_1 ? 32 :
5663 i == Xsand_stonein_2 ? 32 :
5664 i == Xsand_stonein_3 ? 32 :
5665 i == Xsand_stonein_4 ? 32 :
5666 i == Xsand_stoneout_1 ? 16 :
5667 i == Xsand_stoneout_2 ? 16 : 8);
5668 int cx = ABS(dx) * (TILEX / num_steps);
5669 int cy = ABS(dy) * (TILEY / num_steps);
5670 int step_frame = (i == Ydrip_s2 ? j + 8 :
5671 i == Ydrip_s2B ? j + 8 :
5672 i == Xsand_stonein_2 ? j + 8 :
5673 i == Xsand_stonein_3 ? j + 16 :
5674 i == Xsand_stonein_4 ? j + 24 :
5675 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5676 int step = (is_backside ? step_frame : num_steps - step_frame);
5678 if (is_backside) /* tile where movement starts */
5680 if (dx < 0 || dy < 0)
5682 g_em->src_offset_x = cx * step;
5683 g_em->src_offset_y = cy * step;
5687 g_em->dst_offset_x = cx * step;
5688 g_em->dst_offset_y = cy * step;
5691 else /* tile where movement ends */
5693 if (dx < 0 || dy < 0)
5695 g_em->dst_offset_x = cx * step;
5696 g_em->dst_offset_y = cy * step;
5700 g_em->src_offset_x = cx * step;
5701 g_em->src_offset_y = cy * step;
5705 g_em->width = TILEX - cx * step;
5706 g_em->height = TILEY - cy * step;
5709 /* create unique graphic identifier to decide if tile must be redrawn */
5710 /* bit 31 - 16 (16 bit): EM style graphic
5711 bit 15 - 12 ( 4 bit): EM style frame
5712 bit 11 - 6 ( 6 bit): graphic width
5713 bit 5 - 0 ( 6 bit): graphic height */
5714 g_em->unique_identifier =
5715 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5719 /* skip check for EMC elements not contained in original EMC artwork */
5720 if (element == EL_EMC_FAKE_ACID)
5723 if (g_em->bitmap != debug_bitmap ||
5724 g_em->src_x != debug_src_x ||
5725 g_em->src_y != debug_src_y ||
5726 g_em->src_offset_x != 0 ||
5727 g_em->src_offset_y != 0 ||
5728 g_em->dst_offset_x != 0 ||
5729 g_em->dst_offset_y != 0 ||
5730 g_em->width != TILEX ||
5731 g_em->height != TILEY)
5733 static int last_i = -1;
5741 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5742 i, element, element_info[element].token_name,
5743 element_action_info[effective_action].suffix, direction);
5745 if (element != effective_element)
5746 printf(" [%d ('%s')]",
5748 element_info[effective_element].token_name);
5752 if (g_em->bitmap != debug_bitmap)
5753 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5754 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5756 if (g_em->src_x != debug_src_x ||
5757 g_em->src_y != debug_src_y)
5758 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5759 j, (is_backside ? 'B' : 'F'),
5760 g_em->src_x, g_em->src_y,
5761 g_em->src_x / 32, g_em->src_y / 32,
5762 debug_src_x, debug_src_y,
5763 debug_src_x / 32, debug_src_y / 32);
5765 if (g_em->src_offset_x != 0 ||
5766 g_em->src_offset_y != 0 ||
5767 g_em->dst_offset_x != 0 ||
5768 g_em->dst_offset_y != 0)
5769 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5771 g_em->src_offset_x, g_em->src_offset_y,
5772 g_em->dst_offset_x, g_em->dst_offset_y);
5774 if (g_em->width != TILEX ||
5775 g_em->height != TILEY)
5776 printf(" %d (%d): size %d,%d should be %d,%d\n",
5778 g_em->width, g_em->height, TILEX, TILEY);
5780 num_em_gfx_errors++;
5787 for (i = 0; i < TILE_MAX; i++)
5789 for (j = 0; j < 8; j++)
5791 int element = object_mapping[i].element_rnd;
5792 int action = object_mapping[i].action;
5793 int direction = object_mapping[i].direction;
5794 boolean is_backside = object_mapping[i].is_backside;
5795 int graphic_action = el_act_dir2img(element, action, direction);
5796 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5798 if ((action == ACTION_SMASHED_BY_ROCK ||
5799 action == ACTION_SMASHED_BY_SPRING ||
5800 action == ACTION_EATING) &&
5801 graphic_action == graphic_default)
5803 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5804 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5805 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5806 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5809 /* no separate animation for "smashed by rock" -- use rock instead */
5810 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5811 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5813 g_em->bitmap = g_xx->bitmap;
5814 g_em->src_x = g_xx->src_x;
5815 g_em->src_y = g_xx->src_y;
5816 g_em->src_offset_x = g_xx->src_offset_x;
5817 g_em->src_offset_y = g_xx->src_offset_y;
5818 g_em->dst_offset_x = g_xx->dst_offset_x;
5819 g_em->dst_offset_y = g_xx->dst_offset_y;
5820 g_em->width = g_xx->width;
5821 g_em->height = g_xx->height;
5822 g_em->unique_identifier = g_xx->unique_identifier;
5825 g_em->preserve_background = TRUE;
5830 for (p = 0; p < MAX_PLAYERS; p++)
5832 for (i = 0; i < SPR_MAX; i++)
5834 int element = player_mapping[p][i].element_rnd;
5835 int action = player_mapping[p][i].action;
5836 int direction = player_mapping[p][i].direction;
5838 for (j = 0; j < 8; j++)
5840 int effective_element = element;
5841 int effective_action = action;
5842 int graphic = (direction == MV_NONE ?
5843 el_act2img(effective_element, effective_action) :
5844 el_act_dir2img(effective_element, effective_action,
5846 struct GraphicInfo *g = &graphic_info[graphic];
5847 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5853 Bitmap *debug_bitmap = g_em->bitmap;
5854 int debug_src_x = g_em->src_x;
5855 int debug_src_y = g_em->src_y;
5858 int frame = getAnimationFrame(g->anim_frames,
5861 g->anim_start_frame,
5864 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5866 g_em->bitmap = src_bitmap;
5867 g_em->src_x = src_x;
5868 g_em->src_y = src_y;
5869 g_em->src_offset_x = 0;
5870 g_em->src_offset_y = 0;
5871 g_em->dst_offset_x = 0;
5872 g_em->dst_offset_y = 0;
5873 g_em->width = TILEX;
5874 g_em->height = TILEY;
5878 /* skip check for EMC elements not contained in original EMC artwork */
5879 if (element == EL_PLAYER_3 ||
5880 element == EL_PLAYER_4)
5883 if (g_em->bitmap != debug_bitmap ||
5884 g_em->src_x != debug_src_x ||
5885 g_em->src_y != debug_src_y)
5887 static int last_i = -1;
5895 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5896 p, i, element, element_info[element].token_name,
5897 element_action_info[effective_action].suffix, direction);
5899 if (element != effective_element)
5900 printf(" [%d ('%s')]",
5902 element_info[effective_element].token_name);
5906 if (g_em->bitmap != debug_bitmap)
5907 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5908 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5910 if (g_em->src_x != debug_src_x ||
5911 g_em->src_y != debug_src_y)
5912 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5914 g_em->src_x, g_em->src_y,
5915 g_em->src_x / 32, g_em->src_y / 32,
5916 debug_src_x, debug_src_y,
5917 debug_src_x / 32, debug_src_y / 32);
5919 num_em_gfx_errors++;
5929 printf("::: [%d errors found]\n", num_em_gfx_errors);
5935 void PlayMenuSound()
5937 int sound = menu.sound[game_status];
5939 if (sound == SND_UNDEFINED)
5942 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5943 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5946 if (IS_LOOP_SOUND(sound))
5947 PlaySoundLoop(sound);
5952 void PlayMenuSoundStereo(int sound, int stereo_position)
5954 if (sound == SND_UNDEFINED)
5957 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5958 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5961 if (IS_LOOP_SOUND(sound))
5962 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
5964 PlaySoundStereo(sound, stereo_position);
5967 void PlayMenuSoundIfLoop()
5969 int sound = menu.sound[game_status];
5971 if (sound == SND_UNDEFINED)
5974 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5975 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5978 if (IS_LOOP_SOUND(sound))
5979 PlaySoundLoop(sound);
5982 void PlayMenuMusic()
5984 int music = menu.music[game_status];
5986 if (music == MUS_UNDEFINED)
5992 void ToggleFullscreenIfNeeded()
5994 if (setup.fullscreen != video.fullscreen_enabled ||
5995 setup.fullscreen_mode != video.fullscreen_mode_current)
5997 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5999 /* save backbuffer content which gets lost when toggling fullscreen mode */
6000 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6002 if (setup.fullscreen && video.fullscreen_enabled)
6004 /* keep fullscreen mode, but change screen mode */
6005 video.fullscreen_mode_current = setup.fullscreen_mode;
6006 video.fullscreen_enabled = FALSE;
6009 /* toggle fullscreen */
6010 ChangeVideoModeIfNeeded(setup.fullscreen);
6011 setup.fullscreen = video.fullscreen_enabled;
6013 /* restore backbuffer content from temporary backbuffer backup bitmap */
6014 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6016 FreeBitmap(tmp_backbuffer);
6018 redraw_mask = REDRAW_ALL;