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_FIELD)
432 height = FULL_SYSIZE;
434 else /* REDRAW_ALL */
442 redraw_mask |= fade_mask;
444 if (!setup.fade_screens || 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;
2243 case EVENT_BUTTONPRESS:
2244 case EVENT_KEYPRESS:
2248 case EVENT_KEYRELEASE:
2249 ClearPlayerAction();
2253 HandleOtherEvents(&event);
2257 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2264 /* don't eat all CPU time */
2269 #define MAX_REQUEST_LINES 13
2270 #define MAX_REQUEST_LINE_FONT1_LEN 7
2271 #define MAX_REQUEST_LINE_FONT2_LEN 10
2273 boolean Request(char *text, unsigned int req_state)
2275 int mx, my, ty, result = -1;
2276 unsigned int old_door_state;
2277 int last_game_status = game_status; /* save current game status */
2278 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2279 int font_nr = FONT_TEXT_2;
2280 int max_word_len = 0;
2283 for (text_ptr = text; *text_ptr; text_ptr++)
2285 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2287 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2289 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2290 font_nr = FONT_LEVEL_NUMBER;
2296 if (game_status == GAME_MODE_PLAYING &&
2297 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2298 BlitScreenToBitmap_EM(backbuffer);
2300 /* disable deactivated drawing when quick-loading level tape recording */
2301 if (tape.playing && tape.deactivate_display)
2302 TapeDeactivateDisplayOff(TRUE);
2304 SetMouseCursor(CURSOR_DEFAULT);
2306 #if defined(NETWORK_AVALIABLE)
2307 /* pause network game while waiting for request to answer */
2308 if (options.network &&
2309 game_status == GAME_MODE_PLAYING &&
2310 req_state & REQUEST_WAIT_FOR_INPUT)
2311 SendToServer_PausePlaying();
2314 old_door_state = GetDoorState();
2316 /* simulate releasing mouse button over last gadget, if still pressed */
2318 HandleGadgets(-1, -1, 0);
2322 if (old_door_state & DOOR_OPEN_1)
2324 CloseDoor(DOOR_CLOSE_1);
2326 /* save old door content */
2327 BlitBitmap(bitmap_db_door, bitmap_db_door,
2328 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2329 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2333 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2336 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2338 /* clear door drawing field */
2339 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2341 /* force DOOR font on preview level */
2342 game_status = GAME_MODE_PSEUDO_DOOR;
2344 /* write text for request */
2345 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2347 char text_line[max_request_line_len + 1];
2353 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2356 if (!tc || tc == ' ')
2367 strncpy(text_line, text, tl);
2370 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2371 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2372 text_line, font_nr);
2374 text += tl + (tc == ' ' ? 1 : 0);
2377 game_status = last_game_status; /* restore current game status */
2379 if (req_state & REQ_ASK)
2381 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2382 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2384 else if (req_state & REQ_CONFIRM)
2386 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2388 else if (req_state & REQ_PLAYER)
2390 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2391 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2392 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2393 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2396 /* copy request gadgets to door backbuffer */
2397 BlitBitmap(drawto, bitmap_db_door,
2398 DX, DY, DXSIZE, DYSIZE,
2399 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2401 OpenDoor(DOOR_OPEN_1);
2403 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2405 if (game_status == GAME_MODE_PLAYING)
2407 SetPanelBackground();
2408 SetDrawBackgroundMask(REDRAW_DOOR_1);
2412 SetDrawBackgroundMask(REDRAW_FIELD);
2418 if (game_status != GAME_MODE_MAIN)
2421 button_status = MB_RELEASED;
2423 request_gadget_id = -1;
2425 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2437 case EVENT_BUTTONPRESS:
2438 case EVENT_BUTTONRELEASE:
2439 case EVENT_MOTIONNOTIFY:
2441 if (event.type == EVENT_MOTIONNOTIFY)
2443 if (!PointerInWindow(window))
2444 continue; /* window and pointer are on different screens */
2449 motion_status = TRUE;
2450 mx = ((MotionEvent *) &event)->x;
2451 my = ((MotionEvent *) &event)->y;
2455 motion_status = FALSE;
2456 mx = ((ButtonEvent *) &event)->x;
2457 my = ((ButtonEvent *) &event)->y;
2458 if (event.type == EVENT_BUTTONPRESS)
2459 button_status = ((ButtonEvent *) &event)->button;
2461 button_status = MB_RELEASED;
2464 /* this sets 'request_gadget_id' */
2465 HandleGadgets(mx, my, button_status);
2467 switch(request_gadget_id)
2469 case TOOL_CTRL_ID_YES:
2472 case TOOL_CTRL_ID_NO:
2475 case TOOL_CTRL_ID_CONFIRM:
2476 result = TRUE | FALSE;
2479 case TOOL_CTRL_ID_PLAYER_1:
2482 case TOOL_CTRL_ID_PLAYER_2:
2485 case TOOL_CTRL_ID_PLAYER_3:
2488 case TOOL_CTRL_ID_PLAYER_4:
2499 case EVENT_KEYPRESS:
2500 switch(GetEventKey((KeyEvent *)&event, TRUE))
2513 if (req_state & REQ_PLAYER)
2517 case EVENT_KEYRELEASE:
2518 ClearPlayerAction();
2522 HandleOtherEvents(&event);
2526 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2528 int joy = AnyJoystick();
2530 if (joy & JOY_BUTTON_1)
2532 else if (joy & JOY_BUTTON_2)
2538 /* don't eat all CPU time */
2542 if (game_status != GAME_MODE_MAIN)
2547 if (!(req_state & REQ_STAY_OPEN))
2549 CloseDoor(DOOR_CLOSE_1);
2551 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2552 (req_state & REQ_REOPEN))
2553 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2558 if (game_status == GAME_MODE_PLAYING)
2560 SetPanelBackground();
2561 SetDrawBackgroundMask(REDRAW_DOOR_1);
2565 SetDrawBackgroundMask(REDRAW_FIELD);
2568 #if defined(NETWORK_AVALIABLE)
2569 /* continue network game after request */
2570 if (options.network &&
2571 game_status == GAME_MODE_PLAYING &&
2572 req_state & REQUEST_WAIT_FOR_INPUT)
2573 SendToServer_ContinuePlaying();
2576 /* restore deactivated drawing when quick-loading level tape recording */
2577 if (tape.playing && tape.deactivate_display)
2578 TapeDeactivateDisplayOn();
2583 unsigned int OpenDoor(unsigned int door_state)
2585 if (door_state & DOOR_COPY_BACK)
2587 if (door_state & DOOR_OPEN_1)
2588 BlitBitmap(bitmap_db_door, bitmap_db_door,
2589 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2590 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2592 if (door_state & DOOR_OPEN_2)
2593 BlitBitmap(bitmap_db_door, bitmap_db_door,
2594 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2595 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2597 door_state &= ~DOOR_COPY_BACK;
2600 return MoveDoor(door_state);
2603 unsigned int CloseDoor(unsigned int door_state)
2605 unsigned int old_door_state = GetDoorState();
2607 if (!(door_state & DOOR_NO_COPY_BACK))
2609 if (old_door_state & DOOR_OPEN_1)
2610 BlitBitmap(backbuffer, bitmap_db_door,
2611 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2613 if (old_door_state & DOOR_OPEN_2)
2614 BlitBitmap(backbuffer, bitmap_db_door,
2615 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2617 door_state &= ~DOOR_NO_COPY_BACK;
2620 return MoveDoor(door_state);
2623 unsigned int GetDoorState()
2625 return MoveDoor(DOOR_GET_STATE);
2628 unsigned int SetDoorState(unsigned int door_state)
2630 return MoveDoor(door_state | DOOR_SET_STATE);
2633 unsigned int MoveDoor(unsigned int door_state)
2635 static int door1 = DOOR_OPEN_1;
2636 static int door2 = DOOR_CLOSE_2;
2637 unsigned long door_delay = 0;
2638 unsigned long door_delay_value;
2641 if (door_1.width < 0 || door_1.width > DXSIZE)
2642 door_1.width = DXSIZE;
2643 if (door_1.height < 0 || door_1.height > DYSIZE)
2644 door_1.height = DYSIZE;
2645 if (door_2.width < 0 || door_2.width > VXSIZE)
2646 door_2.width = VXSIZE;
2647 if (door_2.height < 0 || door_2.height > VYSIZE)
2648 door_2.height = VYSIZE;
2650 if (door_state == DOOR_GET_STATE)
2651 return (door1 | door2);
2653 if (door_state & DOOR_SET_STATE)
2655 if (door_state & DOOR_ACTION_1)
2656 door1 = door_state & DOOR_ACTION_1;
2657 if (door_state & DOOR_ACTION_2)
2658 door2 = door_state & DOOR_ACTION_2;
2660 return (door1 | door2);
2663 if (!(door_state & DOOR_FORCE_REDRAW))
2665 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2666 door_state &= ~DOOR_OPEN_1;
2667 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2668 door_state &= ~DOOR_CLOSE_1;
2669 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2670 door_state &= ~DOOR_OPEN_2;
2671 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2672 door_state &= ~DOOR_CLOSE_2;
2675 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2678 if (setup.quick_doors)
2680 stepsize = 20; /* must be choosen to always draw last frame */
2681 door_delay_value = 0;
2684 if (global.autoplay_leveldir)
2686 door_state |= DOOR_NO_DELAY;
2687 door_state &= ~DOOR_CLOSE_ALL;
2690 if (door_state & DOOR_ACTION)
2692 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2693 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2694 boolean door_1_done = (!handle_door_1);
2695 boolean door_2_done = (!handle_door_2);
2696 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2697 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2698 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2699 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2700 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2701 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2702 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2703 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2704 int door_skip = max_door_size - door_size;
2705 int end = door_size;
2706 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2709 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2711 /* opening door sound has priority over simultaneously closing door */
2712 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2713 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2714 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2715 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2718 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2721 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2722 GC gc = bitmap->stored_clip_gc;
2724 if (door_state & DOOR_ACTION_1)
2726 int a = MIN(x * door_1.step_offset, end);
2727 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2728 int i = p + door_skip;
2730 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2732 BlitBitmap(bitmap_db_door, drawto,
2733 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2734 DXSIZE, DYSIZE, DX, DY);
2738 BlitBitmap(bitmap_db_door, drawto,
2739 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2740 DXSIZE, DYSIZE - p / 2, DX, DY);
2742 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2745 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2747 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2748 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2749 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2750 int dst2_x = DX, dst2_y = DY;
2751 int width = i, height = DYSIZE;
2753 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2754 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2757 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2758 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2761 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2763 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2764 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2765 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2766 int dst2_x = DX, dst2_y = DY;
2767 int width = DXSIZE, height = i;
2769 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2770 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2773 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2774 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2777 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2779 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2781 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2782 BlitBitmapMasked(bitmap, drawto,
2783 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2784 DX + DXSIZE - i, DY + j);
2785 BlitBitmapMasked(bitmap, drawto,
2786 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2787 DX + DXSIZE - i, DY + 140 + j);
2788 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2789 DY - (DOOR_GFX_PAGEY1 + j));
2790 BlitBitmapMasked(bitmap, drawto,
2791 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2793 BlitBitmapMasked(bitmap, drawto,
2794 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2797 BlitBitmapMasked(bitmap, drawto,
2798 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2800 BlitBitmapMasked(bitmap, drawto,
2801 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2803 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2804 BlitBitmapMasked(bitmap, drawto,
2805 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2806 DX + DXSIZE - i, DY + 77 + j);
2807 BlitBitmapMasked(bitmap, drawto,
2808 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2809 DX + DXSIZE - i, DY + 203 + j);
2812 redraw_mask |= REDRAW_DOOR_1;
2813 door_1_done = (a == end);
2816 if (door_state & DOOR_ACTION_2)
2818 int a = MIN(x * door_2.step_offset, door_size);
2819 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2820 int i = p + door_skip;
2822 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2824 BlitBitmap(bitmap_db_door, drawto,
2825 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2826 VXSIZE, VYSIZE, VX, VY);
2828 else if (x <= VYSIZE)
2830 BlitBitmap(bitmap_db_door, drawto,
2831 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2832 VXSIZE, VYSIZE - p / 2, VX, VY);
2834 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2837 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2839 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2840 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2841 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2842 int dst2_x = VX, dst2_y = VY;
2843 int width = i, height = VYSIZE;
2845 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2846 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2849 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2850 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2853 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2855 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2856 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2857 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2858 int dst2_x = VX, dst2_y = VY;
2859 int width = VXSIZE, height = i;
2861 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2862 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2865 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2866 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2869 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2871 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2873 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2874 BlitBitmapMasked(bitmap, drawto,
2875 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2876 VX + VXSIZE - i, VY + j);
2877 SetClipOrigin(bitmap, gc,
2878 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2879 BlitBitmapMasked(bitmap, drawto,
2880 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2883 BlitBitmapMasked(bitmap, drawto,
2884 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2885 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2886 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2887 BlitBitmapMasked(bitmap, drawto,
2888 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2890 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2893 redraw_mask |= REDRAW_DOOR_2;
2894 door_2_done = (a == VXSIZE);
2897 if (!(door_state & DOOR_NO_DELAY))
2901 if (game_status == GAME_MODE_MAIN)
2904 WaitUntilDelayReached(&door_delay, door_delay_value);
2909 if (door_state & DOOR_ACTION_1)
2910 door1 = door_state & DOOR_ACTION_1;
2911 if (door_state & DOOR_ACTION_2)
2912 door2 = door_state & DOOR_ACTION_2;
2914 return (door1 | door2);
2917 void DrawSpecialEditorDoor()
2919 /* draw bigger toolbox window */
2920 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2921 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2923 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2924 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2927 redraw_mask |= REDRAW_ALL;
2930 void UndrawSpecialEditorDoor()
2932 /* draw normal tape recorder window */
2933 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2934 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2937 redraw_mask |= REDRAW_ALL;
2941 /* ---------- new tool button stuff ---------------------------------------- */
2943 /* graphic position values for tool buttons */
2944 #define TOOL_BUTTON_YES_XPOS 2
2945 #define TOOL_BUTTON_YES_YPOS 250
2946 #define TOOL_BUTTON_YES_GFX_YPOS 0
2947 #define TOOL_BUTTON_YES_XSIZE 46
2948 #define TOOL_BUTTON_YES_YSIZE 28
2949 #define TOOL_BUTTON_NO_XPOS 52
2950 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2951 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2952 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2953 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2954 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2955 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2956 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2957 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2958 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2959 #define TOOL_BUTTON_PLAYER_XSIZE 30
2960 #define TOOL_BUTTON_PLAYER_YSIZE 30
2961 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2962 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2963 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2964 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2965 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2966 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2967 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2968 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2969 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2970 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2971 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2972 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2973 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2974 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2975 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2976 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2977 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2978 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2979 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2980 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2989 } toolbutton_info[NUM_TOOL_BUTTONS] =
2992 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2993 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2994 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2999 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3000 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3001 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3006 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3007 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3008 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3009 TOOL_CTRL_ID_CONFIRM,
3013 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3014 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3015 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3016 TOOL_CTRL_ID_PLAYER_1,
3020 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3021 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3022 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3023 TOOL_CTRL_ID_PLAYER_2,
3027 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3028 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3029 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3030 TOOL_CTRL_ID_PLAYER_3,
3034 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3035 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3036 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3037 TOOL_CTRL_ID_PLAYER_4,
3042 void CreateToolButtons()
3046 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3048 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3049 Bitmap *deco_bitmap = None;
3050 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3051 struct GadgetInfo *gi;
3052 unsigned long event_mask;
3053 int gd_xoffset, gd_yoffset;
3054 int gd_x1, gd_x2, gd_y;
3057 event_mask = GD_EVENT_RELEASED;
3059 gd_xoffset = toolbutton_info[i].xpos;
3060 gd_yoffset = toolbutton_info[i].ypos;
3061 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3062 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3063 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3065 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3067 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3069 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3070 &deco_bitmap, &deco_x, &deco_y);
3071 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3072 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3075 gi = CreateGadget(GDI_CUSTOM_ID, id,
3076 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3077 GDI_X, DX + toolbutton_info[i].x,
3078 GDI_Y, DY + toolbutton_info[i].y,
3079 GDI_WIDTH, toolbutton_info[i].width,
3080 GDI_HEIGHT, toolbutton_info[i].height,
3081 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3082 GDI_STATE, GD_BUTTON_UNPRESSED,
3083 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3084 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3085 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3086 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3087 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3088 GDI_DECORATION_SHIFTING, 1, 1,
3089 GDI_EVENT_MASK, event_mask,
3090 GDI_CALLBACK_ACTION, HandleToolButtons,
3094 Error(ERR_EXIT, "cannot create gadget");
3096 tool_gadget[id] = gi;
3100 void FreeToolButtons()
3104 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3105 FreeGadget(tool_gadget[i]);
3108 static void UnmapToolButtons()
3112 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3113 UnmapGadget(tool_gadget[i]);
3116 static void HandleToolButtons(struct GadgetInfo *gi)
3118 request_gadget_id = gi->custom_id;
3121 static struct Mapping_EM_to_RND_object
3124 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3125 boolean is_backside; /* backside of moving element */
3131 em_object_mapping_list[] =
3134 Xblank, TRUE, FALSE,
3138 Yacid_splash_eB, FALSE, FALSE,
3139 EL_ACID_SPLASH_RIGHT, -1, -1
3142 Yacid_splash_wB, FALSE, FALSE,
3143 EL_ACID_SPLASH_LEFT, -1, -1
3146 #ifdef EM_ENGINE_BAD_ROLL
3148 Xstone_force_e, FALSE, FALSE,
3149 EL_ROCK, -1, MV_BIT_RIGHT
3152 Xstone_force_w, FALSE, FALSE,
3153 EL_ROCK, -1, MV_BIT_LEFT
3156 Xnut_force_e, FALSE, FALSE,
3157 EL_NUT, -1, MV_BIT_RIGHT
3160 Xnut_force_w, FALSE, FALSE,
3161 EL_NUT, -1, MV_BIT_LEFT
3164 Xspring_force_e, FALSE, FALSE,
3165 EL_SPRING, -1, MV_BIT_RIGHT
3168 Xspring_force_w, FALSE, FALSE,
3169 EL_SPRING, -1, MV_BIT_LEFT
3172 Xemerald_force_e, FALSE, FALSE,
3173 EL_EMERALD, -1, MV_BIT_RIGHT
3176 Xemerald_force_w, FALSE, FALSE,
3177 EL_EMERALD, -1, MV_BIT_LEFT
3180 Xdiamond_force_e, FALSE, FALSE,
3181 EL_DIAMOND, -1, MV_BIT_RIGHT
3184 Xdiamond_force_w, FALSE, FALSE,
3185 EL_DIAMOND, -1, MV_BIT_LEFT
3188 Xbomb_force_e, FALSE, FALSE,
3189 EL_BOMB, -1, MV_BIT_RIGHT
3192 Xbomb_force_w, FALSE, FALSE,
3193 EL_BOMB, -1, MV_BIT_LEFT
3195 #endif /* EM_ENGINE_BAD_ROLL */
3198 Xstone, TRUE, FALSE,
3202 Xstone_pause, FALSE, FALSE,
3206 Xstone_fall, FALSE, FALSE,
3210 Ystone_s, FALSE, FALSE,
3211 EL_ROCK, ACTION_FALLING, -1
3214 Ystone_sB, FALSE, TRUE,
3215 EL_ROCK, ACTION_FALLING, -1
3218 Ystone_e, FALSE, FALSE,
3219 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3222 Ystone_eB, FALSE, TRUE,
3223 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3226 Ystone_w, FALSE, FALSE,
3227 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3230 Ystone_wB, FALSE, TRUE,
3231 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3238 Xnut_pause, FALSE, FALSE,
3242 Xnut_fall, FALSE, FALSE,
3246 Ynut_s, FALSE, FALSE,
3247 EL_NUT, ACTION_FALLING, -1
3250 Ynut_sB, FALSE, TRUE,
3251 EL_NUT, ACTION_FALLING, -1
3254 Ynut_e, FALSE, FALSE,
3255 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3258 Ynut_eB, FALSE, TRUE,
3259 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3262 Ynut_w, FALSE, FALSE,
3263 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3266 Ynut_wB, FALSE, TRUE,
3267 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3270 Xbug_n, TRUE, FALSE,
3274 Xbug_e, TRUE, FALSE,
3275 EL_BUG_RIGHT, -1, -1
3278 Xbug_s, TRUE, FALSE,
3282 Xbug_w, TRUE, FALSE,
3286 Xbug_gon, FALSE, FALSE,
3290 Xbug_goe, FALSE, FALSE,
3291 EL_BUG_RIGHT, -1, -1
3294 Xbug_gos, FALSE, FALSE,
3298 Xbug_gow, FALSE, FALSE,
3302 Ybug_n, FALSE, FALSE,
3303 EL_BUG, ACTION_MOVING, MV_BIT_UP
3306 Ybug_nB, FALSE, TRUE,
3307 EL_BUG, ACTION_MOVING, MV_BIT_UP
3310 Ybug_e, FALSE, FALSE,
3311 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3314 Ybug_eB, FALSE, TRUE,
3315 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3318 Ybug_s, FALSE, FALSE,
3319 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3322 Ybug_sB, FALSE, TRUE,
3323 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3326 Ybug_w, FALSE, FALSE,
3327 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3330 Ybug_wB, FALSE, TRUE,
3331 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3334 Ybug_w_n, FALSE, FALSE,
3335 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3338 Ybug_n_e, FALSE, FALSE,
3339 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3342 Ybug_e_s, FALSE, FALSE,
3343 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3346 Ybug_s_w, FALSE, FALSE,
3347 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3350 Ybug_e_n, FALSE, FALSE,
3351 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3354 Ybug_s_e, FALSE, FALSE,
3355 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3358 Ybug_w_s, FALSE, FALSE,
3359 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3362 Ybug_n_w, FALSE, FALSE,
3363 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3366 Ybug_stone, FALSE, FALSE,
3367 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3370 Ybug_spring, FALSE, FALSE,
3371 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3374 Xtank_n, TRUE, FALSE,
3375 EL_SPACESHIP_UP, -1, -1
3378 Xtank_e, TRUE, FALSE,
3379 EL_SPACESHIP_RIGHT, -1, -1
3382 Xtank_s, TRUE, FALSE,
3383 EL_SPACESHIP_DOWN, -1, -1
3386 Xtank_w, TRUE, FALSE,
3387 EL_SPACESHIP_LEFT, -1, -1
3390 Xtank_gon, FALSE, FALSE,
3391 EL_SPACESHIP_UP, -1, -1
3394 Xtank_goe, FALSE, FALSE,
3395 EL_SPACESHIP_RIGHT, -1, -1
3398 Xtank_gos, FALSE, FALSE,
3399 EL_SPACESHIP_DOWN, -1, -1
3402 Xtank_gow, FALSE, FALSE,
3403 EL_SPACESHIP_LEFT, -1, -1
3406 Ytank_n, FALSE, FALSE,
3407 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3410 Ytank_nB, FALSE, TRUE,
3411 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3414 Ytank_e, FALSE, FALSE,
3415 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3418 Ytank_eB, FALSE, TRUE,
3419 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3422 Ytank_s, FALSE, FALSE,
3423 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3426 Ytank_sB, FALSE, TRUE,
3427 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3430 Ytank_w, FALSE, FALSE,
3431 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3434 Ytank_wB, FALSE, TRUE,
3435 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3438 Ytank_w_n, FALSE, FALSE,
3439 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3442 Ytank_n_e, FALSE, FALSE,
3443 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3446 Ytank_e_s, FALSE, FALSE,
3447 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3450 Ytank_s_w, FALSE, FALSE,
3451 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3454 Ytank_e_n, FALSE, FALSE,
3455 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3458 Ytank_s_e, FALSE, FALSE,
3459 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3462 Ytank_w_s, FALSE, FALSE,
3463 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3466 Ytank_n_w, FALSE, FALSE,
3467 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3470 Ytank_stone, FALSE, FALSE,
3471 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3474 Ytank_spring, FALSE, FALSE,
3475 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3478 Xandroid, TRUE, FALSE,
3479 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3482 Xandroid_1_n, FALSE, FALSE,
3483 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3486 Xandroid_2_n, FALSE, FALSE,
3487 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3490 Xandroid_1_e, FALSE, FALSE,
3491 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3494 Xandroid_2_e, FALSE, FALSE,
3495 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3498 Xandroid_1_w, FALSE, FALSE,
3499 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3502 Xandroid_2_w, FALSE, FALSE,
3503 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3506 Xandroid_1_s, FALSE, FALSE,
3507 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3510 Xandroid_2_s, FALSE, FALSE,
3511 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3514 Yandroid_n, FALSE, FALSE,
3515 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3518 Yandroid_nB, FALSE, TRUE,
3519 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3522 Yandroid_ne, FALSE, FALSE,
3523 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3526 Yandroid_neB, FALSE, TRUE,
3527 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3530 Yandroid_e, FALSE, FALSE,
3531 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3534 Yandroid_eB, FALSE, TRUE,
3535 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3538 Yandroid_se, FALSE, FALSE,
3539 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3542 Yandroid_seB, FALSE, TRUE,
3543 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3546 Yandroid_s, FALSE, FALSE,
3547 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3550 Yandroid_sB, FALSE, TRUE,
3551 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3554 Yandroid_sw, FALSE, FALSE,
3555 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3558 Yandroid_swB, FALSE, TRUE,
3559 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3562 Yandroid_w, FALSE, FALSE,
3563 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3566 Yandroid_wB, FALSE, TRUE,
3567 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3570 Yandroid_nw, FALSE, FALSE,
3571 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3574 Yandroid_nwB, FALSE, TRUE,
3575 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3578 Xspring, TRUE, FALSE,
3582 Xspring_pause, FALSE, FALSE,
3586 Xspring_e, FALSE, FALSE,
3590 Xspring_w, FALSE, FALSE,
3594 Xspring_fall, FALSE, FALSE,
3598 Yspring_s, FALSE, FALSE,
3599 EL_SPRING, ACTION_FALLING, -1
3602 Yspring_sB, FALSE, TRUE,
3603 EL_SPRING, ACTION_FALLING, -1
3606 Yspring_e, FALSE, FALSE,
3607 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3610 Yspring_eB, FALSE, TRUE,
3611 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3614 Yspring_w, FALSE, FALSE,
3615 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3618 Yspring_wB, FALSE, TRUE,
3619 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3622 Yspring_kill_e, FALSE, FALSE,
3623 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3626 Yspring_kill_eB, FALSE, TRUE,
3627 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3630 Yspring_kill_w, FALSE, FALSE,
3631 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3634 Yspring_kill_wB, FALSE, TRUE,
3635 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3638 Xeater_n, TRUE, FALSE,
3639 EL_YAMYAM_UP, -1, -1
3642 Xeater_e, TRUE, FALSE,
3643 EL_YAMYAM_RIGHT, -1, -1
3646 Xeater_w, TRUE, FALSE,
3647 EL_YAMYAM_LEFT, -1, -1
3650 Xeater_s, TRUE, FALSE,
3651 EL_YAMYAM_DOWN, -1, -1
3654 Yeater_n, FALSE, FALSE,
3655 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3658 Yeater_nB, FALSE, TRUE,
3659 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3662 Yeater_e, FALSE, FALSE,
3663 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3666 Yeater_eB, FALSE, TRUE,
3667 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3670 Yeater_s, FALSE, FALSE,
3671 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3674 Yeater_sB, FALSE, TRUE,
3675 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3678 Yeater_w, FALSE, FALSE,
3679 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3682 Yeater_wB, FALSE, TRUE,
3683 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3686 Yeater_stone, FALSE, FALSE,
3687 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3690 Yeater_spring, FALSE, FALSE,
3691 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3694 Xalien, TRUE, FALSE,
3698 Xalien_pause, FALSE, FALSE,
3702 Yalien_n, FALSE, FALSE,
3703 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3706 Yalien_nB, FALSE, TRUE,
3707 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3710 Yalien_e, FALSE, FALSE,
3711 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3714 Yalien_eB, FALSE, TRUE,
3715 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3718 Yalien_s, FALSE, FALSE,
3719 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3722 Yalien_sB, FALSE, TRUE,
3723 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3726 Yalien_w, FALSE, FALSE,
3727 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3730 Yalien_wB, FALSE, TRUE,
3731 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3734 Yalien_stone, FALSE, FALSE,
3735 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3738 Yalien_spring, FALSE, FALSE,
3739 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3742 Xemerald, TRUE, FALSE,
3746 Xemerald_pause, FALSE, FALSE,
3750 Xemerald_fall, FALSE, FALSE,
3754 Xemerald_shine, FALSE, FALSE,
3755 EL_EMERALD, ACTION_TWINKLING, -1
3758 Yemerald_s, FALSE, FALSE,
3759 EL_EMERALD, ACTION_FALLING, -1
3762 Yemerald_sB, FALSE, TRUE,
3763 EL_EMERALD, ACTION_FALLING, -1
3766 Yemerald_e, FALSE, FALSE,
3767 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3770 Yemerald_eB, FALSE, TRUE,
3771 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3774 Yemerald_w, FALSE, FALSE,
3775 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3778 Yemerald_wB, FALSE, TRUE,
3779 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3782 Yemerald_eat, FALSE, FALSE,
3783 EL_EMERALD, ACTION_COLLECTING, -1
3786 Yemerald_stone, FALSE, FALSE,
3787 EL_NUT, ACTION_BREAKING, -1
3790 Xdiamond, TRUE, FALSE,
3794 Xdiamond_pause, FALSE, FALSE,
3798 Xdiamond_fall, FALSE, FALSE,
3802 Xdiamond_shine, FALSE, FALSE,
3803 EL_DIAMOND, ACTION_TWINKLING, -1
3806 Ydiamond_s, FALSE, FALSE,
3807 EL_DIAMOND, ACTION_FALLING, -1
3810 Ydiamond_sB, FALSE, TRUE,
3811 EL_DIAMOND, ACTION_FALLING, -1
3814 Ydiamond_e, FALSE, FALSE,
3815 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3818 Ydiamond_eB, FALSE, TRUE,
3819 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3822 Ydiamond_w, FALSE, FALSE,
3823 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3826 Ydiamond_wB, FALSE, TRUE,
3827 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3830 Ydiamond_eat, FALSE, FALSE,
3831 EL_DIAMOND, ACTION_COLLECTING, -1
3834 Ydiamond_stone, FALSE, FALSE,
3835 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3838 Xdrip_fall, TRUE, FALSE,
3839 EL_AMOEBA_DROP, -1, -1
3842 Xdrip_stretch, FALSE, FALSE,
3843 EL_AMOEBA_DROP, ACTION_FALLING, -1
3846 Xdrip_stretchB, FALSE, TRUE,
3847 EL_AMOEBA_DROP, ACTION_FALLING, -1
3850 Xdrip_eat, FALSE, FALSE,
3851 EL_AMOEBA_DROP, ACTION_GROWING, -1
3854 Ydrip_s1, FALSE, FALSE,
3855 EL_AMOEBA_DROP, ACTION_FALLING, -1
3858 Ydrip_s1B, FALSE, TRUE,
3859 EL_AMOEBA_DROP, ACTION_FALLING, -1
3862 Ydrip_s2, FALSE, FALSE,
3863 EL_AMOEBA_DROP, ACTION_FALLING, -1
3866 Ydrip_s2B, FALSE, TRUE,
3867 EL_AMOEBA_DROP, ACTION_FALLING, -1
3874 Xbomb_pause, FALSE, FALSE,
3878 Xbomb_fall, FALSE, FALSE,
3882 Ybomb_s, FALSE, FALSE,
3883 EL_BOMB, ACTION_FALLING, -1
3886 Ybomb_sB, FALSE, TRUE,
3887 EL_BOMB, ACTION_FALLING, -1
3890 Ybomb_e, FALSE, FALSE,
3891 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3894 Ybomb_eB, FALSE, TRUE,
3895 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3898 Ybomb_w, FALSE, FALSE,
3899 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3902 Ybomb_wB, FALSE, TRUE,
3903 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3906 Ybomb_eat, FALSE, FALSE,
3907 EL_BOMB, ACTION_ACTIVATING, -1
3910 Xballoon, TRUE, FALSE,
3914 Yballoon_n, FALSE, FALSE,
3915 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3918 Yballoon_nB, FALSE, TRUE,
3919 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3922 Yballoon_e, FALSE, FALSE,
3923 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3926 Yballoon_eB, FALSE, TRUE,
3927 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3930 Yballoon_s, FALSE, FALSE,
3931 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3934 Yballoon_sB, FALSE, TRUE,
3935 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3938 Yballoon_w, FALSE, FALSE,
3939 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3942 Yballoon_wB, FALSE, TRUE,
3943 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3946 Xgrass, TRUE, FALSE,
3947 EL_EMC_GRASS, -1, -1
3950 Ygrass_nB, FALSE, FALSE,
3951 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3954 Ygrass_eB, FALSE, FALSE,
3955 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3958 Ygrass_sB, FALSE, FALSE,
3959 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3962 Ygrass_wB, FALSE, FALSE,
3963 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3970 Ydirt_nB, FALSE, FALSE,
3971 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3974 Ydirt_eB, FALSE, FALSE,
3975 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3978 Ydirt_sB, FALSE, FALSE,
3979 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3982 Ydirt_wB, FALSE, FALSE,
3983 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3986 Xacid_ne, TRUE, FALSE,
3987 EL_ACID_POOL_TOPRIGHT, -1, -1
3990 Xacid_se, TRUE, FALSE,
3991 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3994 Xacid_s, TRUE, FALSE,
3995 EL_ACID_POOL_BOTTOM, -1, -1
3998 Xacid_sw, TRUE, FALSE,
3999 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4002 Xacid_nw, TRUE, FALSE,
4003 EL_ACID_POOL_TOPLEFT, -1, -1
4006 Xacid_1, TRUE, FALSE,
4010 Xacid_2, FALSE, FALSE,
4014 Xacid_3, FALSE, FALSE,
4018 Xacid_4, FALSE, FALSE,
4022 Xacid_5, FALSE, FALSE,
4026 Xacid_6, FALSE, FALSE,
4030 Xacid_7, FALSE, FALSE,
4034 Xacid_8, FALSE, FALSE,
4038 Xball_1, TRUE, FALSE,
4039 EL_EMC_MAGIC_BALL, -1, -1
4042 Xball_1B, FALSE, FALSE,
4043 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4046 Xball_2, FALSE, FALSE,
4047 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4050 Xball_2B, FALSE, FALSE,
4051 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4054 Yball_eat, FALSE, FALSE,
4055 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4058 Ykey_1_eat, FALSE, FALSE,
4059 EL_EM_KEY_1, ACTION_COLLECTING, -1
4062 Ykey_2_eat, FALSE, FALSE,
4063 EL_EM_KEY_2, ACTION_COLLECTING, -1
4066 Ykey_3_eat, FALSE, FALSE,
4067 EL_EM_KEY_3, ACTION_COLLECTING, -1
4070 Ykey_4_eat, FALSE, FALSE,
4071 EL_EM_KEY_4, ACTION_COLLECTING, -1
4074 Ykey_5_eat, FALSE, FALSE,
4075 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4078 Ykey_6_eat, FALSE, FALSE,
4079 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4082 Ykey_7_eat, FALSE, FALSE,
4083 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4086 Ykey_8_eat, FALSE, FALSE,
4087 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4090 Ylenses_eat, FALSE, FALSE,
4091 EL_EMC_LENSES, ACTION_COLLECTING, -1
4094 Ymagnify_eat, FALSE, FALSE,
4095 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4098 Ygrass_eat, FALSE, FALSE,
4099 EL_EMC_GRASS, ACTION_SNAPPING, -1
4102 Ydirt_eat, FALSE, FALSE,
4103 EL_SAND, ACTION_SNAPPING, -1
4106 Xgrow_ns, TRUE, FALSE,
4107 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4110 Ygrow_ns_eat, FALSE, FALSE,
4111 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4114 Xgrow_ew, TRUE, FALSE,
4115 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4118 Ygrow_ew_eat, FALSE, FALSE,
4119 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4122 Xwonderwall, TRUE, FALSE,
4123 EL_MAGIC_WALL, -1, -1
4126 XwonderwallB, FALSE, FALSE,
4127 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4130 Xamoeba_1, TRUE, FALSE,
4131 EL_AMOEBA_DRY, ACTION_OTHER, -1
4134 Xamoeba_2, FALSE, FALSE,
4135 EL_AMOEBA_DRY, ACTION_OTHER, -1
4138 Xamoeba_3, FALSE, FALSE,
4139 EL_AMOEBA_DRY, ACTION_OTHER, -1
4142 Xamoeba_4, FALSE, FALSE,
4143 EL_AMOEBA_DRY, ACTION_OTHER, -1
4146 Xamoeba_5, TRUE, FALSE,
4147 EL_AMOEBA_WET, ACTION_OTHER, -1
4150 Xamoeba_6, FALSE, FALSE,
4151 EL_AMOEBA_WET, ACTION_OTHER, -1
4154 Xamoeba_7, FALSE, FALSE,
4155 EL_AMOEBA_WET, ACTION_OTHER, -1
4158 Xamoeba_8, FALSE, FALSE,
4159 EL_AMOEBA_WET, ACTION_OTHER, -1
4162 Xdoor_1, TRUE, FALSE,
4163 EL_EM_GATE_1, -1, -1
4166 Xdoor_2, TRUE, FALSE,
4167 EL_EM_GATE_2, -1, -1
4170 Xdoor_3, TRUE, FALSE,
4171 EL_EM_GATE_3, -1, -1
4174 Xdoor_4, TRUE, FALSE,
4175 EL_EM_GATE_4, -1, -1
4178 Xdoor_5, TRUE, FALSE,
4179 EL_EMC_GATE_5, -1, -1
4182 Xdoor_6, TRUE, FALSE,
4183 EL_EMC_GATE_6, -1, -1
4186 Xdoor_7, TRUE, FALSE,
4187 EL_EMC_GATE_7, -1, -1
4190 Xdoor_8, TRUE, FALSE,
4191 EL_EMC_GATE_8, -1, -1
4194 Xkey_1, TRUE, FALSE,
4198 Xkey_2, TRUE, FALSE,
4202 Xkey_3, TRUE, FALSE,
4206 Xkey_4, TRUE, FALSE,
4210 Xkey_5, TRUE, FALSE,
4211 EL_EMC_KEY_5, -1, -1
4214 Xkey_6, TRUE, FALSE,
4215 EL_EMC_KEY_6, -1, -1
4218 Xkey_7, TRUE, FALSE,
4219 EL_EMC_KEY_7, -1, -1
4222 Xkey_8, TRUE, FALSE,
4223 EL_EMC_KEY_8, -1, -1
4226 Xwind_n, TRUE, FALSE,
4227 EL_BALLOON_SWITCH_UP, -1, -1
4230 Xwind_e, TRUE, FALSE,
4231 EL_BALLOON_SWITCH_RIGHT, -1, -1
4234 Xwind_s, TRUE, FALSE,
4235 EL_BALLOON_SWITCH_DOWN, -1, -1
4238 Xwind_w, TRUE, FALSE,
4239 EL_BALLOON_SWITCH_LEFT, -1, -1
4242 Xwind_nesw, TRUE, FALSE,
4243 EL_BALLOON_SWITCH_ANY, -1, -1
4246 Xwind_stop, TRUE, FALSE,
4247 EL_BALLOON_SWITCH_NONE, -1, -1
4251 EL_EXIT_CLOSED, -1, -1
4254 Xexit_1, TRUE, FALSE,
4255 EL_EXIT_OPEN, -1, -1
4258 Xexit_2, FALSE, FALSE,
4259 EL_EXIT_OPEN, -1, -1
4262 Xexit_3, FALSE, FALSE,
4263 EL_EXIT_OPEN, -1, -1
4266 Xdynamite, TRUE, FALSE,
4267 EL_EM_DYNAMITE, -1, -1
4270 Ydynamite_eat, FALSE, FALSE,
4271 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4274 Xdynamite_1, TRUE, FALSE,
4275 EL_EM_DYNAMITE_ACTIVE, -1, -1
4278 Xdynamite_2, FALSE, FALSE,
4279 EL_EM_DYNAMITE_ACTIVE, -1, -1
4282 Xdynamite_3, FALSE, FALSE,
4283 EL_EM_DYNAMITE_ACTIVE, -1, -1
4286 Xdynamite_4, FALSE, FALSE,
4287 EL_EM_DYNAMITE_ACTIVE, -1, -1
4290 Xbumper, TRUE, FALSE,
4291 EL_EMC_SPRING_BUMPER, -1, -1
4294 XbumperB, FALSE, FALSE,
4295 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4298 Xwheel, TRUE, FALSE,
4299 EL_ROBOT_WHEEL, -1, -1
4302 XwheelB, FALSE, FALSE,
4303 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4306 Xswitch, TRUE, FALSE,
4307 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4310 XswitchB, FALSE, FALSE,
4311 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4315 EL_QUICKSAND_EMPTY, -1, -1
4318 Xsand_stone, TRUE, FALSE,
4319 EL_QUICKSAND_FULL, -1, -1
4322 Xsand_stonein_1, FALSE, TRUE,
4323 EL_ROCK, ACTION_FILLING, -1
4326 Xsand_stonein_2, FALSE, TRUE,
4327 EL_ROCK, ACTION_FILLING, -1
4330 Xsand_stonein_3, FALSE, TRUE,
4331 EL_ROCK, ACTION_FILLING, -1
4334 Xsand_stonein_4, FALSE, TRUE,
4335 EL_ROCK, ACTION_FILLING, -1
4338 Xsand_stonesand_1, FALSE, FALSE,
4339 EL_QUICKSAND_FULL, -1, -1
4342 Xsand_stonesand_2, FALSE, FALSE,
4343 EL_QUICKSAND_FULL, -1, -1
4346 Xsand_stonesand_3, FALSE, FALSE,
4347 EL_QUICKSAND_FULL, -1, -1
4350 Xsand_stonesand_4, FALSE, FALSE,
4351 EL_QUICKSAND_FULL, -1, -1
4354 Xsand_stoneout_1, FALSE, FALSE,
4355 EL_ROCK, ACTION_EMPTYING, -1
4358 Xsand_stoneout_2, FALSE, FALSE,
4359 EL_ROCK, ACTION_EMPTYING, -1
4362 Xsand_sandstone_1, FALSE, FALSE,
4363 EL_QUICKSAND_FULL, -1, -1
4366 Xsand_sandstone_2, FALSE, FALSE,
4367 EL_QUICKSAND_FULL, -1, -1
4370 Xsand_sandstone_3, FALSE, FALSE,
4371 EL_QUICKSAND_FULL, -1, -1
4374 Xsand_sandstone_4, FALSE, FALSE,
4375 EL_QUICKSAND_FULL, -1, -1
4378 Xplant, TRUE, FALSE,
4379 EL_EMC_PLANT, -1, -1
4382 Yplant, FALSE, FALSE,
4383 EL_EMC_PLANT, -1, -1
4386 Xlenses, TRUE, FALSE,
4387 EL_EMC_LENSES, -1, -1
4390 Xmagnify, TRUE, FALSE,
4391 EL_EMC_MAGNIFIER, -1, -1
4394 Xdripper, TRUE, FALSE,
4395 EL_EMC_DRIPPER, -1, -1
4398 XdripperB, FALSE, FALSE,
4399 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4402 Xfake_blank, TRUE, FALSE,
4403 EL_INVISIBLE_WALL, -1, -1
4406 Xfake_blankB, FALSE, FALSE,
4407 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4410 Xfake_grass, TRUE, FALSE,
4411 EL_EMC_FAKE_GRASS, -1, -1
4414 Xfake_grassB, FALSE, FALSE,
4415 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4418 Xfake_door_1, TRUE, FALSE,
4419 EL_EM_GATE_1_GRAY, -1, -1
4422 Xfake_door_2, TRUE, FALSE,
4423 EL_EM_GATE_2_GRAY, -1, -1
4426 Xfake_door_3, TRUE, FALSE,
4427 EL_EM_GATE_3_GRAY, -1, -1
4430 Xfake_door_4, TRUE, FALSE,
4431 EL_EM_GATE_4_GRAY, -1, -1
4434 Xfake_door_5, TRUE, FALSE,
4435 EL_EMC_GATE_5_GRAY, -1, -1
4438 Xfake_door_6, TRUE, FALSE,
4439 EL_EMC_GATE_6_GRAY, -1, -1
4442 Xfake_door_7, TRUE, FALSE,
4443 EL_EMC_GATE_7_GRAY, -1, -1
4446 Xfake_door_8, TRUE, FALSE,
4447 EL_EMC_GATE_8_GRAY, -1, -1
4450 Xfake_acid_1, TRUE, FALSE,
4451 EL_EMC_FAKE_ACID, -1, -1
4454 Xfake_acid_2, FALSE, FALSE,
4455 EL_EMC_FAKE_ACID, -1, -1
4458 Xfake_acid_3, FALSE, FALSE,
4459 EL_EMC_FAKE_ACID, -1, -1
4462 Xfake_acid_4, FALSE, FALSE,
4463 EL_EMC_FAKE_ACID, -1, -1
4466 Xfake_acid_5, FALSE, FALSE,
4467 EL_EMC_FAKE_ACID, -1, -1
4470 Xfake_acid_6, FALSE, FALSE,
4471 EL_EMC_FAKE_ACID, -1, -1
4474 Xfake_acid_7, FALSE, FALSE,
4475 EL_EMC_FAKE_ACID, -1, -1
4478 Xfake_acid_8, FALSE, FALSE,
4479 EL_EMC_FAKE_ACID, -1, -1
4482 Xsteel_1, TRUE, FALSE,
4483 EL_STEELWALL, -1, -1
4486 Xsteel_2, TRUE, FALSE,
4487 EL_EMC_STEELWALL_2, -1, -1
4490 Xsteel_3, TRUE, FALSE,
4491 EL_EMC_STEELWALL_3, -1, -1
4494 Xsteel_4, TRUE, FALSE,
4495 EL_EMC_STEELWALL_4, -1, -1
4498 Xwall_1, TRUE, FALSE,
4502 Xwall_2, TRUE, FALSE,
4503 EL_EMC_WALL_14, -1, -1
4506 Xwall_3, TRUE, FALSE,
4507 EL_EMC_WALL_15, -1, -1
4510 Xwall_4, TRUE, FALSE,
4511 EL_EMC_WALL_16, -1, -1
4514 Xround_wall_1, TRUE, FALSE,
4515 EL_WALL_SLIPPERY, -1, -1
4518 Xround_wall_2, TRUE, FALSE,
4519 EL_EMC_WALL_SLIPPERY_2, -1, -1
4522 Xround_wall_3, TRUE, FALSE,
4523 EL_EMC_WALL_SLIPPERY_3, -1, -1
4526 Xround_wall_4, TRUE, FALSE,
4527 EL_EMC_WALL_SLIPPERY_4, -1, -1
4530 Xdecor_1, TRUE, FALSE,
4531 EL_EMC_WALL_8, -1, -1
4534 Xdecor_2, TRUE, FALSE,
4535 EL_EMC_WALL_6, -1, -1
4538 Xdecor_3, TRUE, FALSE,
4539 EL_EMC_WALL_4, -1, -1
4542 Xdecor_4, TRUE, FALSE,
4543 EL_EMC_WALL_7, -1, -1
4546 Xdecor_5, TRUE, FALSE,
4547 EL_EMC_WALL_5, -1, -1
4550 Xdecor_6, TRUE, FALSE,
4551 EL_EMC_WALL_9, -1, -1
4554 Xdecor_7, TRUE, FALSE,
4555 EL_EMC_WALL_10, -1, -1
4558 Xdecor_8, TRUE, FALSE,
4559 EL_EMC_WALL_1, -1, -1
4562 Xdecor_9, TRUE, FALSE,
4563 EL_EMC_WALL_2, -1, -1
4566 Xdecor_10, TRUE, FALSE,
4567 EL_EMC_WALL_3, -1, -1
4570 Xdecor_11, TRUE, FALSE,
4571 EL_EMC_WALL_11, -1, -1
4574 Xdecor_12, TRUE, FALSE,
4575 EL_EMC_WALL_12, -1, -1
4578 Xalpha_0, TRUE, FALSE,
4579 EL_CHAR('0'), -1, -1
4582 Xalpha_1, TRUE, FALSE,
4583 EL_CHAR('1'), -1, -1
4586 Xalpha_2, TRUE, FALSE,
4587 EL_CHAR('2'), -1, -1
4590 Xalpha_3, TRUE, FALSE,
4591 EL_CHAR('3'), -1, -1
4594 Xalpha_4, TRUE, FALSE,
4595 EL_CHAR('4'), -1, -1
4598 Xalpha_5, TRUE, FALSE,
4599 EL_CHAR('5'), -1, -1
4602 Xalpha_6, TRUE, FALSE,
4603 EL_CHAR('6'), -1, -1
4606 Xalpha_7, TRUE, FALSE,
4607 EL_CHAR('7'), -1, -1
4610 Xalpha_8, TRUE, FALSE,
4611 EL_CHAR('8'), -1, -1
4614 Xalpha_9, TRUE, FALSE,
4615 EL_CHAR('9'), -1, -1
4618 Xalpha_excla, TRUE, FALSE,
4619 EL_CHAR('!'), -1, -1
4622 Xalpha_quote, TRUE, FALSE,
4623 EL_CHAR('"'), -1, -1
4626 Xalpha_comma, TRUE, FALSE,
4627 EL_CHAR(','), -1, -1
4630 Xalpha_minus, TRUE, FALSE,
4631 EL_CHAR('-'), -1, -1
4634 Xalpha_perio, TRUE, FALSE,
4635 EL_CHAR('.'), -1, -1
4638 Xalpha_colon, TRUE, FALSE,
4639 EL_CHAR(':'), -1, -1
4642 Xalpha_quest, TRUE, FALSE,
4643 EL_CHAR('?'), -1, -1
4646 Xalpha_a, TRUE, FALSE,
4647 EL_CHAR('A'), -1, -1
4650 Xalpha_b, TRUE, FALSE,
4651 EL_CHAR('B'), -1, -1
4654 Xalpha_c, TRUE, FALSE,
4655 EL_CHAR('C'), -1, -1
4658 Xalpha_d, TRUE, FALSE,
4659 EL_CHAR('D'), -1, -1
4662 Xalpha_e, TRUE, FALSE,
4663 EL_CHAR('E'), -1, -1
4666 Xalpha_f, TRUE, FALSE,
4667 EL_CHAR('F'), -1, -1
4670 Xalpha_g, TRUE, FALSE,
4671 EL_CHAR('G'), -1, -1
4674 Xalpha_h, TRUE, FALSE,
4675 EL_CHAR('H'), -1, -1
4678 Xalpha_i, TRUE, FALSE,
4679 EL_CHAR('I'), -1, -1
4682 Xalpha_j, TRUE, FALSE,
4683 EL_CHAR('J'), -1, -1
4686 Xalpha_k, TRUE, FALSE,
4687 EL_CHAR('K'), -1, -1
4690 Xalpha_l, TRUE, FALSE,
4691 EL_CHAR('L'), -1, -1
4694 Xalpha_m, TRUE, FALSE,
4695 EL_CHAR('M'), -1, -1
4698 Xalpha_n, TRUE, FALSE,
4699 EL_CHAR('N'), -1, -1
4702 Xalpha_o, TRUE, FALSE,
4703 EL_CHAR('O'), -1, -1
4706 Xalpha_p, TRUE, FALSE,
4707 EL_CHAR('P'), -1, -1
4710 Xalpha_q, TRUE, FALSE,
4711 EL_CHAR('Q'), -1, -1
4714 Xalpha_r, TRUE, FALSE,
4715 EL_CHAR('R'), -1, -1
4718 Xalpha_s, TRUE, FALSE,
4719 EL_CHAR('S'), -1, -1
4722 Xalpha_t, TRUE, FALSE,
4723 EL_CHAR('T'), -1, -1
4726 Xalpha_u, TRUE, FALSE,
4727 EL_CHAR('U'), -1, -1
4730 Xalpha_v, TRUE, FALSE,
4731 EL_CHAR('V'), -1, -1
4734 Xalpha_w, TRUE, FALSE,
4735 EL_CHAR('W'), -1, -1
4738 Xalpha_x, TRUE, FALSE,
4739 EL_CHAR('X'), -1, -1
4742 Xalpha_y, TRUE, FALSE,
4743 EL_CHAR('Y'), -1, -1
4746 Xalpha_z, TRUE, FALSE,
4747 EL_CHAR('Z'), -1, -1
4750 Xalpha_arrow_e, TRUE, FALSE,
4751 EL_CHAR('>'), -1, -1
4754 Xalpha_arrow_w, TRUE, FALSE,
4755 EL_CHAR('<'), -1, -1
4758 Xalpha_copyr, TRUE, FALSE,
4759 EL_CHAR('©'), -1, -1
4763 Xboom_bug, FALSE, FALSE,
4764 EL_BUG, ACTION_EXPLODING, -1
4767 Xboom_bomb, FALSE, FALSE,
4768 EL_BOMB, ACTION_EXPLODING, -1
4771 Xboom_android, FALSE, FALSE,
4772 EL_EMC_ANDROID, ACTION_OTHER, -1
4775 Xboom_1, FALSE, FALSE,
4776 EL_DEFAULT, ACTION_EXPLODING, -1
4779 Xboom_2, FALSE, FALSE,
4780 EL_DEFAULT, ACTION_EXPLODING, -1
4783 Znormal, FALSE, FALSE,
4787 Zdynamite, FALSE, FALSE,
4791 Zplayer, FALSE, FALSE,
4795 ZBORDER, FALSE, FALSE,
4805 static struct Mapping_EM_to_RND_player
4814 em_player_mapping_list[] =
4818 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4822 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4826 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4830 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4834 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4838 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4842 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4846 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4850 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4854 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4858 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4862 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4866 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4870 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4874 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4878 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4882 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4886 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4890 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4894 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4898 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4902 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4906 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4910 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4914 EL_PLAYER_1, ACTION_DEFAULT, -1,
4918 EL_PLAYER_2, ACTION_DEFAULT, -1,
4922 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4926 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4930 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4934 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4938 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4942 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4946 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4950 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4954 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4958 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4962 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4966 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4970 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4974 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4978 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4982 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4986 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4990 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4994 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4998 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5002 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5006 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5010 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5014 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5018 EL_PLAYER_3, ACTION_DEFAULT, -1,
5022 EL_PLAYER_4, ACTION_DEFAULT, -1,
5031 int map_element_RND_to_EM(int element_rnd)
5033 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5034 static boolean mapping_initialized = FALSE;
5036 if (!mapping_initialized)
5040 /* return "Xalpha_quest" for all undefined elements in mapping array */
5041 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5042 mapping_RND_to_EM[i] = Xalpha_quest;
5044 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5045 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5046 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5047 em_object_mapping_list[i].element_em;
5049 mapping_initialized = TRUE;
5052 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5053 return mapping_RND_to_EM[element_rnd];
5055 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5060 int map_element_EM_to_RND(int element_em)
5062 static unsigned short mapping_EM_to_RND[TILE_MAX];
5063 static boolean mapping_initialized = FALSE;
5065 if (!mapping_initialized)
5069 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5070 for (i = 0; i < TILE_MAX; i++)
5071 mapping_EM_to_RND[i] = EL_UNKNOWN;
5073 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5074 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5075 em_object_mapping_list[i].element_rnd;
5077 mapping_initialized = TRUE;
5080 if (element_em >= 0 && element_em < TILE_MAX)
5081 return mapping_EM_to_RND[element_em];
5083 Error(ERR_WARN, "invalid EM level element %d", element_em);
5088 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5090 struct LevelInfo_EM *level_em = level->native_em_level;
5091 struct LEVEL *lev = level_em->lev;
5094 for (i = 0; i < TILE_MAX; i++)
5095 lev->android_array[i] = Xblank;
5097 for (i = 0; i < level->num_android_clone_elements; i++)
5099 int element_rnd = level->android_clone_element[i];
5100 int element_em = map_element_RND_to_EM(element_rnd);
5102 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5103 if (em_object_mapping_list[j].element_rnd == element_rnd)
5104 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5108 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5110 struct LevelInfo_EM *level_em = level->native_em_level;
5111 struct LEVEL *lev = level_em->lev;
5114 level->num_android_clone_elements = 0;
5116 for (i = 0; i < TILE_MAX; i++)
5118 int element_em = lev->android_array[i];
5120 boolean element_found = FALSE;
5122 if (element_em == Xblank)
5125 element_rnd = map_element_EM_to_RND(element_em);
5127 for (j = 0; j < level->num_android_clone_elements; j++)
5128 if (level->android_clone_element[j] == element_rnd)
5129 element_found = TRUE;
5133 level->android_clone_element[level->num_android_clone_elements++] =
5136 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5141 if (level->num_android_clone_elements == 0)
5143 level->num_android_clone_elements = 1;
5144 level->android_clone_element[0] = EL_EMPTY;
5148 int map_direction_RND_to_EM(int direction)
5150 return (direction == MV_UP ? 0 :
5151 direction == MV_RIGHT ? 1 :
5152 direction == MV_DOWN ? 2 :
5153 direction == MV_LEFT ? 3 :
5157 int map_direction_EM_to_RND(int direction)
5159 return (direction == 0 ? MV_UP :
5160 direction == 1 ? MV_RIGHT :
5161 direction == 2 ? MV_DOWN :
5162 direction == 3 ? MV_LEFT :
5166 int get_next_element(int element)
5170 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5171 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5172 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5173 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5174 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5175 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5176 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5178 default: return element;
5183 int el_act_dir2img(int element, int action, int direction)
5185 element = GFX_ELEMENT(element);
5187 if (direction == MV_NONE)
5188 return element_info[element].graphic[action];
5190 direction = MV_DIR_TO_BIT(direction);
5192 return element_info[element].direction_graphic[action][direction];
5195 int el_act_dir2img(int element, int action, int direction)
5197 element = GFX_ELEMENT(element);
5198 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5200 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5201 return element_info[element].direction_graphic[action][direction];
5206 static int el_act_dir2crm(int element, int action, int direction)
5208 element = GFX_ELEMENT(element);
5210 if (direction == MV_NONE)
5211 return element_info[element].crumbled[action];
5213 direction = MV_DIR_TO_BIT(direction);
5215 return element_info[element].direction_crumbled[action][direction];
5218 static int el_act_dir2crm(int element, int action, int direction)
5220 element = GFX_ELEMENT(element);
5221 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5223 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5224 return element_info[element].direction_crumbled[action][direction];
5228 int el_act2img(int element, int action)
5230 element = GFX_ELEMENT(element);
5232 return element_info[element].graphic[action];
5235 int el_act2crm(int element, int action)
5237 element = GFX_ELEMENT(element);
5239 return element_info[element].crumbled[action];
5242 int el_dir2img(int element, int direction)
5244 element = GFX_ELEMENT(element);
5246 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5249 int el2baseimg(int element)
5251 return element_info[element].graphic[ACTION_DEFAULT];
5254 int el2img(int element)
5256 element = GFX_ELEMENT(element);
5258 return element_info[element].graphic[ACTION_DEFAULT];
5261 int el2edimg(int element)
5263 element = GFX_ELEMENT(element);
5265 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5268 int el2preimg(int element)
5270 element = GFX_ELEMENT(element);
5272 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5275 int font2baseimg(int font_nr)
5277 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5280 int getNumActivePlayers_EM()
5282 int num_players = 0;
5288 for (i = 0; i < MAX_PLAYERS; i++)
5289 if (tape.player_participates[i])
5295 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5297 int game_frame_delay_value;
5299 game_frame_delay_value =
5300 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5301 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5304 if (tape.playing && tape.warp_forward && !tape.pausing)
5305 game_frame_delay_value = 0;
5307 return game_frame_delay_value;
5310 unsigned int InitRND(long seed)
5312 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5313 return InitEngineRandom_EM(seed);
5315 return InitEngineRandom_RND(seed);
5318 void InitGraphicInfo_EM(void)
5320 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5321 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5325 int num_em_gfx_errors = 0;
5327 if (graphic_info_em_object[0][0].bitmap == NULL)
5329 /* EM graphics not yet initialized in em_open_all() */
5334 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5337 /* always start with reliable default values */
5338 for (i = 0; i < TILE_MAX; i++)
5340 object_mapping[i].element_rnd = EL_UNKNOWN;
5341 object_mapping[i].is_backside = FALSE;
5342 object_mapping[i].action = ACTION_DEFAULT;
5343 object_mapping[i].direction = MV_NONE;
5346 /* always start with reliable default values */
5347 for (p = 0; p < MAX_PLAYERS; p++)
5349 for (i = 0; i < SPR_MAX; i++)
5351 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5352 player_mapping[p][i].action = ACTION_DEFAULT;
5353 player_mapping[p][i].direction = MV_NONE;
5357 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5359 int e = em_object_mapping_list[i].element_em;
5361 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5362 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5364 if (em_object_mapping_list[i].action != -1)
5365 object_mapping[e].action = em_object_mapping_list[i].action;
5367 if (em_object_mapping_list[i].direction != -1)
5368 object_mapping[e].direction =
5369 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5372 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5374 int a = em_player_mapping_list[i].action_em;
5375 int p = em_player_mapping_list[i].player_nr;
5377 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5379 if (em_player_mapping_list[i].action != -1)
5380 player_mapping[p][a].action = em_player_mapping_list[i].action;
5382 if (em_player_mapping_list[i].direction != -1)
5383 player_mapping[p][a].direction =
5384 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5387 for (i = 0; i < TILE_MAX; i++)
5389 int element = object_mapping[i].element_rnd;
5390 int action = object_mapping[i].action;
5391 int direction = object_mapping[i].direction;
5392 boolean is_backside = object_mapping[i].is_backside;
5393 boolean action_removing = (action == ACTION_DIGGING ||
5394 action == ACTION_SNAPPING ||
5395 action == ACTION_COLLECTING);
5396 boolean action_exploding = ((action == ACTION_EXPLODING ||
5397 action == ACTION_SMASHED_BY_ROCK ||
5398 action == ACTION_SMASHED_BY_SPRING) &&
5399 element != EL_DIAMOND);
5400 boolean action_active = (action == ACTION_ACTIVE);
5401 boolean action_other = (action == ACTION_OTHER);
5403 for (j = 0; j < 8; j++)
5405 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5406 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5408 i == Xdrip_stretch ? element :
5409 i == Xdrip_stretchB ? element :
5410 i == Ydrip_s1 ? element :
5411 i == Ydrip_s1B ? element :
5412 i == Xball_1B ? element :
5413 i == Xball_2 ? element :
5414 i == Xball_2B ? element :
5415 i == Yball_eat ? element :
5416 i == Ykey_1_eat ? element :
5417 i == Ykey_2_eat ? element :
5418 i == Ykey_3_eat ? element :
5419 i == Ykey_4_eat ? element :
5420 i == Ykey_5_eat ? element :
5421 i == Ykey_6_eat ? element :
5422 i == Ykey_7_eat ? element :
5423 i == Ykey_8_eat ? element :
5424 i == Ylenses_eat ? element :
5425 i == Ymagnify_eat ? element :
5426 i == Ygrass_eat ? element :
5427 i == Ydirt_eat ? element :
5428 i == Yemerald_stone ? EL_EMERALD :
5429 i == Ydiamond_stone ? EL_ROCK :
5430 i == Xsand_stonein_1 ? element :
5431 i == Xsand_stonein_2 ? element :
5432 i == Xsand_stonein_3 ? element :
5433 i == Xsand_stonein_4 ? element :
5434 is_backside ? EL_EMPTY :
5435 action_removing ? EL_EMPTY :
5437 int effective_action = (j < 7 ? action :
5438 i == Xdrip_stretch ? action :
5439 i == Xdrip_stretchB ? action :
5440 i == Ydrip_s1 ? action :
5441 i == Ydrip_s1B ? action :
5442 i == Xball_1B ? action :
5443 i == Xball_2 ? action :
5444 i == Xball_2B ? action :
5445 i == Yball_eat ? action :
5446 i == Ykey_1_eat ? action :
5447 i == Ykey_2_eat ? action :
5448 i == Ykey_3_eat ? action :
5449 i == Ykey_4_eat ? action :
5450 i == Ykey_5_eat ? action :
5451 i == Ykey_6_eat ? action :
5452 i == Ykey_7_eat ? action :
5453 i == Ykey_8_eat ? action :
5454 i == Ylenses_eat ? action :
5455 i == Ymagnify_eat ? action :
5456 i == Ygrass_eat ? action :
5457 i == Ydirt_eat ? action :
5458 i == Xsand_stonein_1 ? action :
5459 i == Xsand_stonein_2 ? action :
5460 i == Xsand_stonein_3 ? action :
5461 i == Xsand_stonein_4 ? action :
5462 i == Xsand_stoneout_1 ? action :
5463 i == Xsand_stoneout_2 ? action :
5464 i == Xboom_android ? ACTION_EXPLODING :
5465 action_exploding ? ACTION_EXPLODING :
5466 action_active ? action :
5467 action_other ? action :
5469 int graphic = (el_act_dir2img(effective_element, effective_action,
5471 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5473 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5474 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5475 boolean has_action_graphics = (graphic != base_graphic);
5476 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5477 struct GraphicInfo *g = &graphic_info[graphic];
5478 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5481 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5482 boolean special_animation = (action != ACTION_DEFAULT &&
5483 g->anim_frames == 3 &&
5484 g->anim_delay == 2 &&
5485 g->anim_mode & ANIM_LINEAR);
5486 int sync_frame = (i == Xdrip_stretch ? 7 :
5487 i == Xdrip_stretchB ? 7 :
5488 i == Ydrip_s2 ? j + 8 :
5489 i == Ydrip_s2B ? j + 8 :
5498 i == Xfake_acid_1 ? 0 :
5499 i == Xfake_acid_2 ? 10 :
5500 i == Xfake_acid_3 ? 20 :
5501 i == Xfake_acid_4 ? 30 :
5502 i == Xfake_acid_5 ? 40 :
5503 i == Xfake_acid_6 ? 50 :
5504 i == Xfake_acid_7 ? 60 :
5505 i == Xfake_acid_8 ? 70 :
5507 i == Xball_2B ? j + 8 :
5508 i == Yball_eat ? j + 1 :
5509 i == Ykey_1_eat ? j + 1 :
5510 i == Ykey_2_eat ? j + 1 :
5511 i == Ykey_3_eat ? j + 1 :
5512 i == Ykey_4_eat ? j + 1 :
5513 i == Ykey_5_eat ? j + 1 :
5514 i == Ykey_6_eat ? j + 1 :
5515 i == Ykey_7_eat ? j + 1 :
5516 i == Ykey_8_eat ? j + 1 :
5517 i == Ylenses_eat ? j + 1 :
5518 i == Ymagnify_eat ? j + 1 :
5519 i == Ygrass_eat ? j + 1 :
5520 i == Ydirt_eat ? j + 1 :
5521 i == Xamoeba_1 ? 0 :
5522 i == Xamoeba_2 ? 1 :
5523 i == Xamoeba_3 ? 2 :
5524 i == Xamoeba_4 ? 3 :
5525 i == Xamoeba_5 ? 0 :
5526 i == Xamoeba_6 ? 1 :
5527 i == Xamoeba_7 ? 2 :
5528 i == Xamoeba_8 ? 3 :
5529 i == Xexit_2 ? j + 8 :
5530 i == Xexit_3 ? j + 16 :
5531 i == Xdynamite_1 ? 0 :
5532 i == Xdynamite_2 ? 8 :
5533 i == Xdynamite_3 ? 16 :
5534 i == Xdynamite_4 ? 24 :
5535 i == Xsand_stonein_1 ? j + 1 :
5536 i == Xsand_stonein_2 ? j + 9 :
5537 i == Xsand_stonein_3 ? j + 17 :
5538 i == Xsand_stonein_4 ? j + 25 :
5539 i == Xsand_stoneout_1 && j == 0 ? 0 :
5540 i == Xsand_stoneout_1 && j == 1 ? 0 :
5541 i == Xsand_stoneout_1 && j == 2 ? 1 :
5542 i == Xsand_stoneout_1 && j == 3 ? 2 :
5543 i == Xsand_stoneout_1 && j == 4 ? 2 :
5544 i == Xsand_stoneout_1 && j == 5 ? 3 :
5545 i == Xsand_stoneout_1 && j == 6 ? 4 :
5546 i == Xsand_stoneout_1 && j == 7 ? 4 :
5547 i == Xsand_stoneout_2 && j == 0 ? 5 :
5548 i == Xsand_stoneout_2 && j == 1 ? 6 :
5549 i == Xsand_stoneout_2 && j == 2 ? 7 :
5550 i == Xsand_stoneout_2 && j == 3 ? 8 :
5551 i == Xsand_stoneout_2 && j == 4 ? 9 :
5552 i == Xsand_stoneout_2 && j == 5 ? 11 :
5553 i == Xsand_stoneout_2 && j == 6 ? 13 :
5554 i == Xsand_stoneout_2 && j == 7 ? 15 :
5555 i == Xboom_bug && j == 1 ? 2 :
5556 i == Xboom_bug && j == 2 ? 2 :
5557 i == Xboom_bug && j == 3 ? 4 :
5558 i == Xboom_bug && j == 4 ? 4 :
5559 i == Xboom_bug && j == 5 ? 2 :
5560 i == Xboom_bug && j == 6 ? 2 :
5561 i == Xboom_bug && j == 7 ? 0 :
5562 i == Xboom_bomb && j == 1 ? 2 :
5563 i == Xboom_bomb && j == 2 ? 2 :
5564 i == Xboom_bomb && j == 3 ? 4 :
5565 i == Xboom_bomb && j == 4 ? 4 :
5566 i == Xboom_bomb && j == 5 ? 2 :
5567 i == Xboom_bomb && j == 6 ? 2 :
5568 i == Xboom_bomb && j == 7 ? 0 :
5569 i == Xboom_android && j == 7 ? 6 :
5570 i == Xboom_1 && j == 1 ? 2 :
5571 i == Xboom_1 && j == 2 ? 2 :
5572 i == Xboom_1 && j == 3 ? 4 :
5573 i == Xboom_1 && j == 4 ? 4 :
5574 i == Xboom_1 && j == 5 ? 6 :
5575 i == Xboom_1 && j == 6 ? 6 :
5576 i == Xboom_1 && j == 7 ? 8 :
5577 i == Xboom_2 && j == 0 ? 8 :
5578 i == Xboom_2 && j == 1 ? 8 :
5579 i == Xboom_2 && j == 2 ? 10 :
5580 i == Xboom_2 && j == 3 ? 10 :
5581 i == Xboom_2 && j == 4 ? 10 :
5582 i == Xboom_2 && j == 5 ? 12 :
5583 i == Xboom_2 && j == 6 ? 12 :
5584 i == Xboom_2 && j == 7 ? 12 :
5585 special_animation && j == 4 ? 3 :
5586 effective_action != action ? 0 :
5590 Bitmap *debug_bitmap = g_em->bitmap;
5591 int debug_src_x = g_em->src_x;
5592 int debug_src_y = g_em->src_y;
5595 int frame = getAnimationFrame(g->anim_frames,
5598 g->anim_start_frame,
5601 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5602 g->double_movement && is_backside);
5604 g_em->bitmap = src_bitmap;
5605 g_em->src_x = src_x;
5606 g_em->src_y = src_y;
5607 g_em->src_offset_x = 0;
5608 g_em->src_offset_y = 0;
5609 g_em->dst_offset_x = 0;
5610 g_em->dst_offset_y = 0;
5611 g_em->width = TILEX;
5612 g_em->height = TILEY;
5614 g_em->crumbled_bitmap = NULL;
5615 g_em->crumbled_src_x = 0;
5616 g_em->crumbled_src_y = 0;
5617 g_em->crumbled_border_size = 0;
5619 g_em->has_crumbled_graphics = FALSE;
5620 g_em->preserve_background = FALSE;
5623 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5624 printf("::: empty crumbled: %d [%s], %d, %d\n",
5625 effective_element, element_info[effective_element].token_name,
5626 effective_action, direction);
5629 /* if element can be crumbled, but certain action graphics are just empty
5630 space (like snapping sand with the original R'n'D graphics), do not
5631 treat these empty space graphics as crumbled graphics in EMC engine */
5632 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5634 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5636 g_em->has_crumbled_graphics = TRUE;
5637 g_em->crumbled_bitmap = src_bitmap;
5638 g_em->crumbled_src_x = src_x;
5639 g_em->crumbled_src_y = src_y;
5640 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5644 if (element == EL_ROCK &&
5645 effective_action == ACTION_FILLING)
5646 printf("::: has_action_graphics == %d\n", has_action_graphics);
5649 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5650 effective_action == ACTION_MOVING ||
5651 effective_action == ACTION_PUSHING ||
5652 effective_action == ACTION_EATING)) ||
5653 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5654 effective_action == ACTION_EMPTYING)))
5657 (effective_action == ACTION_FALLING ||
5658 effective_action == ACTION_FILLING ||
5659 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5660 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5661 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5662 int num_steps = (i == Ydrip_s1 ? 16 :
5663 i == Ydrip_s1B ? 16 :
5664 i == Ydrip_s2 ? 16 :
5665 i == Ydrip_s2B ? 16 :
5666 i == Xsand_stonein_1 ? 32 :
5667 i == Xsand_stonein_2 ? 32 :
5668 i == Xsand_stonein_3 ? 32 :
5669 i == Xsand_stonein_4 ? 32 :
5670 i == Xsand_stoneout_1 ? 16 :
5671 i == Xsand_stoneout_2 ? 16 : 8);
5672 int cx = ABS(dx) * (TILEX / num_steps);
5673 int cy = ABS(dy) * (TILEY / num_steps);
5674 int step_frame = (i == Ydrip_s2 ? j + 8 :
5675 i == Ydrip_s2B ? j + 8 :
5676 i == Xsand_stonein_2 ? j + 8 :
5677 i == Xsand_stonein_3 ? j + 16 :
5678 i == Xsand_stonein_4 ? j + 24 :
5679 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5680 int step = (is_backside ? step_frame : num_steps - step_frame);
5682 if (is_backside) /* tile where movement starts */
5684 if (dx < 0 || dy < 0)
5686 g_em->src_offset_x = cx * step;
5687 g_em->src_offset_y = cy * step;
5691 g_em->dst_offset_x = cx * step;
5692 g_em->dst_offset_y = cy * step;
5695 else /* tile where movement ends */
5697 if (dx < 0 || dy < 0)
5699 g_em->dst_offset_x = cx * step;
5700 g_em->dst_offset_y = cy * step;
5704 g_em->src_offset_x = cx * step;
5705 g_em->src_offset_y = cy * step;
5709 g_em->width = TILEX - cx * step;
5710 g_em->height = TILEY - cy * step;
5713 /* create unique graphic identifier to decide if tile must be redrawn */
5714 /* bit 31 - 16 (16 bit): EM style graphic
5715 bit 15 - 12 ( 4 bit): EM style frame
5716 bit 11 - 6 ( 6 bit): graphic width
5717 bit 5 - 0 ( 6 bit): graphic height */
5718 g_em->unique_identifier =
5719 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5723 /* skip check for EMC elements not contained in original EMC artwork */
5724 if (element == EL_EMC_FAKE_ACID)
5727 if (g_em->bitmap != debug_bitmap ||
5728 g_em->src_x != debug_src_x ||
5729 g_em->src_y != debug_src_y ||
5730 g_em->src_offset_x != 0 ||
5731 g_em->src_offset_y != 0 ||
5732 g_em->dst_offset_x != 0 ||
5733 g_em->dst_offset_y != 0 ||
5734 g_em->width != TILEX ||
5735 g_em->height != TILEY)
5737 static int last_i = -1;
5745 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5746 i, element, element_info[element].token_name,
5747 element_action_info[effective_action].suffix, direction);
5749 if (element != effective_element)
5750 printf(" [%d ('%s')]",
5752 element_info[effective_element].token_name);
5756 if (g_em->bitmap != debug_bitmap)
5757 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5758 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5760 if (g_em->src_x != debug_src_x ||
5761 g_em->src_y != debug_src_y)
5762 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5763 j, (is_backside ? 'B' : 'F'),
5764 g_em->src_x, g_em->src_y,
5765 g_em->src_x / 32, g_em->src_y / 32,
5766 debug_src_x, debug_src_y,
5767 debug_src_x / 32, debug_src_y / 32);
5769 if (g_em->src_offset_x != 0 ||
5770 g_em->src_offset_y != 0 ||
5771 g_em->dst_offset_x != 0 ||
5772 g_em->dst_offset_y != 0)
5773 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5775 g_em->src_offset_x, g_em->src_offset_y,
5776 g_em->dst_offset_x, g_em->dst_offset_y);
5778 if (g_em->width != TILEX ||
5779 g_em->height != TILEY)
5780 printf(" %d (%d): size %d,%d should be %d,%d\n",
5782 g_em->width, g_em->height, TILEX, TILEY);
5784 num_em_gfx_errors++;
5791 for (i = 0; i < TILE_MAX; i++)
5793 for (j = 0; j < 8; j++)
5795 int element = object_mapping[i].element_rnd;
5796 int action = object_mapping[i].action;
5797 int direction = object_mapping[i].direction;
5798 boolean is_backside = object_mapping[i].is_backside;
5799 int graphic_action = el_act_dir2img(element, action, direction);
5800 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5802 if ((action == ACTION_SMASHED_BY_ROCK ||
5803 action == ACTION_SMASHED_BY_SPRING ||
5804 action == ACTION_EATING) &&
5805 graphic_action == graphic_default)
5807 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5808 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5809 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5810 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5813 /* no separate animation for "smashed by rock" -- use rock instead */
5814 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5815 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5817 g_em->bitmap = g_xx->bitmap;
5818 g_em->src_x = g_xx->src_x;
5819 g_em->src_y = g_xx->src_y;
5820 g_em->src_offset_x = g_xx->src_offset_x;
5821 g_em->src_offset_y = g_xx->src_offset_y;
5822 g_em->dst_offset_x = g_xx->dst_offset_x;
5823 g_em->dst_offset_y = g_xx->dst_offset_y;
5824 g_em->width = g_xx->width;
5825 g_em->height = g_xx->height;
5826 g_em->unique_identifier = g_xx->unique_identifier;
5829 g_em->preserve_background = TRUE;
5834 for (p = 0; p < MAX_PLAYERS; p++)
5836 for (i = 0; i < SPR_MAX; i++)
5838 int element = player_mapping[p][i].element_rnd;
5839 int action = player_mapping[p][i].action;
5840 int direction = player_mapping[p][i].direction;
5842 for (j = 0; j < 8; j++)
5844 int effective_element = element;
5845 int effective_action = action;
5846 int graphic = (direction == MV_NONE ?
5847 el_act2img(effective_element, effective_action) :
5848 el_act_dir2img(effective_element, effective_action,
5850 struct GraphicInfo *g = &graphic_info[graphic];
5851 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5857 Bitmap *debug_bitmap = g_em->bitmap;
5858 int debug_src_x = g_em->src_x;
5859 int debug_src_y = g_em->src_y;
5862 int frame = getAnimationFrame(g->anim_frames,
5865 g->anim_start_frame,
5868 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5870 g_em->bitmap = src_bitmap;
5871 g_em->src_x = src_x;
5872 g_em->src_y = src_y;
5873 g_em->src_offset_x = 0;
5874 g_em->src_offset_y = 0;
5875 g_em->dst_offset_x = 0;
5876 g_em->dst_offset_y = 0;
5877 g_em->width = TILEX;
5878 g_em->height = TILEY;
5882 /* skip check for EMC elements not contained in original EMC artwork */
5883 if (element == EL_PLAYER_3 ||
5884 element == EL_PLAYER_4)
5887 if (g_em->bitmap != debug_bitmap ||
5888 g_em->src_x != debug_src_x ||
5889 g_em->src_y != debug_src_y)
5891 static int last_i = -1;
5899 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5900 p, i, element, element_info[element].token_name,
5901 element_action_info[effective_action].suffix, direction);
5903 if (element != effective_element)
5904 printf(" [%d ('%s')]",
5906 element_info[effective_element].token_name);
5910 if (g_em->bitmap != debug_bitmap)
5911 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5912 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5914 if (g_em->src_x != debug_src_x ||
5915 g_em->src_y != debug_src_y)
5916 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5918 g_em->src_x, g_em->src_y,
5919 g_em->src_x / 32, g_em->src_y / 32,
5920 debug_src_x, debug_src_y,
5921 debug_src_x / 32, debug_src_y / 32);
5923 num_em_gfx_errors++;
5933 printf("::: [%d errors found]\n", num_em_gfx_errors);
5939 void PlayMenuSound()
5941 int sound = menu.sound[game_status];
5943 if (sound == SND_UNDEFINED)
5946 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5947 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5950 if (IS_LOOP_SOUND(sound))
5951 PlaySoundLoop(sound);
5956 void PlayMenuSoundStereo(int sound, int stereo_position)
5958 if (sound == SND_UNDEFINED)
5961 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5962 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5965 if (IS_LOOP_SOUND(sound))
5966 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
5968 PlaySoundStereo(sound, stereo_position);
5971 void PlayMenuSoundIfLoop()
5973 int sound = menu.sound[game_status];
5975 if (sound == SND_UNDEFINED)
5978 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5979 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5982 if (IS_LOOP_SOUND(sound))
5983 PlaySoundLoop(sound);
5986 void PlayMenuMusic()
5988 int music = menu.music[game_status];
5990 if (music == MUS_UNDEFINED)
5996 void ToggleFullscreenIfNeeded()
5998 if (setup.fullscreen != video.fullscreen_enabled ||
5999 setup.fullscreen_mode != video.fullscreen_mode_current)
6001 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6003 /* save backbuffer content which gets lost when toggling fullscreen mode */
6004 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6006 if (setup.fullscreen && video.fullscreen_enabled)
6008 /* keep fullscreen mode, but change screen mode */
6009 video.fullscreen_mode_current = setup.fullscreen_mode;
6010 video.fullscreen_enabled = FALSE;
6013 /* toggle fullscreen */
6014 ChangeVideoModeIfNeeded(setup.fullscreen);
6015 setup.fullscreen = video.fullscreen_enabled;
6017 /* restore backbuffer content from temporary backbuffer backup bitmap */
6018 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6020 FreeBitmap(tmp_backbuffer);
6022 redraw_mask = REDRAW_ALL;