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 */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
202 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
205 void DrawMaskedBorder_FIELD()
207 if (game_status >= GAME_MODE_TITLE &&
208 game_status <= GAME_MODE_PLAYING &&
209 border.draw_masked[game_status])
210 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
213 void DrawMaskedBorder_DOOR_1()
215 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
216 (game_status != GAME_MODE_EDITOR ||
217 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
218 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
221 void DrawMaskedBorder_DOOR_2()
223 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
224 game_status != GAME_MODE_EDITOR)
225 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
228 void DrawMaskedBorder_DOOR_3()
230 /* currently not available */
233 void DrawMaskedBorder_ALL()
235 DrawMaskedBorder_FIELD();
236 DrawMaskedBorder_DOOR_1();
237 DrawMaskedBorder_DOOR_2();
238 DrawMaskedBorder_DOOR_3();
241 void DrawMaskedBorder(int redraw_mask)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
264 redraw_mask &= ~REDRAW_MAIN;
266 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
267 redraw_mask |= REDRAW_FIELD;
269 if (redraw_mask & REDRAW_FIELD)
270 redraw_mask &= ~REDRAW_TILES;
272 if (redraw_mask == REDRAW_NONE)
275 if (redraw_mask & REDRAW_TILES &&
276 game_status == GAME_MODE_PLAYING &&
277 border.draw_masked[game_status])
278 redraw_mask |= REDRAW_FIELD;
280 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
282 static boolean last_frame_skipped = FALSE;
283 boolean skip_even_when_not_scrolling = TRUE;
284 boolean just_scrolling = (ScreenMovDir != 0);
285 boolean verbose = FALSE;
287 if (global.fps_slowdown_factor > 1 &&
288 (FrameCounter % global.fps_slowdown_factor) &&
289 (just_scrolling || skip_even_when_not_scrolling))
291 redraw_mask &= ~REDRAW_MAIN;
293 last_frame_skipped = TRUE;
296 printf("FRAME SKIPPED\n");
300 if (last_frame_skipped)
301 redraw_mask |= REDRAW_FIELD;
303 last_frame_skipped = FALSE;
306 printf("frame not skipped\n");
310 /* synchronize X11 graphics at this point; if we would synchronize the
311 display immediately after the buffer switching (after the XFlush),
312 this could mean that we have to wait for the graphics to complete,
313 although we could go on doing calculations for the next frame */
318 DrawMaskedBorder(redraw_mask);
321 if (redraw_mask & REDRAW_ALL)
324 DrawMaskedBorder(REDRAW_ALL);
326 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
328 redraw_mask = REDRAW_NONE;
331 if (redraw_mask & REDRAW_FIELD)
333 if (game_status != GAME_MODE_PLAYING ||
334 redraw_mask & REDRAW_FROM_BACKBUFFER)
337 DrawMaskedBorder(REDRAW_FIELD);
339 BlitBitmap(backbuffer, window,
340 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
344 int fx = FX, fy = FY;
346 if (setup.soft_scrolling)
348 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
349 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
352 if (setup.soft_scrolling ||
353 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
354 ABS(ScreenMovPos) == ScrollStepSize ||
355 redraw_tiles > REDRAWTILES_THRESHOLD)
358 if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
360 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
362 DrawMaskedBorder(REDRAW_FIELD);
363 BlitBitmap(backbuffer, window,
364 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
368 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
370 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
375 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
377 (setup.soft_scrolling ?
378 "setup.soft_scrolling" :
379 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
380 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
381 ABS(ScreenGfxPos) == ScrollStepSize ?
382 "ABS(ScreenGfxPos) == ScrollStepSize" :
383 "redraw_tiles > REDRAWTILES_THRESHOLD"));
389 redraw_mask &= ~REDRAW_MAIN;
392 if (redraw_mask & REDRAW_DOORS)
394 if (redraw_mask & REDRAW_DOOR_1)
397 DrawMaskedBorder(REDRAW_DOOR_1);
399 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
405 DrawMaskedBorder(REDRAW_DOOR_2);
407 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
410 if (redraw_mask & REDRAW_DOOR_3)
413 DrawMaskedBorder(REDRAW_DOOR_3);
415 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
418 redraw_mask &= ~REDRAW_DOORS;
421 if (redraw_mask & REDRAW_MICROLEVEL)
423 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
424 SX, SY + 10 * TILEY);
426 redraw_mask &= ~REDRAW_MICROLEVEL;
429 if (redraw_mask & REDRAW_TILES)
431 for (x = 0; x < SCR_FIELDX; x++)
432 for (y = 0 ; y < SCR_FIELDY; y++)
433 if (redraw[redraw_x1 + x][redraw_y1 + y])
434 BlitBitmap(buffer, window,
435 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
436 SX + x * TILEX, SY + y * TILEY);
439 if (redraw_mask & REDRAW_FPS) /* display frames per second */
444 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
445 if (!global.fps_slowdown)
448 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
449 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
454 for (x = 0; x < MAX_BUF_XSIZE; x++)
455 for (y = 0; y < MAX_BUF_YSIZE; y++)
458 redraw_mask = REDRAW_NONE;
464 long fading_delay = 300;
466 if (setup.fading && (redraw_mask & REDRAW_FIELD))
473 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
476 for (i = 0; i < 2 * FULL_SYSIZE; i++)
478 for (y = 0; y < FULL_SYSIZE; y++)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
489 for (i = 1; i < FULL_SYSIZE; i+=2)
490 BlitBitmap(backbuffer, window,
491 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
497 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
498 BlitBitmapMasked(backbuffer, window,
499 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
504 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
505 BlitBitmapMasked(backbuffer, window,
506 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
511 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
512 BlitBitmapMasked(backbuffer, window,
513 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
518 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
519 BlitBitmapMasked(backbuffer, window,
520 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
525 redraw_mask &= ~REDRAW_MAIN;
532 void FadeExt(int fade_mask, int fade_mode)
534 void (*draw_border_function)(void) = NULL;
535 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
536 int fade_delay = menu.fade_delay;
537 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
538 int x, y, width, height;
540 if (fade_mask & REDRAW_FIELD)
545 height = FULL_SYSIZE;
547 draw_border_function = DrawMaskedBorder_FIELD;
549 else /* REDRAW_ALL */
557 redraw_mask |= fade_mask;
559 if (!setup.fade_screens || fade_delay == 0)
561 if (fade_mode == FADE_MODE_FADE_OUT)
562 ClearRectangle(backbuffer, x, y, width, height);
569 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
570 draw_border_function);
572 redraw_mask &= ~fade_mask;
575 void FadeIn(int fade_mask)
577 FadeExt(fade_mask, FADE_MODE_FADE_IN);
580 void FadeOut(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
585 void FadeCross(int fade_mask)
587 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
590 void FadeCrossSaveBackbuffer()
592 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
595 void SetMainBackgroundImageIfDefined(int graphic)
597 if (graphic_info[graphic].bitmap)
598 SetMainBackgroundImage(graphic);
601 void SetMainBackgroundImage(int graphic)
603 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
604 graphic_info[graphic].bitmap ?
605 graphic_info[graphic].bitmap :
606 graphic_info[IMG_BACKGROUND].bitmap);
609 void SetDoorBackgroundImage(int graphic)
611 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
612 graphic_info[graphic].bitmap ?
613 graphic_info[graphic].bitmap :
614 graphic_info[IMG_BACKGROUND].bitmap);
617 void SetPanelBackground()
619 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
620 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
622 SetDoorBackgroundBitmap(bitmap_db_panel);
625 void DrawBackground(int dst_x, int dst_y, int width, int height)
628 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
630 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
633 redraw_mask |= REDRAW_FIELD;
638 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
640 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
642 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
643 SetDrawtoField(DRAW_BUFFERED);
646 SetDrawtoField(DRAW_BACKBUFFER);
648 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
650 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
651 SetDrawtoField(DRAW_DIRECT);
655 void MarkTileDirty(int x, int y)
657 int xx = redraw_x1 + x;
658 int yy = redraw_y1 + y;
663 redraw[xx][yy] = TRUE;
664 redraw_mask |= REDRAW_TILES;
667 void SetBorderElement()
671 BorderElement = EL_EMPTY;
673 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
675 for (x = 0; x < lev_fieldx; x++)
677 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
678 BorderElement = EL_STEELWALL;
680 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
686 void SetRandomAnimationValue(int x, int y)
688 gfx.anim_random_frame = GfxRandom[x][y];
691 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
693 /* animation synchronized with global frame counter, not move position */
694 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
695 sync_frame = FrameCounter;
697 return getAnimationFrame(graphic_info[graphic].anim_frames,
698 graphic_info[graphic].anim_delay,
699 graphic_info[graphic].anim_mode,
700 graphic_info[graphic].anim_start_frame,
704 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
705 int *x, int *y, boolean get_backside)
707 struct GraphicInfo *g = &graphic_info[graphic];
708 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
709 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
713 if (g->offset_y == 0) /* frames are ordered horizontally */
715 int max_width = g->anim_frames_per_line * g->width;
716 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
718 *x = pos % max_width;
719 *y = src_y % g->height + pos / max_width * g->height;
721 else if (g->offset_x == 0) /* frames are ordered vertically */
723 int max_height = g->anim_frames_per_line * g->height;
724 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
726 *x = src_x % g->width + pos / max_height * g->width;
727 *y = pos % max_height;
729 else /* frames are ordered diagonally */
731 *x = src_x + frame * g->offset_x;
732 *y = src_y + frame * g->offset_y;
736 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
738 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
741 void DrawGraphic(int x, int y, int graphic, int frame)
744 if (!IN_SCR_FIELD(x, y))
746 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
747 printf("DrawGraphic(): This should never happen!\n");
752 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
756 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
762 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
763 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
766 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
769 if (!IN_SCR_FIELD(x, y))
771 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
772 printf("DrawGraphicThruMask(): This should never happen!\n");
777 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
782 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
788 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
790 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
791 dst_x - src_x, dst_y - src_y);
792 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
795 void DrawMiniGraphic(int x, int y, int graphic)
797 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
798 MarkTileDirty(x / 2, y / 2);
801 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
803 struct GraphicInfo *g = &graphic_info[graphic];
805 int mini_starty = g->bitmap->height * 2 / 3;
808 *x = mini_startx + g->src_x / 2;
809 *y = mini_starty + g->src_y / 2;
812 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
817 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
818 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
821 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
822 int graphic, int frame,
823 int cut_mode, int mask_mode)
828 int width = TILEX, height = TILEY;
831 if (dx || dy) /* shifted graphic */
833 if (x < BX1) /* object enters playfield from the left */
840 else if (x > BX2) /* object enters playfield from the right */
846 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
852 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
854 else if (dx) /* general horizontal movement */
855 MarkTileDirty(x + SIGN(dx), y);
857 if (y < BY1) /* object enters playfield from the top */
859 if (cut_mode==CUT_BELOW) /* object completely above top border */
867 else if (y > BY2) /* object enters playfield from the bottom */
873 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
879 else if (dy > 0 && cut_mode == CUT_ABOVE)
881 if (y == BY2) /* object completely above bottom border */
887 MarkTileDirty(x, y + 1);
888 } /* object leaves playfield to the bottom */
889 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
891 else if (dy) /* general vertical movement */
892 MarkTileDirty(x, y + SIGN(dy));
896 if (!IN_SCR_FIELD(x, y))
898 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
899 printf("DrawGraphicShifted(): This should never happen!\n");
904 if (width > 0 && height > 0)
906 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
911 dst_x = FX + x * TILEX + dx;
912 dst_y = FY + y * TILEY + dy;
914 if (mask_mode == USE_MASKING)
916 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
917 dst_x - src_x, dst_y - src_y);
918 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
922 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
929 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
930 int graphic, int frame,
931 int cut_mode, int mask_mode)
936 int width = TILEX, height = TILEY;
939 int x2 = x + SIGN(dx);
940 int y2 = y + SIGN(dy);
941 int anim_frames = graphic_info[graphic].anim_frames;
942 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
943 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
944 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
946 /* re-calculate animation frame for two-tile movement animation */
947 frame = getGraphicAnimationFrame(graphic, sync_frame);
949 /* check if movement start graphic inside screen area and should be drawn */
950 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
952 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
954 dst_x = FX + x1 * TILEX;
955 dst_y = FY + y1 * TILEY;
957 if (mask_mode == USE_MASKING)
959 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
960 dst_x - src_x, dst_y - src_y);
961 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
965 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
968 MarkTileDirty(x1, y1);
971 /* check if movement end graphic inside screen area and should be drawn */
972 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
974 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
976 dst_x = FX + x2 * TILEX;
977 dst_y = FY + y2 * TILEY;
979 if (mask_mode == USE_MASKING)
981 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
982 dst_x - src_x, dst_y - src_y);
983 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
987 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
990 MarkTileDirty(x2, y2);
994 static void DrawGraphicShifted(int x, int y, int dx, int dy,
995 int graphic, int frame,
996 int cut_mode, int mask_mode)
1000 DrawGraphic(x, y, graphic, frame);
1005 if (graphic_info[graphic].double_movement) /* EM style movement images */
1006 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1008 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1011 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1012 int frame, int cut_mode)
1014 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1017 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1018 int cut_mode, int mask_mode)
1020 int lx = LEVELX(x), ly = LEVELY(y);
1024 if (IN_LEV_FIELD(lx, ly))
1026 SetRandomAnimationValue(lx, ly);
1028 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1029 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1031 /* do not use double (EM style) movement graphic when not moving */
1032 if (graphic_info[graphic].double_movement && !dx && !dy)
1034 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1035 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1038 else /* border element */
1040 graphic = el2img(element);
1041 frame = getGraphicAnimationFrame(graphic, -1);
1044 if (element == EL_EXPANDABLE_WALL)
1046 boolean left_stopped = FALSE, right_stopped = FALSE;
1048 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1049 left_stopped = TRUE;
1050 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1051 right_stopped = TRUE;
1053 if (left_stopped && right_stopped)
1055 else if (left_stopped)
1057 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1058 frame = graphic_info[graphic].anim_frames - 1;
1060 else if (right_stopped)
1062 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1063 frame = graphic_info[graphic].anim_frames - 1;
1068 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1069 else if (mask_mode == USE_MASKING)
1070 DrawGraphicThruMask(x, y, graphic, frame);
1072 DrawGraphic(x, y, graphic, frame);
1075 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1076 int cut_mode, int mask_mode)
1078 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1079 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1080 cut_mode, mask_mode);
1083 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1086 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1089 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1092 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1095 void DrawLevelElementThruMask(int x, int y, int element)
1097 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1100 void DrawLevelFieldThruMask(int x, int y)
1102 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1105 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1109 int sx = SCREENX(x), sy = SCREENY(y);
1111 int width, height, cx, cy, i;
1112 int crumbled_border_size = graphic_info[graphic].border_size;
1113 static int xy[4][2] =
1121 if (!IN_LEV_FIELD(x, y))
1124 element = TILE_GFX_ELEMENT(x, y);
1126 /* crumble field itself */
1127 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1129 if (!IN_SCR_FIELD(sx, sy))
1132 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1134 for (i = 0; i < 4; i++)
1136 int xx = x + xy[i][0];
1137 int yy = y + xy[i][1];
1139 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1142 /* check if neighbour field is of same type */
1143 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1146 if (i == 1 || i == 2)
1148 width = crumbled_border_size;
1150 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1156 height = crumbled_border_size;
1158 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1161 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1162 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1165 MarkTileDirty(sx, sy);
1167 else /* crumble neighbour fields */
1169 for (i = 0; i < 4; i++)
1171 int xx = x + xy[i][0];
1172 int yy = y + xy[i][1];
1173 int sxx = sx + xy[i][0];
1174 int syy = sy + xy[i][1];
1176 if (!IN_LEV_FIELD(xx, yy) ||
1177 !IN_SCR_FIELD(sxx, syy) ||
1181 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1184 element = TILE_GFX_ELEMENT(xx, yy);
1186 if (!GFX_CRUMBLED(element))
1189 graphic = el_act2crm(element, ACTION_DEFAULT);
1190 crumbled_border_size = graphic_info[graphic].border_size;
1192 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1194 if (i == 1 || i == 2)
1196 width = crumbled_border_size;
1198 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1204 height = crumbled_border_size;
1206 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1209 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1210 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1212 MarkTileDirty(sxx, syy);
1217 void DrawLevelFieldCrumbledSand(int x, int y)
1221 if (!IN_LEV_FIELD(x, y))
1225 /* !!! CHECK THIS !!! */
1228 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1229 GFX_CRUMBLED(GfxElement[x][y]))
1232 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1233 GfxElement[x][y] != EL_UNDEFINED &&
1234 GFX_CRUMBLED(GfxElement[x][y]))
1236 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1243 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1245 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1248 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1251 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1254 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1255 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1256 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1257 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1258 int sx = SCREENX(x), sy = SCREENY(y);
1260 DrawGraphic(sx, sy, graphic1, frame1);
1261 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1264 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1266 int sx = SCREENX(x), sy = SCREENY(y);
1267 static int xy[4][2] =
1276 for (i = 0; i < 4; i++)
1278 int xx = x + xy[i][0];
1279 int yy = y + xy[i][1];
1280 int sxx = sx + xy[i][0];
1281 int syy = sy + xy[i][1];
1283 if (!IN_LEV_FIELD(xx, yy) ||
1284 !IN_SCR_FIELD(sxx, syy) ||
1285 !GFX_CRUMBLED(Feld[xx][yy]) ||
1289 DrawLevelField(xx, yy);
1293 static int getBorderElement(int x, int y)
1297 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1298 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1299 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1300 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1301 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1302 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1303 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1305 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1306 int steel_position = (x == -1 && y == -1 ? 0 :
1307 x == lev_fieldx && y == -1 ? 1 :
1308 x == -1 && y == lev_fieldy ? 2 :
1309 x == lev_fieldx && y == lev_fieldy ? 3 :
1310 x == -1 || x == lev_fieldx ? 4 :
1311 y == -1 || y == lev_fieldy ? 5 : 6);
1313 return border[steel_position][steel_type];
1316 void DrawScreenElement(int x, int y, int element)
1318 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1319 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1322 void DrawLevelElement(int x, int y, int element)
1324 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1325 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1328 void DrawScreenField(int x, int y)
1330 int lx = LEVELX(x), ly = LEVELY(y);
1331 int element, content;
1333 if (!IN_LEV_FIELD(lx, ly))
1335 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1338 element = getBorderElement(lx, ly);
1340 DrawScreenElement(x, y, element);
1344 element = Feld[lx][ly];
1345 content = Store[lx][ly];
1347 if (IS_MOVING(lx, ly))
1349 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1350 boolean cut_mode = NO_CUTTING;
1352 if (element == EL_QUICKSAND_EMPTYING ||
1353 element == EL_MAGIC_WALL_EMPTYING ||
1354 element == EL_BD_MAGIC_WALL_EMPTYING ||
1355 element == EL_AMOEBA_DROPPING)
1356 cut_mode = CUT_ABOVE;
1357 else if (element == EL_QUICKSAND_FILLING ||
1358 element == EL_MAGIC_WALL_FILLING ||
1359 element == EL_BD_MAGIC_WALL_FILLING)
1360 cut_mode = CUT_BELOW;
1362 if (cut_mode == CUT_ABOVE)
1363 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1365 DrawScreenElement(x, y, EL_EMPTY);
1368 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1369 else if (cut_mode == NO_CUTTING)
1370 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1372 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1374 if (content == EL_ACID)
1376 int dir = MovDir[lx][ly];
1377 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1378 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1380 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1383 else if (IS_BLOCKED(lx, ly))
1388 boolean cut_mode = NO_CUTTING;
1389 int element_old, content_old;
1391 Blocked2Moving(lx, ly, &oldx, &oldy);
1394 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1395 MovDir[oldx][oldy] == MV_RIGHT);
1397 element_old = Feld[oldx][oldy];
1398 content_old = Store[oldx][oldy];
1400 if (element_old == EL_QUICKSAND_EMPTYING ||
1401 element_old == EL_MAGIC_WALL_EMPTYING ||
1402 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1403 element_old == EL_AMOEBA_DROPPING)
1404 cut_mode = CUT_ABOVE;
1406 DrawScreenElement(x, y, EL_EMPTY);
1409 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1411 else if (cut_mode == NO_CUTTING)
1412 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1415 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1418 else if (IS_DRAWABLE(element))
1419 DrawScreenElement(x, y, element);
1421 DrawScreenElement(x, y, EL_EMPTY);
1424 void DrawLevelField(int x, int y)
1426 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1427 DrawScreenField(SCREENX(x), SCREENY(y));
1428 else if (IS_MOVING(x, y))
1432 Moving2Blocked(x, y, &newx, &newy);
1433 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1434 DrawScreenField(SCREENX(newx), SCREENY(newy));
1436 else if (IS_BLOCKED(x, y))
1440 Blocked2Moving(x, y, &oldx, &oldy);
1441 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1442 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1446 void DrawMiniElement(int x, int y, int element)
1450 graphic = el2edimg(element);
1451 DrawMiniGraphic(x, y, graphic);
1454 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1456 int x = sx + scroll_x, y = sy + scroll_y;
1458 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1459 DrawMiniElement(sx, sy, EL_EMPTY);
1460 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1461 DrawMiniElement(sx, sy, Feld[x][y]);
1463 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1466 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1467 int x, int y, int xsize, int ysize, int font_nr)
1469 int font_width = getFontWidth(font_nr);
1470 int font_height = getFontHeight(font_nr);
1471 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1474 int dst_x = SX + startx + x * font_width;
1475 int dst_y = SY + starty + y * font_height;
1476 int width = graphic_info[graphic].width;
1477 int height = graphic_info[graphic].height;
1478 int inner_width = MAX(width - 2 * font_width, font_width);
1479 int inner_height = MAX(height - 2 * font_height, font_height);
1480 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1481 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1482 boolean draw_masked = graphic_info[graphic].draw_masked;
1484 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1486 if (src_bitmap == NULL || width < font_width || height < font_height)
1488 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1492 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1493 inner_sx + (x - 1) * font_width % inner_width);
1494 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1495 inner_sy + (y - 1) * font_height % inner_height);
1499 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1500 dst_x - src_x, dst_y - src_y);
1501 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1505 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1509 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1511 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1512 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1513 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1514 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1515 boolean no_delay = (tape.warp_forward);
1516 unsigned long anim_delay = 0;
1517 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1518 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1519 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1520 int font_width = getFontWidth(font_nr);
1521 int font_height = getFontHeight(font_nr);
1522 int max_xsize = level.envelope[envelope_nr].xsize;
1523 int max_ysize = level.envelope[envelope_nr].ysize;
1524 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1525 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1526 int xend = max_xsize;
1527 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1528 int xstep = (xstart < xend ? 1 : 0);
1529 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1532 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1534 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1535 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1536 int sx = (SXSIZE - xsize * font_width) / 2;
1537 int sy = (SYSIZE - ysize * font_height) / 2;
1540 SetDrawtoField(DRAW_BUFFERED);
1542 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1544 SetDrawtoField(DRAW_BACKBUFFER);
1546 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1547 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1549 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1550 level.envelope[envelope_nr].text, font_nr, max_xsize,
1551 xsize - 2, ysize - 2, mask_mode);
1553 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1556 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1560 void ShowEnvelope(int envelope_nr)
1562 int element = EL_ENVELOPE_1 + envelope_nr;
1563 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1564 int sound_opening = element_info[element].sound[ACTION_OPENING];
1565 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1566 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1567 boolean no_delay = (tape.warp_forward);
1568 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1569 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1570 int anim_mode = graphic_info[graphic].anim_mode;
1571 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1572 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1574 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1576 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1578 if (anim_mode == ANIM_DEFAULT)
1579 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1581 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1584 Delay(wait_delay_value);
1586 WaitForEventToContinue();
1588 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1590 if (anim_mode != ANIM_NONE)
1591 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1593 if (anim_mode == ANIM_DEFAULT)
1594 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1596 game.envelope_active = FALSE;
1598 SetDrawtoField(DRAW_BUFFERED);
1600 redraw_mask |= REDRAW_FIELD;
1604 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1609 int width_mult, width_div;
1610 int height_mult, height_div;
1618 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1619 5 - log_2(tilesize));
1620 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1621 int width_mult = offset_calc[offset_calc_pos].width_mult;
1622 int width_div = offset_calc[offset_calc_pos].width_div;
1623 int height_mult = offset_calc[offset_calc_pos].height_mult;
1624 int height_div = offset_calc[offset_calc_pos].height_div;
1625 int mini_startx = src_bitmap->width * width_mult / width_div;
1626 int mini_starty = src_bitmap->height * height_mult / height_div;
1627 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1628 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1630 *bitmap = src_bitmap;
1635 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1639 int graphic = el2preimg(element);
1641 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1642 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1649 SetDrawBackgroundMask(REDRAW_NONE);
1652 for (x = BX1; x <= BX2; x++)
1653 for (y = BY1; y <= BY2; y++)
1654 DrawScreenField(x, y);
1656 redraw_mask |= REDRAW_FIELD;
1659 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1663 for (x = 0; x < size_x; x++)
1664 for (y = 0; y < size_y; y++)
1665 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1667 redraw_mask |= REDRAW_FIELD;
1670 static void DrawPreviewLevelExt(int from_x, int from_y)
1672 boolean show_level_border = (BorderElement != EL_EMPTY);
1673 int dst_x = preview.x;
1674 int dst_y = preview.y;
1675 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1676 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1677 int tile_size = preview.tile_size;
1678 int preview_width = preview.xsize * tile_size;
1679 int preview_height = preview.ysize * tile_size;
1680 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1681 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1684 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1686 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1687 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1689 for (x = 0; x < real_preview_xsize; x++)
1691 for (y = 0; y < real_preview_ysize; y++)
1693 int lx = from_x + x + (show_level_border ? -1 : 0);
1694 int ly = from_y + y + (show_level_border ? -1 : 0);
1695 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1696 getBorderElement(lx, ly));
1698 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1699 element, tile_size);
1703 redraw_mask |= REDRAW_MICROLEVEL;
1706 #define MICROLABEL_EMPTY 0
1707 #define MICROLABEL_LEVEL_NAME 1
1708 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1709 #define MICROLABEL_LEVEL_AUTHOR 3
1710 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1711 #define MICROLABEL_IMPORTED_FROM 5
1712 #define MICROLABEL_IMPORTED_BY_HEAD 6
1713 #define MICROLABEL_IMPORTED_BY 7
1715 static void DrawPreviewLevelLabelExt(int mode)
1717 char label_text[MAX_OUTPUT_LINESIZE + 1];
1718 int max_len_label_text;
1719 int font_nr = FONT_TEXT_2;
1722 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1723 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1724 mode == MICROLABEL_IMPORTED_BY_HEAD)
1725 font_nr = FONT_TEXT_3;
1727 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1729 for (i = 0; i < max_len_label_text; i++)
1730 label_text[i] = ' ';
1731 label_text[max_len_label_text] = '\0';
1733 if (strlen(label_text) > 0)
1735 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1736 int lypos = MICROLABEL2_YPOS;
1738 DrawText(lxpos, lypos, label_text, font_nr);
1742 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1743 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1744 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1745 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1746 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1747 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1748 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1749 max_len_label_text);
1750 label_text[max_len_label_text] = '\0';
1752 if (strlen(label_text) > 0)
1754 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1755 int lypos = MICROLABEL2_YPOS;
1757 DrawText(lxpos, lypos, label_text, font_nr);
1760 redraw_mask |= REDRAW_MICROLEVEL;
1763 void DrawPreviewLevel(boolean restart)
1765 static unsigned long scroll_delay = 0;
1766 static unsigned long label_delay = 0;
1767 static int from_x, from_y, scroll_direction;
1768 static int label_state, label_counter;
1769 unsigned long scroll_delay_value = preview.step_delay;
1770 boolean show_level_border = (BorderElement != EL_EMPTY);
1771 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1772 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1773 int last_game_status = game_status; /* save current game status */
1775 /* force PREVIEW font on preview level */
1776 game_status = GAME_MODE_PSEUDO_PREVIEW;
1780 from_x = from_y = 0;
1781 scroll_direction = MV_RIGHT;
1785 DrawPreviewLevelExt(from_x, from_y);
1786 DrawPreviewLevelLabelExt(label_state);
1788 /* initialize delay counters */
1789 DelayReached(&scroll_delay, 0);
1790 DelayReached(&label_delay, 0);
1792 if (leveldir_current->name)
1794 char label_text[MAX_OUTPUT_LINESIZE + 1];
1795 int font_nr = FONT_TEXT_1;
1796 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1799 strncpy(label_text, leveldir_current->name, max_len_label_text);
1800 label_text[max_len_label_text] = '\0';
1802 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1803 lypos = SY + MICROLABEL1_YPOS;
1805 DrawText(lxpos, lypos, label_text, font_nr);
1808 game_status = last_game_status; /* restore current game status */
1813 /* scroll preview level, if needed */
1814 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1815 DelayReached(&scroll_delay, scroll_delay_value))
1817 switch (scroll_direction)
1822 from_x -= preview.step_offset;
1823 from_x = (from_x < 0 ? 0 : from_x);
1826 scroll_direction = MV_UP;
1830 if (from_x < level_xsize - preview.xsize)
1832 from_x += preview.step_offset;
1833 from_x = (from_x > level_xsize - preview.xsize ?
1834 level_xsize - preview.xsize : from_x);
1837 scroll_direction = MV_DOWN;
1843 from_y -= preview.step_offset;
1844 from_y = (from_y < 0 ? 0 : from_y);
1847 scroll_direction = MV_RIGHT;
1851 if (from_y < level_ysize - preview.ysize)
1853 from_y += preview.step_offset;
1854 from_y = (from_y > level_ysize - preview.ysize ?
1855 level_ysize - preview.ysize : from_y);
1858 scroll_direction = MV_LEFT;
1865 DrawPreviewLevelExt(from_x, from_y);
1868 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1869 /* redraw micro level label, if needed */
1870 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1871 !strEqual(level.author, ANONYMOUS_NAME) &&
1872 !strEqual(level.author, leveldir_current->name) &&
1873 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1875 int max_label_counter = 23;
1877 if (leveldir_current->imported_from != NULL &&
1878 strlen(leveldir_current->imported_from) > 0)
1879 max_label_counter += 14;
1880 if (leveldir_current->imported_by != NULL &&
1881 strlen(leveldir_current->imported_by) > 0)
1882 max_label_counter += 14;
1884 label_counter = (label_counter + 1) % max_label_counter;
1885 label_state = (label_counter >= 0 && label_counter <= 7 ?
1886 MICROLABEL_LEVEL_NAME :
1887 label_counter >= 9 && label_counter <= 12 ?
1888 MICROLABEL_LEVEL_AUTHOR_HEAD :
1889 label_counter >= 14 && label_counter <= 21 ?
1890 MICROLABEL_LEVEL_AUTHOR :
1891 label_counter >= 23 && label_counter <= 26 ?
1892 MICROLABEL_IMPORTED_FROM_HEAD :
1893 label_counter >= 28 && label_counter <= 35 ?
1894 MICROLABEL_IMPORTED_FROM :
1895 label_counter >= 37 && label_counter <= 40 ?
1896 MICROLABEL_IMPORTED_BY_HEAD :
1897 label_counter >= 42 && label_counter <= 49 ?
1898 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1900 if (leveldir_current->imported_from == NULL &&
1901 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1902 label_state == MICROLABEL_IMPORTED_FROM))
1903 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1904 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1906 DrawPreviewLevelLabelExt(label_state);
1909 game_status = last_game_status; /* restore current game status */
1912 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1913 int graphic, int sync_frame, int mask_mode)
1915 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1917 if (mask_mode == USE_MASKING)
1918 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1920 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1923 inline void DrawGraphicAnimation(int x, int y, int graphic)
1925 int lx = LEVELX(x), ly = LEVELY(y);
1927 if (!IN_SCR_FIELD(x, y))
1930 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1931 graphic, GfxFrame[lx][ly], NO_MASKING);
1932 MarkTileDirty(x, y);
1935 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1937 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1940 void DrawLevelElementAnimation(int x, int y, int element)
1942 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1944 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1947 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1949 int sx = SCREENX(x), sy = SCREENY(y);
1951 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1954 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1957 DrawGraphicAnimation(sx, sy, graphic);
1960 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1961 DrawLevelFieldCrumbledSand(x, y);
1963 if (GFX_CRUMBLED(Feld[x][y]))
1964 DrawLevelFieldCrumbledSand(x, y);
1968 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1970 int sx = SCREENX(x), sy = SCREENY(y);
1973 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1976 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1978 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1981 DrawGraphicAnimation(sx, sy, graphic);
1983 if (GFX_CRUMBLED(element))
1984 DrawLevelFieldCrumbledSand(x, y);
1987 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1989 if (player->use_murphy)
1991 /* this works only because currently only one player can be "murphy" ... */
1992 static int last_horizontal_dir = MV_LEFT;
1993 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1995 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1996 last_horizontal_dir = move_dir;
1998 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2000 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2002 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2008 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2011 static boolean equalGraphics(int graphic1, int graphic2)
2013 struct GraphicInfo *g1 = &graphic_info[graphic1];
2014 struct GraphicInfo *g2 = &graphic_info[graphic2];
2016 return (g1->bitmap == g2->bitmap &&
2017 g1->src_x == g2->src_x &&
2018 g1->src_y == g2->src_y &&
2019 g1->anim_frames == g2->anim_frames &&
2020 g1->anim_delay == g2->anim_delay &&
2021 g1->anim_mode == g2->anim_mode);
2024 void DrawAllPlayers()
2028 for (i = 0; i < MAX_PLAYERS; i++)
2029 if (stored_player[i].active)
2030 DrawPlayer(&stored_player[i]);
2033 void DrawPlayerField(int x, int y)
2035 if (!IS_PLAYER(x, y))
2038 DrawPlayer(PLAYERINFO(x, y));
2041 void DrawPlayer(struct PlayerInfo *player)
2043 int jx = player->jx;
2044 int jy = player->jy;
2045 int move_dir = player->MovDir;
2046 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2047 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2048 int last_jx = (player->is_moving ? jx - dx : jx);
2049 int last_jy = (player->is_moving ? jy - dy : jy);
2050 int next_jx = jx + dx;
2051 int next_jy = jy + dy;
2052 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2053 boolean player_is_opaque = FALSE;
2054 int sx = SCREENX(jx), sy = SCREENY(jy);
2055 int sxx = 0, syy = 0;
2056 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2058 int action = ACTION_DEFAULT;
2059 int last_player_graphic = getPlayerGraphic(player, move_dir);
2060 int last_player_frame = player->Frame;
2063 /* GfxElement[][] is set to the element the player is digging or collecting;
2064 remove also for off-screen player if the player is not moving anymore */
2065 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2066 GfxElement[jx][jy] = EL_UNDEFINED;
2068 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2072 if (!IN_LEV_FIELD(jx, jy))
2074 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2075 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2076 printf("DrawPlayerField(): This should never happen!\n");
2081 if (element == EL_EXPLOSION)
2084 action = (player->is_pushing ? ACTION_PUSHING :
2085 player->is_digging ? ACTION_DIGGING :
2086 player->is_collecting ? ACTION_COLLECTING :
2087 player->is_moving ? ACTION_MOVING :
2088 player->is_snapping ? ACTION_SNAPPING :
2089 player->is_dropping ? ACTION_DROPPING :
2090 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2092 if (player->is_waiting)
2093 move_dir = player->dir_waiting;
2095 InitPlayerGfxAnimation(player, action, move_dir);
2097 /* ----------------------------------------------------------------------- */
2098 /* draw things in the field the player is leaving, if needed */
2099 /* ----------------------------------------------------------------------- */
2101 if (player->is_moving)
2103 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2105 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2107 if (last_element == EL_DYNAMITE_ACTIVE ||
2108 last_element == EL_EM_DYNAMITE_ACTIVE ||
2109 last_element == EL_SP_DISK_RED_ACTIVE)
2110 DrawDynamite(last_jx, last_jy);
2112 DrawLevelFieldThruMask(last_jx, last_jy);
2114 else if (last_element == EL_DYNAMITE_ACTIVE ||
2115 last_element == EL_EM_DYNAMITE_ACTIVE ||
2116 last_element == EL_SP_DISK_RED_ACTIVE)
2117 DrawDynamite(last_jx, last_jy);
2119 /* !!! this is not enough to prevent flickering of players which are
2120 moving next to each others without a free tile between them -- this
2121 can only be solved by drawing all players layer by layer (first the
2122 background, then the foreground etc.) !!! => TODO */
2123 else if (!IS_PLAYER(last_jx, last_jy))
2124 DrawLevelField(last_jx, last_jy);
2127 DrawLevelField(last_jx, last_jy);
2130 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2131 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2134 if (!IN_SCR_FIELD(sx, sy))
2137 if (setup.direct_draw)
2138 SetDrawtoField(DRAW_BUFFERED);
2140 /* ----------------------------------------------------------------------- */
2141 /* draw things behind the player, if needed */
2142 /* ----------------------------------------------------------------------- */
2145 DrawLevelElement(jx, jy, Back[jx][jy]);
2146 else if (IS_ACTIVE_BOMB(element))
2147 DrawLevelElement(jx, jy, EL_EMPTY);
2150 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2152 int old_element = GfxElement[jx][jy];
2153 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2154 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2156 if (GFX_CRUMBLED(old_element))
2157 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2159 DrawGraphic(sx, sy, old_graphic, frame);
2161 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2162 player_is_opaque = TRUE;
2166 GfxElement[jx][jy] = EL_UNDEFINED;
2168 /* make sure that pushed elements are drawn with correct frame rate */
2170 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2172 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2173 GfxFrame[jx][jy] = player->StepFrame;
2175 if (player->is_pushing && player->is_moving)
2176 GfxFrame[jx][jy] = player->StepFrame;
2179 DrawLevelField(jx, jy);
2183 /* ----------------------------------------------------------------------- */
2184 /* draw player himself */
2185 /* ----------------------------------------------------------------------- */
2187 graphic = getPlayerGraphic(player, move_dir);
2189 /* in the case of changed player action or direction, prevent the current
2190 animation frame from being restarted for identical animations */
2191 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2192 player->Frame = last_player_frame;
2194 frame = getGraphicAnimationFrame(graphic, player->Frame);
2198 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2199 sxx = player->GfxPos;
2201 syy = player->GfxPos;
2204 if (!setup.soft_scrolling && ScreenMovPos)
2207 if (player_is_opaque)
2208 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2210 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2212 if (SHIELD_ON(player))
2214 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2215 IMG_SHIELD_NORMAL_ACTIVE);
2216 int frame = getGraphicAnimationFrame(graphic, -1);
2218 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2221 /* ----------------------------------------------------------------------- */
2222 /* draw things the player is pushing, if needed */
2223 /* ----------------------------------------------------------------------- */
2226 printf("::: %d, %d [%d, %d] [%d]\n",
2227 player->is_pushing, player_is_moving, player->GfxAction,
2228 player->is_moving, player_is_moving);
2232 if (player->is_pushing && player->is_moving)
2234 int px = SCREENX(jx), py = SCREENY(jy);
2235 int pxx = (TILEX - ABS(sxx)) * dx;
2236 int pyy = (TILEY - ABS(syy)) * dy;
2237 int gfx_frame = GfxFrame[jx][jy];
2243 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2245 element = Feld[next_jx][next_jy];
2246 gfx_frame = GfxFrame[next_jx][next_jy];
2249 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2252 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2253 frame = getGraphicAnimationFrame(graphic, sync_frame);
2255 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2258 /* draw background element under pushed element (like the Sokoban field) */
2259 if (Back[next_jx][next_jy])
2260 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2262 /* masked drawing is needed for EMC style (double) movement graphics */
2263 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2267 /* ----------------------------------------------------------------------- */
2268 /* draw things in front of player (active dynamite or dynabombs) */
2269 /* ----------------------------------------------------------------------- */
2271 if (IS_ACTIVE_BOMB(element))
2273 graphic = el2img(element);
2274 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2276 if (game.emulation == EMU_SUPAPLEX)
2277 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2279 DrawGraphicThruMask(sx, sy, graphic, frame);
2282 if (player_is_moving && last_element == EL_EXPLOSION)
2284 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2285 GfxElement[last_jx][last_jy] : EL_EMPTY);
2286 int graphic = el_act2img(element, ACTION_EXPLODING);
2287 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2288 int phase = ExplodePhase[last_jx][last_jy] - 1;
2289 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2292 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2295 /* ----------------------------------------------------------------------- */
2296 /* draw elements the player is just walking/passing through/under */
2297 /* ----------------------------------------------------------------------- */
2299 if (player_is_moving)
2301 /* handle the field the player is leaving ... */
2302 if (IS_ACCESSIBLE_INSIDE(last_element))
2303 DrawLevelField(last_jx, last_jy);
2304 else if (IS_ACCESSIBLE_UNDER(last_element))
2305 DrawLevelFieldThruMask(last_jx, last_jy);
2308 /* do not redraw accessible elements if the player is just pushing them */
2309 if (!player_is_moving || !player->is_pushing)
2311 /* ... and the field the player is entering */
2312 if (IS_ACCESSIBLE_INSIDE(element))
2313 DrawLevelField(jx, jy);
2314 else if (IS_ACCESSIBLE_UNDER(element))
2315 DrawLevelFieldThruMask(jx, jy);
2318 if (setup.direct_draw)
2320 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2321 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2322 int x_size = TILEX * (1 + ABS(jx - last_jx));
2323 int y_size = TILEY * (1 + ABS(jy - last_jy));
2325 BlitBitmap(drawto_field, window,
2326 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2327 SetDrawtoField(DRAW_DIRECT);
2330 MarkTileDirty(sx, sy);
2333 /* ------------------------------------------------------------------------- */
2335 void WaitForEventToContinue()
2337 boolean still_wait = TRUE;
2339 /* simulate releasing mouse button over last gadget, if still pressed */
2341 HandleGadgets(-1, -1, 0);
2343 button_status = MB_RELEASED;
2359 case EVENT_BUTTONPRESS:
2360 case EVENT_KEYPRESS:
2364 case EVENT_KEYRELEASE:
2365 ClearPlayerAction();
2369 HandleOtherEvents(&event);
2373 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2380 /* don't eat all CPU time */
2385 #define MAX_REQUEST_LINES 13
2386 #define MAX_REQUEST_LINE_FONT1_LEN 7
2387 #define MAX_REQUEST_LINE_FONT2_LEN 10
2389 boolean Request(char *text, unsigned int req_state)
2391 int mx, my, ty, result = -1;
2392 unsigned int old_door_state;
2393 int last_game_status = game_status; /* save current game status */
2394 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2395 int font_nr = FONT_TEXT_2;
2396 int max_word_len = 0;
2399 for (text_ptr = text; *text_ptr; text_ptr++)
2401 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2403 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2405 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2406 font_nr = FONT_LEVEL_NUMBER;
2412 if (game_status == GAME_MODE_PLAYING &&
2413 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2414 BlitScreenToBitmap_EM(backbuffer);
2416 /* disable deactivated drawing when quick-loading level tape recording */
2417 if (tape.playing && tape.deactivate_display)
2418 TapeDeactivateDisplayOff(TRUE);
2420 SetMouseCursor(CURSOR_DEFAULT);
2422 #if defined(NETWORK_AVALIABLE)
2423 /* pause network game while waiting for request to answer */
2424 if (options.network &&
2425 game_status == GAME_MODE_PLAYING &&
2426 req_state & REQUEST_WAIT_FOR_INPUT)
2427 SendToServer_PausePlaying();
2430 old_door_state = GetDoorState();
2432 /* simulate releasing mouse button over last gadget, if still pressed */
2434 HandleGadgets(-1, -1, 0);
2438 if (old_door_state & DOOR_OPEN_1)
2440 CloseDoor(DOOR_CLOSE_1);
2442 /* save old door content */
2443 BlitBitmap(bitmap_db_door, bitmap_db_door,
2444 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2445 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2449 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2452 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2454 /* clear door drawing field */
2455 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2457 /* force DOOR font on preview level */
2458 game_status = GAME_MODE_PSEUDO_DOOR;
2460 /* write text for request */
2461 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2463 char text_line[max_request_line_len + 1];
2469 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2472 if (!tc || tc == ' ')
2483 strncpy(text_line, text, tl);
2486 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2487 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2488 text_line, font_nr);
2490 text += tl + (tc == ' ' ? 1 : 0);
2493 game_status = last_game_status; /* restore current game status */
2495 if (req_state & REQ_ASK)
2497 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2498 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2500 else if (req_state & REQ_CONFIRM)
2502 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2504 else if (req_state & REQ_PLAYER)
2506 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2507 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2508 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2509 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2512 /* copy request gadgets to door backbuffer */
2513 BlitBitmap(drawto, bitmap_db_door,
2514 DX, DY, DXSIZE, DYSIZE,
2515 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2517 OpenDoor(DOOR_OPEN_1);
2519 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2521 if (game_status == GAME_MODE_PLAYING)
2523 SetPanelBackground();
2524 SetDrawBackgroundMask(REDRAW_DOOR_1);
2528 SetDrawBackgroundMask(REDRAW_FIELD);
2534 if (game_status != GAME_MODE_MAIN)
2537 button_status = MB_RELEASED;
2539 request_gadget_id = -1;
2541 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2553 case EVENT_BUTTONPRESS:
2554 case EVENT_BUTTONRELEASE:
2555 case EVENT_MOTIONNOTIFY:
2557 if (event.type == EVENT_MOTIONNOTIFY)
2559 if (!PointerInWindow(window))
2560 continue; /* window and pointer are on different screens */
2565 motion_status = TRUE;
2566 mx = ((MotionEvent *) &event)->x;
2567 my = ((MotionEvent *) &event)->y;
2571 motion_status = FALSE;
2572 mx = ((ButtonEvent *) &event)->x;
2573 my = ((ButtonEvent *) &event)->y;
2574 if (event.type == EVENT_BUTTONPRESS)
2575 button_status = ((ButtonEvent *) &event)->button;
2577 button_status = MB_RELEASED;
2580 /* this sets 'request_gadget_id' */
2581 HandleGadgets(mx, my, button_status);
2583 switch(request_gadget_id)
2585 case TOOL_CTRL_ID_YES:
2588 case TOOL_CTRL_ID_NO:
2591 case TOOL_CTRL_ID_CONFIRM:
2592 result = TRUE | FALSE;
2595 case TOOL_CTRL_ID_PLAYER_1:
2598 case TOOL_CTRL_ID_PLAYER_2:
2601 case TOOL_CTRL_ID_PLAYER_3:
2604 case TOOL_CTRL_ID_PLAYER_4:
2615 case EVENT_KEYPRESS:
2616 switch(GetEventKey((KeyEvent *)&event, TRUE))
2629 if (req_state & REQ_PLAYER)
2633 case EVENT_KEYRELEASE:
2634 ClearPlayerAction();
2638 HandleOtherEvents(&event);
2642 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2644 int joy = AnyJoystick();
2646 if (joy & JOY_BUTTON_1)
2648 else if (joy & JOY_BUTTON_2)
2655 if (!PendingEvent()) /* delay only if no pending events */
2658 /* don't eat all CPU time */
2663 if (game_status != GAME_MODE_MAIN)
2668 if (!(req_state & REQ_STAY_OPEN))
2670 CloseDoor(DOOR_CLOSE_1);
2672 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2673 (req_state & REQ_REOPEN))
2674 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2679 if (game_status == GAME_MODE_PLAYING)
2681 SetPanelBackground();
2682 SetDrawBackgroundMask(REDRAW_DOOR_1);
2686 SetDrawBackgroundMask(REDRAW_FIELD);
2689 #if defined(NETWORK_AVALIABLE)
2690 /* continue network game after request */
2691 if (options.network &&
2692 game_status == GAME_MODE_PLAYING &&
2693 req_state & REQUEST_WAIT_FOR_INPUT)
2694 SendToServer_ContinuePlaying();
2697 /* restore deactivated drawing when quick-loading level tape recording */
2698 if (tape.playing && tape.deactivate_display)
2699 TapeDeactivateDisplayOn();
2704 unsigned int OpenDoor(unsigned int door_state)
2706 if (door_state & DOOR_COPY_BACK)
2708 if (door_state & DOOR_OPEN_1)
2709 BlitBitmap(bitmap_db_door, bitmap_db_door,
2710 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2711 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2713 if (door_state & DOOR_OPEN_2)
2714 BlitBitmap(bitmap_db_door, bitmap_db_door,
2715 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2716 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2718 door_state &= ~DOOR_COPY_BACK;
2721 return MoveDoor(door_state);
2724 unsigned int CloseDoor(unsigned int door_state)
2726 unsigned int old_door_state = GetDoorState();
2728 if (!(door_state & DOOR_NO_COPY_BACK))
2730 if (old_door_state & DOOR_OPEN_1)
2731 BlitBitmap(backbuffer, bitmap_db_door,
2732 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2734 if (old_door_state & DOOR_OPEN_2)
2735 BlitBitmap(backbuffer, bitmap_db_door,
2736 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2738 door_state &= ~DOOR_NO_COPY_BACK;
2741 return MoveDoor(door_state);
2744 unsigned int GetDoorState()
2746 return MoveDoor(DOOR_GET_STATE);
2749 unsigned int SetDoorState(unsigned int door_state)
2751 return MoveDoor(door_state | DOOR_SET_STATE);
2754 unsigned int MoveDoor(unsigned int door_state)
2756 static int door1 = DOOR_OPEN_1;
2757 static int door2 = DOOR_CLOSE_2;
2758 unsigned long door_delay = 0;
2759 unsigned long door_delay_value;
2762 if (door_1.width < 0 || door_1.width > DXSIZE)
2763 door_1.width = DXSIZE;
2764 if (door_1.height < 0 || door_1.height > DYSIZE)
2765 door_1.height = DYSIZE;
2766 if (door_2.width < 0 || door_2.width > VXSIZE)
2767 door_2.width = VXSIZE;
2768 if (door_2.height < 0 || door_2.height > VYSIZE)
2769 door_2.height = VYSIZE;
2771 if (door_state == DOOR_GET_STATE)
2772 return (door1 | door2);
2774 if (door_state & DOOR_SET_STATE)
2776 if (door_state & DOOR_ACTION_1)
2777 door1 = door_state & DOOR_ACTION_1;
2778 if (door_state & DOOR_ACTION_2)
2779 door2 = door_state & DOOR_ACTION_2;
2781 return (door1 | door2);
2784 if (!(door_state & DOOR_FORCE_REDRAW))
2786 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2787 door_state &= ~DOOR_OPEN_1;
2788 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2789 door_state &= ~DOOR_CLOSE_1;
2790 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2791 door_state &= ~DOOR_OPEN_2;
2792 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2793 door_state &= ~DOOR_CLOSE_2;
2796 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2799 if (setup.quick_doors)
2801 stepsize = 20; /* must be choosen to always draw last frame */
2802 door_delay_value = 0;
2805 if (global.autoplay_leveldir)
2807 door_state |= DOOR_NO_DELAY;
2808 door_state &= ~DOOR_CLOSE_ALL;
2811 if (door_state & DOOR_ACTION)
2813 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2814 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2815 boolean door_1_done = (!handle_door_1);
2816 boolean door_2_done = (!handle_door_2);
2817 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2818 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2819 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2820 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2821 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2822 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2823 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2824 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2825 int door_skip = max_door_size - door_size;
2826 int end = door_size;
2827 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2830 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2832 /* opening door sound has priority over simultaneously closing door */
2833 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2834 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2835 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2836 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2839 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2842 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2843 GC gc = bitmap->stored_clip_gc;
2845 if (door_state & DOOR_ACTION_1)
2847 int a = MIN(x * door_1.step_offset, end);
2848 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2849 int i = p + door_skip;
2851 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2853 BlitBitmap(bitmap_db_door, drawto,
2854 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2855 DXSIZE, DYSIZE, DX, DY);
2859 BlitBitmap(bitmap_db_door, drawto,
2860 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2861 DXSIZE, DYSIZE - p / 2, DX, DY);
2863 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2866 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2868 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2869 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2870 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2871 int dst2_x = DX, dst2_y = DY;
2872 int width = i, height = DYSIZE;
2874 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2875 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2878 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2879 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2882 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2884 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2885 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2886 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2887 int dst2_x = DX, dst2_y = DY;
2888 int width = DXSIZE, height = i;
2890 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2891 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2894 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2895 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2898 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2900 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2902 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2903 BlitBitmapMasked(bitmap, drawto,
2904 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2905 DX + DXSIZE - i, DY + j);
2906 BlitBitmapMasked(bitmap, drawto,
2907 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2908 DX + DXSIZE - i, DY + 140 + j);
2909 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2910 DY - (DOOR_GFX_PAGEY1 + j));
2911 BlitBitmapMasked(bitmap, drawto,
2912 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2914 BlitBitmapMasked(bitmap, drawto,
2915 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2918 BlitBitmapMasked(bitmap, drawto,
2919 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2921 BlitBitmapMasked(bitmap, drawto,
2922 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2924 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2925 BlitBitmapMasked(bitmap, drawto,
2926 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2927 DX + DXSIZE - i, DY + 77 + j);
2928 BlitBitmapMasked(bitmap, drawto,
2929 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2930 DX + DXSIZE - i, DY + 203 + j);
2933 redraw_mask |= REDRAW_DOOR_1;
2934 door_1_done = (a == end);
2937 if (door_state & DOOR_ACTION_2)
2939 int a = MIN(x * door_2.step_offset, door_size);
2940 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2941 int i = p + door_skip;
2943 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2945 BlitBitmap(bitmap_db_door, drawto,
2946 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2947 VXSIZE, VYSIZE, VX, VY);
2949 else if (x <= VYSIZE)
2951 BlitBitmap(bitmap_db_door, drawto,
2952 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2953 VXSIZE, VYSIZE - p / 2, VX, VY);
2955 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2958 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2960 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2961 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2962 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2963 int dst2_x = VX, dst2_y = VY;
2964 int width = i, height = VYSIZE;
2966 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2967 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2970 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2971 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2974 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2976 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2977 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2978 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2979 int dst2_x = VX, dst2_y = VY;
2980 int width = VXSIZE, height = i;
2982 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2983 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2986 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2987 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2990 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2992 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2994 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2995 BlitBitmapMasked(bitmap, drawto,
2996 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2997 VX + VXSIZE - i, VY + j);
2998 SetClipOrigin(bitmap, gc,
2999 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3000 BlitBitmapMasked(bitmap, drawto,
3001 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3004 BlitBitmapMasked(bitmap, drawto,
3005 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3006 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3007 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3008 BlitBitmapMasked(bitmap, drawto,
3009 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3011 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3014 redraw_mask |= REDRAW_DOOR_2;
3015 door_2_done = (a == VXSIZE);
3018 if (!(door_state & DOOR_NO_DELAY))
3022 if (game_status == GAME_MODE_MAIN)
3025 WaitUntilDelayReached(&door_delay, door_delay_value);
3030 if (door_state & DOOR_ACTION_1)
3031 door1 = door_state & DOOR_ACTION_1;
3032 if (door_state & DOOR_ACTION_2)
3033 door2 = door_state & DOOR_ACTION_2;
3035 return (door1 | door2);
3038 void DrawSpecialEditorDoor()
3040 /* draw bigger toolbox window */
3041 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3042 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3044 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3045 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3048 redraw_mask |= REDRAW_ALL;
3051 void UndrawSpecialEditorDoor()
3053 /* draw normal tape recorder window */
3054 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3055 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3058 redraw_mask |= REDRAW_ALL;
3062 /* ---------- new tool button stuff ---------------------------------------- */
3064 /* graphic position values for tool buttons */
3065 #define TOOL_BUTTON_YES_XPOS 2
3066 #define TOOL_BUTTON_YES_YPOS 250
3067 #define TOOL_BUTTON_YES_GFX_YPOS 0
3068 #define TOOL_BUTTON_YES_XSIZE 46
3069 #define TOOL_BUTTON_YES_YSIZE 28
3070 #define TOOL_BUTTON_NO_XPOS 52
3071 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3072 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3073 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3074 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3075 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3076 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3077 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3078 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3079 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3080 #define TOOL_BUTTON_PLAYER_XSIZE 30
3081 #define TOOL_BUTTON_PLAYER_YSIZE 30
3082 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3083 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3084 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3085 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3086 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3087 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3088 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3089 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3090 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3091 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3092 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3093 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3094 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3095 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3096 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3097 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3098 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3099 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3100 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3101 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3110 } toolbutton_info[NUM_TOOL_BUTTONS] =
3113 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3114 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3115 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3120 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3121 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3122 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3127 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3128 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3129 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3130 TOOL_CTRL_ID_CONFIRM,
3134 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3135 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3136 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3137 TOOL_CTRL_ID_PLAYER_1,
3141 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3142 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3143 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3144 TOOL_CTRL_ID_PLAYER_2,
3148 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3149 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3150 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3151 TOOL_CTRL_ID_PLAYER_3,
3155 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3156 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3157 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3158 TOOL_CTRL_ID_PLAYER_4,
3163 void CreateToolButtons()
3167 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3169 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3170 Bitmap *deco_bitmap = None;
3171 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3172 struct GadgetInfo *gi;
3173 unsigned long event_mask;
3174 int gd_xoffset, gd_yoffset;
3175 int gd_x1, gd_x2, gd_y;
3178 event_mask = GD_EVENT_RELEASED;
3180 gd_xoffset = toolbutton_info[i].xpos;
3181 gd_yoffset = toolbutton_info[i].ypos;
3182 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3183 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3184 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3186 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3188 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3190 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3191 &deco_bitmap, &deco_x, &deco_y);
3192 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3193 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3196 gi = CreateGadget(GDI_CUSTOM_ID, id,
3197 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3198 GDI_X, DX + toolbutton_info[i].x,
3199 GDI_Y, DY + toolbutton_info[i].y,
3200 GDI_WIDTH, toolbutton_info[i].width,
3201 GDI_HEIGHT, toolbutton_info[i].height,
3202 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3203 GDI_STATE, GD_BUTTON_UNPRESSED,
3204 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3205 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3206 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3207 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3208 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3209 GDI_DECORATION_SHIFTING, 1, 1,
3210 GDI_DIRECT_DRAW, FALSE,
3211 GDI_EVENT_MASK, event_mask,
3212 GDI_CALLBACK_ACTION, HandleToolButtons,
3216 Error(ERR_EXIT, "cannot create gadget");
3218 tool_gadget[id] = gi;
3222 void FreeToolButtons()
3226 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3227 FreeGadget(tool_gadget[i]);
3230 static void UnmapToolButtons()
3234 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3235 UnmapGadget(tool_gadget[i]);
3238 static void HandleToolButtons(struct GadgetInfo *gi)
3240 request_gadget_id = gi->custom_id;
3243 static struct Mapping_EM_to_RND_object
3246 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3247 boolean is_backside; /* backside of moving element */
3253 em_object_mapping_list[] =
3256 Xblank, TRUE, FALSE,
3260 Yacid_splash_eB, FALSE, FALSE,
3261 EL_ACID_SPLASH_RIGHT, -1, -1
3264 Yacid_splash_wB, FALSE, FALSE,
3265 EL_ACID_SPLASH_LEFT, -1, -1
3268 #ifdef EM_ENGINE_BAD_ROLL
3270 Xstone_force_e, FALSE, FALSE,
3271 EL_ROCK, -1, MV_BIT_RIGHT
3274 Xstone_force_w, FALSE, FALSE,
3275 EL_ROCK, -1, MV_BIT_LEFT
3278 Xnut_force_e, FALSE, FALSE,
3279 EL_NUT, -1, MV_BIT_RIGHT
3282 Xnut_force_w, FALSE, FALSE,
3283 EL_NUT, -1, MV_BIT_LEFT
3286 Xspring_force_e, FALSE, FALSE,
3287 EL_SPRING, -1, MV_BIT_RIGHT
3290 Xspring_force_w, FALSE, FALSE,
3291 EL_SPRING, -1, MV_BIT_LEFT
3294 Xemerald_force_e, FALSE, FALSE,
3295 EL_EMERALD, -1, MV_BIT_RIGHT
3298 Xemerald_force_w, FALSE, FALSE,
3299 EL_EMERALD, -1, MV_BIT_LEFT
3302 Xdiamond_force_e, FALSE, FALSE,
3303 EL_DIAMOND, -1, MV_BIT_RIGHT
3306 Xdiamond_force_w, FALSE, FALSE,
3307 EL_DIAMOND, -1, MV_BIT_LEFT
3310 Xbomb_force_e, FALSE, FALSE,
3311 EL_BOMB, -1, MV_BIT_RIGHT
3314 Xbomb_force_w, FALSE, FALSE,
3315 EL_BOMB, -1, MV_BIT_LEFT
3317 #endif /* EM_ENGINE_BAD_ROLL */
3320 Xstone, TRUE, FALSE,
3324 Xstone_pause, FALSE, FALSE,
3328 Xstone_fall, FALSE, FALSE,
3332 Ystone_s, FALSE, FALSE,
3333 EL_ROCK, ACTION_FALLING, -1
3336 Ystone_sB, FALSE, TRUE,
3337 EL_ROCK, ACTION_FALLING, -1
3340 Ystone_e, FALSE, FALSE,
3341 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3344 Ystone_eB, FALSE, TRUE,
3345 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3348 Ystone_w, FALSE, FALSE,
3349 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3352 Ystone_wB, FALSE, TRUE,
3353 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3360 Xnut_pause, FALSE, FALSE,
3364 Xnut_fall, FALSE, FALSE,
3368 Ynut_s, FALSE, FALSE,
3369 EL_NUT, ACTION_FALLING, -1
3372 Ynut_sB, FALSE, TRUE,
3373 EL_NUT, ACTION_FALLING, -1
3376 Ynut_e, FALSE, FALSE,
3377 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3380 Ynut_eB, FALSE, TRUE,
3381 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3384 Ynut_w, FALSE, FALSE,
3385 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3388 Ynut_wB, FALSE, TRUE,
3389 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3392 Xbug_n, TRUE, FALSE,
3396 Xbug_e, TRUE, FALSE,
3397 EL_BUG_RIGHT, -1, -1
3400 Xbug_s, TRUE, FALSE,
3404 Xbug_w, TRUE, FALSE,
3408 Xbug_gon, FALSE, FALSE,
3412 Xbug_goe, FALSE, FALSE,
3413 EL_BUG_RIGHT, -1, -1
3416 Xbug_gos, FALSE, FALSE,
3420 Xbug_gow, FALSE, FALSE,
3424 Ybug_n, FALSE, FALSE,
3425 EL_BUG, ACTION_MOVING, MV_BIT_UP
3428 Ybug_nB, FALSE, TRUE,
3429 EL_BUG, ACTION_MOVING, MV_BIT_UP
3432 Ybug_e, FALSE, FALSE,
3433 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3436 Ybug_eB, FALSE, TRUE,
3437 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3440 Ybug_s, FALSE, FALSE,
3441 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3444 Ybug_sB, FALSE, TRUE,
3445 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3448 Ybug_w, FALSE, FALSE,
3449 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3452 Ybug_wB, FALSE, TRUE,
3453 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3456 Ybug_w_n, FALSE, FALSE,
3457 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3460 Ybug_n_e, FALSE, FALSE,
3461 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3464 Ybug_e_s, FALSE, FALSE,
3465 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3468 Ybug_s_w, FALSE, FALSE,
3469 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3472 Ybug_e_n, FALSE, FALSE,
3473 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3476 Ybug_s_e, FALSE, FALSE,
3477 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3480 Ybug_w_s, FALSE, FALSE,
3481 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3484 Ybug_n_w, FALSE, FALSE,
3485 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3488 Ybug_stone, FALSE, FALSE,
3489 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3492 Ybug_spring, FALSE, FALSE,
3493 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3496 Xtank_n, TRUE, FALSE,
3497 EL_SPACESHIP_UP, -1, -1
3500 Xtank_e, TRUE, FALSE,
3501 EL_SPACESHIP_RIGHT, -1, -1
3504 Xtank_s, TRUE, FALSE,
3505 EL_SPACESHIP_DOWN, -1, -1
3508 Xtank_w, TRUE, FALSE,
3509 EL_SPACESHIP_LEFT, -1, -1
3512 Xtank_gon, FALSE, FALSE,
3513 EL_SPACESHIP_UP, -1, -1
3516 Xtank_goe, FALSE, FALSE,
3517 EL_SPACESHIP_RIGHT, -1, -1
3520 Xtank_gos, FALSE, FALSE,
3521 EL_SPACESHIP_DOWN, -1, -1
3524 Xtank_gow, FALSE, FALSE,
3525 EL_SPACESHIP_LEFT, -1, -1
3528 Ytank_n, FALSE, FALSE,
3529 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3532 Ytank_nB, FALSE, TRUE,
3533 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3536 Ytank_e, FALSE, FALSE,
3537 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3540 Ytank_eB, FALSE, TRUE,
3541 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3544 Ytank_s, FALSE, FALSE,
3545 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3548 Ytank_sB, FALSE, TRUE,
3549 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3552 Ytank_w, FALSE, FALSE,
3553 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3556 Ytank_wB, FALSE, TRUE,
3557 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3560 Ytank_w_n, FALSE, FALSE,
3561 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3564 Ytank_n_e, FALSE, FALSE,
3565 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3568 Ytank_e_s, FALSE, FALSE,
3569 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3572 Ytank_s_w, FALSE, FALSE,
3573 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3576 Ytank_e_n, FALSE, FALSE,
3577 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3580 Ytank_s_e, FALSE, FALSE,
3581 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3584 Ytank_w_s, FALSE, FALSE,
3585 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3588 Ytank_n_w, FALSE, FALSE,
3589 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3592 Ytank_stone, FALSE, FALSE,
3593 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3596 Ytank_spring, FALSE, FALSE,
3597 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3600 Xandroid, TRUE, FALSE,
3601 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3604 Xandroid_1_n, FALSE, FALSE,
3605 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3608 Xandroid_2_n, FALSE, FALSE,
3609 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3612 Xandroid_1_e, FALSE, FALSE,
3613 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3616 Xandroid_2_e, FALSE, FALSE,
3617 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3620 Xandroid_1_w, FALSE, FALSE,
3621 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3624 Xandroid_2_w, FALSE, FALSE,
3625 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3628 Xandroid_1_s, FALSE, FALSE,
3629 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3632 Xandroid_2_s, FALSE, FALSE,
3633 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3636 Yandroid_n, FALSE, FALSE,
3637 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3640 Yandroid_nB, FALSE, TRUE,
3641 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3644 Yandroid_ne, FALSE, FALSE,
3645 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3648 Yandroid_neB, FALSE, TRUE,
3649 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3652 Yandroid_e, FALSE, FALSE,
3653 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3656 Yandroid_eB, FALSE, TRUE,
3657 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3660 Yandroid_se, FALSE, FALSE,
3661 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3664 Yandroid_seB, FALSE, TRUE,
3665 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3668 Yandroid_s, FALSE, FALSE,
3669 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3672 Yandroid_sB, FALSE, TRUE,
3673 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3676 Yandroid_sw, FALSE, FALSE,
3677 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3680 Yandroid_swB, FALSE, TRUE,
3681 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3684 Yandroid_w, FALSE, FALSE,
3685 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3688 Yandroid_wB, FALSE, TRUE,
3689 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3692 Yandroid_nw, FALSE, FALSE,
3693 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3696 Yandroid_nwB, FALSE, TRUE,
3697 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3700 Xspring, TRUE, FALSE,
3704 Xspring_pause, FALSE, FALSE,
3708 Xspring_e, FALSE, FALSE,
3712 Xspring_w, FALSE, FALSE,
3716 Xspring_fall, FALSE, FALSE,
3720 Yspring_s, FALSE, FALSE,
3721 EL_SPRING, ACTION_FALLING, -1
3724 Yspring_sB, FALSE, TRUE,
3725 EL_SPRING, ACTION_FALLING, -1
3728 Yspring_e, FALSE, FALSE,
3729 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3732 Yspring_eB, FALSE, TRUE,
3733 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3736 Yspring_w, FALSE, FALSE,
3737 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3740 Yspring_wB, FALSE, TRUE,
3741 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3744 Yspring_kill_e, FALSE, FALSE,
3745 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3748 Yspring_kill_eB, FALSE, TRUE,
3749 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3752 Yspring_kill_w, FALSE, FALSE,
3753 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3756 Yspring_kill_wB, FALSE, TRUE,
3757 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3760 Xeater_n, TRUE, FALSE,
3761 EL_YAMYAM_UP, -1, -1
3764 Xeater_e, TRUE, FALSE,
3765 EL_YAMYAM_RIGHT, -1, -1
3768 Xeater_w, TRUE, FALSE,
3769 EL_YAMYAM_LEFT, -1, -1
3772 Xeater_s, TRUE, FALSE,
3773 EL_YAMYAM_DOWN, -1, -1
3776 Yeater_n, FALSE, FALSE,
3777 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3780 Yeater_nB, FALSE, TRUE,
3781 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3784 Yeater_e, FALSE, FALSE,
3785 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3788 Yeater_eB, FALSE, TRUE,
3789 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3792 Yeater_s, FALSE, FALSE,
3793 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3796 Yeater_sB, FALSE, TRUE,
3797 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3800 Yeater_w, FALSE, FALSE,
3801 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3804 Yeater_wB, FALSE, TRUE,
3805 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3808 Yeater_stone, FALSE, FALSE,
3809 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3812 Yeater_spring, FALSE, FALSE,
3813 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3816 Xalien, TRUE, FALSE,
3820 Xalien_pause, FALSE, FALSE,
3824 Yalien_n, FALSE, FALSE,
3825 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3828 Yalien_nB, FALSE, TRUE,
3829 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3832 Yalien_e, FALSE, FALSE,
3833 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3836 Yalien_eB, FALSE, TRUE,
3837 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3840 Yalien_s, FALSE, FALSE,
3841 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3844 Yalien_sB, FALSE, TRUE,
3845 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3848 Yalien_w, FALSE, FALSE,
3849 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3852 Yalien_wB, FALSE, TRUE,
3853 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3856 Yalien_stone, FALSE, FALSE,
3857 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3860 Yalien_spring, FALSE, FALSE,
3861 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3864 Xemerald, TRUE, FALSE,
3868 Xemerald_pause, FALSE, FALSE,
3872 Xemerald_fall, FALSE, FALSE,
3876 Xemerald_shine, FALSE, FALSE,
3877 EL_EMERALD, ACTION_TWINKLING, -1
3880 Yemerald_s, FALSE, FALSE,
3881 EL_EMERALD, ACTION_FALLING, -1
3884 Yemerald_sB, FALSE, TRUE,
3885 EL_EMERALD, ACTION_FALLING, -1
3888 Yemerald_e, FALSE, FALSE,
3889 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3892 Yemerald_eB, FALSE, TRUE,
3893 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3896 Yemerald_w, FALSE, FALSE,
3897 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3900 Yemerald_wB, FALSE, TRUE,
3901 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3904 Yemerald_eat, FALSE, FALSE,
3905 EL_EMERALD, ACTION_COLLECTING, -1
3908 Yemerald_stone, FALSE, FALSE,
3909 EL_NUT, ACTION_BREAKING, -1
3912 Xdiamond, TRUE, FALSE,
3916 Xdiamond_pause, FALSE, FALSE,
3920 Xdiamond_fall, FALSE, FALSE,
3924 Xdiamond_shine, FALSE, FALSE,
3925 EL_DIAMOND, ACTION_TWINKLING, -1
3928 Ydiamond_s, FALSE, FALSE,
3929 EL_DIAMOND, ACTION_FALLING, -1
3932 Ydiamond_sB, FALSE, TRUE,
3933 EL_DIAMOND, ACTION_FALLING, -1
3936 Ydiamond_e, FALSE, FALSE,
3937 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3940 Ydiamond_eB, FALSE, TRUE,
3941 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3944 Ydiamond_w, FALSE, FALSE,
3945 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3948 Ydiamond_wB, FALSE, TRUE,
3949 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3952 Ydiamond_eat, FALSE, FALSE,
3953 EL_DIAMOND, ACTION_COLLECTING, -1
3956 Ydiamond_stone, FALSE, FALSE,
3957 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3960 Xdrip_fall, TRUE, FALSE,
3961 EL_AMOEBA_DROP, -1, -1
3964 Xdrip_stretch, FALSE, FALSE,
3965 EL_AMOEBA_DROP, ACTION_FALLING, -1
3968 Xdrip_stretchB, FALSE, TRUE,
3969 EL_AMOEBA_DROP, ACTION_FALLING, -1
3972 Xdrip_eat, FALSE, FALSE,
3973 EL_AMOEBA_DROP, ACTION_GROWING, -1
3976 Ydrip_s1, FALSE, FALSE,
3977 EL_AMOEBA_DROP, ACTION_FALLING, -1
3980 Ydrip_s1B, FALSE, TRUE,
3981 EL_AMOEBA_DROP, ACTION_FALLING, -1
3984 Ydrip_s2, FALSE, FALSE,
3985 EL_AMOEBA_DROP, ACTION_FALLING, -1
3988 Ydrip_s2B, FALSE, TRUE,
3989 EL_AMOEBA_DROP, ACTION_FALLING, -1
3996 Xbomb_pause, FALSE, FALSE,
4000 Xbomb_fall, FALSE, FALSE,
4004 Ybomb_s, FALSE, FALSE,
4005 EL_BOMB, ACTION_FALLING, -1
4008 Ybomb_sB, FALSE, TRUE,
4009 EL_BOMB, ACTION_FALLING, -1
4012 Ybomb_e, FALSE, FALSE,
4013 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4016 Ybomb_eB, FALSE, TRUE,
4017 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4020 Ybomb_w, FALSE, FALSE,
4021 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4024 Ybomb_wB, FALSE, TRUE,
4025 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4028 Ybomb_eat, FALSE, FALSE,
4029 EL_BOMB, ACTION_ACTIVATING, -1
4032 Xballoon, TRUE, FALSE,
4036 Yballoon_n, FALSE, FALSE,
4037 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4040 Yballoon_nB, FALSE, TRUE,
4041 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4044 Yballoon_e, FALSE, FALSE,
4045 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4048 Yballoon_eB, FALSE, TRUE,
4049 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4052 Yballoon_s, FALSE, FALSE,
4053 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4056 Yballoon_sB, FALSE, TRUE,
4057 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4060 Yballoon_w, FALSE, FALSE,
4061 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4064 Yballoon_wB, FALSE, TRUE,
4065 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4068 Xgrass, TRUE, FALSE,
4069 EL_EMC_GRASS, -1, -1
4072 Ygrass_nB, FALSE, FALSE,
4073 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4076 Ygrass_eB, FALSE, FALSE,
4077 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4080 Ygrass_sB, FALSE, FALSE,
4081 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4084 Ygrass_wB, FALSE, FALSE,
4085 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4092 Ydirt_nB, FALSE, FALSE,
4093 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4096 Ydirt_eB, FALSE, FALSE,
4097 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4100 Ydirt_sB, FALSE, FALSE,
4101 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4104 Ydirt_wB, FALSE, FALSE,
4105 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4108 Xacid_ne, TRUE, FALSE,
4109 EL_ACID_POOL_TOPRIGHT, -1, -1
4112 Xacid_se, TRUE, FALSE,
4113 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4116 Xacid_s, TRUE, FALSE,
4117 EL_ACID_POOL_BOTTOM, -1, -1
4120 Xacid_sw, TRUE, FALSE,
4121 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4124 Xacid_nw, TRUE, FALSE,
4125 EL_ACID_POOL_TOPLEFT, -1, -1
4128 Xacid_1, TRUE, FALSE,
4132 Xacid_2, FALSE, FALSE,
4136 Xacid_3, FALSE, FALSE,
4140 Xacid_4, FALSE, FALSE,
4144 Xacid_5, FALSE, FALSE,
4148 Xacid_6, FALSE, FALSE,
4152 Xacid_7, FALSE, FALSE,
4156 Xacid_8, FALSE, FALSE,
4160 Xball_1, TRUE, FALSE,
4161 EL_EMC_MAGIC_BALL, -1, -1
4164 Xball_1B, FALSE, FALSE,
4165 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4168 Xball_2, FALSE, FALSE,
4169 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4172 Xball_2B, FALSE, FALSE,
4173 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4176 Yball_eat, FALSE, FALSE,
4177 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4180 Ykey_1_eat, FALSE, FALSE,
4181 EL_EM_KEY_1, ACTION_COLLECTING, -1
4184 Ykey_2_eat, FALSE, FALSE,
4185 EL_EM_KEY_2, ACTION_COLLECTING, -1
4188 Ykey_3_eat, FALSE, FALSE,
4189 EL_EM_KEY_3, ACTION_COLLECTING, -1
4192 Ykey_4_eat, FALSE, FALSE,
4193 EL_EM_KEY_4, ACTION_COLLECTING, -1
4196 Ykey_5_eat, FALSE, FALSE,
4197 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4200 Ykey_6_eat, FALSE, FALSE,
4201 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4204 Ykey_7_eat, FALSE, FALSE,
4205 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4208 Ykey_8_eat, FALSE, FALSE,
4209 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4212 Ylenses_eat, FALSE, FALSE,
4213 EL_EMC_LENSES, ACTION_COLLECTING, -1
4216 Ymagnify_eat, FALSE, FALSE,
4217 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4220 Ygrass_eat, FALSE, FALSE,
4221 EL_EMC_GRASS, ACTION_SNAPPING, -1
4224 Ydirt_eat, FALSE, FALSE,
4225 EL_SAND, ACTION_SNAPPING, -1
4228 Xgrow_ns, TRUE, FALSE,
4229 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4232 Ygrow_ns_eat, FALSE, FALSE,
4233 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4236 Xgrow_ew, TRUE, FALSE,
4237 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4240 Ygrow_ew_eat, FALSE, FALSE,
4241 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4244 Xwonderwall, TRUE, FALSE,
4245 EL_MAGIC_WALL, -1, -1
4248 XwonderwallB, FALSE, FALSE,
4249 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4252 Xamoeba_1, TRUE, FALSE,
4253 EL_AMOEBA_DRY, ACTION_OTHER, -1
4256 Xamoeba_2, FALSE, FALSE,
4257 EL_AMOEBA_DRY, ACTION_OTHER, -1
4260 Xamoeba_3, FALSE, FALSE,
4261 EL_AMOEBA_DRY, ACTION_OTHER, -1
4264 Xamoeba_4, FALSE, FALSE,
4265 EL_AMOEBA_DRY, ACTION_OTHER, -1
4268 Xamoeba_5, TRUE, FALSE,
4269 EL_AMOEBA_WET, ACTION_OTHER, -1
4272 Xamoeba_6, FALSE, FALSE,
4273 EL_AMOEBA_WET, ACTION_OTHER, -1
4276 Xamoeba_7, FALSE, FALSE,
4277 EL_AMOEBA_WET, ACTION_OTHER, -1
4280 Xamoeba_8, FALSE, FALSE,
4281 EL_AMOEBA_WET, ACTION_OTHER, -1
4284 Xdoor_1, TRUE, FALSE,
4285 EL_EM_GATE_1, -1, -1
4288 Xdoor_2, TRUE, FALSE,
4289 EL_EM_GATE_2, -1, -1
4292 Xdoor_3, TRUE, FALSE,
4293 EL_EM_GATE_3, -1, -1
4296 Xdoor_4, TRUE, FALSE,
4297 EL_EM_GATE_4, -1, -1
4300 Xdoor_5, TRUE, FALSE,
4301 EL_EMC_GATE_5, -1, -1
4304 Xdoor_6, TRUE, FALSE,
4305 EL_EMC_GATE_6, -1, -1
4308 Xdoor_7, TRUE, FALSE,
4309 EL_EMC_GATE_7, -1, -1
4312 Xdoor_8, TRUE, FALSE,
4313 EL_EMC_GATE_8, -1, -1
4316 Xkey_1, TRUE, FALSE,
4320 Xkey_2, TRUE, FALSE,
4324 Xkey_3, TRUE, FALSE,
4328 Xkey_4, TRUE, FALSE,
4332 Xkey_5, TRUE, FALSE,
4333 EL_EMC_KEY_5, -1, -1
4336 Xkey_6, TRUE, FALSE,
4337 EL_EMC_KEY_6, -1, -1
4340 Xkey_7, TRUE, FALSE,
4341 EL_EMC_KEY_7, -1, -1
4344 Xkey_8, TRUE, FALSE,
4345 EL_EMC_KEY_8, -1, -1
4348 Xwind_n, TRUE, FALSE,
4349 EL_BALLOON_SWITCH_UP, -1, -1
4352 Xwind_e, TRUE, FALSE,
4353 EL_BALLOON_SWITCH_RIGHT, -1, -1
4356 Xwind_s, TRUE, FALSE,
4357 EL_BALLOON_SWITCH_DOWN, -1, -1
4360 Xwind_w, TRUE, FALSE,
4361 EL_BALLOON_SWITCH_LEFT, -1, -1
4364 Xwind_nesw, TRUE, FALSE,
4365 EL_BALLOON_SWITCH_ANY, -1, -1
4368 Xwind_stop, TRUE, FALSE,
4369 EL_BALLOON_SWITCH_NONE, -1, -1
4373 EL_EXIT_CLOSED, -1, -1
4376 Xexit_1, TRUE, FALSE,
4377 EL_EXIT_OPEN, -1, -1
4380 Xexit_2, FALSE, FALSE,
4381 EL_EXIT_OPEN, -1, -1
4384 Xexit_3, FALSE, FALSE,
4385 EL_EXIT_OPEN, -1, -1
4388 Xdynamite, TRUE, FALSE,
4389 EL_EM_DYNAMITE, -1, -1
4392 Ydynamite_eat, FALSE, FALSE,
4393 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4396 Xdynamite_1, TRUE, FALSE,
4397 EL_EM_DYNAMITE_ACTIVE, -1, -1
4400 Xdynamite_2, FALSE, FALSE,
4401 EL_EM_DYNAMITE_ACTIVE, -1, -1
4404 Xdynamite_3, FALSE, FALSE,
4405 EL_EM_DYNAMITE_ACTIVE, -1, -1
4408 Xdynamite_4, FALSE, FALSE,
4409 EL_EM_DYNAMITE_ACTIVE, -1, -1
4412 Xbumper, TRUE, FALSE,
4413 EL_EMC_SPRING_BUMPER, -1, -1
4416 XbumperB, FALSE, FALSE,
4417 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4420 Xwheel, TRUE, FALSE,
4421 EL_ROBOT_WHEEL, -1, -1
4424 XwheelB, FALSE, FALSE,
4425 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4428 Xswitch, TRUE, FALSE,
4429 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4432 XswitchB, FALSE, FALSE,
4433 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4437 EL_QUICKSAND_EMPTY, -1, -1
4440 Xsand_stone, TRUE, FALSE,
4441 EL_QUICKSAND_FULL, -1, -1
4444 Xsand_stonein_1, FALSE, TRUE,
4445 EL_ROCK, ACTION_FILLING, -1
4448 Xsand_stonein_2, FALSE, TRUE,
4449 EL_ROCK, ACTION_FILLING, -1
4452 Xsand_stonein_3, FALSE, TRUE,
4453 EL_ROCK, ACTION_FILLING, -1
4456 Xsand_stonein_4, FALSE, TRUE,
4457 EL_ROCK, ACTION_FILLING, -1
4460 Xsand_stonesand_1, FALSE, FALSE,
4461 EL_QUICKSAND_FULL, -1, -1
4464 Xsand_stonesand_2, FALSE, FALSE,
4465 EL_QUICKSAND_FULL, -1, -1
4468 Xsand_stonesand_3, FALSE, FALSE,
4469 EL_QUICKSAND_FULL, -1, -1
4472 Xsand_stonesand_4, FALSE, FALSE,
4473 EL_QUICKSAND_FULL, -1, -1
4476 Xsand_stoneout_1, FALSE, FALSE,
4477 EL_ROCK, ACTION_EMPTYING, -1
4480 Xsand_stoneout_2, FALSE, FALSE,
4481 EL_ROCK, ACTION_EMPTYING, -1
4484 Xsand_sandstone_1, FALSE, FALSE,
4485 EL_QUICKSAND_FULL, -1, -1
4488 Xsand_sandstone_2, FALSE, FALSE,
4489 EL_QUICKSAND_FULL, -1, -1
4492 Xsand_sandstone_3, FALSE, FALSE,
4493 EL_QUICKSAND_FULL, -1, -1
4496 Xsand_sandstone_4, FALSE, FALSE,
4497 EL_QUICKSAND_FULL, -1, -1
4500 Xplant, TRUE, FALSE,
4501 EL_EMC_PLANT, -1, -1
4504 Yplant, FALSE, FALSE,
4505 EL_EMC_PLANT, -1, -1
4508 Xlenses, TRUE, FALSE,
4509 EL_EMC_LENSES, -1, -1
4512 Xmagnify, TRUE, FALSE,
4513 EL_EMC_MAGNIFIER, -1, -1
4516 Xdripper, TRUE, FALSE,
4517 EL_EMC_DRIPPER, -1, -1
4520 XdripperB, FALSE, FALSE,
4521 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4524 Xfake_blank, TRUE, FALSE,
4525 EL_INVISIBLE_WALL, -1, -1
4528 Xfake_blankB, FALSE, FALSE,
4529 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4532 Xfake_grass, TRUE, FALSE,
4533 EL_EMC_FAKE_GRASS, -1, -1
4536 Xfake_grassB, FALSE, FALSE,
4537 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4540 Xfake_door_1, TRUE, FALSE,
4541 EL_EM_GATE_1_GRAY, -1, -1
4544 Xfake_door_2, TRUE, FALSE,
4545 EL_EM_GATE_2_GRAY, -1, -1
4548 Xfake_door_3, TRUE, FALSE,
4549 EL_EM_GATE_3_GRAY, -1, -1
4552 Xfake_door_4, TRUE, FALSE,
4553 EL_EM_GATE_4_GRAY, -1, -1
4556 Xfake_door_5, TRUE, FALSE,
4557 EL_EMC_GATE_5_GRAY, -1, -1
4560 Xfake_door_6, TRUE, FALSE,
4561 EL_EMC_GATE_6_GRAY, -1, -1
4564 Xfake_door_7, TRUE, FALSE,
4565 EL_EMC_GATE_7_GRAY, -1, -1
4568 Xfake_door_8, TRUE, FALSE,
4569 EL_EMC_GATE_8_GRAY, -1, -1
4572 Xfake_acid_1, TRUE, FALSE,
4573 EL_EMC_FAKE_ACID, -1, -1
4576 Xfake_acid_2, FALSE, FALSE,
4577 EL_EMC_FAKE_ACID, -1, -1
4580 Xfake_acid_3, FALSE, FALSE,
4581 EL_EMC_FAKE_ACID, -1, -1
4584 Xfake_acid_4, FALSE, FALSE,
4585 EL_EMC_FAKE_ACID, -1, -1
4588 Xfake_acid_5, FALSE, FALSE,
4589 EL_EMC_FAKE_ACID, -1, -1
4592 Xfake_acid_6, FALSE, FALSE,
4593 EL_EMC_FAKE_ACID, -1, -1
4596 Xfake_acid_7, FALSE, FALSE,
4597 EL_EMC_FAKE_ACID, -1, -1
4600 Xfake_acid_8, FALSE, FALSE,
4601 EL_EMC_FAKE_ACID, -1, -1
4604 Xsteel_1, TRUE, FALSE,
4605 EL_STEELWALL, -1, -1
4608 Xsteel_2, TRUE, FALSE,
4609 EL_EMC_STEELWALL_2, -1, -1
4612 Xsteel_3, TRUE, FALSE,
4613 EL_EMC_STEELWALL_3, -1, -1
4616 Xsteel_4, TRUE, FALSE,
4617 EL_EMC_STEELWALL_4, -1, -1
4620 Xwall_1, TRUE, FALSE,
4624 Xwall_2, TRUE, FALSE,
4625 EL_EMC_WALL_14, -1, -1
4628 Xwall_3, TRUE, FALSE,
4629 EL_EMC_WALL_15, -1, -1
4632 Xwall_4, TRUE, FALSE,
4633 EL_EMC_WALL_16, -1, -1
4636 Xround_wall_1, TRUE, FALSE,
4637 EL_WALL_SLIPPERY, -1, -1
4640 Xround_wall_2, TRUE, FALSE,
4641 EL_EMC_WALL_SLIPPERY_2, -1, -1
4644 Xround_wall_3, TRUE, FALSE,
4645 EL_EMC_WALL_SLIPPERY_3, -1, -1
4648 Xround_wall_4, TRUE, FALSE,
4649 EL_EMC_WALL_SLIPPERY_4, -1, -1
4652 Xdecor_1, TRUE, FALSE,
4653 EL_EMC_WALL_8, -1, -1
4656 Xdecor_2, TRUE, FALSE,
4657 EL_EMC_WALL_6, -1, -1
4660 Xdecor_3, TRUE, FALSE,
4661 EL_EMC_WALL_4, -1, -1
4664 Xdecor_4, TRUE, FALSE,
4665 EL_EMC_WALL_7, -1, -1
4668 Xdecor_5, TRUE, FALSE,
4669 EL_EMC_WALL_5, -1, -1
4672 Xdecor_6, TRUE, FALSE,
4673 EL_EMC_WALL_9, -1, -1
4676 Xdecor_7, TRUE, FALSE,
4677 EL_EMC_WALL_10, -1, -1
4680 Xdecor_8, TRUE, FALSE,
4681 EL_EMC_WALL_1, -1, -1
4684 Xdecor_9, TRUE, FALSE,
4685 EL_EMC_WALL_2, -1, -1
4688 Xdecor_10, TRUE, FALSE,
4689 EL_EMC_WALL_3, -1, -1
4692 Xdecor_11, TRUE, FALSE,
4693 EL_EMC_WALL_11, -1, -1
4696 Xdecor_12, TRUE, FALSE,
4697 EL_EMC_WALL_12, -1, -1
4700 Xalpha_0, TRUE, FALSE,
4701 EL_CHAR('0'), -1, -1
4704 Xalpha_1, TRUE, FALSE,
4705 EL_CHAR('1'), -1, -1
4708 Xalpha_2, TRUE, FALSE,
4709 EL_CHAR('2'), -1, -1
4712 Xalpha_3, TRUE, FALSE,
4713 EL_CHAR('3'), -1, -1
4716 Xalpha_4, TRUE, FALSE,
4717 EL_CHAR('4'), -1, -1
4720 Xalpha_5, TRUE, FALSE,
4721 EL_CHAR('5'), -1, -1
4724 Xalpha_6, TRUE, FALSE,
4725 EL_CHAR('6'), -1, -1
4728 Xalpha_7, TRUE, FALSE,
4729 EL_CHAR('7'), -1, -1
4732 Xalpha_8, TRUE, FALSE,
4733 EL_CHAR('8'), -1, -1
4736 Xalpha_9, TRUE, FALSE,
4737 EL_CHAR('9'), -1, -1
4740 Xalpha_excla, TRUE, FALSE,
4741 EL_CHAR('!'), -1, -1
4744 Xalpha_quote, TRUE, FALSE,
4745 EL_CHAR('"'), -1, -1
4748 Xalpha_comma, TRUE, FALSE,
4749 EL_CHAR(','), -1, -1
4752 Xalpha_minus, TRUE, FALSE,
4753 EL_CHAR('-'), -1, -1
4756 Xalpha_perio, TRUE, FALSE,
4757 EL_CHAR('.'), -1, -1
4760 Xalpha_colon, TRUE, FALSE,
4761 EL_CHAR(':'), -1, -1
4764 Xalpha_quest, TRUE, FALSE,
4765 EL_CHAR('?'), -1, -1
4768 Xalpha_a, TRUE, FALSE,
4769 EL_CHAR('A'), -1, -1
4772 Xalpha_b, TRUE, FALSE,
4773 EL_CHAR('B'), -1, -1
4776 Xalpha_c, TRUE, FALSE,
4777 EL_CHAR('C'), -1, -1
4780 Xalpha_d, TRUE, FALSE,
4781 EL_CHAR('D'), -1, -1
4784 Xalpha_e, TRUE, FALSE,
4785 EL_CHAR('E'), -1, -1
4788 Xalpha_f, TRUE, FALSE,
4789 EL_CHAR('F'), -1, -1
4792 Xalpha_g, TRUE, FALSE,
4793 EL_CHAR('G'), -1, -1
4796 Xalpha_h, TRUE, FALSE,
4797 EL_CHAR('H'), -1, -1
4800 Xalpha_i, TRUE, FALSE,
4801 EL_CHAR('I'), -1, -1
4804 Xalpha_j, TRUE, FALSE,
4805 EL_CHAR('J'), -1, -1
4808 Xalpha_k, TRUE, FALSE,
4809 EL_CHAR('K'), -1, -1
4812 Xalpha_l, TRUE, FALSE,
4813 EL_CHAR('L'), -1, -1
4816 Xalpha_m, TRUE, FALSE,
4817 EL_CHAR('M'), -1, -1
4820 Xalpha_n, TRUE, FALSE,
4821 EL_CHAR('N'), -1, -1
4824 Xalpha_o, TRUE, FALSE,
4825 EL_CHAR('O'), -1, -1
4828 Xalpha_p, TRUE, FALSE,
4829 EL_CHAR('P'), -1, -1
4832 Xalpha_q, TRUE, FALSE,
4833 EL_CHAR('Q'), -1, -1
4836 Xalpha_r, TRUE, FALSE,
4837 EL_CHAR('R'), -1, -1
4840 Xalpha_s, TRUE, FALSE,
4841 EL_CHAR('S'), -1, -1
4844 Xalpha_t, TRUE, FALSE,
4845 EL_CHAR('T'), -1, -1
4848 Xalpha_u, TRUE, FALSE,
4849 EL_CHAR('U'), -1, -1
4852 Xalpha_v, TRUE, FALSE,
4853 EL_CHAR('V'), -1, -1
4856 Xalpha_w, TRUE, FALSE,
4857 EL_CHAR('W'), -1, -1
4860 Xalpha_x, TRUE, FALSE,
4861 EL_CHAR('X'), -1, -1
4864 Xalpha_y, TRUE, FALSE,
4865 EL_CHAR('Y'), -1, -1
4868 Xalpha_z, TRUE, FALSE,
4869 EL_CHAR('Z'), -1, -1
4872 Xalpha_arrow_e, TRUE, FALSE,
4873 EL_CHAR('>'), -1, -1
4876 Xalpha_arrow_w, TRUE, FALSE,
4877 EL_CHAR('<'), -1, -1
4880 Xalpha_copyr, TRUE, FALSE,
4881 EL_CHAR('©'), -1, -1
4885 Xboom_bug, FALSE, FALSE,
4886 EL_BUG, ACTION_EXPLODING, -1
4889 Xboom_bomb, FALSE, FALSE,
4890 EL_BOMB, ACTION_EXPLODING, -1
4893 Xboom_android, FALSE, FALSE,
4894 EL_EMC_ANDROID, ACTION_OTHER, -1
4897 Xboom_1, FALSE, FALSE,
4898 EL_DEFAULT, ACTION_EXPLODING, -1
4901 Xboom_2, FALSE, FALSE,
4902 EL_DEFAULT, ACTION_EXPLODING, -1
4905 Znormal, FALSE, FALSE,
4909 Zdynamite, FALSE, FALSE,
4913 Zplayer, FALSE, FALSE,
4917 ZBORDER, FALSE, FALSE,
4927 static struct Mapping_EM_to_RND_player
4936 em_player_mapping_list[] =
4940 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4944 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4948 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4952 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4956 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4960 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4964 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4968 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4972 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4976 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4980 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4984 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4988 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4992 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4996 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5000 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5004 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5008 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5012 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5016 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5020 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5024 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5028 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5032 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5036 EL_PLAYER_1, ACTION_DEFAULT, -1,
5040 EL_PLAYER_2, ACTION_DEFAULT, -1,
5044 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5048 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5052 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5056 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5060 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5064 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5068 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5072 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5076 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5080 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5084 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5088 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5092 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5096 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5100 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5104 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5108 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5112 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5116 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5120 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5124 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5128 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5132 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5136 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5140 EL_PLAYER_3, ACTION_DEFAULT, -1,
5144 EL_PLAYER_4, ACTION_DEFAULT, -1,
5153 int map_element_RND_to_EM(int element_rnd)
5155 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5156 static boolean mapping_initialized = FALSE;
5158 if (!mapping_initialized)
5162 /* return "Xalpha_quest" for all undefined elements in mapping array */
5163 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5164 mapping_RND_to_EM[i] = Xalpha_quest;
5166 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5167 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5168 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5169 em_object_mapping_list[i].element_em;
5171 mapping_initialized = TRUE;
5174 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5175 return mapping_RND_to_EM[element_rnd];
5177 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5182 int map_element_EM_to_RND(int element_em)
5184 static unsigned short mapping_EM_to_RND[TILE_MAX];
5185 static boolean mapping_initialized = FALSE;
5187 if (!mapping_initialized)
5191 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5192 for (i = 0; i < TILE_MAX; i++)
5193 mapping_EM_to_RND[i] = EL_UNKNOWN;
5195 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5196 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5197 em_object_mapping_list[i].element_rnd;
5199 mapping_initialized = TRUE;
5202 if (element_em >= 0 && element_em < TILE_MAX)
5203 return mapping_EM_to_RND[element_em];
5205 Error(ERR_WARN, "invalid EM level element %d", element_em);
5210 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5212 struct LevelInfo_EM *level_em = level->native_em_level;
5213 struct LEVEL *lev = level_em->lev;
5216 for (i = 0; i < TILE_MAX; i++)
5217 lev->android_array[i] = Xblank;
5219 for (i = 0; i < level->num_android_clone_elements; i++)
5221 int element_rnd = level->android_clone_element[i];
5222 int element_em = map_element_RND_to_EM(element_rnd);
5224 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5225 if (em_object_mapping_list[j].element_rnd == element_rnd)
5226 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5230 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5232 struct LevelInfo_EM *level_em = level->native_em_level;
5233 struct LEVEL *lev = level_em->lev;
5236 level->num_android_clone_elements = 0;
5238 for (i = 0; i < TILE_MAX; i++)
5240 int element_em = lev->android_array[i];
5242 boolean element_found = FALSE;
5244 if (element_em == Xblank)
5247 element_rnd = map_element_EM_to_RND(element_em);
5249 for (j = 0; j < level->num_android_clone_elements; j++)
5250 if (level->android_clone_element[j] == element_rnd)
5251 element_found = TRUE;
5255 level->android_clone_element[level->num_android_clone_elements++] =
5258 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5263 if (level->num_android_clone_elements == 0)
5265 level->num_android_clone_elements = 1;
5266 level->android_clone_element[0] = EL_EMPTY;
5270 int map_direction_RND_to_EM(int direction)
5272 return (direction == MV_UP ? 0 :
5273 direction == MV_RIGHT ? 1 :
5274 direction == MV_DOWN ? 2 :
5275 direction == MV_LEFT ? 3 :
5279 int map_direction_EM_to_RND(int direction)
5281 return (direction == 0 ? MV_UP :
5282 direction == 1 ? MV_RIGHT :
5283 direction == 2 ? MV_DOWN :
5284 direction == 3 ? MV_LEFT :
5288 int get_next_element(int element)
5292 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5293 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5294 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5295 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5296 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5297 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5298 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5300 default: return element;
5305 int el_act_dir2img(int element, int action, int direction)
5307 element = GFX_ELEMENT(element);
5309 if (direction == MV_NONE)
5310 return element_info[element].graphic[action];
5312 direction = MV_DIR_TO_BIT(direction);
5314 return element_info[element].direction_graphic[action][direction];
5317 int el_act_dir2img(int element, int action, int direction)
5319 element = GFX_ELEMENT(element);
5320 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5322 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5323 return element_info[element].direction_graphic[action][direction];
5328 static int el_act_dir2crm(int element, int action, int direction)
5330 element = GFX_ELEMENT(element);
5332 if (direction == MV_NONE)
5333 return element_info[element].crumbled[action];
5335 direction = MV_DIR_TO_BIT(direction);
5337 return element_info[element].direction_crumbled[action][direction];
5340 static int el_act_dir2crm(int element, int action, int direction)
5342 element = GFX_ELEMENT(element);
5343 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5345 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5346 return element_info[element].direction_crumbled[action][direction];
5350 int el_act2img(int element, int action)
5352 element = GFX_ELEMENT(element);
5354 return element_info[element].graphic[action];
5357 int el_act2crm(int element, int action)
5359 element = GFX_ELEMENT(element);
5361 return element_info[element].crumbled[action];
5364 int el_dir2img(int element, int direction)
5366 element = GFX_ELEMENT(element);
5368 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5371 int el2baseimg(int element)
5373 return element_info[element].graphic[ACTION_DEFAULT];
5376 int el2img(int element)
5378 element = GFX_ELEMENT(element);
5380 return element_info[element].graphic[ACTION_DEFAULT];
5383 int el2edimg(int element)
5385 element = GFX_ELEMENT(element);
5387 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5390 int el2preimg(int element)
5392 element = GFX_ELEMENT(element);
5394 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5397 int font2baseimg(int font_nr)
5399 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5402 int getNumActivePlayers_EM()
5404 int num_players = 0;
5410 for (i = 0; i < MAX_PLAYERS; i++)
5411 if (tape.player_participates[i])
5417 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5419 int game_frame_delay_value;
5421 game_frame_delay_value =
5422 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5423 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5426 if (tape.playing && tape.warp_forward && !tape.pausing)
5427 game_frame_delay_value = 0;
5429 return game_frame_delay_value;
5432 unsigned int InitRND(long seed)
5434 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5435 return InitEngineRandom_EM(seed);
5437 return InitEngineRandom_RND(seed);
5440 void InitGraphicInfo_EM(void)
5442 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5443 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5447 int num_em_gfx_errors = 0;
5449 if (graphic_info_em_object[0][0].bitmap == NULL)
5451 /* EM graphics not yet initialized in em_open_all() */
5456 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5459 /* always start with reliable default values */
5460 for (i = 0; i < TILE_MAX; i++)
5462 object_mapping[i].element_rnd = EL_UNKNOWN;
5463 object_mapping[i].is_backside = FALSE;
5464 object_mapping[i].action = ACTION_DEFAULT;
5465 object_mapping[i].direction = MV_NONE;
5468 /* always start with reliable default values */
5469 for (p = 0; p < MAX_PLAYERS; p++)
5471 for (i = 0; i < SPR_MAX; i++)
5473 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5474 player_mapping[p][i].action = ACTION_DEFAULT;
5475 player_mapping[p][i].direction = MV_NONE;
5479 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5481 int e = em_object_mapping_list[i].element_em;
5483 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5484 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5486 if (em_object_mapping_list[i].action != -1)
5487 object_mapping[e].action = em_object_mapping_list[i].action;
5489 if (em_object_mapping_list[i].direction != -1)
5490 object_mapping[e].direction =
5491 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5494 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5496 int a = em_player_mapping_list[i].action_em;
5497 int p = em_player_mapping_list[i].player_nr;
5499 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5501 if (em_player_mapping_list[i].action != -1)
5502 player_mapping[p][a].action = em_player_mapping_list[i].action;
5504 if (em_player_mapping_list[i].direction != -1)
5505 player_mapping[p][a].direction =
5506 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5509 for (i = 0; i < TILE_MAX; i++)
5511 int element = object_mapping[i].element_rnd;
5512 int action = object_mapping[i].action;
5513 int direction = object_mapping[i].direction;
5514 boolean is_backside = object_mapping[i].is_backside;
5515 boolean action_removing = (action == ACTION_DIGGING ||
5516 action == ACTION_SNAPPING ||
5517 action == ACTION_COLLECTING);
5518 boolean action_exploding = ((action == ACTION_EXPLODING ||
5519 action == ACTION_SMASHED_BY_ROCK ||
5520 action == ACTION_SMASHED_BY_SPRING) &&
5521 element != EL_DIAMOND);
5522 boolean action_active = (action == ACTION_ACTIVE);
5523 boolean action_other = (action == ACTION_OTHER);
5525 for (j = 0; j < 8; j++)
5527 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5528 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5530 i == Xdrip_stretch ? element :
5531 i == Xdrip_stretchB ? element :
5532 i == Ydrip_s1 ? element :
5533 i == Ydrip_s1B ? element :
5534 i == Xball_1B ? element :
5535 i == Xball_2 ? element :
5536 i == Xball_2B ? element :
5537 i == Yball_eat ? element :
5538 i == Ykey_1_eat ? element :
5539 i == Ykey_2_eat ? element :
5540 i == Ykey_3_eat ? element :
5541 i == Ykey_4_eat ? element :
5542 i == Ykey_5_eat ? element :
5543 i == Ykey_6_eat ? element :
5544 i == Ykey_7_eat ? element :
5545 i == Ykey_8_eat ? element :
5546 i == Ylenses_eat ? element :
5547 i == Ymagnify_eat ? element :
5548 i == Ygrass_eat ? element :
5549 i == Ydirt_eat ? element :
5550 i == Yemerald_stone ? EL_EMERALD :
5551 i == Ydiamond_stone ? EL_ROCK :
5552 i == Xsand_stonein_1 ? element :
5553 i == Xsand_stonein_2 ? element :
5554 i == Xsand_stonein_3 ? element :
5555 i == Xsand_stonein_4 ? element :
5556 is_backside ? EL_EMPTY :
5557 action_removing ? EL_EMPTY :
5559 int effective_action = (j < 7 ? action :
5560 i == Xdrip_stretch ? action :
5561 i == Xdrip_stretchB ? action :
5562 i == Ydrip_s1 ? action :
5563 i == Ydrip_s1B ? action :
5564 i == Xball_1B ? action :
5565 i == Xball_2 ? action :
5566 i == Xball_2B ? action :
5567 i == Yball_eat ? action :
5568 i == Ykey_1_eat ? action :
5569 i == Ykey_2_eat ? action :
5570 i == Ykey_3_eat ? action :
5571 i == Ykey_4_eat ? action :
5572 i == Ykey_5_eat ? action :
5573 i == Ykey_6_eat ? action :
5574 i == Ykey_7_eat ? action :
5575 i == Ykey_8_eat ? action :
5576 i == Ylenses_eat ? action :
5577 i == Ymagnify_eat ? action :
5578 i == Ygrass_eat ? action :
5579 i == Ydirt_eat ? action :
5580 i == Xsand_stonein_1 ? action :
5581 i == Xsand_stonein_2 ? action :
5582 i == Xsand_stonein_3 ? action :
5583 i == Xsand_stonein_4 ? action :
5584 i == Xsand_stoneout_1 ? action :
5585 i == Xsand_stoneout_2 ? action :
5586 i == Xboom_android ? ACTION_EXPLODING :
5587 action_exploding ? ACTION_EXPLODING :
5588 action_active ? action :
5589 action_other ? action :
5591 int graphic = (el_act_dir2img(effective_element, effective_action,
5593 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5595 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5596 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5597 boolean has_action_graphics = (graphic != base_graphic);
5598 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5599 struct GraphicInfo *g = &graphic_info[graphic];
5600 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5603 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5604 boolean special_animation = (action != ACTION_DEFAULT &&
5605 g->anim_frames == 3 &&
5606 g->anim_delay == 2 &&
5607 g->anim_mode & ANIM_LINEAR);
5608 int sync_frame = (i == Xdrip_stretch ? 7 :
5609 i == Xdrip_stretchB ? 7 :
5610 i == Ydrip_s2 ? j + 8 :
5611 i == Ydrip_s2B ? j + 8 :
5620 i == Xfake_acid_1 ? 0 :
5621 i == Xfake_acid_2 ? 10 :
5622 i == Xfake_acid_3 ? 20 :
5623 i == Xfake_acid_4 ? 30 :
5624 i == Xfake_acid_5 ? 40 :
5625 i == Xfake_acid_6 ? 50 :
5626 i == Xfake_acid_7 ? 60 :
5627 i == Xfake_acid_8 ? 70 :
5629 i == Xball_2B ? j + 8 :
5630 i == Yball_eat ? j + 1 :
5631 i == Ykey_1_eat ? j + 1 :
5632 i == Ykey_2_eat ? j + 1 :
5633 i == Ykey_3_eat ? j + 1 :
5634 i == Ykey_4_eat ? j + 1 :
5635 i == Ykey_5_eat ? j + 1 :
5636 i == Ykey_6_eat ? j + 1 :
5637 i == Ykey_7_eat ? j + 1 :
5638 i == Ykey_8_eat ? j + 1 :
5639 i == Ylenses_eat ? j + 1 :
5640 i == Ymagnify_eat ? j + 1 :
5641 i == Ygrass_eat ? j + 1 :
5642 i == Ydirt_eat ? j + 1 :
5643 i == Xamoeba_1 ? 0 :
5644 i == Xamoeba_2 ? 1 :
5645 i == Xamoeba_3 ? 2 :
5646 i == Xamoeba_4 ? 3 :
5647 i == Xamoeba_5 ? 0 :
5648 i == Xamoeba_6 ? 1 :
5649 i == Xamoeba_7 ? 2 :
5650 i == Xamoeba_8 ? 3 :
5651 i == Xexit_2 ? j + 8 :
5652 i == Xexit_3 ? j + 16 :
5653 i == Xdynamite_1 ? 0 :
5654 i == Xdynamite_2 ? 8 :
5655 i == Xdynamite_3 ? 16 :
5656 i == Xdynamite_4 ? 24 :
5657 i == Xsand_stonein_1 ? j + 1 :
5658 i == Xsand_stonein_2 ? j + 9 :
5659 i == Xsand_stonein_3 ? j + 17 :
5660 i == Xsand_stonein_4 ? j + 25 :
5661 i == Xsand_stoneout_1 && j == 0 ? 0 :
5662 i == Xsand_stoneout_1 && j == 1 ? 0 :
5663 i == Xsand_stoneout_1 && j == 2 ? 1 :
5664 i == Xsand_stoneout_1 && j == 3 ? 2 :
5665 i == Xsand_stoneout_1 && j == 4 ? 2 :
5666 i == Xsand_stoneout_1 && j == 5 ? 3 :
5667 i == Xsand_stoneout_1 && j == 6 ? 4 :
5668 i == Xsand_stoneout_1 && j == 7 ? 4 :
5669 i == Xsand_stoneout_2 && j == 0 ? 5 :
5670 i == Xsand_stoneout_2 && j == 1 ? 6 :
5671 i == Xsand_stoneout_2 && j == 2 ? 7 :
5672 i == Xsand_stoneout_2 && j == 3 ? 8 :
5673 i == Xsand_stoneout_2 && j == 4 ? 9 :
5674 i == Xsand_stoneout_2 && j == 5 ? 11 :
5675 i == Xsand_stoneout_2 && j == 6 ? 13 :
5676 i == Xsand_stoneout_2 && j == 7 ? 15 :
5677 i == Xboom_bug && j == 1 ? 2 :
5678 i == Xboom_bug && j == 2 ? 2 :
5679 i == Xboom_bug && j == 3 ? 4 :
5680 i == Xboom_bug && j == 4 ? 4 :
5681 i == Xboom_bug && j == 5 ? 2 :
5682 i == Xboom_bug && j == 6 ? 2 :
5683 i == Xboom_bug && j == 7 ? 0 :
5684 i == Xboom_bomb && j == 1 ? 2 :
5685 i == Xboom_bomb && j == 2 ? 2 :
5686 i == Xboom_bomb && j == 3 ? 4 :
5687 i == Xboom_bomb && j == 4 ? 4 :
5688 i == Xboom_bomb && j == 5 ? 2 :
5689 i == Xboom_bomb && j == 6 ? 2 :
5690 i == Xboom_bomb && j == 7 ? 0 :
5691 i == Xboom_android && j == 7 ? 6 :
5692 i == Xboom_1 && j == 1 ? 2 :
5693 i == Xboom_1 && j == 2 ? 2 :
5694 i == Xboom_1 && j == 3 ? 4 :
5695 i == Xboom_1 && j == 4 ? 4 :
5696 i == Xboom_1 && j == 5 ? 6 :
5697 i == Xboom_1 && j == 6 ? 6 :
5698 i == Xboom_1 && j == 7 ? 8 :
5699 i == Xboom_2 && j == 0 ? 8 :
5700 i == Xboom_2 && j == 1 ? 8 :
5701 i == Xboom_2 && j == 2 ? 10 :
5702 i == Xboom_2 && j == 3 ? 10 :
5703 i == Xboom_2 && j == 4 ? 10 :
5704 i == Xboom_2 && j == 5 ? 12 :
5705 i == Xboom_2 && j == 6 ? 12 :
5706 i == Xboom_2 && j == 7 ? 12 :
5707 special_animation && j == 4 ? 3 :
5708 effective_action != action ? 0 :
5712 Bitmap *debug_bitmap = g_em->bitmap;
5713 int debug_src_x = g_em->src_x;
5714 int debug_src_y = g_em->src_y;
5717 int frame = getAnimationFrame(g->anim_frames,
5720 g->anim_start_frame,
5723 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5724 g->double_movement && is_backside);
5726 g_em->bitmap = src_bitmap;
5727 g_em->src_x = src_x;
5728 g_em->src_y = src_y;
5729 g_em->src_offset_x = 0;
5730 g_em->src_offset_y = 0;
5731 g_em->dst_offset_x = 0;
5732 g_em->dst_offset_y = 0;
5733 g_em->width = TILEX;
5734 g_em->height = TILEY;
5736 g_em->crumbled_bitmap = NULL;
5737 g_em->crumbled_src_x = 0;
5738 g_em->crumbled_src_y = 0;
5739 g_em->crumbled_border_size = 0;
5741 g_em->has_crumbled_graphics = FALSE;
5742 g_em->preserve_background = FALSE;
5745 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5746 printf("::: empty crumbled: %d [%s], %d, %d\n",
5747 effective_element, element_info[effective_element].token_name,
5748 effective_action, direction);
5751 /* if element can be crumbled, but certain action graphics are just empty
5752 space (like snapping sand with the original R'n'D graphics), do not
5753 treat these empty space graphics as crumbled graphics in EMC engine */
5754 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5756 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5758 g_em->has_crumbled_graphics = TRUE;
5759 g_em->crumbled_bitmap = src_bitmap;
5760 g_em->crumbled_src_x = src_x;
5761 g_em->crumbled_src_y = src_y;
5762 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5766 if (element == EL_ROCK &&
5767 effective_action == ACTION_FILLING)
5768 printf("::: has_action_graphics == %d\n", has_action_graphics);
5771 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5772 effective_action == ACTION_MOVING ||
5773 effective_action == ACTION_PUSHING ||
5774 effective_action == ACTION_EATING)) ||
5775 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5776 effective_action == ACTION_EMPTYING)))
5779 (effective_action == ACTION_FALLING ||
5780 effective_action == ACTION_FILLING ||
5781 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5782 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5783 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5784 int num_steps = (i == Ydrip_s1 ? 16 :
5785 i == Ydrip_s1B ? 16 :
5786 i == Ydrip_s2 ? 16 :
5787 i == Ydrip_s2B ? 16 :
5788 i == Xsand_stonein_1 ? 32 :
5789 i == Xsand_stonein_2 ? 32 :
5790 i == Xsand_stonein_3 ? 32 :
5791 i == Xsand_stonein_4 ? 32 :
5792 i == Xsand_stoneout_1 ? 16 :
5793 i == Xsand_stoneout_2 ? 16 : 8);
5794 int cx = ABS(dx) * (TILEX / num_steps);
5795 int cy = ABS(dy) * (TILEY / num_steps);
5796 int step_frame = (i == Ydrip_s2 ? j + 8 :
5797 i == Ydrip_s2B ? j + 8 :
5798 i == Xsand_stonein_2 ? j + 8 :
5799 i == Xsand_stonein_3 ? j + 16 :
5800 i == Xsand_stonein_4 ? j + 24 :
5801 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5802 int step = (is_backside ? step_frame : num_steps - step_frame);
5804 if (is_backside) /* tile where movement starts */
5806 if (dx < 0 || dy < 0)
5808 g_em->src_offset_x = cx * step;
5809 g_em->src_offset_y = cy * step;
5813 g_em->dst_offset_x = cx * step;
5814 g_em->dst_offset_y = cy * step;
5817 else /* tile where movement ends */
5819 if (dx < 0 || dy < 0)
5821 g_em->dst_offset_x = cx * step;
5822 g_em->dst_offset_y = cy * step;
5826 g_em->src_offset_x = cx * step;
5827 g_em->src_offset_y = cy * step;
5831 g_em->width = TILEX - cx * step;
5832 g_em->height = TILEY - cy * step;
5835 /* create unique graphic identifier to decide if tile must be redrawn */
5836 /* bit 31 - 16 (16 bit): EM style graphic
5837 bit 15 - 12 ( 4 bit): EM style frame
5838 bit 11 - 6 ( 6 bit): graphic width
5839 bit 5 - 0 ( 6 bit): graphic height */
5840 g_em->unique_identifier =
5841 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5845 /* skip check for EMC elements not contained in original EMC artwork */
5846 if (element == EL_EMC_FAKE_ACID)
5849 if (g_em->bitmap != debug_bitmap ||
5850 g_em->src_x != debug_src_x ||
5851 g_em->src_y != debug_src_y ||
5852 g_em->src_offset_x != 0 ||
5853 g_em->src_offset_y != 0 ||
5854 g_em->dst_offset_x != 0 ||
5855 g_em->dst_offset_y != 0 ||
5856 g_em->width != TILEX ||
5857 g_em->height != TILEY)
5859 static int last_i = -1;
5867 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5868 i, element, element_info[element].token_name,
5869 element_action_info[effective_action].suffix, direction);
5871 if (element != effective_element)
5872 printf(" [%d ('%s')]",
5874 element_info[effective_element].token_name);
5878 if (g_em->bitmap != debug_bitmap)
5879 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5880 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5882 if (g_em->src_x != debug_src_x ||
5883 g_em->src_y != debug_src_y)
5884 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5885 j, (is_backside ? 'B' : 'F'),
5886 g_em->src_x, g_em->src_y,
5887 g_em->src_x / 32, g_em->src_y / 32,
5888 debug_src_x, debug_src_y,
5889 debug_src_x / 32, debug_src_y / 32);
5891 if (g_em->src_offset_x != 0 ||
5892 g_em->src_offset_y != 0 ||
5893 g_em->dst_offset_x != 0 ||
5894 g_em->dst_offset_y != 0)
5895 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5897 g_em->src_offset_x, g_em->src_offset_y,
5898 g_em->dst_offset_x, g_em->dst_offset_y);
5900 if (g_em->width != TILEX ||
5901 g_em->height != TILEY)
5902 printf(" %d (%d): size %d,%d should be %d,%d\n",
5904 g_em->width, g_em->height, TILEX, TILEY);
5906 num_em_gfx_errors++;
5913 for (i = 0; i < TILE_MAX; i++)
5915 for (j = 0; j < 8; j++)
5917 int element = object_mapping[i].element_rnd;
5918 int action = object_mapping[i].action;
5919 int direction = object_mapping[i].direction;
5920 boolean is_backside = object_mapping[i].is_backside;
5921 int graphic_action = el_act_dir2img(element, action, direction);
5922 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5924 if ((action == ACTION_SMASHED_BY_ROCK ||
5925 action == ACTION_SMASHED_BY_SPRING ||
5926 action == ACTION_EATING) &&
5927 graphic_action == graphic_default)
5929 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5930 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5931 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5932 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5935 /* no separate animation for "smashed by rock" -- use rock instead */
5936 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5937 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5939 g_em->bitmap = g_xx->bitmap;
5940 g_em->src_x = g_xx->src_x;
5941 g_em->src_y = g_xx->src_y;
5942 g_em->src_offset_x = g_xx->src_offset_x;
5943 g_em->src_offset_y = g_xx->src_offset_y;
5944 g_em->dst_offset_x = g_xx->dst_offset_x;
5945 g_em->dst_offset_y = g_xx->dst_offset_y;
5946 g_em->width = g_xx->width;
5947 g_em->height = g_xx->height;
5948 g_em->unique_identifier = g_xx->unique_identifier;
5951 g_em->preserve_background = TRUE;
5956 for (p = 0; p < MAX_PLAYERS; p++)
5958 for (i = 0; i < SPR_MAX; i++)
5960 int element = player_mapping[p][i].element_rnd;
5961 int action = player_mapping[p][i].action;
5962 int direction = player_mapping[p][i].direction;
5964 for (j = 0; j < 8; j++)
5966 int effective_element = element;
5967 int effective_action = action;
5968 int graphic = (direction == MV_NONE ?
5969 el_act2img(effective_element, effective_action) :
5970 el_act_dir2img(effective_element, effective_action,
5972 struct GraphicInfo *g = &graphic_info[graphic];
5973 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5979 Bitmap *debug_bitmap = g_em->bitmap;
5980 int debug_src_x = g_em->src_x;
5981 int debug_src_y = g_em->src_y;
5984 int frame = getAnimationFrame(g->anim_frames,
5987 g->anim_start_frame,
5990 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5992 g_em->bitmap = src_bitmap;
5993 g_em->src_x = src_x;
5994 g_em->src_y = src_y;
5995 g_em->src_offset_x = 0;
5996 g_em->src_offset_y = 0;
5997 g_em->dst_offset_x = 0;
5998 g_em->dst_offset_y = 0;
5999 g_em->width = TILEX;
6000 g_em->height = TILEY;
6004 /* skip check for EMC elements not contained in original EMC artwork */
6005 if (element == EL_PLAYER_3 ||
6006 element == EL_PLAYER_4)
6009 if (g_em->bitmap != debug_bitmap ||
6010 g_em->src_x != debug_src_x ||
6011 g_em->src_y != debug_src_y)
6013 static int last_i = -1;
6021 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6022 p, i, element, element_info[element].token_name,
6023 element_action_info[effective_action].suffix, direction);
6025 if (element != effective_element)
6026 printf(" [%d ('%s')]",
6028 element_info[effective_element].token_name);
6032 if (g_em->bitmap != debug_bitmap)
6033 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6034 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6036 if (g_em->src_x != debug_src_x ||
6037 g_em->src_y != debug_src_y)
6038 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6040 g_em->src_x, g_em->src_y,
6041 g_em->src_x / 32, g_em->src_y / 32,
6042 debug_src_x, debug_src_y,
6043 debug_src_x / 32, debug_src_y / 32);
6045 num_em_gfx_errors++;
6055 printf("::: [%d errors found]\n", num_em_gfx_errors);
6061 void PlayMenuSound()
6063 int sound = menu.sound[game_status];
6065 if (sound == SND_UNDEFINED)
6068 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6069 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6072 if (IS_LOOP_SOUND(sound))
6073 PlaySoundLoop(sound);
6078 void PlayMenuSoundStereo(int sound, int stereo_position)
6080 if (sound == SND_UNDEFINED)
6083 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6084 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6087 if (IS_LOOP_SOUND(sound))
6088 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6090 PlaySoundStereo(sound, stereo_position);
6093 void PlayMenuSoundIfLoop()
6095 int sound = menu.sound[game_status];
6097 if (sound == SND_UNDEFINED)
6100 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6101 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6104 if (IS_LOOP_SOUND(sound))
6105 PlaySoundLoop(sound);
6108 void PlayMenuMusic()
6110 int music = menu.music[game_status];
6112 if (music == MUS_UNDEFINED)
6118 void ToggleFullscreenIfNeeded()
6120 boolean change_fullscreen = (setup.fullscreen !=
6121 video.fullscreen_enabled);
6122 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6123 !strEqual(setup.fullscreen_mode,
6124 video.fullscreen_mode_current));
6126 if (!video.fullscreen_available)
6130 if (change_fullscreen || change_fullscreen_mode)
6132 if (setup.fullscreen != video.fullscreen_enabled ||
6133 setup.fullscreen_mode != video.fullscreen_mode_current)
6136 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6138 /* save backbuffer content which gets lost when toggling fullscreen mode */
6139 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6142 if (change_fullscreen_mode)
6144 if (setup.fullscreen && video.fullscreen_enabled)
6147 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6149 /* (this is now set in sdl.c) */
6151 video.fullscreen_mode_current = setup.fullscreen_mode;
6153 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6156 /* toggle fullscreen */
6157 ChangeVideoModeIfNeeded(setup.fullscreen);
6159 setup.fullscreen = video.fullscreen_enabled;
6161 /* restore backbuffer content from temporary backbuffer backup bitmap */
6162 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6164 FreeBitmap(tmp_backbuffer);
6167 /* update visible window/screen */
6168 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6170 redraw_mask = REDRAW_ALL;